diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2006-06-02 15:05:31 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-06-02 15:05:31 -0700 |
commit | 824837789fc2c31455d2faf32d259f2b3d25a73d (patch) | |
tree | 5e99c7d880b473595733c9608a764e5671945bb6 /usb | |
parent | ce6089ada2fea84bef30a839543688664859162b (diff) | |
download | patches-824837789fc2c31455d2faf32d259f2b3d25a73d.tar.gz |
more usb patches
Diffstat (limited to 'usb')
-rw-r--r-- | usb/always-announce-new-usb-devices.patch | 6 | ||||
-rw-r--r-- | usb/usb-hub-use-usb_reset_composite_device.patch | 134 | ||||
-rw-r--r-- | usb/usb-new-devices-for-the-option-driver.patch | 275 | ||||
-rw-r--r-- | usb/usb-serial-dynamic-id.patch | 6 | ||||
-rw-r--r-- | usb/usb-storage-use-usb_reset_composite_device.patch | 161 | ||||
-rw-r--r-- | usb/usbcore-port-reset-for-composite-devices.patch | 177 | ||||
-rw-r--r-- | usb/usbcore-recovery-from-set-configuration-failure.patch | 199 | ||||
-rw-r--r-- | usb/usbhid-use-usb_reset_composite_device.patch | 93 |
8 files changed, 1045 insertions, 6 deletions
diff --git a/usb/always-announce-new-usb-devices.patch b/usb/always-announce-new-usb-devices.patch index 6f0cb775b4392..92c215956b3f3 100644 --- a/usb/always-announce-new-usb-devices.patch +++ b/usb/always-announce-new-usb-devices.patch @@ -14,7 +14,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- gregkh-2.6.orig/drivers/usb/core/hub.c +++ gregkh-2.6/drivers/usb/core/hub.c -@@ -1285,7 +1285,6 @@ static int choose_configuration(struct u +@@ -1289,7 +1289,6 @@ static int choose_configuration(struct u return i; } @@ -22,7 +22,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> static void show_string(struct usb_device *udev, char *id, char *string) { if (!string) -@@ -1293,10 +1292,6 @@ static void show_string(struct usb_devic +@@ -1297,10 +1296,6 @@ static void show_string(struct usb_devic dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, string); } @@ -33,7 +33,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> #ifdef CONFIG_USB_OTG -@@ -1341,7 +1336,10 @@ int usb_new_device(struct usb_device *ud +@@ -1345,7 +1340,10 @@ int usb_new_device(struct usb_device *ud udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); /* Tell the world! */ diff --git a/usb/usb-hub-use-usb_reset_composite_device.patch b/usb/usb-hub-use-usb_reset_composite_device.patch new file mode 100644 index 0000000000000..365d1fe34df73 --- /dev/null +++ b/usb/usb-hub-use-usb_reset_composite_device.patch @@ -0,0 +1,134 @@ +From stern@rowland.harvard.edu Thu Jun 1 10:37:33 2006 +Date: Thu, 1 Jun 2006 13:37:24 -0400 (EDT) +From: Alan Stern <stern@rowland.harvard.edu> +To: Greg KH <greg@kroah.com> +cc: USB development list <linux-usb-devel@lists.sourceforge.net> +Subject: USB hub: use usb_reset_composite_device +Message-ID: <Pine.LNX.4.44L0.0606011333440.5835-100000@iolanthe.rowland.org> + +This patch (as700) modifies the hub driver to take advantage of the new +usb_reset_composite_device API. The existing code had special-case +calls stuck into usb_reset_device, just before and after the reset. +With the new version there's no need for special-case stuff; it all +happens naturally in the form of pre_reset and post_reset notifications. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/core/hub.c | 34 +++++++++++++++------------------- + 1 file changed, 15 insertions(+), 19 deletions(-) + +--- gregkh-2.6.orig/drivers/usb/core/hub.c ++++ gregkh-2.6/drivers/usb/core/hub.c +@@ -525,15 +525,16 @@ static int hub_port_disable(struct usb_h + + + /* caller has locked the hub device */ +-static void hub_pre_reset(struct usb_hub *hub, int disable_ports) ++static void hub_pre_reset(struct usb_interface *intf) + { ++ struct usb_hub *hub = usb_get_intfdata(intf); + struct usb_device *hdev = hub->hdev; + int port1; + + for (port1 = 1; port1 <= hdev->maxchild; ++port1) { + if (hdev->children[port1 - 1]) { + usb_disconnect(&hdev->children[port1 - 1]); +- if (disable_ports) ++ if (hub->error == 0) + hub_port_disable(hub, port1, 0); + } + } +@@ -541,8 +542,10 @@ static void hub_pre_reset(struct usb_hub + } + + /* caller has locked the hub device */ +-static void hub_post_reset(struct usb_hub *hub) ++static void hub_post_reset(struct usb_interface *intf) + { ++ struct usb_hub *hub = usb_get_intfdata(intf); ++ + hub_activate(hub); + hub_power_on(hub); + } +@@ -802,15 +805,16 @@ static void hub_disconnect(struct usb_in + struct usb_hub *hub = usb_get_intfdata (intf); + struct usb_device *hdev; + ++ /* Disconnect all children and quiesce the hub */ ++ hub->error = 0; ++ hub_pre_reset(intf); ++ + usb_set_intfdata (intf, NULL); + hdev = hub->hdev; + + if (hdev->speed == USB_SPEED_HIGH) + highspeed_hubs--; + +- /* Disconnect all children and quiesce the hub */ +- hub_pre_reset(hub, 1); +- + usb_free_urb(hub->urb); + hub->urb = NULL; + +@@ -2747,7 +2751,8 @@ static void hub_events(void) + + /* If the hub has died, clean up after it */ + if (hdev->state == USB_STATE_NOTATTACHED) { +- hub_pre_reset(hub, 0); ++ hub->error = -ENODEV; ++ hub_pre_reset(intf); + goto loop; + } + +@@ -2759,7 +2764,7 @@ static void hub_events(void) + dev_dbg (hub_dev, "resetting for error %d\n", + hub->error); + +- ret = usb_reset_device(hdev); ++ ret = usb_reset_composite_device(hdev, intf); + if (ret) { + dev_dbg (hub_dev, + "error resetting hub: %d\n", ret); +@@ -2928,6 +2933,8 @@ static struct usb_driver hub_driver = { + .disconnect = hub_disconnect, + .suspend = hub_suspend, + .resume = hub_resume, ++ .pre_reset = hub_pre_reset, ++ .post_reset = hub_post_reset, + .ioctl = hub_ioctl, + .id_table = hub_id_table, + }; +@@ -3033,7 +3040,6 @@ int usb_reset_device(struct usb_device * + struct usb_device *parent_hdev = udev->parent; + struct usb_hub *parent_hub; + struct usb_device_descriptor descriptor = udev->descriptor; +- struct usb_hub *hub = NULL; + int i, ret = 0; + int port1 = udev->portnum; + +@@ -3051,14 +3057,6 @@ int usb_reset_device(struct usb_device * + } + parent_hub = hdev_to_hub(parent_hdev); + +- /* If we're resetting an active hub, take some special actions */ +- if (udev->actconfig && udev->actconfig->desc.bNumInterfaces > 0 && +- udev->actconfig->interface[0]->dev.driver == +- &hub_driver.driver && +- (hub = hdev_to_hub(udev)) != NULL) { +- hub_pre_reset(hub, 0); +- } +- + set_bit(port1, parent_hub->busy_bits); + for (i = 0; i < SET_CONFIG_TRIES; ++i) { + +@@ -3117,8 +3115,6 @@ int usb_reset_device(struct usb_device * + } + + done: +- if (hub) +- hub_post_reset(hub); + return 0; + + re_enumerate: diff --git a/usb/usb-new-devices-for-the-option-driver.patch b/usb/usb-new-devices-for-the-option-driver.patch new file mode 100644 index 0000000000000..dd6e2f011613c --- /dev/null +++ b/usb/usb-new-devices-for-the-option-driver.patch @@ -0,0 +1,275 @@ +From smurf@smurf.noris.de Fri Jun 2 03:16:29 2006 +Date: Fri, 2 Jun 2006 11:48:56 +0200 +From: Matthias Urlichs <smurf@smurf.noris.de> +Cc: greg@kroah.com +Subject: USB: new devices for the Option driver +Message-ID: <20060602094856.GD406@kiste.smurf.noris.de> +Content-Disposition: inline + +This patch extends the "option" driver with a few more devices, some of +which are actually connected to USB the "right" way -- as opposed to +doing it via PCMCIA and OHCI. + +Signed-Off-By: Matthias Urlichs <smurf@debian.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + +--- + drivers/usb/serial/Kconfig | 28 +++++++-- + drivers/usb/serial/option.c | 136 ++++++++++++++++++++++++++++++++++---------- + 2 files changed, 130 insertions(+), 34 deletions(-) + +--- gregkh-2.6.orig/drivers/usb/serial/Kconfig ++++ gregkh-2.6/drivers/usb/serial/Kconfig +@@ -491,12 +491,30 @@ config USB_SERIAL_XIRCOM + module will be called keyspan_pda. + + config USB_SERIAL_OPTION +- tristate "USB Option PCMCIA serial driver" +- depends on USB_SERIAL && USB_OHCI_HCD && PCCARD ++ tristate "USB driver for GSM modems" ++ depends on USB_SERIAL + help +- Say Y here if you want to use an Option card. This is a +- GSM card, controlled by three serial ports which are connected +- via an OHCI adapter located on a PC card. ++ Say Y here if you have a GSM modem that's connected to USB. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called option. ++ ++ If this driver doesn't recognize your device, ++ it might be accessible via the FTDI_SIO driver. ++ ++config USB_SERIAL_OPTION_PCCARD ++ tristate "driver for GSM modems on PCMCIA cards" ++ depends on USB_SERIAL ++ select PCCARD ++ select USB_OHCI_HCD ++ select USB_SERIAL_OPTION ++ help ++ Say Y here if you have an "Option" GSM PCMCIA card ++ (or an OEM version: branded Huawei, Audiovox, or Novatel). ++ ++ These cards feature a built-in OHCI-USB adapter and an ++ internally-connected GSM modem. The USB bus is not ++ accessible externally. + + To compile this driver as a module, choose M here: the + module will be called option. +--- gregkh-2.6.orig/drivers/usb/serial/option.c ++++ gregkh-2.6/drivers/usb/serial/option.c +@@ -1,5 +1,5 @@ + /* +- Option Card (PCMCIA to) USB to Serial Driver ++ USB Driver for GSM modems + + Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de> + +@@ -28,15 +28,34 @@ + 2005-09-10 v0.4.3 added HUAWEI E600 card and Audiovox AirCard + 2005-09-20 v0.4.4 increased recv buffer size: the card sometimes + wants to send >2000 bytes. +- 2006-04-10 v0.4.2 fixed two array overrun errors :-/ ++ 2006-04-10 v0.5 fixed two array overrun errors :-/ ++ 2006-04-21 v0.5.1 added support for Sierra Wireless MC8755 ++ 2006-05-15 v0.6 re-enable multi-port support ++ 2006-06-01 v0.6.1 add COBRA ++ 2006-06-01 v0.6.2 add backwards-compatibility stuff ++ 2006-06-01 v0.6.3 add Novatel Wireless ++ 2006-06-01 v0.7 Option => GSM + + Work sponsored by: Sigos GmbH, Germany <info@sigos.de> + ++ This driver exists because the "normal" serial driver doesn't work too well ++ with GSM modems. Issues: ++ - data loss -- one single Receive URB is not nearly enough ++ - nonstandard flow (Option devices) and multiplex (Sierra) control ++ - controlling the baud rate doesn't make sense ++ ++ This driver is named "option" because the most common device it's ++ used for is a PC-Card (with an internal OHCI-USB interface, behind ++ which the GSM interface sits), made by Option Inc. ++ ++ Some of the "one port" devices actually exhibit multiple USB instances ++ on the USB bus. This is not a bug, these ports are used for different ++ device features. + */ + +-#define DRIVER_VERSION "v0.4" ++#define DRIVER_VERSION "v0.7.0" + #define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>" +-#define DRIVER_DESC "Option Card (PC-Card to) USB to Serial Driver" ++#define DRIVER_DESC "USB Driver for GSM modems" + + #include <linux/config.h> + #include <linux/kernel.h> +@@ -74,22 +93,45 @@ static int option_tiocmset(struct usb_s + static int option_send_setup(struct usb_serial_port *port); + + /* Vendor and product IDs */ +-#define OPTION_VENDOR_ID 0x0AF0 +-#define HUAWEI_VENDOR_ID 0x12D1 +-#define AUDIOVOX_VENDOR_ID 0x0F3D +- +-#define OPTION_PRODUCT_OLD 0x5000 +-#define OPTION_PRODUCT_FUSION 0x6000 +-#define OPTION_PRODUCT_FUSION2 0x6300 +-#define HUAWEI_PRODUCT_E600 0x1001 +-#define AUDIOVOX_PRODUCT_AIRCARD 0x0112 ++#define OPTION_VENDOR_ID 0x0AF0 ++#define HUAWEI_VENDOR_ID 0x12D1 ++#define AUDIOVOX_VENDOR_ID 0x0F3D ++#define SIERRAWIRELESS_VENDOR_ID 0x1199 ++#define NOVATELWIRELESS_VENDOR_ID 0x1410 ++ ++#define OPTION_PRODUCT_OLD 0x5000 ++#define OPTION_PRODUCT_FUSION 0x6000 ++#define OPTION_PRODUCT_FUSION2 0x6300 ++#define OPTION_PRODUCT_COBRA 0x6500 ++#define HUAWEI_PRODUCT_E600 0x1001 ++#define AUDIOVOX_PRODUCT_AIRCARD 0x0112 ++#define SIERRAWIRELESS_PRODUCT_MC8755 0x6802 ++#define NOVATELWIRELESS_PRODUCT_U740 0x1400 + + static struct usb_device_id option_ids[] = { + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, ++ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) }, + { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, + { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, ++ { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) }, ++ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, ++ { } /* Terminating entry */ ++}; ++ ++static struct usb_device_id option_ids1[] = { ++ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) }, ++ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) }, ++ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, ++ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) }, ++ { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, ++ { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, ++ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, ++ { } /* Terminating entry */ ++}; ++static struct usb_device_id option_ids3[] = { ++ { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) }, + { } /* Terminating entry */ + }; + +@@ -111,12 +153,39 @@ static struct usb_serial_driver option_3 + .owner = THIS_MODULE, + .name = "option", + }, +- .description = "Option 3G data card", +- .id_table = option_ids, ++ .description = "GSM modem (3-port)", ++ .id_table = option_ids3, ++ .num_interrupt_in = NUM_DONT_CARE, ++ .num_bulk_in = NUM_DONT_CARE, ++ .num_bulk_out = NUM_DONT_CARE, ++ .num_ports = 3, ++ .open = option_open, ++ .close = option_close, ++ .write = option_write, ++ .write_room = option_write_room, ++ .chars_in_buffer = option_chars_in_buffer, ++ .throttle = option_rx_throttle, ++ .unthrottle = option_rx_unthrottle, ++ .set_termios = option_set_termios, ++ .break_ctl = option_break_ctl, ++ .tiocmget = option_tiocmget, ++ .tiocmset = option_tiocmset, ++ .attach = option_startup, ++ .shutdown = option_shutdown, ++ .read_int_callback = option_instat_callback, ++}; ++ ++static struct usb_serial_driver option_1port_device = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "option", ++ }, ++ .description = "GSM modem (1-port)", ++ .id_table = option_ids1, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = NUM_DONT_CARE, + .num_bulk_out = NUM_DONT_CARE, +- .num_ports = 1, /* 3, but the card reports its ports separately */ ++ .num_ports = 1, + .open = option_open, + .close = option_close, + .write = option_write, +@@ -170,6 +239,9 @@ struct option_port_private { + static int __init option_init(void) + { + int retval; ++ retval = usb_serial_register(&option_1port_device); ++ if (retval) ++ goto failed_1port_device_register; + retval = usb_serial_register(&option_3port_device); + if (retval) + goto failed_3port_device_register; +@@ -184,6 +256,8 @@ static int __init option_init(void) + failed_driver_register: + usb_serial_deregister (&option_3port_device); + failed_3port_device_register: ++ usb_serial_deregister (&option_1port_device); ++failed_1port_device_register: + return retval; + } + +@@ -191,6 +265,7 @@ static void __exit option_exit(void) + { + usb_deregister (&option_driver); + usb_serial_deregister (&option_3port_device); ++ usb_serial_deregister (&option_1port_device); + } + + module_init(option_init); +@@ -572,27 +647,30 @@ static struct urb *option_setup_urb(stru + /* Setup urbs */ + static void option_setup_urbs(struct usb_serial *serial) + { +- int j; ++ int i,j; + struct usb_serial_port *port; + struct option_port_private *portdata; + + dbg("%s", __FUNCTION__); + +- port = serial->port[0]; +- portdata = usb_get_serial_port_data(port); ++ ++ for (i = 0; i < serial->num_ports; i++) { ++ port = serial->port[i]; ++ portdata = usb_get_serial_port_data(port); + + /* Do indat endpoints first */ +- for (j = 0; j < N_IN_URB; ++j) { +- portdata->in_urbs[j] = option_setup_urb (serial, +- port->bulk_in_endpointAddress, USB_DIR_IN, port, +- portdata->in_buffer[j], IN_BUFLEN, option_indat_callback); +- } ++ for (j = 0; j < N_IN_URB; ++j) { ++ portdata->in_urbs[j] = option_setup_urb (serial, ++ port->bulk_in_endpointAddress, USB_DIR_IN, port, ++ portdata->in_buffer[j], IN_BUFLEN, option_indat_callback); ++ } + +- /* outdat endpoints */ +- for (j = 0; j < N_OUT_URB; ++j) { +- portdata->out_urbs[j] = option_setup_urb (serial, +- port->bulk_out_endpointAddress, USB_DIR_OUT, port, +- portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback); ++ /* outdat endpoints */ ++ for (j = 0; j < N_OUT_URB; ++j) { ++ portdata->out_urbs[j] = option_setup_urb (serial, ++ port->bulk_out_endpointAddress, USB_DIR_OUT, port, ++ portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback); ++ } + } + } + diff --git a/usb/usb-serial-dynamic-id.patch b/usb/usb-serial-dynamic-id.patch index 238c06f401f86..64abcdb9f292f 100644 --- a/usb/usb-serial-dynamic-id.patch +++ b/usb/usb-serial-dynamic-id.patch @@ -284,7 +284,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- gregkh-2.6.orig/include/linux/usb.h +++ gregkh-2.6/include/linux/usb.h -@@ -417,6 +417,8 @@ extern void usb_driver_release_interface +@@ -419,6 +419,8 @@ extern void usb_driver_release_interface struct usb_interface *iface); const struct usb_device_id *usb_match_id(struct usb_interface *interface, const struct usb_device_id *id); @@ -293,7 +293,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> extern struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor); -@@ -531,11 +533,21 @@ static inline int usb_make_path (struct +@@ -533,11 +535,21 @@ static inline int usb_make_path (struct /* ----------------------------------------------------------------------- */ @@ -315,7 +315,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> /** * struct usb_driver - identifies USB driver to usbcore * @name: The driver name should be unique among USB drivers, -@@ -1192,6 +1204,7 @@ usb_maxpacket(struct usb_device *udev, i +@@ -1201,6 +1213,7 @@ usb_maxpacket(struct usb_device *udev, i extern void usb_register_notify(struct notifier_block *nb); extern void usb_unregister_notify(struct notifier_block *nb); diff --git a/usb/usb-storage-use-usb_reset_composite_device.patch b/usb/usb-storage-use-usb_reset_composite_device.patch new file mode 100644 index 0000000000000..7d071bf4e8db8 --- /dev/null +++ b/usb/usb-storage-use-usb_reset_composite_device.patch @@ -0,0 +1,161 @@ +From linux-usb-devel-bounces@lists.sourceforge.net Thu Jun 1 10:53:25 2006 +Date: Thu, 1 Jun 2006 13:52:56 -0400 (EDT) +From: Alan Stern <stern@rowland.harvard.edu> +To: Greg KH <greg@kroah.com> +Message-ID: <Pine.LNX.4.44L0.0606011337250.5835-100000@iolanthe.rowland.org> +Cc: Matthew Dharm <mdharm-usb@one-eyed-alien.net> +Subject: usb-storage: use usb_reset_composite_device + +This patch (as701) modifies usb-storage to take advantage of the new +usb_reset_composite_device() API. Now we will be able to safely request +port resets even if other drivers are bound to a mass-storage device. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/storage/scsiglue.c | 4 --- + drivers/usb/storage/transport.c | 50 ++++++++++++++++++++-------------------- + drivers/usb/storage/usb.c | 33 ++++++++++++++++++++++++++ + 3 files changed, 59 insertions(+), 28 deletions(-) + +--- gregkh-2.6.orig/drivers/usb/storage/scsiglue.c ++++ gregkh-2.6/drivers/usb/storage/scsiglue.c +@@ -286,11 +286,7 @@ static int bus_reset(struct scsi_cmnd *s + int result; + + US_DEBUGP("%s called\n", __FUNCTION__); +- +- mutex_lock(&(us->dev_mutex)); + result = usb_stor_port_reset(us); +- mutex_unlock(&us->dev_mutex); +- + return result < 0 ? FAILED : SUCCESS; + } + +--- gregkh-2.6.orig/drivers/usb/storage/transport.c ++++ gregkh-2.6/drivers/usb/storage/transport.c +@@ -703,16 +703,19 @@ void usb_stor_invoke_transport(struct sc + * device reset. */ + Handle_Errors: + +- /* Let the SCSI layer know we are doing a reset, set the +- * RESETTING bit, and clear the ABORTING bit so that the reset +- * may proceed. */ ++ /* Set the RESETTING bit, and clear the ABORTING bit so that ++ * the reset may proceed. */ + scsi_lock(us_to_host(us)); +- usb_stor_report_bus_reset(us); + set_bit(US_FLIDX_RESETTING, &us->flags); + clear_bit(US_FLIDX_ABORTING, &us->flags); + scsi_unlock(us_to_host(us)); + ++ /* We must release the device lock because the pre_reset routine ++ * will want to acquire it. */ ++ mutex_unlock(&us->dev_mutex); + result = usb_stor_port_reset(us); ++ mutex_lock(&us->dev_mutex); ++ + if (result < 0) { + scsi_lock(us_to_host(us)); + usb_stor_report_device_reset(us); +@@ -1196,31 +1199,30 @@ int usb_stor_Bulk_reset(struct us_data * + 0, us->ifnum, NULL, 0); + } + +-/* Issue a USB port reset to the device. But don't do anything if +- * there's more than one interface in the device, so that other users +- * are not affected. */ ++/* Issue a USB port reset to the device. The caller must not hold ++ * us->dev_mutex. ++ */ + int usb_stor_port_reset(struct us_data *us) + { +- int result, rc; ++ int result, rc_lock; + +- if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { +- result = -EIO; +- US_DEBUGP("No reset during disconnect\n"); +- } else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) { +- result = -EBUSY; +- US_DEBUGP("Refusing to reset a multi-interface device\n"); +- } else { +- result = rc = +- usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf); +- if (result < 0) { +- US_DEBUGP("unable to lock device for reset: %d\n", +- result); ++ result = rc_lock = ++ usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf); ++ if (result < 0) ++ US_DEBUGP("unable to lock device for reset: %d\n", result); ++ else { ++ /* Were we disconnected while waiting for the lock? */ ++ if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { ++ result = -EIO; ++ US_DEBUGP("No reset during disconnect\n"); + } else { +- result = usb_reset_device(us->pusb_dev); +- if (rc) +- usb_unlock_device(us->pusb_dev); +- US_DEBUGP("usb_reset_device returns %d\n", result); ++ result = usb_reset_composite_device( ++ us->pusb_dev, us->pusb_intf); ++ US_DEBUGP("usb_reset_composite_device returns %d\n", ++ result); + } ++ if (rc_lock) ++ usb_unlock_device(us->pusb_dev); + } + return result; + } +--- gregkh-2.6.orig/drivers/usb/storage/usb.c ++++ gregkh-2.6/drivers/usb/storage/usb.c +@@ -221,6 +221,37 @@ static int storage_resume(struct usb_int + #endif /* CONFIG_PM */ + + /* ++ * The next two routines get called just before and just after ++ * a USB port reset, whether from this driver or a different one. ++ */ ++ ++static void storage_pre_reset(struct usb_interface *iface) ++{ ++ struct us_data *us = usb_get_intfdata(iface); ++ ++ US_DEBUGP("%s\n", __FUNCTION__); ++ ++ /* Make sure no command runs during the reset */ ++ mutex_lock(&us->dev_mutex); ++} ++ ++static void storage_post_reset(struct usb_interface *iface) ++{ ++ struct us_data *us = usb_get_intfdata(iface); ++ ++ US_DEBUGP("%s\n", __FUNCTION__); ++ ++ /* Report the reset to the SCSI core */ ++ scsi_lock(us_to_host(us)); ++ usb_stor_report_bus_reset(us); ++ scsi_unlock(us_to_host(us)); ++ ++ /* FIXME: Notify the subdrivers that they need to reinitialize ++ * the device */ ++ mutex_unlock(&us->dev_mutex); ++} ++ ++/* + * fill_inquiry_response takes an unsigned char array (which must + * be at least 36 characters) and populates the vendor name, + * product name, and revision fields. Then the array is copied +@@ -1002,6 +1033,8 @@ static struct usb_driver usb_storage_dri + .suspend = storage_suspend, + .resume = storage_resume, + #endif ++ .pre_reset = storage_pre_reset, ++ .post_reset = storage_post_reset, + .id_table = storage_usb_ids, + }; + diff --git a/usb/usbcore-port-reset-for-composite-devices.patch b/usb/usbcore-port-reset-for-composite-devices.patch new file mode 100644 index 0000000000000..29a95ad337fe1 --- /dev/null +++ b/usb/usbcore-port-reset-for-composite-devices.patch @@ -0,0 +1,177 @@ +From stern@rowland.harvard.edu Thu Jun 1 10:33:52 2006 +Date: Thu, 1 Jun 2006 13:33:42 -0400 (EDT) +From: Alan Stern <stern@rowland.harvard.edu> +To: Greg KH <greg@kroah.com> +Subject: usbcore: port reset for composite devices +Message-ID: <Pine.LNX.4.44L0.0606011328470.5835-100000@iolanthe.rowland.org> + +This patch (as699) adds usb_reset_composite_device(), a routine for +sending a USB port reset to a device with multiple interfaces owned by +different drivers. Drivers are notified about impending and completed +resets through two new methods in the usb_driver structure. + +The patch modifieds the usbfs ioctl code to make it use the new routine +instead of usb_reset_device(). Follow-up patches will modify the hub, +usb-storage, and usbhid drivers so they can utilize this new API. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/core/devio.c | 3 - + drivers/usb/core/hub.c | 84 +++++++++++++++++++++++++++++++++++++++++++++-- + drivers/usb/core/usb.c | 1 + include/linux/usb.h | 9 +++++ + 4 files changed, 92 insertions(+), 5 deletions(-) + +--- gregkh-2.6.orig/drivers/usb/core/devio.c ++++ gregkh-2.6/drivers/usb/core/devio.c +@@ -823,8 +823,7 @@ static int proc_connectinfo(struct dev_s + + static int proc_resetdevice(struct dev_state *ps) + { +- return usb_reset_device(ps->dev); +- ++ return usb_reset_composite_device(ps->dev, NULL); + } + + static int proc_setintf(struct dev_state *ps, void __user *arg) +--- gregkh-2.6.orig/drivers/usb/core/hub.c ++++ gregkh-2.6/drivers/usb/core/hub.c +@@ -3007,9 +3007,9 @@ static int config_descriptors_changed(st + * usb_reset_device - perform a USB port reset to reinitialize a device + * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) + * +- * WARNING - don't reset any device unless drivers for all of its +- * interfaces are expecting that reset! Maybe some driver->reset() +- * method should eventually help ensure sufficient cooperation. ++ * WARNING - don't use this routine to reset a composite device ++ * (one with multiple interfaces owned by separate drivers)! ++ * Use usb_reset_composite_device() instead. + * + * Do a port reset, reassign the device's address, and establish its + * former operating configuration. If the reset fails, or the device's +@@ -3125,3 +3125,81 @@ re_enumerate: + hub_port_logical_disconnect(parent_hub, port1); + return -ENODEV; + } ++ ++/** ++ * usb_reset_composite_device - warn interface drivers and perform a USB port reset ++ * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) ++ * @iface: interface bound to the driver making the request (optional) ++ * ++ * Warns all drivers bound to registered interfaces (using their pre_reset ++ * method), performs the port reset, and then lets the drivers know that ++ * the reset is over (using their post_reset method). ++ * ++ * Return value is the same as for usb_reset_device(). ++ * ++ * The caller must own the device lock. For example, it's safe to use ++ * this from a driver probe() routine after downloading new firmware. ++ * For calls that might not occur during probe(), drivers should lock ++ * the device using usb_lock_device_for_reset(). ++ * ++ * The interface locks are acquired during the pre_reset stage and released ++ * during the post_reset stage. However if iface is not NULL and is ++ * currently being probed, we assume that the caller already owns its ++ * lock. ++ */ ++int usb_reset_composite_device(struct usb_device *udev, ++ struct usb_interface *iface) ++{ ++ int ret; ++ struct usb_host_config *config = udev->actconfig; ++ ++ if (udev->state == USB_STATE_NOTATTACHED || ++ udev->state == USB_STATE_SUSPENDED) { ++ dev_dbg(&udev->dev, "device reset not allowed in state %d\n", ++ udev->state); ++ return -EINVAL; ++ } ++ ++ if (iface && iface->condition != USB_INTERFACE_BINDING) ++ iface = NULL; ++ ++ if (config) { ++ int i; ++ struct usb_interface *cintf; ++ struct usb_driver *drv; ++ ++ for (i = 0; i < config->desc.bNumInterfaces; ++i) { ++ cintf = config->interface[i]; ++ if (cintf != iface) ++ down(&cintf->dev.sem); ++ if (device_is_registered(&cintf->dev) && ++ cintf->dev.driver) { ++ drv = to_usb_driver(cintf->dev.driver); ++ if (drv->pre_reset) ++ (drv->pre_reset)(cintf); ++ } ++ } ++ } ++ ++ ret = usb_reset_device(udev); ++ ++ if (config) { ++ int i; ++ struct usb_interface *cintf; ++ struct usb_driver *drv; ++ ++ for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) { ++ cintf = config->interface[i]; ++ if (device_is_registered(&cintf->dev) && ++ cintf->dev.driver) { ++ drv = to_usb_driver(cintf->dev.driver); ++ if (drv->post_reset) ++ (drv->post_reset)(cintf); ++ } ++ if (cintf != iface) ++ up(&cintf->dev.sem); ++ } ++ } ++ ++ return ret; ++} +--- gregkh-2.6.orig/drivers/usb/core/usb.c ++++ gregkh-2.6/drivers/usb/core/usb.c +@@ -1207,6 +1207,7 @@ EXPORT_SYMBOL(usb_ifnum_to_if); + EXPORT_SYMBOL(usb_altnum_to_altsetting); + + EXPORT_SYMBOL(usb_reset_device); ++EXPORT_SYMBOL(usb_reset_composite_device); + + EXPORT_SYMBOL(__usb_get_extra_descriptor); + +--- gregkh-2.6.orig/include/linux/usb.h ++++ gregkh-2.6/include/linux/usb.h +@@ -387,6 +387,8 @@ extern int usb_lock_device_for_reset(str + + /* USB port reset for device reinitialization */ + extern int usb_reset_device(struct usb_device *dev); ++extern int usb_reset_composite_device(struct usb_device *dev, ++ struct usb_interface *iface); + + extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id); + +@@ -555,6 +557,10 @@ struct usb_dynids { + * do (or don't) show up otherwise in the filesystem. + * @suspend: Called when the device is going to be suspended by the system. + * @resume: Called when the device is being resumed by the system. ++ * @pre_reset: Called by usb_reset_composite_device() when the device ++ * is about to be reset. ++ * @post_reset: Called by usb_reset_composite_device() after the device ++ * has been reset. + * @id_table: USB drivers use ID table to support hotplugging. + * Export this with MODULE_DEVICE_TABLE(usb,...). This must be set + * or your driver's probe function will never get called. +@@ -593,6 +599,9 @@ struct usb_driver { + int (*suspend) (struct usb_interface *intf, pm_message_t message); + int (*resume) (struct usb_interface *intf); + ++ void (*pre_reset) (struct usb_interface *intf); ++ void (*post_reset) (struct usb_interface *intf); ++ + const struct usb_device_id *id_table; + + struct usb_dynids dynids; diff --git a/usb/usbcore-recovery-from-set-configuration-failure.patch b/usb/usbcore-recovery-from-set-configuration-failure.patch new file mode 100644 index 0000000000000..66c534a1b2215 --- /dev/null +++ b/usb/usbcore-recovery-from-set-configuration-failure.patch @@ -0,0 +1,199 @@ +From stern@rowland.harvard.edu Thu Jun 1 10:59:20 2006 +Date: Thu, 1 Jun 2006 13:59:16 -0400 (EDT) +From: Alan Stern <stern@rowland.harvard.edu> +To: Greg KH <greg@kroah.com> +Subject: usbcore: recovery from Set-Configuration failure +Message-ID: <Pine.LNX.4.44L0.0606011355330.7209-100000@iolanthe.rowland.org> + +This patch (as703) improves the error handling when a Set-Configuration +request fails. The old interfaces are all unregistered before the +request is sent, and if the request fails then we don't know what config +the device is using. So it makes no sense to leave actconfig pointing +to the old configuration with its invalid interfaces. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + +--- + drivers/usb/core/message.c | 151 ++++++++++++++++++++++----------------------- + 1 file changed, 75 insertions(+), 76 deletions(-) + +--- gregkh-2.6.orig/drivers/usb/core/message.c ++++ gregkh-2.6/drivers/usb/core/message.c +@@ -1411,15 +1411,7 @@ free_interfaces: + return ret; + } + } +- } +- +- /* if it's already configured, clear out old state first. +- * getting rid of old interfaces means unbinding their drivers. +- */ +- if (dev->state != USB_STATE_ADDRESS) +- usb_disable_device (dev, 1); // Skip ep0 + +- if (cp) { + i = dev->bus_mA - cp->desc.bMaxPower * 2; + if (i < 0) + dev_warn(&dev->dev, "new config #%d exceeds power " +@@ -1427,84 +1419,91 @@ free_interfaces: + configuration, -i); + } + ++ /* if it's already configured, clear out old state first. ++ * getting rid of old interfaces means unbinding their drivers. ++ */ ++ if (dev->state != USB_STATE_ADDRESS) ++ usb_disable_device (dev, 1); // Skip ep0 ++ + if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_CONFIGURATION, 0, configuration, 0, +- NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) +- goto free_interfaces; ++ NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) { ++ ++ /* All the old state is gone, so what else can we do? ++ * The device is probably useless now anyway. ++ */ ++ cp = NULL; ++ } + + dev->actconfig = cp; +- if (!cp) ++ if (!cp) { + usb_set_device_state(dev, USB_STATE_ADDRESS); +- else { +- usb_set_device_state(dev, USB_STATE_CONFIGURED); ++ goto free_interfaces; ++ } ++ usb_set_device_state(dev, USB_STATE_CONFIGURED); + +- /* Initialize the new interface structures and the +- * hc/hcd/usbcore interface/endpoint state. ++ /* Initialize the new interface structures and the ++ * hc/hcd/usbcore interface/endpoint state. ++ */ ++ for (i = 0; i < nintf; ++i) { ++ struct usb_interface_cache *intfc; ++ struct usb_interface *intf; ++ struct usb_host_interface *alt; ++ ++ cp->interface[i] = intf = new_interfaces[i]; ++ intfc = cp->intf_cache[i]; ++ intf->altsetting = intfc->altsetting; ++ intf->num_altsetting = intfc->num_altsetting; ++ kref_get(&intfc->ref); ++ ++ alt = usb_altnum_to_altsetting(intf, 0); ++ ++ /* No altsetting 0? We'll assume the first altsetting. ++ * We could use a GetInterface call, but if a device is ++ * so non-compliant that it doesn't have altsetting 0 ++ * then I wouldn't trust its reply anyway. + */ +- for (i = 0; i < nintf; ++i) { +- struct usb_interface_cache *intfc; +- struct usb_interface *intf; +- struct usb_host_interface *alt; +- +- cp->interface[i] = intf = new_interfaces[i]; +- intfc = cp->intf_cache[i]; +- intf->altsetting = intfc->altsetting; +- intf->num_altsetting = intfc->num_altsetting; +- kref_get(&intfc->ref); +- +- alt = usb_altnum_to_altsetting(intf, 0); +- +- /* No altsetting 0? We'll assume the first altsetting. +- * We could use a GetInterface call, but if a device is +- * so non-compliant that it doesn't have altsetting 0 +- * then I wouldn't trust its reply anyway. +- */ +- if (!alt) +- alt = &intf->altsetting[0]; +- +- intf->cur_altsetting = alt; +- usb_enable_interface(dev, intf); +- intf->dev.parent = &dev->dev; +- intf->dev.driver = NULL; +- intf->dev.bus = &usb_bus_type; +- intf->dev.dma_mask = dev->dev.dma_mask; +- intf->dev.release = release_interface; +- device_initialize (&intf->dev); +- mark_quiesced(intf); +- sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", +- dev->bus->busnum, dev->devpath, +- configuration, +- alt->desc.bInterfaceNumber); +- } +- kfree(new_interfaces); ++ if (!alt) ++ alt = &intf->altsetting[0]; + +- if (cp->string == NULL) +- cp->string = usb_cache_string(dev, +- cp->desc.iConfiguration); +- +- /* Now that all the interfaces are set up, register them +- * to trigger binding of drivers to interfaces. probe() +- * routines may install different altsettings and may +- * claim() any interfaces not yet bound. Many class drivers +- * need that: CDC, audio, video, etc. +- */ +- for (i = 0; i < nintf; ++i) { +- struct usb_interface *intf = cp->interface[i]; ++ intf->cur_altsetting = alt; ++ usb_enable_interface(dev, intf); ++ intf->dev.parent = &dev->dev; ++ intf->dev.driver = NULL; ++ intf->dev.bus = &usb_bus_type; ++ intf->dev.dma_mask = dev->dev.dma_mask; ++ intf->dev.release = release_interface; ++ device_initialize (&intf->dev); ++ mark_quiesced(intf); ++ sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", ++ dev->bus->busnum, dev->devpath, ++ configuration, alt->desc.bInterfaceNumber); ++ } ++ kfree(new_interfaces); + +- dev_dbg (&dev->dev, +- "adding %s (config #%d, interface %d)\n", +- intf->dev.bus_id, configuration, +- intf->cur_altsetting->desc.bInterfaceNumber); +- ret = device_add (&intf->dev); +- if (ret != 0) { +- dev_err(&dev->dev, +- "device_add(%s) --> %d\n", +- intf->dev.bus_id, +- ret); +- continue; +- } +- usb_create_sysfs_intf_files (intf); ++ if (cp->string == NULL) ++ cp->string = usb_cache_string(dev, cp->desc.iConfiguration); ++ ++ /* Now that all the interfaces are set up, register them ++ * to trigger binding of drivers to interfaces. probe() ++ * routines may install different altsettings and may ++ * claim() any interfaces not yet bound. Many class drivers ++ * need that: CDC, audio, video, etc. ++ */ ++ for (i = 0; i < nintf; ++i) { ++ struct usb_interface *intf = cp->interface[i]; ++ ++ dev_dbg (&dev->dev, ++ "adding %s (config #%d, interface %d)\n", ++ intf->dev.bus_id, configuration, ++ intf->cur_altsetting->desc.bInterfaceNumber); ++ ret = device_add (&intf->dev); ++ if (ret != 0) { ++ dev_err(&dev->dev, "device_add(%s) --> %d\n", ++ intf->dev.bus_id, ret); ++ continue; + } ++ usb_create_sysfs_intf_files (intf); + } + + return 0; diff --git a/usb/usbhid-use-usb_reset_composite_device.patch b/usb/usbhid-use-usb_reset_composite_device.patch new file mode 100644 index 0000000000000..a80e7e02b0adf --- /dev/null +++ b/usb/usbhid-use-usb_reset_composite_device.patch @@ -0,0 +1,93 @@ +From stern@rowland.harvard.edu Thu Jun 1 10:55:36 2006 +Date: Thu, 1 Jun 2006 13:55:28 -0400 (EDT) +From: Alan Stern <stern@rowland.harvard.edu> +To: Greg KH <greg@kroah.com>, Dmitry Torokhov <dtor_core@ameritech.net>, Vojtech Pavlik <vojtech@suse.cz> +Subject: usbhid: use usb_reset_composite_device +Message-ID: <Pine.LNX.4.44L0.0606011350500.7209-100000@iolanthe.rowland.org> + +This patch (as702) makes usbhid use the new usb_reset_composite_device +API. Now HID interfaces can coexist with other interfaces on the same +device, and a reset can safely be requested by any of the drivers. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/input/hid-core.c | 37 ++++++++++++++++++++++++++++++++----- + 1 file changed, 32 insertions(+), 5 deletions(-) + +--- gregkh-2.6.orig/drivers/usb/input/hid-core.c ++++ gregkh-2.6/drivers/usb/input/hid-core.c +@@ -944,21 +944,28 @@ static void hid_reset(void *_hid) + dev_dbg(&hid->intf->dev, "resetting device\n"); + rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf); + if (rc_lock >= 0) { +- rc = usb_reset_device(hid->dev); ++ rc = usb_reset_composite_device(hid->dev, hid->intf); + if (rc_lock) + usb_unlock_device(hid->dev); + } + clear_bit(HID_RESET_PENDING, &hid->iofl); + +- if (rc == 0) { +- hid->retry_delay = 0; +- if (hid_start_in(hid)) ++ switch (rc) { ++ case 0: ++ if (!test_bit(HID_IN_RUNNING, &hid->iofl)) + hid_io_error(hid); +- } else if (!(rc == -ENODEV || rc == -EHOSTUNREACH || rc == -EINTR)) ++ break; ++ default: + err("can't reset device, %s-%s/input%d, status %d", + hid->dev->bus->bus_name, + hid->dev->devpath, + hid->ifnum, rc); ++ /* FALLTHROUGH */ ++ case -EHOSTUNREACH: ++ case -ENODEV: ++ case -EINTR: ++ break; ++ } + } + + /* Main I/O error handler */ +@@ -2063,11 +2070,29 @@ static int hid_resume(struct usb_interfa + int status; + + clear_bit(HID_SUSPENDED, &hid->iofl); ++ hid->retry_delay = 0; + status = hid_start_in(hid); + dev_dbg(&intf->dev, "resume status %d\n", status); + return status; + } + ++/* Treat USB reset pretty much the same as suspend/resume */ ++static void hid_pre_reset(struct usb_interface *intf) ++{ ++ /* FIXME: What if the interface is already suspended? */ ++ hid_suspend(intf, PMSG_ON); ++} ++ ++static void hid_post_reset(struct usb_interface *intf) ++{ ++ struct usb_device *dev = interface_to_usbdev (intf); ++ ++ hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0); ++ /* FIXME: Any more reinitialization needed? */ ++ ++ hid_resume(intf); ++} ++ + static struct usb_device_id hid_usb_ids [] = { + { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, + .bInterfaceClass = USB_INTERFACE_CLASS_HID }, +@@ -2082,6 +2107,8 @@ static struct usb_driver hid_driver = { + .disconnect = hid_disconnect, + .suspend = hid_suspend, + .resume = hid_resume, ++ .pre_reset = hid_pre_reset, ++ .post_reset = hid_post_reset, + .id_table = hid_usb_ids, + }; + |