summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-03-23 02:25:38 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-03-23 02:25:38 +0000
commit16b5d462f73eb29d1f67fa01cc1ea66afdc72569 (patch)
tree5407bd573f4840e473ea27cbe61e5c7a07131fcd /drivers/usb
parentce8a076e11e7e5ee36007f9a3eee5bb3744cb8f6 (diff)
Merge with Linux 2.3.99-pre2.
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/Config.in23
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/dc2xx.c23
-rw-r--r--drivers/usb/drivers.c6
-rw-r--r--drivers/usb/dsbr100.c6
-rw-r--r--drivers/usb/hub.c104
-rw-r--r--drivers/usb/hub.h13
-rw-r--r--drivers/usb/joydev.c4
-rw-r--r--drivers/usb/serial/Makefile2
-rw-r--r--drivers/usb/serial/usb-serial.c37
-rw-r--r--drivers/usb/serial/usb-serial.h1
-rw-r--r--drivers/usb/uhci.c34
-rw-r--r--drivers/usb/usb-ohci.c25
-rw-r--r--drivers/usb/usb-storage.c514
-rw-r--r--drivers/usb/usb-uhci.c1
15 files changed, 455 insertions, 340 deletions
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
index fbb7562dc..012a27187 100644
--- a/drivers/usb/Config.in
+++ b/drivers/usb/Config.in
@@ -8,7 +8,9 @@ tristate 'Support for USB' CONFIG_USB
if [ ! "$CONFIG_USB" = "n" ]; then
comment 'USB Controllers'
- dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
+ if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
+ dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
+ fi
if [ "$CONFIG_USB_UHCI" != "y" ]; then
dep_tristate ' UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
if [ "$CONFIG_USB_UHCI_ALT" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
@@ -34,21 +36,26 @@ comment 'USB Devices'
bool ' USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO
bool ' USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA
fi
+ bool ' USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG
fi
dep_tristate ' USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB
dep_tristate ' USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB
dep_tristate ' USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB
dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
- dep_tristate ' USB Mass Storage support' CONFIG_USB_STORAGE $CONFIG_USB
- if [ "$CONFIG_USB_STORAGE" != "n" ]; then
- bool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' USB Mass Storage support (EXPERIMENTAL)' CONFIG_USB_STORAGE $CONFIG_USB m
+ if [ "$CONFIG_USB_STORAGE" != "n" ]; then
+ bool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG
+ fi
fi
dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
- dep_tristate ' PLUSB Prolific USB-Network driver' CONFIG_USB_PLUSB $CONFIG_USB
- dep_tristate ' USB ADMtek Pegasus-based device support' CONFIG_USB_PEGASUS $CONFIG_USB
- dep_tristate ' USB Diamond Rio500 support' CONFIG_USB_RIO500 $CONFIG_USB
- dep_tristate ' D-Link USB FM radio support' CONFIG_USB_DSBR $CONFIG_USB
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB
+ dep_tristate ' USB ADMtek Pegasus-based device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB
+ dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB
+ dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB
+ fi
comment 'USB HID'
dep_tristate ' USB Human Interface Device (HID) support' CONFIG_USB_HID $CONFIG_USB
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 35bef0e45..6e9e99714 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -45,7 +45,7 @@ ifeq ($(CONFIG_USB_SERIAL),y)
obj-y += serial/serial.o
else
ifeq ($(CONFIG_USB_SERIAL),m)
- MOD_SUB_DIRS += serial
+ MOD_IN_SUB_DIRS += serial
endif
endif
diff --git a/drivers/usb/dc2xx.c b/drivers/usb/dc2xx.c
index 3a2df9155..9dff6bda1 100644
--- a/drivers/usb/dc2xx.c
+++ b/drivers/usb/dc2xx.c
@@ -25,7 +25,8 @@
* and have fun!
*
* This should also work for a number of other digital (non-Kodak) cameras,
- * by adding the vendor and product IDs to the table below.
+ * by adding the vendor and product IDs to the table below. They'll need
+ * to be the sort using USB just as a fast bulk data channel.
*/
/*
@@ -100,7 +101,8 @@ static const struct camera {
// { 0x03f0, 0xffff }, // HP PhotoSmart C500
/* Other USB devices may well work here too, so long as they
- * just stick to half duplex bulk packet exchanges.
+ * just stick to half duplex bulk packet exchanges. That
+ * means, among other things, no iso or interrupt endpoints.
*/
};
@@ -162,7 +164,7 @@ static ssize_t camera_read (struct file *file,
usb_rcvbulkpipe (camera->dev, camera->inEP),
camera->buf, len, &count, HZ*10);
- dbg ("read (%d) - 0x%x %ld", len, result, count);
+ dbg ("read (%d) - 0x%x %d", len, result, count);
if (!result) {
if (copy_to_user (buf, camera->buf, count))
@@ -382,7 +384,7 @@ static void * camera_probe(struct usb_device *dev, unsigned int ifnum)
err ("no memory!");
return NULL;
}
- camera->dev = dev;
+ camera->info = camera_info;
camera->subminor = i;
camera->isActive = 0;
camera->buf = NULL;
@@ -413,19 +415,22 @@ static void * camera_probe(struct usb_device *dev, unsigned int ifnum)
|| endpoint [1].bmAttributes != USB_ENDPOINT_XFER_BULK
) {
dbg ("Bogus endpoints");
- camera->dev = NULL;
- return NULL;
+ goto error;
}
if (usb_set_configuration (dev, dev->config[0].bConfigurationValue)) {
err ("Failed usb_set_configuration");
- camera->dev = NULL;
- return NULL;
+ goto error;
}
- camera->info = camera_info;
+ camera->dev = dev;
return camera;
+
+error:
+ minor_data [camera->subminor] = NULL;
+ kfree (camera);
+ return NULL;
}
static void camera_disconnect(struct usb_device *dev, void *ptr)
diff --git a/drivers/usb/drivers.c b/drivers/usb/drivers.c
index 7682c7442..0dcc9f719 100644
--- a/drivers/usb/drivers.c
+++ b/drivers/usb/drivers.c
@@ -69,7 +69,11 @@ static ssize_t usb_driver_read(struct file *file, char *buf, size_t nbytes, loff
pos = *ppos;
for (; tmp != &usb_driver_list; tmp = tmp->next) {
struct usb_driver *driver = list_entry(tmp, struct usb_driver, driver_list);
- start += sprintf (start, "%s\n", driver->name);
+ int minor = driver->fops ? driver->minor : -1;
+ if (minor == -1)
+ start += sprintf (start, " %s\n", driver->name);
+ else
+ start += sprintf (start, "%3d-%3d: %s\n", minor, minor + 15, driver->name);
if (start > end) {
start += sprintf(start, "(truncated)\n");
break;
diff --git a/drivers/usb/dsbr100.c b/drivers/usb/dsbr100.c
index 8b81e06c0..22c21bb33 100644
--- a/drivers/usb/dsbr100.c
+++ b/drivers/usb/dsbr100.c
@@ -48,12 +48,6 @@
#include <linux/kernel.h>
-
-#if CONFIG_MODVERSIONS==1
-#define MODVERSIONS
-#include <linux/modversions.h>
-#endif
-
#include <linux/module.h>
#include <linux/init.h>
#include <linux/malloc.h>
diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c
index 9138ee4da..8bd919d67 100644
--- a/drivers/usb/hub.c
+++ b/drivers/usb/hub.c
@@ -4,8 +4,6 @@
* (C) Copyright 1999 Linus Torvalds
* (C) Copyright 1999 Johannes Erdfelt
* (C) Copyright 1999 Gregory P. Smith
- *
- * $Id: hub.c,v 1.21 2000/01/16 21:19:44 acher Exp $
*/
#include <linux/kernel.h>
@@ -75,31 +73,29 @@ static int usb_get_port_status(struct usb_device *dev, int port, void *data)
* the low-level driver that it wants to be re-activated,
* or zero to say "I'm done".
*/
-static int hub_irq(int status, void *__buffer, int len, void *dev_id)
+static void hub_irq(struct urb *urb)
{
- struct usb_hub *hub = dev_id;
+ struct usb_hub *hub = (struct usb_hub *)urb->context;
unsigned long flags;
- switch (status) {
- case -ENODEV:
- /* Just ignore it */
- break;
- case 0:
- /* Something happened, let khubd figure it out */
- if (waitqueue_active(&khubd_wait)) {
- /* Add the hub to the event queue */
- spin_lock_irqsave(&hub_event_lock, flags);
- if (hub->event_list.next == &hub->event_list) {
- list_add(&hub->event_list, &hub_event_list);
- /* Wake up khubd */
- wake_up(&khubd_wait);
- }
- spin_unlock_irqrestore(&hub_event_lock, flags);
- }
- break;
+ if (urb->status) {
+ if (urb->status != -ENOENT)
+ dbg("nonzero status in irq %d", urb->status);
+
+ return;
}
- return 1;
+ /* Something happened, let khubd figure it out */
+ if (waitqueue_active(&khubd_wait)) {
+ /* Add the hub to the event queue */
+ spin_lock_irqsave(&hub_event_lock, flags);
+ if (hub->event_list.next == &hub->event_list) {
+ list_add(&hub->event_list, &hub_event_list);
+ /* Wake up khubd */
+ wake_up(&khubd_wait);
+ }
+ spin_unlock_irqrestore(&hub_event_lock, flags);
+ }
}
static void usb_hub_power_on(struct usb_hub *hub)
@@ -196,13 +192,14 @@ static int usb_hub_configure(struct usb_hub *hub)
return 0;
}
-static void * hub_probe(struct usb_device *dev, unsigned int i)
+static void *hub_probe(struct usb_device *dev, unsigned int i)
{
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
struct usb_hub *hub;
unsigned long flags;
- int ret;
+ unsigned int pipe;
+ int maxp, ret;
interface = &dev->actconfig->interface[i].altsetting[0];
@@ -233,7 +230,8 @@ static void * hub_probe(struct usb_device *dev, unsigned int i)
/* We found a hub */
info("USB hub found");
- if ((hub = kmalloc(sizeof(*hub), GFP_KERNEL)) == NULL) {
+ hub = kmalloc(sizeof(*hub), GFP_KERNEL);
+ if (!hub) {
err("couldn't kmalloc hub struct");
return NULL;
}
@@ -250,26 +248,24 @@ static void * hub_probe(struct usb_device *dev, unsigned int i)
spin_unlock_irqrestore(&hub_event_lock, flags);
if (usb_hub_configure(hub) >= 0) {
- hub->irqpipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
- ret = usb_request_irq(dev, hub->irqpipe,
- hub_irq, endpoint->bInterval,
- hub, &hub->irq_handle);
- if (ret) {
- err("usb_request_irq failed (%d)", ret);
- /* free hub, but first clean up its list. */
- spin_lock_irqsave(&hub_event_lock, flags);
+ pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
- /* Delete it and then reset it */
- list_del(&hub->event_list);
- INIT_LIST_HEAD(&hub->event_list);
- list_del(&hub->hub_list);
- INIT_LIST_HEAD(&hub->hub_list);
+ if (maxp > sizeof(hub->buffer))
+ maxp = sizeof(hub->buffer);
- spin_unlock_irqrestore(&hub_event_lock, flags);
-
- kfree(hub);
+ hub->urb = usb_alloc_urb(0);
+ if (!hub->urb) {
+ err("couldn't allocate interrupt urb");
+ goto fail;
+ }
- return NULL;
+ FILL_INT_URB(hub->urb, dev, pipe, hub->buffer, maxp, hub_irq,
+ hub, endpoint->bInterval);
+ ret = usb_submit_urb(hub->urb);
+ if (ret) {
+ err("usb_submit_urb failed (%d)", ret);
+ goto fail;
}
/* Wake up khubd */
@@ -277,11 +273,27 @@ static void * hub_probe(struct usb_device *dev, unsigned int i)
}
return hub;
+
+fail:
+ /* free hub, but first clean up its list. */
+ spin_lock_irqsave(&hub_event_lock, flags);
+
+ /* Delete it and then reset it */
+ list_del(&hub->event_list);
+ INIT_LIST_HEAD(&hub->event_list);
+ list_del(&hub->hub_list);
+ INIT_LIST_HEAD(&hub->hub_list);
+
+ spin_unlock_irqrestore(&hub_event_lock, flags);
+
+ kfree(hub);
+
+ return NULL;
}
static void hub_disconnect(struct usb_device *dev, void *ptr)
{
- struct usb_hub *hub = ptr;
+ struct usb_hub *hub = (struct usb_hub *)ptr;
unsigned long flags;
spin_lock_irqsave(&hub_event_lock, flags);
@@ -294,8 +306,10 @@ static void hub_disconnect(struct usb_device *dev, void *ptr)
spin_unlock_irqrestore(&hub_event_lock, flags);
- if (hub->irq_handle) {
- usb_release_irq(hub->dev, hub->irq_handle, hub->irqpipe);
+ if (hub->urb) {
+ usb_unlink_urb(hub->urb);
+ usb_free_urb(hub->urb);
+ hub->urb = NULL;
}
/* Free the memory */
diff --git a/drivers/usb/hub.h b/drivers/usb/hub.h
index 0da7eb87c..913c44a2d 100644
--- a/drivers/usb/hub.h
+++ b/drivers/usb/hub.h
@@ -78,16 +78,10 @@ struct usb_hub_descriptor {
__u8 bDescriptorType;
__u8 bNbrPorts;
__u16 wHubCharacteristics;
-#if 0
- __u8 wHubCharacteristics[2]; /* __u16 but not aligned! */
-#endif
__u8 bPwrOn2PwrGood;
__u8 bHubContrCurrent;
/* DeviceRemovable and PortPwrCtrlMask want to be variable-length
bitmaps that hold max 256 entries, but for now they're ignored */
-#if 0
- __u8 filler;
-#endif
} __attribute__ ((packed));
struct usb_device;
@@ -112,9 +106,10 @@ struct usb_hub {
/* Device structure */
struct usb_device *dev;
- /* Reference to the hub's polling IRQ and its associated pipe */
- void *irq_handle;
- unsigned int irqpipe;
+ /* Interrupt polling pipe */
+ struct urb *urb;
+
+ char buffer[USB_MAXCHILDREN / 8];
/* List of hubs */
struct list_head hub_list;
diff --git a/drivers/usb/joydev.c b/drivers/usb/joydev.c
index a5dcabdab..9b54300e2 100644
--- a/drivers/usb/joydev.c
+++ b/drivers/usb/joydev.c
@@ -224,8 +224,8 @@ static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *p
struct JS_DATA_TYPE data;
- data.buttons = (joydev->nkey > 0 && test_bit(joydev->keypam[0], input->key)) ? 1 : 0 |
- (joydev->nkey > 1 && test_bit(joydev->keypam[1], input->key)) ? 2 : 0;
+ data.buttons = ((joydev->nkey > 0 && test_bit(joydev->keypam[0], input->key)) ? 1 : 0) |
+ ((joydev->nkey > 1 && test_bit(joydev->keypam[1], input->key)) ? 2 : 0);
data.x = ((joydev_correct(input->abs[ABS_X], &joydev->corr[0]) / 256) + 128) >> joydev->glue.JS_CORR.x;
data.y = ((joydev_correct(input->abs[ABS_Y], &joydev->corr[1]) / 256) + 128) >> joydev->glue.JS_CORR.y;
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 20dc5dde5..02bd7aad6 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -14,7 +14,7 @@ ALL_SUB_DIRS := $(SUB_DIRS)
O_TARGET := serial.o
M_OBJS := usb-serial.o
O_OBJS := usb-serial.o
-#MOD_LIST_NAME := USB_MODULES
+MOD_LIST_NAME := USB_SERIAL_MODULES
# Objects that export symbols.
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index ad86c6a80..6effcc048 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -14,6 +14,10 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (03/17/2000) gkh
+ * Added config option for debugging messages.
+ * Added patch for keyspan pda from Brian Warner.
+ *
* (03/06/2000) gkh
* Added the keyspan pda code from Brian Warner <warner@lothar.com>
* Moved a bunch of the port specific stuff into its own structure. This
@@ -175,7 +179,12 @@
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/spinlock.h>
-#define DEBUG
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
#include <linux/usb.h>
#ifdef CONFIG_USB_SERIAL_WHITEHEAT
@@ -1428,6 +1437,7 @@ static void keyspan_pda_rx_interrupt (struct urb *urb)
case 2: /* tx unthrottle interrupt */
serial->tx_throttled = 0;
wake_up(&serial->write_wait); /* wake up writer */
+ wake_up(&tty->write_wait); /* them too */
break;
default:
break;
@@ -1846,25 +1856,12 @@ static int keyspan_pda_write_room (struct tty_struct *tty)
static int keyspan_pda_chars_in_buffer (struct tty_struct *tty)
{
struct usb_serial *serial = (struct usb_serial *)tty->driver_data;
- unsigned char count;
- int rc;
-
- /* used by tty stuff to wait for output to drain. Go ask the
- device how much is still queued in the tx ring */
- rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- 6, /* write_room */
- USB_TYPE_VENDOR | USB_RECIP_INTERFACE
- | USB_DIR_IN,
- 1, /* value: 1 means chars_in_buffer */
- 0, /* index */
- &count,
- 1,
- 2*HZ);
- if (rc < 0)
- return rc; /* failed */
- if (rc == 0)
- return -EIO; /* device didn't return any data */
- return (count);
+
+ /* when throttled, return at least WAKEUP_CHARS to tell select() (via
+ n_tty.c:normal_poll() ) that we're not writeable. */
+ if (serial->tx_throttled)
+ return 256;
+ return 0;
}
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
index f02eeedf5..71fecb0ec 100644
--- a/drivers/usb/serial/usb-serial.h
+++ b/drivers/usb/serial/usb-serial.h
@@ -371,6 +371,7 @@ static struct usb_serial_device_type keyspan_pda_fake_device = {
num_interrupt_in: NUM_DONT_CARE,
num_bulk_in: NUM_DONT_CARE,
num_bulk_out: NUM_DONT_CARE,
+ num_ports: 1,
startup: keyspan_pda_fake_startup
};
static struct usb_serial_device_type keyspan_pda_device = {
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
index 480c6252d..f5e67acec 100644
--- a/drivers/usb/uhci.c
+++ b/drivers/usb/uhci.c
@@ -689,19 +689,18 @@ status_phase:
return 0;
td_error:
- /* Some debugging code */
- if (debug) {
+ if (status & TD_CTRL_STALLED)
+ /* endpoint has stalled - mark it halted */
+ usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
+ uhci_packetout(td->info));
+ else if (debug) {
+ /* Some debugging code */
dbg("uhci_result_control() failed with status %x", status);
/* Print the chain for debugging purposes */
uhci_show_queue(urbp->qh);
}
- if (status & TD_CTRL_STALLED)
- /* endpoint has stalled - mark it halted */
- usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
- uhci_packetout(td->info));
-
return uhci_map_status(status, uhci_packetout(td->info));
}
@@ -818,8 +817,12 @@ static int uhci_result_interrupt(urb_t *urb)
return 0;
td_error:
- /* Some debugging code */
- if (debug) {
+ if (status & TD_CTRL_STALLED)
+ /* endpoint has stalled - mark it halted */
+ usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
+ uhci_packetout(td->info));
+ else if (debug) {
+ /* Some debugging code */
dbg("uhci_result_interrupt/bulk() failed with status %x",
status);
@@ -830,11 +833,6 @@ td_error:
uhci_show_td(td);
}
- if (status & TD_CTRL_STALLED)
- /* endpoint has stalled - mark it halted */
- usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
- uhci_packetout(td->info));
-
return uhci_map_status(status, uhci_packetout(td->info));
}
@@ -1251,12 +1249,14 @@ static int uhci_unlink_urb(urb_t *urb)
uhci_unlink_generic(urb);
if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+ urb->status = -ECONNABORTED;
+
spin_lock_irqsave(&uhci->urb_remove_lock, flags);
list_add(&urb->urb_list, &uhci->urb_remove_list);
spin_unlock_irqrestore(&uhci->urb_remove_lock, flags);
-
- urb->status = -ECONNABORTED;
} else {
+ urb->status = -ENOENT;
+
if (in_interrupt()) { /* wait at least 1 frame */
static int errorcount = 10;
@@ -1268,8 +1268,6 @@ static int uhci_unlink_urb(urb_t *urb)
if (urb->complete)
urb->complete(urb);
-
- urb->status = -ENOENT;
}
}
diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
index cf457762a..78ae0a0ea 100644
--- a/drivers/usb/usb-ohci.c
+++ b/drivers/usb/usb-ohci.c
@@ -252,6 +252,9 @@ static int sohci_submit_urb (urb_t * urb)
if (urb->hcpriv) return -EINVAL; /* urb already in use */
+// if(usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)))
+// return -EPIPE;
+
usb_inc_dev_use (urb->dev);
ohci = (ohci_t *) urb->dev->bus->hcpriv;
@@ -838,28 +841,36 @@ static void td_submit_urb (urb_t * urb)
int data_len = urb->transfer_buffer_length;
int cnt = 0;
__u32 info = 0;
-
+ unsigned int toggle = 0;
+ /* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
+ if(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe))) {
+ toggle = TD_T_TOGGLE;
+ } else {
+ toggle = TD_T_DATA0;
+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 1);
+ }
+
urb_priv->td_cnt = 0;
switch (usb_pipetype (urb->pipe)) {
case PIPE_BULK:
info = usb_pipeout (urb->pipe)?
- TD_CC | TD_DP_OUT | TD_T_TOGGLE: TD_CC | TD_DP_IN | TD_T_TOGGLE;
+ TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
while(data_len > 4096) {
- td_fill (info, data, 4096, urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt);
+ td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, 4096, urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt);
data += 4096; data_len -= 4096; cnt++;
}
info = usb_pipeout (urb->pipe)?
- TD_CC | TD_DP_OUT | TD_T_TOGGLE: TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE;
- td_fill (info, data, data_len, urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt);
+ TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
+ td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt);
cnt++;
writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
break;
case PIPE_INTERRUPT:
info = usb_pipeout (urb->pipe)?
- TD_CC | TD_DP_OUT | TD_T_TOGGLE: TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE;
+ TD_CC | TD_DP_OUT | toggle: TD_CC | TD_R | TD_DP_IN | toggle;
td_fill (info, data, data_len, urb, ST_ADDR | ADD_LEN, cnt++);
break;
@@ -1059,6 +1070,8 @@ static void dl_done_list (ohci_t * ohci, td_t * td_list)
}
/* error code of transfer */
cc = TD_CC_GET (tdINFO);
+ if( cc == TD_CC_STALL) usb_endpoint_halt(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+
if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))
cc = TD_CC_NOERROR;
if (++(urb_priv->td_cnt) == urb_priv->length) {
diff --git a/drivers/usb/usb-storage.c b/drivers/usb/usb-storage.c
index 956e80a0a..0cac2ef13 100644
--- a/drivers/usb/usb-storage.c
+++ b/drivers/usb/usb-storage.c
@@ -52,6 +52,10 @@
/* direction table -- this indicates the direction of the data
* transfer for each command code -- a 1 indicates input
*/
+/* FIXME: we need to use the new direction indicators in the Scsi_Cmnd
+ * structure, not this table. First we need to evaluate if it's being set
+ * correctly for us, though
+ */
unsigned char us_direction[256/8] = {
0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
@@ -81,13 +85,12 @@ struct us_data {
__u8 ep_int; /* interrupt . */
__u8 subclass; /* as in overview */
__u8 protocol; /* .............. */
- __u8 attention_done; /* force attn on first cmd */
trans_cmnd transport; /* protocol specific do cmd */
trans_reset transport_reset; /* .......... device reset */
proto_cmnd proto_handler; /* protocol handler */
GUID(guid); /* unique dev id */
struct Scsi_Host *host; /* our dummy host data */
- Scsi_Host_Template *htmplt; /* own host template */
+ Scsi_Host_Template htmplt; /* own host template */
int host_number; /* to find us */
int host_no; /* allocated by scsi */
Scsi_Cmnd *srb; /* current srb */
@@ -114,7 +117,9 @@ struct us_data {
#define US_ACT_BUS_RESET 4
#define US_ACT_HOST_RESET 5
+/* The list of structures and the protective lock for them */
static struct us_data *us_list;
+spinlock_t us_list_spinlock = SPIN_LOCK_UNLOCKED;
static void * storage_probe(struct usb_device *dev, unsigned int ifnum);
static void storage_disconnect(struct usb_device *dev, void *ptr);
@@ -225,7 +230,7 @@ static void us_transfer(Scsi_Cmnd *srb, int dir_in)
srb->result = result;
}
-/* calculate the length of the data transfer (not the command) for any
+/* Calculate the length of the data transfer (not the command) for any
* given SCSI command
*/
static unsigned int us_transfer_length(Scsi_Cmnd *srb)
@@ -243,14 +248,18 @@ static unsigned int us_transfer_length(Scsi_Cmnd *srb)
case TEST_UNIT_READY:
return 0;
+ /* FIXME: these should be removed and tested */
case REQUEST_SENSE:
case INQUIRY:
case MODE_SENSE:
return srb->cmnd[4];
+ /* FIXME: this needs to come out when the other
+ * fix is in place */
case READ_CAPACITY:
return 8;
+ /* FIXME: these should be removed and tested */
case LOG_SENSE:
case MODE_SENSE_10:
return (srb->cmnd[7] << 8) + srb->cmnd[8];
@@ -795,7 +804,7 @@ static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
return USB_STOR_TRANSPORT_ERROR;
}
- /* FIXME: we need to handle NAKs here */
+ /* FIXME: we need to handle NAKs here */
return USB_STOR_TRANSPORT_ERROR;
}
@@ -812,7 +821,9 @@ static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
/* STATUS STAGE */
/* go to sleep until we get this interrup */
- /* FIXME: this should be changed to use a timeout */
+ /* FIXME: this should be changed to use a timeout -- or let the
+ * device reset routine up() this for us to unjam us
+ */
down(&(us->ip_waitq));
/* FIXME: currently this code is unreachable, but the idea is
@@ -827,8 +838,8 @@ static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
US_DEBUGP("Got interrupt data 0x%x\n", us->ip_data);
/* UFI gives us ASC and ASCQ, like a request sense */
- /* FIXME: is this right? Do REQUEST_SENSE and INQUIRY need special
- * case handling?
+ /* REQUEST_SENSE and INQUIRY don't affect the sense data, so we
+ * ignore the information for those commands
*/
if (us->subclass == US_SC_UFI) {
if (srb->cmnd[0] == REQUEST_SENSE ||
@@ -887,7 +898,7 @@ static int CB_transport(Scsi_Cmnd *srb, struct us_data *us)
return USB_STOR_TRANSPORT_ERROR;
}
- /* FIXME: we need to handle NAKs here */
+ /* FIXME: we need to handle NAKs here */
return USB_STOR_TRANSPORT_ERROR;
}
@@ -1103,7 +1114,8 @@ static int us_detect(struct SHT *sht)
static int us_release(struct Scsi_Host *psh)
{
struct us_data *us = (struct us_data *)psh->hostdata[0];
- struct us_data *prev = (struct us_data *)&us_list;
+ struct us_data *prev;
+ unsigned long flags;
if (us->irq_handle) {
usb_release_irq(us->pusb_dev, us->irq_handle, us->irqpipe);
@@ -1111,18 +1123,20 @@ static int us_release(struct Scsi_Host *psh)
}
/* FIXME: release the interface claim here? */
- // if (us->pusb_dev)
- // usb_deregister(&storage_driver);
- /* FIXME - leaves hanging host template copy */
- /* (because scsi layer uses it after removal !!!) */
+ /* FIXME: we need to move this elsewhere --
+ * the remove function only gets called to remove the module
+ */
+ spin_lock_irqsave(&us_list_spinlock, flags);
if (us_list == us)
us_list = us->next;
else {
+ prev = us_list;
while (prev->next != us)
prev = prev->next;
prev->next = us->next;
}
+ spin_unlock_irqrestore(&us_list_spinlock, flags);
return 0;
}
@@ -1190,11 +1204,20 @@ static int us_host_reset( Scsi_Cmnd *srb )
int usb_stor_proc_info (char *buffer, char **start, off_t offset,
int length, int hostno, int inout)
{
- struct us_data *us = us_list;
+ struct us_data *us;
char *pos = buffer;
char *tmp_ptr;
+ unsigned long flags;
+
+ /* if someone is sending us data, just throw it away */
+ if (inout)
+ return length;
+
+ /* lock the data structures */
+ spin_lock_irqsave(&us_list_spinlock, flags);
/* find our data from hostno */
+ us = us_list;
while (us) {
if (us->host_no == hostno)
break;
@@ -1202,13 +1225,11 @@ int usb_stor_proc_info (char *buffer, char **start, off_t offset,
}
/* if we couldn't find it, we return an error */
- if (!us)
+ if (!us) {
+ spin_unlock_irqrestore(&us_list_spinlock, flags);
return -ESRCH;
-
- /* if someone is sending us data, just throw it away */
- if (inout)
- return length;
-
+ }
+
/* print the controler name */
SPRINTF ("Host scsi%d: usb-storage\n", hostno);
@@ -1254,6 +1275,9 @@ int usb_stor_proc_info (char *buffer, char **start, off_t offset,
/* show the GUID of the device */
SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
+ /* release our lock on the data structures */
+ spin_unlock_irqrestore(&us_list_spinlock, flags);
+
/*
* Calculate start of next buffer, and return value.
*/
@@ -1365,6 +1389,7 @@ static int usb_stor_control_thread(void * __us)
switch (action) {
case US_ACT_COMMAND:
/* bad device */
+ /* FIXME: we need to enable and test multiple LUNs */
if (us->srb->target || us->srb->lun) {
US_DEBUGP( "Bad device number (%d/%d) or dev 0x%x\n",
us->srb->target, us->srb->lun, (unsigned int)us->pusb_dev);
@@ -1378,9 +1403,12 @@ static int usb_stor_control_thread(void * __us)
/* our device has gone - pretend not ready */
/* FIXME: we also need to handle INQUIRY here,
* probably */
+ /* FIXME: fix return codes and sense buffer handling */
if (!us->pusb_dev) {
+ US_DEBUGP("Request is for removed device\n");
if (us->srb->cmnd[0] == REQUEST_SENSE) {
- memcpy(us->srb->request_buffer, sense_notready,
+ memcpy(us->srb->request_buffer,
+ sense_notready,
sizeof(sense_notready));
us->srb->result = DID_OK << 16;
} else {
@@ -1443,34 +1471,29 @@ static int usb_stor_control_thread(void * __us)
/* Probe to see if a new device is actually a SCSI device */
static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
{
- struct usb_interface_descriptor *interface;
int i;
char mf[32]; /* manufacturer */
char prod[32]; /* product */
char serial[32]; /* serial number */
struct us_data *ss = NULL;
- unsigned int flags = 0;
GUID(guid); /* Global Unique Identifier */
- struct us_data *prev;
- int protocol = 0;
- int subclass = 0;
+ int result;
+ unsigned long flags;
+
+ /* these are temporary copies -- we test on these, then put them
+ * in the us-data structure
+ */
+ __u8 ep_in = 0;
+ __u8 ep_out = 0;
+ __u8 ep_int = 0;
+ __u8 subclass = 0;
+ __u8 protocol = 0;
+
+ /* the altsettting 0 on the interface we're probing */
struct usb_interface_descriptor *altsetting =
&(dev->actconfig->interface[ifnum].altsetting[0]);
- /* clear the GUID and fetch the strings */
- GUID_CLEAR(guid);
- memset(mf, 0, sizeof(mf));
- memset(prod, 0, sizeof(prod));
- memset(serial, 0, sizeof(serial));
- if (dev->descriptor.iManufacturer)
- usb_string(dev, dev->descriptor.iManufacturer, mf, sizeof(mf));
- if (dev->descriptor.iProduct)
- usb_string(dev, dev->descriptor.iProduct, prod, sizeof(prod));
- if (dev->descriptor.iSerialNumber)
- usb_string(dev, dev->descriptor.iSerialNumber, serial, sizeof(serial));
-
- /* let's examine the device now */
-
+ /* FIXME: this isn't quite right... */
/* We make an exception for the shuttle E-USB */
if (dev->descriptor.idVendor == 0x04e6 &&
dev->descriptor.idProduct == 0x0001) {
@@ -1487,6 +1510,91 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
/* At this point, we know we've got a live one */
US_DEBUGP("USB Mass Storage device detected\n");
+ /*
+ * We are expecting a minimum of 2 endpoints - in and out (bulk).
+ * An optional interrupt is OK (necessary for CBI protocol).
+ * We will ignore any others.
+ */
+ for (i = 0; i < altsetting->bNumEndpoints; i++) {
+ /* is it an BULK endpoint? */
+ if ((altsetting->endpoint[i].bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+ if (altsetting->endpoint[i].bEndpointAddress &
+ USB_DIR_IN)
+ ep_in = altsetting->endpoint[i].bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ else
+ ep_out = altsetting->endpoint[i].bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ }
+
+ /* is it an interrupt endpoint? */
+ if ((altsetting->endpoint[i].bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
+ ep_int = altsetting->endpoint[i].bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ }
+ }
+ US_DEBUGP("Endpoints In %d Out %d Int %d\n",
+ ep_in, ep_out, ep_int);
+
+ /* set the interface -- STALL is an acceptable response here */
+ result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0);
+ US_DEBUGP("Result from usb_set_interface is %d\n", result);
+ if (result == -EPIPE) {
+ usb_clear_halt(dev, usb_sndctrlpipe(dev, 0));
+ } else if (result != 0) {
+ /* it's not a stall, but another error -- time to bail */
+ return NULL;
+ }
+
+ /* shuttle E-USB */
+ /* FIXME: all we should need to do here is determine the protocol */
+ if (dev->descriptor.idVendor == 0x04e6 &&
+ dev->descriptor.idProduct == 0x0001) {
+ __u8 qstat[2];
+
+ result = usb_control_msg(ss->pusb_dev,
+ usb_rcvctrlpipe(dev,0),
+ 1, 0xC0,
+ 0, ss->ifnum,
+ qstat, 2, HZ*5);
+ US_DEBUGP("C0 status 0x%x 0x%x\n", qstat[0], qstat[1]);
+ init_MUTEX_LOCKED(&(ss->ip_waitq));
+ ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
+ result = usb_request_irq(ss->pusb_dev, ss->irqpipe,
+ CBI_irq, 255, (void *)ss,
+ &ss->irq_handle);
+ if (result < 0)
+ return NULL;
+
+ /* FIXME: what is this?? */
+ down(&(ss->ip_waitq));
+ }
+
+ /* Do some basic sanity checks, and bail if we find a problem */
+ if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) {
+ US_DEBUGP("Problems with device\n");
+ return NULL;
+ }
+
+ /* At this point, we're committed to using the device */
+
+ /* clear the GUID and fetch the strings */
+ GUID_CLEAR(guid);
+ memset(mf, 0, sizeof(mf));
+ memset(prod, 0, sizeof(prod));
+ memset(serial, 0, sizeof(serial));
+ if (dev->descriptor.iManufacturer)
+ usb_string(dev, dev->descriptor.iManufacturer, mf,
+ sizeof(mf));
+ if (dev->descriptor.iProduct)
+ usb_string(dev, dev->descriptor.iProduct, prod,
+ sizeof(prod));
+ if (dev->descriptor.iSerialNumber)
+ usb_string(dev, dev->descriptor.iSerialNumber, serial,
+ sizeof(serial));
+
/* Create a GUID for this device */
if (dev->descriptor.iSerialNumber && serial[0]) {
/* If we have a serial number, and it's a non-NULL string */
@@ -1498,23 +1606,50 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
dev->descriptor.idProduct, "0");
}
- /* Now check if we have seen this GUID before, and restore
- * the flags if we find it
+ /* lock access to the data structures */
+ spin_lock_irqsave(&us_list_spinlock, flags);
+
+ /*
+ * Now check if we have seen this GUID before
+ * We're looking for a device with a matching GUID that isn't
+ * allready on the system
*/
- for (ss = us_list; ss != NULL; ss = ss->next) {
- if (!ss->pusb_dev && GUID_EQUAL(guid, ss->guid)) {
- US_DEBUGP("Found existing GUID " GUID_FORMAT "\n",
- GUID_ARGS(guid));
- flags = ss->flags;
- break;
+ ss = us_list;
+ while ((ss != NULL) &&
+ ((ss->pusb_dev) || !GUID_EQUAL(guid, ss->guid)))
+ ss = ss->next;
+
+ if (ss != NULL) {
+ /* Existing device -- re-connect */
+ US_DEBUGP("Found existing GUID " GUID_FORMAT "\n",
+ GUID_ARGS(guid));
+
+ /* establish the connection to the new device upon reconnect */
+ ss->ifnum = ifnum;
+ ss->pusb_dev = dev;
+
+ /* hook up the IRQ handler again */
+ if (ss->protocol == US_PR_CBI) {
+ /* set up so we'll wait for notification */
+ init_MUTEX_LOCKED(&(ss->ip_waitq));
+
+ /* set up the IRQ pipe and handler */
+ /* FIXME: This needs to get period from the device */
+ US_DEBUGP("Allocating IRQ for CBI transport\n");
+ ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
+ result = usb_request_irq(ss->pusb_dev, ss->irqpipe,
+ CBI_irq, 255,
+ (void *)ss, &ss->irq_handle);
+ US_DEBUGP("usb_request_irq returned %d\n", result);
}
- }
-
- /* If ss == NULL, then this is a new device. Allocate memory for it */
- if (!ss) {
- if ((ss = (struct us_data *)kmalloc(sizeof(*ss),
+ } else {
+ /* New device -- Allocate memory and initialize */
+ US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
+
+ if ((ss = (struct us_data *)kmalloc(sizeof(struct us_data),
GFP_KERNEL)) == NULL) {
printk(KERN_WARNING USB_STORAGE "Out of memory\n");
+ spin_unlock_irqrestore(&us_list_spinlock, flags);
return NULL;
}
memset(ss, 0, sizeof(struct us_data));
@@ -1522,104 +1657,66 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
/* Initialize the mutexes only when the struct is new */
init_MUTEX_LOCKED(&(ss->sleeper));
init_MUTEX(&(ss->queue_exclusion));
- }
-
- /* establish the connection to the new device */
- interface = altsetting;
- ss->flags = flags;
- ss->ifnum = ifnum;
- ss->attention_done = 0;
- ss->pusb_dev = dev;
-
- /* If the device has subclass and protocol, then use that. Otherwise,
- * take data from the specific interface.
- */
- if (subclass) {
- ss->subclass = subclass;
- ss->protocol = protocol;
- } else {
- ss->subclass = interface->bInterfaceSubClass;
- ss->protocol = interface->bInterfaceProtocol;
- }
- /* set the handler pointers based on the protocol */
- US_DEBUGP("Transport: ");
- switch (ss->protocol) {
- case US_PR_CB:
- US_DEBUGPX("Control/Bulk\n");
- ss->transport = CB_transport;
- ss->transport_reset = CB_reset;
- break;
-
- case US_PR_CBI:
- US_DEBUGPX("Control/Bulk/Interrupt\n");
- ss->transport = CBI_transport;
- ss->transport_reset = CB_reset;
- break;
-
- case US_PR_BULK:
- US_DEBUGPX("Bulk\n");
- ss->transport = Bulk_transport;
- ss->transport_reset = Bulk_reset;
- break;
-
- default:
- US_DEBUGPX("Unknown\n");
- kfree(ss);
- return NULL;
- break;
- }
-
- /*
- * We are expecting a minimum of 2 endpoints - in and out (bulk).
- * An optional interrupt is OK (necessary for CBI protocol).
- * We will ignore any others.
- */
- for (i = 0; i < interface->bNumEndpoints; i++) {
- /* is it an BULK endpoint? */
- if ((interface->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK) {
- if (interface->endpoint[i].bEndpointAddress & USB_DIR_IN)
- ss->ep_in = interface->endpoint[i].bEndpointAddress &
- USB_ENDPOINT_NUMBER_MASK;
- else
- ss->ep_out = interface->endpoint[i].bEndpointAddress &
- USB_ENDPOINT_NUMBER_MASK;
- }
-
- /* is it an interrupt endpoint? */
- if ((interface->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_INT) {
- ss->ep_int = interface->endpoint[i].bEndpointAddress &
- USB_ENDPOINT_NUMBER_MASK;
+ /*
+ * If we've allready determined the subclass and protocol,
+ * use that. Otherwise, use the interface ones. This
+ * allows us to support devices which are compliant but
+ * don't announce it. Note that this information is
+ * maintained in the us_data struct so we only have to do
+ * this for new devices.
+ */
+ if (subclass) {
+ ss->subclass = subclass;
+ ss->protocol = protocol;
+ } else {
+ ss->subclass = altsetting->bInterfaceSubClass;
+ ss->protocol = altsetting->bInterfaceProtocol;
}
- }
- US_DEBUGP("Endpoints In %d Out %d Int %d\n",
- ss->ep_in, ss->ep_out, ss->ep_int);
- /* Do some basic sanity checks, and bail if we find a problem */
- if (usb_set_interface(dev, interface->bInterfaceNumber, 0) ||
- !ss->ep_in || !ss->ep_out ||
- (ss->protocol == US_PR_CBI && ss->ep_int == 0)) {
- US_DEBUGP("Problems with device\n");
- if (ss->host) {
- kfree(ss->htmplt->name);
- kfree(ss->htmplt);
- }
+ /* copy over the endpoint data */
+ ss->ep_in = ep_in;
+ ss->ep_out = ep_out;
+ ss->ep_int = ep_int;
- kfree(ss);
- return NULL;
- }
+ /* establish the connection to the new device */
+ ss->ifnum = ifnum;
+ ss->pusb_dev = dev;
- /* If this is a new device (i.e. we haven't seen it before), we need to
- * generate a scsi host definition, and register with scsi above us
- */
- if (!ss->host) {
/* copy the GUID we created before */
- US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
memcpy(ss->guid, guid, sizeof(guid));
+
+ /*
+ * Set the handler pointers based on the protocol
+ * Again, this data is persistant across reattachments
+ */
+ US_DEBUGP("Transport: ");
+ switch (ss->protocol) {
+ case US_PR_CB:
+ US_DEBUGPX("Control/Bulk\n");
+ ss->transport = CB_transport;
+ ss->transport_reset = CB_reset;
+ break;
+
+ case US_PR_CBI:
+ US_DEBUGPX("Control/Bulk/Interrupt\n");
+ ss->transport = CBI_transport;
+ ss->transport_reset = CB_reset;
+ break;
+
+ case US_PR_BULK:
+ US_DEBUGPX("Bulk\n");
+ ss->transport = Bulk_transport;
+ ss->transport_reset = Bulk_reset;
+ break;
+
+ default:
+ US_DEBUGPX("Unknown\n");
+ kfree(ss);
+ return NULL;
+ break;
+ }
- /* set class specific stuff */
US_DEBUGP("Protocol: ");
switch (ss->subclass) {
case US_SC_RBC:
@@ -1656,97 +1753,75 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
break;
}
- /* Allocate memory for the SCSI Host Template */
- if ((ss->htmplt = (Scsi_Host_Template *)
- kmalloc(sizeof(Scsi_Host_Template),GFP_KERNEL))==NULL ) {
- printk(KERN_WARNING USB_STORAGE "Out of memory\n");
-
- kfree(ss);
- return NULL;
+ if (ss->protocol == US_PR_CBI) {
+ /* set up so we'll wait for notification */
+ init_MUTEX_LOCKED(&(ss->ip_waitq));
+
+ /* set up the IRQ pipe and handler */
+ /* FIXME: This needs to get period from the device */
+ US_DEBUGP("Allocating IRQ for CBI transport\n");
+ ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
+ result = usb_request_irq(ss->pusb_dev, ss->irqpipe,
+ CBI_irq, 255,
+ (void *)ss, &ss->irq_handle);
+ US_DEBUGP("usb_request_irq returned %d", result);
}
+
+ /*
+ * Since this is a new device, we need to generate a scsi
+ * host definition, and register with the higher SCSI layers
+ */
/* Initialize the host template based on the default one */
- memcpy(ss->htmplt, &my_host_template, sizeof(my_host_template));
+ memcpy(&(ss->htmplt), &my_host_template,
+ sizeof(my_host_template));
/* Grab the next host number */
ss->host_number = my_host_number++;
-
- /* MDD: FIXME: this is bad. We abuse this pointer so we
+
+ /* FIXME: this is bad. We abuse this pointer so we
* can pass the ss pointer to the host controler thread
* in us_detect
*/
- (struct us_data *)ss->htmplt->proc_dir = ss;
-
- /* shuttle E-USB */
- if (dev->descriptor.idVendor == 0x04e6 &&
- dev->descriptor.idProduct == 0x0001) {
- __u8 qstat[2];
- int result;
-
- result = usb_control_msg(ss->pusb_dev,
- usb_rcvctrlpipe(dev,0),
- 1, 0xC0,
- 0, ss->ifnum,
- qstat, 2, HZ*5);
- US_DEBUGP("C0 status 0x%x 0x%x\n", qstat[0], qstat[1]);
- init_MUTEX_LOCKED(&(ss->ip_waitq));
- ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
- result = usb_request_irq(ss->pusb_dev, ss->irqpipe,
- CBI_irq, 255, (void *)ss,
- &ss->irq_handle);
- if (result < 0)
- return NULL;
- /* FIXME: what is this?? */
- down(&(ss->ip_waitq));
- } else if (ss->protocol == US_PR_CBI) {
- int result;
-
- /* set up so we'll wait for notification */
- init_MUTEX_LOCKED(&(ss->ip_waitq));
-
- /* set up the IRQ pipe and handler */
- /* FIXME: This needs to get the period from the device */
- ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int);
- result = usb_request_irq(ss->pusb_dev, ss->irqpipe, CBI_irq,
- 255, (void *)ss, &ss->irq_handle);
- if (result) {
- US_DEBUGP("usb_request_irq failed (0x%x), No interrupt for CBI\n",
- result);
- }
- }
-
-
- /* start up our thread */
+ (struct us_data *)ss->htmplt.proc_dir = ss;
+
+ /* start up our thread */
{
DECLARE_MUTEX_LOCKED(sem);
-
+
ss->notify = &sem;
ss->pid = kernel_thread(usb_stor_control_thread, ss,
- CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+ CLONE_FS | CLONE_FILES |
+ CLONE_SIGHAND);
if (ss->pid < 0) {
- printk(KERN_WARNING USB_STORAGE "Unable to start control thread\n");
- kfree(ss->htmplt);
-
+ printk(KERN_WARNING USB_STORAGE
+ "Unable to start control thread\n");
kfree(ss);
return NULL;
}
-
- /* wait for it to start */
+
+ /* wait for it to start */
down(&sem);
}
-
+
/* now register - our detect function will be called */
- ss->htmplt->module = &__this_module;
- scsi_register_module(MODULE_SCSI_HA, ss->htmplt);
-
+ ss->htmplt.module = &__this_module;
+ scsi_register_module(MODULE_SCSI_HA, &(ss->htmplt));
+
/* put us in the list */
ss->next = us_list;
- us_list = ss;
+ us_list = ss;
}
- printk(KERN_DEBUG "WARNING: USB Mass Storage data integrity not assured\n");
- printk(KERN_DEBUG "USB Mass Storage device found at %d\n", dev->devnum);
+ /* release the data structure lock */
+ spin_unlock_irqrestore(&us_list_spinlock, flags);
+ printk(KERN_DEBUG
+ "WARNING: USB Mass Storage data integrity not assured\n");
+ printk(KERN_DEBUG
+ "USB Mass Storage device found at %d\n", dev->devnum);
+
+ /* return a pointer for the disconnect function */
return ss;
}
@@ -1758,6 +1833,14 @@ static void storage_disconnect(struct usb_device *dev, void *ptr)
if (!ss)
return;
+ /* FIXME: we need mututal exclusion and resource freeing here */
+
+ /* release the IRQ, if we have one */
+ if (ss->irq_handle) {
+ usb_release_irq(ss->pusb_dev, ss->irq_handle, ss->irqpipe);
+ ss->irq_handle = NULL;
+ }
+
ss->pusb_dev = NULL;
}
@@ -1788,12 +1871,15 @@ void __exit usb_stor_exit(void)
{
static struct us_data *ptr;
- // FIXME: this needs to be put back to free _all_ the hosts
- // for (ptr = us_list; ptr != NULL; ptr = ptr->next)
- // scsi_unregister_module(MODULE_SCSI_HA, ptr->htmplt);
- printk("MDD: us_list->htmplt is 0x%x\n", (unsigned int)(us_list->htmplt));
- scsi_unregister_module(MODULE_SCSI_HA, us_list->htmplt);
+ /* unregister all the virtual hosts */
+ for (ptr = us_list; ptr != NULL; ptr = ptr->next)
+ scsi_unregister_module(MODULE_SCSI_HA, &(ptr->htmplt));
+
+ /* free up the data structures */
+
+ /* kill the threads */
+ /* deregister the driver */
usb_deregister(&storage_driver) ;
}
diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
index 85a5cd476..5dbde2959 100644
--- a/drivers/usb/usb-uhci.c
+++ b/drivers/usb/usb-uhci.c
@@ -28,6 +28,7 @@
#include <linux/unistd.h>
#include <linux/interrupt.h> /* for in_interrupt() */
#include <linux/init.h>
+#include <linux/version.h>
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,44)
#include <linux/pm.h>
#endif