bk://kernel.bkbits.net/gregkh/linux/usb-2.6 greg@kroah.com|ChangeSet|20040730235546|50349 greg # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/07/30 16:55:46-07:00 greg@kroah.com # USB: fix build error in the cyberjack driver # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/serial/cyberjack.c # 2004/07/30 16:55:16-07:00 greg@kroah.com +1 -0 # USB: fix build error in the cyberjack driver # # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2004/07/30 16:38:58-07:00 luca.risolia@studio.unibo.it # [PATCH] USB: New entry in MAINTAINERS # # I forgot to add an entry in MAINTAINERS about the new SN9C10[12] driver. # # Signed-off-by: Luca Risolia # Signed-off-by: Greg Kroah-Hartman # # MAINTAINERS # 2004/07/15 04:04:07-07:00 luca.risolia@studio.unibo.it +7 -0 # USB: New entry in MAINTAINERS # # ChangeSet # 2004/07/30 16:38:38-07:00 stern@rowland.harvard.edu # [PATCH] USB: unusual_devs.h update # # In view of the comments below, I think we should modify this # unusual_devs.h entry to suppress the warning messages. Please apply. # # # # On Mon, 28 Jun 2004, Joël Bourquard wrote: # # > There seem to be two different flavors of ISD-300 (ie: 05ab,0060) # > devices, one of which needs this entry to work, and the other doesn't. # > # > I have a 2 1/2'' HDD enclosure which (just like your device) doesn't # > need the entry (so when I plug it, I get the same warning as you). # > # > However, I also happen to own two 5 1/4'' CD-ROM enclosures, for which # > this entry *is* necessary. I tried again, very recently to remove my # > unusual_devs.h entry, and it prevented them from working. # > # > So, I think the entry should be kept (it does more good than harm), but # > maybe it could get some tweaking ? If there's a way to recognize these # > "CD-ROM enclosure" bridge chips and exclude the others, I'm all for it. # # # # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/storage/unusual_devs.h # 2004/07/19 04:26:41-07:00 stern@rowland.harvard.edu +6 -2 # USB: unusual_devs.h update # # ChangeSet # 2004/07/30 16:38:21-07:00 stern@rowland.harvard.edu # [PATCH] USB: unusual_devs.h update # # Just like in as347, we have another example of descriptors that vary from # device to device. Please apply this patch to suppress the warning # message. # # On Fri, 16 Jul 2004, Ken Yap wrote: # # > Jul 16 21:44:20 media kernel: usb-storage: This device (090a,1001,0100 S 06 P 50) has an unneeded Protocol entry in unusual_devs.h # > Jul 16 21:44:20 media kernel: Please send a copy of this message to # # # # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/storage/unusual_devs.h # 2004/07/19 04:35:14-07:00 stern@rowland.harvard.edu +1 -1 # USB: unusual_devs.h update # # ChangeSet # 2004/07/30 16:38:02-07:00 johann.cardon@free.fr # [PATCH] USB: New unusual_devs.h entry # # Please merge this new entry for the unusual_devs.h database. # # From: Johann Cardon # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/storage/unusual_devs.h # 2004/07/19 04:43:38-07:00 johann.cardon@free.fr +9 -0 # USB: New unusual_devs.h entry # # ChangeSet # 2004/07/30 16:37:43-07:00 domen@coderock.org # [PATCH] USB: use list_for_each() in core/devices.c # # Signed-off-by: Maximilian Attems # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/core/devices.c # 2004/07/11 05:41:36-07:00 domen@coderock.org +1 -1 # USB: use list_for_each() in core/devices.c # # ChangeSet # 2004/07/30 16:37:24-07:00 domen@coderock.org # [PATCH] USB: use list_for_each() in class/usb-midi.c # # Signed-off-by: Maximilian Attems # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/class/usb-midi.c # 2004/07/11 05:41:39-07:00 domen@coderock.org +3 -3 # USB: use list_for_each() in class/usb-midi.c # # ChangeSet # 2004/07/30 16:37:05-07:00 domen@coderock.org # [PATCH] USB: use list_for_each() in class/audio.c # # Signed-off-by: Maximilian Attems # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/class/audio.c # 2004/07/11 05:41:32-07:00 domen@coderock.org +6 -6 # USB: use list_for_each() in class/audio.c # # ChangeSet # 2004/07/30 16:36:42-07:00 ganesh@veritas.com # [PATCH] USB: fix for ipaq.c # # as per pete and greg's input, fixing only the uninitialized variable. # # Signed-off-by: Ganesh Varadarajan # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/serial/ipaq.c # 2004/07/22 08:42:31-07:00 ganesh@veritas.com +1 -0 # USB: fix for ipaq.c # # ChangeSet # 2004/07/30 16:36:24-07:00 phil@ipom.com # [PATCH] USB: Debug fix in pl2303 # # This is a simple patch to fix a debug statement where the arguements are # in the wrong order. Resending it with a CC to Greg and a signed-off-by line. # # Signed-off-by: Phil Dibowitz # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/serial/pl2303.c # 2004/07/24 00:50:24-07:00 phil@ipom.com +1 -1 # USB: Debug fix in pl2303 # # ChangeSet # 2004/07/30 16:36:03-07:00 stern@rowland.harvard.edu # [PATCH] USB: Remove unneeded unusual_devs.h entry # # According to Jonas Fährmann, the very first entry in unusual_devs.h isn't # needed. In fact, I can't tell why it was there in the first place... # unless some earlier device in the product line had incorrect descriptor # values. # # # On Mon, 26 Jul 2004, Jonas Fährmann wrote: # # > usb-storage: This device (03ee,0000,0045 S 02 P 00) has unneeded SubClass and Protocol entries in unusual_devs.h # > Please send a copy of this message to # # # # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/storage/unusual_devs.h # 2004/07/27 04:39:20-07:00 stern@rowland.harvard.edu +0 -5 # USB: Remove unneeded unusual_devs.h entry # # ChangeSet # 2004/07/30 16:35:44-07:00 abbotti@mev.co.uk # [PATCH] USB: Add support for FT2232C chip to ftdi_sio # # This patch adds support for the FTDI FT2232C USB to dual serial port # converter to the ftdi_sio driver. # # The patch is based on a fork of the 2.4 ftdi_sio driver by Steven # Turner of FTDI, and a preliminary port of these changes to the 2.6 # ftdi_sio driver by Rus V. Brushkoff. I've tidied it up and fixed a # couple of things. # # I don't have a FT2232C to test it with, but Steven Turner of FTDI # has tested it. He mentioned a couple of known problems with the # driver, but nothing to do with this patch. # # # Signed-off-by: Ian Abbott # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/serial/ftdi_sio.h # 2004/07/27 11:12:46-07:00 abbotti@mev.co.uk +17 -0 # USB: Add support for FT2232C chip to ftdi_sio # # drivers/usb/serial/ftdi_sio.c # 2004/07/27 11:12:46-07:00 abbotti@mev.co.uk +102 -13 # USB: Add support for FT2232C chip to ftdi_sio # # ChangeSet # 2004/07/30 16:35:24-07:00 abbotti@mev.co.uk # [PATCH] USB: ftdi_sio doesn't re-assert DTR modem control line # # I've dredged up another old ftdi_sio patch that I never Cc'd to you # the first time. Please see Nathan's description below. # # It applies okay against your usb-2.6 tree, with or without the patch # I posted yesterday to support the FT2232C chip and neither patch # invalidates the other in any way. # # # On 25/06/2004 21:56, Croy, Nathan wrote: # > SUMMARY # > ======= # > ftdi_sio never reasserts modem control lines once the baud has been set to # > B0. # > # > DESCRIPTION # > =========== # > Setting the baud to B0 (hangup) drops DTR. When the baud is raised again, # > DTR is not raised. This can cause a modem to ignore any commands sent to it # > until the device is closed and reopened. This renders minicom (and other # > software) useless, unless you instruct the modem to ignore DTR. # > # > The following patch is intended to make ftdi_sio act like other serial # > devices I have used (i.e. the standard serial ports (/dev/ttyS*) and # > stallion ports (/dev/ttyE*)). Upon setting the baud to something other than # > B0, it ensures the modem control lines are set back to the way they were # > when the port was opened. # > # > Thanks to Ian Abbott for confirming my suspicions: # > http://sourceforge.net/mailarchive/forum.php?thread_id=4984710&forum_id=12120 # # Nathan's email suffered from a line-folding bug (blame M$, # probably!), so his patch came out corrupted. I'm reposting an # uncorrupted version. # # # Signed off by: Ian Abbott # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/serial/ftdi_sio.c # 2004/06/24 05:29:22-07:00 abbotti@mev.co.uk +7 -0 # USB: ftdi_sio doesn't re-assert DTR modem control line # # ChangeSet # 2004/07/30 16:35:06-07:00 laforge@netfilter.org # [PATCH] USB: Hackish fix for cyberjack driver # # The following patch is in use by REINER-SCT customres for some time and # works for them in about 90% of all cases. I would really appreciate # this going in before 2.6.8-final, since the device doesn't work at all # with current 2.6.x driver. # # Changes: # - bump version number # - open interrupt endpoint in startup() rather than open # # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/serial/cyberjack.c # 2004/07/28 08:40:57-07:00 laforge@netfilter.org +16 -17 # USB: Hackish fix for cyberjack driver # # ChangeSet # 2004/07/30 16:34:47-07:00 akpm@osdl.org # [PATCH] USB: gcc-3.5 fixes # # From: Andi Kleen # # Trivial gcc-3.5 build fixes. # # Signed-off-by: Andrew Morton # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/class/usblp.c # 2004/07/10 17:52:27-07:00 akpm@osdl.org +1 -1 # USB: gcc-3.5 fixes # # ChangeSet # 2004/07/30 16:34:27-07:00 david-b@pacbell.net # [PATCH] USB: usb hub docs and locktree() # # Please merge; the CONFIG_USB_SUSPEND patch depends on it. # # This hub patch: # # - updates internal docs about locking, matching current usage # for device state spinlock and dev->serialize semaphore # # - adds locktree() to use with signaling that affect everything # downstream of a given device ... right now just khubd uses it, # but usb_reset_device() should too (not just with hub resets...) # # - adds hub_quiesce()/hub_reactivate() ... former is used now # during shutdown, both are needed in suspend/resume paths # # Net change in behavior for current systems should be nothing. # # Signed-off-by: David Brownell # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/core/hub.h # 2004/07/29 01:31:30-07:00 david-b@pacbell.net +2 -0 # USB: usb hub docs and locktree() # # drivers/usb/core/hub.c # 2004/07/29 03:00:59-07:00 david-b@pacbell.net +105 -21 # USB: usb hub docs and locktree() # # ChangeSet # 2004/07/30 16:34:04-07:00 david-b@pacbell.net # [PATCH] USB: add CONFIG_USB_SUSPEND # # This is the core of the USB_SUSPEND functionality. Please merge. # # This adds an experimental CONFIG_USB_SUSPEND option, which supports the # USB "suspend" state. Linux-USB hosts have previously ignored that state. # # - New driver API calls, usb_suspend_device() and its # sibling usb_resume_device(). # # - Access to those calls through sysfs, such as # echo -n 2 > power/state # echo -n 0 > power/state # # That can be used to reduce the power consumption of any given USB device, # then re-activate it later. Eventually, most USB device drivers should # probably suspend idle USB devices. # # One problem with this patch: USB drivers without suspend() callbacks # may badly misbehave. Right now only hub drivers know suspend(). If the # driver core didn't self-deadlock when we try it, unbinding those drivers # from those devices (then re-enumerating on resume) would be perfect... # the current compromise is just to emit a warning message. # # In conjunction with host controller driver support (already merged for # OHCI and EHCI), PCI host controllers will issue the PME# wakeup signal # when a USB keyboard starts remote wakeup signaling. (But the keyboard # wasn't usable later, since HID doesn't try to suspend.) # # I understand some ACPI patches are circulating, and maybe already in # the MM tree, to make a suspended system wake up given PME# signaling. # It'd be great if someone made that work transparently with USB, but # for now I'm told it'll need some sysfs setup first. # # Signed-off-by: David Brownell # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/core/hub.c # 2004/07/29 03:00:59-07:00 david-b@pacbell.net +484 -1 # USB: add CONFIG_USB_SUSPEND # # drivers/usb/core/Kconfig # 2004/07/29 01:31:44-07:00 david-b@pacbell.net +11 -0 # USB: add CONFIG_USB_SUSPEND # # Documentation/DocBook/usb.tmpl # 2004/07/29 01:42:14-07:00 david-b@pacbell.net +1 -0 # USB: add CONFIG_USB_SUSPEND # # ChangeSet # 2004/07/30 16:33:45-07:00 stern@rowland.harvard.edu # [PATCH] USB: Make removable-LUN support a non-test option in the g_file_storage driver # # This patch follows the suggestions sent by Todd Fischer and Diego Dompe # for making removable-LUN support part of the normal non-testing version of # the g_file_storage driver. It also moves LUN device registration to the # correct place and eliminates a code path that stalls the bulk-out pipe in # a racy way. # # There are also some smaller changes: update some comments, add initial # debugging support for USB suspend/resume, and miscellaneous code cleanups. # Last but not least, the driver has been sufficiently stable for # sufficiently long that it's fair to remove the "(DEVELOPMENT)" warning in # Kconfig. # # # # Sent-by: Todd Fischer # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/gadget/file_storage.c # 2004/07/28 04:17:49-07:00 stern@rowland.harvard.edu +94 -75 # USB: Make removable-LUN support a non-test option in the g_file_storage driver # # drivers/usb/gadget/Kconfig # 2004/07/28 04:08:24-07:00 stern@rowland.harvard.edu +2 -2 # USB: Make removable-LUN support a non-test option in the g_file_storage driver # # ChangeSet # 2004/07/30 16:33:20-07:00 stern@rowland.harvard.edu # [PATCH] USB: Fix NULL-pointer bug in dummy_hcd # # This patch fixes a NULL-pointer-dereference bug in the dummy_hcd driver. # It also makes the code slightly more elegant and removes an unnecessary # buffer-overflow test. Unfortunately it's still a little bit racy, but # this is a fault it shares with other gadget controller drivers, like # net2280. # # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/gadget/dummy_hcd.c # 2004/07/29 05:10:55-07:00 stern@rowland.harvard.edu +4 -5 # USB: Fix NULL-pointer bug in dummy_hcd # diff -Nru a/Documentation/DocBook/usb.tmpl b/Documentation/DocBook/usb.tmpl --- a/Documentation/DocBook/usb.tmpl 2004-08-01 22:34:58 -07:00 +++ b/Documentation/DocBook/usb.tmpl 2004-08-01 22:34:58 -07:00 @@ -251,6 +251,7 @@ !Edrivers/usb/core/message.c !Edrivers/usb/core/file.c !Edrivers/usb/core/usb.c +!Edrivers/usb/core/hub.c Host Controller APIs diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS 2004-08-01 22:34:58 -07:00 +++ b/MAINTAINERS 2004-08-01 22:34:58 -07:00 @@ -2292,6 +2292,13 @@ W: http://www.connecttech.com S: Supported +USB SN9C10[12] DRIVER +P: Luca Risolia +M: luca.risolia@studio.unibo.it +L: linux-usb-devel@lists.sourceforge.net +W: http://go.lamarinapunto.com +S: Maintained + USB SUBSYSTEM P: Greg Kroah-Hartman M: greg@kroah.com diff -Nru a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c --- a/drivers/usb/class/audio.c 2004-08-01 22:34:58 -07:00 +++ b/drivers/usb/class/audio.c 2004-08-01 22:34:58 -07:00 @@ -1954,9 +1954,9 @@ struct usb_audio_state *s; down(&open_sem); - for (devs = audiodevs.next; devs != &audiodevs; devs = devs->next) { + list_for_each(devs, &audiodevs) { s = list_entry(devs, struct usb_audio_state, audiodev); - for (mdevs = s->mixerlist.next; mdevs != &s->mixerlist; mdevs = mdevs->next) { + list_for_each(mdevs, &s->mixerlist) { ms = list_entry(mdevs, struct usb_mixerdev, list); if (ms->dev_mixer == minor) goto mixer_found; @@ -2644,9 +2644,9 @@ for (;;) { down(&open_sem); - for (devs = audiodevs.next; devs != &audiodevs; devs = devs->next) { + list_for_each(devs, &audiodevs) { s = list_entry(devs, struct usb_audio_state, audiodev); - for (adevs = s->audiolist.next; adevs != &s->audiolist; adevs = adevs->next) { + list_for_each(adevs, &s->audiolist) { as = list_entry(adevs, struct usb_audiodev, list); if (!((as->dev_audio ^ minor) & ~0xf)) goto device_found; @@ -3835,7 +3835,7 @@ usb_set_intfdata (intf, NULL); /* deregister all audio and mixer devices, so no new processes can open this device */ - for(list = s->audiolist.next; list != &s->audiolist; list = list->next) { + list_for_each(list, &s->audiolist) { as = list_entry(list, struct usb_audiodev, list); usbin_disc(as); usbout_disc(as); @@ -3847,7 +3847,7 @@ } as->dev_audio = -1; } - for(list = s->mixerlist.next; list != &s->mixerlist; list = list->next) { + list_for_each(list, &s->mixerlist) { ms = list_entry(list, struct usb_mixerdev, list); if (ms->dev_mixer >= 0) { unregister_sound_mixer(ms->dev_mixer); diff -Nru a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c --- a/drivers/usb/class/usb-midi.c 2004-08-01 22:34:58 -07:00 +++ b/drivers/usb/class/usb-midi.c 2004-08-01 22:34:58 -07:00 @@ -823,9 +823,9 @@ for(;;) { down(&open_sem); - for (devs = mididevs.next; devs != &mididevs; devs = devs->next) { + list_for_each(devs, &mididevs) { s = list_entry(devs, struct usb_midi_state, mididev); - for (mdevs = s->midiDevList.next; mdevs != &s->midiDevList; mdevs = mdevs->next) { + list_for_each(mdevs, &s->midiDevList) { m = list_entry(mdevs, struct usb_mididev, list); if ( !((m->dev_midi ^ minor) & ~0xf) ) goto device_found; @@ -2018,7 +2018,7 @@ s->usbdev = NULL; usb_set_intfdata (intf, NULL); - for ( list = s->midiDevList.next; list != &s->midiDevList; list = list->next ) { + list_for_each(list, &s->midiDevList) { m = list_entry(list, struct usb_mididev, list); wake_up(&(m->min.ep->wait)); wake_up(&(m->mout.ep->wait)); diff -Nru a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c --- a/drivers/usb/class/usblp.c 2004-08-01 22:34:58 -07:00 +++ b/drivers/usb/class/usblp.c 2004-08-01 22:34:58 -07:00 @@ -221,7 +221,7 @@ static int usblp_cache_device_id_string(struct usblp *usblp); /* forward reference to make our lives easier */ -extern struct usb_driver usblp_driver; +static struct usb_driver usblp_driver; /* * Functions for usblp control messages. diff -Nru a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig --- a/drivers/usb/core/Kconfig 2004-08-01 22:34:58 -07:00 +++ b/drivers/usb/core/Kconfig 2004-08-01 22:34:58 -07:00 @@ -60,3 +60,14 @@ If you are unsure about this, say N here. +config USB_SUSPEND + bool "USB suspend/resume (EXPERIMENTAL)" + depends on USB && PM && EXPERIMENTAL + help + If you say Y here, you can use driver calls or the sysfs + "power/state" file to suspend or resume individual USB + peripherals. There are many related features, such as + remote wakeup and driver-specific suspend processing, that + may not yet work as expected. + + If you are unsure about this, say N here. diff -Nru a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c --- a/drivers/usb/core/devices.c 2004-08-01 22:34:58 -07:00 +++ b/drivers/usb/core/devices.c 2004-08-01 22:34:58 -07:00 @@ -584,7 +584,7 @@ /* enumerate busses */ down (&usb_bus_list_lock); - for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) { + list_for_each(buslist, &usb_bus_list) { /* print devices for this bus */ bus = list_entry(buslist, struct usb_bus, bus_list); diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c 2004-08-01 22:34:58 -07:00 +++ b/drivers/usb/core/hub.c 2004-08-01 22:34:58 -07:00 @@ -36,7 +36,7 @@ #include "hcd.h" #include "hub.h" -/* Protect all struct usb_device state members */ +/* Protect struct usb_device state and children members */ static spinlock_t device_state_lock = SPIN_LOCK_UNLOCKED; /* Wakes up khubd */ @@ -143,7 +143,7 @@ unsigned changed = 0; int cursor = -1; - if (hdev->state != USB_STATE_CONFIGURED) + if (hdev->state != USB_STATE_CONFIGURED || hub->quiescing) return; for (i = 0; i < hub->descriptor->bNbrPorts; i++) { @@ -269,6 +269,9 @@ spin_unlock(&hub_event_lock); resubmit: + if (hub->quiescing) + return; + if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0 && status != -ENODEV && status != -EPERM) dev_err (&hub->intf->dev, "resubmit --> %d\n", status); @@ -623,6 +626,33 @@ static unsigned highspeed_hubs; +static void hub_quiesce(struct usb_hub *hub) +{ + /* stop khubd and related activity */ + hub->quiescing = 1; + usb_kill_urb(hub->urb); + if (hub->has_indicators) + cancel_delayed_work(&hub->leds); + if (hub->has_indicators || hub->tt.hub) + flush_scheduled_work(); +} + +#ifdef CONFIG_USB_SUSPEND + +static void hub_reactivate(struct usb_hub *hub) +{ + int status; + + hub->quiescing = 0; + status = usb_submit_urb(hub->urb, GFP_NOIO); + if (status < 0) + dev_err(&hub->intf->dev, "reactivate --> %d\n", status); + if (hub->has_indicators && blinkenlights) + schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD); +} + +#endif + static void hub_disconnect(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata (intf); @@ -637,22 +667,14 @@ usb_set_intfdata (intf, NULL); - if (hub->urb) { - usb_kill_urb(hub->urb); - usb_free_urb(hub->urb); - hub->urb = NULL; - } + hub_quiesce(hub); + usb_free_urb(hub->urb); + hub->urb = NULL; spin_lock_irq(&hub_event_lock); list_del_init(&hub->event_list); spin_unlock_irq(&hub_event_lock); - /* assuming we used keventd, it must quiesce too */ - if (hub->has_indicators) - cancel_delayed_work (&hub->leds); - if (hub->has_indicators || hub->tt.hub) - flush_scheduled_work (); - if (hub->descriptor) { kfree(hub->descriptor); hub->descriptor = NULL; @@ -772,6 +794,7 @@ } } +/* caller has locked the hub */ static int hub_reset(struct usb_hub *hub) { struct usb_device *hdev = hub->hdev; @@ -801,6 +824,7 @@ return 0; } +/* caller has locked the hub */ /* FIXME! This routine should be subsumed into hub_reset */ static void hub_start_disconnect(struct usb_device *hdev) { @@ -832,12 +856,65 @@ udev->state = USB_STATE_NOTATTACHED; } +/* grab device/port lock, returning index of that port (zero based). + * protects the upstream link used by this device from concurrent + * tree operations like suspend, resume, reset, and disconnect, which + * apply to everything downstream of a given port. + */ +static int locktree(struct usb_device *udev) +{ + int t; + struct usb_device *hdev; + + if (!udev) + return -ENODEV; + + /* root hub is always the first lock in the series */ + hdev = udev->parent; + if (!hdev) { + down(&udev->serialize); + return 0; + } + + /* on the path from root to us, lock everything from + * top down, dropping parent locks when not needed + * + * NOTE: if disconnect were to ignore the locking, we'd need + * to get extra refcounts to everything since hdev->children + * and udev->parent could be invalidated while we work... + */ + t = locktree(hdev); + if (t < 0) + return t; + spin_lock_irq(&device_state_lock); + for (t = 0; t < hdev->maxchild; t++) { + if (hdev->children[t] == udev) { + /* everything is fail-fast once disconnect + * processing starts + */ + if (udev->state == USB_STATE_NOTATTACHED) + break; + + /* when everyone grabs locks top->bottom, + * non-overlapping work may be concurrent + */ + spin_unlock_irq(&device_state_lock); + down(&udev->serialize); + up(&hdev->serialize); + return t; + } + } + spin_unlock_irq(&device_state_lock); + up(&hdev->serialize); + return -ENODEV; +} + /** * usb_set_device_state - change a device's current state (usbcore-internal) * @udev: pointer to device whose state should be changed * @new_state: new state value to be stored * - * udev->state is _not_ protected by the udev->serialize semaphore. This + * udev->state is _not_ protected by the device lock. This * is so that devices can be marked as disconnected as soon as possible, * without having to wait for the semaphore to be released. Instead, * changes to the state must be protected by the device_state_lock spinlock. @@ -897,7 +974,7 @@ /** * usb_disconnect - disconnect a device (usbcore-internal) - * @pdev: pointer to device being disconnected + * @pdev: pointer to device being disconnected, into a locked hub * Context: !in_interrupt () * * Something got disconnected. Get rid of it, and all of its children. @@ -921,7 +998,8 @@ } /* mark the device as inactive, so any further urb submissions for - * this device will fail. + * this device (and any of its children) will fail immediately. + * this quiesces everyting except pending urbs. */ usb_set_device_state(udev, USB_STATE_NOTATTACHED); @@ -940,6 +1018,7 @@ /* deallocate hcd/hardware state ... nuking all pending urbs and * cleaning up all state associated with the current configuration + * so that the hardware is now fully quiesced. */ usb_disable_device(udev, 0); @@ -952,7 +1031,7 @@ usbfs_remove_device(udev); usb_remove_sysfs_dev_files(udev); - /* Avoid races with recursively_mark_NOTATTACHED() */ + /* Avoid races with recursively_mark_NOTATTACHED() and locktree() */ spin_lock_irq(&device_state_lock); *pdev = NULL; spin_unlock_irq(&device_state_lock); @@ -1203,6 +1282,7 @@ if (status == -ENOTCONN || status == 0) { clear_port_feature(hdev, port + 1, USB_PORT_FEAT_C_RESET); + /* FIXME need disconnect() for NOTATTACHED device */ usb_set_device_state(udev, status ? USB_STATE_NOTATTACHED : USB_STATE_DEFAULT); @@ -1226,9 +1306,11 @@ { int ret; - if (hdev->children[port]) + if (hdev->children[port]) { + /* FIXME need disconnect() for NOTATTACHED device */ usb_set_device_state(hdev->children[port], USB_STATE_NOTATTACHED); + } ret = clear_port_feature(hdev, port + 1, USB_PORT_FEAT_ENABLE); if (ret) dev_err(hubdev(hdev), "cannot disable port %d (err = %d)\n", @@ -1239,7 +1321,490 @@ #ifdef CONFIG_USB_SUSPEND - /* no USB_SUSPEND yet! */ +/* + * Selective port suspend reduces power; most suspended devices draw + * less than 500 uA. It's also used in OTG, along with remote wakeup. + * All devices below the suspended port are also suspended. + * + * Devices leave suspend state when the host wakes them up. Some devices + * also support "remote wakeup", where the device can activate the USB + * tree above them to deliver data, such as a keypress or packet. In + * some cases, this wakes the USB host. + */ +static int hub_port_suspend(struct usb_device *hdev, int port) +{ + int status; + struct usb_device *udev; + + udev = hdev->children[port - 1]; + // dev_dbg(hubdev(hdev), "suspend port %d\n", port); + + /* enable remote wakeup when appropriate; this lets the device + * wake up the upstream hub (including maybe the root hub). + * + * NOTE: OTG devices may issue remote wakeup (or SRP) even when + * we don't explicitly enable it here. + */ + if (udev->actconfig + // && FIXME (remote wakeup enabled on this bus) + // ... currently assuming it's always appropriate + && (udev->actconfig->desc.bmAttributes + & USB_CONFIG_ATT_WAKEUP) != 0) { + status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, + USB_DEVICE_REMOTE_WAKEUP, 0, + NULL, 0, + USB_CTRL_SET_TIMEOUT); + if (status) + dev_dbg(&udev->dev, + "won't remote wakeup, status %d\n", + status); + } + + /* see 7.1.7.6 */ + status = set_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND); + if (status) { + dev_dbg(hubdev(hdev), + "can't suspend port %d, status %d\n", + port, status); + /* paranoia: "should not happen" */ + (void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, + USB_DEVICE_REMOTE_WAKEUP, 0, + NULL, 0, + USB_CTRL_SET_TIMEOUT); + } else { + /* device has up to 10 msec to fully suspend */ + dev_dbg(&udev->dev, "usb suspend\n"); + udev->state = USB_STATE_SUSPENDED; + msleep(10); + } + return status; +} + +/* + * Devices on USB hub ports have only one "suspend" state, corresponding + * to ACPI D2 (PM_SUSPEND_MEM), "may cause the device to lose some context". + * State transitions include: + * + * - suspend, resume ... when the VBUS power link stays live + * - suspend, disconnect ... VBUS lost + * + * Once VBUS drop breaks the circuit, the port it's using has to go through + * normal re-enumeration procedures, starting with enabling VBUS power. + * Other than re-initializing the hub (plug/unplug, except for root hubs), + * Linux (2.6) currently has NO mechanisms to initiate that: no khubd + * timer, no SRP, no requests through sysfs. + */ +static int __usb_suspend_device (struct usb_device *udev, int port, u32 state) +{ + int status; + + if (port < 0) + return port; + + /* NOTE: udev->serialize released on all real returns! */ + + if (state <= udev->dev.power.power_state + || state < PM_SUSPEND_MEM + || udev->state == USB_STATE_SUSPENDED + || udev->state == USB_STATE_NOTATTACHED) { + up(&udev->serialize); + return 0; + } + + /* suspend interface drivers; if this is a hub, it + * suspends the child devices + */ + if (udev->actconfig) { + int i; + + for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { + struct usb_interface *intf; + struct usb_driver *driver; + + intf = udev->actconfig->interface[i]; + if (state <= intf->dev.power.power_state) + continue; + if (!intf->dev.driver) + continue; + driver = to_usb_driver(intf->dev.driver); + + if (driver->suspend) { + status = driver->suspend(intf, state); + if (intf->dev.power.power_state != state + || status) + dev_err(&intf->dev, + "suspend %d fail, code %d\n", + state, status); + } + + /* only drivers with suspend() can ever resume(); + * and after power loss, even they won't. + * bus_rescan_devices() can rebind drivers later. + * + * FIXME the PM core self-deadlocks when unbinding + * drivers during suspend/resume ... everything grabs + * dpm_sem (not a spinlock, ugh). we want to unbind, + * since we know every driver's probe/disconnect works + * even for drivers that can't suspend. + */ + if (!driver->suspend || state > PM_SUSPEND_MEM) { +#if 1 + dev_warn(&intf->dev, "resume is unsafe!\n"); +#else + down_write(&usb_bus_type.rwsem); + device_release_driver(&intf->dev); + up_write(&usb_bus_type.rwsem); +#endif + } + } + } + + /* + * FIXME this needs port power off call paths too, to help force + * USB into the "generic" PM model. At least for devices on + * ports that aren't using ganged switching (usually root hubs). + * + * NOTE: SRP-capable links should adopt more aggressive poweroff + * policies (when HNP doesn't apply) once we have mechanisms to + * turn power back on! (Likely not before 2.7...) + */ + if (state > PM_SUSPEND_MEM) { + dev_warn(&udev->dev, "no poweroff yet, suspending instead\n"); + state = PM_SUSPEND_MEM; + } + + /* "global suspend" of the HC-to-USB interface (root hub), or + * "selective suspend" of just one hub-device link. + */ + if (!udev->parent) { + struct usb_bus *bus = udev->bus; + if (bus && bus->op->hub_suspend) + status = bus->op->hub_suspend (bus); + else + status = -EOPNOTSUPP; + } else + status = hub_port_suspend(udev->parent, port + 1); + + if (status == 0) + udev->dev.power.power_state = state; + up(&udev->serialize); + return status; +} + +/** + * usb_suspend_device - suspend a usb device + * @udev: device that's no longer in active use + * @state: PM_SUSPEND_MEM to suspend + * Context: must be able to sleep; device not locked + * + * Suspends a USB device that isn't in active use, conserving power. + * Devices may wake out of a suspend, if anything important happens, + * using the remote wakeup mechanism. They may also be taken out of + * suspend by the host, using usb_resume_device(). It's also routine + * to disconnect devices while they are suspended. + * + * Suspending OTG devices may trigger HNP, if that's been enabled + * between a pair of dual-role devices. That will change roles, such + * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral. + * + * Returns 0 on success, else negative errno. + */ +int usb_suspend_device(struct usb_device *udev, u32 state) +{ + return __usb_suspend_device(udev, locktree(udev), state); +} + +/* + * hardware resume signaling is finished, either because of selective + * resume (by host) or remote wakeup (by device) ... now see what changed + * in the tree that's rooted at this device. + */ +static int finish_port_resume(struct usb_device *udev) +{ + int status; + u16 devstatus; + + /* caller owns udev->serialize */ + dev_dbg(&udev->dev, "usb resume\n"); + udev->dev.power.power_state = PM_SUSPEND_ON; + + /* usb ch9 identifies four variants of SUSPENDED, based on what + * state the device resumes to. Linux currently won't see the + * first two on the host side; they'd be inside hub_port_init() + * during many timeouts, but khubd can't suspend until later. + */ + udev->state = udev->actconfig + ? USB_STATE_CONFIGURED + : USB_STATE_ADDRESS; + + /* 10.5.4.5 says be sure devices in the tree are still there. + * For now let's assume the device didn't go crazy on resume, + * and device drivers will know about any resume quirks. + */ + status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus); + if (status < 0) + dev_dbg(&udev->dev, + "gone after usb resume? status %d\n", + status); + else if (udev->actconfig) { + unsigned i; + + le16_to_cpus(&devstatus); + if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { + status = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + USB_REQ_CLEAR_FEATURE, + USB_RECIP_DEVICE, + USB_DEVICE_REMOTE_WAKEUP, 0, + NULL, 0, + USB_CTRL_SET_TIMEOUT); + if (status) { + dev_dbg(&udev->dev, "disable remote " + "wakeup, status %d\n", status); + status = 0; + } + } + + /* resume interface drivers; if this is a hub, it + * resumes the child devices + */ + for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { + struct usb_interface *intf; + struct usb_driver *driver; + + intf = udev->actconfig->interface[i]; + if (intf->dev.power.power_state == PM_SUSPEND_ON) + continue; + if (!intf->dev.driver) { + /* FIXME maybe force to alt 0 */ + continue; + } + driver = to_usb_driver(intf->dev.driver); + + /* bus_rescan_devices() may rebind drivers */ + if (!driver->resume) + continue; + + /* can we do better than just logging errors? */ + status = driver->resume(intf); + if (intf->dev.power.power_state != PM_SUSPEND_ON + || status) + dev_dbg(&intf->dev, + "resume fail, state %d code %d\n", + intf->dev.power.power_state, status); + } + status = 0; + + } else if (udev->devnum <= 0) { + dev_dbg(&udev->dev, "bogus resume!\n"); + status = -EINVAL; + } + return status; +} + +static int +hub_port_resume(struct usb_device *hdev, int port) +{ + int status; + struct usb_device *udev; + + udev = hdev->children[port - 1]; + // dev_dbg(hubdev(hdev), "resume port %d\n", port); + + /* see 7.1.7.7; affects power usage, but not budgeting */ + status = clear_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND); + if (status) { + dev_dbg(&hdev->actconfig->interface[0]->dev, + "can't resume port %d, status %d\n", + port, status); + } else { + u16 devstatus; + u16 portchange; + + /* drive resume for at least 20 msec */ + dev_dbg(&udev->dev, "RESUME\n"); + msleep(25); + +#define LIVE_FLAGS ( USB_PORT_STAT_POWER \ + | USB_PORT_STAT_ENABLE \ + | USB_PORT_STAT_CONNECTION) + + /* Virtual root hubs can trigger on GET_PORT_STATUS to + * stop resume signaling. Then finish the resume + * sequence. + */ + devstatus = portchange = 0; + status = hub_port_status(hdev, port - 1, + &devstatus, &portchange); + if (status < 0 + || (devstatus & LIVE_FLAGS) != LIVE_FLAGS + || (devstatus & USB_PORT_STAT_SUSPEND) != 0 + ) { + dev_dbg(&hdev->actconfig->interface[0]->dev, + "port %d status %04x.%04x after resume, %d\n", + port, portchange, devstatus, status); + } else { + /* TRSMRCY = 10 msec */ + msleep(10); + status = finish_port_resume(udev); + } + } + if (status < 0) + status = hub_port_disable(hdev, port); + + return status; +} + +static int hub_resume (struct usb_interface *intf); + +/** + * usb_resume_device - re-activate a suspended usb device + * @udev: device to re-activate + * Context: must be able to sleep; device not locked + * + * This will re-activate the suspended device, increasing power usage + * while letting drivers communicate again with its endpoints. + * USB resume explicitly guarantees that the power session between + * the host and the device is the same as it was when the device + * suspended. + * + * Returns 0 on success, else negative errno. + */ +int usb_resume_device(struct usb_device *udev) +{ + int port, status; + + port = locktree(udev); + if (port < 0) + return port; + + /* "global resume" of the HC-to-USB interface (root hub), or + * selective resume of one hub-to-device port + */ + if (!udev->parent) { + struct usb_bus *bus = udev->bus; + if (bus && bus->op->hub_resume) + status = bus->op->hub_resume (bus); + else + status = -EOPNOTSUPP; + if (status == 0) { + /* TRSMRCY = 10 msec */ + msleep(10); + status = hub_resume (bus->root_hub + ->actconfig->interface[0]); + } + } else if (udev->state == USB_STATE_SUSPENDED) { + status = hub_port_resume(udev->parent, port + 1); + } else { + status = 0; + udev->dev.power.power_state = PM_SUSPEND_ON; + } + if (status < 0) { + dev_dbg(&udev->dev, "can't resume, status %d\n", + status); + } + + up(&udev->serialize); + + /* rebind drivers that had no suspend() */ + bus_rescan_devices(&usb_bus_type); + + return status; +} + +static int remote_wakeup(struct usb_device *udev) +{ + int status = 0; + + /* don't repeat RESUME sequence if this device + * was already woken up by some other task + */ + down(&udev->serialize); + if (udev->state == USB_STATE_SUSPENDED) { + dev_dbg(&udev->dev, "RESUME (wakeup)\n"); + /* TRSMRCY = 10 msec */ + msleep(10); + status = finish_port_resume(udev); + } + up(&udev->serialize); + return status; +} + +static int hub_suspend(struct usb_interface *intf, u32 state) +{ + struct usb_hub *hub = usb_get_intfdata (intf); + struct usb_device *hdev = hub->hdev; + unsigned port; + int status; + + /* stop khubd and related activity */ + hub_quiesce(hub); + + /* then suspend every port */ + for (port = 0; port < hdev->maxchild; port++) { + struct usb_device *udev; + + udev = hdev->children [port]; + if (!udev) + continue; + down(&udev->serialize); + status = __usb_suspend_device(udev, port, state); + if (status < 0) + dev_dbg(&intf->dev, "suspend port %d --> %d\n", + port, status); + } + + intf->dev.power.power_state = state; + return 0; +} + +static int hub_resume(struct usb_interface *intf) +{ + struct usb_device *hdev = interface_to_usbdev(intf); + struct usb_hub *hub = usb_get_intfdata (intf); + unsigned port; + int status; + + for (port = 0; port < hdev->maxchild; port++) { + struct usb_device *udev; + u16 portstat, portchange; + + udev = hdev->children [port]; + status = hub_port_status(hdev, port, &portstat, &portchange); + if (status == 0) { + if (portchange & USB_PORT_STAT_C_SUSPEND) { + clear_port_feature(hdev, port + 1, + USB_PORT_FEAT_C_SUSPEND); + portchange &= ~USB_PORT_STAT_C_SUSPEND; + } + + /* let khubd handle disconnects etc */ + if (portchange) + continue; + } + + if (!udev) + continue; + down (&udev->serialize); + if (portstat & USB_PORT_STAT_SUSPEND) + status = hub_port_resume(hdev, port + 1); + else { + status = finish_port_resume(udev); + if (status < 0) + status = hub_port_disable(hdev, port); + if (status < 0) + dev_dbg(&intf->dev, "resume port %d --> %d\n", + port, status); + } + up(&udev->serialize); + } + intf->dev.power.power_state = PM_SUSPEND_ON; + + hub_reactivate(hub); + return 0; +} #else /* !CONFIG_USB_SUSPEND */ @@ -1574,6 +2139,7 @@ * a port enable-change occurs (often caused by EMI); * usb_reset_device() encounters changed descriptors (as from * a firmware download) + * caller already locked the hub */ static void hub_port_connect_change(struct usb_hub *hub, int port, u16 portstatus, u16 portchange) @@ -1780,7 +2346,8 @@ /* Lock the device, then check to see if we were * disconnected while waiting for the lock to succeed. */ - down(&hdev->serialize); + if (locktree(hdev) < 0) + break; if (hdev->state != USB_STATE_CONFIGURED || !hdev->actconfig || hub != usb_get_intfdata( @@ -2034,7 +2601,7 @@ } /** - * usb_reset_devce - perform a USB port reset to reinitialize a device + * 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 @@ -2123,7 +2690,7 @@ struct usb_interface *intf = udev->actconfig->interface[i]; struct usb_interface_descriptor *desc; - /* set_interface resets host side toggle and halt status even + /* set_interface resets host side toggle even * for altsetting zero. the interface may have no driver. */ desc = &intf->cur_altsetting->desc; diff -Nru a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h --- a/drivers/usb/core/hub.h 2004-08-01 22:34:58 -07:00 +++ b/drivers/usb/core/hub.h 2004-08-01 22:34:58 -07:00 @@ -214,6 +214,8 @@ u8 power_budget; /* in 2mA units; or zero */ + unsigned quiescing:1; + unsigned has_indicators:1; enum hub_led_mode indicator[USB_MAXCHILDREN]; struct work_struct leds; diff -Nru a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig --- a/drivers/usb/gadget/Kconfig 2004-08-01 22:34:58 -07:00 +++ b/drivers/usb/gadget/Kconfig 2004-08-01 22:34:58 -07:00 @@ -275,7 +275,7 @@ dynamically linked module called "gadgetfs". config USB_FILE_STORAGE - tristate "File-backed Storage Gadget (DEVELOPMENT)" + tristate "File-backed Storage Gadget" # we don't support the SA1100 because of its limitations depends on USB_GADGET_SA1100 = n help @@ -288,7 +288,7 @@ dynamically linked module called "g_file_storage". config USB_FILE_STORAGE_TEST - bool "File-backed Storage Gadget test version" + bool "File-backed Storage Gadget testing version" depends on USB_FILE_STORAGE default n help diff -Nru a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c --- a/drivers/usb/gadget/dummy_hcd.c 2004-08-01 22:34:58 -07:00 +++ b/drivers/usb/gadget/dummy_hcd.c 2004-08-01 22:34:58 -07:00 @@ -596,14 +596,13 @@ /* "function" sysfs attribute */ static ssize_t -show_function (struct device *_dev, char *buf) +show_function (struct device *dev, char *buf) { - struct dummy *dum = the_controller; + struct dummy *dum = gadget_dev_to_dummy (dev); - if (!dum->driver->function - || strlen (dum->driver->function) > PAGE_SIZE) + if (!dum->driver || !dum->driver->function) return 0; - return snprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function); + return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function); } DEVICE_ATTR (function, S_IRUGO, show_function, NULL); diff -Nru a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c --- a/drivers/usb/gadget/file_storage.c 2004-08-01 22:34:58 -07:00 +++ b/drivers/usb/gadget/file_storage.c 2004-08-01 22:34:58 -07:00 @@ -46,17 +46,16 @@ * * Backing storage is provided by a regular file or a block device, specified * by the "file" module parameter. Access can be limited to read-only by - * setting the optional "ro" module parameter. + * setting the optional "ro" module parameter. The gadget will indicate that + * it has removable media if the optional "removable" module parameter is set. * * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI), * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected * by the optional "transport" module parameter. It also supports the * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03), * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by - * the optional "protocol" module parameter. For testing purposes the - * gadget will indicate that it has removable media if the optional - * "removable" module parameter is set. In addition, the default Vendor ID, - * Product ID, and release number can be overridden. + * the optional "protocol" module parameter. In addition, the default + * Vendor ID, Product ID, and release number can be overridden. * * There is support for multiple logical units (LUNs), each of which has * its own backing file. The number of LUNs can be set using the optional @@ -79,13 +78,13 @@ * the files or block devices used for * backing storage * ro=b[,b...] Default false, booleans for read-only access + * removable Default false, boolean for removable media * luns=N Default N = number of filenames, number of * LUNs to support * transport=XXX Default BBB, transport name (CB, CBI, or BBB) * protocol=YYY Default SCSI, protocol name (RBC, 8020 or * ATAPI, QIC, UFI, 8070, or SCSI; * also 1 - 6) - * removable Default false, boolean for removable media * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID * release=0xRRRR Override the USB release number (bcdDevice) @@ -97,16 +96,16 @@ * boolean to permit the driver to halt * bulk endpoints * - * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file" and "ro" - * options are available; default values are used for everything else. + * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro", + * "removable", and "luns" options are available; default values are used + * for everything else. * * The pathnames of the backing files and the ro settings are available in * the attribute files "file" and "ro" in the lun subdirectory of the - * gadget's sysfs directory. If CONFIG_USB_FILE_STORAGE_TEST and the - * "removable" option are both set, writing to these files will simulate - * ejecting/loading the medium (writing an empty line means eject) and - * adjusting a write-enable tab. Changes to the ro setting are not allowed - * when the medium is loaded. + * gadget's sysfs directory. If the "removable" option is set, writing to + * these files will simulate ejecting/loading the medium (writing an empty + * line means eject) and adjusting a write-enable tab. Changes to the ro + * setting are not allowed when the medium is loaded. * * This gadget driver is heavily based on "Gadget Zero" by David Brownell. */ @@ -178,7 +177,10 @@ * Bulk-only specification requires a stall. In such cases the driver * will halt the endpoint and set a flag indicating that it should clear * the halt in software during the next device reset. Hopefully this - * will permit everything to work correctly. + * will permit everything to work correctly. Furthermore, although the + * specification allows the bulk-out endpoint to halt when the host sends + * too much data, implementing this would cause an unavoidable race. + * The driver will always use the "no-stall" approach for OUT transfers. * * One subtle point concerns sending status-stage responses for ep0 * requests. Some of these requests, such as device reset, can involve @@ -246,7 +248,7 @@ #define DRIVER_DESC "File-backed Storage Gadget" #define DRIVER_NAME "g_file_storage" -#define DRIVER_VERSION "21 March 2004" +#define DRIVER_VERSION "28 July 2004" static const char longname[] = DRIVER_DESC; static const char shortname[] = DRIVER_NAME; @@ -371,14 +373,17 @@ module_param_array(ro, bool, mod_data.num_ros, S_IRUGO); MODULE_PARM_DESC(ro, "true to force read-only"); +module_param_named(luns, mod_data.nluns, uint, S_IRUGO); +MODULE_PARM_DESC(luns, "number of LUNs"); -/* In the non-TEST version, only the file and ro module parameters +module_param_named(removable, mod_data.removable, bool, S_IRUGO); +MODULE_PARM_DESC(removable, "true to simulate removable media"); + + +/* In the non-TEST version, only the module parameters listed above * are available. */ #ifdef CONFIG_USB_FILE_STORAGE_TEST -module_param_named(luns, mod_data.nluns, uint, S_IRUGO); -MODULE_PARM_DESC(luns, "number of LUNs"); - module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO); MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)"); @@ -386,9 +391,6 @@ MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, " "8070, or SCSI)"); -module_param_named(removable, mod_data.removable, bool, S_IRUGO); -MODULE_PARM_DESC(removable, "true to simulate removable media"); - module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO); MODULE_PARM_DESC(vendor, "USB Vendor ID"); @@ -525,11 +527,6 @@ * parts of the driver that aren't used in the non-TEST version. Even gcc * can recognize when a test of a constant expression yields a dead code * path. - * - * Also, in the non-TEST version, open_backing_file() is only used during - * initialization and the sysfs attribute store_xxx routines aren't used - * at all. We will define NORMALLY_INIT to mark them as __init so they - * don't occupy kernel code space unnecessarily. */ #ifdef CONFIG_USB_FILE_STORAGE_TEST @@ -537,16 +534,12 @@ #define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK) #define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI) #define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI) -#define backing_file_is_open(curlun) ((curlun)->filp != NULL) -#define NORMALLY_INIT #else #define transport_is_bbb() 1 #define transport_is_cbi() 0 #define protocol_is_scsi() 1 -#define backing_file_is_open(curlun) 1 -#define NORMALLY_INIT __init #endif /* CONFIG_USB_FILE_STORAGE_TEST */ @@ -567,6 +560,8 @@ struct device dev; }; +#define backing_file_is_open(curlun) ((curlun)->filp != NULL) + static inline struct lun *dev_to_lun(struct device *dev) { return container_of(dev, struct lun, dev); @@ -659,6 +654,7 @@ unsigned long atomic_bitflags; #define REGISTERED 0 #define CLEAR_BULK_HALTS 1 +#define SUSPENDED 2 struct usb_ep *bulk_in; struct usb_ep *bulk_out; @@ -1041,8 +1037,6 @@ function = fs_function; len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); - if (len < 0) - return len; ((struct usb_config_descriptor *) buf)->bDescriptorType = type; return len; } @@ -1172,9 +1166,10 @@ wakeup_thread(fsg); } + +#ifdef CONFIG_USB_FILE_STORAGE_TEST static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) { -#ifdef CONFIG_USB_FILE_STORAGE_TEST struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; @@ -1190,17 +1185,21 @@ bh->state = BUF_STATE_EMPTY; spin_unlock(&fsg->lock); wakeup_thread(fsg); -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ } +#else +static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) +{} +#endif /* CONFIG_USB_FILE_STORAGE_TEST */ + /*-------------------------------------------------------------------------*/ /* Ep0 class-specific handlers. These always run in_irq. */ +#ifdef CONFIG_USB_FILE_STORAGE_TEST static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) { -#ifdef CONFIG_USB_FILE_STORAGE_TEST struct usb_request *req = fsg->ep0req; static u8 cbi_reset_cmnd[6] = { SC_SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff}; @@ -1238,9 +1237,13 @@ spin_unlock(&fsg->lock); wakeup_thread(fsg); -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ } +#else +static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{} +#endif /* CONFIG_USB_FILE_STORAGE_TEST */ + static int class_setup_req(struct fsg_dev *fsg, const struct usb_ctrlrequest *ctrl) @@ -1465,8 +1468,8 @@ /* Respond with data/status or defer until later? */ if (rc >= 0 && rc != DELAYED_STATUS) { fsg->ep0req->length = rc; - fsg->ep0req->zero = rc < ctrl->wLength - && (rc % gadget->ep0->maxpacket) == 0; + fsg->ep0req->zero = (rc < ctrl->wLength && + (rc % gadget->ep0->maxpacket) == 0); fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ? "ep0-in" : "ep0-out"); rc = ep0_queue(fsg); @@ -2443,14 +2446,19 @@ rc = -EINTR; } - /* We haven't processed all the incoming data. If we are - * allowed to stall, halt the bulk-out endpoint and cancel - * any outstanding requests. */ + /* We haven't processed all the incoming data. Even though + * we may be allowed to stall, doing so would cause a race. + * The controller may already have ACK'ed all the remaining + * bulk-out packets, in which case the host wouldn't see a + * STALL. Not realizing the endpoint was halted, it wouldn't + * clear the halt -- leading to problems later on. */ +#if 0 else if (mod_data.can_stall) { fsg_set_halt(fsg, fsg->bulk_out); raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); rc = -EINTR; } +#endif /* We can't stall. Read in the excess data and throw it * all away. */ @@ -2513,7 +2521,7 @@ } else if (mod_data.transport_type == USB_PR_CB) { - /* Control-Bulk transport has no status stage! */ + /* Control-Bulk transport has no status phase! */ return 0; } else { // USB_PR_CBI @@ -2603,8 +2611,10 @@ fsg->residue = fsg->usb_amount_left = fsg->data_size; /* Conflicting data directions is a phase error */ - if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) - goto phase_error; + if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) { + fsg->phase_error = 1; + return -EINVAL; + } /* Verify the length of the command itself */ if (cmnd_size != fsg->cmnd_size) { @@ -2613,8 +2623,10 @@ * with cbw->Length == 12 (it should be 6). */ if (fsg->cmnd[0] == SC_REQUEST_SENSE && fsg->cmnd_size == 12) cmnd_size = fsg->cmnd_size; - else - goto phase_error; + else { + fsg->phase_error = 1; + return -EINVAL; + } } /* Check that the LUN values are oonsistent */ @@ -2674,10 +2686,6 @@ } return 0; - -phase_error: - fsg->phase_error = 1; - return -EINVAL; } @@ -3424,8 +3432,7 @@ /* If the next two routines are called while the gadget is registered, * the caller must own fsg->filesem for writing. */ -static int NORMALLY_INIT open_backing_file(struct lun *curlun, - const char *filename) +static int open_backing_file(struct lun *curlun, const char *filename) { int ro; struct file *filp = NULL; @@ -3550,8 +3557,7 @@ } -ssize_t NORMALLY_INIT store_ro(struct device *dev, const char *buf, - size_t count) +ssize_t store_ro(struct device *dev, const char *buf, size_t count) { ssize_t rc = count; struct lun *curlun = dev_to_lun(dev); @@ -3575,8 +3581,7 @@ return rc; } -ssize_t NORMALLY_INIT store_file(struct device *dev, const char *buf, - size_t count) +ssize_t store_file(struct device *dev, const char *buf, size_t count) { struct lun *curlun = dev_to_lun(dev); struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); @@ -3805,9 +3810,8 @@ goto out; } - /* Create the LUNs and open their backing files. We can't register - * the LUN devices until the gadget itself is registered, which - * doesn't happen until after fsg_bind() returns. */ + /* Create the LUNs, open their backing files, and register the + * LUN devices in sysfs. */ fsg->luns = kmalloc(i * sizeof(struct lun), GFP_KERNEL); if (!fsg->luns) { rc = -ENOMEM; @@ -3825,6 +3829,15 @@ snprintf(curlun->dev.bus_id, BUS_ID_SIZE, "%s-lun%d", gadget->dev.bus_id, i); + if ((rc = device_register(&curlun->dev)) != 0) + INFO(fsg, "failed to register LUN%d: %d\n", i, rc); + else { + curlun->registered = 1; + curlun->dev.release = lun_release; + device_create_file(&curlun->dev, &dev_attr_ro); + device_create_file(&curlun->dev, &dev_attr_file); + } + if (file[i] && *file[i]) { if ((rc = open_backing_file(curlun, file[i])) != 0) goto out; @@ -3974,6 +3987,25 @@ /*-------------------------------------------------------------------------*/ +static void fsg_suspend(struct usb_gadget *gadget) +{ + struct fsg_dev *fsg = get_gadget_data(gadget); + + DBG(fsg, "suspend\n"); + set_bit(SUSPENDED, &fsg->atomic_bitflags); +} + +static void fsg_resume(struct usb_gadget *gadget) +{ + struct fsg_dev *fsg = get_gadget_data(gadget); + + DBG(fsg, "resume\n"); + clear_bit(SUSPENDED, &fsg->atomic_bitflags); +} + + +/*-------------------------------------------------------------------------*/ + static struct usb_gadget_driver fsg_driver = { #ifdef CONFIG_USB_GADGET_DUALSPEED .speed = USB_SPEED_HIGH, @@ -3985,6 +4017,8 @@ .unbind = fsg_unbind, .disconnect = fsg_disconnect, .setup = fsg_setup, + .suspend = fsg_suspend, + .resume = fsg_resume, .driver = { .name = (char *) shortname, @@ -4024,8 +4058,6 @@ { int rc; struct fsg_dev *fsg; - int i; - struct lun *curlun; if ((rc = fsg_alloc()) != 0) return rc; @@ -4035,19 +4067,6 @@ return rc; } set_bit(REGISTERED, &fsg->atomic_bitflags); - - /* Register the LUN devices and their attribute files */ - for (i = 0; i < fsg->nluns; ++i) { - curlun = &fsg->luns[i]; - if ((rc = device_register(&curlun->dev)) != 0) - INFO(fsg, "failed to register LUN%d: %d\n", i, rc); - else { - curlun->registered = 1; - curlun->dev.release = lun_release; - device_create_file(&curlun->dev, &dev_attr_ro); - device_create_file(&curlun->dev, &dev_attr_file); - } - } /* Tell the thread to start working */ complete(&fsg->thread_notifier); diff -Nru a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c --- a/drivers/usb/serial/cyberjack.c 2004-08-01 22:34:58 -07:00 +++ b/drivers/usb/serial/cyberjack.c 2004-08-01 22:34:58 -07:00 @@ -44,7 +44,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.0" +#define DRIVER_VERSION "v1.01" #define DRIVER_AUTHOR "Matthias Bruestle" #define DRIVER_DESC "REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver" @@ -111,6 +111,7 @@ static int cyberjack_startup (struct usb_serial *serial) { struct cyberjack_private *priv; + int i; dbg("%s", __FUNCTION__); @@ -128,6 +129,16 @@ init_waitqueue_head(&serial->port[0]->write_wait); + for (i = 0; i < serial->num_ports; ++i) { + int result; + serial->port[i]->interrupt_in_urb->dev = serial->dev; + result = usb_submit_urb(serial->port[i]->interrupt_in_urb, + GFP_KERNEL); + if (result) + err(" usb_submit_urb(read int) failed"); + dbg("%s - usb_submit_urb(int urb)", __FUNCTION__); + } + return( 0 ); } @@ -138,6 +149,7 @@ dbg("%s", __FUNCTION__); for (i=0; i < serial->num_ports; ++i) { + usb_unlink_urb (serial->port[i]->interrupt_in_urb); /* My special items, the standard routines free my urbs */ kfree(usb_get_serial_port_data(serial->port[i])); usb_set_serial_port_data(serial->port[i], NULL); @@ -168,17 +180,6 @@ priv->wrsent = 0; spin_unlock_irqrestore(&priv->lock, flags); - /* shutdown any bulk reads that might be going on */ - usb_unlink_urb (port->write_urb); - usb_unlink_urb (port->read_urb); - usb_unlink_urb (port->interrupt_in_urb); - - port->interrupt_in_urb->dev = port->serial->dev; - result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (result) - err(" usb_submit_urb(read int) failed"); - dbg("%s - usb_submit_urb(int urb)", __FUNCTION__); - return result; } @@ -190,11 +191,6 @@ /* shutdown any bulk reads that might be going on */ usb_unlink_urb (port->write_urb); usb_unlink_urb (port->read_urb); - usb_unlink_urb (port->interrupt_in_urb); - dbg("%s - usb_clear_halt", __FUNCTION__ ); - usb_clear_halt(port->serial->dev, port->write_urb->pipe); - usb_clear_halt(port->serial->dev, port->read_urb->pipe); - usb_clear_halt(port->serial->dev, port->interrupt_in_urb->pipe); } } @@ -376,6 +372,10 @@ } tty = port->tty; + if (!tty) { + dbg("%s - ignoring since device not open\n", __FUNCTION__); + return; + } if (urb->actual_length) { for (i = 0; i < urb->actual_length ; ++i) { /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c --- a/drivers/usb/serial/ftdi_sio.c 2004-08-01 22:34:58 -07:00 +++ b/drivers/usb/serial/ftdi_sio.c 2004-08-01 22:34:58 -07:00 @@ -17,6 +17,11 @@ * See http://ftdi-usb-sio.sourceforge.net for upto date testing info * and extra documentation * + * (21/Jul/2004) Ian Abbott + * Incorporated Steven Turner's code to add support for the FT2232C chip. + * The prelimilary port to the 2.6 kernel was by Rus V. Brushkoff. I have + * fixed a couple of things. + * * (27/May/2004) Ian Abbott * Improved throttling code, mostly stolen from the WhiteHEAT driver. * @@ -259,7 +264,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.4.0" +#define DRIVER_VERSION "v1.4.1" #define DRIVER_AUTHOR "Greg Kroah-Hartman , Bill Ryder , Kuba Ober " #define DRIVER_DESC "USB FTDI Serial Converters Driver" @@ -489,11 +494,18 @@ }; +static struct usb_device_id id_table_FT2232C[] = { + { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, + { } /* Terminating entry */ +}; + + static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, @@ -621,6 +633,8 @@ __u8 rx_flags; /* receive state flags (throttling) */ spinlock_t rx_lock; /* spinlock for receive state */ + __u16 interface; /* FT2232C port interface (0 for FT232/245) */ + int force_baud; /* if non-zero, force the baud rate to this value */ int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ }; @@ -637,6 +651,7 @@ static int ftdi_SIO_startup (struct usb_serial *serial); static int ftdi_8U232AM_startup (struct usb_serial *serial); static int ftdi_FT232BM_startup (struct usb_serial *serial); +static int ftdi_FT2232C_startup (struct usb_serial *serial); static int ftdi_USB_UIRT_startup (struct usb_serial *serial); static int ftdi_HE_TIRA1_startup (struct usb_serial *serial); static void ftdi_shutdown (struct usb_serial *serial); @@ -739,6 +754,32 @@ .shutdown = ftdi_shutdown, }; +static struct usb_serial_device_type ftdi_FT2232C_device = { + .owner = THIS_MODULE, + .name = "FTDI FT2232C Compatible", + .id_table = id_table_FT2232C, + .num_interrupt_in = 0, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = ftdi_open, + .close = ftdi_close, + .throttle = ftdi_throttle, + .unthrottle = ftdi_unthrottle, + .write = ftdi_write, + .write_room = ftdi_write_room, + .chars_in_buffer = ftdi_chars_in_buffer, + .read_bulk_callback = ftdi_read_bulk_callback, + .write_bulk_callback = ftdi_write_bulk_callback, + .tiocmget = ftdi_tiocmget, + .tiocmset = ftdi_tiocmset, + .ioctl = ftdi_ioctl, + .set_termios = ftdi_set_termios, + .break_ctl = ftdi_break_ctl, + .attach = ftdi_FT2232C_startup, + .shutdown = ftdi_shutdown, +}; + static struct usb_serial_device_type ftdi_USB_UIRT_device = { .owner = THIS_MODULE, .name = "USB-UIRT Infrared Tranceiver", @@ -866,7 +907,7 @@ usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - ftdi_high_or_low, 0, + ftdi_high_or_low, priv->interface, buf, 0, WDR_TIMEOUT); kfree(buf); @@ -896,7 +937,7 @@ usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - ftdi_high_or_low, 0, + ftdi_high_or_low, priv->interface, buf, 0, WDR_TIMEOUT); kfree(buf); @@ -909,6 +950,7 @@ static int change_speed(struct usb_serial_port *port) { + struct ftdi_private *priv = usb_get_serial_port_data(port); char *buf; __u16 urb_value; __u16 urb_index; @@ -922,6 +964,9 @@ urb_index_value = get_ftdi_divisor(port); urb_value = (__u16)urb_index_value; urb_index = (__u16)(urb_index_value >> 16); + if (priv->interface) { /* FT2232C */ + urb_index = (__u16)((urb_index << 8) | priv->interface); + } rv = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), @@ -1015,7 +1060,12 @@ } break; case FT232BM: /* FT232BM chip */ - chip_name = "FT232BM"; + case FT2232C: /* FT2232C chip */ + if (priv->chip_type == FT2232C) { + chip_name = "FT2232C"; + } else { + chip_name = "FT232BM"; + } if (baud <= 3000000) { div_value = ftdi_232bm_baud_to_divisor(baud); } else { @@ -1231,6 +1281,35 @@ return (0); } /* ftdi_FT232BM_startup */ +/* Startup for the FT2232C chip */ +/* Called from usbserial:serial_probe */ +static int ftdi_FT2232C_startup (struct usb_serial *serial) +{ /* ftdi_FT2232C_startup */ + struct ftdi_private *priv; + int err; + int inter; + + dbg("%s",__FUNCTION__); + err = ftdi_common_startup(serial); + if (err){ + return (err); + } + + priv = usb_get_serial_port_data(serial->port[0]); + priv->chip_type = FT2232C; + inter = serial->interface->altsetting->desc.bInterfaceNumber; + + if (inter) { + priv->interface = INTERFACE_B; + } + else { + priv->interface = INTERFACE_A; + } + priv->baud_base = 48000000 / 2; /* Would be / 16, but FT2232C supports multiple of 0.125 divisor fractions! */ + + return (0); +} /* ftdi_FT2232C_startup */ + /* Startup for the USB-UIRT device, which requires hardwired baudrate (38400 gets mapped to 312500) */ /* Called from usbserial:serial_probe */ static int ftdi_USB_UIRT_startup (struct usb_serial *serial) @@ -1323,7 +1402,7 @@ usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, FTDI_SIO_RESET_SIO, - 0, buf, 0, WDR_TIMEOUT); + priv->interface, buf, 0, WDR_TIMEOUT); /* Termios defaults are set by usb_serial_init. We don't change port->tty->termios - this would loose speed settings, etc. @@ -1373,6 +1452,7 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp) { /* ftdi_close */ unsigned int c_cflag = port->tty->termios->c_cflag; + struct ftdi_private *priv = usb_get_serial_port_data(port); char buf[1]; dbg("%s", __FUNCTION__); @@ -1383,7 +1463,8 @@ usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, 0, buf, 0, WDR_TIMEOUT) < 0) { + 0, priv->interface, buf, 0, + WDR_TIMEOUT) < 0) { err("error from flowcontrol urb"); } @@ -1796,7 +1877,7 @@ if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, - urb_value , 0, + urb_value , priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state); } @@ -1875,7 +1956,7 @@ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, - urb_value , 0, + urb_value , priv->interface, buf, 0, 100) < 0) { err("%s FAILED to set databits/stopbits/parity", __FUNCTION__); } @@ -1886,7 +1967,7 @@ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, 0, + 0, priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("%s error from disable flowcontrol urb", __FUNCTION__); } @@ -1903,6 +1984,13 @@ if (change_speed(port)) { err("%s urb failed to set baurdrate", __FUNCTION__); } + /* Ensure RTS and DTR are raised */ + else if (set_dtr(port, HIGH) < 0){ + err("%s Error from DTR HIGH urb", __FUNCTION__); + } + else if (set_rts(port, HIGH) < 0){ + err("%s Error from RTS HIGH urb", __FUNCTION__); + } } /* Set flow control */ @@ -1913,7 +2001,7 @@ usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0 , FTDI_SIO_RTS_CTS_HS, + 0 , (FTDI_SIO_RTS_CTS_HS | priv->interface), buf, 0, WDR_TIMEOUT) < 0) { err("urb failed to set to rts/cts flow control"); } @@ -1939,7 +2027,8 @@ usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - urb_value , FTDI_SIO_XON_XOFF_HS, + urb_value , (FTDI_SIO_XON_XOFF_HS + | priv->interface), buf, 0, WDR_TIMEOUT) < 0) { err("urb failed to set to xon/xoff flow control"); } @@ -1951,7 +2040,7 @@ usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, 0, + 0, priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("urb failed to clear flow control"); } @@ -1985,13 +2074,14 @@ break; case FT8U232AM: case FT232BM: + case FT2232C: /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same format as the data returned from the in point */ if ((ret = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), FTDI_SIO_GET_MODEM_STATUS_REQUEST, FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, - 0, 0, + 0, priv->interface, buf, 2, WDR_TIMEOUT)) < 0 ) { err("%s Could not get modem status of device - err: %d", __FUNCTION__, ret); @@ -2206,6 +2296,9 @@ retval = usb_serial_register(&ftdi_FT232BM_device); if (retval) goto failed_FT232BM_register; + retval = usb_serial_register(&ftdi_FT2232C_device); + if (retval) + goto failed_FT2232C_register; retval = usb_serial_register(&ftdi_USB_UIRT_device); if (retval) goto failed_USB_UIRT_register; @@ -2223,6 +2316,8 @@ failed_HE_TIRA1_register: usb_serial_deregister(&ftdi_USB_UIRT_device); failed_USB_UIRT_register: + usb_serial_deregister(&ftdi_FT2232C_device); +failed_FT2232C_register: usb_serial_deregister(&ftdi_FT232BM_device); failed_FT232BM_register: usb_serial_deregister(&ftdi_8U232AM_device); @@ -2241,6 +2336,7 @@ usb_deregister (&ftdi_driver); usb_serial_deregister (&ftdi_HE_TIRA1_device); usb_serial_deregister (&ftdi_USB_UIRT_device); + usb_serial_deregister (&ftdi_FT2232C_device); usb_serial_deregister (&ftdi_FT232BM_device); usb_serial_deregister (&ftdi_8U232AM_device); usb_serial_deregister (&ftdi_SIO_device); diff -Nru a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h --- a/drivers/usb/serial/ftdi_sio.h 2004-08-01 22:34:58 -07:00 +++ b/drivers/usb/serial/ftdi_sio.h 2004-08-01 22:34:58 -07:00 @@ -26,6 +26,7 @@ #define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ #define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */ #define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */ +#define FTDI_8U2232C_PID 0x6010 /* Dual channel device */ #define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */ #define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */ #define FTDI_NF_RIC_PID 0x0001 /* Product Id */ @@ -234,6 +235,21 @@ #define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ #define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ +/* Port interface code for FT2232C */ +#define INTERFACE_A 1 +#define INTERFACE_B 2 + + +/* + * BmRequestType: 1100 0000b + * bRequest: FTDI_E2_READ + * wValue: 0 + * wIndex: Address of word to read + * wLength: 2 + * Data: Will return a word of data from E2Address + * + */ + /* Port Identifier Table */ #define PIT_DEFAULT 0 /* SIOA */ #define PIT_SIOA 1 /* SIOA */ @@ -333,6 +349,7 @@ SIO = 1, FT8U232AM = 2, FT232BM = 3, + FT2232C = 4, } ftdi_chip_type_t; typedef enum { diff -Nru a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c --- a/drivers/usb/serial/ipaq.c 2004-08-01 22:34:58 -07:00 +++ b/drivers/usb/serial/ipaq.c 2004-08-01 22:34:58 -07:00 @@ -188,6 +188,7 @@ usb_set_serial_port_data(port, priv); priv->active = 0; priv->queue_len = 0; + priv->free_len = 0; INIT_LIST_HEAD(&priv->queue); INIT_LIST_HEAD(&priv->freelist); diff -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c --- a/drivers/usb/serial/pl2303.c 2004-08-01 22:34:58 -07:00 +++ b/drivers/usb/serial/pl2303.c 2004-08-01 22:34:58 -07:00 @@ -659,7 +659,7 @@ state = BREAK_OFF; else state = BREAK_ON; - dbg("%s - turning break %s", state==BREAK_OFF ? "off" : "on", __FUNCTION__); + dbg("%s - turning break %s", __FUNCTION__, state==BREAK_OFF ? "off" : "on"); result = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), BREAK_REQUEST, BREAK_REQUEST_TYPE, state, diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h --- a/drivers/usb/storage/unusual_devs.h 2004-08-01 22:34:58 -07:00 +++ b/drivers/usb/storage/unusual_devs.h 2004-08-01 22:34:58 -07:00 @@ -45,11 +45,6 @@ * */ -UNUSUAL_DEV( 0x03ee, 0x0000, 0x0000, 0x0245, - "Mitsumi", - "CD-R/RW Drive", - US_SC_8020, US_PR_CBI, NULL, 0), - UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0100, "Mitsumi", "USB FDD", @@ -373,6 +368,15 @@ US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_SINGLE_LUN), +/* Reported by Johann Cardon + * This entry is needed only because the device reports + * bInterfaceClass = 0xff (vendor-specific) + */ +UNUSUAL_DEV( 0x057b, 0x0022, 0x0000, 0x9999, + "Y-E Data", + "Silicon Media R/W", + US_SC_DEVICE, US_PR_DEVICE, NULL, 0), + /* Fabrizio Fellini */ UNUSUAL_DEV( 0x0595, 0x4343, 0x0000, 0x2210, "Fujifilm", @@ -384,11 +388,15 @@ "USB Hard Disk", US_SC_RBC, US_PR_CB, NULL, 0 ), -/* Submitted by Jol Bourquard */ +/* Submitted by Joel Bourquard + * Some versions of this device need the SubClass and Protocol overrides + * while others don't. + */ UNUSUAL_DEV( 0x05ab, 0x0060, 0x1104, 0x1110, "In-System", "PyroGate External CD-ROM Enclosure (FCD-523)", - US_SC_SCSI, US_PR_BULK, NULL, 0 ), + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_NEED_OVERRIDE ), #ifdef CONFIG_USB_STORAGE_ISD200 UNUSUAL_DEV( 0x05ab, 0x0031, 0x0100, 0x0110, @@ -685,7 +693,7 @@ "Trumpion", "t33520 USB Flash Card Controller", US_SC_DEVICE, US_PR_BULK, NULL, - US_FL_MODE_XLATE), + US_FL_NEED_OVERRIDE | US_FL_MODE_XLATE), /* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */ UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999,