summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/bluetooth.c669
-rw-r--r--drivers/usb/storage/protocol.c75
-rw-r--r--drivers/usb/storage/protocol.h3
-rw-r--r--drivers/usb/storage/scsiglue.c3
-rw-r--r--drivers/usb/storage/sddr09.c534
-rw-r--r--drivers/usb/storage/sddr09.h7
-rw-r--r--drivers/usb/storage/transport.c13
-rw-r--r--drivers/usb/storage/usb.c20
-rw-r--r--drivers/usb/storage/usb.h4
-rw-r--r--drivers/usb/usb-uhci.c78
-rw-r--r--drivers/usb/usb.c50
11 files changed, 1110 insertions, 346 deletions
diff --git a/drivers/usb/bluetooth.c b/drivers/usb/bluetooth.c
index bd7be69e8..4ee29a702 100644
--- a/drivers/usb/bluetooth.c
+++ b/drivers/usb/bluetooth.c
@@ -1,11 +1,24 @@
/*
- * bluetooth.c Version 0.2
+ * bluetooth.c Version 0.3
*
* Copyright (c) 2000 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (c) 2000 Mark Douglas Corner <mcorner@umich.edu>
*
* USB Bluetooth driver, based on the Bluetooth Spec version 1.0B
*
*
+ * (08/03/2000) Version 0.3 gkh mdc
+ * Merged in Mark's changes to make the driver play nice with the Axis
+ * stack.
+ * Made the write bulk use an urb pool to enable larger transfers with
+ * fewer calls to the driver.
+ * Fixed off by one bug in acl pkt receive
+ * Made packet counters specific to each bluetooth device
+ * Added checks for zero length callbacks
+ * Added buffers for int and bulk packets. Had to do this otherwise
+ * packet types could intermingle.
+ * Made a control urb pool for the control messages.
+ *
* (07/11/2000) Version 0.2 gkh
* Fixed a small bug found by Nils Faerber in the usb_bluetooth_probe
* function.
@@ -49,17 +62,16 @@
#include <linux/tty_flip.h>
#include <linux/tty.h>
#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/smp_lock.h>
#define DEBUG
#include <linux/usb.h>
/* Module information */
-MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/");
+MODULE_AUTHOR("Greg Kroah-Hartman, Mark Douglas Corner");
MODULE_DESCRIPTION("USB Bluetooth driver");
+/* define this if you have hardware that is not good */
+/*#define BTBUGGYHARDWARE */
/* Class, SubClass, and Protocol codes that describe a Bluetooth device */
#define WIRELESS_CLASS_CODE 0xe0
@@ -72,19 +84,47 @@ MODULE_DESCRIPTION("USB Bluetooth driver");
#define USB_BLUETOOTH_MAGIC 0x6d02 /* magic number for bluetooth struct */
+#define BLUETOOTH_CONTROL_REQUEST_TYPE 0x20
+
+/* Bluetooth packet types */
+#define CMD_PKT 0x01
+#define ACL_PKT 0x02
+#define SCO_PKT 0x03
+#define EVENT_PKT 0x04
+#define ERROR_PKT 0x05
+#define NEG_PKT 0x06
+
+/* Message sizes */
+#define MAX_EVENT_SIZE 0xFF
+#define EVENT_HDR_SIZE 3 /* 2 for the header + 1 for the type indicator */
+#define EVENT_BUFFER_SIZE (MAX_EVENT_SIZE + EVENT_HDR_SIZE)
+
+#define MAX_ACL_SIZE 0xFFFF
+#define ACL_HDR_SIZE 5 /* 4 for the header + 1 for the type indicator */
+#define ACL_BUFFER_SIZE (MAX_ACL_SIZE + ACL_HDR_SIZE)
+
/* parity check flag */
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+#define CHAR2INT16(c1,c0) (((u32)((c1) & 0xff) << 8) + (u32)((c0) & 0xff))
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define NUM_BULK_URBS 24
+#define NUM_CONTROL_URBS 16
struct usb_bluetooth {
int magic;
struct usb_device * dev;
struct tty_driver * tty_driver; /* the tty_driver for this device */
struct tty_struct * tty; /* the coresponding tty for this port */
-
+
unsigned char minor; /* the starting minor number for this device */
char active; /* someone has this device open */
+ int throttle; /* throttled by tty layer */
+
+ __u8 control_out_bInterfaceNum;
+ struct urb * control_urb_pool[NUM_CONTROL_URBS];
+ devrequest dr[NUM_CONTROL_URBS];
unsigned char * interrupt_in_buffer;
struct urb * interrupt_in_urb;
@@ -92,17 +132,21 @@ struct usb_bluetooth {
unsigned char * bulk_in_buffer;
struct urb * read_urb;
- unsigned char * bulk_out_buffer;
int bulk_out_size;
- struct urb * write_urb;
+ struct urb * write_urb_pool[NUM_BULK_URBS];
+ __u8 bulk_out_endpointAddress;
wait_queue_head_t write_wait;
struct tq_struct tqueue; /* task queue for line discipline waking up */
+
+ unsigned int int_packet_pos;
+ unsigned char int_buffer[EVENT_BUFFER_SIZE];
+ unsigned int bulk_packet_pos;
+ unsigned char bulk_buffer[ACL_BUFFER_SIZE]; /* 64k preallocated, fix? */
};
-
/* local function prototypes */
static int bluetooth_open (struct tty_struct *tty, struct file *filp);
static void bluetooth_close (struct tty_struct *tty, struct file *filp);
@@ -114,9 +158,15 @@ static void bluetooth_unthrottle (struct tty_struct *tty);
static int bluetooth_ioctl (struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
static void bluetooth_set_termios (struct tty_struct *tty, struct termios *old);
+static void bluetooth_int_callback (struct urb *urb);
+static void bluetooth_ctrl_callback (struct urb *urb);
+static void bluetooth_read_bulk_callback (struct urb *urb);
+static void bluetooth_write_bulk_callback (struct urb *urb);
+
static void * usb_bluetooth_probe (struct usb_device *dev, unsigned int ifnum);
static void usb_bluetooth_disconnect (struct usb_device *dev, void *ptr);
+
static struct usb_driver usb_bluetooth_driver = {
name: "bluetooth",
probe: usb_bluetooth_probe,
@@ -131,6 +181,7 @@ static struct termios * bluetooth_termios_locked[BLUETOOTH_TTY_MINORS];
static struct usb_bluetooth *bluetooth_table[BLUETOOTH_TTY_MINORS] = {NULL, };
+
static inline int bluetooth_paranoia_check (struct usb_bluetooth *bluetooth, const char *function)
{
if (!bluetooth) {
@@ -141,17 +192,17 @@ static inline int bluetooth_paranoia_check (struct usb_bluetooth *bluetooth, con
dbg("%s - bad magic number for bluetooth", function);
return -1;
}
-
+
return 0;
}
-static inline struct usb_bluetooth* get_usb_bluetooth (struct usb_bluetooth *bluetooth, const char *function)
-{
+static inline struct usb_bluetooth* get_usb_bluetooth (struct usb_bluetooth *bluetooth, const char *function)
+{
if (!bluetooth ||
- bluetooth_paranoia_check (bluetooth, function)) {
+ bluetooth_paranoia_check (bluetooth, function)) {
/* then say that we dont have a valid usb_bluetooth thing, which will
- * end up genrating -ENODEV return values */
+ * end up generating -ENODEV return values */
return NULL;
}
@@ -165,6 +216,54 @@ static inline struct usb_bluetooth *get_bluetooth_by_minor (int minor)
}
+static int bluetooth_ctrl_msg (struct usb_bluetooth *bluetooth, int request, int value, void *buf, int len)
+{
+ struct urb *urb = NULL;
+ devrequest *dr = NULL;
+ int i;
+ int status;
+
+ dbg (__FUNCTION__);
+
+ /* try to find a free urb in our list */
+ for (i = 0; i < NUM_CONTROL_URBS; ++i) {
+ if (bluetooth->control_urb_pool[i]->status != -EINPROGRESS) {
+ urb = bluetooth->control_urb_pool[i];
+ dr = &bluetooth->dr[i];
+ break;
+ }
+ }
+ if (urb == NULL) {
+ dbg (__FUNCTION__ " - no free urbs");
+ return -ENOMEM;
+ }
+
+ /* free up the last buffer that this urb used */
+ if (urb->transfer_buffer != NULL) {
+ kfree(urb->transfer_buffer);
+ urb->transfer_buffer = NULL;
+ }
+
+ dr->requesttype = BLUETOOTH_CONTROL_REQUEST_TYPE;
+ dr->request = request;
+ dr->value = cpu_to_le16p(&value);
+ dr->index = cpu_to_le16p(&bluetooth->control_out_bInterfaceNum);
+ dr->length = cpu_to_le16p(&len);
+
+ FILL_CONTROL_URB (urb, bluetooth->dev, usb_sndctrlpipe(bluetooth->dev, 0),
+ (unsigned char*)dr, buf, len, bluetooth_ctrl_callback, 0);
+
+ /* send it down the pipe */
+ status = usb_submit_urb(urb);
+ if (status)
+ dbg(__FUNCTION__ " - usb_submit_urb(control) failed with status = %d", status);
+
+ return 0;
+}
+
+
+
+
/*****************************************************************************
* Driver tty interface functions
@@ -172,7 +271,8 @@ static inline struct usb_bluetooth *get_bluetooth_by_minor (int minor)
static int bluetooth_open (struct tty_struct *tty, struct file * filp)
{
struct usb_bluetooth *bluetooth;
-
+ int result;
+
dbg(__FUNCTION__);
/* initialize the pointer incase something fails */
@@ -189,16 +289,26 @@ static int bluetooth_open (struct tty_struct *tty, struct file * filp)
dbg (__FUNCTION__ " - device already open");
return -EINVAL;
}
-
+
/* set up our structure making the tty driver remember our object, and us it */
tty->driver_data = bluetooth;
bluetooth->tty = tty;
-
+
bluetooth->active = 1;
-
- /*Start reading from the device*/
- if (usb_submit_urb(bluetooth->read_urb))
- dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
+
+ /* Reset the packet position counters */
+ bluetooth->int_packet_pos = 0;
+ bluetooth->bulk_packet_pos = 0;
+
+#ifndef BTBUGGYHARDWARE
+ /* Start reading from the device */
+ result = usb_submit_urb(bluetooth->read_urb);
+ if (result)
+ dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed with status %d", result);
+#endif
+ result = usb_submit_urb(bluetooth->interrupt_in_urb);
+ if (result)
+ dbg(__FUNCTION__ " - usb_submit_urb(interrupt in) failed with status %d", result);
return 0;
}
@@ -207,20 +317,22 @@ static int bluetooth_open (struct tty_struct *tty, struct file * filp)
static void bluetooth_close (struct tty_struct *tty, struct file * filp)
{
struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+ int i;
if (!bluetooth) {
return;
}
dbg(__FUNCTION__);
-
+
if (!bluetooth->active) {
dbg (__FUNCTION__ " - device not opened");
return;
}
- /* shutdown any bulk reads that might be going on */
- usb_unlink_urb (bluetooth->write_urb);
+ /* shutdown any bulk reads and writes that might be going on */
+ for (i = 0; i < NUM_BULK_URBS; ++i)
+ usb_unlink_urb (bluetooth->write_urb_pool[i]);
usb_unlink_urb (bluetooth->read_urb);
bluetooth->active = 0;
@@ -230,55 +342,137 @@ static void bluetooth_close (struct tty_struct *tty, struct file * filp)
static int bluetooth_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
{
struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-
+ struct urb *urb = NULL;
+ unsigned char *new_buffer;
+ const unsigned char *current_position;
+ int status;
+ int bytes_sent;
+ int buffer_size;
+ int i;
+
if (!bluetooth) {
return -ENODEV;
}
-
+
dbg(__FUNCTION__ " - %d byte(s)", count);
if (!bluetooth->active) {
dbg (__FUNCTION__ " - device not opened");
return -EINVAL;
}
-
+
if (count == 0) {
dbg(__FUNCTION__ " - write request of 0 bytes");
- return (0);
+ return 0;
}
-
- if (bluetooth->write_urb->status == -EINPROGRESS) {
- dbg (__FUNCTION__ " - already writing");
- return (0);
+ if (count == 1) {
+ dbg(__FUNCTION__ " - write request only included type %d", buf[0]);
+ return 1;
}
- count = (count > bluetooth->bulk_out_size) ? bluetooth->bulk_out_size : count;
-
#ifdef DEBUG
- {
- int i;
- printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count);
- for (i = 0; i < count; ++i) {
- printk ("%.2x ", buf[i]);
- }
- printk ("\n");
+ printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count);
+ for (i = 0; i < count; ++i) {
+ printk ("%.2x ", buf[i]);
}
+ printk ("\n");
#endif
- if (from_user) {
- copy_from_user(bluetooth->write_urb->transfer_buffer, buf, count);
- }
- else {
- memcpy (bluetooth->write_urb->transfer_buffer, buf, count);
- }
-
- /* send the data out the bulk bluetooth */
- bluetooth->write_urb->transfer_buffer_length = count;
+ switch (*buf) {
+ /* First byte indicates the type of packet */
+ case CMD_PKT:
+ /* dbg(__FUNCTION__ "- Send cmd_pkt len:%d", count);*/
+
+ if (in_interrupt()){
+ printk("cmd_pkt from interrupt!\n");
+ return count;
+ }
+
+ new_buffer = kmalloc (count-1, GFP_KERNEL);
+
+ if (!new_buffer) {
+ err (__FUNCTION__ "- out of memory.");
+ return -ENOMEM;
+ }
+
+ if (from_user)
+ copy_from_user (new_buffer, buf+1, count-1);
+ else
+ memcpy (new_buffer, buf+1, count-1);
+
+ bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, new_buffer, count-1);
+
+ /* need to free new_buffer somehow... FIXME */
+ return count;
+
+ case ACL_PKT:
+ current_position = buf;
+ ++current_position;
+ --count;
+ bytes_sent = 0;
+
+ while (count > 0) {
+ urb = NULL;
+
+ /* try to find a free urb in our list */
+ for (i = 0; i < NUM_BULK_URBS; ++i) {
+ if (bluetooth->write_urb_pool[i]->status != -EINPROGRESS) {
+ urb = bluetooth->write_urb_pool[i];
+ break;
+ }
+ }
+ if (urb == NULL) {
+ dbg (__FUNCTION__ " - no free urbs");
+ return bytes_sent;
+ }
+
+ /* free up the last buffer that this urb used */
+ if (urb->transfer_buffer != NULL) {
+ kfree(urb->transfer_buffer);
+ urb->transfer_buffer = NULL;
+ }
+
+ buffer_size = MIN (count, bluetooth->bulk_out_size);
+
+ new_buffer = kmalloc (buffer_size, GFP_KERNEL);
+ if (new_buffer == NULL) {
+ err(__FUNCTION__" no more kernel memory...");
+ return bytes_sent;
+ }
+
+ if (from_user)
+ copy_from_user(new_buffer, current_position, buffer_size);
+ else
+ memcpy (new_buffer, current_position, buffer_size);
+
+ /* build up our urb */
+ FILL_BULK_URB (urb, bluetooth->dev, usb_sndbulkpipe(bluetooth->dev, bluetooth->bulk_out_endpointAddress),
+ new_buffer, buffer_size, bluetooth_write_bulk_callback, bluetooth);
+ urb->transfer_flags |= USB_QUEUE_BULK;
+
+ /* send it down the pipe */
+ status = usb_submit_urb(urb);
+ if (status)
+ dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
+#ifdef BTBUGGYHARDWARE
+ /* A workaround for the stalled data bug */
+ /* May or may not be needed...*/
+ if (count != 0) {
+ udelay(500);
+ }
+#endif
+ current_position += buffer_size;
+ bytes_sent += buffer_size;
+ count -= buffer_size;
+ }
- if (usb_submit_urb(bluetooth->write_urb))
- dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed");
+ return bytes_sent + 1;
+
+ default :
+ dbg(__FUNCTION__" - unsupported (at this time) write type");
+ }
- return count;
+ return 0;
}
@@ -286,21 +480,25 @@ static int bluetooth_write_room (struct tty_struct *tty)
{
struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
int room = 0;
+ int i;
if (!bluetooth) {
return -ENODEV;
}
dbg(__FUNCTION__);
-
+
if (!bluetooth->active) {
dbg (__FUNCTION__ " - device not open");
return -EINVAL;
}
- if (bluetooth->write_urb->status != -EINPROGRESS)
- room = bluetooth->bulk_out_size;
-
+ for (i = 0; i < NUM_BULK_URBS; ++i) {
+ if (bluetooth->write_urb_pool[i]->status != -EINPROGRESS) {
+ room += bluetooth->bulk_out_size;
+ }
+ }
+
dbg(__FUNCTION__ " - returns %d", room);
return room;
}
@@ -310,6 +508,7 @@ static int bluetooth_chars_in_buffer (struct tty_struct *tty)
{
struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
int chars = 0;
+ int i;
if (!bluetooth) {
return -ENODEV;
@@ -320,9 +519,11 @@ static int bluetooth_chars_in_buffer (struct tty_struct *tty)
return -EINVAL;
}
-
- if (bluetooth->write_urb->status == -EINPROGRESS)
- chars = bluetooth->write_urb->transfer_buffer_length;
+ for (i = 0; i < NUM_BULK_URBS; ++i) {
+ if (bluetooth->write_urb_pool[i]->status == -EINPROGRESS) {
+ chars += bluetooth->write_urb_pool[i]->transfer_buffer_length;
+ }
+ }
dbg (__FUNCTION__ " - returns %d", chars);
return chars;
@@ -343,9 +544,9 @@ static void bluetooth_throttle (struct tty_struct * tty)
dbg (__FUNCTION__ " - device not open");
return;
}
-
- /* FIXME!!! */
+ dbg(__FUNCTION__ " unsupported (at this time)");
+
return;
}
@@ -365,9 +566,7 @@ static void bluetooth_unthrottle (struct tty_struct * tty)
return;
}
- /* FIXME!!! */
-
- return;
+ dbg(__FUNCTION__ " unsupported (at this time)");
}
@@ -387,7 +586,6 @@ static int bluetooth_ioctl (struct tty_struct *tty, struct file * file, unsigned
}
/* FIXME!!! */
-
return -ENOIOCTLCMD;
}
@@ -408,59 +606,184 @@ static void bluetooth_set_termios (struct tty_struct *tty, struct termios * old)
}
/* FIXME!!! */
-
+
return;
}
+#ifdef BTBUGGYHARDWARE
+void btusb_enable_bulk_read(struct tty_struct *tty){
+ struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+
+ if (!bluetooth) {
+ return;
+ }
+
+ dbg(__FUNCTION__);
+
+ if (!bluetooth->active) {
+ dbg (__FUNCTION__ " - device not open");
+ return;
+ }
+
+ if (bluetooth->read_urb)
+ if (usb_submit_urb(bluetooth->read_urb))
+ dbg (__FUNCTION__ " - usb_submit_urb(read bulk) failed");
+}
+
+void btusb_disable_bulk_read(struct tty_struct *tty){
+ struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+
+ if (!bluetooth) {
+ return;
+ }
+
+ dbg(__FUNCTION__);
+
+ if (!bluetooth->active) {
+ dbg (__FUNCTION__ " - device not open");
+ return;
+ }
+
+ if ((bluetooth->read_urb) && (bluetooth->read_urb->actual_length))
+ usb_unlink_urb(bluetooth->read_urb);
+}
+#endif
+
+
/*****************************************************************************
* urb callback functions
*****************************************************************************/
+
static void bluetooth_int_callback (struct urb *urb)
{
struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
unsigned char *data = urb->transfer_buffer;
- int i;
+ unsigned int i;
+ unsigned int count = urb->actual_length;
+ unsigned int packet_size;
dbg(__FUNCTION__);
-
+
if (!bluetooth) {
dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
return;
}
if (urb->status) {
- dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+ dbg(__FUNCTION__ " - nonzero int status received: %d", urb->status);
return;
}
+ if (!count) {
+ dbg(__FUNCTION__ " - zero length int");
+ return;
+ }
+
+
#ifdef DEBUG
- if (urb->actual_length) {
- printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", urb->actual_length);
- for (i = 0; i < urb->actual_length; ++i) {
+ if (count) {
+ printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", count);
+ for (i = 0; i < count; ++i) {
printk ("%.2x ", data[i]);
}
printk ("\n");
}
#endif
- /* Don't really know what else to do with this data yet. */
- /* FIXME!!! */
+#ifdef BTBUGGYHARDWARE
+ if ((count >= 2) && (data[0] == 0xFF) && (data[1] == 0x00)) {
+ data += 2;
+ count -= 2;
+ }
+ if (count == 0) {
+ urb->actual_length = 0;
+ return;
+ }
+#endif
+ /* We add a packet type identifier to the beginning of each
+ HCI frame. This makes the data in the tty look like a
+ serial USB devices. Each HCI frame can be broken across
+ multiple URBs so we buffer them until we have a full hci
+ packet */
+
+ if (!bluetooth->int_packet_pos) {
+ bluetooth->int_buffer[0] = EVENT_PKT;
+ bluetooth->int_packet_pos++;
+ }
- return;
+ if (bluetooth->int_packet_pos + count > EVENT_BUFFER_SIZE) {
+ err(__FUNCTION__ " - exceeded EVENT_BUFFER_SIZE");
+ bluetooth->int_packet_pos = 0;
+ return;
+ }
+
+ memcpy (&bluetooth->int_buffer[bluetooth->int_packet_pos],
+ urb->transfer_buffer, count);
+ bluetooth->int_packet_pos += count;
+ urb->actual_length = 0;
+
+ if (bluetooth->int_packet_pos >= EVENT_HDR_SIZE)
+ packet_size = bluetooth->int_buffer[2];
+ else
+ return;
+
+ if (packet_size + EVENT_HDR_SIZE < bluetooth->int_packet_pos) {
+ err(__FUNCTION__ " - packet was too long");
+ bluetooth->int_packet_pos = 0;
+ return;
+ }
+
+ if (packet_size + EVENT_HDR_SIZE == bluetooth->int_packet_pos){
+ for (i = 0; i < bluetooth->int_packet_pos; ++i)
+ tty_insert_flip_char(bluetooth->tty, bluetooth->int_buffer[i], 0);
+ tty_flip_buffer_push(bluetooth->tty);
+
+ bluetooth->int_packet_pos = 0;
+ }
+}
+
+
+static void bluetooth_ctrl_callback (struct urb *urb)
+{
+ struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
+
+ dbg(__FUNCTION__);
+
+ if (!bluetooth) {
+ dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
+ return;
+ }
+
+ if (urb->status) {
+ dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+ return;
+ }
}
static void bluetooth_read_bulk_callback (struct urb *urb)
{
struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
- struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
- int i;
+ unsigned int count = urb->actual_length;
+ unsigned int i;
+ uint packet_size;
+
+#ifdef BTBUGGYHARDWARE
+ if ((count == 4) && (data[0] == 0x00) && (data[1] == 0x00)
+ && (data[2] == 0x00) && (data[3] == 0x00)) {
+ urb->actual_length = 0;
+ if (usb_submit_urb(urb))
+ dbg(__FUNCTION__ " - failed resubmitting read urb");
+
+ return;
+ }
+#endif
dbg(__FUNCTION__);
-
+
if (!bluetooth) {
dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
return;
@@ -471,25 +794,67 @@ static void bluetooth_read_bulk_callback (struct urb *urb)
return;
}
+ if (!count) {
+ dbg(__FUNCTION__ " - zero length read bulk");
+ return;
+ }
+
#ifdef DEBUG
- if (urb->actual_length) {
- printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", urb->actual_length);
- for (i = 0; i < urb->actual_length; ++i) {
+ if (count) {
+ printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", count);
+ for (i = 0; i < count; ++i) {
printk ("%.2x ", data[i]);
}
printk ("\n");
}
#endif
+ /* We add a packet type identifier to the beginning of each
+ HCI frame. This makes the data in the tty look like a
+ serial USB devices. Each HCI frame can be broken across
+ multiple URBs so we buffer them until we have a full hci
+ packet */
+
+ if (!bluetooth->bulk_packet_pos) {
+ bluetooth->bulk_buffer[0] = ACL_PKT;
+ bluetooth->bulk_packet_pos++;
+ }
- tty = bluetooth->tty;
- if (urb->actual_length) {
- for (i = 0; i < urb->actual_length ; ++i) {
- tty_insert_flip_char(tty, data[i], 0);
- }
- tty_flip_buffer_push(tty);
+ if (bluetooth->bulk_packet_pos + count > ACL_BUFFER_SIZE) {
+ err(__FUNCTION__ " - exceeded ACL_BUFFER_SIZE");
+ bluetooth->bulk_packet_pos = 0;
+ if (usb_submit_urb(urb))
+ dbg(__FUNCTION__ " - failed resubmitting read urb");
+ return;
+ }
+
+ memcpy (&bluetooth->bulk_buffer[bluetooth->bulk_packet_pos],
+ urb->transfer_buffer, count);
+ bluetooth->bulk_packet_pos += count;
+ urb->actual_length = 0;
+
+ if (bluetooth->bulk_packet_pos >= ACL_HDR_SIZE) {
+ packet_size = CHAR2INT16(bluetooth->bulk_buffer[4],bluetooth->bulk_buffer[3]);
+ } else {
+ if (usb_submit_urb(urb))
+ dbg(__FUNCTION__ " - failed resubmitting read urb");
+ return;
}
- /* Continue trying to always read */
+ if (packet_size + ACL_HDR_SIZE < bluetooth->bulk_packet_pos) {
+ err(__FUNCTION__ " - packet was too long");
+ bluetooth->bulk_packet_pos = 0;
+ if (usb_submit_urb(urb))
+ dbg(__FUNCTION__ " - failed resubmitting read urb");
+ return;
+ }
+
+ if (packet_size + ACL_HDR_SIZE == bluetooth->bulk_packet_pos) {
+ for (i = 0; i < bluetooth->bulk_packet_pos; ++i)
+ tty_insert_flip_char(bluetooth->tty, bluetooth->bulk_buffer[i], 0);
+ tty_flip_buffer_push(bluetooth->tty);
+ bluetooth->bulk_packet_pos = 0;
+ }
+
if (usb_submit_urb(urb))
dbg(__FUNCTION__ " - failed resubmitting read urb");
@@ -502,7 +867,7 @@ static void bluetooth_write_bulk_callback (struct urb *urb)
struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
dbg(__FUNCTION__);
-
+
if (!bluetooth) {
dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
return;
@@ -513,9 +878,9 @@ static void bluetooth_write_bulk_callback (struct urb *urb)
return;
}
+ /* wake up our little function to let the tty layer know that something happened */
queue_task(&bluetooth->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
-
return;
}
@@ -526,11 +891,11 @@ static void bluetooth_softint(void *private)
struct tty_struct *tty;
dbg(__FUNCTION__);
-
+
if (!bluetooth) {
return;
}
-
+
tty = bluetooth->tty;
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
dbg(__FUNCTION__ " - write wakeup call.");
@@ -549,28 +914,32 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum)
struct usb_endpoint_descriptor *interrupt_in_endpoint[8];
struct usb_endpoint_descriptor *bulk_in_endpoint[8];
struct usb_endpoint_descriptor *bulk_out_endpoint[8];
+ int control_out_endpoint;
+
int minor;
int buffer_size;
int i;
int num_interrupt_in = 0;
int num_bulk_in = 0;
int num_bulk_out = 0;
-
+
/* see if this device has the proper class signature */
if ((dev->descriptor.bDeviceClass != WIRELESS_CLASS_CODE) ||
(dev->descriptor.bDeviceSubClass != RF_SUBCLASS_CODE) ||
(dev->descriptor.bDeviceProtocol != BLUETOOTH_PROGRAMMING_PROTOCOL_CODE)) {
dbg (__FUNCTION__ " - class signature %d, %d, %d did not match",
- dev->descriptor.bDeviceClass, dev->descriptor.bDeviceSubClass,
- dev->descriptor.bDeviceProtocol);
+ dev->descriptor.bDeviceClass, dev->descriptor.bDeviceSubClass,
+ dev->descriptor.bDeviceProtocol);
return NULL;
}
- /* find the endpoints that we need */
interface = &dev->actconfig->interface[ifnum].altsetting[0];
+ control_out_endpoint = interface->bInterfaceNumber;
+
+ /* find the endpoints that we need */
for (i = 0; i < interface->bNumEndpoints; ++i) {
endpoint = &interface->endpoint[i];
-
+
if ((endpoint->bEndpointAddress & 0x80) &&
((endpoint->bmAttributes & 3) == 0x02)) {
/* we found a bulk in endpoint */
@@ -586,7 +955,7 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum)
bulk_out_endpoint[num_bulk_out] = endpoint;
++num_bulk_out;
}
-
+
if ((endpoint->bEndpointAddress & 0x80) &&
((endpoint->bmAttributes & 3) == 0x03)) {
/* we found a interrupt in endpoint */
@@ -595,7 +964,7 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum)
++num_interrupt_in;
}
}
-
+
/* according to the spec, we can only have 1 bulk_in, 1 bulk_out, and 1 interrupt_in endpoints */
if ((num_bulk_in != 1) ||
(num_bulk_out != 1) ||
@@ -603,7 +972,7 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum)
dbg (__FUNCTION__ " - improper number of endpoints. Bluetooth driver not bound.");
return NULL;
}
-
+
MOD_INC_USE_COUNT;
info("USB Bluetooth converter detected");
@@ -620,15 +989,29 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum)
MOD_DEC_USE_COUNT;
return NULL;
}
-
+
memset(bluetooth, 0, sizeof(struct usb_bluetooth));
-
+
bluetooth->magic = USB_BLUETOOTH_MAGIC;
bluetooth->dev = dev;
bluetooth->minor = minor;
bluetooth->tqueue.routine = bluetooth_softint;
bluetooth->tqueue.data = bluetooth;
+ /* record the interface number for the control out */
+ bluetooth->control_out_bInterfaceNum = control_out_endpoint;
+
+ /* create our control out urb pool */
+ for (i = 0; i < NUM_CONTROL_URBS; ++i) {
+ struct urb *urb = usb_alloc_urb(0);
+ if (urb == NULL) {
+ err("No free urbs available");
+ goto probe_error;
+ }
+ urb->transfer_buffer = NULL;
+ bluetooth->control_urb_pool[i] = urb;
+ }
+
/* set up the endpoint information */
endpoint = bulk_in_endpoint[0];
bluetooth->read_urb = usb_alloc_urb (0);
@@ -646,20 +1029,20 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum)
bluetooth->bulk_in_buffer, buffer_size, bluetooth_read_bulk_callback, bluetooth);
endpoint = bulk_out_endpoint[0];
- bluetooth->write_urb = usb_alloc_urb(0);
- if (!bluetooth->write_urb) {
- err("No free urbs available");
- goto probe_error;
- }
- buffer_size = endpoint->wMaxPacketSize;
- bluetooth->bulk_out_size = buffer_size;
- bluetooth->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
- if (!bluetooth->bulk_out_buffer) {
- err("Couldn't allocate bulk_out_buffer");
- goto probe_error;
+ bluetooth->bulk_out_endpointAddress = endpoint->bEndpointAddress;
+
+ /* create our write urb pool */
+ for (i = 0; i < NUM_BULK_URBS; ++i) {
+ struct urb *urb = usb_alloc_urb(0);
+ if (urb == NULL) {
+ err("No free urbs available");
+ goto probe_error;
+ }
+ urb->transfer_buffer = NULL;
+ bluetooth->write_urb_pool[i] = urb;
}
- FILL_BULK_URB(bluetooth->write_urb, dev, usb_sndbulkpipe(dev, endpoint->bEndpointAddress),
- bluetooth->bulk_out_buffer, buffer_size, bluetooth_write_bulk_callback, bluetooth);
+
+ bluetooth->bulk_out_size = endpoint->wMaxPacketSize * 2;
endpoint = interrupt_in_endpoint[0];
bluetooth->interrupt_in_urb = usb_alloc_urb(0);
@@ -680,9 +1063,9 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum)
/* initialize the devfs nodes for this device and let the user know what bluetooths we are bound to */
tty_register_devfs (&bluetooth_tty_driver, 0, minor);
info("Bluetooth converter now attached to ttyBLUE%d (or usb/ttblue/%d for devfs)", minor, minor);
-
+
bluetooth_table[minor] = bluetooth;
-
+
return bluetooth; /* success */
probe_error:
@@ -690,15 +1073,17 @@ probe_error:
usb_free_urb (bluetooth->read_urb);
if (bluetooth->bulk_in_buffer)
kfree (bluetooth->bulk_in_buffer);
- if (bluetooth->write_urb)
- usb_free_urb (bluetooth->write_urb);
- if (bluetooth->bulk_out_buffer)
- kfree (bluetooth->bulk_out_buffer);
if (bluetooth->interrupt_in_urb)
usb_free_urb (bluetooth->interrupt_in_urb);
if (bluetooth->interrupt_in_buffer)
kfree (bluetooth->interrupt_in_buffer);
-
+ for (i = 0; i < NUM_BULK_URBS; ++i)
+ if (bluetooth->write_urb_pool[i])
+ usb_free_urb (bluetooth->write_urb_pool[i]);
+ for (i = 0; i < NUM_CONTROL_URBS; ++i)
+ if (bluetooth->control_urb_pool[i])
+ usb_free_urb (bluetooth->control_urb_pool[i]);
+
bluetooth_table[minor] = NULL;
/* free up any memory that we allocated */
@@ -711,6 +1096,7 @@ probe_error:
static void usb_bluetooth_disconnect(struct usb_device *dev, void *ptr)
{
struct usb_bluetooth *bluetooth = (struct usb_bluetooth *) ptr;
+ int i;
if (bluetooth) {
bluetooth->active = 0;
@@ -721,14 +1107,7 @@ static void usb_bluetooth_disconnect(struct usb_device *dev, void *ptr)
}
if (bluetooth->bulk_in_buffer)
kfree (bluetooth->bulk_in_buffer);
-
- if (bluetooth->write_urb) {
- usb_unlink_urb (bluetooth->write_urb);
- usb_free_urb (bluetooth->write_urb);
- }
- if (bluetooth->bulk_out_buffer)
- kfree (bluetooth->bulk_out_buffer);
-
+
if (bluetooth->interrupt_in_urb) {
usb_unlink_urb (bluetooth->interrupt_in_urb);
usb_free_urb (bluetooth->interrupt_in_urb);
@@ -737,6 +1116,26 @@ static void usb_bluetooth_disconnect(struct usb_device *dev, void *ptr)
kfree (bluetooth->interrupt_in_buffer);
tty_unregister_devfs (&bluetooth_tty_driver, bluetooth->minor);
+
+ if (bluetooth->tty)
+ tty_hangup(bluetooth->tty);
+
+ for (i = 0; i < NUM_BULK_URBS; ++i) {
+ if (bluetooth->write_urb_pool[i]) {
+ usb_unlink_urb (bluetooth->write_urb_pool[i]);
+ if (bluetooth->write_urb_pool[i]->transfer_buffer)
+ kfree (bluetooth->write_urb_pool[i]->transfer_buffer);
+ usb_free_urb (bluetooth->write_urb_pool[i]);
+ }
+ }
+ for (i = 0; i < NUM_CONTROL_URBS; ++i) {
+ if (bluetooth->control_urb_pool[i]) {
+ usb_unlink_urb (bluetooth->control_urb_pool[i]);
+ if (bluetooth->control_urb_pool[i]->transfer_buffer)
+ kfree (bluetooth->control_urb_pool[i]->transfer_buffer);
+ usb_free_urb (bluetooth->control_urb_pool[i]);
+ }
+ }
info("Bluetooth converter now disconnected from ttyBLUE%d", bluetooth->minor);
@@ -748,7 +1147,7 @@ static void usb_bluetooth_disconnect(struct usb_device *dev, void *ptr)
} else {
info("device disconnected");
}
-
+
MOD_DEC_USE_COUNT;
}
@@ -763,12 +1162,12 @@ static struct tty_driver bluetooth_tty_driver = {
type: TTY_DRIVER_TYPE_SERIAL,
subtype: SERIAL_TYPE_NORMAL,
flags: TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
-
+
refcount: &bluetooth_refcount,
table: bluetooth_tty,
termios: bluetooth_termios,
termios_locked: bluetooth_termios_locked,
-
+
open: bluetooth_open,
close: bluetooth_close,
write: bluetooth_write,
@@ -808,7 +1207,7 @@ int usb_bluetooth_init(void)
err("usb_register failed for the USB bluetooth driver. Error number %d", result);
return -1;
}
-
+
return 0;
}
diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
index 5e7a5a23b..aee6b420e 100644
--- a/drivers/usb/storage/protocol.c
+++ b/drivers/usb/storage/protocol.c
@@ -1,6 +1,6 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: protocol.c,v 1.2 2000/07/19 17:21:39 groovyjava Exp $
+ * $Id: protocol.c,v 1.4 2000/08/01 22:01:19 mdharm Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -50,9 +50,58 @@
#include "transport.h"
/***********************************************************************
+ * Helper routines
+ ***********************************************************************/
+
+/* Fix-up the return data from an INQUIRY command to show
+ * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
+ */
+void fix_inquiry_data(Scsi_Cmnd *srb)
+{
+ unsigned char *data_ptr;
+
+ /* verify that it's an INQUIRY command */
+ if (srb->cmnd[0] != INQUIRY)
+ return;
+
+ US_DEBUGP("Fixing INQUIRY data to show SCSI rev 2\n");
+
+ /* find the location of the data */
+ if (srb->use_sg) {
+ struct scatterlist *sg;
+
+ sg = (struct scatterlist *) srb->request_buffer;
+ data_ptr = (unsigned char *) sg[0].address;
+ } else
+ data_ptr = (unsigned char *)srb->request_buffer;
+
+ /* Change the SCSI revision number */
+ data_ptr[2] |= 0x2;
+}
+
+/***********************************************************************
* Protocol routines
***********************************************************************/
+void usb_stor_qic157_command(Scsi_Cmnd *srb, struct us_data *us)
+{
+ /* Pad the ATAPI command with zeros
+ * NOTE: This only works because a Scsi_Cmnd struct field contains
+ * a unsigned char cmnd[12], so we know we have storage available
+ */
+ for (; srb->cmd_len<12; srb->cmd_len++)
+ srb->cmnd[srb->cmd_len] = 0;
+
+ /* set command length to 12 bytes */
+ srb->cmd_len = 12;
+
+ /* send the command to the transport layer */
+ usb_stor_invoke_transport(srb, us);
+
+ /* fix the INQUIRY data if necessary */
+ fix_inquiry_data(srb);
+}
+
void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
{
int old_cmnd = 0;
@@ -65,7 +114,6 @@ void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
*/
/* Pad the ATAPI command with zeros */
-
for (; srb->cmd_len<12; srb->cmd_len++)
srb->cmnd[srb->cmd_len] = 0;
@@ -125,12 +173,8 @@ void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
if ((old_cmnd == MODE_SENSE) && (srb->result == GOOD))
usb_stor_scsiSense10to6(srb);
- /* Fix-up the return data from an INQUIRY command to show
- * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
- */
- if (srb->cmnd[0] == INQUIRY) {
- ((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
- }
+ /* fix the INQUIRY data if necessary */
+ fix_inquiry_data(srb);
}
@@ -224,12 +268,8 @@ void usb_stor_ufi_command(Scsi_Cmnd *srb, struct us_data *us)
if ((old_cmnd == MODE_SENSE) && (srb->result == GOOD))
usb_stor_scsiSense10to6(srb);
- /* Fix-up the return data from an INQUIRY command to show
- * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
- */
- if (srb->cmnd[0] == INQUIRY) {
- ((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
- }
+ /* Fix the data for an INQUIRY, if necessary */
+ fix_inquiry_data(srb);
}
void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
@@ -300,10 +340,7 @@ void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
/* send the command to the transport layer */
usb_stor_invoke_transport(srb, us);
- /* fix the results of an INQUIRY */
- if (srb->cmnd[0] == INQUIRY) {
- US_DEBUGP("Fixing INQUIRY data, setting SCSI rev to 2\n");
- ((unsigned char*)us->srb->request_buffer)[2] |= 2;
- }
+ /* fix the INQUIRY data if necessary */
+ fix_inquiry_data(srb);
}
diff --git a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h
index 1a343af41..239d37983 100644
--- a/drivers/usb/storage/protocol.h
+++ b/drivers/usb/storage/protocol.h
@@ -1,7 +1,7 @@
/* Driver for USB Mass Storage compliant devices
* Protocol Functions Header File
*
- * $Id: protocol.h,v 1.1 2000/06/27 01:25:28 mdharm Exp $
+ * $Id: protocol.h,v 1.2 2000/08/01 22:01:19 mdharm Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -57,6 +57,7 @@
#define US_SC_MAX US_SC_SCSI
extern void usb_stor_ATAPI_command(Scsi_Cmnd*, struct us_data*);
+extern void usb_stor_qic157_command(Scsi_Cmnd*, struct us_data*);
extern void usb_stor_ufi_command(Scsi_Cmnd*, struct us_data*);
extern void usb_stor_transparent_scsi_command(Scsi_Cmnd*, struct us_data*);
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 25328669b..7517d63bc 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -1,13 +1,14 @@
/* Driver for USB Mass Storage compliant devices
* SCSI layer glue code
*
- * $Id: scsiglue.c,v 1.6 2000/07/25 23:04:47 mdharm Exp $
+ * $Id: scsiglue.c,v 1.7 2000/07/28 20:33:18 gowdy Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* Developed with the assistance of:
* (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
+ * (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov)
*
* Initial work by:
* (c) 1999 Michael Gee (michael@linuxspecific.com)
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
index 275712961..6bf9f1477 100644
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -44,7 +44,7 @@ extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
unsigned int len, unsigned int *act_len);
-#define short_pack(b1,b2) ( ((u16)(b1)) | ( ((u16)(b2))<<8 ) )
+#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )
#define LSB_of(s) ((s)&0xFF)
#define MSB_of(s) ((s)>>8)
@@ -132,7 +132,7 @@ static int sddr09_send_control(struct us_data *us,
static int sddr09_raw_bulk(struct us_data *us,
int direction,
unsigned char *data,
- unsigned short len) {
+ unsigned int len) {
int result;
int act_len;
@@ -196,64 +196,38 @@ static int sddr09_raw_bulk(struct us_data *us,
*/
static int sddr09_bulk_transport(struct us_data *us,
- unsigned char *command,
- unsigned short command_len,
int direction,
unsigned char *data,
- unsigned short len,
+ unsigned int len,
int use_sg) {
int result = USB_STOR_TRANSPORT_GOOD;
int transferred = 0;
- unsigned char execute[8] = {
- 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
int i;
struct scatterlist *sg;
char string[64];
-/*
- if (command_len != 0) {
-
- // Fix up the command's data length
- command[6] = len&0xFF;
- command[7] = (len>>8)&0xFF;
-
- result = sddr09_send_control(us,
- execute,
- command,
- command_len);
-
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
- }
-*/
if (len==0)
return USB_STOR_TRANSPORT_GOOD;
- /* transfer the data payload for the command, if there is any */
-
-
- if (command_len != 0)
- direction = (command[0]&0x80) ? SCSI_DATA_READ :
- SCSI_DATA_WRITE;
+ /* transfer the data */
if (direction == SCSI_DATA_WRITE) {
/* Debug-print the first 48 bytes of the write transfer */
if (!use_sg) {
- string[0] = 0;
+ strcpy(string, "wr: ");
for (i=0; i<len && i<48; i++) {
sprintf(string+strlen(string), "%02X ",
data[i]);
if ((i%16)==15) {
US_DEBUGP("%s\n", string);
- string[0] = 0;
+ strcpy(string, "wr: ");
}
}
- if (string[0]!=0)
+ if ((i%16)!=0)
US_DEBUGP("%s\n", string);
}
}
@@ -278,6 +252,25 @@ static int sddr09_bulk_transport(struct us_data *us,
}
}
+ if (direction == SCSI_DATA_READ) {
+
+ /* Debug-print the first 48 bytes of the read transfer */
+
+ if (!use_sg) {
+ strcpy(string, "rd: ");
+ for (i=0; i<len && i<48; i++) {
+ sprintf(string+strlen(string), "%02X ",
+ data[i]);
+ if ((i%16)==15) {
+ US_DEBUGP("%s\n", string);
+ strcpy(string, "rd: ");
+ }
+ }
+ if ((i%16)!=0)
+ US_DEBUGP("%s\n", string);
+ }
+ }
+
return result;
}
@@ -289,45 +282,142 @@ int sddr09_read_data(struct us_data *us,
int result;
unsigned char command[12] = {
- 0xe8, 0x20, MSB_of(address>>16),
- LSB_of(address>>16), MSB_of(address&0xFFFF),
- LSB_of(address&0xFFFF), 0, 0, 0, 0,
- MSB_of(sectors), LSB_of(sectors)
+ 0xe8, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
+ struct sddr09_card_info *info = (struct sddr09_card_info *)us->extra;
+ unsigned int lba;
+ unsigned int pba;
+ unsigned short page;
+ unsigned short pages;
+ unsigned char *buffer = NULL;
+ unsigned char *ptr;
+ struct scatterlist *sg = NULL;
+ int i;
+ int len;
+ int transferred;
- result = sddr09_send_control(us,
- usb_sndctrlpipe(us->pusb_dev,0),
- 0,
- 0x41,
- 0,
- 0,
- command,
- 12);
+ // If we're using scatter-gather, we have to create a new
+ // buffer to read all of the data in first, since a
+ // scatter-gather buffer could in theory start in the middle
+ // of a page, which would be bad. A developer who wants a
+ // challenge might want to write a limited-buffer
+ // version of this code.
+
+ len = sectors*info->pagesize;
+
+ if (use_sg) {
+ sg = (struct scatterlist *)content;
+ buffer = kmalloc(len, GFP_KERNEL);
+ if (buffer == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
+ ptr = buffer;
+ } else
+ ptr = content;
+
+ // Figure out the initial LBA and page
+
+ pba = (address/info->pagesize)>>4;
+ lba = info->pba_to_lba[pba];
+ page = (address/info->pagesize)&0x0F;
+
+ // This could be made much more efficient by checking for
+ // contiguous LBA's. Another exercise left to the student.
+
+ while (sectors>0) {
+
+ pba = info->lba_to_pba[lba];
+
+ // Read as many sectors as possible in this block
+
+ pages = 0x10-page;
+ if (pages > sectors)
+ pages = sectors;
+
+ US_DEBUGP("Read %01X pages, from PBA %04X"
+ " (LBA %04X) page %01X\n",
+ pages, pba, lba, page);
+
+ address = ((pba<<4)+page)*info->pagesize;
+
+ // Unlike in the documentation, the address is in
+ // words of 2 bytes.
+
+ command[2] = MSB_of(address>>17);
+ command[3] = LSB_of(address>>17);
+ command[4] = MSB_of((address>>1)&0xFFFF);
+ command[5] = LSB_of((address>>1)&0xFFFF);
+
+ command[10] = MSB_of(pages);
+ command[11] = LSB_of(pages);
+
+ result = sddr09_send_control(us,
+ usb_sndctrlpipe(us->pusb_dev,0),
+ 0,
+ 0x41,
+ 0,
+ 0,
+ command,
+ 12);
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
+ US_DEBUGP("Result for send_control in read_data %d\n",
+ result);
+
+ if (result != USB_STOR_TRANSPORT_GOOD) {
+ if (use_sg)
+ kfree(buffer);
+ return result;
+ }
- result = sddr09_bulk_transport(us,
- NULL, 0, SCSI_DATA_READ, content,
- sectors*512, use_sg);
+ result = sddr09_bulk_transport(us,
+ SCSI_DATA_READ, ptr,
+ pages*info->pagesize, 0);
- return result;
+ if (result != USB_STOR_TRANSPORT_GOOD) {
+ if (use_sg)
+ kfree(buffer);
+ return result;
+ }
+
+ page = 0;
+ lba++;
+ sectors -= pages;
+ ptr += pages*info->pagesize;
+ }
+
+ if (use_sg) {
+ transferred = 0;
+ for (i=0; i<use_sg && transferred<len; i++) {
+ memcpy(sg[i].address, buffer+transferred,
+ len-transferred > sg[i].length ?
+ sg[i].length : len-transferred);
+ transferred += sg[i].length;
+ }
+ kfree(buffer);
+ }
+
+ return USB_STOR_TRANSPORT_GOOD;
}
int sddr09_read_control(struct us_data *us,
unsigned long address,
- unsigned short sectors,
+ unsigned short blocks,
unsigned char *content,
int use_sg) {
+ // Unlike in the documentation, the last two bytes are the
+ // number of blocks, not sectors.
+
int result;
unsigned char command[12] = {
0xe8, 0x21, MSB_of(address>>16),
LSB_of(address>>16), MSB_of(address&0xFFFF),
LSB_of(address&0xFFFF), 0, 0, 0, 0,
- MSB_of(sectors), LSB_of(sectors)
+ MSB_of(blocks), LSB_of(blocks)
};
+ US_DEBUGP("Read control address %08X blocks %04X\n",
+ address, blocks);
+
result = sddr09_send_control(us,
usb_sndctrlpipe(us->pusb_dev,0),
0,
@@ -336,13 +426,19 @@ int sddr09_read_control(struct us_data *us,
0,
command,
12);
+
+ US_DEBUGP("Result for send_control in read_control %d\n",
+ result);
if (result != USB_STOR_TRANSPORT_GOOD)
return result;
result = sddr09_bulk_transport(us,
- NULL, 0, SCSI_DATA_READ, content,
- sectors*64, use_sg);
+ SCSI_DATA_READ, content,
+ blocks*0x40, use_sg);
+
+ US_DEBUGP("Result for bulk read in read_control %d\n",
+ result);
return result;
}
@@ -373,7 +469,7 @@ int sddr09_read_deviceID(struct us_data *us,
return result;
result = sddr09_bulk_transport(us,
- NULL, 0, SCSI_DATA_READ, content,
+ SCSI_DATA_READ, content,
64, 0);
*manufacturerID = content[0];
@@ -389,7 +485,6 @@ int sddr09_read_status(struct us_data *us,
unsigned char command[12] = {
0xec, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
- unsigned char content[2];
result = sddr09_send_control(us,
usb_sndctrlpipe(us->pusb_dev,0),
@@ -404,7 +499,7 @@ int sddr09_read_status(struct us_data *us,
return result;
result = sddr09_bulk_transport(us,
- NULL, 0, SCSI_DATA_READ, status,
+ SCSI_DATA_READ, status,
1, 0);
return result;
@@ -429,6 +524,154 @@ int sddr09_reset(struct us_data *us) {
return result;
}
+unsigned long sddr09_get_capacity(struct us_data *us,
+ unsigned int *pagesize) {
+
+ unsigned char manufacturerID;
+ unsigned char deviceID;
+ int result;
+
+ US_DEBUGP("Reading capacity...\n");
+
+ result = sddr09_read_deviceID(us,
+ &manufacturerID,
+ &deviceID);
+
+ US_DEBUGP("Result of read_deviceID is %d\n",
+ result);
+
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ return 0;
+
+ US_DEBUGP("Device ID = %02X\n", deviceID);
+ US_DEBUGP("Manuf ID = %02X\n", manufacturerID);
+
+ *pagesize = 512;
+
+ switch (deviceID) {
+
+ case 0x6e: // 1MB
+ case 0xe8:
+ case 0xec:
+ *pagesize = 256;
+ return 0x00100000;
+
+ case 0x5d: // 2MB
+ case 0xea:
+ case 0x64:
+ if (deviceID!=0x5D)
+ *pagesize = 256;
+ return 0x00200000;
+
+ case 0xe3: // 4MB
+ case 0xe5:
+ case 0x6b:
+ case 0xd5:
+ return 0x00400000;
+
+ case 0xe6: // 8MB
+ case 0xd6:
+ return 0x00800000;
+
+ case 0x73: // 16MB
+ return 0x01000000;
+
+ case 0x75: // 32MB
+ return 0x02000000;
+
+ default: // unknown
+ return 0;
+
+ }
+}
+
+int sddr09_read_map(struct us_data *us) {
+
+ unsigned char *control;
+ struct sddr09_card_info *info = (struct sddr09_card_info *)(us->extra);
+ int numblocks;
+ int i;
+ unsigned char *ptr;
+ unsigned short lba;
+ unsigned char parity;
+ unsigned char fast_parity[16] = {
+ 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0
+ };
+ int result;
+
+ if (!info->capacity)
+ return -1;
+
+ /* read 64 (2^6) bytes for every block (8192 (2^13) bytes)
+ of capacity:
+ 64*(capacity/8192) = capacity*(2^6)*(2^-13) =
+ capacity*2^(6-13) = capacity*(2^-7)
+ */
+
+ control = kmalloc(info->capacity>>7, GFP_KERNEL);
+
+
+ numblocks = info->capacity>>13;
+
+ if ( (result = sddr09_read_control(us, 0, numblocks,
+ control, 0)) !=
+ USB_STOR_TRANSPORT_GOOD) {
+ kfree(control);
+ return -1;
+ }
+
+
+
+ if (info->lba_to_pba)
+ kfree(info->lba_to_pba);
+ if (info->pba_to_lba)
+ kfree(info->pba_to_lba);
+ info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_KERNEL);
+ info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_KERNEL);
+ memset(info->lba_to_pba, 0, numblocks*sizeof(int));
+ memset(info->pba_to_lba, 0, numblocks*sizeof(int));
+
+ for (i=0; i<numblocks; i++) {
+ ptr = control+64*i;
+ if (ptr[0]!=0xFF || ptr[1]!=0xFF || ptr[2]!=0xFF ||
+ ptr[3]!=0xFF || ptr[4]!=0xFF || ptr[5]!=0xFF)
+ continue;
+ if ((ptr[6]>>4)!=0x01)
+ continue;
+
+ /* ensure even parity */
+
+ lba = short_pack(ptr[7], ptr[6]);
+ parity = 1; // the parity of 0x1000
+ parity ^= fast_parity[lba & 0x000F];
+ parity ^= fast_parity[(lba>>4) & 0x000F];
+ parity ^= fast_parity[(lba>>8) & 0x000F];
+
+ if (parity) { /* bad parity bit */
+ US_DEBUGP("Bad parity in LBA for block %04X\n", i);
+ continue;
+ }
+
+ lba = (lba&0x07FF)>>1;
+
+ if (lba>=numblocks) {
+ US_DEBUGP("Bad LBA %04X for block %04X\n", lba, i);
+ continue;
+ }
+
+ if (i<0x10)
+ US_DEBUGP("LBA %04X <-> PBA %04X\n",
+ lba, i);
+
+ info->pba_to_lba[i] = lba;
+ info->lba_to_pba[lba] = i;
+ }
+
+ kfree(control);
+ return 0;
+}
+
/*
static int init_sddr09(struct us_data *us) {
@@ -477,15 +720,24 @@ static int init_sddr09(struct us_data *us) {
}
*/
+void sddr09_card_info_destructor(void *extra) {
+ struct sddr09_card_info *info = (struct sddr09_card_info *)extra;
+
+ if (!extra)
+ return;
+
+ if (info->lba_to_pba)
+ kfree(info->lba_to_pba);
+ if (info->pba_to_lba)
+ kfree(info->pba_to_lba);
+}
+
/*
* Transport for the Sandisk SDDR-09
*/
int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
{
int result;
- unsigned char send_scsi_command[8] = {
- 0x41, 0, 0, 0, 0, 0, 0, 0
- };
int i;
char string[64];
unsigned char inquiry_response[36] = {
@@ -495,9 +747,16 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
'e', ' ', 'S', 'D', 'D', 'R', '0', '9',
' ', ' ', ' ', ' '
};
- unsigned char deviceID;
- unsigned char manufacturerID;
+ unsigned char mode_page_01[12] = {
+ 0x01, 0x0a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
unsigned char *ptr;
+ unsigned long capacity;
+ unsigned int lba;
+ unsigned int pba;
+ unsigned int page;
+ unsigned short pages;
+ struct sddr09_card_info *info = (struct sddr09_card_info *)(us->extra);
/*
if (us->flags & US_FL_NEED_INIT) {
@@ -507,85 +766,116 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
}
*/
+ if (!us->extra) {
+ us->extra = kmalloc(
+ sizeof(struct sddr09_card_info), GFP_KERNEL);
+ memset(us->extra, 0, sizeof(struct sddr09_card_info));
+ us->extra_destructor = sddr09_card_info_destructor;
+ }
+
ptr = (unsigned char *)srb->request_buffer;
/* Dummy up a response for INQUIRY since SDDR09 doesn't
respond to INQUIRY commands */
if (srb->cmnd[0] == INQUIRY) {
- memcpy(srb->request_buffer, inquiry_response, 36);
+ memcpy(ptr, inquiry_response, 36);
return USB_STOR_TRANSPORT_GOOD;
}
if (srb->cmnd[0] == READ_CAPACITY) {
- US_DEBUGP("Reading capacity...\n");
+ capacity = sddr09_get_capacity(us, &info->pagesize);
+ info->capacity = capacity;
- result = sddr09_read_deviceID(us,
- &manufacturerID,
- &deviceID);
+ // Last page in the card
- US_DEBUGP("Result of read_deviceID is %d\n",
- result);
+ capacity /= info->pagesize;
+ capacity--;
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
+ ptr[0] = MSB_of(capacity>>16);
+ ptr[1] = LSB_of(capacity>>16);
+ ptr[2] = MSB_of(capacity&0xFFFF);
+ ptr[3] = LSB_of(capacity&0xFFFF);
- US_DEBUGP("Device ID = %02X\n", deviceID);
- US_DEBUGP("Manuf ID = %02X\n", manufacturerID);
-
- ptr[0] = 0;
- ptr[1] = 0;
- ptr[2] = 0;
- ptr[3] = 0;
-
- switch (deviceID) {
-
- case 0x6e: // 1MB
- case 0xe8:
- case 0xec:
- ptr[4] = 0;
- ptr[5] = 0x10;
- break;
-
- case 0xea: // 2MB
- case 0x64:
- case 0x5d:
- ptr[4] = 0;
- ptr[5] = 0x20;
- break;
-
- case 0xe3: // 4MB
- case 0xe5:
- case 0x6b:
- case 0xd5:
- ptr[4] = 0;
- ptr[5] = 0x40;
- break;
-
- case 0xe6: // 8MB
- case 0xd6:
- ptr[4] = 0;
- ptr[5] = 0x80;
- break;
-
- case 0x75: // 32MB
- ptr[4] = 0x02;
- ptr[5] = 0;
- break;
-
- default: // unknown
- ptr[4] = 0;
- ptr[5] = 0;
+ // The page size
- }
+ ptr[4] = MSB_of(info->pagesize>>16);
+ ptr[5] = LSB_of(info->pagesize>>16);
+ ptr[6] = MSB_of(info->pagesize&0xFFFF);
+ ptr[7] = LSB_of(info->pagesize&0xFFFF);
- ptr[6] = 0;
- ptr[7] = 0;
+ sddr09_read_map(us);
return USB_STOR_TRANSPORT_GOOD;
}
+ if (srb->cmnd[0] == MODE_SENSE) {
+
+ // Read-write error recovery page: there needs to
+ // be a check for write-protect here
+
+ if ( (srb->cmnd[2] & 0x3F) == 0x01 ) {
+ if (ptr==NULL || srb->request_bufflen<12)
+ return USB_STOR_TRANSPORT_ERROR;
+ memcpy(ptr, mode_page_01, 12);
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ // FIXME: sense buffer?
+
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ if (srb->cmnd[0] == READ_10) {
+
+ page = short_pack(srb->cmnd[3], srb->cmnd[2]);
+ page <<= 16;
+ page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
+ pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
+
+ // convert page to block and page-within-block
+
+ lba = page>>4;
+ page = page&0x0F;
+
+ // locate physical block corresponding to logical block
+
+ if (lba>=(info->capacity>>13)) {
+
+ // FIXME: sense buffer?
+
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ pba = info->lba_to_pba[lba];
+
+ // if pba is 0, either it's really 0, in which case
+ // the pba-to-lba map for pba 0 will be the lba,
+ // or that lba doesn't exist.
+
+ if (pba==0 && info->pba_to_lba[0] != lba) {
+
+ // FIXME: sense buffer?
+
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ US_DEBUGP("READ_10: read block %04X (LBA %04X) page %01X"
+ " pages %d\n",
+ pba, lba, page, pages);
+
+ return sddr09_read_data(us,
+ ((pba<<4)+page)*info->pagesize, pages,
+ ptr, srb->use_sg);
+ }
+
+ // Pass TEST_UNIT_READY and REQUEST_SENSE through
+
+ if (srb->cmnd[0] != TEST_UNIT_READY &&
+ srb->cmnd[0] != REQUEST_SENSE)
+ return USB_STOR_TRANSPORT_ERROR; // FIXME: sense buffer?
+
for (; srb->cmd_len<12; srb->cmd_len++)
srb->cmnd[srb->cmd_len] = 0;
@@ -622,7 +912,7 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
srb->request_bufflen);
result = sddr09_bulk_transport(us,
- NULL, 0, srb->sc_data_direction,
+ srb->sc_data_direction,
srb->request_buffer,
srb->request_bufflen, srb->use_sg);
diff --git a/drivers/usb/storage/sddr09.h b/drivers/usb/storage/sddr09.h
index 76a749528..ecd9b7611 100644
--- a/drivers/usb/storage/sddr09.h
+++ b/drivers/usb/storage/sddr09.h
@@ -28,4 +28,11 @@
extern int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us);
+struct sddr09_card_info {
+ unsigned long capacity; /* Size of card in bytes */
+ int pagesize; /* Size of page in bytes */
+ int *lba_to_pba; /* logical to physical map */
+ int *pba_to_lba; /* physical to logical map */
+};
+
#endif
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 69dfcfde8..a0fb2407c 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -1,6 +1,6 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: transport.c,v 1.4 2000/07/25 23:04:47 mdharm Exp $
+ * $Id: transport.c,v 1.5 2000/07/28 22:40:20 mdharm Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -717,6 +717,8 @@ int usb_stor_Bulk_max_lun(struct us_data *us)
return 0;
}
+int usb_stor_Bulk_reset(struct us_data *us);
+
int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
{
struct bulk_cb_wrap bcb;
@@ -820,7 +822,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
}
/* check bulk status */
- US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n",
+ US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n",
le32_to_cpu(bcs.Signature), bcs.Tag,
bcs.Residue, bcs.Status);
if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) ||
@@ -842,6 +844,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
case US_BULK_STAT_PHASE:
/* phase error */
+ usb_stor_Bulk_reset(us);
return USB_STOR_TRANSPORT_ERROR;
}
@@ -883,11 +886,15 @@ int usb_stor_CB_reset(struct us_data *us)
return 0;
}
-/* FIXME: Does this work? */
+/* This issues a Bulk-only Reset to the device in question, including
+ * clearing the subsequent endpoint halts that may occur.
+ */
int usb_stor_Bulk_reset(struct us_data *us)
{
int result;
+ US_DEBUGP("Bulk reset requested\n");
+
result = usb_control_msg(us->pusb_dev,
usb_sndctrlpipe(us->pusb_dev,0),
US_BULK_RESET_REQUEST,
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index c82d7e914..fc70bc72a 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -1,6 +1,6 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: usb.c,v 1.14 2000/07/27 14:42:43 groovyjava Exp $
+ * $Id: usb.c,v 1.16 2000/08/01 22:01:19 mdharm Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -685,13 +685,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
case US_SC_QIC:
ss->protocol_name = "QIC-157";
- US_DEBUGP("Sorry, device not supported. Please\n");
- US_DEBUGP("contact mdharm-usb@one-eyed-alien.net\n");
- US_DEBUGP("if you see this message.\n");
- up(&us_list_semaphore);
- kfree(ss->current_urb);
- kfree(ss);
- return NULL;
+ ss->proto_handler = usb_stor_qic157_command;
break;
case US_SC_8070:
@@ -862,6 +856,16 @@ void __exit usb_stor_exit(void)
/* Now that scsi_unregister_module is done with the host
* template, we can free the us_data structure (the host
* template is inline in this structure). */
+
+ /* If there's extra data in the us_data structure then
+ * free that first */
+
+ if (us_list->extra) {
+ if (us_list->extra_destructor)
+ (*us_list->extra_destructor)(
+ us_list->extra);
+ kfree(us_list->extra);
+ }
kfree (us_list);
/* advance the list pointer */
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index 8c7008fa9..b376d39ee 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -1,7 +1,7 @@
/* Driver for USB Mass Storage compliant devices
* Main Header File
*
- * $Id: usb.h,v 1.3 2000/07/20 01:14:56 mdharm Exp $
+ * $Id: usb.h,v 1.4 2000/07/28 20:14:49 groovyjava Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -176,6 +176,8 @@ struct us_data {
/* mutual exclusion structures */
struct semaphore notify; /* thread begin/end */
struct semaphore queue_exclusion; /* to protect data structs */
+ void *extra; /* Any extra data */
+ void (*extra_destructor)(void *); /* extra data destructor */
};
/* The list of structures and the protective lock for them */
diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
index e82fa78a0..bd721cba2 100644
--- a/drivers/usb/usb-uhci.c
+++ b/drivers/usb/usb-uhci.c
@@ -1,10 +1,10 @@
/*
* Universal Host Controller Interface driver for USB (take II).
*
- * (c) 1999 Georg Acher, acher@in.tum.de (executive slave) (base guitar)
- * Deti Fliegl, deti@fliegl.de (executive slave) (lead voice)
- * Thomas Sailer, sailer@ife.ee.ethz.ch (chief consultant) (cheer leader)
- * Roman Weissgaerber, weissg@vienna.at (virt root hub) (studio porter)
+ * (c) 1999-2000 Georg Acher, acher@in.tum.de (executive slave) (base guitar)
+ * Deti Fliegl, deti@fliegl.de (executive slave) (lead voice)
+ * Thomas Sailer, sailer@ife.ee.ethz.ch (chief consultant) (cheer leader)
+ * Roman Weissgaerber, weissg@vienna.at (virt root hub) (studio porter)
*
* HW-initalization based on material of
*
@@ -12,7 +12,7 @@
* (C) Copyright 1999 Johannes Erdfelt
* (C) Copyright 1999 Randy Dunlap
*
- * $Id: usb-uhci.c,v 1.232 2000/06/11 13:18:30 acher Exp $
+ * $Id: usb-uhci.c,v 1.236 2000/08/02 20:28:28 acher Exp $
*/
#include <linux/config.h>
@@ -48,7 +48,7 @@
/* This enables an extra UHCI slab for memory debugging */
#define DEBUG_SLAB
-#define VERSTR "$Revision: 1.232 $ time " __TIME__ " " __DATE__
+#define VERSTR "$Revision: 1.236 $ time " __TIME__ " " __DATE__
#include <linux/usb.h>
#include "usb-uhci.h"
@@ -791,7 +791,7 @@ _static int uhci_submit_bulk_urb (urb_t *urb, urb_t *bulk_urb)
char *data;
unsigned int pipe = urb->pipe;
int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
- int info, len;
+ int info, len, last;
int depth_first=USE_BULK_DEPTH_FIRST; // UHCI descriptor chasing method
urb_priv_t *upriv, *bpriv;
@@ -888,13 +888,15 @@ _static int uhci_submit_bulk_urb (urb_t *urb, urb_t *bulk_urb)
data += pktsze;
len -= pktsze;
- if (!len)
+ last = (len == 0 && (usb_pipein(pipe) || pktsze < maxsze || (urb->transfer_flags & USB_DISABLE_SPD)));
+
+ if (last)
td->hw.td.status |= TD_CTRL_IOC; // last one generates INT
insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);
usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
- } while (len > 0);
+ } while (!last);
list_add (&qh->desc_list, &urb_priv->desc_list);
@@ -1036,11 +1038,18 @@ _static int uhci_unlink_urb_sync (uhci_t *s, urb_t *urb)
spin_lock_irqsave (&s->urb_list_lock, flags);
+ if (!in_interrupt()) // shouldn't be called from interrupt at all...
+ spin_lock(&urb->lock);
+
if (urb->status == -EINPROGRESS) {
// URB probably still in work
dequeue_urb (s, urb);
uhci_switch_timer_int(s);
s->unlink_urb_done=1;
+
+ if (!in_interrupt())
+ spin_unlock(&urb->lock);
+
spin_unlock_irqrestore (&s->urb_list_lock, flags);
urb->status = -ENOENT; // mark urb as killed
@@ -1076,10 +1085,13 @@ _static int uhci_unlink_urb_sync (uhci_t *s, urb_t *urb)
urb->complete ((struct urb *) urb);
}
usb_dec_dev_use (urb->dev);
- return 0;
}
- else
+ else {
+ if (!in_interrupt())
+ spin_unlock(&urb->lock);
spin_unlock_irqrestore (&s->urb_list_lock, flags);
+ }
+
return 0;
}
/*-------------------------------------------------------------------*/
@@ -1198,9 +1210,10 @@ _static int uhci_unlink_urb_async (uhci_t *s,urb_t *urb)
break;
}
((urb_priv_t*)urb->hcpriv)->started = UHCI_GET_CURRENT_FRAME(s);
+ return -EINPROGRESS; // completion will follow
}
- return -EINPROGRESS;
+ return 0; // URB already dead
}
/*-------------------------------------------------------------------*/
_static int uhci_unlink_urb (urb_t *urb)
@@ -1222,9 +1235,20 @@ _static int uhci_unlink_urb (urb_t *urb)
if (urb->transfer_flags & USB_ASYNC_UNLINK) {
int ret;
- spin_lock_irqsave (&s->urb_list_lock, flags);
+ spin_lock_irqsave (&s->urb_list_lock, flags);
+
+ // The URB needs to be locked if called outside completion context
+
+ if (!in_interrupt())
+ spin_lock(&urb->lock);
+
ret = uhci_unlink_urb_async(s, urb);
- spin_unlock_irqrestore (&s->urb_list_lock, flags);
+
+ if (!in_interrupt())
+ spin_unlock(&urb->lock);
+
+ spin_unlock_irqrestore (&s->urb_list_lock, flags);
+
return ret;
}
else
@@ -1427,10 +1451,10 @@ _static int uhci_submit_iso_urb (urb_t *urb)
#ifdef ISO_SANITY_CHECK
if(urb->iso_frame_desc[n].length > maxsze) {
+
err("submit_iso: urb->iso_frame_desc[%d].length(%d)>%d",n , urb->iso_frame_desc[n].length, maxsze);
tdm[n] = 0;
- ret=-EINVAL;
- goto inval;
+ ret=-EINVAL;
}
else
#endif
@@ -2177,10 +2201,9 @@ _static int process_transfer (uhci_t *s, urb_t *urb, int mode)
usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
}
- if (status != 0) { // if any error occured stop processing of further TDs
+ if (status && (status != -EPIPE)) { // if any error occurred stop processing of further TDs
// only set ret if status returned an error
- if (status != -EPIPE)
- uhci_show_td (desc);
+ is_error:
ret = status;
urb->error_count++;
break;
@@ -2212,6 +2235,8 @@ _static int process_transfer (uhci_t *s, urb_t *urb, int mode)
data_toggle = uhci_toggle (desc->hw.td.info);
break;
}
+ else if (status)
+ goto is_error;
data_toggle = uhci_toggle (desc->hw.td.info);
queue_dbg("process_transfer: len:%d status:%x mapped:%x toggle:%d", actual_length, desc->hw.td.status,status, data_toggle);
@@ -2457,10 +2482,11 @@ _static int process_urb (uhci_t *s, struct list_head *p)
is_ring = 1;
}
+ spin_lock(&urb->lock);
spin_unlock(&s->urb_list_lock);
- // In case you need the current URB status for your completion handler
- if (urb->complete && (!proceed || (urb->transfer_flags & USB_URB_EARLY_COMPLETE))) {
+ // In case you need the current URB status for your completion handler (before resubmit)
+ if (urb->complete && (!proceed )) {
dbg("process_transfer: calling early completion");
urb->complete ((struct urb *) urb);
if (!proceed && is_ring && (urb->status != -ENOENT))
@@ -2478,15 +2504,15 @@ _static int process_urb (uhci_t *s, struct list_head *p)
}
while (tmp != NULL && tmp != urb->next); // submit until we reach NULL or our own pointer or submit fails
- if (urb->complete && !(urb->transfer_flags & USB_URB_EARLY_COMPLETE)) {
+ if (urb->complete) {
dbg("process_transfer: calling completion");
urb->complete ((struct urb *) urb);
}
}
- spin_lock(&s->urb_list_lock);
-
usb_dec_dev_use (urb->dev);
+ spin_unlock(&urb->lock);
+ spin_lock(&s->urb_list_lock);
}
}
@@ -2790,10 +2816,6 @@ _static int __init start_uhci (struct pci_dev *dev)
break;
/* disable legacy emulation */
pci_write_config_word (dev, USBLEGSUP, USBLEGSUP_DEFAULT);
- if(dev->vendor==0x8086) {
- info("Intel USB controller: setting latency timer to %d", UHCI_LATENCY_TIMER);
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, UHCI_LATENCY_TIMER);
- }
return alloc_uhci(dev, dev->irq, io_addr, io_size);
}
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index 0154d7f48..777e2d650 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -775,8 +775,8 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)
void usb_free_dev(struct usb_device *dev)
{
if (atomic_dec_and_test(&dev->refcnt)) {
- usb_destroy_configuration(dev);
dev->bus->op->deallocate(dev);
+ usb_destroy_configuration(dev);
kfree(dev);
}
}
@@ -819,7 +819,7 @@ int usb_submit_urb(urb_t *urb)
if (urb && urb->dev)
return urb->dev->bus->op->submit_urb(urb);
else
- return -1;
+ return -ENODEV;
}
/*-------------------------------------------------------------------*/
@@ -828,7 +828,7 @@ int usb_unlink_urb(urb_t *urb)
if (urb && urb->dev)
return urb->dev->bus->op->unlink_urb(urb);
else
- return -1;
+ return -ENODEV;
}
/*-------------------------------------------------------------------*
* COMPLETION HANDLERS *
@@ -1330,13 +1330,6 @@ void usb_destroy_configuration(struct usb_device *dev)
}
kfree(dev->config);
}
-
-void usb_init_root_hub(struct usb_device *dev)
-{
- dev->devnum = -1;
- dev->slow = 0;
- dev->actconfig = NULL;
-}
/* for returning string descriptors in UTF-16LE */
static int ascii2utf (char *ascii, __u8 *utf, int utfmax)
@@ -1451,13 +1444,13 @@ void usb_disconnect(struct usb_device **pdev)
usb_disconnect(child);
}
- /* remove /proc/bus/usb entry */
- usbdevfs_remove_device(dev);
-
- /* Free up the device itself, including its device number */
- if (dev->devnum > 0)
+ /* Free the device number and remove the /proc/bus/usb entry */
+ if (dev->devnum > 0) {
clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
+ usbdevfs_remove_device(dev);
+ }
+ /* Free up the device itself */
usb_free_dev(dev);
}
@@ -1631,7 +1624,7 @@ int usb_clear_halt(struct usb_device *dev, int pipe)
if (result < 0)
return result;
- if (status & 1)
+ if (le16_to_cpu(status) & 1)
return -EPIPE; /* still halted */
usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
@@ -1679,7 +1672,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
}
if (!cp) {
warn("selecting invalid configuration %d", configuration);
- return -1;
+ return -EINVAL;
}
if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
@@ -1719,12 +1712,12 @@ int usb_get_configuration(struct usb_device *dev)
if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
warn("too many configurations");
- return -1;
+ return -EINVAL;
}
if (dev->descriptor.bNumConfigurations < 1) {
warn("not enough configurations");
- return -1;
+ return -EINVAL;
}
dev->config = (struct usb_config_descriptor *)
@@ -1732,7 +1725,7 @@ int usb_get_configuration(struct usb_device *dev)
sizeof(struct usb_config_descriptor), GFP_KERNEL);
if (!dev->config) {
err("out of memory");
- return -1;
+ return -ENOMEM;
}
memset(dev->config, 0, dev->descriptor.bNumConfigurations *
sizeof(struct usb_config_descriptor));
@@ -1741,7 +1734,7 @@ int usb_get_configuration(struct usb_device *dev)
dev->descriptor.bNumConfigurations, GFP_KERNEL);
if (!dev->rawdescriptors) {
err("out of memory");
- return -1;
+ return -ENOMEM;
}
for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) {
@@ -1751,8 +1744,10 @@ int usb_get_configuration(struct usb_device *dev)
if (result < 8) {
if (result < 0)
err("unable to get descriptor");
- else
+ else {
err("config descriptor too short (expected %i, got %i)", 8, result);
+ result = -EINVAL;
+ }
goto err;
}
@@ -1776,6 +1771,7 @@ int usb_get_configuration(struct usb_device *dev)
if (result < length) {
err("config descriptor too short (expected %i, got %i)", length, result);
+ result = -EINVAL;
kfree(bigbuffer);
goto err;
}
@@ -1786,7 +1782,7 @@ int usb_get_configuration(struct usb_device *dev)
if (result > 0)
dbg("descriptor data left");
else if (result < 0) {
- result = -1;
+ result = -EINVAL;
goto err;
}
}
@@ -1921,14 +1917,13 @@ int usb_new_device(struct usb_device *dev)
return 1;
}
- dev->actconfig = dev->config;
- usb_set_maxpacket(dev);
-
/* we set the default configuration here */
err = usb_set_configuration(dev, dev->config[0].bConfigurationValue);
if (err) {
err("failed to set default configuration (error=%d)", err);
- return -1;
+ clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
+ dev->devnum = -1;
+ return 1;
}
dbg("new device strings: Mfr=%d, Product=%d, SerialNumber=%d",
@@ -2035,7 +2030,6 @@ EXPORT_SYMBOL(usb_driver_claim_interface);
EXPORT_SYMBOL(usb_interface_claimed);
EXPORT_SYMBOL(usb_driver_release_interface);
-EXPORT_SYMBOL(usb_init_root_hub);
EXPORT_SYMBOL(usb_root_hub_string);
EXPORT_SYMBOL(usb_new_device);
EXPORT_SYMBOL(usb_reset_device);