bk://kernel.bkbits.net/gregkh/linux/usb-2.6 david-b@pacbell.net|ChangeSet|20040402202330|12668 david-b # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/04/02 12:23:30-08:00 david-b@pacbell.net # [PATCH] USB: usbcore blinkenlights # # The per-port LEDs on the most USB 2.0 hubs are programmable. # And the USB spec describes some ways to use them, blinking # to alert users about hardware (amber) or software (green) # problems. # # This patch is the infrastructure for that blinking. And # if you should happen to "modprobe usbcore blinkenlights", # the LEDs will cycle through all the ports ... which is # not a USB-standard mode, but it can certainly handy be # handy as a system heartbeat visible across the room. # # drivers/usb/core/hub.h # 2004/03/29 10:22:18-08:00 david-b@pacbell.net +20 -0 # USB: usbcore blinkenlights # # drivers/usb/core/hub.c # 2004/03/29 10:25:01-08:00 david-b@pacbell.net +128 -9 # USB: usbcore blinkenlights # # ChangeSet # 2004/04/02 11:35:28-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6 # into bix.(none):/usr/src/bk-usb # # include/linux/pci_ids.h # 2004/04/02 11:35:25-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/04/02 09:57:49-08:00 david-b@pacbell.net # [PATCH] USB Gadget: ethernet/rndis gadget updates # # This fixes an oops during "ifconfig usb0 down" after unplug # from a Windows box. It also shrinks the driver size to something # much more reasonable by leaving out debug messaging, and adds # a few missing newlines. # # drivers/usb/gadget/rndis.c # 2004/04/01 02:16:31-08:00 david-b@pacbell.net +14 -8 # USB Gadget: ethernet/rndis gadget updates # # drivers/usb/gadget/ether.c # 2004/04/01 02:20:26-08:00 david-b@pacbell.net +5 -1 # USB Gadget: ethernet/rndis gadget updates # # ChangeSet # 2004/04/02 09:56:28-08:00 david-b@pacbell.net # [PATCH] USB: ehci updates: CONFIG_PCI, integrated TT # # Generalize the driver a bit: # # - PCI-specific handling is restricted to a small chunk of # init code. Non-PCI implementations are in the pipeline. # # - Merge support from ARC International (Craig Nadler) for # their integrated root hub transaction translators (on PCI). # Other implementations should be similar. # # include/linux/pci_ids.h # 2004/04/01 00:36:59-08:00 david-b@pacbell.net +3 -0 # USB: ehci updates: CONFIG_PCI, integrated TT # # drivers/usb/host/Kconfig # 2004/04/01 00:44:47-08:00 david-b@pacbell.net +11 -0 # USB: ehci updates: CONFIG_PCI, integrated TT # # drivers/usb/host/ehci.h # 2004/04/01 00:36:59-08:00 david-b@pacbell.net +40 -0 # USB: ehci updates: CONFIG_PCI, integrated TT # # drivers/usb/host/ehci-q.c # 2004/04/01 00:36:58-08:00 david-b@pacbell.net +12 -3 # USB: ehci updates: CONFIG_PCI, integrated TT # # drivers/usb/host/ehci-hub.c # 2004/04/01 00:36:58-08:00 david-b@pacbell.net +16 -2 # USB: ehci updates: CONFIG_PCI, integrated TT # # drivers/usb/host/ehci-hcd.c # 2004/04/01 00:36:58-08:00 david-b@pacbell.net +41 -9 # USB: ehci updates: CONFIG_PCI, integrated TT # # drivers/usb/host/ehci-dbg.c # 2004/04/01 00:36:58-08:00 david-b@pacbell.net +4 -2 # USB: ehci updates: CONFIG_PCI, integrated TT # # ChangeSet # 2004/04/01 15:16:14-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # CREDITS # 2004/04/01 15:16:11-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/31 19:24:39-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6 # into bix.(none):/usr/src/bk-usb # # include/linux/usb.h # 2004/03/31 19:24:37-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/core/usb.c # 2004/03/31 19:24:37-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/core/message.c # 2004/03/31 19:24:37-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ppc64/defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ppc64/configs/pSeries_defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ppc/defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ppc/configs/pmac_defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ppc/configs/common_defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/parisc/configs/c3000_defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ia64/defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ia64/configs/zx1_defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ia64/configs/generic_defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/arm/configs/neponset_defconfig # 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/31 14:27:14-08:00 greg@kroah.com # Merge kroah.com:/home/greg/linux/BK/bleed-2.6 # into kroah.com:/home/greg/linux/BK/usb-2.6 # # drivers/usb/core/message.c # 2004/03/31 14:27:07-08:00 greg@kroah.com +0 -0 # Auto merged # # arch/ppc64/defconfig # 2004/03/31 14:27:07-08:00 greg@kroah.com +0 -0 # Auto merged # # arch/ppc64/configs/pSeries_defconfig # 2004/03/31 14:27:07-08:00 greg@kroah.com +0 -0 # Auto merged # # arch/ppc/configs/pmac_defconfig # 2004/03/31 14:27:07-08:00 greg@kroah.com +0 -0 # Auto merged # # arch/ppc/defconfig # 2004/03/31 14:27:06-08:00 greg@kroah.com +0 -0 # Auto merged # # arch/ppc/configs/common_defconfig # 2004/03/31 14:27:06-08:00 greg@kroah.com +0 -0 # Auto merged # # arch/parisc/configs/c3000_defconfig # 2004/03/31 14:27:06-08:00 greg@kroah.com +0 -0 # Auto merged # # arch/ia64/defconfig # 2004/03/31 14:27:06-08:00 greg@kroah.com +0 -0 # Auto merged # # arch/ia64/configs/zx1_defconfig # 2004/03/31 14:27:06-08:00 greg@kroah.com +0 -0 # Auto merged # # arch/ia64/configs/generic_defconfig # 2004/03/31 14:27:06-08:00 greg@kroah.com +0 -0 # Auto merged # # arch/arm/configs/neponset_defconfig # 2004/03/31 14:27:06-08:00 greg@kroah.com +0 -0 # Auto merged # # ChangeSet # 2004/03/31 14:17:38-08:00 greg@kroah.com # USB: add usb_get_intf() and usb_put_intf() functions as they will be needed. # # include/linux/usb.h # 2004/03/31 06:17:00-08:00 greg@kroah.com +3 -0 # USB: add usb_get_intf() and usb_put_intf() functions as they will be needed. # # drivers/usb/core/usb.c # 2004/03/31 06:17:00-08:00 greg@kroah.com +35 -1 # USB: add usb_get_intf() and usb_put_intf() functions as they will be needed. # # ChangeSet # 2004/03/31 14:08:01-08:00 greg@kroah.com # USB: clean up usb_get_dev() as it was written quite horribly. # # drivers/usb/core/usb.c # 2004/03/31 06:07:19-08:00 greg@kroah.com +3 -10 # USB: clean up usb_get_dev() as it was written quite horribly. # # ChangeSet # 2004/03/31 13:46:06-08:00 greg@kroah.com # USB: remove "released" field from struct usb_interface as it is not needed. # # include/linux/usb.h # 2004/03/31 05:45:30-08:00 greg@kroah.com +0 -3 # USB: remove "released" field from struct usb_interface as it is not needed. # # ChangeSet # 2004/03/31 13:35:04-08:00 david-b@pacbell.net # [PATCH] USB: remove usb_interface.driver field # # Remove usb_interface.driver, and along with it the "half bound" state # previously associated with drivers binding with claim() instead of probe(). # This changes usb_driver_claim_interface() semantics slightly: drivers must # now be prepared to accept disconnect() callbacks. # # Fixes more locking bugs, and a claim() oops that snuck in with a # recent patch. # # include/linux/usb.h # 2004/03/30 08:49:55-08:00 david-b@pacbell.net +16 -2 # USB: remove usb_interface.driver field # # drivers/usb/core/usb.c # 2004/03/30 09:30:45-08:00 david-b@pacbell.net +28 -59 # USB: remove usb_interface.driver field # # drivers/usb/core/message.c # 2004/03/30 09:34:54-08:00 david-b@pacbell.net +22 -3 # USB: remove usb_interface.driver field # # drivers/usb/core/devio.c # 2004/03/30 09:19:53-08:00 david-b@pacbell.net +33 -55 # USB: remove usb_interface.driver field # # drivers/usb/core/devices.c # 2004/03/30 08:50:40-08:00 david-b@pacbell.net +3 -1 # USB: remove usb_interface.driver field # # ChangeSet # 2004/03/31 13:34:31-08:00 david-b@pacbell.net # [PATCH] USB: RNDIS/Ethernet Gadget Driver .inf file # # Documentation/usb/linux.inf # 2004/03/30 16:25:48-08:00 david-b@pacbell.net +200 -0 # USB: RNDIS/Ethernet Gadget Driver .inf file # # Documentation/usb/linux.inf # 2004/03/30 16:25:48-08:00 david-b@pacbell.net +0 -0 # BitKeeper file /home/greg/linux/BK/usb-2.6/Documentation/usb/linux.inf # # ChangeSet # 2004/03/31 13:09:56-08:00 stern@rowland.harvard.edu # [PATCH] USB Gadget: Rename the dummy_hcd's gadget # # When David added an entry to the gadget_chips.h file for the dummy_hcd # driver, he mistakenly used the name "dummy_udc" rather than "dummy_hcd". # The mistake is understandable, since other controllers use "_udc" in their # names and it is illogical to put "_hcd" in a _device_ controller's name. # # This patch updates the dummy_hcd driver and changes the gadget name to # agree with the gadget_chips.h entry. # # drivers/usb/gadget/dummy_hcd.c # 2004/03/31 03:24:50-08:00 stern@rowland.harvard.edu +3 -1 # USB Gadget: Rename the dummy_hcd's gadget # # ChangeSet # 2004/03/31 13:09:35-08:00 stern@rowland.harvard.edu # [PATCH] USB: Complete all URBs in UHCI when releasing the bus # # This patch changes the UHCI driver's bus-release routine; now it will # correctly finish all pending but not-yet-completed URBs. This fixes a # reported bug, when trying to rmmod uhci-hcd while using a USB mouse under # X. Also, the patch changes a variable name from ...hs... to ...fs... # ("high speed" -> "full speed") -- something I accidentally omitted in an # earlier patch. # # drivers/usb/host/uhci-hcd.h # 2004/03/26 07:19:24-08:00 stern@rowland.harvard.edu +1 -1 # USB: Complete all URBs in UHCI when releasing the bus # # drivers/usb/host/uhci-hcd.c # 2004/03/26 07:19:10-08:00 stern@rowland.harvard.edu +8 -8 # USB: Complete all URBs in UHCI when releasing the bus # # drivers/usb/host/uhci-debug.c # 2004/03/26 07:19:43-08:00 stern@rowland.harvard.edu +1 -1 # USB: Complete all URBs in UHCI when releasing the bus # # ChangeSet # 2004/03/31 13:09:04-08:00 stern@rowland.harvard.edu # [PATCH] USB Gadget: Use automatic endpoint selection in file-storage # # This patch imports the endpoint auto-config library into the file-storage # gadget, simplifying the code needed for endpoint selection and removing # almost all dependencies on the controller type from the driver. It also # changes some log messages for reporting fatal problems from INFO to ERROR. # # drivers/usb/gadget/file_storage.c # 2004/03/31 03:28:54-08:00 stern@rowland.harvard.edu +81 -175 # USB Gadget: Use automatic endpoint selection in file-storage # # drivers/usb/gadget/Makefile # 2004/03/31 03:28:50-08:00 stern@rowland.harvard.edu +2 -1 # USB Gadget: Use automatic endpoint selection in file-storage # # ChangeSet # 2004/03/31 13:08:35-08:00 stern@rowland.harvard.edu # [PATCH] USB Gadget: Use configuration-buffer library in file-storage # # This patch imports the config-buffer library into the file-storage gadget, # simplifying and decreasing the amount of code needed for assembling # configuration descriptors. It also changes the driver to remove any # pretense at bus-powered operation and to use the new DUALSPEED # configuration option. This is in line with recent changes made to other # gadget drivers. # # drivers/usb/gadget/file_storage.c # 2004/03/31 03:28:54-08:00 stern@rowland.harvard.edu +91 -107 # USB Gadget: Use configuration-buffer library in file-storage # # drivers/usb/gadget/Makefile # 2004/03/31 03:28:50-08:00 stern@rowland.harvard.edu +1 -1 # USB Gadget: Use configuration-buffer library in file-storage # # ChangeSet # 2004/03/30 20:18:36-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6 # into bix.(none):/usr/src/bk-usb # # arch/ppc64/defconfig # 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ppc64/configs/pSeries_defconfig # 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ppc/defconfig # 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ppc/configs/pmac_defconfig # 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ppc/configs/common_defconfig # 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/parisc/configs/c3000_defconfig # 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ia64/defconfig # 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ia64/configs/zx1_defconfig # 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/ia64/configs/generic_defconfig # 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0 # Auto merged # # arch/arm/configs/neponset_defconfig # 2004/03/30 20:18:32-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/30 17:18:44-08:00 david-b@pacbell.net # [PATCH] USB: fix dvb-ttusb-budget driver due to set_configuration locking cleanups # # > Oops, you forgot to grep: # > # > CC [M] drivers/media/dvb/ttusb-dec/ttusb_dec.o # > drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c: In function `ttusb_setup_interfaces': # > drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c:1011: warning: implicit declaration of function `usb_set_configuration' # # Well, when I did the grep that bug wasn't there; it # was just integrated on Feb 26! # # # > Care to send a patch to fix it up before Andrew gets grumpy with me for # > breaking his build? :) # # The first part makes it use usb_reset_configuration() like # it did before ... I'm surprised this driver hasn't been # generating "it deadlocks during probe" reports. # # The second part prints a diagnostic if the configuration # wasn't set right; the fix would use hotplug and sysfs. # # drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c # 2004/03/30 07:50:57-08:00 david-b@pacbell.net +12 -1 # USB: fix dvb-ttusb-budget driver due to set_configuration locking cleanups # # ChangeSet # 2004/03/30 17:18:20-08:00 davej@redhat.com # [PATCH] USB: w9968cf driver misplaced ; # # drivers/usb/media/w9968cf.c # 2004/03/30 06:29:08-08:00 davej@redhat.com +1 -1 # USB: w9968cf driver misplaced ; # # ChangeSet # 2004/03/30 14:12:25-08:00 alessandro.zummo@towertech.it # [PATCH] USB: omninet patch # # here's a small patch for omninet.c . # # drivers/usb/serial/omninet.c # 2004/03/27 07:59:33-08:00 alessandro.zummo@towertech.it +3 -1 # USB: omninet patch # # ChangeSet # 2004/03/30 14:12:10-08:00 marcel@holtmann.org # [PATCH] USB: Rename the USB HID driver # # > > I like to see this rename as soon as possible. So if nobody minds I send # > > a patch to LKML and ask Linus for inclusion. # > # > Go ahead, but also please patch all relevant documentation in the # > kernel. # # the attached patch should do the renaming everywhere hid or hid.o was # mentioned. It also removes all references to *.o module names. # # drivers/usb/input/Makefile # 2004/03/22 06:32:15-08:00 marcel@holtmann.org +8 -8 # USB: Rename the USB HID driver # # drivers/usb/input/Kconfig # 2004/03/22 06:42:37-08:00 marcel@holtmann.org +1 -1 # USB: Rename the USB HID driver # # Documentation/input/joystick.txt # 2004/03/23 06:15:59-08:00 marcel@holtmann.org +2 -2 # USB: Rename the USB HID driver # # Documentation/input/input.txt # 2004/03/23 06:15:14-08:00 marcel@holtmann.org +35 -35 # USB: Rename the USB HID driver # # Documentation/input/ff.txt # 2004/03/23 06:13:26-08:00 marcel@holtmann.org +1 -1 # USB: Rename the USB HID driver # # ChangeSet # 2004/03/30 14:11:48-08:00 david-b@pacbell.net # [PATCH] USB: RNDIS/Ethernet Gadget Driver comment changes # # Whoops, I missed something. You should apply this patch too. # # The RNDIS spec license agreement does NOT require tacking any # GPL-incompatible restrictions on the results of _using_ the # spec: # # "... may be used solely for the purpose of implementing # the RNDIS protocol message set to interface with ..." # (the two cases identified in the text) # # And that's all the implementation does -- end of story. # # drivers/usb/gadget/rndis.h # 2004/03/30 01:16:09-08:00 david-b@pacbell.net +2 -4 # USB: RNDIS/Ethernet Gadget Driver comment changes # # ChangeSet # 2004/03/30 14:11:25-08:00 davej@redhat.com # [PATCH] USB: kill off CONFIG_USB_BRLVGER detritus. # # This died a while ago, but lingers on in defconfigs. # # arch/ppc64/defconfig # 2004/03/30 09:36:55-08:00 davej@redhat.com +0 -1 # USB: kill off CONFIG_USB_BRLVGER detritus. # # arch/ppc64/configs/pSeries_defconfig # 2004/03/30 09:36:53-08:00 davej@redhat.com +0 -1 # USB: kill off CONFIG_USB_BRLVGER detritus. # # arch/ppc/defconfig # 2004/03/30 09:36:45-08:00 davej@redhat.com +0 -1 # USB: kill off CONFIG_USB_BRLVGER detritus. # # arch/ppc/configs/sandpoint_defconfig # 2004/03/30 09:35:50-08:00 davej@redhat.com +0 -1 # USB: kill off CONFIG_USB_BRLVGER detritus. # # arch/ppc/configs/pmac_defconfig # 2004/03/30 09:36:43-08:00 davej@redhat.com +0 -1 # USB: kill off CONFIG_USB_BRLVGER detritus. # # arch/ppc/configs/lopec_defconfig # 2004/03/30 09:35:36-08:00 davej@redhat.com +0 -1 # USB: kill off CONFIG_USB_BRLVGER detritus. # # arch/ppc/configs/common_defconfig # 2004/03/30 09:35:57-08:00 davej@redhat.com +0 -1 # USB: kill off CONFIG_USB_BRLVGER detritus. # # arch/ppc/configs/adir_defconfig # 2004/03/30 09:35:42-08:00 davej@redhat.com +0 -1 # USB: kill off CONFIG_USB_BRLVGER detritus. # # arch/parisc/defconfig # 2004/03/30 09:36:59-08:00 davej@redhat.com +0 -1 # USB: kill off CONFIG_USB_BRLVGER detritus. # # arch/parisc/configs/c3000_defconfig # 2004/03/30 09:36:57-08:00 davej@redhat.com +0 -1 # USB: kill off CONFIG_USB_BRLVGER detritus. # # arch/mips/configs/rm200_defconfig # 2004/03/30 09:36:52-08:00 davej@redhat.com +0 -1 # USB: kill off CONFIG_USB_BRLVGER detritus. # # arch/ia64/defconfig # 2004/03/30 09:36:50-08:00 davej@redhat.com +0 -1 # USB: kill off CONFIG_USB_BRLVGER detritus. # # arch/ia64/configs/zx1_defconfig # 2004/03/30 09:36:46-08:00 davej@redhat.com +0 -1 # USB: kill off CONFIG_USB_BRLVGER detritus. # # arch/ia64/configs/generic_defconfig # 2004/03/30 09:36:48-08:00 davej@redhat.com +0 -1 # USB: kill off CONFIG_USB_BRLVGER detritus. # # arch/arm/configs/neponset_defconfig # 2004/03/30 09:35:28-08:00 davej@redhat.com +0 -1 # USB: kill off CONFIG_USB_BRLVGER detritus. # # ChangeSet # 2004/03/30 14:11:00-08:00 Andries.Brouwer@cwi.nl # [PATCH] USB Storage: datafab fix and unusual devices # # datafab.c has an often-seen bug: the SCSI READ_CAPACITY command # does not need the number of sectors but the last sector. # # I just tried the CF and SM parts of a 5-in-1 card reader. # The CF part works with US_PR_DATAFAB when the bug mentioned is fixed. # The SM part works with US_PR_SDDR55. # (Revision Number is 17.08 - that in case the 0000-ffff # should prove to be too optimistic.) # # We still must discuss what setup to use for readers like this - # I have several of them - that require different drivers for # different LUNs. As it is now one has to compile usb-storage # twice, once with CONFIG_USB_STORAGE_DATAFAB defined and once # without, and remove one usb-storage.ko and insert the other # to go from CF to SM. (And that hangs with 2.6.4 so a reboot # is required..) # # drivers/usb/storage/unusual_devs.h # 2004/03/29 13:59:47-08:00 Andries.Brouwer@cwi.nl +15 -0 # USB Storage: datafab fix and unusual devices # # drivers/usb/storage/datafab.c # 2004/03/29 14:00:36-08:00 Andries.Brouwer@cwi.nl +2 -2 # USB Storage: datafab fix and unusual devices # # ChangeSet # 2004/03/30 14:10:36-08:00 pmarques@grupopie.com # [PATCH] USB: ftdi_sio.c: not unlinking urb on ftdi_close # # This patch fixes a bug in ftdi_sio.c where the driver wouldn't unlink the # read urb if the user application cleared the HUPCL flag on termios->c_cflag. # # drivers/usb/serial/ftdi_sio.c # 2004/03/29 08:22:02-08:00 pmarques@grupopie.com +8 -7 # USB: ftdi_sio.c: not unlinking urb on ftdi_close # # ChangeSet # 2004/03/30 14:10:11-08:00 akpm@osdl.org # [PATCH] USB: drivers/usb/gadget/epautoconf.c gcc-3.5 build fix # # drivers/usb/gadget/epautoconf.c: In function `ep_matches': # drivers/usb/gadget/epautoconf.c:175: error: `typeof' applied to a bit-field # # drivers/usb/gadget/epautoconf.c # 2004/03/27 03:28:44-08:00 akpm@osdl.org +8 -3 # USB: drivers/usb/gadget/epautoconf.c gcc-3.5 build fix # # ChangeSet # 2004/03/30 12:09:32-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6 # into bix.(none):/usr/src/bk-usb # # include/linux/usb.h # 2004/03/30 12:09:29-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/core/usb.c # 2004/03/30 12:09:29-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/core/message.c # 2004/03/30 12:09:29-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/30 09:25:17-08:00 david-b@pacbell.net # [PATCH] USB: set_configuration locking cleanups # # I've posted all these before, the only notable change is # treating that one gphoto2 case as warn-and-continue rather # than return-with-failure. # # # usb_set_configuration() cleanup # # * Remove it from the USB kernel driver API. No drivers need it now, # and the sysadmin can change bConfigurationValue using sysfs (say, # when hotplugging an otherwise problematic device). # # * Simpler/cleaner locking: caller must own dev->serialize. # # * Access from usbfs now uses usb_reset_configuration() sometimes, # preventing sysfs thrash, and warns about some dangerous usage # (which gphoto2 and other programs may be relying on). (This is # from Alan Stern, but I morphed an error return into a warning.) # # * Prevent a couple potential "no configuration" oopses. (Alan's?) # # * Remove one broken call from usbcore, in the "device morphed" path # of usb_reset_device(). This should be more polite now, hanging # that one device rather than khubd. # # include/linux/usb.h # 2004/03/30 01:04:29-08:00 david-b@pacbell.net +0 -1 # USB: set_configuration locking cleanups # # drivers/usb/core/usb.h # 2004/03/30 01:06:12-08:00 david-b@pacbell.net +1 -0 # USB: set_configuration locking cleanups # # drivers/usb/core/usb.c # 2004/03/30 01:04:29-08:00 david-b@pacbell.net +4 -0 # USB: set_configuration locking cleanups # # drivers/usb/core/message.c # 2004/03/30 01:04:29-08:00 david-b@pacbell.net +2 -5 # USB: set_configuration locking cleanups # # drivers/usb/core/hub.c # 2004/03/30 01:04:28-08:00 david-b@pacbell.net +8 -26 # USB: set_configuration locking cleanups # # drivers/usb/core/driverfs.c # 2004/03/30 01:04:28-08:00 david-b@pacbell.net +2 -0 # USB: set_configuration locking cleanups # # drivers/usb/core/devio.c # 2004/03/30 01:04:28-08:00 david-b@pacbell.net +46 -1 # USB: set_configuration locking cleanups # # ChangeSet # 2004/03/30 08:56:45-08:00 david-b@pacbell.net # [PATCH] USB Gadget: RNDIS/Ethernet Gadget Driver (2/2) # # This updates the existing Ethernet gadget driver to # support an additional RNDIS configuration on all # current USB controllers that can support one. # # It also includes a bit more work to address the complex # autoconfiguration of this driver. Needs testing on PXA. # # Patch (mostly) contributed by Robert Schwebel, and developed # with support from Auerswald GmbH. # # drivers/usb/gadget/ether.c # 2004/03/30 00:22:30-08:00 david-b@pacbell.net +818 -176 # USB Gadget: RNDIS/Ethernet Gadget Driver (2/2) # # ChangeSet # 2004/03/30 08:56:15-08:00 david-b@pacbell.net # [PATCH] USB Gadget: RNDIS/Ethernet Gadget Driver (1/2) # # This patch adds the RNDIS message engine and kbuild/kconfig # support for it. This is currently labeled EXPERIMENTAL. # # Patch contributed by Robert Schwebel, and developed with # support from Auerswald GmbH. # # drivers/usb/gadget/rndis.h # 2004/03/28 07:54:37-08:00 david-b@pacbell.net +313 -0 # USB Gadget: RNDIS/Ethernet Gadget Driver (1/2) # # drivers/usb/gadget/rndis.c # 2004/03/28 07:54:37-08:00 david-b@pacbell.net +1362 -0 # USB Gadget: RNDIS/Ethernet Gadget Driver (1/2) # # drivers/usb/gadget/rndis.h # 2004/03/28 07:54:37-08:00 david-b@pacbell.net +0 -0 # BitKeeper file /home/linux/BK/usb-2.6/drivers/usb/gadget/rndis.h # # drivers/usb/gadget/rndis.c # 2004/03/28 07:54:37-08:00 david-b@pacbell.net +0 -0 # BitKeeper file /home/linux/BK/usb-2.6/drivers/usb/gadget/rndis.c # # drivers/usb/gadget/ndis.h # 2004/03/27 17:42:32-08:00 david-b@pacbell.net +187 -0 # USB Gadget: RNDIS/Ethernet Gadget Driver (1/2) # # drivers/usb/gadget/Makefile # 2004/03/28 07:54:37-08:00 david-b@pacbell.net +4 -0 # USB Gadget: RNDIS/Ethernet Gadget Driver (1/2) # # drivers/usb/gadget/Kconfig # 2004/03/28 07:54:37-08:00 david-b@pacbell.net +16 -1 # USB Gadget: RNDIS/Ethernet Gadget Driver (1/2) # # drivers/usb/gadget/ndis.h # 2004/03/27 17:42:32-08:00 david-b@pacbell.net +0 -0 # BitKeeper file /home/linux/BK/usb-2.6/drivers/usb/gadget/ndis.h # # ChangeSet # 2004/03/30 08:55:44-08:00 david-b@pacbell.net # [PATCH] USB: ohci unlink tweaks # # Minor unlink tweaks, including a case where SMP could oops # if it were abused, as if from 'usbtest' or 'stir4200'. # # drivers/usb/host/ohci-q.c # 2004/03/29 08:17:38-08:00 david-b@pacbell.net +5 -3 # USB: ohci unlink tweaks # # drivers/usb/host/ohci-hcd.c # 2004/03/29 08:17:38-08:00 david-b@pacbell.net +1 -1 # USB: ohci unlink tweaks # # ChangeSet # 2004/03/30 08:55:23-08:00 david-b@pacbell.net # [PATCH] USB: usb/core/config.c null pointers after kfree # # Prevents an oops with some other patchsets. # # # Clear some pointers after the memory is kfreed, to avoid # making some other patch combinations oops. # # drivers/usb/core/config.c # 2004/03/29 08:17:38-08:00 david-b@pacbell.net +2 -0 # USB: usb/core/config.c null pointers after kfree # # ChangeSet # 2004/03/30 08:53:38-08:00 david-b@pacbell.net # [PATCH] USB; minor usbfs locking updates # # These are "obvious" locking fixes: using the right lock # to protect interface claim/release (should be the driver # model bus lock, not BKL). # # drivers/usb/core/devio.c # 2004/03/29 09:20:58-08:00 david-b@pacbell.net +7 -2 # USB; minor usbfs locking updates # # drivers/usb/core/devices.c # 2004/03/29 09:18:25-08:00 david-b@pacbell.net +2 -2 # USB; minor usbfs locking updates # # ChangeSet # 2004/03/29 18:05:43-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # MAINTAINERS # 2004/03/29 18:05:41-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/29 13:51:58-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # CREDITS # 2004/03/29 13:51:56-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/28 12:29:41-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # drivers/usb/core/message.c # 2004/03/28 12:29:38-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/27 02:28:18-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6 # into bix.(none):/usr/src/bk-usb # # drivers/usb/input/wacom.c # 2004/03/27 02:28:16-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/26 14:39:04-08:00 stern@rowland.harvard.edu # [PATCH] USB: Altsetting update for USB input drivers # # This patch continues the update process for the cur_altsetting change. # The drivers in usb/input were all in good shape and needed only minimal # changes. # # drivers/usb/input/xpad.c # 2004/03/26 07:44:59-08:00 stern@rowland.harvard.edu +1 -1 # USB: Altsetting update for USB input drivers # # drivers/usb/input/wacom.c # 2004/03/26 07:44:17-08:00 stern@rowland.harvard.edu +1 -1 # USB: Altsetting update for USB input drivers # # drivers/usb/input/powermate.c # 2004/03/26 07:41:07-08:00 stern@rowland.harvard.edu +1 -1 # USB: Altsetting update for USB input drivers # # drivers/usb/input/kbtab.c # 2004/03/26 07:38:45-08:00 stern@rowland.harvard.edu +1 -1 # USB: Altsetting update for USB input drivers # # drivers/usb/input/aiptek.c # 2004/03/17 07:49:06-08:00 stern@rowland.harvard.edu +1 -1 # USB: Altsetting update for USB input drivers # # ChangeSet # 2004/03/26 14:26:00-08:00 david-b@pacbell.net # [PATCH] USB: ohci misc updates # # Mostly from Benjamin Herrenschmidt: # # - prevent usbcore from asking the HCD root hub code # to read registers on one more suspend path (some # hardware gets upset in those cases); # # - try handling a "device died" cleanup case better # # - add some wmb() calls in spots that could matter # on some hardware # # drivers/usb/host/ohci-q.c # 2004/03/25 12:46:59-08:00 david-b@pacbell.net +4 -0 # USB: ohci misc updates # # drivers/usb/host/ohci-hcd.c # 2004/03/25 12:48:40-08:00 david-b@pacbell.net +4 -1 # USB: ohci misc updates # # drivers/usb/core/hcd.c # 2004/03/25 12:58:45-08:00 david-b@pacbell.net +8 -3 # USB: ohci misc updates # # ChangeSet # 2004/03/26 14:25:35-08:00 dsaxena@plexity.net # [PATCH] IXP425 -> IXP4XX conversion for USB-gadget # # The 2.6 code for Intel's IXP4xx NPU line has been updated to # remove all references to IXP42x or IXP425 and replace it # with IXP4XX, including config options and file names. This # patch updates the USB-gadget pxa-udc driver with these changes. # # drivers/usb/gadget/pxa2xx_udc.c # 2004/03/14 14:08:38-08:00 dsaxena@plexity.net +4 -4 # IXP425 -> IXP4XX conversion for USB-gadget # # drivers/usb/gadget/Kconfig # 2004/03/14 14:08:38-08:00 dsaxena@plexity.net +2 -2 # IXP425 -> IXP4XX conversion for USB-gadget # # ChangeSet # 2004/03/26 13:45:58-08:00 greg@kroah.com # USB: fix compiler warning in whiteheat driver. # # drivers/usb/serial/whiteheat.c # 2004/03/26 05:45:39-08:00 greg@kroah.com +0 -1 # USB: fix compiler warning in whiteheat driver. # # ChangeSet # 2004/03/26 13:42:45-08:00 coreyed@linxtechnologies.com # [PATCH] USB: add ftdi_sio product ids # # drivers/usb/serial/ftdi_sio.h # 2004/03/25 12:24:55-08:00 coreyed@linxtechnologies.com +9 -0 # USB: add ftdi_sio product ids # # drivers/usb/serial/ftdi_sio.c # 2004/03/25 12:24:55-08:00 coreyed@linxtechnologies.com +10 -0 # USB: add ftdi_sio product ids # # ChangeSet # 2004/03/26 13:33:56-08:00 greg@kroah.com # USB: ftdi_sio merge fixups. # # drivers/usb/serial/ftdi_sio.h # 2004/03/26 05:33:25-08:00 greg@kroah.com +0 -5 # USB: ftdi_sio merge fixups. # # drivers/usb/serial/ftdi_sio.c # 2004/03/26 05:33:25-08:00 greg@kroah.com +0 -1 # USB: ftdi_sio merge fixups. # # ChangeSet # 2004/03/26 13:32:06-08:00 info@gudeads.com # [PATCH] USB: more ftdi_sio ids # # drivers/usb/serial/ftdi_sio.h # 2004/03/26 01:36:12-08:00 info@gudeads.com +21 -1 # USB: more ftdi_sio ids # # drivers/usb/serial/ftdi_sio.c # 2004/03/26 01:32:28-08:00 info@gudeads.com +16 -0 # USB: more ftdi_sio ids # # ChangeSet # 2004/03/26 13:29:43-08:00 stern@rowland.harvard.edu # [PATCH] USB: Add dummy_hcd to the main kernel # # This is a resubmission of as225, together with appropriate changes for the # g_serial driver. David Brownell's latest g_ether update makes it # unnecessary to change that file or gadget_chips.h. # # # # dummy_hcd is simultaneously a host controller driver and a device # controller driver. It creates a simulated HC together with a simulated # UDC plugged into it. Gadget drivers can run under the simulated UDC and # will appear as regular USB devices on the simulated HC. The simulation is # reasonably (although not totally) realistic. # # It's a wonderful tool for testing and developing gadget drivers without # the need for lots of additional hardware: Both the host driver and the # gadget driver can run on the same computer. It's been available for quite # some time in David's gadget-2.6 tree and it works well. I couldn't have # gotten the file-storage gadget running in any reasonable length of time # without it. # # drivers/usb/gadget/serial.c # 2004/03/16 09:59:35-08:00 stern@rowland.harvard.edu +21 -0 # USB: Add dummy_hcd to the main kernel # # drivers/usb/gadget/Makefile # 2004/03/15 08:28:59-08:00 stern@rowland.harvard.edu +1 -0 # USB: Add dummy_hcd to the main kernel # # drivers/usb/gadget/Kconfig # 2004/03/15 08:28:39-08:00 stern@rowland.harvard.edu +28 -0 # USB: Add dummy_hcd to the main kernel # # drivers/usb/gadget/dummy_hcd.c # 2004/03/15 08:30:46-08:00 stern@rowland.harvard.edu +1677 -0 # USB: Add dummy_hcd to the main kernel # # drivers/usb/gadget/dummy_hcd.c # 2004/03/15 08:30:46-08:00 stern@rowland.harvard.edu +0 -0 # BitKeeper file /home/greg/linux/BK/usb-2.6/drivers/usb/gadget/dummy_hcd.c # # ChangeSet # 2004/03/26 13:23:41-08:00 greg@kroah.com # USB: mark pwc driver as broken, as it is. # # And the maintainer doesn't seem to want to fix it :( # # drivers/usb/media/Kconfig # 2004/03/26 05:23:18-08:00 greg@kroah.com +1 -1 # USB: mark pwc driver as broken, as it is. # # And the maintainer doesn't seem to want to fix it :( # # ChangeSet # 2004/03/26 12:32:39-08:00 mroos@linux.ee # [PATCH] USB: fix whiteheat USB serial compile failure on PPC # # > Bah, looks like PPC doesn't ever define CMSPAR :( # > # > How about adding something like: # > #ifndef CMSPAR # > #define CMSPAR 0 # > #endif # > To the beginning of the driver like the cdc-acm.c driver does? If that # > works, care to send me a patch? # # Yes, it compiles. # # drivers/usb/serial/whiteheat.c # 2004/03/26 06:10:26-08:00 mroos@linux.ee +4 -0 # USB: fix whiteheat USB serial compile failure on PPC # # ChangeSet # 2004/03/26 12:32:02-08:00 david-b@pacbell.net # [PATCH] USB: g_ether does endpoint autoconfig too # # Here's an update for the Ethernet gadget that corresponds # to the earlier one for Gadget Zero ... it gets rid of almost # all the remaining controller-specific #ifdefs in this driver. # (And also lets the driver initialize using "dummy_hcd".) # # This is a significant step towards doing hardware-specific # configuration at run time (or at least init-time) rather # than compile time, but other patches will be needed to take # it the rest of the way there. (Especially considering the # RNDIS support...) The runtime footprint of the driver shrank # a bit, mostly because things moved into the init section. # # drivers/usb/gadget/gadget_chips.h # 2004/03/25 11:10:44-08:00 david-b@pacbell.net +6 -0 # USB: g_ether does endpoint autoconfig too # # drivers/usb/gadget/ether.c # 2004/03/25 11:25:03-08:00 david-b@pacbell.net +266 -287 # USB: g_ether does endpoint autoconfig too # # drivers/usb/gadget/epautoconf.c # 2004/03/25 11:10:44-08:00 david-b@pacbell.net +1 -1 # USB: g_ether does endpoint autoconfig too # # drivers/usb/gadget/Makefile # 2004/03/25 11:11:01-08:00 david-b@pacbell.net +2 -2 # USB: g_ether does endpoint autoconfig too # # ChangeSet # 2004/03/26 12:31:37-08:00 david-b@pacbell.net # [PATCH] USB: usbnet, minor probe() fault fix # # Some hardware had the poor taste to misbehave during probe(), # which turned up a minor bug. This fixes it: don't try to # free a network device that hasn't been registerd. # # drivers/usb/net/usbnet.c # 2004/03/25 07:55:35-08:00 david-b@pacbell.net +1 -2 # USB: usbnet, minor probe() fault fix # # ChangeSet # 2004/03/26 12:31:15-08:00 david-b@pacbell.net # [PATCH] USB: define USB feature bit indices # # This patch provides standard symbols for the various USB # device and endpoint feature bits, so that drivers can # use symbolic names for them. It also changes the code # relating to endpoint halts so it uses those symbols. # # include/linux/usb_ch9.h # 2004/03/24 08:08:49-08:00 david-b@pacbell.net +14 -0 # USB: define USB feature bit indices # # drivers/usb/storage/transport.c # 2004/03/24 08:11:56-08:00 david-b@pacbell.net +3 -2 # USB: define USB feature bit indices # # drivers/usb/misc/usbtest.c # 2004/03/25 01:37:22-08:00 david-b@pacbell.net +2 -1 # USB: define USB feature bit indices # # drivers/usb/gadget/net2280.c # 2004/03/24 08:12:41-08:00 david-b@pacbell.net +2 -2 # USB: define USB feature bit indices # # drivers/usb/gadget/goku_udc.c # 2004/03/24 08:13:26-08:00 david-b@pacbell.net +1 -2 # USB: define USB feature bit indices # # drivers/usb/core/message.c # 2004/03/24 08:10:38-08:00 david-b@pacbell.net +2 -1 # USB: define USB feature bit indices # # drivers/usb/core/hcd.h # 2004/03/24 08:08:49-08:00 david-b@pacbell.net +0 -4 # USB: define USB feature bit indices # # ChangeSet # 2004/03/26 12:30:48-08:00 arjanv@redhat.com # [PATCH] USB: fix race in whiteheat serial driver # # Patch below fixes an obvious race in the whiteheat usb serial driver... # # drivers/usb/serial/whiteheat.c # 2004/03/25 02:12:51-08:00 arjanv@redhat.com +2 -4 # USB: fix race in whiteheat serial driver # # ChangeSet # 2004/03/26 12:24:49-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6 # into bix.(none):/usr/src/bk-usb # # include/linux/usb_gadget.h # 2004/03/26 12:24:46-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/core/usb.c # 2004/03/26 12:24:46-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/26 11:25:25-08:00 mochel@digitalimplant.org # [PATCH] USB: Fix drivers/usb/net/Kconfig # # This allows the pegasus driver to actually be seen as a config option. # Apparently it's not that popular, though I have confirmed that it still # works on at least the netgear fv101. # # drivers/usb/net/Kconfig # 2004/03/23 07:47:16-08:00 mochel@digitalimplant.org +1 -1 # USB: Fix drivers/usb/net/Kconfig # # ChangeSet # 2004/03/26 11:24:29-08:00 oliver@neukum.org # [PATCH] USB: fix hfc_usb sleeping in irq # # you are using GFP_KERNEL in irq and __devinit with hotpluggable code. # # - use proper GFP flags # - kill __devinit # # drivers/isdn/hisax/hfc_usb.c # 2004/03/23 15:09:59-08:00 oliver@neukum.org +4 -4 # USB: fix hfc_usb sleeping in irq # # ChangeSet # 2004/03/26 11:23:03-08:00 oliver@neukum.org # [PATCH] USB: fix typo in previous patch # # I screwed up. This corrects it. # # drivers/isdn/hisax/st5481_usb.c # 2004/03/23 14:19:04-08:00 oliver@neukum.org +1 -1 # USB: fix typo in previous patch # # ChangeSet # 2004/03/26 11:21:48-08:00 oliver@neukum.org # [PATCH] USB: cleanup of st5481 # # you are using __devinit which must not be used with USB drivers, # in addition you are using some false GFP values and fail to check # some error codes. # # - check for unlink due to removal of controller # - correct GFP values # - no __devinit in USB # # drivers/isdn/hisax/st5481_usb.c # 2004/03/23 14:16:52-08:00 oliver@neukum.org +12 -12 # USB: cleanup of st5481 # # drivers/isdn/hisax/st5481_init.c # 2004/03/23 14:16:52-08:00 oliver@neukum.org +2 -2 # USB: cleanup of st5481 # # drivers/isdn/hisax/st5481_d.c # 2004/03/23 14:16:52-08:00 oliver@neukum.org +4 -4 # USB: cleanup of st5481 # # drivers/isdn/hisax/st5481_b.c # 2004/03/23 14:16:52-08:00 oliver@neukum.org +3 -3 # USB: cleanup of st5481 # # ChangeSet # 2004/03/26 11:20:06-08:00 oliver@neukum.org # [PATCH] USB: fix DMA to stack in ftdi driver # # this driver is doing DMA to the stack. Here's the obvious fix. # # drivers/usb/serial/ftdi_sio.c # 2004/03/22 15:25:09-08:00 oliver@neukum.org +35 -9 # USB: fix DMA to stack in ftdi driver # # ChangeSet # 2004/03/26 11:18:25-08:00 patrick.boettcher@desy.de # [PATCH] USB: fix bug in usb-skeleton.c # # drivers/usb/usb-skeleton.c # 2004/03/20 11:49:01-08:00 patrick.boettcher@desy.de +1 -1 # USB: fix bug in usb-skeleton.c # # ChangeSet # 2004/03/25 17:19:38-08:00 arjanv@redhat.com # [PATCH] USB: usb hiddev stack usage patch # # Patch below fixes some obscenely high stack uage; # struct hiddev_usage_ref_multi is well over 4Kb in size so really doesn't # belong on the stack. # # drivers/usb/input/hiddev.c # 2004/03/22 01:33:05-08:00 arjanv@redhat.com +49 -31 # USB: usb hiddev stack usage patch # # ChangeSet # 2004/03/25 17:19:03-08:00 oliver@neukum.org # [PATCH] USB: fix error paths in kobil_sct # # some error codes are incorrect and there's an URB leak in an error path. # # drivers/usb/serial/kobil_sct.c # 2004/03/22 11:10:39-08:00 oliver@neukum.org +5 -3 # USB: fix error paths in kobil_sct # # ChangeSet # 2004/03/25 17:18:01-08:00 stern@rowland.harvard.edu # [PATCH] USB: UHCI: Get rid of excessive spinlocks # # This patch introduces a major simplification into the UHCI driver by # replacing its multiple spinlocks with a single one. The protected area of # code is slightly larger and there's more possibilities for contention on # an SMP system, but I think that shouldn't be a problem. Stephen Hemminger # has been kind enough to test this on his SMP computer and he hasn't # encountered any difficulties. # # drivers/usb/host/uhci-hcd.h # 2004/03/15 03:59:33-08:00 stern@rowland.harvard.edu +13 -29 # USB: UHCI: Get rid of excessive spinlocks # # drivers/usb/host/uhci-hcd.c # 2004/03/15 06:52:41-08:00 stern@rowland.harvard.edu +25 -127 # USB: UHCI: Get rid of excessive spinlocks # # drivers/usb/host/uhci-debug.c # 2004/03/15 06:12:17-08:00 stern@rowland.harvard.edu +4 -16 # USB: UHCI: Get rid of excessive spinlocks # # ChangeSet # 2004/03/25 17:17:18-08:00 stern@rowland.harvard.edu # [PATCH] USB: UHCI: Improved handling of short control transfers # # This patch simplies the way the UHCI driver handles short control # transfers. When a transfer is short the HC will stop handling that # endpoint, and it's necessary to get it going again so that the status # stage of the control transfer can take place. Currently the driver does # this by allocating a new QH for the transfer and setting its element # pointer to point at the final status TD. The old QH is recycled. But # it's not necessary to go to all that trouble; the element pointer in the # original QH can be updated directly. # # Normally the element pointer is supposed to be owned by the HC, and it's # not safe to just change its value since the HC may overwrite it at any # time. But when a transfer is stopped because of a short packet, the # current TD is marked inactive and the HC will not update the element # pointer. To write an unchanged pointer value back to memory would be a # waste of PCI bus cycles. Now the UHCI spec doesn't say explicitly that an # HC _can't_ do this, but I've tested both Intel and VIA hardware and # neither of them does. # # As a side effect of this change, some of the code for removing QHs can be # eliminated. # # drivers/usb/host/uhci-hcd.c # 2004/03/19 08:30:38-08:00 stern@rowland.harvard.edu +24 -75 # USB: UHCI: Improved handling of short control transfers # # ChangeSet # 2004/03/25 17:16:33-08:00 stern@rowland.harvard.edu # [PATCH] USB: UHCI: Do short packet detection correctly # # This patch makes some simple changes to the way the UHCI driver does short # packet detection. The current implementation is incorrect in several # ways: # # The Short-Packet-Detect flag is set for OUT transfers, which # yields undefined behavior according to the UHCI spec. # # It's not set for URBs with URB_SHORT_NOT_OK, which is just the # opposite of what we want! Those are the ones where short packets # do matter. # # It is set for the last packet in a transfer, which causes an # unnecessary pause in the data flow (except of course that the # pause _is_ necessary when URB_SHORT_NOT_OK is set). # # The patch also implements the URB_NO_INTERRUPT flag for bulk transfers, # which can help improve system performance by reducing interrupt overhead. # # drivers/usb/host/uhci-hcd.c # 2004/03/19 08:30:38-08:00 stern@rowland.harvard.edu +17 -10 # USB: UHCI: Do short packet detection correctly # # ChangeSet # 2004/03/25 17:06:47-08:00 stern@rowland.harvard.edu # [PATCH] USB: Don't trust raw descriptor length in devioc. # # This is a very minor point, unlikely ever to come up. But just in case... # # It's conceivable that a device might transmit different values for a # configuration descriptor's wTotalLength the first time we ask for it (in # order to get the length) and the second time (to get the entire # descriptor). Should that improbable event occur, the rawdescriptor buffer # could be allocated using a size that's smaller than the length recorded in # the rawdescriptor itself. This patch protects devio.c against such a # problem. # # If you feel this sequence of events is too unlikely to worry about, then # don't bother to apply the patch. # # drivers/usb/core/devio.c # 2004/03/19 07:55:45-08:00 stern@rowland.harvard.edu +15 -4 # USB: Don't trust raw descriptor length in devioc. # # ChangeSet # 2004/03/25 16:53:25-08:00 oliver@neukum.org # [PATCH] USB: race condition in open of w9968cf # # there's a race in how open handles multiple openers. # You implement exclusive opening and wait for close # in case of further openers. However if there are more than one # waiter, only one of them must be allowed to proceed. # # drivers/usb/media/w9968cf.c # 2004/03/19 09:08:38-08:00 oliver@neukum.org +6 -4 # USB: race condition in open of w9968cf # # ChangeSet # 2004/03/25 16:52:38-08:00 stern@rowland.harvard.edu # [PATCH] USB: Unusual_devs.h update # # On Thu, 18 Mar 2004, Urban Borstnik wrote: # # > The 2.6.4 and 2.6.3 (and possibly some earlier) kernels log the # > following message when I plug in a Lexar CompactFlash Reader: # > # > usb-storage: This device (05dc,b002,0113 S 06 P 50) has unneeded # > SubClass and Protocol entries in unusual_devs.h # > Please send a copy of this message to # > # > Otherwise it has been working very well with the devepment kernels on at # > least 4 machines ever since a trivial fix was introduced for this device # > to unusual_devs.c over a year ago. # > # > Best regards, # > Urban. # # Thank you for sending this in. An update will appear soon. # # drivers/usb/storage/unusual_devs.h # 2004/03/19 01:32:35-08:00 stern@rowland.harvard.edu +1 -1 # USB: Unusual_devs.h update # # ChangeSet # 2004/03/25 16:41:16-08:00 thoffman@arnor.net # [PATCH] USB: fix race in ati_remote and small cleanup # # On Thu, 2004-03-18 at 07:44, Oliver Neukum wrote: # > Hi, # > # > you must use set_current_state() only after usb_submit_urb() with GFP_KERNEL # > as second argument, because it may sleep to allocate memory and is woken up # > resetting the state to TASK_RUNNING. In that case you had a busy polling loop. # > Furthermore, always use wake_up unconditionally. It checkes anyway. # # Thanks for reviewing this code, I'm new to Linux driver development and # more eyes on my work is a good thing. I've actually been working on # some more cleanups to the driver to fix the race between open and # disconnect, and was just about to send it in... # # So, the attached patch against 2.6.5-rc1-mm1 includes a mutex to lock # the open/disconnect paths, modelled after the usb-skeleton driver. It # includes Oliver Neukum's fixes and other cleanups as well. # # drivers/usb/input/ati_remote.c # 2004/03/18 08:55:38-08:00 thoffman@arnor.net +34 -26 # USB: fix race in ati_remote and small cleanup # # ChangeSet # 2004/03/25 16:20:30-08:00 mikal@stillhq.com # [PATCH] USB: kernel-doc comment tweak in vicam.c # # Correct kernel-doc comment with incorrect parameters documented # # drivers/usb/media/vicam.c # 2004/01/29 22:39:05-08:00 mikal@stillhq.com +2 -0 # USB: kernel-doc comment tweak in vicam.c # # ChangeSet # 2004/03/25 16:15:24-08:00 stern@rowland.harvard.edu # [PATCH] USB: Regularize unusual_devs entries for Genesys Logic # # I saw that you just added another unusual_devs.h entry submitted by # Henning Schild, for vendor ID 0x05e3. It turns out this is our old friend # Genesys Logic. # # A recent message from Brad Campbell included a Windows driver file by # Genesys, and it included these lines: # # USB\VID_05E3&PID_0700.DeviceDesc="USB Card Reader" # USB\VID_05E3&PID_0701.DeviceDesc="USB Optical Device" # USB\VID_05E3&PID_0702.DeviceDesc="USB Mass Storage Device" # # Based on this information, we can clean up the 0x05e3 entries in # unusual_devs.h. This patch puts all three entries into a regularized # form. # # drivers/usb/storage/unusual_devs.h # 2004/03/17 03:59:58-08:00 stern@rowland.harvard.edu +7 -14 # USB: Regularize unusual_devs entries for Genesys Logic # # ChangeSet # 2004/03/25 16:14:29-08:00 stern@rowland.harvard.edu # [PATCH] USB: Unusual_devs update # # On Tue, 16 Mar 2004, John Katzmaier wrote: # # > Hi, # > # > Just wanted to let you know that when using my Panasonic PV-SD4090 digital # > camera with kernel 2.6.3, I found this entry in my logs: # > # > Mar 16 21:43:27 rocket kernel: usb-storage: Vendor: Panasonic # > Mar 16 21:43:27 rocket kernel: usb-storage: Product: LS-120 Camera # > Mar 16 21:43:27 rocket kernel: usb-storage: This device (04da,0901,0109 S 00 P # > 00) has an unneeded Protocol entry in unusual_devs.h # > Mar 16 21:43:27 rocket kernel: Please send a copy of this message to # > # > # > I thought it might be best to follow its instructions and so I did. # > # > Thanks. # > # > -John Katzmaier # # Thank you for sending this in. An update will appear in a forthcoming # kernel. # # Greg, here's the patch. # # drivers/usb/storage/unusual_devs.h # 2004/03/17 03:48:33-08:00 stern@rowland.harvard.edu +1 -1 # USB: Unusual_devs update # # ChangeSet # 2004/03/25 16:06:44-08:00 david-b@pacbell.net # [PATCH] USB: fix osdl bugid 2006 (timer init and fault paths) # # Need to initialize timers a bit earlier to handle # certain initialization faults. # # # OSDL bug 2006 # # Need to initialize some timers a bit earlier to clean up safely # after very early init HCD failures. # # Those early init faults were needlessly mysterious since they # didn't emit diagnostics except at HCD discretion. # # drivers/usb/host/ehci-hcd.c # 2004/02/25 01:04:11-08:00 david-b@pacbell.net +4 -4 # USB: fix osdl bugid 2006 (timer init and fault paths) # # drivers/usb/core/hcd-pci.c # 2004/02/25 00:51:00-08:00 david-b@pacbell.net +4 -1 # USB: fix osdl bugid 2006 (timer init and fault paths) # # ChangeSet # 2004/03/25 15:56:56-08:00 david-b@pacbell.net # [PATCH] USB: fix osdl bugid 481 (USB boot messages) # # Some boot-time messages were obnoxiously long because # they used "old-style" diagnostics. # # # OSDL bugid 481 # # Get rid of most remaining "old style" diagnostics from usbcore. # Most messages use driver model style diagnostics. Messages that # don't have an associated device use the standard kernel printk # wrappers and label themselves as from "usbcore". (Except that # there's no such wrapper for KERN_ERR.) # # This doesn't touch usbfs, "config.c" (Alan's patches do this), or # usb_reset_device() (needs a more substantial overhaul). Or any # other USB drivers (notably HID). # # drivers/usb/core/usb.h # 2004/03/16 03:10:15-08:00 david-b@pacbell.net +3 -0 # USB: fix osdl bugid 481 (USB boot messages) # # drivers/usb/core/usb.c # 2004/03/16 03:27:07-08:00 david-b@pacbell.net +22 -13 # USB: fix osdl bugid 481 (USB boot messages) # # drivers/usb/core/message.c # 2004/03/16 02:46:23-08:00 david-b@pacbell.net +11 -7 # USB: fix osdl bugid 481 (USB boot messages) # # drivers/usb/core/hub.c # 2004/03/16 03:30:17-08:00 david-b@pacbell.net +8 -9 # USB: fix osdl bugid 481 (USB boot messages) # # drivers/usb/core/hcd.c # 2004/03/16 03:06:22-08:00 david-b@pacbell.net +7 -3 # USB: fix osdl bugid 481 (USB boot messages) # # drivers/usb/core/hcd-pci.c # 2004/03/16 03:21:17-08:00 david-b@pacbell.net +10 -7 # USB: fix osdl bugid 481 (USB boot messages) # # ChangeSet # 2004/03/25 15:17:16-08:00 stern@rowland.harvard.edu # [PATCH] USB: Code improvements for core/config.c # # This patch makes some improvements to the code in config.c. # # Create a subroutine to handle the repeated task of skipping # forward to the next descriptor of a certain type. # # Remove some fairly useless debugging messages (they could # never even have been enabled in the pre-as221 code). # # Verify that endpoint descriptors don't have an address # equal to 0 (as well as not being above 15). # # Rename some local variables so they are a little more # consistent and meaningful. # # Despite all the changes, the functionality should remain the same. # Please apply. # # drivers/usb/core/config.c # 2004/03/12 09:19:40-08:00 stern@rowland.harvard.edu +101 -134 # USB: Code improvements for core/config.c # # ChangeSet # 2004/03/25 15:16:15-08:00 stern@rowland.harvard.edu # [PATCH] USB: Improve core/config.c error messages # # This patch improves error reporting in the configuration parsing routines. # It also adds a few extra minor tweaks. # # #include linux/config.h and make the usual DEBUG settings # available. # # Use the driver-model dev_xxx() macros for log output. # # Be much more explicit about the nature of errors, including # configuration, interface, and altsetting numbers where # appropriate. # # Log fatal problems as errors, non-fatal ones as warnings. # # Remove a #define'd constant that is already set in linux/usb.h. # # Fix some variables declared as pointer to char that really # should be pointers to unsigned char. # # Replace a whole bunch of "out-of-memory" error messages with # a single message. # # Wrap source lines that are longer than 80 columns (but not # log output lines!). # # Clean up the logic for detecting errors when retrieving a # configuration descriptor. # # Apart from the log messages themselves, this introduces no functional # changes. # # drivers/usb/core/config.c # 2004/03/12 08:32:08-08:00 stern@rowland.harvard.edu +132 -93 # USB: Improve core/config.c error messages # # ChangeSet # 2004/03/25 13:43:15-08:00 david-b@pacbell.net # [PATCH] USB: USB gadgets can autoconfigure endpoints # # This adds some code that gadget drivers can call from # driver initialization, to simplify the "configure against # this hardware" step. # # # Add endpoint autoconfiguration for gadget drivers. # # Endpoint selection is currently being done with conditional compilation. # That doesn't look nice, but more importantly it doesn't work well with # the model that some distributions won't be custom-matched to hardware. # Say, a PDA distro running on iPaq (pxa2xx_udc) or Axim (mq11xx_udc). # # This code just makes it easier for drivers to match to hardware at # run-time. It's a convenience function for something they could have # been doing already, but weren't. # # include/linux/usb_gadget.h # 2004/03/11 10:34:19-08:00 david-b@pacbell.net +9 -0 # USB: USB gadgets can autoconfigure endpoints # # drivers/usb/gadget/usbstring.c # 2004/03/11 10:34:19-08:00 david-b@pacbell.net +1 -0 # USB: USB gadgets can autoconfigure endpoints # # drivers/usb/gadget/epautoconf.c # 2004/03/11 19:44:59-08:00 david-b@pacbell.net +301 -0 # USB: USB gadgets can autoconfigure endpoints # # drivers/usb/gadget/epautoconf.c # 2004/03/11 19:44:59-08:00 david-b@pacbell.net +0 -0 # BitKeeper file /home/greg/linux/BK/usb-2.6/drivers/usb/gadget/epautoconf.c # # ChangeSet # 2004/03/25 11:53:52-08:00 greg@kroah.com # [PATCH] USB: add cytherm driver to the build # # drivers/usb/misc/Makefile # 2004/03/25 03:51:05-08:00 greg@kroah.com +2 -1 # USB: add cytherm driver to the build # # drivers/usb/Makefile # 2004/03/25 03:51:05-08:00 greg@kroah.com +3 -0 # USB: add cytherm driver to the build # # ChangeSet # 2004/03/25 11:53:27-08:00 erik@rigtorp.com # [PATCH] USB: new cypress thermometer driver # # drivers/usb/misc/Kconfig # 2004/03/14 07:22:41-08:00 erik@rigtorp.com +13 -0 # USB: new cypress thermometer driver # # drivers/usb/misc/cytherm.c # 2004/03/12 17:56:17-08:00 erik@rigtorp.com +433 -0 # USB: new cypress thermometer driver # # drivers/usb/misc/cytherm.c # 2004/03/12 17:56:17-08:00 erik@rigtorp.com +0 -0 # BitKeeper file /home/greg/linux/BK/usb-2.6/drivers/usb/misc/cytherm.c # # ChangeSet # 2004/03/25 11:31:25-08:00 petkan@nucleusys.com # [PATCH] USB: rtl8150 update # # adds two more vid/did and better packet error statistics. Link # detection also has been added. # # drivers/usb/net/rtl8150.c # 2004/03/13 11:13:41-08:00 petkan@nucleusys.com +108 -7 # USB: rtl8150 update # # ChangeSet # 2004/03/25 11:30:58-08:00 david-b@pacbell.net # [PATCH] USB: gadget zero does endpoint autoconfig # # Here's where all those preceding autoconfig patches start # to fit together: one gadget driver gets rid of almost all # the controller-specific #ifdeffery. # # Two of the other gadget drivers can do the same thing, # and just as easily: file storage, and serial. (I'll # hope their maintainers do those changes though.) # # The "ether.c" gadget driver is a lot more complicated to # do this way since it has to cope with some differences # by switching to alternate protocols (CDC Ethernet vs # a subset) and soon be able to handle RNDIS. So that'll # be a while yet. # # # Gadget Zero learns to autoconfigure. # # - Gets rid of remaining controller-specific #ifdeffery. Now # hardware choices can be made at run time too (not just # compile time). # # - Simplifies its use of the "DEBUG" CPP symbol. # # - Force device to report itself consistently as self-powered. # # drivers/usb/gadget/zero.c # 2004/03/12 01:40:05-08:00 david-b@pacbell.net +92 -119 # USB: gadget zero does endpoint autoconfig # # drivers/usb/gadget/Makefile # 2004/03/12 01:43:47-08:00 david-b@pacbell.net +1 -1 # USB: gadget zero does endpoint autoconfig # # ChangeSet # 2004/03/25 11:05:11-08:00 mikal@stillhq.com # [PATCH] USB: kernel-doc comment tweak # # Correct kernel-doc comment with incorrect parameters documented # # drivers/usb/serial/io_ti.c # 2004/01/29 22:39:05-08:00 mikal@stillhq.com +1 -1 # USB: kernel-doc comment tweak # # ChangeSet # 2004/03/25 11:04:37-08:00 mail@gude.info # [PATCH] USB: FTDI 232BM "USB-RS232 OptoBridge" # # we (the german company Gude Analog und Digitalsysteme GmbH, # http://www.gude.info) have manufactored a USB<->RS232 adapter with # galvanic isolated RS232 Interface. Data is transmitted by optical # signals only. # # The Product's name is "USB-RS232 OptoBridge". # We used the FTDI 233BM Chip with PID 0xE889 (VID 0x0403). # The Product will be released this Cebit 2004. # # Could you please extend the ftdi_sio code with this PID. # You find a .diff file attached which I have tested with kernel 2.6.4 # # At http://ftdi-usb-sio.sourceforge.net/ I saw that you provide a patch # for 2.4.x kernels. Will our PID also find it's way in this back-ported # driver patch? # # In the future (in the next 10 month), our company will have some more # Products using the FTDI Chip. The PID's FTDI already allocated for us # are: E888 to E88F and E808 to E80F # # # Thank you very much, # Martin Bachem # # drivers/usb/serial/ftdi_sio.h # 2004/03/17 05:03:33-08:00 mail@gude.info +5 -0 # USB: FTDI 232BM "USB-RS232 OptoBridge" # # drivers/usb/serial/ftdi_sio.c # 2004/03/17 05:04:35-08:00 mail@gude.info +1 -0 # USB: FTDI 232BM "USB-RS232 OptoBridge" # # ChangeSet # 2004/03/20 13:26:55-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # CREDITS # 2004/03/20 13:26:53-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/16 21:53:42-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # drivers/usb/input/wacom.c # 2004/03/16 21:53:39-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/input/hid-core.c # 2004/03/16 21:53:39-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/16 12:59:58-08:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6 # into bix.(none):/usr/src/bk-usb # # include/linux/usb_gadget.h # 2004/03/16 12:59:47-08:00 akpm@bix.(none) +0 -0 # Auto merged # # include/linux/usb.h # 2004/03/16 12:59:47-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/core/usb.c # 2004/03/16 12:59:46-08:00 akpm@bix.(none) +0 -0 # Auto merged # # MAINTAINERS # 2004/03/16 12:59:46-08:00 akpm@bix.(none) +0 -0 # Auto merged # # CREDITS # 2004/03/16 12:59:46-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/16 12:58:57-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # drivers/usb/input/wacom.c # 2004/03/16 12:58:47-08:00 akpm@bix.(none) +0 -4 # Auto merged # # drivers/usb/input/hid-core.c # 2004/03/16 12:58:47-08:00 akpm@bix.(none) +0 -0 # Auto merged # # CREDITS # 2004/03/16 12:58:46-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/14 11:03:00-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # include/linux/usb_gadget.h # 2004/03/14 11:02:47-08:00 akpm@bix.(none) +0 -0 # Auto merged # # include/linux/usb.h # 2004/03/14 11:02:47-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/core/usb.c # 2004/03/14 11:02:47-08:00 akpm@bix.(none) +0 -0 # Auto merged # # MAINTAINERS # 2004/03/14 11:02:47-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/03/12 10:57:17-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # MAINTAINERS # 2004/03/12 10:57:02-08:00 akpm@bix.(none) +0 -0 # Auto merged # # CREDITS # 2004/03/12 10:57:01-08:00 akpm@bix.(none) +0 -0 # Auto merged # diff -Nru a/Documentation/input/ff.txt b/Documentation/input/ff.txt --- a/Documentation/input/ff.txt Tue Apr 6 17:22:26 2004 +++ b/Documentation/input/ff.txt Tue Apr 6 17:22:26 2004 @@ -20,7 +20,7 @@ 2. Instructions to the user ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Here are instructions on how to compile and use the driver. In fact, this -driver is the normal iforce.o, input.o and evdev.o drivers written by Vojtech +driver is the normal iforce, input and evdev drivers written by Vojtech Pavlik, plus additions to support force feedback. Before you start, let me WARN you that some devices shake violently during the diff -Nru a/Documentation/input/input.txt b/Documentation/input/input.txt --- a/Documentation/input/input.txt Tue Apr 6 17:22:26 2004 +++ b/Documentation/input/input.txt Tue Apr 6 17:22:26 2004 @@ -35,18 +35,18 @@ most of the existing input system, which is why it lives in drivers/input/ instead of drivers/usb/. - The centre of the input drivers is the input.o module, which must be + The centre of the input drivers is the input module, which must be loaded before any other of the input modules - it serves as a way of communication between two groups of modules: 1.1 Device drivers ~~~~~~~~~~~~~~~~~~ These modules talk to the hardware (for example via USB), and provide -events (keystrokes, mouse movements) to the input.o module. +events (keystrokes, mouse movements) to the input module. 1.2 Event handlers ~~~~~~~~~~~~~~~~~~ - These modules get events from input.o and pass them where needed via + These modules get events from input and pass them where needed via various interfaces - keystrokes to the kernel, mouse movements via a simulated PS/2 interface to GPM and X and so on. @@ -56,12 +56,12 @@ you'll have to load the following modules (or have them built in to the kernel): - input.o - mousedev.o - keybdev.o - usbcore.o - usb-uhci.o or usb-ohci.o or uhci.o - hid.o + input + mousedev + keybdev + usbcore + uhci_hcd or ohci_hcd or ehci_hcd + usbhid After this, the USB keyboard will work straight away, and the USB mouse will be available as a character device on major 13, minor 63: @@ -98,9 +98,9 @@ however not useful without being handled, so you also will need to use some of the modules from section 3.2. -3.1.1 hid.o -~~~~~~~~~~~ - hid.o is the largest and most complex driver of the whole suite. It +3.1.1 usbhid +~~~~~~~~~~~~ + usbhid is the largest and most complex driver of the whole suite. It handles all HID devices, and because there is a very wide variety of them, and because the USB HID specification isn't simple, it needs to be this big. @@ -115,7 +115,7 @@ the hiddev interface was designed. See Documentation/usb/hiddev.txt for more information about it. - The usage of the hid.o module is very simple, it takes no parameters, + The usage of the usbhid module is very simple, it takes no parameters, detects everything automatically and when a HID device is inserted, it detects it appropriately. @@ -123,30 +123,30 @@ device that doesn't work well. In that case #define DEBUG at the beginning of hid-core.c and send me the syslog traces. -3.1.2 usbmouse.o -~~~~~~~~~~~~~~~~ +3.1.2 usbmouse +~~~~~~~~~~~~~~ For embedded systems, for mice with broken HID descriptors and just any -other use when the big hid.o wouldn't be a good choice, there is the -usbmouse.c driver. It handles USB mice only. It uses a simpler HIDBP +other use when the big usbhid wouldn't be a good choice, there is the +usbmouse driver. It handles USB mice only. It uses a simpler HIDBP protocol. This also means the mice must support this simpler protocol. Not -all do. If you don't have any strong reason to use this module, use hid.o +all do. If you don't have any strong reason to use this module, use usbhid instead. -3.1.3 usbkbd.o -~~~~~~~~~~~~~~ - Much like usbmouse.c, this module talks to keyboards with a simplified +3.1.3 usbkbd +~~~~~~~~~~~~ + Much like usbmouse, this module talks to keyboards with a simplified HIDBP protocol. It's smaller, but doesn't support any extra special keys. -Use hid.o instead if there isn't any special reason to use this. +Use usbhid instead if there isn't any special reason to use this. -3.1.4 wacom.o -~~~~~~~~~~~~~ +3.1.4 wacom +~~~~~~~~~~~ This is a driver for Wacom Graphire and Intuos tablets. Not for Wacom PenPartner, that one is handled by the HID driver. Although the Intuos and Graphire tablets claim that they are HID tablets as well, they are not and thus need this specific driver. -3.1.5 iforce.o -~~~~~~~~~~~~~~~ +3.1.5 iforce +~~~~~~~~~~~~ A driver for I-Force joysticks and wheels, both over USB and RS232. It includes ForceFeedback support now, even though Immersion Corp. considers the protocol a trade secret and won't disclose a word @@ -157,8 +157,8 @@ Event handlers distrubite the events from the devices to userland and kernel, as needed. -3.2.1 keybdev.o -~~~~~~~~~~~~~~~ +3.2.1 keybdev +~~~~~~~~~~~~~ keybdev is currently a rather ugly hack that translates the input events into architecture-specific keyboard raw mode (Xlated AT Set2 on x86), and passes them into the handle_scancode function of the @@ -170,13 +170,13 @@ best if keyboard.c would itself be an event handler. This is done in the input patch, available on the webpage mentioned below. -3.2.2 mousedev.o -~~~~~~~~~~~~~~~~ +3.2.2 mousedev +~~~~~~~~~~~~~~ mousedev is also a hack to make programs that use mouse input work. It takes events from either mice or digitizers/tablets and makes a PS/2-style (a la /dev/psaux) mouse device available to the userland. Ideally, the programs could use a more reasonable interface, -for example evdev.o +for example evdev Mousedev devices in /dev/input (as shown above) are: @@ -207,8 +207,8 @@ these. You'll need ImPS/2 if you want to make use of a wheel on a USB mouse and ExplorerPS/2 if you want to use extra (up to 5) buttons. -3.2.3 joydev.o -~~~~~~~~~~~~~~ +3.2.3 joydev +~~~~~~~~~~~~ Joydev implements v0.x and v1.x Linux joystick api, much like drivers/char/joystick/joystick.c used to in earlier versions. See joystick-api.txt in the Documentation subdirectory for details. As @@ -223,8 +223,8 @@ And so on up to js31. -3.2.4 evdev.o -~~~~~~~~~~~~~ +3.2.4 evdev +~~~~~~~~~~~ evdev is the generic input event interface. It passes the events generated in the kernel straight to the program, with timestamps. The API is still evolving, but should be useable now. It's described in diff -Nru a/Documentation/input/joystick.txt b/Documentation/input/joystick.txt --- a/Documentation/input/joystick.txt Tue Apr 6 17:22:26 2004 +++ b/Documentation/input/joystick.txt Tue Apr 6 17:22:26 2004 @@ -182,7 +182,7 @@ For other joystick types (more/less axes, hats, and buttons) support you'll need to specify the types either on the kernel command line or on the -module command line, when inserting analog.o into the kernel. The +module command line, when inserting analog into the kernel. The parameters are: analog.map=,,,.... @@ -503,7 +503,7 @@ 3.21 I-Force devices ~~~~~~~~~~~~~~~~~~~~ - All I-Force devices are supported by the iforce.o module. This includes: + All I-Force devices are supported by the iforce module. This includes: * AVB Mag Turbo Force * AVB Top Shot Pegasus diff -Nru a/Documentation/usb/linux.inf b/Documentation/usb/linux.inf --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/usb/linux.inf Tue Apr 6 17:22:26 2004 @@ -0,0 +1,200 @@ +; MS-Windows driver config matching some basic modes of the +; Linux-USB Ethernet/RNDIS gadget firmware: +; +; - RNDIS plus CDC Ethernet ... this may be familiar as a DOCSIS +; cable modem profile, and supports most non-Microsoft USB hosts +; +; - RNDIS plus CDC Subset ... used by hardware that incapable of +; full CDC Ethernet support. +; +; Microsoft only directly supports RNDIS drivers, and bundled them into XP. +; The Microsoft "Remote NDIS USB Driver Kit" is currently found at: +; http://www.microsoft.com/whdc/hwdev/resources/HWservices/rndis.mspx + + +[Version] +Signature = "$CHICAGO$" +Class = Net +ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} +Provider = %Linux% +Compatible = 1 +MillenniumPreferred = .ME +DriverVer = 03/30/2004,0.0.0.0 +; catalog file would be used by WHQL +;CatalogFile = Linux.cat + +[Manufacturer] +%Linux% = LinuxDevices,NT.5.1 + +[LinuxDevices] +; NetChip IDs, used by both firmware modes +%LinuxDevice% = RNDIS, USB\VID_0525&PID_a4a2 + +[LinuxDevices.NT.5.1] +%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a1 + +[ControlFlags] +ExcludeFromSelect=* + +; Windows 98, Windows 98 Second Edition specific sections -------- + +[RNDIS] +DeviceID = usb8023 +MaxInstance = 512 +DriverVer = 03/30/2004,0.0.0.0 +AddReg = RNDIS_AddReg_98, RNDIS_AddReg_Common + +[RNDIS_AddReg_98] +HKR, , DevLoader, 0, *ndis +HKR, , DeviceVxDs, 0, usb8023.sys +HKR, NDIS, LogDriverName, 0, "usb8023" +HKR, NDIS, MajorNdisVersion, 1, 5 +HKR, NDIS, MinorNdisVersion, 1, 0 +HKR, Ndi\Interfaces, DefUpper, 0, "ndis3,ndis4,ndis5" +HKR, Ndi\Interfaces, DefLower, 0, "ethernet" +HKR, Ndi\Interfaces, UpperRange, 0, "ndis3,ndis4,ndis5" +HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" +HKR, Ndi\Install, ndis3, 0, "RNDIS_Install_98" +HKR, Ndi\Install, ndis4, 0, "RNDIS_Install_98" +HKR, Ndi\Install, ndis5, 0, "RNDIS_Install_98" +HKR, Ndi, DeviceId, 0, "USB\VID_0525&PID_a4a1" + +[RNDIS_Install_98] +CopyFiles=RNDIS_CopyFiles_98 + +[RNDIS_CopyFiles_98] +usb8023.sys, usb8023w.sys, , 0 +rndismp.sys, rndismpw.sys, , 0 + +; Windows Millennium Edition specific sections -------------------- + +[RNDIS.ME] +DeviceID = usb8023 +MaxInstance = 512 +DriverVer = 03/30/2004,0.0.0.0 +AddReg = RNDIS_AddReg_ME, RNDIS_AddReg_Common +Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI +BusType = 15 + +[RNDIS_AddReg_ME] +HKR, , DevLoader, 0, *ndis +HKR, , DeviceVxDs, 0, usb8023.sys +HKR, NDIS, LogDriverName, 0, "usb8023" +HKR, NDIS, MajorNdisVersion, 1, 5 +HKR, NDIS, MinorNdisVersion, 1, 0 +HKR, Ndi\Interfaces, DefUpper, 0, "ndis3,ndis4,ndis5" +HKR, Ndi\Interfaces, DefLower, 0, "ethernet" +HKR, Ndi\Interfaces, UpperRange, 0, "ndis3,ndis4,ndis5" +HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" +HKR, Ndi\Install, ndis3, 0, "RNDIS_Install_ME" +HKR, Ndi\Install, ndis4, 0, "RNDIS_Install_ME" +HKR, Ndi\Install, ndis5, 0, "RNDIS_Install_ME" +HKR, Ndi, DeviceId, 0, "USB\VID_0525&PID_a4a1" + +[RNDIS_Install_ME] +CopyFiles=RNDIS_CopyFiles_ME + +[RNDIS_CopyFiles_ME] +usb8023.sys, usb8023m.sys, , 0 +rndismp.sys, rndismpm.sys, , 0 + +; Windows 2000 specific sections --------------------------------- + +[RNDIS.NT] +Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI +BusType = 15 +DriverVer = 03/30/2004,0.0.0.0 +AddReg = RNDIS_AddReg_NT, RNDIS_AddReg_Common +CopyFiles = RNDIS_CopyFiles_NT + +[RNDIS.NT.Services] +AddService = USB_RNDIS, 2, RNDIS_ServiceInst_NT, RNDIS_EventLog + +[RNDIS_CopyFiles_NT] +; no rename of files on Windows 2000, use the 'k' names as is +usb8023k.sys, , , 0 +rndismpk.sys, , , 0 + +[RNDIS_ServiceInst_NT] +DisplayName = %ServiceDisplayName% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\usb8023k.sys +LoadOrderGroup = NDIS +AddReg = RNDIS_WMI_AddReg_NT + +[RNDIS_WMI_AddReg_NT] +HKR, , MofImagePath, 0x00020000, "System32\drivers\rndismpk.sys" + +; Windows XP specific sections ----------------------------------- + +[RNDIS.NT.5.1] +Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI +BusType = 15 +DriverVer = 03/30/2004,0.0.0.0 +AddReg = RNDIS_AddReg_NT, RNDIS_AddReg_Common +; no copyfiles - the files are already in place + +[RNDIS.NT.5.1.Services] +AddService = USB_RNDIS, 2, RNDIS_ServiceInst_51, RNDIS_EventLog + +[RNDIS_ServiceInst_51] +DisplayName = %ServiceDisplayName% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\usb8023.sys +LoadOrderGroup = NDIS +AddReg = RNDIS_WMI_AddReg_51 + +[RNDIS_WMI_AddReg_51] +HKR, , MofImagePath, 0x00020000, "System32\drivers\rndismp.sys" + +; Windows 2000 and Windows XP common sections -------------------- + +[RNDIS_AddReg_NT] +HKR, Ndi, Service, 0, "USB_RNDIS" +HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" +HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" + +[RNDIS_EventLog] +AddReg = RNDIS_EventLog_AddReg + +[RNDIS_EventLog_AddReg] +HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\netevent.dll" +HKR, , TypesSupported, 0x00010001, 7 + +; Common Sections ------------------------------------------------- + +[RNDIS_AddReg_Common] +HKR, NDI\params\NetworkAddress, ParamDesc, 0, %NetworkAddress% +HKR, NDI\params\NetworkAddress, type, 0, "edit" +HKR, NDI\params\NetworkAddress, LimitText, 0, "12" +HKR, NDI\params\NetworkAddress, UpperCase, 0, "1" +HKR, NDI\params\NetworkAddress, default, 0, " " +HKR, NDI\params\NetworkAddress, optional, 0, "1" + +[SourceDisksNames] +1=%SourceDisk%,,1 + +[SourceDisksFiles] +usb8023m.sys=1 +rndismpm.sys=1 +usb8023w.sys=1 +rndismpw.sys=1 +usb8023k.sys=1 +rndismpk.sys=1 + +[DestinationDirs] +RNDIS_CopyFiles_98 = 10, system32/drivers +RNDIS_CopyFiles_ME = 10, system32/drivers +RNDIS_CopyFiles_NT = 12 + +[Strings] +ServiceDisplayName = "USB Remote NDIS Network Device Driver" +NetworkAddress = "Network Address" +Linux = "Linux Developer Community" +LinuxDevice = "Linux USB Ethernet/RNDIS Gadget" +SourceDisk = "Ethernet/RNDIS Gadget Driver Install Disk" + diff -Nru a/arch/arm/configs/neponset_defconfig b/arch/arm/configs/neponset_defconfig --- a/arch/arm/configs/neponset_defconfig Tue Apr 6 17:22:26 2004 +++ b/arch/arm/configs/neponset_defconfig Tue Apr 6 17:22:26 2004 @@ -848,7 +848,6 @@ # CONFIG_USB_TIGL is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set -# CONFIG_USB_BRLVGER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_TEST is not set diff -Nru a/arch/ia64/configs/generic_defconfig b/arch/ia64/configs/generic_defconfig --- a/arch/ia64/configs/generic_defconfig Tue Apr 6 17:22:26 2004 +++ b/arch/ia64/configs/generic_defconfig Tue Apr 6 17:22:26 2004 @@ -976,7 +976,6 @@ # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set -# CONFIG_USB_BRLVGER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_TEST is not set # CONFIG_USB_GADGET is not set diff -Nru a/arch/ia64/configs/zx1_defconfig b/arch/ia64/configs/zx1_defconfig --- a/arch/ia64/configs/zx1_defconfig Tue Apr 6 17:22:26 2004 +++ b/arch/ia64/configs/zx1_defconfig Tue Apr 6 17:22:26 2004 @@ -1028,7 +1028,6 @@ # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set -# CONFIG_USB_BRLVGER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_LED is not set diff -Nru a/arch/ia64/defconfig b/arch/ia64/defconfig --- a/arch/ia64/defconfig Tue Apr 6 17:22:26 2004 +++ b/arch/ia64/defconfig Tue Apr 6 17:22:26 2004 @@ -906,7 +906,6 @@ # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set -# CONFIG_USB_BRLVGER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_LED is not set # CONFIG_USB_TEST is not set diff -Nru a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig --- a/arch/mips/configs/rm200_defconfig Tue Apr 6 17:22:26 2004 +++ b/arch/mips/configs/rm200_defconfig Tue Apr 6 17:22:26 2004 @@ -986,7 +986,6 @@ CONFIG_USB_AUERSWALD=m CONFIG_USB_RIO500=m CONFIG_USB_LEGOTOWER=m -CONFIG_USB_BRLVGER=m CONFIG_USB_LCD=m # CONFIG_USB_LED is not set CONFIG_USB_TEST=m diff -Nru a/arch/parisc/configs/c3000_defconfig b/arch/parisc/configs/c3000_defconfig --- a/arch/parisc/configs/c3000_defconfig Tue Apr 6 17:22:26 2004 +++ b/arch/parisc/configs/c3000_defconfig Tue Apr 6 17:22:26 2004 @@ -876,7 +876,6 @@ # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set CONFIG_USB_LEGOTOWER=m -# CONFIG_USB_BRLVGER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_LED is not set # CONFIG_USB_TEST is not set diff -Nru a/arch/parisc/defconfig b/arch/parisc/defconfig --- a/arch/parisc/defconfig Tue Apr 6 17:22:26 2004 +++ b/arch/parisc/defconfig Tue Apr 6 17:22:26 2004 @@ -737,7 +737,6 @@ # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set -# CONFIG_USB_BRLVGER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_LED is not set diff -Nru a/arch/ppc/configs/adir_defconfig b/arch/ppc/configs/adir_defconfig --- a/arch/ppc/configs/adir_defconfig Tue Apr 6 17:22:26 2004 +++ b/arch/ppc/configs/adir_defconfig Tue Apr 6 17:22:26 2004 @@ -776,7 +776,6 @@ # CONFIG_USB_TIGL is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set -# CONFIG_USB_BRLVGER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_TEST is not set # CONFIG_USB_GADGET is not set diff -Nru a/arch/ppc/configs/common_defconfig b/arch/ppc/configs/common_defconfig --- a/arch/ppc/configs/common_defconfig Tue Apr 6 17:22:26 2004 +++ b/arch/ppc/configs/common_defconfig Tue Apr 6 17:22:26 2004 @@ -1209,7 +1209,6 @@ # CONFIG_USB_TIGL is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set -# CONFIG_USB_BRLVGER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_TEST is not set # CONFIG_USB_GADGET is not set diff -Nru a/arch/ppc/configs/lopec_defconfig b/arch/ppc/configs/lopec_defconfig --- a/arch/ppc/configs/lopec_defconfig Tue Apr 6 17:22:26 2004 +++ b/arch/ppc/configs/lopec_defconfig Tue Apr 6 17:22:26 2004 @@ -788,7 +788,6 @@ # CONFIG_USB_TIGL is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set -# CONFIG_USB_BRLVGER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_TEST is not set # CONFIG_USB_GADGET is not set diff -Nru a/arch/ppc/configs/pmac_defconfig b/arch/ppc/configs/pmac_defconfig --- a/arch/ppc/configs/pmac_defconfig Tue Apr 6 17:22:26 2004 +++ b/arch/ppc/configs/pmac_defconfig Tue Apr 6 17:22:26 2004 @@ -1249,7 +1249,6 @@ # CONFIG_USB_TIGL is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set -# CONFIG_USB_BRLVGER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_TEST is not set # CONFIG_USB_GADGET is not set diff -Nru a/arch/ppc/configs/sandpoint_defconfig b/arch/ppc/configs/sandpoint_defconfig --- a/arch/ppc/configs/sandpoint_defconfig Tue Apr 6 17:22:26 2004 +++ b/arch/ppc/configs/sandpoint_defconfig Tue Apr 6 17:22:26 2004 @@ -775,7 +775,6 @@ # CONFIG_USB_TIGL is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set -# CONFIG_USB_BRLVGER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_TEST is not set # CONFIG_USB_GADGET is not set diff -Nru a/arch/ppc/defconfig b/arch/ppc/defconfig --- a/arch/ppc/defconfig Tue Apr 6 17:22:26 2004 +++ b/arch/ppc/defconfig Tue Apr 6 17:22:26 2004 @@ -1208,7 +1208,6 @@ # CONFIG_USB_TIGL is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set -# CONFIG_USB_BRLVGER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_TEST is not set # CONFIG_USB_GADGET is not set diff -Nru a/arch/ppc64/configs/pSeries_defconfig b/arch/ppc64/configs/pSeries_defconfig --- a/arch/ppc64/configs/pSeries_defconfig Tue Apr 6 17:22:26 2004 +++ b/arch/ppc64/configs/pSeries_defconfig Tue Apr 6 17:22:26 2004 @@ -880,7 +880,6 @@ # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set -# CONFIG_USB_BRLVGER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_LED is not set # CONFIG_USB_TEST is not set diff -Nru a/arch/ppc64/defconfig b/arch/ppc64/defconfig --- a/arch/ppc64/defconfig Tue Apr 6 17:22:26 2004 +++ b/arch/ppc64/defconfig Tue Apr 6 17:22:26 2004 @@ -880,7 +880,6 @@ # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set -# CONFIG_USB_BRLVGER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_LED is not set # CONFIG_USB_TEST is not set diff -Nru a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c --- a/drivers/isdn/hisax/hfc_usb.c Tue Apr 6 17:22:26 2004 +++ b/drivers/isdn/hisax/hfc_usb.c Tue Apr 6 17:22:26 2004 @@ -262,7 +262,7 @@ hfc->ctrl_urb->transfer_buffer_length = 0; hfc->ctrl_write.wIndex = hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg; hfc->ctrl_write.wValue = hfc->ctrl_buff[hfc->ctrl_out_idx].reg_val; - err = usb_submit_urb(hfc->ctrl_urb, GFP_KERNEL); /* start transfer */ + err = usb_submit_urb(hfc->ctrl_urb, GFP_ATOMIC); /* start transfer */ printk(KERN_DEBUG "ctrl_start_transfer: submit %d\n", err); } } /* ctrl_start_transfer */ @@ -754,7 +754,7 @@ } } - errcode = usb_submit_urb(urb, GFP_KERNEL); + errcode = usb_submit_urb(urb, GFP_ATOMIC); if(errcode < 0) { printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i \n", errcode); @@ -821,7 +821,7 @@ fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,context_iso_urb->buffer, num_isoc_packets, fifo->usb_packet_maxlen, fifo->intervall, rx_iso_complete, urb->context); - errcode = usb_submit_urb(urb, GFP_KERNEL); + errcode = usb_submit_urb(urb, GFP_ATOMIC); if(errcode < 0) { printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i \n", errcode); @@ -1345,7 +1345,7 @@ /*************************************************/ /* function called to probe a new plugged device */ /*************************************************/ -static int __devinit hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) +static int hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev= interface_to_usbdev(intf); hfcusb_data *context; diff -Nru a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c --- a/drivers/isdn/hisax/st5481_b.c Tue Apr 6 17:22:26 2004 +++ b/drivers/isdn/hisax/st5481_b.c Tue Apr 6 17:22:26 2004 @@ -119,7 +119,7 @@ DBG_ISO_PACKET(0x200,urb); - SUBMIT_URB(urb, GFP_KERNEL); + SUBMIT_URB(urb, GFP_NOIO); } /* @@ -171,8 +171,8 @@ buf_nr = get_buf_nr(b_out->urb, urb); test_and_clear_bit(buf_nr, &b_out->busy); - if (urb->status < 0) { - if (urb->status != -ENOENT) { + if (unlikely(urb->status < 0)) { + if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) { WARN("urb status %d",urb->status); if (b_out->busy == 0) { st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2 | USB_DIR_OUT, NULL, NULL); diff -Nru a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c --- a/drivers/isdn/hisax/st5481_d.c Tue Apr 6 17:22:26 2004 +++ b/drivers/isdn/hisax/st5481_d.c Tue Apr 6 17:22:26 2004 @@ -381,8 +381,8 @@ buf_nr = get_buf_nr(d_out->urb, urb); test_and_clear_bit(buf_nr, &d_out->busy); - if (urb->status < 0) { - if (urb->status != -ENOENT) { + if (unlikely(urb->status < 0)) { + if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) { WARN("urb status %d",urb->status); if (d_out->busy == 0) { st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, fifo_reseted, adapter); @@ -649,7 +649,7 @@ st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL); } -static int __devinit st5481_setup_d_out(struct st5481_adapter *adapter) +static int st5481_setup_d_out(struct st5481_adapter *adapter) { struct usb_device *dev = adapter->usb_dev; struct usb_host_interface *altsetting; @@ -682,7 +682,7 @@ st5481_release_isocpipes(d_out->urb); } -int __devinit st5481_setup_d(struct st5481_adapter *adapter) +int st5481_setup_d(struct st5481_adapter *adapter) { int retval; diff -Nru a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c --- a/drivers/isdn/hisax/st5481_init.c Tue Apr 6 17:22:26 2004 +++ b/drivers/isdn/hisax/st5481_init.c Tue Apr 6 17:22:26 2004 @@ -58,8 +58,8 @@ * This function will be called when the adapter is plugged * into the USB bus. */ -static int __devinit probe_st5481(struct usb_interface *intf, - const struct usb_device_id *id) +static int probe_st5481(struct usb_interface *intf, + const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); struct st5481_adapter *adapter; diff -Nru a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c --- a/drivers/isdn/hisax/st5481_usb.c Tue Apr 6 17:22:26 2004 +++ b/drivers/isdn/hisax/st5481_usb.c Tue Apr 6 17:22:26 2004 @@ -48,7 +48,7 @@ // Prepare the URB urb->dev = adapter->usb_dev; - SUBMIT_URB(urb, GFP_KERNEL); + SUBMIT_URB(urb, GFP_ATOMIC); } /* @@ -129,8 +129,8 @@ struct st5481_ctrl *ctrl = &adapter->ctrl; struct ctrl_msg *ctrl_msg; - if (urb->status < 0) { - if (urb->status != -ENOENT) { + if (unlikely(urb->status < 0)) { + if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) { WARN("urb status %d",urb->status); } else { DBG(1,"urb killed"); @@ -239,7 +239,7 @@ * initialization */ -int __devinit st5481_setup_usb(struct st5481_adapter *adapter) +int st5481_setup_usb(struct st5481_adapter *adapter) { struct usb_device *dev = adapter->usb_dev; struct st5481_ctrl *ctrl = &adapter->ctrl; @@ -341,7 +341,7 @@ /* * Initialize the adapter. */ -void __devinit st5481_start(struct st5481_adapter *adapter) +void st5481_start(struct st5481_adapter *adapter) { static const u8 init_cmd_table[]={ SET_DEFAULT,0, @@ -381,7 +381,7 @@ /* * Reset the adapter to default values. */ -void __devexit st5481_stop(struct st5481_adapter *adapter) +void st5481_stop(struct st5481_adapter *adapter) { DBG(8,""); @@ -392,7 +392,7 @@ * isochronous USB helpers */ -static void __devinit +static void fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void *buf, int num_packets, int packet_size, usb_complete_t complete, @@ -417,7 +417,7 @@ } } -int __devinit +int st5481_setup_isocpipes(struct urb* urb[2], struct usb_device *dev, unsigned int pipe, int num_packets, int packet_size, int buf_size, @@ -481,8 +481,8 @@ struct sk_buff *skb; int len, count, status; - if (urb->status < 0) { - if (urb->status != -ENOENT) { + if (unlikely(urb->status < 0)) { + if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) { WARN("urb status %d",urb->status); } else { DBG(1,"urb killed"); @@ -529,10 +529,10 @@ urb->dev = in->adapter->usb_dev; urb->actual_length = 0; - SUBMIT_URB(urb, GFP_KERNEL); + SUBMIT_URB(urb, GFP_ATOMIC); } -int __devinit st5481_setup_in(struct st5481_in *in) +int st5481_setup_in(struct st5481_in *in) { struct usb_device *dev = in->adapter->usb_dev; int retval; diff -Nru a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c Tue Apr 6 17:22:26 2004 +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c Tue Apr 6 17:22:26 2004 @@ -1008,7 +1008,7 @@ static int ttusb_setup_interfaces(struct ttusb *ttusb) { - usb_set_configuration(ttusb->dev, 1); + usb_reset_configuration(ttusb->dev); usb_set_interface(ttusb->dev, 1, 1); ttusb->bulk_out_pipe = usb_sndbulkpipe(ttusb->dev, 1); @@ -1076,6 +1076,17 @@ dprintk("%s: TTUSB DVB connected\n", __FUNCTION__); udev = interface_to_usbdev(intf); + + /* Device has already been reset; its configuration was chosen. + * If this fault happens, use a hotplug script to choose the + * right configuration (write bConfigurationValue in sysfs). + */ + if (udev->actconfig->desc.bConfigurationValue != 1) { + dev_err(&intf->dev, "device config is #%d, need #1\n", + udev->actconfig->desc.bConfigurationValue); + return -ENODEV; + } + if (!(ttusb = kmalloc(sizeof(struct ttusb), GFP_KERNEL))) return -ENOMEM; diff -Nru a/drivers/usb/Makefile b/drivers/usb/Makefile --- a/drivers/usb/Makefile Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/Makefile Tue Apr 6 17:22:26 2004 @@ -55,8 +55,11 @@ obj-$(CONFIG_USB_SERIAL) += serial/ obj-$(CONFIG_USB_AUERSWALD) += misc/ +obj-$(CONFIG_USB_CYTHERM) += misc/ obj-$(CONFIG_USB_EMI26) += misc/ +obj-$(CONFIG_USB_EMI62) += misc/ obj-$(CONFIG_USB_LCD) += misc/ +obj-$(CONFIG_USB_LED) += misc/ obj-$(CONFIG_USB_LEGOTOWER) += misc/ obj-$(CONFIG_USB_RIO500) += misc/ obj-$(CONFIG_USB_SPEEDTOUCH) += misc/ diff -Nru a/drivers/usb/core/config.c b/drivers/usb/core/config.c --- a/drivers/usb/core/config.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/core/config.c Tue Apr 6 17:22:26 2004 @@ -1,28 +1,62 @@ +#include + +#ifdef CONFIG_USB_DEBUG +#define DEBUG +#endif + #include #include #include #include +#include #include #define USB_MAXALTSETTING 128 /* Hard limit */ #define USB_MAXENDPOINTS 30 /* Hard limit */ -/* these maximums are arbitrary */ -#define USB_MAXCONFIG 8 -#define USB_MAXINTERFACES 32 +#define USB_MAXCONFIG 8 /* Arbitrary limit */ + -static int usb_parse_endpoint(struct usb_host_endpoint *endpoint, unsigned char *buffer, int size) +static int find_next_descriptor(unsigned char *buffer, int size, + int dt1, int dt2, int *num_skipped) +{ + struct usb_descriptor_header *h; + int n = 0; + unsigned char *buffer0 = buffer; + + /* Find the next descriptor of type dt1 or dt2 */ + while (size >= sizeof(struct usb_descriptor_header)) { + h = (struct usb_descriptor_header *) buffer; + if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2) + break; + buffer += h->bLength; + size -= h->bLength; + ++n; + } + + /* Store the number of descriptors skipped and return the + * number of bytes skipped */ + if (num_skipped) + *num_skipped = n; + return buffer - buffer0; +} + +static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, + int asnum, struct usb_host_endpoint *endpoint, + unsigned char *buffer, int size) { unsigned char *buffer0 = buffer; struct usb_descriptor_header *header; - unsigned char *begin; - int numskipped; + int n, i; header = (struct usb_descriptor_header *)buffer; if (header->bDescriptorType != USB_DT_ENDPOINT) { - warn("unexpected descriptor 0x%X, expecting endpoint, 0x%X", - header->bDescriptorType, USB_DT_ENDPOINT); + dev_err(ddev, "config %d interface %d altsetting %d has an " + "unexpected descriptor of type 0x%X, " + "expecting endpoint type 0x%X\n", + cfgno, inum, asnum, + header->bDescriptorType, USB_DT_ENDPOINT); return -EINVAL; } @@ -31,13 +65,17 @@ else if (header->bLength >= USB_DT_ENDPOINT_SIZE) memcpy(&endpoint->desc, buffer, USB_DT_ENDPOINT_SIZE); else { - warn("invalid endpoint descriptor"); + dev_err(ddev, "config %d interface %d altsetting %d has an " + "invalid endpoint descriptor of length %d\n", + cfgno, inum, asnum, header->bLength); return -EINVAL; } - if ((endpoint->desc.bEndpointAddress & ~USB_ENDPOINT_DIR_MASK) >= 16) { - warn("invalid endpoint address 0x%X", - endpoint->desc.bEndpointAddress); + i = endpoint->desc.bEndpointAddress & ~USB_ENDPOINT_DIR_MASK; + if (i >= 16 || i == 0) { + dev_err(ddev, "config %d interface %d altsetting %d has an " + "invalid endpoint with address 0x%X\n", + cfgno, inum, asnum, endpoint->desc.bEndpointAddress); return -EINVAL; } @@ -46,30 +84,16 @@ buffer += header->bLength; size -= header->bLength; - /* Skip over any Class Specific or Vendor Specific descriptors */ - begin = buffer; - numskipped = 0; - while (size >= sizeof(struct usb_descriptor_header)) { - header = (struct usb_descriptor_header *)buffer; - - /* If we find another "proper" descriptor then we're done */ - if ((header->bDescriptorType == USB_DT_ENDPOINT) || - (header->bDescriptorType == USB_DT_INTERFACE)) - break; - - dbg("skipping descriptor 0x%X", header->bDescriptorType); - numskipped++; - - buffer += header->bLength; - size -= header->bLength; - } - if (numskipped) { - dbg("skipped %d class/vendor specific endpoint descriptors", numskipped); - endpoint->extra = begin; - endpoint->extralen = buffer - begin; - } - - return buffer - buffer0; + /* Skip over any Class Specific or Vendor Specific descriptors; + * find the next endpoint or interface descriptor */ + endpoint->extra = buffer; + i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, + USB_DT_INTERFACE, &n); + endpoint->extralen = i; + if (n > 0) + dev_dbg(ddev, "skipped %d class/vendor specific endpoint " + "descriptors\n", n); + return buffer - buffer0 + i; } static void usb_free_intf(struct usb_interface *intf) @@ -78,253 +102,235 @@ if (intf->altsetting) { for (j = 0; j < intf->num_altsetting; j++) { - struct usb_host_interface *as = &intf->altsetting[j]; + struct usb_host_interface *alt = &intf->altsetting[j]; - kfree(as->endpoint); + kfree(alt->endpoint); } kfree(intf->altsetting); } kfree(intf); } -static int usb_parse_interface(struct usb_host_config *config, unsigned char *buffer, int size) +static int usb_parse_interface(struct device *ddev, int cfgno, + struct usb_host_config *config, unsigned char *buffer, int size) { unsigned char *buffer0 = buffer; struct usb_interface_descriptor *d; int inum, asnum; struct usb_interface *interface; - struct usb_host_interface *ifp; - int len, numskipped; - struct usb_descriptor_header *header; - unsigned char *begin; - int i, retval; + struct usb_host_interface *alt; + int i, n; + int len, retval; d = (struct usb_interface_descriptor *) buffer; + buffer += d->bLength; + size -= d->bLength; + if (d->bDescriptorType != USB_DT_INTERFACE) { - warn("unexpected descriptor 0x%X, expecting interface, 0x%X", - d->bDescriptorType, USB_DT_INTERFACE); + dev_err(ddev, "config %d has an unexpected descriptor of type " + "0x%X, expecting interface type 0x%X\n", + cfgno, d->bDescriptorType, USB_DT_INTERFACE); return -EINVAL; } inum = d->bInterfaceNumber; - if (inum >= config->desc.bNumInterfaces) { - - /* Skip to the next interface descriptor */ - buffer += d->bLength; - size -= d->bLength; - while (size >= sizeof(struct usb_descriptor_header)) { - header = (struct usb_descriptor_header *) buffer; - - if (header->bDescriptorType == USB_DT_INTERFACE) - break; - buffer += header->bLength; - size -= header->bLength; - } - return buffer - buffer0; - } + if (inum >= config->desc.bNumInterfaces) + goto skip_to_next_interface_descriptor; interface = config->interface[inum]; asnum = d->bAlternateSetting; if (asnum >= interface->num_altsetting) { - warn("invalid alternate setting %d for interface %d", - asnum, inum); + dev_err(ddev, "config %d interface %d has an invalid " + "alternate setting number: %d but max is %d\n", + cfgno, inum, asnum, interface->num_altsetting - 1); return -EINVAL; } - ifp = &interface->altsetting[asnum]; - if (ifp->desc.bLength) { - warn("duplicate descriptor for interface %d altsetting %d", - inum, asnum); + alt = &interface->altsetting[asnum]; + if (alt->desc.bLength) { + dev_err(ddev, "Duplicate descriptor for config %d " + "interface %d altsetting %d\n", cfgno, inum, asnum); return -EINVAL; } - memcpy(&ifp->desc, buffer, USB_DT_INTERFACE_SIZE); - - buffer += d->bLength; - size -= d->bLength; - - /* Skip over any Class Specific or Vendor Specific descriptors */ - begin = buffer; - numskipped = 0; - while (size >= sizeof(struct usb_descriptor_header)) { - header = (struct usb_descriptor_header *)buffer; - - /* If we find another "proper" descriptor then we're done */ - if ((header->bDescriptorType == USB_DT_INTERFACE) || - (header->bDescriptorType == USB_DT_ENDPOINT)) - break; - - dbg("skipping descriptor 0x%X", header->bDescriptorType); - numskipped++; - - buffer += header->bLength; - size -= header->bLength; - } - if (numskipped) { - dbg("skipped %d class/vendor specific interface descriptors", numskipped); - ifp->extra = begin; - ifp->extralen = buffer - begin; - } + memcpy(&alt->desc, d, USB_DT_INTERFACE_SIZE); - if (ifp->desc.bNumEndpoints > USB_MAXENDPOINTS) { - warn("too many endpoints for interface %d altsetting %d", - inum, asnum); + /* Skip over any Class Specific or Vendor Specific descriptors; + * find the first endpoint or interface descriptor */ + alt->extra = buffer; + i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, + USB_DT_INTERFACE, &n); + alt->extralen = i; + if (n > 0) + dev_dbg(ddev, "skipped %d class/vendor specific " + "interface descriptors\n", n); + buffer += i; + size -= i; + + if (alt->desc.bNumEndpoints > USB_MAXENDPOINTS) { + dev_err(ddev, "too many endpoints for config %d interface %d " + "altsetting %d: %d, maximum allowed: %d\n", + cfgno, inum, asnum, alt->desc.bNumEndpoints, + USB_MAXENDPOINTS); return -EINVAL; } - len = ifp->desc.bNumEndpoints * sizeof(struct usb_host_endpoint); - ifp->endpoint = kmalloc(len, GFP_KERNEL); - if (!ifp->endpoint) { - err("out of memory"); + len = alt->desc.bNumEndpoints * sizeof(struct usb_host_endpoint); + alt->endpoint = kmalloc(len, GFP_KERNEL); + if (!alt->endpoint) return -ENOMEM; - } - memset(ifp->endpoint, 0, len); + memset(alt->endpoint, 0, len); - for (i = 0; i < ifp->desc.bNumEndpoints; i++) { + for (i = 0; i < alt->desc.bNumEndpoints; i++) { if (size < USB_DT_ENDPOINT_SIZE) { - warn("ran out of descriptors while parsing endpoints"); + dev_err(ddev, "too few endpoint descriptors for " + "config %d interface %d altsetting %d\n", + cfgno, inum, asnum); return -EINVAL; } - retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size); + retval = usb_parse_endpoint(ddev, cfgno, inum, asnum, + alt->endpoint + i, buffer, size); if (retval < 0) return retval; buffer += retval; size -= retval; } - return buffer - buffer0; + +skip_to_next_interface_descriptor: + i = find_next_descriptor(buffer, size, USB_DT_INTERFACE, + USB_DT_INTERFACE, NULL); + return buffer - buffer0 + i; } -int usb_parse_configuration(struct usb_host_config *config, char *buffer, int size) +int usb_parse_configuration(struct device *ddev, int cfgidx, + struct usb_host_config *config, unsigned char *buffer, int size) { + int cfgno; int nintf, nintf_orig; - int i, j; + int i, j, n; struct usb_interface *interface; - char *buffer2; + unsigned char *buffer2; int size2; struct usb_descriptor_header *header; - int numskipped, len; - char *begin; - int retval; + int len, retval; memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); if (config->desc.bDescriptorType != USB_DT_CONFIG || config->desc.bLength < USB_DT_CONFIG_SIZE) { - warn("invalid configuration descriptor"); + dev_err(ddev, "invalid descriptor for config index %d: " + "type = 0x%X, length = %d\n", cfgidx, + config->desc.bDescriptorType, config->desc.bLength); return -EINVAL; } config->desc.wTotalLength = size; + cfgno = config->desc.bConfigurationValue; + + buffer += config->desc.bLength; + size -= config->desc.bLength; nintf = nintf_orig = config->desc.bNumInterfaces; if (nintf > USB_MAXINTERFACES) { - warn("too many interfaces (%d max %d)", - nintf, USB_MAXINTERFACES); + dev_warn(ddev, "config %d has too many interfaces: %d, " + "using maximum allowed: %d\n", + cfgno, nintf, USB_MAXINTERFACES); config->desc.bNumInterfaces = nintf = USB_MAXINTERFACES; } for (i = 0; i < nintf; ++i) { interface = config->interface[i] = kmalloc(sizeof(struct usb_interface), GFP_KERNEL); - dbg("kmalloc IF %p, numif %i", interface, i); - if (!interface) { - err("out of memory"); + if (!interface) return -ENOMEM; - } memset(interface, 0, sizeof(struct usb_interface)); } /* Go through the descriptors, checking their length and counting the * number of altsettings for each interface */ - buffer2 = buffer; - size2 = size; - j = 0; - while (size2 >= sizeof(struct usb_descriptor_header)) { + for ((buffer2 = buffer, size2 = size); + size2 >= sizeof(struct usb_descriptor_header); + (buffer2 += header->bLength, size2 -= header->bLength)) { + header = (struct usb_descriptor_header *) buffer2; if ((header->bLength > size2) || (header->bLength < 2)) { - warn("invalid descriptor of length %d", header->bLength); + dev_err(ddev, "config %d has an invalid descriptor " + "of length %d\n", cfgno, header->bLength); return -EINVAL; } if (header->bDescriptorType == USB_DT_INTERFACE) { struct usb_interface_descriptor *d; - if (header->bLength < USB_DT_INTERFACE_SIZE) { - warn("invalid interface descriptor"); + d = (struct usb_interface_descriptor *) header; + if (d->bLength < USB_DT_INTERFACE_SIZE) { + dev_err(ddev, "config %d has an invalid " + "interface descriptor of length %d\n", + cfgno, d->bLength); return -EINVAL; } - d = (struct usb_interface_descriptor *) header; + i = d->bInterfaceNumber; if (i >= nintf_orig) { - warn("invalid interface number (%d/%d)", - i, nintf_orig); + dev_err(ddev, "config %d has an invalid " + "interface number: %d but max is %d\n", + cfgno, i, nintf_orig - 1); return -EINVAL; } if (i < nintf) ++config->interface[i]->num_altsetting; - } else if ((header->bDescriptorType == USB_DT_DEVICE || - header->bDescriptorType == USB_DT_CONFIG) && j) { - warn("unexpected descriptor type 0x%X", header->bDescriptorType); + } else if (header->bDescriptorType == USB_DT_DEVICE || + header->bDescriptorType == USB_DT_CONFIG) { + dev_err(ddev, "config %d contains an unexpected " + "descriptor of type 0x%X\n", + cfgno, header->bDescriptorType); return -EINVAL; } - j = 1; - buffer2 += header->bLength; - size2 -= header->bLength; - } + } /* for ((buffer2 = buffer, size2 = size); ...) */ /* Allocate the altsetting arrays */ - for (i = 0; i < config->desc.bNumInterfaces; ++i) { + for (i = 0; i < nintf; ++i) { interface = config->interface[i]; if (interface->num_altsetting > USB_MAXALTSETTING) { - warn("too many alternate settings for interface %d (%d max %d)\n", - i, interface->num_altsetting, USB_MAXALTSETTING); + dev_err(ddev, "too many alternate settings for " + "config %d interface %d: %d, " + "maximum allowed: %d\n", + cfgno, i, interface->num_altsetting, + USB_MAXALTSETTING); return -EINVAL; } if (interface->num_altsetting == 0) { - warn("no alternate settings for interface %d", i); + dev_err(ddev, "config %d has no interface number " + "%d\n", cfgno, i); return -EINVAL; } - len = sizeof(*interface->altsetting) * interface->num_altsetting; + len = sizeof(*interface->altsetting) * + interface->num_altsetting; interface->altsetting = kmalloc(len, GFP_KERNEL); - if (!interface->altsetting) { - err("couldn't kmalloc interface->altsetting"); + if (!interface->altsetting) return -ENOMEM; - } memset(interface->altsetting, 0, len); } - buffer += config->desc.bLength; - size -= config->desc.bLength; - - /* Skip over any Class Specific or Vendor Specific descriptors */ - begin = buffer; - numskipped = 0; - while (size >= sizeof(struct usb_descriptor_header)) { - header = (struct usb_descriptor_header *)buffer; - - /* If we find another "proper" descriptor then we're done */ - if ((header->bDescriptorType == USB_DT_ENDPOINT) || - (header->bDescriptorType == USB_DT_INTERFACE)) - break; - - dbg("skipping descriptor 0x%X", header->bDescriptorType); - numskipped++; - - buffer += header->bLength; - size -= header->bLength; - } - if (numskipped) { - dbg("skipped %d class/vendor specific configuration descriptors", numskipped); - config->extra = begin; - config->extralen = buffer - begin; - } + /* Skip over any Class Specific or Vendor Specific descriptors; + * find the first interface descriptor */ + config->extra = buffer; + i = find_next_descriptor(buffer, size, USB_DT_INTERFACE, + USB_DT_INTERFACE, &n); + config->extralen = i; + if (n > 0) + dev_dbg(ddev, "skipped %d class/vendor specific " + "configuration descriptors\n", n); + buffer += i; + size -= i; /* Parse all the interface/altsetting descriptors */ while (size >= sizeof(struct usb_descriptor_header)) { - retval = usb_parse_interface(config, buffer, size); + retval = usb_parse_interface(ddev, cfgno, config, + buffer, size); if (retval < 0) return retval; @@ -337,7 +343,8 @@ interface = config->interface[i]; for (j = 0; j < interface->num_altsetting; ++j) { if (!interface->altsetting[j].desc.bLength) { - warn("missing altsetting %d for interface %d", j, i); + dev_err(ddev, "config %d interface %d has no " + "altsetting %d\n", cfgno, i, j); return -EINVAL; } } @@ -360,6 +367,7 @@ kfree(dev->rawdescriptors[i]); kfree(dev->rawdescriptors); + dev->rawdescriptors = 0; } for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { @@ -373,6 +381,7 @@ } } kfree(dev->config); + dev->config = 0; } @@ -380,81 +389,77 @@ // (used by real hubs and virtual root hubs) int usb_get_configuration(struct usb_device *dev) { + struct device *ddev = &dev->dev; int ncfg = dev->descriptor.bNumConfigurations; - int result; + int result = -ENOMEM; unsigned int cfgno, length; unsigned char *buffer; unsigned char *bigbuffer; struct usb_config_descriptor *desc; if (ncfg > USB_MAXCONFIG) { - warn("too many configurations (%d max %d)", - ncfg, USB_MAXCONFIG); + dev_warn(ddev, "too many configurations: %d, " + "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG); dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG; } if (ncfg < 1) { - warn("no configurations"); + dev_err(ddev, "no configurations\n"); return -EINVAL; } length = ncfg * sizeof(struct usb_host_config); dev->config = kmalloc(length, GFP_KERNEL); - if (!dev->config) { - err("out of memory"); - return -ENOMEM; - } + if (!dev->config) + goto err2; memset(dev->config, 0, length); length = ncfg * sizeof(char *); dev->rawdescriptors = kmalloc(length, GFP_KERNEL); - if (!dev->rawdescriptors) { - err("out of memory"); - return -ENOMEM; - } + if (!dev->rawdescriptors) + goto err2; memset(dev->rawdescriptors, 0, length); buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) { - err("unable to allocate memory for configuration descriptors"); - return -ENOMEM; - } + if (!buffer) + goto err2; desc = (struct usb_config_descriptor *)buffer; for (cfgno = 0; cfgno < ncfg; cfgno++) { /* We grab the first 8 bytes so we know how long the whole */ - /* configuration is */ - result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8); - if (result < 8) { - if (result < 0) - err("unable to get descriptor"); - else { - warn("config descriptor too short (expected %i, got %i)", 8, result); - result = -EINVAL; - } + /* configuration is */ + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, + buffer, 8); + if (result < 0) { + dev_err(ddev, "unable to read config index %d " + "descriptor\n", cfgno); + goto err; + } else if (result < 8) { + dev_err(ddev, "config index %d descriptor too short " + "(expected %i, got %i)\n", cfgno, 8, result); + result = -EINVAL; goto err; } + length = max((int) le16_to_cpu(desc->wTotalLength), + USB_DT_CONFIG_SIZE); - /* Get the full buffer */ - length = max((int) le16_to_cpu(desc->wTotalLength), USB_DT_CONFIG_SIZE); - + /* Now that we know the length, get the whole thing */ bigbuffer = kmalloc(length, GFP_KERNEL); if (!bigbuffer) { - err("unable to allocate memory for configuration descriptors"); result = -ENOMEM; goto err; } - - /* Now that we know the length, get the whole thing */ - result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length); + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, + bigbuffer, length); if (result < 0) { - err("couldn't get all of config descriptors"); + dev_err(ddev, "unable to read config index %d " + "descriptor\n", cfgno); kfree(bigbuffer); goto err; } - if (result < length) { - err("config descriptor too short (expected %i, got %i)", length, result); + dev_err(ddev, "config index %d descriptor too short " + "(expected %i, got %i)\n", cfgno, length, result); result = -EINVAL; kfree(bigbuffer); goto err; @@ -462,20 +467,23 @@ dev->rawdescriptors[cfgno] = bigbuffer; - result = usb_parse_configuration(&dev->config[cfgno], bigbuffer, length); + result = usb_parse_configuration(&dev->dev, cfgno, + &dev->config[cfgno], bigbuffer, length); if (result > 0) - dbg("descriptor data left"); + dev_dbg(ddev, "config index %d descriptor has %d " + "excess byte(s)\n", cfgno, result); else if (result < 0) { ++cfgno; goto err; } } + result = 0; - kfree(buffer); - return 0; err: kfree(buffer); dev->descriptor.bNumConfigurations = cfgno; +err2: + if (result == -ENOMEM) + dev_err(ddev, "out of memory\n"); return result; } - diff -Nru a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c --- a/drivers/usb/core/devices.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/core/devices.c Tue Apr 6 17:22:26 2004 @@ -238,7 +238,7 @@ if (start > end) return start; - lock_kernel(); /* driver might be unloaded */ + down_read(&usb_bus_type.subsys.rwsem); start += sprintf(start, format_iface, desc->bInterfaceNumber, desc->bAlternateSetting, @@ -247,8 +247,10 @@ class_decode(desc->bInterfaceClass), desc->bInterfaceSubClass, desc->bInterfaceProtocol, - iface->driver ? iface->driver->name : "(none)"); - unlock_kernel(); + iface->dev.driver + ? iface->dev.driver->name + : "(none)"); + up_read(&usb_bus_type.subsys.rwsem); return start; } diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c --- a/drivers/usb/core/devio.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/core/devio.c Tue Apr 6 17:22:26 2004 @@ -124,14 +124,25 @@ unsigned int length = le16_to_cpu(config->wTotalLength); if (*ppos < pos + length) { + + /* The descriptor may claim to be longer than it + * really is. Here is the actual allocated length. */ + unsigned alloclen = + ps->dev->config[i].desc.wTotalLength; + len = length - (*ppos - pos); if (len > nbytes) len = nbytes; - if (copy_to_user(buf, - ps->dev->rawdescriptors[i] + (*ppos - pos), len)) { - ret = -EFAULT; - goto err; + /* Simply don't write (skip over) unallocated parts */ + if (alloclen > (*ppos - pos)) { + alloclen -= (*ppos - pos); + if (copy_to_user(buf, + ps->dev->rawdescriptors[i] + (*ppos - pos), + min(len, alloclen))) { + ret = -EFAULT; + goto err; + } } *ppos += len; @@ -363,13 +374,15 @@ return 0; iface = dev->actconfig->interface[intf]; err = -EBUSY; - lock_kernel(); + + /* lock against other changes to driver bindings */ + down_write(&usb_bus_type.subsys.rwsem); if (!usb_interface_claimed(iface)) { usb_driver_claim_interface(&usbdevfs_driver, iface, ps); set_bit(intf, &ps->ifclaimed); err = 0; } - unlock_kernel(); + up_write(&usb_bus_type.subsys.rwsem); return err; } @@ -384,11 +397,14 @@ err = -EINVAL; dev = ps->dev; down(&dev->serialize); + /* lock against other changes to driver bindings */ + down_write(&usb_bus_type.subsys.rwsem); if (test_and_clear_bit(intf, &ps->ifclaimed)) { iface = dev->actconfig->interface[intf]; usb_driver_release_interface(&usbdevfs_driver, iface); err = 0; } + up_write(&usb_bus_type.subsys.rwsem); up(&dev->serialize); return err; } @@ -414,6 +430,8 @@ if (ep & ~(USB_DIR_IN|0xf)) return -EINVAL; + if (!dev->actconfig) + return -ESRCH; for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { iface = dev->actconfig->interface[i]; for (j = 0; j < iface->num_altsetting; j++) { @@ -434,6 +452,8 @@ if (ifn & ~0xff) return -EINVAL; + if (!dev->actconfig) + return -ESRCH; for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { if (dev->actconfig->interface[i]-> altsetting[0].desc.bInterfaceNumber == ifn) @@ -684,9 +704,9 @@ if ((ret = findintfif(ps->dev, gd.interface)) < 0) return ret; interface = ps->dev->actconfig->interface[ret]; - if (!interface->driver) + if (!interface->dev.driver) return -ENODATA; - strcpy(gd.driver, interface->driver->name); + strncpy(gd.driver, interface->dev.driver->name, sizeof(gd.driver)); if (copy_to_user(arg, &gd, sizeof(gd))) return -EFAULT; return 0; @@ -705,26 +725,11 @@ static int proc_resetdevice(struct dev_state *ps) { - int i, ret; - - ret = usb_reset_device(ps->dev); - if (ret < 0) - return ret; - - for (i = 0; i < ps->dev->actconfig->desc.bNumInterfaces; i++) { - struct usb_interface *intf = ps->dev->actconfig->interface[i]; - - /* Don't simulate interfaces we've claimed */ - if (test_bit(i, &ps->ifclaimed)) - continue; - - err ("%s - this function is broken", __FUNCTION__); - if (intf->driver && ps->dev) { - usb_probe_interface (&intf->dev); - } - } + /* FIXME when usb_reset_device() is fixed we'll need to grab + * ps->dev->serialize before calling it. + */ + return usb_reset_device(ps->dev); - return 0; } static int proc_setintf(struct dev_state *ps, void __user *arg) @@ -738,7 +743,7 @@ if ((ret = findintfif(ps->dev, setintf.interface)) < 0) return ret; interface = ps->dev->actconfig->interface[ret]; - if (interface->driver) { + if (interface->dev.driver) { if ((ret = checkintf(ps, ret))) return ret; } @@ -750,10 +755,51 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg) { unsigned int u; + int status = 0; + struct usb_host_config *actconfig; if (get_user(u, (unsigned int __user *)arg)) return -EFAULT; - return usb_set_configuration(ps->dev, u); + + down(&ps->dev->serialize); + actconfig = ps->dev->actconfig; + + /* Don't touch the device if any interfaces are claimed. + * It could interfere with other drivers' operations, and if + * an interface is claimed by usbfs it could easily deadlock. + */ + if (actconfig) { + int i; + + for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) { + if (usb_interface_claimed(actconfig->interface[i])) { + dev_warn (&ps->dev->dev, + "usbfs: interface %d claimed " + "while '%s' sets config #%d\n", + actconfig->interface[i] + ->cur_altsetting + ->desc.bInterfaceNumber, + current->comm, u); +#if 0 /* FIXME: enable in 2.6.10 or so */ + status = -EBUSY; + break; +#endif + } + } + } + + /* SET_CONFIGURATION is often abused as a "cheap" driver reset, + * so avoid usb_set_configuration()'s kick to sysfs + */ + if (status == 0) { + if (actconfig && actconfig->desc.bConfigurationValue == u) + status = usb_reset_configuration(ps->dev); + else + status = usb_set_configuration(ps->dev, u); + } + up(&ps->dev->serialize); + + return status; } static int proc_submiturb(struct dev_state *ps, void __user *arg) @@ -1080,58 +1126,51 @@ } } - if (!ps->dev) - retval = -ENODEV; - else if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno))) + if (!ps->dev) { + if (buf) + kfree(buf); + return -ENODEV; + } + + down(&ps->dev->serialize); + if (ps->dev->state != USB_STATE_CONFIGURED) + retval = -ENODEV; + else if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno))) retval = -EINVAL; - else switch (ctrl.ioctl_code) { + else switch (ctrl.ioctl_code) { - /* disconnect kernel driver from interface, leaving it unbound. */ - /* maybe unbound - you get no guarantee it stays unbound */ - case USBDEVFS_DISCONNECT: - /* this function is misdesigned - retained for compatibility */ - lock_kernel(); - driver = ifp->driver; - if (driver) { - dbg ("disconnect '%s' from dev %d interface %d", - driver->name, ps->dev->devnum, ctrl.ifno); - usb_unbind_interface(&ifp->dev); + /* disconnect kernel driver from interface */ + case USBDEVFS_DISCONNECT: + down_write(&usb_bus_type.subsys.rwsem); + if (ifp->dev.driver) { + driver = to_usb_driver(ifp->dev.driver); + dev_dbg (&ifp->dev, "disconnect by usbfs\n"); + usb_driver_release_interface(driver, ifp); } else retval = -ENODATA; - unlock_kernel(); + up_write(&usb_bus_type.subsys.rwsem); break; /* let kernel drivers try to (re)bind to the interface */ case USBDEVFS_CONNECT: - lock_kernel(); - retval = usb_probe_interface (&ifp->dev); - unlock_kernel(); + bus_rescan_devices(ifp->dev.bus); break; /* talk directly to the interface's driver */ default: - /* BKL used here to protect against changing the binding - * of this driver to this device, as well as unloading its - * driver module. - */ - lock_kernel (); - driver = ifp->driver; + down_read(&usb_bus_type.subsys.rwsem); + if (ifp->dev.driver) + driver = to_usb_driver(ifp->dev.driver); if (driver == 0 || driver->ioctl == 0) { - unlock_kernel(); - retval = -ENOSYS; + retval = -ENOTTY; } else { - if (!try_module_get (driver->owner)) { - unlock_kernel(); - retval = -ENOSYS; - break; - } - unlock_kernel (); retval = driver->ioctl (ifp, ctrl.ioctl_code, buf); if (retval == -ENOIOCTLCMD) retval = -ENOTTY; - module_put (driver->owner); } + up_read(&usb_bus_type.subsys.rwsem); } + up(&ps->dev->serialize); /* cleanup and return */ if (retval >= 0 diff -Nru a/drivers/usb/core/driverfs.c b/drivers/usb/core/driverfs.c --- a/drivers/usb/core/driverfs.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/core/driverfs.c Tue Apr 6 17:22:26 2004 @@ -55,7 +55,9 @@ if (sscanf (buf, "%u", &config) != 1 || config > 255) return -EINVAL; + down(&udev->serialize); value = usb_set_configuration (udev, config); + up(&udev->serialize); return (value < 0) ? value : count; } diff -Nru a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c --- a/drivers/usb/core/hcd-pci.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/core/hcd-pci.c Tue Apr 6 17:22:26 2004 @@ -80,7 +80,8 @@ return -ENODEV; if (!dev->irq) { - err ("Found HC with no IRQ. Check BIOS/PCI %s setup!", + dev_err (&dev->dev, + "Found HC with no IRQ. Check BIOS/PCI %s setup!\n", pci_name(dev)); return -ENODEV; } @@ -90,16 +91,17 @@ resource = pci_resource_start (dev, 0); len = pci_resource_len (dev, 0); if (!request_mem_region (resource, len, driver->description)) { - dbg ("controller already in use"); + dev_dbg (&dev->dev, "controller already in use\n"); return -EBUSY; } base = ioremap_nocache (resource, len); if (base == NULL) { - dbg ("error mapping memory"); + dev_dbg (&dev->dev, "error mapping memory\n"); retval = -EFAULT; clean_1: release_mem_region (resource, len); - err ("init %s fail, %d", pci_name(dev), retval); + dev_err (&dev->dev, "init %s fail, %d\n", + pci_name(dev), retval); return retval; } @@ -116,7 +118,7 @@ break; } if (region == PCI_ROM_RESOURCE) { - dbg ("no i/o regions available"); + dev_dbg (&dev->dev, "no i/o regions available\n"); return -EBUSY; } base = (void *) resource; @@ -127,7 +129,7 @@ hcd = driver->hcd_alloc (); if (hcd == NULL){ - dbg ("hcd alloc fail"); + dev_dbg (&dev->dev, "hcd alloc fail\n"); retval = -ENOMEM; clean_2: if (driver->flags & HCD_MEMORY) { @@ -135,7 +137,8 @@ goto clean_1; } else { release_region (resource, len); - err ("init %s fail, %d", pci_name(dev), retval); + dev_err (&dev->dev, "init %s fail, %d\n", + pci_name(dev), retval); return retval; } } @@ -193,13 +196,16 @@ hcd->self.op = &usb_hcd_operations; hcd->self.hcpriv = (void *) hcd; hcd->self.release = &hcd_pci_release; + init_timer (&hcd->rh_timer); INIT_LIST_HEAD (&hcd->dev_list); usb_register_bus (&hcd->self); - if ((retval = driver->start (hcd)) < 0) + if ((retval = driver->start (hcd)) < 0) { + dev_err (hcd->self.controller, "init error %d\n", retval); usb_hcd_pci_remove (dev); + } return retval; } diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/core/hcd.c Tue Apr 6 17:22:26 2004 @@ -42,6 +42,8 @@ #include #include + +#include "usb.h" #include "hcd.h" @@ -416,9 +418,14 @@ default: /* non-generic request */ - urb->status = hcd->driver->hub_control (hcd, - typeReq, wValue, wIndex, - ubuf, wLength); + if (HCD_IS_SUSPENDED (hcd->state)) + urb->status = -EAGAIN; + else if (!HCD_IS_RUNNING (hcd->state)) + urb->status = -ENODEV; + else + urb->status = hcd->driver->hub_control (hcd, + typeReq, wValue, wIndex, + ubuf, wLength); break; error: /* "protocol stall" on error */ @@ -678,8 +685,10 @@ if (busnum < USB_MAXBUS) { set_bit (busnum, busmap.busmap); bus->busnum = busnum; - } else - warn ("too many buses"); + } else { + printk (KERN_ERR "%s: too many buses\n", usbcore_name); + return -E2BIG; + } snprintf(bus->class_dev.class_id, BUS_ID_SIZE, "usb%d", busnum); bus->class_dev.class = &usb_host_class; @@ -804,7 +813,7 @@ tmp = HS_USECS_ISO (bytecount); return tmp; default: - dbg ("bogus device speed!"); + pr_debug ("%s: bogus device speed!\n", usbcore_name); return -1; } } diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h --- a/drivers/usb/core/hcd.h Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/core/hcd.h Tue Apr 6 17:22:26 2004 @@ -275,10 +275,6 @@ #define EndpointOutRequest \ ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8) -/* table 9.6 standard features */ -#define DEVICE_REMOTE_WAKEUP 1 -#define ENDPOINT_HALT 0 - /* class requests from the USB 2.0 hub spec, table 11-15 */ /* GetBusState and SetHubDescriptor are optional, omitted */ #define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE) diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/core/hub.c Tue Apr 6 17:22:26 2004 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,12 @@ static pid_t khubd_pid = 0; /* PID of khubd */ static DECLARE_COMPLETION(khubd_exited); +/* cycle leds on hubs that aren't blinking for attention */ +static int blinkenlights = 0; +module_param (blinkenlights, bool, S_IRUGO); +MODULE_PARM_DESC (blinkenlights, "true to cycle leds on hubs"); + + #ifdef DEBUG static inline char *portspeed (int portstatus) { @@ -83,7 +90,6 @@ /* * USB 2.0 spec Section 11.24.2.2 - * BUG: doesn't handle port indicator selector in high byte of wIndex */ static int clear_port_feature(struct usb_device *dev, int port, int feature) { @@ -93,7 +99,6 @@ /* * USB 2.0 spec Section 11.24.2.13 - * BUG: doesn't handle port indicator selector in high byte of wIndex */ static int set_port_feature(struct usb_device *dev, int port, int feature) { @@ -102,6 +107,104 @@ } /* + * USB 2.0 spec Section 11.24.2.7.1.10 and table 11-7 + * for info about using port indicators + */ +static void set_port_led( + struct usb_device *dev, + struct usb_hub *hub, + int port, + int selector +) +{ + int status = set_port_feature(dev, (selector << 8) | port, + USB_PORT_FEAT_INDICATOR); + if (status < 0) + dev_dbg (&hub->intf->dev, + "port %d indicator %s status %d\n", + port, + ({ char *s; switch (selector) { + case HUB_LED_AMBER: s = "amber"; break; + case HUB_LED_GREEN: s = "green"; break; + case HUB_LED_OFF: s = "off"; break; + case HUB_LED_AUTO: s = "auto"; break; + default: s = "??"; break; + }; s; }), + status); +} + +#define LED_CYCLE_PERIOD ((2*HZ)/3) + +static void led_work (void *__hub) +{ + struct usb_hub *hub = __hub; + struct usb_device *dev = interface_to_usbdev (hub->intf); + unsigned i; + unsigned changed = 0; + int cursor = -1; + + if (dev->state != USB_STATE_CONFIGURED) + return; + + for (i = 0; i < hub->descriptor->bNbrPorts; i++) { + unsigned selector, mode; + + /* 30%-50% duty cycle */ + + switch (hub->indicator[i]) { + /* cycle marker */ + case INDICATOR_CYCLE: + cursor = i; + selector = HUB_LED_AUTO; + mode = INDICATOR_AUTO; + break; + /* blinking green = sw attention */ + case INDICATOR_GREEN_BLINK: + selector = HUB_LED_GREEN; + mode = INDICATOR_GREEN_BLINK_OFF; + break; + case INDICATOR_GREEN_BLINK_OFF: + selector = HUB_LED_OFF; + mode = INDICATOR_GREEN_BLINK; + break; + /* blinking amber = hw attention */ + case INDICATOR_AMBER_BLINK: + selector = HUB_LED_AMBER; + mode = INDICATOR_AMBER_BLINK_OFF; + break; + case INDICATOR_AMBER_BLINK_OFF: + selector = HUB_LED_OFF; + mode = INDICATOR_AMBER_BLINK; + break; + /* blink green/amber = reserved */ + case INDICATOR_ALT_BLINK: + selector = HUB_LED_GREEN; + mode = INDICATOR_ALT_BLINK_OFF; + break; + case INDICATOR_ALT_BLINK_OFF: + selector = HUB_LED_AMBER; + mode = INDICATOR_ALT_BLINK; + break; + default: + continue; + } + if (selector != HUB_LED_AUTO) + changed = 1; + set_port_led(dev, hub, i + 1, selector); + hub->indicator[i] = mode; + } + if (!changed && blinkenlights) { + cursor++; + cursor %= hub->descriptor->bNbrPorts; + set_port_led(dev, hub, cursor + 1, HUB_LED_GREEN); + hub->indicator[cursor] = INDICATOR_CYCLE; + changed++; + } + if (changed) + schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD); +} + +/* * USB 2.0 spec Section 11.24.2.6 */ static int get_hub_status(struct usb_device *dev, @@ -212,8 +315,7 @@ spin_lock_irqsave (&hub->tt.lock, flags); if (status) - err ("usb-%s-%s clear tt %d (%04x) error %d", - dev->bus->bus_name, dev->devpath, + dev_err (&dev->dev, "clear tt %d (%04x) error %d\n", clear->tt, clear->devinfo, status); kfree (clear); } @@ -244,8 +346,7 @@ * there can be many TTs per hub). even if they're uncommon. */ if ((clear = kmalloc (sizeof *clear, SLAB_ATOMIC)) == 0) { - err ("can't save CLEAR_TT_BUFFER state for hub at usb-%s-%s", - dev->bus->bus_name, tt->hub->devpath); + dev_err (&dev->dev, "can't save CLEAR_TT_BUFFER state\n"); /* FIXME recover somehow ... RESET_TT? */ return; } @@ -377,7 +478,7 @@ break; case 0x02: case 0x03: - dev_dbg(hub_dev, "unknown reserved power switching mode\n"); + dev_dbg(hub_dev, "no power switching (usb 1.0)\n"); break; } @@ -436,9 +537,11 @@ break; } - dev_dbg(hub_dev, "Port indicators are %s supported\n", - (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND) - ? "" : "not"); + /* probe() zeroes hub->indicator[] */ + if (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND) { + hub->has_indicators = 1; + dev_dbg(hub_dev, "Port indicators are supported\n"); + } dev_dbg(hub_dev, "power on to power good time: %dms\n", hub->descriptor->bPwrOn2PwrGood * 2); @@ -451,12 +554,16 @@ goto fail; } + /* FIXME implement per-port power budgeting; + * enable it for bus-powered hubs. + */ dev_dbg(hub_dev, "local power source is %s\n", (hubstatus & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good"); - dev_dbg(hub_dev, "%sover-current condition exists\n", - (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no "); + if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) == 0) + dev_dbg(hub_dev, "%sover-current condition exists\n", + (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no "); /* Start the interrupt endpoint */ pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); @@ -486,6 +593,13 @@ /* Wake up khubd */ wake_up(&khubd_wait); + /* maybe start cycling the hub leds */ + if (hub->has_indicators && blinkenlights) { + set_port_led(dev, hub, 1, HUB_LED_GREEN); + hub->indicator [0] = INDICATOR_CYCLE; + schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD); + } + hub_power_on(hub); return 0; @@ -520,7 +634,9 @@ up(&hub->khubd_sem); /* assuming we used keventd, it must quiesce too */ - if (hub->tt.hub) + if (hub->has_indicators) + cancel_delayed_work (&hub->leds); + if (hub->has_indicators || hub->tt.hub) flush_scheduled_work (); if (hub->urb) { @@ -596,7 +712,7 @@ hub = kmalloc(sizeof(*hub), GFP_KERNEL); if (!hub) { - err("couldn't kmalloc hub struct"); + dev_dbg (hubdev(dev), "couldn't kmalloc hub struct\n"); return -ENOMEM; } @@ -605,6 +721,7 @@ INIT_LIST_HEAD(&hub->event_list); hub->intf = intf; init_MUTEX(&hub->khubd_sem); + INIT_WORK(&hub->leds, led_work, hub); /* Record the new hub's existence */ spin_lock_irqsave(&hub_event_lock, flags); @@ -700,7 +817,7 @@ } } - err("cannot disconnect hub %s", dev->devpath); + dev_err(&dev->dev, "cannot disconnect hub!\n"); } static int hub_port_status(struct usb_device *dev, int port, @@ -1145,7 +1262,7 @@ refrigerator(PF_IOTHREAD); } while (!signal_pending(current)); - dbg("hub_thread exiting"); + pr_debug ("%s: khubd exiting\n", usbcore_name); complete_and_exit(&khubd_exited, 0); } @@ -1176,7 +1293,8 @@ pid_t pid; if (usb_register(&hub_driver) < 0) { - err("Unable to register USB hub driver"); + printk(KERN_ERR "%s: can't register hub driver\n", + usbcore_name); return -1; } @@ -1189,7 +1307,7 @@ /* Fall through if kernel_thread failed */ usb_deregister(&hub_driver); - err("failed to start hub_thread"); + printk(KERN_ERR "%s: can't start khubd\n", usbcore_name); return -1; } @@ -1300,33 +1418,15 @@ kfree(descriptor); usb_destroy_configuration(dev); - ret = usb_get_device_descriptor(dev, sizeof(dev->descriptor)); - if (ret != sizeof(dev->descriptor)) { - if (ret < 0) - err("unable to get device %s descriptor " - "(error=%d)", dev->devpath, ret); - else - err("USB device %s descriptor short read " - "(expected %Zi, got %i)", - dev->devpath, - sizeof(dev->descriptor), ret); - - clear_bit(dev->devnum, dev->bus->devmap.devicemap); - dev->devnum = -1; - return -EIO; - } - - ret = usb_get_configuration(dev); - if (ret < 0) { - err("unable to get configuration (error=%d)", ret); - usb_destroy_configuration(dev); - clear_bit(dev->devnum, dev->bus->devmap.devicemap); - dev->devnum = -1; - return 1; - } + /* FIXME Linux doesn't yet handle these "device morphed" + * paths. DFU variants need this to work ... and they + * include the "config descriptors changed" case this + * doesn't yet detect! + */ + dev->state = USB_STATE_NOTATTACHED; + dev_err(&dev->dev, "device morphed (DFU?), nyet supported\n"); - usb_set_configuration(dev, dev->config[0].desc.bConfigurationValue); - return 1; + return -ENODEV; } kfree(descriptor); diff -Nru a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h --- a/drivers/usb/core/hub.h Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/core/hub.h Tue Apr 6 17:22:26 2004 @@ -139,6 +139,22 @@ __u8 PortPwrCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8]; } __attribute__ ((packed)); + +/* port indicator status selectors, tables 11-7 and 11-25 */ +#define HUB_LED_AUTO 0 +#define HUB_LED_AMBER 1 +#define HUB_LED_GREEN 2 +#define HUB_LED_OFF 3 + +enum hub_led_mode { + INDICATOR_AUTO = 0, + INDICATOR_CYCLE, + /* software blinks for attention: software, hardware, reserved */ + INDICATOR_GREEN_BLINK, INDICATOR_GREEN_BLINK_OFF, + INDICATOR_AMBER_BLINK, INDICATOR_AMBER_BLINK_OFF, + INDICATOR_ALT_BLINK, INDICATOR_ALT_BLINK_OFF +} __attribute__ ((packed)); + struct usb_device; /* @@ -192,6 +208,10 @@ struct usb_hub_descriptor *descriptor; /* class descriptor */ struct semaphore khubd_sem; struct usb_tt tt; /* Transaction Translator */ + + unsigned has_indicators:1; + enum hub_led_mode indicator[USB_MAXCHILDREN]; + struct work_struct leds; }; #endif /* __LINUX_HUB_H */ diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c --- a/drivers/usb/core/message.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/core/message.c Tue Apr 6 17:22:26 2004 @@ -722,7 +722,8 @@ * this request for iso endpoints, which can't halt! */ result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, + USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, + USB_ENDPOINT_HALT, endp, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); /* don't un-halt or force to DATA0 except on success */ @@ -928,7 +929,8 @@ iface = usb_ifnum_to_if(dev, interface); if (!iface) { - warn("selecting invalid interface %d", interface); + dev_dbg(&dev->dev, "selecting invalid interface %d\n", + interface); return -EINVAL; } @@ -946,8 +948,9 @@ * request if the interface only has one alternate setting. */ if (ret == -EPIPE && iface->num_altsetting == 1) { - dbg("manual set_interface for dev %d, iface %d, alt %d", - dev->devnum, interface, alternate); + dev_dbg(&dev->dev, + "manual set_interface for iface %d, alt %d\n", + interface, alternate); manual = 1; } else if (ret < 0) return ret; @@ -1065,11 +1068,11 @@ return 0; } -/** +/* * usb_set_configuration - Makes a particular device setting be current * @dev: the device whose configuration is being updated * @configuration: the configuration being chosen. - * Context: !in_interrupt () + * Context: !in_interrupt(), caller holds dev->serialize * * This is used to enable non-default device modes. Not all devices * use this kind of configurability; many devices only have one @@ -1105,7 +1108,6 @@ struct usb_host_config *cp = NULL; /* dev->serialize guards all config changes */ - down(&dev->serialize); for (i=0; idescriptor.bNumConfigurations; i++) { if (dev->config[i].desc.bConfigurationValue == configuration) { @@ -1167,21 +1169,39 @@ intf->dev.bus = &usb_bus_type; intf->dev.dma_mask = dev->dev.dma_mask; intf->dev.release = release_interface; + device_initialize (&intf->dev); sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", dev->bus->busnum, dev->devpath, configuration, alt->desc.bInterfaceNumber); + } + + /* Now that all interfaces are setup, probe() calls + * may claim() any interface that's not yet bound. + * Many class drivers need that: CDC, audio, video, etc. + */ + for (i = 0; i < cp->desc.bNumInterfaces; ++i) { + struct usb_interface *intf = cp->interface[i]; + struct usb_interface_descriptor *desc; + + desc = &intf->altsetting [0].desc; dev_dbg (&dev->dev, - "registering %s (config #%d, interface %d)\n", + "adding %s (config #%d, interface %d)\n", intf->dev.bus_id, configuration, - alt->desc.bInterfaceNumber); - device_register (&intf->dev); + 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_driverfs_intf_files (intf); } } out: - up(&dev->serialize); return ret; } @@ -1226,18 +1246,20 @@ if (!dev->have_langid) { err = usb_get_string(dev, 0, 0, tbuf, 4); if (err < 0) { - err("error getting string descriptor 0 (error=%d)", err); + dev_err (&dev->dev, + "string descriptor 0 read error: %d\n", + err); goto errout; } else if (err < 4 || tbuf[0] < 4) { - err("string descriptor 0 too short"); + dev_err (&dev->dev, "string descriptor 0 too short\n"); err = -EINVAL; goto errout; } else { dev->have_langid = -1; dev->string_langid = tbuf[2] | (tbuf[3]<< 8); /* always use the first langid listed */ - dbg("USB device number %d default language ID 0x%x", - dev->devnum, dev->string_langid); + dev_dbg (&dev->dev, "default language 0x%04x\n", + dev->string_langid); } } @@ -1288,6 +1310,5 @@ // synchronous calls that also maintain usbcore state EXPORT_SYMBOL(usb_clear_halt); EXPORT_SYMBOL(usb_reset_configuration); -EXPORT_SYMBOL(usb_set_configuration); EXPORT_SYMBOL(usb_set_interface); diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/core/usb.c Tue Apr 6 17:22:26 2004 @@ -7,8 +7,7 @@ * (C) Copyright Gregory P. Smith 1999 * (C) Copyright Deti Fliegl 1999 (new USB architecture) * (C) Copyright Randy Dunlap 2000 - * (C) Copyright David Brownell 2000-2001 (kernel hotplug, usb_device_id, - more docs, etc) + * (C) Copyright David Brownell 2000-2004 * (C) Copyright Yggdrasil Computing, Inc. 2000 * (usb_device_id matching changes by Adam J. Richter) * (C) Copyright Greg Kroah-Hartman 2002-2003 @@ -58,6 +57,8 @@ extern void usb_host_cleanup(void); +const char *usbcore_name = "usbcore"; + int nousb; /* Disable USB when built into kernel image */ /* Not honored on modular build */ @@ -93,17 +94,11 @@ if (!driver->probe) return error; - /* driver claim() doesn't yet affect dev->driver... */ - if (intf->driver) - return error; - id = usb_match_id (intf, driver->id_table); if (id) { dev_dbg (dev, "%s - got id\n", __FUNCTION__); error = driver->probe (intf, id); } - if (!error) - intf->driver = driver; return error; } @@ -112,7 +107,7 @@ int usb_unbind_interface(struct device *dev) { struct usb_interface *intf = to_usb_interface(dev); - struct usb_driver *driver = intf->driver; + struct usb_driver *driver = to_usb_driver(intf->dev.driver); /* release all urbs for this interface */ usb_disable_interface(interface_to_usbdev(intf), intf); @@ -125,7 +120,6 @@ intf->altsetting[0].desc.bInterfaceNumber, 0); usb_set_intfdata(intf, NULL); - intf->driver = NULL; return 0; } @@ -158,11 +152,12 @@ retval = driver_register(&new_driver->driver); if (!retval) { - info("registered new driver %s", new_driver->name); + pr_info("%s: registered new driver %s\n", + usbcore_name, new_driver->name); usbfs_update_special(); } else { - err("problem %d when registering driver %s", - retval, new_driver->name); + printk(KERN_ERR "%s: error %d registering driver %s\n", + usbcore_name, retval, new_driver->name); } return retval; @@ -181,7 +176,7 @@ */ void usb_deregister(struct usb_driver *driver) { - info("deregistering driver %s", driver->name); + pr_info("%s: deregistering driver %s\n", usbcore_name, driver->name); driver_unregister (&driver->driver); @@ -287,7 +282,8 @@ /** * usb_driver_claim_interface - bind a driver to an interface * @driver: the driver to be bound - * @iface: the interface to which it will be bound + * @iface: the interface to which it will be bound; must be in the + * usb device's active configuration * @priv: driver data associated with that interface * * This is used by usb device drivers that need to claim more than one @@ -305,75 +301,52 @@ */ int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv) { - if (!iface || !driver) - return -EINVAL; + struct device *dev = &iface->dev; - if (iface->driver) + if (dev->driver) return -EBUSY; - /* FIXME should device_bind_driver() */ - iface->driver = driver; + dev->driver = &driver->driver; usb_set_intfdata(iface, priv); - return 0; -} -/** - * usb_interface_claimed - returns true iff an interface is claimed - * @iface: the interface being checked - * - * This should be used by drivers to check other interfaces to see if - * they are available or not. If another driver has claimed the interface, - * they may not claim it. Otherwise it's OK to claim it using - * usb_driver_claim_interface(). - * - * Returns true (nonzero) iff the interface is claimed, else false (zero). - */ -int usb_interface_claimed(struct usb_interface *iface) -{ - if (!iface) - return 0; + /* if interface was already added, bind now; else let + * the future device_add() bind it, bypassing probe() + */ + if (!list_empty (&dev->bus_list)) + device_bind_driver(dev); - return (iface->driver != NULL); -} /* usb_interface_claimed() */ + return 0; +} /** * usb_driver_release_interface - unbind a driver from an interface * @driver: the driver to be unbound * @iface: the interface from which it will be unbound * - * In addition to unbinding the driver, this re-initializes the interface - * by selecting altsetting 0, the default alternate setting. - * * This can be used by drivers to release an interface without waiting - * for their disconnect() methods to be called. - * - * When the USB subsystem disconnect()s a driver from some interface, - * it automatically invokes this method for that interface. That - * means that even drivers that used usb_driver_claim_interface() - * usually won't need to call this. + * for their disconnect() methods to be called. In typical cases this + * also causes the driver disconnect() method to be called. * * This call is synchronous, and may not be used in an interrupt context. - * Callers must own the driver model's usb bus writelock. So driver - * disconnect() entries don't need extra locking, but other call contexts - * may need to explicitly claim that lock. + * Callers must own the usb_device serialize semaphore and the driver model's + * usb bus writelock. So driver disconnect() entries don't need extra locking, + * but other call contexts may need to explicitly claim those locks. */ -void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface) +void usb_driver_release_interface(struct usb_driver *driver, + struct usb_interface *iface) { + struct device *dev = &iface->dev; + /* this should never happen, don't release something that's not ours */ - if (!iface || !iface->driver || iface->driver != driver) + if (!dev->driver || dev->driver != &driver->driver) return; - if (iface->dev.driver) { - /* FIXME should be the ONLY case here */ - device_release_driver(&iface->dev); - return; - } + /* don't disconnect from disconnect(), or before dev_add() */ + if (!list_empty (&dev->driver_list) && !list_empty (&dev->bus_list)) + device_release_driver(dev); - usb_set_interface(interface_to_usbdev(iface), - iface->altsetting[0].desc.bInterfaceNumber, - 0); + dev->driver = NULL; usb_set_intfdata(iface, NULL); - iface->driver = NULL; } /** @@ -587,11 +560,12 @@ int i = 0; int length = 0; - dbg ("%s", __FUNCTION__); - if (!dev) return -ENODEV; + /* driver is often null here; dev_dbg() would oops */ + pr_debug ("usb %s: hotplug\n", dev->bus_id); + /* Must check driver_data here, as on remove driver is always NULL */ if ((dev->driver == &usb_generic_driver) || (dev->driver_data == &usb_generic_driver_data)) @@ -601,11 +575,11 @@ usb_dev = interface_to_usbdev (intf); if (usb_dev->devnum < 0) { - dbg ("device already deleted ??"); + pr_debug ("usb %s: already deleted?\n", dev->bus_id); return -ENODEV; } if (!usb_dev->bus) { - dbg ("bus already removed?"); + pr_debug ("usb %s: bus removed?\n", dev->bus_id); return -ENODEV; } @@ -794,18 +768,11 @@ * * A pointer to the device with the incremented reference counter is returned. */ -struct usb_device *usb_get_dev (struct usb_device *dev) +struct usb_device *usb_get_dev(struct usb_device *dev) { - struct device *tmp; - - if (!dev) - return NULL; - - tmp = get_device(&dev->dev); - if (tmp) - return to_usb_device(tmp); - else - return NULL; + if (dev) + get_device(&dev->dev); + return dev; } /** @@ -821,20 +788,54 @@ put_device(&dev->dev); } +/** + * usb_get_intf - increments the reference count of the usb interface structure + * @intf: the interface being referenced + * + * Each live reference to a interface must be refcounted. + * + * Drivers for USB interfaces should normally record such references in + * their probe() methods, when they bind to an interface, and release + * them by calling usb_put_intf(), in their disconnect() methods. + * + * A pointer to the interface with the incremented reference counter is + * returned. + */ +struct usb_interface *usb_get_intf(struct usb_interface *intf) +{ + if (intf) + get_device(&intf->dev); + return intf; +} + +/** + * usb_put_intf - release a use of the usb interface structure + * @intf: interface that's been decremented + * + * Must be called when a user of an interface is finished with it. When the + * last user of the interface calls this function, the memory of the interface + * is freed. + */ +void usb_put_intf(struct usb_interface *intf) +{ + if (intf) + put_device(&intf->dev); +} + static struct usb_device *match_device(struct usb_device *dev, u16 vendor_id, u16 product_id) { struct usb_device *ret_dev = NULL; int child; - dbg("looking at vendor %d, product %d", + dev_dbg(&dev->dev, "check for vendor %04x, product %04x ...\n", dev->descriptor.idVendor, dev->descriptor.idProduct); /* see if this device matches */ if ((dev->descriptor.idVendor == vendor_id) && (dev->descriptor.idProduct == product_id)) { - dbg ("found the device!"); + dev_dbg (&dev->dev, "matched this device!\n"); ret_dev = usb_get_dev(dev); goto exit; } @@ -909,7 +910,8 @@ * extra field of the interface and endpoint descriptor structs. */ -int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr) +int __usb_get_extra_descriptor(char *buffer, unsigned size, + unsigned char type, void **ptr) { struct usb_descriptor_header *header; @@ -917,7 +919,11 @@ header = (struct usb_descriptor_header *)buffer; if (header->bLength < 2) { - err("invalid descriptor length of %d", header->bLength); + printk(KERN_ERR + "%s: bogus descriptor, type %d length %d\n", + usbcore_name, + header->bDescriptorType, + header->bLength); return -1; } @@ -1164,10 +1170,13 @@ usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber); #endif + down(&dev->serialize); + /* put device-specific files into sysfs */ err = device_add (&dev->dev); if (err) { dev_err(&dev->dev, "can't device_add, error %d\n", err); + up(&dev->serialize); goto fail; } usb_create_driverfs_dev_files (dev); @@ -1202,6 +1211,7 @@ dev->descriptor.bNumConfigurations); } err = usb_set_configuration(dev, config); + up(&dev->serialize); if (err) { dev_err(&dev->dev, "can't set config #%d, error %d\n", config, err); @@ -1568,7 +1578,7 @@ static int __init usb_init(void) { if (nousb) { - info("USB support disabled\n"); + pr_info ("%s: USB support disabled\n", usbcore_name); return 0; } @@ -1620,7 +1630,6 @@ EXPORT_SYMBOL(usb_hub_tt_clear_buffer); EXPORT_SYMBOL(usb_driver_claim_interface); -EXPORT_SYMBOL(usb_interface_claimed); EXPORT_SYMBOL(usb_driver_release_interface); EXPORT_SYMBOL(usb_match_id); EXPORT_SYMBOL(usb_find_interface); diff -Nru a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h --- a/drivers/usb/core/usb.h Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/core/usb.h Tue Apr 6 17:22:26 2004 @@ -17,3 +17,7 @@ extern int usb_get_device_descriptor(struct usb_device *dev, unsigned int size); +extern int usb_set_configuration(struct usb_device *dev, int configuration); + +/* for labeling diagnostics */ +extern const char *usbcore_name; diff -Nru a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig --- a/drivers/usb/gadget/Kconfig Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/gadget/Kconfig Tue Apr 6 17:22:26 2004 @@ -71,8 +71,8 @@ default USB_GADGET config USB_GADGET_PXA2XX - boolean "PXA 2xx or IXP 42x" - depends on ARCH_PXA || ARCH_IXP425 + boolean "PXA 2xx or IXP 4xx" + depends on ARCH_PXA || ARCH_IXP4XX help Intel's PXA 2xx series XScale ARM-5TE processors include an integrated full speed USB 1.1 device controller. The @@ -134,6 +134,34 @@ depends on USB_GADGET_SA1100 default USB_GADGET +config USB_GADGET_DUMMY_HCD + boolean "Dummy HCD (DEVELOPMENT)" + depends on USB && EXPERIMENTAL + select USB_GADGET_DUALSPEED + help + This host controller driver emulates USB, looping all data transfer + requests back to a USB "gadget driver" in the same host. The host + side is the master; the gadget side is the slave. Gadget drivers + can be high, full, or low speed; and they have access to endpoints + like those from NET2280, PXA2xx, or SA1100 hardware. + + This may help in some stages of creating a driver to embed in a + Linux device, since it lets you debug several parts of the gadget + driver without its hardware or drivers being involved. + + Since such a gadget side driver needs to interoperate with a host + side Linux-USB device driver, this may help to debug both sides + of a USB protocol stack. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "dummy_hcd" and force all + gadget drivers to also be dynamically linked. + +config USB_DUMMY_HCD + tristate + depends on USB_GADGET_DUMMY_HCD + default USB_GADGET + endchoice config USB_GADGET_DUALSPEED @@ -191,9 +219,11 @@ favor of simpler vendor-specific hardware, but is widely supported by firmware for smart network devices. - - On hardware can't implement that protocol, a simpler approach + - On hardware can't implement that protocol, a simple CDC subset is used, placing fewer demands on USB. + RNDIS support is a third option, more demanding than that subset. + Within the USB device, this gadget driver exposes a network device "usbX", where X depends on what other networking devices you have. Treat it like a two-node Ethernet link: host, and gadget. @@ -206,6 +236,19 @@ Say "y" to link the driver statically, or "m" to build a dynamically linked module called "g_ether". + +config USB_ETH_RNDIS + bool "RNDIS support (EXPERIMENTAL)" + depends on USB_ETH && EXPERIMENTAL + default y + help + Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol, + and Microsoft provides redistributable binary RNDIS drivers for + older versions of Windows. + + If you say "y" here, the Ethernet gadget driver will try to provide + a second device configuration, supporting RNDIS to talk to such + Microsoft USB hosts. config USB_GADGETFS tristate "Gadget Filesystem (EXPERIMENTAL)" diff -Nru a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile --- a/drivers/usb/gadget/Makefile Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/gadget/Makefile Tue Apr 6 17:22:26 2004 @@ -1,6 +1,7 @@ # # USB peripheral controller drivers # +obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o obj-$(CONFIG_USB_NET2280) += net2280.o obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o obj-$(CONFIG_USB_GOKU) += goku_udc.o @@ -8,11 +9,16 @@ # # USB gadget drivers # -g_zero-objs := zero.o usbstring.o config.o -g_ether-objs := ether.o usbstring.o config.o +g_zero-objs := zero.o usbstring.o config.o epautoconf.o +g_ether-objs := ether.o usbstring.o config.o epautoconf.o g_serial-objs := serial.o usbstring.o -gadgetfs-objs := inode.o usbstring.o -g_file_storage-objs := file_storage.o usbstring.o +gadgetfs-objs := inode.o +g_file_storage-objs := file_storage.o usbstring.o config.o \ + epautoconf.o + +ifeq ($(CONFIG_USB_ETH_RNDIS),y) + g_ether-objs += rndis.o +endif obj-$(CONFIG_USB_ZERO) += g_zero.o obj-$(CONFIG_USB_ETH) += g_ether.o diff -Nru a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/gadget/dummy_hcd.c Tue Apr 6 17:22:26 2004 @@ -0,0 +1,1679 @@ +/* + * dummy_hcd.c -- Dummy/Loopback USB host and device emulator driver. + * + * Maintainer: Alan Stern + * + * Copyright (C) 2003 David Brownell + * Copyright (C) 2003, 2004 Alan Stern + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* + * This exposes a device side "USB gadget" API, driven by requests to a + * Linux-USB host controller driver. USB traffic is simulated; there's + * no need for USB hardware. Use this with two other drivers: + * + * - Gadget driver, responding to requests (slave); + * - Host-side device driver, as already familiar in Linux. + * + * Having this all in one kernel can help some stages of development, + * bypassing some hardware (and driver) issues. UML could help too. + */ + +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + + +#include "../core/hcd.h" + + +#define DRIVER_DESC "USB Host+Gadget Emulator" +#define DRIVER_VERSION "14 Mar 2004" + +static const char driver_name [] = "dummy_hcd"; +static const char driver_desc [] = "USB Host+Gadget Emulator"; + +static const char gadget_name [] = "dummy_udc"; + +MODULE_DESCRIPTION (DRIVER_DESC); +MODULE_AUTHOR ("David Brownell"); +MODULE_LICENSE ("GPL"); + +/*-------------------------------------------------------------------------*/ + +/* gadget side driver data structres */ +struct dummy_ep { + struct list_head queue; + unsigned long last_io; /* jiffies timestamp */ + struct usb_gadget *gadget; + const struct usb_endpoint_descriptor *desc; + struct usb_ep ep; + unsigned halted : 1; + unsigned already_seen : 1; + unsigned setup_stage : 1; +}; + +struct dummy_request { + struct list_head queue; /* ep's requests */ + struct usb_request req; +}; + +/*-------------------------------------------------------------------------*/ + +/* + * Every device has ep0 for control requests, plus up to 30 more endpoints, + * in one of two types: + * + * - Configurable: direction (in/out), type (bulk, iso, etc), and endpoint + * number can be changed. Names like "ep-a" are used for this type. + * + * - Fixed Function: in other cases. some characteristics may be mutable; + * that'd be hardware-specific. Names like "ep12out-bulk" are used. + * + * Gadget drivers are responsible for not setting up conflicting endpoint + * configurations, illegal or unsupported packet lengths, and so on. + */ + +static const char ep0name [] = "ep0"; + +static const char *const ep_name [] = { + ep0name, /* everyone has ep0 */ + + /* act like a net2280: high speed, six configurable endpoints */ + "ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f", + + /* or like pxa250: fifteen fixed function endpoints */ + "ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int", + "ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int", + "ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso", + "ep15in-int", + + /* or like sa1100: two fixed function endpoints */ + "ep1out-bulk", "ep2in-bulk", +}; +#define DUMMY_ENDPOINTS (sizeof(ep_name)/sizeof(char *)) + +#define FIFO_SIZE 64 + +struct dummy { + spinlock_t lock; + + /* + * SLAVE/GADGET side support + */ + struct dummy_ep ep [DUMMY_ENDPOINTS]; + int address; + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct dummy_request fifo_req; + u8 fifo_buf [FIFO_SIZE]; + + struct hcd_dev *hdev; + + /* + * MASTER/HOST side support + */ + struct usb_hcd hcd; + struct platform_device pdev; + struct timer_list timer; + u32 port_status; + int started; + struct completion released; +}; + +static struct dummy *the_controller; + +static inline struct dummy *ep_to_dummy (struct dummy_ep *ep) +{ + return container_of (ep->gadget, struct dummy, gadget); +} + +static inline struct dummy *gadget_dev_to_dummy (struct device *dev) +{ + return container_of (dev, struct dummy, gadget.dev); +} + +/* + * This "hardware" may look a bit odd in diagnostics since it's got both + * host and device sides; and it binds different drivers to each side. + */ +#define hardware (&the_controller->pdev.dev) + +/*-------------------------------------------------------------------------*/ + +static struct device_driver dummy_driver = { + .name = (char *) driver_name, + .bus = &platform_bus_type, +}; + +/*-------------------------------------------------------------------------*/ + +/* SLAVE/GADGET SIDE DRIVER + * + * This only tracks gadget state. All the work is done when the host + * side tries some (emulated) i/o operation. Real device controller + * drivers would do real i/o using dma, fifos, irqs, timers, etc. + */ + +#define is_enabled() \ + (the_controller->port_status & USB_PORT_STAT_ENABLE) + +static int +dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) +{ + struct dummy *dum; + struct dummy_ep *ep; + unsigned max; + int retval; + + ep = container_of (_ep, struct dummy_ep, ep); + if (!_ep || !desc || ep->desc || _ep->name == ep0name + || desc->bDescriptorType != USB_DT_ENDPOINT) + if (!the_controller->driver || !is_enabled ()) + return -ESHUTDOWN; + max = desc->wMaxPacketSize & 0x3ff; + + /* drivers must not request bad settings, since lower levels + * (hardware or its drivers) may not check. some endpoints + * can't do iso, many have maxpacket limitations, etc. + * + * since this "hardware" driver is here to help debugging, we + * have some extra sanity checks. (there could be more though, + * especially for "ep9out" style fixed function ones.) + */ + dum = container_of (ep->gadget, struct dummy, gadget); + retval = -EINVAL; + switch (desc->bmAttributes & 0x03) { + case USB_ENDPOINT_XFER_BULK: + if (strstr (ep->ep.name, "-iso") + || strstr (ep->ep.name, "-int")) { + goto done; + } + switch (dum->gadget.speed) { + case USB_SPEED_HIGH: + if (max == 512) + break; + /* conserve return statements */ + default: + switch (max) { + case 8: case 16: case 32: case 64: + /* we'll fake any legal size */ + break; + default: + case USB_SPEED_LOW: + goto done; + } + } + break; + case USB_ENDPOINT_XFER_INT: + if (strstr (ep->ep.name, "-iso")) /* bulk is ok */ + goto done; + /* real hardware might not handle all packet sizes */ + switch (dum->gadget.speed) { + case USB_SPEED_HIGH: + if (max <= 1024) + break; + /* save a return statement */ + case USB_SPEED_FULL: + if (max <= 64) + break; + /* save a return statement */ + default: + if (max <= 8) + break; + goto done; + } + break; + case USB_ENDPOINT_XFER_ISOC: + if (strstr (ep->ep.name, "-bulk") + || strstr (ep->ep.name, "-int")) + goto done; + /* real hardware might not handle all packet sizes */ + switch (dum->gadget.speed) { + case USB_SPEED_HIGH: + if (max <= 1024) + break; + /* save a return statement */ + case USB_SPEED_FULL: + if (max <= 1023) + break; + /* save a return statement */ + default: + goto done; + } + break; + default: + /* few chips support control except on ep0 */ + goto done; + } + + _ep->maxpacket = max; + ep->desc = desc; + + dev_dbg (hardware, "enabled %s (ep%d%s-%s) maxpacket %d\n", + _ep->name, + desc->bEndpointAddress & 0x0f, + (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", + ({ char *val; + switch (desc->bmAttributes & 0x03) { + case USB_ENDPOINT_XFER_BULK: val = "bulk"; break; + case USB_ENDPOINT_XFER_ISOC: val = "iso"; break; + case USB_ENDPOINT_XFER_INT: val = "intr"; break; + default: val = "ctrl"; break; + }; val; }), + max); + + /* at this point real hardware should be NAKing transfers + * to that endpoint, until a buffer is queued to it. + */ + retval = 0; +done: + return retval; +} + +/* called with spinlock held */ +static void nuke (struct dummy *dum, struct dummy_ep *ep) +{ + while (!list_empty (&ep->queue)) { + struct dummy_request *req; + + req = list_entry (ep->queue.next, struct dummy_request, queue); + list_del_init (&req->queue); + req->req.status = -ESHUTDOWN; + + spin_unlock (&dum->lock); + req->req.complete (&ep->ep, &req->req); + spin_lock (&dum->lock); + } +} + +static int dummy_disable (struct usb_ep *_ep) +{ + struct dummy_ep *ep; + struct dummy *dum; + unsigned long flags; + int retval; + + ep = container_of (_ep, struct dummy_ep, ep); + if (!_ep || !ep->desc || _ep->name == ep0name) + return -EINVAL; + dum = ep_to_dummy (ep); + + spin_lock_irqsave (&dum->lock, flags); + ep->desc = 0; + retval = 0; + nuke (dum, ep); + spin_unlock_irqrestore (&dum->lock, flags); + + dev_dbg (hardware, "disabled %s\n", _ep->name); + return retval; +} + +static struct usb_request * +dummy_alloc_request (struct usb_ep *_ep, int mem_flags) +{ + struct dummy_ep *ep; + struct dummy_request *req; + + ep = container_of (_ep, struct dummy_ep, ep); + if (!_ep) + return 0; + + req = kmalloc (sizeof *req, mem_flags); + if (!req) + return 0; + memset (req, 0, sizeof *req); + INIT_LIST_HEAD (&req->queue); + return &req->req; +} + +static void +dummy_free_request (struct usb_ep *_ep, struct usb_request *_req) +{ + struct dummy_ep *ep; + struct dummy_request *req; + + ep = container_of (_ep, struct dummy_ep, ep); + if (!ep || !_req || (!ep->desc && _ep->name != ep0name)) + return; + + req = container_of (_req, struct dummy_request, req); + WARN_ON (!list_empty (&req->queue)); + kfree (req); +} + +static void * +dummy_alloc_buffer ( + struct usb_ep *_ep, + unsigned bytes, + dma_addr_t *dma, + int mem_flags +) { + char *retval; + + if (!the_controller->driver) + return 0; + retval = kmalloc (bytes, mem_flags); + *dma = (dma_addr_t) retval; + return retval; +} + +static void +dummy_free_buffer ( + struct usb_ep *_ep, + void *buf, + dma_addr_t dma, + unsigned bytes +) { + if (bytes) + kfree (buf); +} + +static void +fifo_complete (struct usb_ep *ep, struct usb_request *req) +{ +#if 0 + dev_dbg (hardware, "fifo_complete: %d\n", req->status); +#endif +} + +static int +dummy_queue (struct usb_ep *_ep, struct usb_request *_req, int mem_flags) +{ + struct dummy_ep *ep; + struct dummy_request *req; + struct dummy *dum; + unsigned long flags; + + req = container_of (_req, struct dummy_request, req); + if (!_req || !list_empty (&req->queue) || !_req->complete) + return -EINVAL; + + ep = container_of (_ep, struct dummy_ep, ep); + if (!_ep || (!ep->desc && _ep->name != ep0name)) + return -EINVAL; + + if (!the_controller->driver || !is_enabled ()) + return -ESHUTDOWN; + + dum = container_of (ep->gadget, struct dummy, gadget); + +#if 0 + dev_dbg (hardware, "ep %p queue req %p to %s, len %d buf %p\n", + ep, _req, _ep->name, _req->length, _req->buf); +#endif + + _req->status = -EINPROGRESS; + _req->actual = 0; + spin_lock_irqsave (&dum->lock, flags); + + /* implement an emulated single-request FIFO */ + if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) && + list_empty (&dum->fifo_req.queue) && + list_empty (&ep->queue) && + _req->length <= FIFO_SIZE) { + req = &dum->fifo_req; + req->req = *_req; + req->req.buf = dum->fifo_buf; + memcpy (dum->fifo_buf, _req->buf, _req->length); + req->req.context = dum; + req->req.complete = fifo_complete; + + spin_unlock (&dum->lock); + _req->actual = _req->length; + _req->status = 0; + _req->complete (_ep, _req); + spin_lock (&dum->lock); + } + list_add_tail (&req->queue, &ep->queue); + spin_unlock_irqrestore (&dum->lock, flags); + + /* real hardware would likely enable transfers here, in case + * it'd been left NAKing. + */ + return 0; +} + +static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req) +{ + struct dummy_ep *ep; + struct dummy *dum; + int retval = -EINVAL; + unsigned long flags; + struct dummy_request *req = 0; + + if (!the_controller->driver) + return -ESHUTDOWN; + + if (!_ep || !_req) + return retval; + ep = container_of (_ep, struct dummy_ep, ep); + dum = container_of (ep->gadget, struct dummy, gadget); + + spin_lock_irqsave (&dum->lock, flags); + list_for_each_entry (req, &ep->queue, queue) { + if (&req->req == _req) { + list_del_init (&req->queue); + _req->status = -ECONNRESET; + retval = 0; + break; + } + } + spin_unlock_irqrestore (&dum->lock, flags); + + if (retval == 0) { + dev_dbg (hardware, "dequeued req %p from %s, len %d buf %p\n", + req, _ep->name, _req->length, _req->buf); + + _req->complete (_ep, _req); + } + return retval; +} + +static int +dummy_set_halt (struct usb_ep *_ep, int value) +{ + struct dummy_ep *ep; + + if (!_ep) + return -EINVAL; + if (!the_controller->driver) + return -ESHUTDOWN; + ep = container_of (_ep, struct dummy_ep, ep); + if (!value) + ep->halted = 0; + else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) && + !list_empty (&ep->queue)) + return -EAGAIN; + else + ep->halted = 1; + /* FIXME clear emulated data toggle too */ + return 0; +} + +static const struct usb_ep_ops dummy_ep_ops = { + .enable = dummy_enable, + .disable = dummy_disable, + + .alloc_request = dummy_alloc_request, + .free_request = dummy_free_request, + + .alloc_buffer = dummy_alloc_buffer, + .free_buffer = dummy_free_buffer, + /* map, unmap, ... eventually hook the "generic" dma calls */ + + .queue = dummy_queue, + .dequeue = dummy_dequeue, + + .set_halt = dummy_set_halt, +}; + +/*-------------------------------------------------------------------------*/ + +/* there are both host and device side versions of this call ... */ +static int dummy_g_get_frame (struct usb_gadget *_gadget) +{ + struct timeval tv; + + do_gettimeofday (&tv); + return tv.tv_usec / 1000; +} + +static const struct usb_gadget_ops dummy_ops = { + .get_frame = dummy_g_get_frame, +}; + +/*-------------------------------------------------------------------------*/ + +/* "function" sysfs attribute */ +static ssize_t +show_function (struct device *_dev, char *buf) +{ + struct dummy *dum = the_controller; + + if (!dum->driver->function + || strlen (dum->driver->function) > PAGE_SIZE) + return 0; + return snprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function); +} +DEVICE_ATTR (function, S_IRUGO, show_function, NULL); + +/*-------------------------------------------------------------------------*/ + +/* + * Driver registration/unregistration. + * + * This is basically hardware-specific; there's usually only one real USB + * device (not host) controller since that's how USB devices are intended + * to work. So most implementations of these api calls will rely on the + * fact that only one driver will ever bind to the hardware. But curious + * hardware can be built with discrete components, so the gadget API doesn't + * require that assumption. + * + * For this emulator, it might be convenient to create a usb slave device + * for each driver that registers: just add to a big root hub. + */ + +static void +dummy_udc_release (struct device *dev) +{ + struct dummy *dum = gadget_dev_to_dummy (dev); + + complete (&dum->released); +} + +static void +dummy_hc_release (struct device *dev) +{ + struct dummy *dum = dev_get_drvdata (dev); + + complete (&dum->released); +} + +static int +dummy_register_udc (struct dummy *dum) +{ + int rc; + + strcpy (dum->gadget.dev.bus_id, "udc"); + dum->gadget.dev.parent = &dum->pdev.dev; + dum->gadget.dev.release = dummy_udc_release; + + rc = device_register (&dum->gadget.dev); + if (rc == 0) + device_create_file (&dum->gadget.dev, &dev_attr_function); + return rc; +} + +static void +dummy_unregister_udc (struct dummy *dum) +{ + device_remove_file (&dum->gadget.dev, &dev_attr_function); + init_completion (&dum->released); + device_unregister (&dum->gadget.dev); + wait_for_completion (&dum->released); +} + +int +usb_gadget_register_driver (struct usb_gadget_driver *driver) +{ + struct dummy *dum = the_controller; + int retval, i; + + if (!dum) + return -EINVAL; + if (dum->driver) + return -EBUSY; + if (!driver->bind || !driver->unbind || !driver->setup + || driver->speed == USB_SPEED_UNKNOWN) + return -EINVAL; + + /* + * SLAVE side init ... the layer above hardware, which + * can't enumerate without help from the driver we're binding. + */ + dum->gadget.name = gadget_name; + dum->gadget.ops = &dummy_ops; + dum->gadget.is_dualspeed = 1; + + INIT_LIST_HEAD (&dum->gadget.ep_list); + for (i = 0; i < DUMMY_ENDPOINTS; i++) { + struct dummy_ep *ep = &dum->ep [i]; + + if (!ep_name [i]) + break; + ep->ep.name = ep_name [i]; + ep->ep.ops = &dummy_ep_ops; + list_add_tail (&ep->ep.ep_list, &dum->gadget.ep_list); + ep->halted = ep->already_seen = ep->setup_stage = 0; + ep->ep.maxpacket = ~0; + ep->last_io = jiffies; + ep->gadget = &dum->gadget; + ep->desc = 0; + INIT_LIST_HEAD (&ep->queue); + } + + dum->gadget.ep0 = &dum->ep [0].ep; + dum->ep [0].ep.maxpacket = 64; + list_del_init (&dum->ep [0].ep.ep_list); + INIT_LIST_HEAD(&dum->fifo_req.queue); + + dum->driver = driver; + dum->gadget.dev.driver = &driver->driver; + dev_dbg (hardware, "binding gadget driver '%s'\n", driver->driver.name); + if ((retval = driver->bind (&dum->gadget)) != 0) { + dum->driver = 0; + dum->gadget.dev.driver = 0; + return retval; + } + + // FIXME: Check these calls for errors and re-order + driver->driver.bus = dum->pdev.dev.bus; + driver_register (&driver->driver); + + device_bind_driver (&dum->gadget.dev); + + /* khubd will enumerate this in a while */ + dum->port_status |= USB_PORT_STAT_CONNECTION + | (1 << USB_PORT_FEAT_C_CONNECTION); + return 0; +} +EXPORT_SYMBOL (usb_gadget_register_driver); + +/* caller must hold lock */ +static void +stop_activity (struct dummy *dum, struct usb_gadget_driver *driver) +{ + struct dummy_ep *ep; + + /* prevent any more requests */ + dum->hdev = 0; + dum->address = 0; + + /* this might not succeed ... */ + del_timer (&dum->timer); + + /* nuke any pending requests first, so driver i/o is quiesced */ + list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list) + nuke (dum, ep); + + /* driver now does any non-usb quiescing necessary */ + if (driver) { + spin_unlock (&dum->lock); + driver->disconnect (&dum->gadget); + spin_lock (&dum->lock); + } +} + +int +usb_gadget_unregister_driver (struct usb_gadget_driver *driver) +{ + struct dummy *dum = the_controller; + unsigned long flags; + + if (!dum) + return -ENODEV; + if (!driver || driver != dum->driver) + return -EINVAL; + + dev_dbg (hardware, "unregister gadget driver '%s'\n", + driver->driver.name); + + spin_lock_irqsave (&dum->lock, flags); + stop_activity (dum, driver); + dum->port_status &= ~USB_PORT_STAT_CONNECTION; + dum->port_status |= (1 << USB_PORT_FEAT_C_CONNECTION); + spin_unlock_irqrestore (&dum->lock, flags); + + driver->unbind (&dum->gadget); + dum->driver = 0; + + device_release_driver (&dum->gadget.dev); + + driver_unregister (&driver->driver); + + del_timer_sync (&dum->timer); + return 0; +} +EXPORT_SYMBOL (usb_gadget_unregister_driver); + +#undef is_enabled + +int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode) +{ + return -ENOSYS; +} +EXPORT_SYMBOL (net2280_set_fifo_mode); + +/*-------------------------------------------------------------------------*/ + +/* MASTER/HOST SIDE DRIVER + * + * this uses the hcd framework to hook up to host side drivers. + * its root hub will only have one device, otherwise it acts like + * a normal host controller. + * + * when urbs are queued, they're just stuck on a list that we + * scan in a timer callback. that callback connects writes from + * the host with reads from the device, and so on, based on the + * usb 2.0 rules. + */ + +static int dummy_urb_enqueue ( + struct usb_hcd *hcd, + struct urb *urb, + int mem_flags +) { + struct dummy *dum; + unsigned long flags; + + /* patch to usb_sg_init() is in 2.5.60 */ + BUG_ON (!urb->transfer_buffer && urb->transfer_buffer_length); + + dum = container_of (hcd, struct dummy, hcd); + spin_lock_irqsave (&dum->lock, flags); + + if (!dum->hdev) + dum->hdev = urb->dev->hcpriv; + urb->hcpriv = dum; + if (usb_pipetype (urb->pipe) == PIPE_CONTROL) + urb->error_count = 1; /* mark as a new urb */ + + /* kick the scheduler, it'll do the rest */ + if (!timer_pending (&dum->timer)) + mod_timer (&dum->timer, jiffies + 1); + + spin_unlock_irqrestore (&dum->lock, flags); + return 0; +} + +static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) +{ + /* giveback happens automatically in timer callback */ + return 0; +} + +static void maybe_set_status (struct urb *urb, int status) +{ + spin_lock (&urb->lock); + if (urb->status == -EINPROGRESS) + urb->status = status; + spin_unlock (&urb->lock); +} + +/* transfer up to a frame's worth; caller must own lock */ +static int +transfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit) +{ + struct dummy_request *req; + +top: + /* if there's no request queued, the device is NAKing; return */ + list_for_each_entry (req, &ep->queue, queue) { + unsigned host_len, dev_len, len; + int is_short, to_host; + int rescan = 0; + + /* 1..N packets of ep->ep.maxpacket each ... the last one + * may be short (including zero length). + * + * writer can send a zlp explicitly (length 0) or implicitly + * (length mod maxpacket zero, and 'zero' flag); they always + * terminate reads. + */ + host_len = urb->transfer_buffer_length - urb->actual_length; + dev_len = req->req.length - req->req.actual; + len = min (host_len, dev_len); + + /* FIXME update emulated data toggle too */ + + to_host = usb_pipein (urb->pipe); + if (unlikely (len == 0)) + is_short = 1; + else { + char *ubuf, *rbuf; + + /* not enough bandwidth left? */ + if (limit < ep->ep.maxpacket && limit < len) + break; + len = min (len, (unsigned) limit); + if (len == 0) + break; + + /* use an extra pass for the final short packet */ + if (len > ep->ep.maxpacket) { + rescan = 1; + len -= (len % ep->ep.maxpacket); + } + is_short = (len % ep->ep.maxpacket) != 0; + + /* else transfer packet(s) */ + ubuf = urb->transfer_buffer + urb->actual_length; + rbuf = req->req.buf + req->req.actual; + if (to_host) + memcpy (ubuf, rbuf, len); + else + memcpy (rbuf, ubuf, len); + ep->last_io = jiffies; + + limit -= len; + urb->actual_length += len; + req->req.actual += len; + } + + /* short packets terminate, maybe with overflow/underflow. + * it's only really an error to write too much. + * + * partially filling a buffer optionally blocks queue advances + * (so completion handlers can clean up the queue) but we don't + * need to emulate such data-in-flight. so we only show part + * of the URB_SHORT_NOT_OK effect: completion status. + */ + if (is_short) { + if (host_len == dev_len) { + req->req.status = 0; + maybe_set_status (urb, 0); + } else if (to_host) { + req->req.status = 0; + if (dev_len > host_len) + maybe_set_status (urb, -EOVERFLOW); + else + maybe_set_status (urb, + (urb->transfer_flags + & URB_SHORT_NOT_OK) + ? -EREMOTEIO : 0); + } else if (!to_host) { + maybe_set_status (urb, 0); + if (host_len > dev_len) + req->req.status = -EOVERFLOW; + else + req->req.status = 0; + } + + /* many requests terminate without a short packet */ + } else { + if (req->req.length == req->req.actual + && !req->req.zero) + req->req.status = 0; + if (urb->transfer_buffer_length == urb->actual_length + && !(urb->transfer_flags + & URB_ZERO_PACKET)) { + maybe_set_status (urb, 0); + } + } + + /* device side completion --> continuable */ + if (req->req.status != -EINPROGRESS) { + list_del_init (&req->queue); + + spin_unlock (&dum->lock); + req->req.complete (&ep->ep, &req->req); + spin_lock (&dum->lock); + + /* requests might have been unlinked... */ + rescan = 1; + } + + /* host side completion --> terminate */ + if (urb->status != -EINPROGRESS) + break; + + /* rescan to continue with any other queued i/o */ + if (rescan) + goto top; + } + return limit; +} + +static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep) +{ + int limit = ep->ep.maxpacket; + + if (dum->gadget.speed == USB_SPEED_HIGH) { + int tmp; + + /* high bandwidth mode */ + tmp = ep->desc->wMaxPacketSize; + tmp = le16_to_cpu (tmp); + tmp = (tmp >> 11) & 0x03; + tmp *= 8 /* applies to entire frame */; + limit += limit * tmp; + } + return limit; +} + +static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address) +{ + int i; + + if ((address & ~USB_DIR_IN) == 0) + return &dum->ep [0]; + for (i = 1; i < DUMMY_ENDPOINTS; i++) { + struct dummy_ep *ep = &dum->ep [i]; + + if (!ep->desc) + continue; + if (ep->desc->bEndpointAddress == address) + return ep; + } + return NULL; +} + +#define Dev_Request (USB_TYPE_STANDARD | USB_RECIP_DEVICE) +#define Dev_InRequest (Dev_Request | USB_DIR_IN) +#define Intf_Request (USB_TYPE_STANDARD | USB_RECIP_INTERFACE) +#define Intf_InRequest (Intf_Request | USB_DIR_IN) +#define Ep_Request (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT) +#define Ep_InRequest (Ep_Request | USB_DIR_IN) + +/* drive both sides of the transfers; looks like irq handlers to + * both drivers except the callbacks aren't in_irq(). + */ +static void dummy_timer (unsigned long _dum) +{ + struct dummy *dum = (struct dummy *) _dum; + struct hcd_dev *hdev = dum->hdev; + struct list_head *entry, *tmp; + unsigned long flags; + int limit, total; + int i; + + if (!hdev) { + dev_err (hardware, "timer fired with device gone?\n"); + return; + } + + /* simplistic model for one frame's bandwidth */ + switch (dum->gadget.speed) { + case USB_SPEED_LOW: + total = 8/*bytes*/ * 12/*packets*/; + break; + case USB_SPEED_FULL: + total = 64/*bytes*/ * 19/*packets*/; + break; + case USB_SPEED_HIGH: + total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/; + break; + default: + dev_err (hardware, "bogus device speed\n"); + return; + } + + /* FIXME if HZ != 1000 this will probably misbehave ... */ + + /* look at each urb queued by the host side driver */ + spin_lock_irqsave (&dum->lock, flags); + for (i = 0; i < DUMMY_ENDPOINTS; i++) { + if (!ep_name [i]) + break; + dum->ep [i].already_seen = 0; + } + +restart: + list_for_each_safe (entry, tmp, &hdev->urb_list) { + struct urb *urb; + struct dummy_request *req; + u8 address; + struct dummy_ep *ep = 0; + int type; + + urb = list_entry (entry, struct urb, urb_list); + if (urb->status != -EINPROGRESS) { + /* likely it was just unlinked */ + goto return_urb; + } + type = usb_pipetype (urb->pipe); + + /* used up this frame's non-periodic bandwidth? + * FIXME there's infinite bandwidth for control and + * periodic transfers ... unrealistic. + */ + if (total <= 0 && type == PIPE_BULK) + continue; + + /* find the gadget's ep for this request (if configured) */ + address = usb_pipeendpoint (urb->pipe); + if (usb_pipein (urb->pipe)) + address |= USB_DIR_IN; + ep = find_endpoint(dum, address); + if (!ep) { + /* set_configuration() disagreement */ + dev_err (hardware, + "no ep configured for urb %p\n", + urb); + maybe_set_status (urb, -ETIMEDOUT); + goto return_urb; + } + + if (ep->already_seen) + continue; + ep->already_seen = 1; + if (ep == &dum->ep [0] && urb->error_count) { + ep->setup_stage = 1; /* a new urb */ + urb->error_count = 0; + } + if (ep->halted && !ep->setup_stage) { + /* NOTE: must not be iso! */ + dev_dbg (hardware, "ep %s halted, urb %p\n", + ep->ep.name, urb); + maybe_set_status (urb, -EPIPE); + goto return_urb; + } + /* FIXME make sure both ends agree on maxpacket */ + + /* handle control requests */ + if (ep == &dum->ep [0] && ep->setup_stage) { + struct usb_ctrlrequest setup; + int value = 1; + struct dummy_ep *ep2; + + setup = *(struct usb_ctrlrequest*) urb->setup_packet; + le16_to_cpus (&setup.wIndex); + le16_to_cpus (&setup.wValue); + le16_to_cpus (&setup.wLength); + if (setup.wLength != urb->transfer_buffer_length) { + maybe_set_status (urb, -EOVERFLOW); + goto return_urb; + } + + /* paranoia, in case of stale queued data */ + list_for_each_entry (req, &ep->queue, queue) { + list_del_init (&req->queue); + req->req.status = -EOVERFLOW; + dev_dbg (hardware, "stale req = %p\n", req); + + spin_unlock (&dum->lock); + req->req.complete (&ep->ep, &req->req); + spin_lock (&dum->lock); + ep->already_seen = 0; + goto restart; + } + + /* gadget driver never sees set_address or operations + * on standard feature flags. some hardware doesn't + * even expose them. + */ + ep->last_io = jiffies; + ep->setup_stage = 0; + ep->halted = 0; + switch (setup.bRequest) { + case USB_REQ_SET_ADDRESS: + if (setup.bRequestType != Dev_Request) + break; + if (dum->address != 0) { + maybe_set_status (urb, -ETIMEDOUT); + urb->actual_length = 0; + goto return_urb; + } + dum->address = setup.wValue; + maybe_set_status (urb, 0); + dev_dbg (hardware, "set_address = %d\n", + setup.wValue); + value = 0; + break; + case USB_REQ_SET_FEATURE: + if (setup.bRequestType == Dev_Request) { + // remote wakeup, and (hs) test mode + value = -EOPNOTSUPP; + } else if (setup.bRequestType == Ep_Request) { + // endpoint halt + ep2 = find_endpoint (dum, + setup.wIndex); + if (!ep2) { + value = -EOPNOTSUPP; + break; + } + ep2->halted = 1; + value = 0; + maybe_set_status (urb, 0); + } + break; + case USB_REQ_CLEAR_FEATURE: + if (setup.bRequestType == Dev_Request) { + // remote wakeup + value = 0; + maybe_set_status (urb, 0); + } else if (setup.bRequestType == Ep_Request) { + // endpoint halt + ep2 = find_endpoint (dum, + setup.wIndex); + if (!ep2) { + value = -EOPNOTSUPP; + break; + } + ep2->halted = 0; + value = 0; + maybe_set_status (urb, 0); + } + break; + case USB_REQ_GET_STATUS: + if (setup.bRequestType == Dev_InRequest + || setup.bRequestType + == Intf_InRequest + || setup.bRequestType + == Ep_InRequest + ) { + char *buf; + + // device: remote wakeup, selfpowered + // interface: nothing + // endpoint: halt + buf = (char *)urb->transfer_buffer; + if (urb->transfer_buffer_length > 0) { + if (setup.bRequestType == + Ep_InRequest) { + ep2 = find_endpoint (dum, setup.wIndex); + if (!ep2) { + value = -EOPNOTSUPP; + break; + } + buf [0] = ep2->halted; + } else + buf [0] = 0; + } + if (urb->transfer_buffer_length > 1) + buf [1] = 0; + urb->actual_length = min (2, + urb->transfer_buffer_length); + value = 0; + maybe_set_status (urb, 0); + } + break; + } + + /* gadget driver handles all other requests. block + * until setup() returns; no reentrancy issues etc. + */ + if (value > 0) { + spin_unlock (&dum->lock); + value = dum->driver->setup (&dum->gadget, + &setup); + spin_lock (&dum->lock); + + if (value >= 0) { + /* no delays (max 64KB data stage) */ + limit = 64*1024; + goto treat_control_like_bulk; + } + /* error, see below */ + } + + if (value < 0) { + if (value != -EOPNOTSUPP) + dev_dbg (hardware, + "setup --> %d\n", + value); + maybe_set_status (urb, -EPIPE); + urb->actual_length = 0; + } + + goto return_urb; + } + + /* non-control requests */ + limit = total; + switch (usb_pipetype (urb->pipe)) { + case PIPE_ISOCHRONOUS: + /* FIXME is it urb->interval since the last xfer? + * use urb->iso_frame_desc[i]. + * complete whether or not ep has requests queued. + * report random errors, to debug drivers. + */ + limit = max (limit, periodic_bytes (dum, ep)); + maybe_set_status (urb, -ENOSYS); + break; + + case PIPE_INTERRUPT: + /* FIXME is it urb->interval since the last xfer? + * this almost certainly polls too fast. + */ + limit = max (limit, periodic_bytes (dum, ep)); + /* FALLTHROUGH */ + + // case PIPE_BULK: case PIPE_CONTROL: + default: + treat_control_like_bulk: + ep->last_io = jiffies; + total = transfer (dum, urb, ep, limit); + break; + } + + /* incomplete transfer? */ + if (urb->status == -EINPROGRESS) + continue; + +return_urb: + urb->hcpriv = 0; + if (ep) + ep->already_seen = ep->setup_stage = 0; + + spin_unlock (&dum->lock); + usb_hcd_giveback_urb (&dum->hcd, urb, 0); + spin_lock (&dum->lock); + + goto restart; + } + + /* want a 1 msec delay here */ + if (!list_empty (&hdev->urb_list)) + mod_timer (&dum->timer, jiffies + 1); + + spin_unlock_irqrestore (&dum->lock, flags); +} + +/*-------------------------------------------------------------------------*/ + +#define PORT_C_MASK \ + ((1 << USB_PORT_FEAT_C_CONNECTION) \ + | (1 << USB_PORT_FEAT_C_ENABLE) \ + | (1 << USB_PORT_FEAT_C_SUSPEND) \ + | (1 << USB_PORT_FEAT_C_OVER_CURRENT) \ + | (1 << USB_PORT_FEAT_C_RESET)) + +static int dummy_hub_status (struct usb_hcd *hcd, char *buf) +{ + struct dummy *dum; + unsigned long flags; + int retval; + + dum = container_of (hcd, struct dummy, hcd); + + spin_lock_irqsave (&dum->lock, flags); + if (!(dum->port_status & PORT_C_MASK)) + retval = 0; + else { + *buf = (1 << 1); + dev_dbg (hardware, "port status 0x%08x has changes\n", + dum->port_status); + retval = 1; + } + spin_unlock_irqrestore (&dum->lock, flags); + return retval; +} + +static inline void +hub_descriptor (struct usb_hub_descriptor *desc) +{ + memset (desc, 0, sizeof *desc); + desc->bDescriptorType = 0x29; + desc->bDescLength = 9; + desc->wHubCharacteristics = __constant_cpu_to_le16 (0x0001); + desc->bNbrPorts = 1; + desc->bitmap [0] = 0xff; + desc->bitmap [1] = 0xff; +} + +static int dummy_hub_control ( + struct usb_hcd *hcd, + u16 typeReq, + u16 wValue, + u16 wIndex, + char *buf, + u16 wLength +) { + struct dummy *dum; + int retval = 0; + unsigned long flags; + + dum = container_of (hcd, struct dummy, hcd); + spin_lock_irqsave (&dum->lock, flags); + switch (typeReq) { + case ClearHubFeature: + break; + case ClearPortFeature: + // FIXME won't some of these need special handling? + dum->port_status &= ~(1 << wValue); + break; + case GetHubDescriptor: + hub_descriptor ((struct usb_hub_descriptor *) buf); + break; + case GetHubStatus: + *(u32 *) buf = __constant_cpu_to_le32 (0); + break; + case GetPortStatus: + if (wIndex != 1) + retval = -EPIPE; + ((u16 *) buf)[0] = cpu_to_le16 (dum->port_status); + ((u16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16); + break; + case SetHubFeature: + retval = -EPIPE; + break; + case SetPortFeature: + if (wValue == USB_PORT_FEAT_RESET) { + /* if it's already running, disconnect first */ + if (dum->port_status & USB_PORT_STAT_ENABLE) { + dum->port_status &= ~(USB_PORT_STAT_ENABLE + | USB_PORT_STAT_LOW_SPEED + | USB_PORT_STAT_HIGH_SPEED); + if (dum->driver) { + dev_dbg (hardware, "disconnect\n"); + stop_activity (dum, dum->driver); + } + + /* FIXME test that code path! */ + } else + dum->port_status |= + (1 << USB_PORT_FEAT_C_ENABLE); + + dum->port_status |= USB_PORT_STAT_ENABLE | + (1 << USB_PORT_FEAT_C_RESET); + if (dum->driver) { + + /* give it the best speed we agree on */ + dum->gadget.speed = dum->driver->speed; + dum->gadget.ep0->maxpacket = 64; + switch (dum->gadget.speed) { + case USB_SPEED_HIGH: + dum->port_status |= + USB_PORT_STAT_HIGH_SPEED; + break; + case USB_SPEED_LOW: + dum->gadget.ep0->maxpacket = 8; + dum->port_status |= + USB_PORT_STAT_LOW_SPEED; + break; + default: + dum->gadget.speed = USB_SPEED_FULL; + break; + } + } + } else + dum->port_status |= (1 << wValue); + break; + + default: + dev_dbg (hardware, + "hub control req%04x v%04x i%04x l%d\n", + typeReq, wValue, wIndex, wLength); + + /* "protocol stall" on error */ + retval = -EPIPE; + } + spin_unlock_irqrestore (&dum->lock, flags); + return retval; +} + + +/*-------------------------------------------------------------------------*/ + +static struct usb_hcd *dummy_alloc (void) +{ + struct dummy *dum; + + dum = kmalloc (sizeof *dum, SLAB_KERNEL); + if (dum == NULL) + return 0; + memset (dum, 0, sizeof *dum); + return &dum->hcd; +} + +static void dummy_free (struct usb_hcd *hcd) +{ + struct dummy *dum; + + dum = container_of (hcd, struct dummy, hcd); + WARN_ON (dum->driver != 0); + kfree (dum); +} + +/*-------------------------------------------------------------------------*/ + +static inline ssize_t +show_urb (char *buf, size_t size, struct urb *urb) +{ + int ep = usb_pipeendpoint (urb->pipe); + + return snprintf (buf, size, + "urb/%p %s ep%d%s%s len %d/%d\n", + urb, + ({ char *s; + switch (urb->dev->speed) { + case USB_SPEED_LOW: s = "ls"; break; + case USB_SPEED_FULL: s = "fs"; break; + case USB_SPEED_HIGH: s = "hs"; break; + default: s = "?"; break; + }; s; }), + ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "", + ({ char *s; \ + switch (usb_pipetype (urb->pipe)) { \ + case PIPE_CONTROL: s = ""; break; \ + case PIPE_BULK: s = "-bulk"; break; \ + case PIPE_INTERRUPT: s = "-int"; break; \ + default: s = "-iso"; break; \ + }; s;}), + urb->actual_length, urb->transfer_buffer_length); +} + +static ssize_t +show_urbs (struct device *dev, char *buf) +{ + struct dummy *dum = dev_get_drvdata(dev); + struct urb *urb; + size_t size = 0; + unsigned long flags; + + spin_lock_irqsave (&dum->lock, flags); + if (dum->hdev) { + list_for_each_entry (urb, &dum->hdev->urb_list, urb_list) { + size_t temp; + + temp = show_urb (buf, PAGE_SIZE - size, urb); + buf += temp; + size += temp; + } + } + spin_unlock_irqrestore (&dum->lock, flags); + + return size; +} +static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL); + + +static const struct hc_driver dummy_hcd; + +static int dummy_start (struct usb_hcd *hcd) +{ + struct dummy *dum; + struct usb_bus *bus; + struct usb_device *root; + int retval; + + dum = container_of (hcd, struct dummy, hcd); + + /* + * MASTER side init ... we emulate a root hub that'll only ever + * talk to one device (the slave side). Also appears in sysfs, + * just like more familiar pci-based HCDs. + */ + spin_lock_init (&dum->lock); + + retval = driver_register (&dummy_driver); + if (retval < 0) + return retval; + + dum->pdev.name = "hc"; + dum->pdev.dev.driver = &dummy_driver; + dev_set_drvdata(&dum->pdev.dev, dum); + dum->pdev.dev.release = dummy_hc_release; + retval = platform_device_register (&dum->pdev); + if (retval < 0) { + driver_unregister (&dummy_driver); + return retval; + } + dev_info (&dum->pdev.dev, "%s, driver " DRIVER_VERSION "\n", + driver_desc); + + hcd->self.controller = &dum->pdev.dev; + + /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ + device_create_file (hcd->self.controller, &dev_attr_urbs); + + init_timer (&dum->timer); + dum->timer.function = dummy_timer; + dum->timer.data = (unsigned long) dum; + + /* root hub will appear as another device */ + dum->hcd.driver = (struct hc_driver *) &dummy_hcd; + dum->hcd.description = dummy_hcd.description; + dum->hcd.product_desc = "Dummy host controller"; + + bus = hcd_to_bus (&dum->hcd); + bus->bus_name = dum->pdev.dev.bus_id; + usb_bus_init (bus); + bus->op = &usb_hcd_operations; + bus->hcpriv = &dum->hcd; + + /* FIXME don't require the pci-based buffer/alloc impls; + * the "generic dma" implementation still requires them, + * it's not very generic yet. + */ + if ((retval = hcd_buffer_create (&dum->hcd)) != 0) { +clean0: + init_completion (&dum->released); + platform_device_unregister (&dum->pdev); + wait_for_completion (&dum->released); + driver_unregister (&dummy_driver); + return retval; + } + + INIT_LIST_HEAD (&hcd->dev_list); + usb_register_bus (bus); + + bus->root_hub = root = usb_alloc_dev (0, bus, 0); + if (!root) { + retval = -ENOMEM; +clean1: + hcd_buffer_destroy (&dum->hcd); + usb_deregister_bus (bus); + goto clean0; + } + + /* root hub enters addressed state... */ + dum->hcd.state = USB_STATE_RUNNING; + root->speed = USB_SPEED_HIGH; + + /* ...then configured, so khubd sees us. */ + if ((retval = hcd_register_root (&dum->hcd)) != 0) { + bus->root_hub = 0; + usb_put_dev (root); +clean2: + dum->hcd.state = USB_STATE_QUIESCING; + goto clean1; + } + + dum->started = 1; + + if ((retval = dummy_register_udc (dum)) != 0) { + dum->started = 0; + usb_disconnect (&bus->root_hub); + goto clean2; + } + return 0; +} + +static void dummy_stop (struct usb_hcd *hcd) +{ + struct dummy *dum; + struct usb_bus *bus; + + dum = container_of (hcd, struct dummy, hcd); + if (!dum->started) + return; + dum->started = 0; + + usb_gadget_unregister_driver (dum->driver); + dummy_unregister_udc (dum); + + bus = hcd_to_bus (&dum->hcd); + hcd->state = USB_STATE_QUIESCING; + dev_dbg (hardware, "remove root hub\n"); + usb_disconnect (&bus->root_hub); + + hcd_buffer_destroy (&dum->hcd); + usb_deregister_bus (bus); + + dev_info (hardware, "stopped\n"); + + device_remove_file (hcd->self.controller, &dev_attr_urbs); + init_completion (&dum->released); + platform_device_unregister (&dum->pdev); + wait_for_completion (&dum->released); + + driver_unregister (&dummy_driver); +} + +/*-------------------------------------------------------------------------*/ + +static int dummy_h_get_frame (struct usb_hcd *hcd) +{ + return dummy_g_get_frame (0); +} + +static const struct hc_driver dummy_hcd = { + .description = (char *) driver_name, + .flags = HCD_USB2, + + .start = dummy_start, + .stop = dummy_stop, + + .hcd_alloc = dummy_alloc, + .hcd_free = dummy_free, + + .urb_enqueue = dummy_urb_enqueue, + .urb_dequeue = dummy_urb_dequeue, + + .get_frame_number = dummy_h_get_frame, + + .hub_status_data = dummy_hub_status, + .hub_control = dummy_hub_control, +}; + +/*-------------------------------------------------------------------------*/ + +static int __init init (void) +{ + struct usb_hcd *hcd; + int value; + + if (usb_disabled ()) + return -ENODEV; + if ((hcd = dummy_alloc ()) == 0) + return -ENOMEM; + + the_controller = container_of (hcd, struct dummy, hcd); + value = dummy_start (hcd); + + if (value != 0) { + dummy_free (hcd); + the_controller = 0; + } + return value; +} +module_init (init); + +static void __exit cleanup (void) +{ + dummy_stop (&the_controller->hcd); + dummy_free (&the_controller->hcd); + the_controller = 0; +} +module_exit (cleanup); + diff -Nru a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/gadget/epautoconf.c Tue Apr 6 17:22:26 2004 @@ -0,0 +1,306 @@ +/* + * epautoconf.c -- endpoint autoconfiguration for usb gadget drivers + * + * Copyright (C) 2004 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "gadget_chips.h" + + +/* we must assign addresses for configurable endpoints (like net2280) */ +static __initdata unsigned epnum; + +// #define MANY_ENDPOINTS +#ifdef MANY_ENDPOINTS +/* more than 15 configurable endpoints */ +static __initdata unsigned in_epnum; +#endif + + +/* + * This should work with endpoints from controller drivers sharing the + * same endpoint naming convention. By example: + * + * - ep1, ep2, ... address is fixed, not direction or type + * - ep1in, ep2out, ... address and direction are fixed, not type + * - ep1-bulk, ep2-bulk, ... address and type are fixed, not direction + * - ep1in-bulk, ep2out-iso, ... all three are fixed + * - ep-* ... no functionality restrictions + * + * Type suffixes are "-bulk", "-iso", or "-int". Numbers are decimal. + * Less common restrictions are implied by gadget_is_*(). + */ +static int __init +ep_matches ( + struct usb_gadget *gadget, + struct usb_ep *ep, + struct usb_endpoint_descriptor *desc +) +{ + u8 type; + const char *tmp; + u16 max; + + /* endpoint already claimed? */ + if (0 != ep->driver_data) + return 0; + + /* only support ep0 for portable CONTROL traffic */ + type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + if (USB_ENDPOINT_XFER_CONTROL == type) + return 0; + + /* some other naming convention */ + if ('e' != ep->name[0]) + return 0; + + /* type-restriction: "-iso", "-bulk", or "-int". + * direction-restriction: "in", "out". + */ + if ('-' != ep->name[2]) { + tmp = strrchr (ep->name, '-'); + if (tmp) { + switch (type) { + case USB_ENDPOINT_XFER_INT: + /* bulk endpoints handle interrupt transfers, + * except the toggle-quirky iso-synch kind + */ + if ('s' == tmp[2]) // == "-iso" + return 0; + /* for now, avoid PXA "interrupt-in"; + * it's documented as never using DATA1. + */ + if (gadget_is_pxa (gadget)) + return 0; + break; + case USB_ENDPOINT_XFER_BULK: + if ('b' != tmp[1]) // != "-bulk" + return 0; + break; + case USB_ENDPOINT_XFER_ISOC: + if ('s' != tmp[2]) // != "-iso" + return 0; + } + } else { + tmp = ep->name + strlen (ep->name); + } + + /* direction-restriction: "..in-..", "out-.." */ + tmp--; + if (!isdigit (*tmp)) { + if (desc->bEndpointAddress & USB_DIR_IN) { + if ('n' != *tmp) + return 0; + } else { + if ('t' != *tmp) + return 0; + } + } + } + + /* endpoint maxpacket size is an input parameter, except for bulk + * where it's an output parameter representing the full speed limit. + * the usb spec fixes high speed bulk maxpacket at 512 bytes. + */ + max = 0x7ff & le16_to_cpup (&desc->wMaxPacketSize); + switch (type) { + case USB_ENDPOINT_XFER_INT: + /* INT: limit 64 bytes full speed, 1024 high speed */ + if (!gadget->is_dualspeed && max > 64) + return 0; + /* FALLTHROUGH */ + + case USB_ENDPOINT_XFER_ISOC: + /* ISO: limit 1023 bytes full speed, 1024 high speed */ + if (ep->maxpacket < max) + return 0; + if (!gadget->is_dualspeed && max > 1023) + return 0; + + /* BOTH: "high bandwidth" works only at high speed */ + if ((desc->wMaxPacketSize & __constant_cpu_to_le16(3<<11))) { + if (!gadget->is_dualspeed) + return 0; + /* configure your hardware with enough buffering!! */ + } + break; + } + + /* MATCH!! */ + + /* report address */ + if (isdigit (ep->name [2])) { + u8 num = simple_strtol (&ep->name [2], NULL, 10); + desc->bEndpointAddress |= num; +#ifdef MANY_ENDPOINTS + } else if (desc->bEndpointAddress & USB_DIR_IN) { + if (++in_epnum > 15) + return 0; + desc->bEndpointAddress = USB_DIR_IN | in_epnum; +#endif + } else { + if (++epnum > 15) + return 0; + desc->bEndpointAddress |= epnum; + } + + /* report (variable) full speed bulk maxpacket */ + if (USB_ENDPOINT_XFER_BULK == type) { + int size = ep->maxpacket; + + /* min() doesn't work on bitfields with gcc-3.5 */ + if (size > 64) + size = 64; + desc->wMaxPacketSize = cpu_to_le16(size); + } + return 1; +} + +static struct usb_ep * __init +find_ep (struct usb_gadget *gadget, const char *name) +{ + struct usb_ep *ep; + + list_for_each_entry (ep, &gadget->ep_list, ep_list) { + if (0 == strcmp (ep->name, name)) + return ep; + } + return 0; +} + +/** + * usb_ep_autoconfig - choose an endpoint matching the descriptor + * @gadget: The device to which the endpoint must belong. + * @desc: Endpoint descriptor, with endpoint direction and transfer mode + * initialized. For periodic transfers, the maximum packet + * size must also be initialized. This is modified on success. + * + * By choosing an endpoint to use with the specified descriptor, this + * routine simplifies writing gadget drivers that work with multiple + * USB device controllers. The endpoint would be passed later to + * usb_ep_enable(), along with some descriptor. + * + * That second descriptor won't always be the same as the first one. + * For example, isochronous endpoints can be autoconfigured for high + * bandwidth, and then used in several lower bandwidth altsettings. + * Also, high and full speed descriptors will be different. + * + * Be sure to examine and test the results of autoconfiguration on your + * hardware. This code may not make the best choices about how to use the + * USB controller, and it can't know all the restrictions that may apply. + * Some combinations of driver and hardware won't be able to autoconfigure. + * + * On success, this returns an un-claimed usb_ep, and modifies the endpoint + * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value + * is initialized as if the endpoint were used at full speed. To prevent + * the endpoint from being returned by a later autoconfig call, claim it + * by assigning ep->driver_data to some non-null value. + * + * On failure, this returns a null endpoint descriptor. + */ +struct usb_ep * __init usb_ep_autoconfig ( + struct usb_gadget *gadget, + struct usb_endpoint_descriptor *desc +) +{ + struct usb_ep *ep; + u8 type; + + type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + + /* First, apply chip-specific "best usage" knowledge. + * This might make a good usb_gadget_ops hook ... + */ + if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) { + /* ep-e, ep-f are PIO with only 64 byte fifos */ + ep = find_ep (gadget, "ep-e"); + if (ep && ep_matches (gadget, ep, desc)) + return ep; + ep = find_ep (gadget, "ep-f"); + if (ep && ep_matches (gadget, ep, desc)) + return ep; + + } else if (gadget_is_goku (gadget)) { + if (USB_ENDPOINT_XFER_INT == type) { + /* single buffering is enough */ + ep = find_ep (gadget, "ep3-bulk"); + if (ep && ep_matches (gadget, ep, desc)) + return ep; + } else if (USB_ENDPOINT_XFER_BULK == type + && (USB_DIR_IN & desc->bEndpointAddress)) { + /* DMA may be available */ + ep = find_ep (gadget, "ep2-bulk"); + if (ep && ep_matches (gadget, ep, desc)) + return ep; + } + + } else if (gadget_is_sh (gadget) && USB_ENDPOINT_XFER_INT == type) { + /* single buffering is enough; maybe 8 byte fifo is too */ + ep = find_ep (gadget, "ep3in-bulk"); + if (ep && ep_matches (gadget, ep, desc)) + return ep; + + } else if (gadget_is_mq11xx (gadget) && USB_ENDPOINT_XFER_INT == type) { + ep = find_ep (gadget, "ep1-bulk"); + if (ep && ep_matches (gadget, ep, desc)) + return ep; + } + + /* Second, look at endpoints until an unclaimed one looks usable */ + list_for_each_entry (ep, &gadget->ep_list, ep_list) { + if (ep_matches (gadget, ep, desc)) + return ep; + } + + /* Fail */ + return 0; +} + +/** + * usb_ep_autoconfig_reset - reset endpoint autoconfig state + * @gadget: device for which autoconfig state will be reset + * + * Use this for devices where one configuration may need to assign + * endpoint resources very differently from the next one. It clears + * state such as ep->driver_data and the record of assigned endpoints + * used by usb_ep_autoconfig(). + */ +void __init usb_ep_autoconfig_reset (struct usb_gadget *gadget) +{ + struct usb_ep *ep; + + list_for_each_entry (ep, &gadget->ep_list, ep_list) { + ep->driver_data = 0; + } +#ifdef MANY_ENDPOINTS + in_epnum = 0; +#endif + epnum = 0; +} + diff -Nru a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c --- a/drivers/usb/gadget/ether.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/gadget/ether.c Tue Apr 6 17:22:26 2004 @@ -1,7 +1,8 @@ /* * ether.c -- Ethernet gadget driver, with CDC and non-CDC options * - * Copyright (C) 2003 David Brownell + * Copyright (C) 2003-2004 David Brownell + * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -55,6 +56,8 @@ #include #include +#include "gadget_chips.h" + /*-------------------------------------------------------------------------*/ /* @@ -62,25 +65,36 @@ * * CDC Ethernet is the standard USB solution for sending Ethernet frames * using USB. Real hardware tends to use the same framing protocol but look - * different for control features. And Microsoft pushes their own approach - * (RNDIS) instead of the standard. + * different for control features. This driver strongly prefers to use + * this USB-IF standard as its open-systems interoperability solution; + * most host side USB stacks (except from Microsoft) support it. * * There's some hardware that can't talk CDC. We make that hardware * implement a "minimalist" vendor-agnostic CDC core: same framing, but * link-level setup only requires activating the configuration. + * Linux supports it, but other host operating systems may not. + * (This is a subset of CDC Ethernet.) + * + * A third option is also in use. Rather than CDC Ethernet, or something + * simpler, Microsoft pushes their own approach: RNDIS. The published + * RNDIS specs are ambiguous and appear to be incomplete, and are also + * needlessly complex. */ #define DRIVER_DESC "Ethernet Gadget" -#define DRIVER_VERSION "Bastille Day 2003" +#define DRIVER_VERSION "St Patrick's Day 2004" static const char shortname [] = "ether"; static const char driver_desc [] = DRIVER_DESC; -#define MIN_PACKET sizeof(struct ethhdr) -#define MAX_PACKET ETH_DATA_LEN /* biggest packet we'll rx/tx */ #define RX_EXTRA 20 /* guard against rx overflows */ -/* FIXME allow high speed jumbograms */ +#ifdef CONFIG_USB_ETH_RNDIS +#include "rndis.h" +#else +#define rndis_init() 0 +#define rndis_exit() do{}while(0) +#endif /*-------------------------------------------------------------------------*/ @@ -100,214 +114,130 @@ atomic_t tx_qlen; struct work_struct work; + unsigned zlp:1; + unsigned cdc:1; + unsigned rndis:1; unsigned long todo; #define WORK_RX_MEMORY 0 + int rndis_config; }; +/* This version autoconfigures as much as possible at run-time. + * + * It also ASSUMES a self-powered device, without remote wakeup, + * although remote wakeup support would make sense. + */ +static const char *EP_IN_NAME; +static const char *EP_OUT_NAME; +static const char *EP_STATUS_NAME; + /*-------------------------------------------------------------------------*/ -/* Thanks to NetChip Technologies for donating this product ID. - * - * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! +/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! * Instead: allocate your own, using normal USB-IF procedures. */ -#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ -#define DRIVER_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget */ -/*-------------------------------------------------------------------------*/ +/* Thanks to NetChip Technologies for donating this product ID. + * It's for devices with only CDC Ethernet configurations. + */ +#define CDC_VENDOR_NUM 0x0525 /* NetChip */ +#define CDC_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget */ -/* - * hardware-specific configuration, controlled by which device - * controller driver was configured. - * - * CHIP ... hardware identifier - * DRIVER_VERSION_NUM ... alerts the host side driver to differences - * EP_*_NAME ... which endpoints do we use for which purpose? - * EP_*_NUM ... numbers for them (often limited by hardware) - * WAKEUP ... if hardware supports remote wakeup AND we will issue the - * usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP - * - * hw_optimize(gadget) ... for any hardware tweaks we want to kick in - * before we enable our endpoints +/* For hardware that can't talk CDC, we use the same vendor ID that + * ARM Linux has used for ethernet-over-usb, both with sa1100 and + * with pxa250. We're protocol-compatible, if the host-side drivers + * use the endpoint descriptors. bcdDevice (version) is nonzero, so + * drivers that need to hard-wire endpoint numbers have a hook. * - * add other defines for other portability issues, like hardware that - * for some reason doesn't handle full speed bulk maxpacket of 64. + * The protocol is a minimal subset of CDC Ether, which works on any bulk + * hardware that's not deeply broken ... even on hardware that can't talk + * RNDIS (like SA-1100, with no interrupt endpoint, or anything that + * doesn't handle control-OUT). */ +#define SIMPLE_VENDOR_NUM 0x049f +#define SIMPLE_PRODUCT_NUM 0x505a -#define DEV_CONFIG_VALUE 3 /* some hardware cares */ - -/* #undef on hardware that can't implement CDC */ -#define DEV_CONFIG_CDC +/* For hardware that can talk RNDIS and either of the above protocols, + * use this ID ... the windows INF files will know it. Unless it's + * used with CDC Ethernet, Linux hosts will need updates to choose the + * non-MSFT configuration, either in the kernel (2.4) or else from a + * hotplug script (2.6). + */ +#define RNDIS_VENDOR_NUM 0x0525 /* NetChip */ +#define RNDIS_PRODUCT_NUM 0xa4a2 /* Ethernet/RNDIS Gadget */ -/* undef on bus-powered hardware, and #define MAX_USB_POWER */ -#define SELFPOWER -/* - * NetChip 2280, PCI based. - * - * use DMA with fat fifos for all data traffic, PIO for the status channel - * where its 64 byte maxpacket ceiling is no issue. - * - * performance note: only PIO needs per-usb-packet IRQs (ep0, ep-e, ep-f) - * otherwise IRQs are per-Ethernet-packet unless TX_DELAY and chaining help. +/* Some systems will want different product identifers published in the + * device descriptor, either numbers or strings or both. These string + * parameters are in UTF-8 (superset of ASCII's 7 bit characters). */ -#ifdef CONFIG_USB_GADGET_NET2280 -#define CHIP "net2280" -#define DEFAULT_QLEN 4 /* has dma chaining */ -#define DRIVER_VERSION_NUM 0x0101 -static const char EP_OUT_NAME [] = "ep-a"; -#define EP_OUT_NUM 1 -static const char EP_IN_NAME [] = "ep-b"; -#define EP_IN_NUM 2 -static const char EP_STATUS_NAME [] = "ep-f"; -#define EP_STATUS_NUM 3 -/* supports remote wakeup, but this driver doesn't */ -extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); +static ushort __initdata idVendor; +module_param(idVendor, ushort, S_IRUGO); +MODULE_PARM_DESC(idVendor, "USB Vendor ID"); -static inline void hw_optimize (struct usb_gadget *gadget) -{ - /* we can have bigger ep-a/ep-b fifos (2KB each, 4 USB packets - * for highspeed bulk) because we're not using ep-c/ep-d. - */ - net2280_set_fifo_mode (gadget, 1); -} -#endif +static ushort __initdata idProduct; +module_param(idProduct, ushort, S_IRUGO); +MODULE_PARM_DESC(idProduct, "USB Product ID"); -/* - * PXA-2xx UDC: widely used in second gen Linux-capable ARM PDAs - * and other products. - * - * multiple interfaces (or altsettings) aren't usable. so this hardware - * can't implement CDC, which needs both capabilities. - */ -#ifdef CONFIG_USB_GADGET_PXA2XX -#undef DEV_CONFIG_CDC -#define CHIP "pxa2xx" -#define DRIVER_VERSION_NUM 0x0103 -static const char EP_OUT_NAME [] = "ep2out-bulk"; -#define EP_OUT_NUM 2 -static const char EP_IN_NAME [] = "ep1in-bulk"; -#define EP_IN_NUM 1 -/* supports remote wakeup, but this driver doesn't */ +static ushort __initdata bcdDevice; +module_param(bcdDevice, ushort, S_IRUGO); +MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); -/* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0) -#endif +static char *__initdata iManufacturer; +module_param(iManufacturer, charp, S_IRUGO); +MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); -/* - * SA-1100 UDC: widely used in first gen Linux-capable PDAs. - * - * can't have a notification endpoint, since there are only the two - * bulk-capable ones. the CDC spec allows that. - */ -#ifdef CONFIG_USB_GADGET_SA1100 -#define CHIP "sa1100" -#define DRIVER_VERSION_NUM 0x0105 -static const char EP_OUT_NAME [] = "ep1out-bulk"; -#define EP_OUT_NUM 1 -static const char EP_IN_NAME [] = "ep2in-bulk"; -#define EP_IN_NUM 2 -// EP_STATUS_NUM is undefined -/* doesn't support remote wakeup? */ +static char *__initdata iProduct; +module_param(iProduct, charp, S_IRUGO); +MODULE_PARM_DESC(iProduct, "USB Product string"); -/* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0) -#endif -/* - * Toshiba TC86C001 ("Goku-S") UDC - * - * This has three semi-configurable full speed bulk/interrupt endpoints. - */ -#ifdef CONFIG_USB_GADGET_GOKU -#define CHIP "goku" -#define DRIVER_VERSION_NUM 0x0106 -static const char EP_OUT_NAME [] = "ep1-bulk"; -#define EP_OUT_NUM 1 -static const char EP_IN_NAME [] = "ep2-bulk"; -#define EP_IN_NUM 2 -static const char EP_STATUS_NAME [] = "ep3-bulk"; -#define EP_STATUS_NUM 3 -/* doesn't support remote wakeup */ +/*-------------------------------------------------------------------------*/ + +/* Include CDC support if we could run on CDC-capable hardware. */ -#define hw_optimize(g) do {} while (0) +#ifdef CONFIG_USB_GADGET_NET2280 +#define DEV_CONFIG_CDC #endif -/* - * SuperH UDC: UDC built-in to some Renesas SH processors. - * - * This has three semi-configurable full speed bulk/interrupt endpoints. - * - * Only one configuration and interface is supported. So this hardware - * can't implement CDC. - */ -#ifdef CONFIG_USB_GADGET_SUPERH -#undef DEV_CONFIG_CDC -#define CHIP "superh" -#define DRIVER_VERSION_NUM 0x0107 -static const char EP_OUT_NAME[] = "ep1out-bulk"; -#define EP_OUT_NUM 1 -static const char EP_IN_NAME[] = "ep2in-bulk"; -#define EP_IN_NUM 2 +#ifdef CONFIG_USB_GADGET_DUMMY_HCD +#define DEV_CONFIG_CDC +#endif -#define hw_optimize(g) do {} while (0) +#ifdef CONFIG_USB_GADGET_GOKU +#define DEV_CONFIG_CDC #endif -/*-------------------------------------------------------------------------*/ +#ifdef CONFIG_USB_GADGET_MQ11XX +#define DEV_CONFIG_CDC +#endif -#ifndef CHIP -# error Configure some USB peripheral controller driver! +#ifdef CONFIG_USB_GADGET_OMAP +#define DEV_CONFIG_CDC #endif -/* We normally expect hardware that can talk CDC. That involves - * using multiple interfaces and altsettings, and maybe a status - * interrupt. Driver binding to be done according to USB-IF class, - * though you can use different VENDOR and PRODUCT numbers if you - * want (and they're officially assigned). - * - * For hardware that can't talk CDC, we use the same vendor ID that - * ARM Linux has used for ethernet-over-usb, both with sa1100 and - * with pxa250. We're protocol-compatible, if the host-side drivers - * use the endpoint descriptors. DRIVER_VERSION_NUM is nonzero, so - * drivers that need to hard-wire endpoint numbers have a hook. + +/* For CDC-incapable hardware, choose the simple cdc subset. + * Anything that talks bulk (without notable bugs) can do this. */ -#ifdef DEV_CONFIG_CDC -#define DEV_CONFIG_CLASS USB_CLASS_COMM -#else -#define DEV_CONFIG_CLASS USB_CLASS_VENDOR_SPEC -#undef EP_STATUS_NUM -#undef DRIVER_VENDOR_NUM -#undef DRIVER_PRODUCT_NUM -#define DRIVER_VENDOR_NUM 0x049f -#define DRIVER_PRODUCT_NUM 0x505a -#endif /* CONFIG_CDC_ETHER */ - -/* power usage is config specific. - * hardware that supports remote wakeup defaults to disabling it. - */ - -#ifndef MAX_USB_POWER -#ifdef SELFPOWER -/* some hosts are confused by 0mA */ -#define MAX_USB_POWER 2 /* mA */ -#else -/* bus powered */ -#error Define your bus power consumption! +#ifdef CONFIG_USB_GADGET_PXA +#define DEV_CONFIG_SUBSET +#endif + +#ifdef CONFIG_USB_GADGET_SH +#define DEV_CONFIG_SUBSET #endif -#endif /* MAX_USB_POWER */ -#ifndef WAKEUP -/* default: this driver won't do remote wakeup */ -#define WAKEUP 0 -/* else value must be USB_CONFIG_ATT_WAKEUP */ +#ifdef CONFIG_USB_GADGET_SA1100 +/* use non-CDC for backwards compatibility */ +#define DEV_CONFIG_SUBSET #endif + /*-------------------------------------------------------------------------*/ -#ifndef DEFAULT_QLEN #define DEFAULT_QLEN 2 /* double buffering by default */ -#endif #ifdef CONFIG_USB_GADGET_DUALSPEED @@ -320,10 +250,14 @@ (DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1)) /* also defer IRQs on highspeed TX */ -#define TX_DELAY DEFAULT_QLEN +#define TX_DELAY qmult + +#define BITRATE(g) ((g->speed == USB_SPEED_HIGH) ? 4800000 : 120000) #else /* full speed (low speed doesn't do bulk) */ #define qlen(gadget) DEFAULT_QLEN + +#define BITRATE(g) (12000) #endif @@ -364,8 +298,13 @@ /* * DESCRIPTORS ... most are static, but strings and (full) configuration - * descriptors are built on demand. Notice how most of the cdc descriptors - * aren't needed in the "minimalist" mode. + * descriptors are built on demand. For now we do either full CDC, or + * our simple subset, with RNDIS as an optional second configuration. + * + * RNDIS includes some CDC ACM descriptors ... like CDC Ethernet. But + * the class descriptors match a modem (they're ignored; it's really just + * Ethernet functionality), they don't need the NOP altsetting, and the + * status transfer endpoint isn't optional. */ #define STRING_MANUFACTURER 1 @@ -373,12 +312,24 @@ #define STRING_ETHADDR 3 #define STRING_DATA 4 #define STRING_CONTROL 5 +#define STRING_RNDIS_CONTROL 6 +#define STRING_CDC 7 +#define STRING_SUBSET 8 +#define STRING_RNDIS 9 #define USB_BUFSIZ 256 /* holds our biggest descriptor */ /* - * This device advertises one configuration. + * This device advertises one configuration, eth_config, unless RNDIS + * is enabled (rndis_config) on hardware supporting at least two configs. + * + * NOTE: Controllers like superh_udc should probably be able to use + * an RNDIS-only configuration. */ + +#define DEV_CONFIG_VALUE 1 /* cdc or subset */ +#define DEV_RNDIS_CONFIG_VALUE 2 /* rndis; optional */ + static struct usb_device_descriptor device_desc = { .bLength = sizeof device_desc, @@ -386,13 +337,12 @@ .bcdUSB = __constant_cpu_to_le16 (0x0200), - .bDeviceClass = DEV_CONFIG_CLASS, + .bDeviceClass = USB_CLASS_COMM, .bDeviceSubClass = 0, .bDeviceProtocol = 0, - .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM), - .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM), - .bcdDevice = __constant_cpu_to_le16 (DRIVER_VERSION_NUM), + .idVendor = __constant_cpu_to_le16 (CDC_VENDOR_NUM), + .idProduct = __constant_cpu_to_le16 (CDC_PRODUCT_NUM), .iManufacturer = STRING_MANUFACTURER, .iProduct = STRING_PRODUCT, .bNumConfigurations = 1, @@ -404,44 +354,70 @@ .bDescriptorType = USB_DT_CONFIG, /* compute wTotalLength on the fly */ -#ifdef DEV_CONFIG_CDC .bNumInterfaces = 2, -#else - .bNumInterfaces = 1, -#endif .bConfigurationValue = DEV_CONFIG_VALUE, - .iConfiguration = STRING_PRODUCT, - .bmAttributes = USB_CONFIG_ATT_ONE | WAKEUP, - .bMaxPower = (MAX_USB_POWER + 1) / 2, + .iConfiguration = STRING_CDC, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 1, }; -#ifdef DEV_CONFIG_CDC +#ifdef CONFIG_USB_ETH_RNDIS +static const struct usb_config_descriptor +rndis_config = { + .bLength = sizeof rndis_config, + .bDescriptorType = USB_DT_CONFIG, + + /* compute wTotalLength on the fly */ + .bNumInterfaces = 2, + .bConfigurationValue = DEV_RNDIS_CONFIG_VALUE, + .iConfiguration = STRING_RNDIS, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 1, +}; +#endif /* - * Compared to the "minimalist" non-CDC model, the CDC model adds - * three class descriptors, two interface descrioptors, and a status + * Compared to the simple CDC subset, the full CDC Ethernet model adds + * three class descriptors, two interface descriptors, optional status * endpoint. Both have a "data" interface and two bulk endpoints. * There are also differences in how control requests are handled. + * + * RNDIS shares a lot with CDC-Ethernet, since it's a variant of + * the CDC-ACM (modem) spec. */ -/* master comm interface optionally has a status notification endpoint */ - -static const struct usb_interface_descriptor +#ifdef DEV_CONFIG_CDC +static struct usb_interface_descriptor control_intf = { .bLength = sizeof control_intf, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0, -#ifdef EP_STATUS_NUM + /* status endpoint is optional; this may be patched later */ .bNumEndpoints = 1, -#else - .bNumEndpoints = 0, -#endif .bInterfaceClass = USB_CLASS_COMM, .bInterfaceSubClass = 6, /* ethernet control model */ .bInterfaceProtocol = 0, .iInterface = STRING_CONTROL, }; +#endif + +#ifdef CONFIG_USB_ETH_RNDIS +static const struct usb_interface_descriptor +rndis_control_intf = { + .bLength = sizeof rndis_control_intf, + .bDescriptorType = USB_DT_INTERFACE, + + .bInterfaceNumber = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = 2, /* abstract control model */ + .bInterfaceProtocol = 0xff, /* vendor specific */ + .iInterface = STRING_RNDIS_CONTROL, +}; +#endif + +#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) /* "Header Functional Descriptor" from CDC spec 5.2.3.1 */ struct header_desc { @@ -454,13 +430,13 @@ static const struct header_desc header_desc = { .bLength = sizeof header_desc, - .bDescriptorType = 0x24, + .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = 0, .bcdCDC = __constant_cpu_to_le16 (0x0110), }; -/* "Union Functional Descriptor" from CDC spec 5.2.3.X */ +/* "Union Functional Descriptor" from CDC spec 5.2.3.8 */ struct union_desc { u8 bLength; u8 bDescriptorType; @@ -473,13 +449,58 @@ static const struct union_desc union_desc = { .bLength = sizeof union_desc, - .bDescriptorType = 0x24, + .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = 6, .bMasterInterface0 = 0, /* index of control interface */ .bSlaveInterface0 = 1, /* index of DATA interface */ }; +#endif /* CDC || RNDIS */ + +#ifdef CONFIG_USB_ETH_RNDIS + +/* "Call Management Descriptor" from CDC spec 5.2.3.3 */ +struct call_mgmt_descriptor { + u8 bLength; + u8 bDescriptorType; + u8 bDescriptorSubType; + + u8 bmCapabilities; + u8 bDataInterface; +} __attribute__ ((packed)); + +static const struct call_mgmt_descriptor call_mgmt_descriptor = { + .bLength = sizeof call_mgmt_descriptor, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = 0x01, + + .bmCapabilities = 0x00, + .bDataInterface = 0x01, +}; + + +/* "Abstract Control Management Descriptor" from CDC spec 5.2.3.4 */ +struct acm_descriptor { + u8 bLength; + u8 bDescriptorType; + u8 bDescriptorSubType; + + u8 bmCapabilities; +} __attribute__ ((packed)); + +static struct acm_descriptor acm_descriptor = { + .bLength = sizeof acm_descriptor, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = 0x02, + + .bmCapabilities = 0X00, +}; + +#endif + +#ifdef DEV_CONFIG_CDC + /* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */ struct ether_desc { u8 bLength; @@ -495,41 +516,53 @@ static const struct ether_desc ether_desc = { .bLength = sizeof ether_desc, - .bDescriptorType = 0x24, + .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = 0x0f, /* this descriptor actually adds value, surprise! */ .iMACAddress = STRING_ETHADDR, .bmEthernetStatistics = __constant_cpu_to_le32 (0), /* no statistics */ - .wMaxSegmentSize = __constant_cpu_to_le16 (MAX_PACKET + ETH_HLEN), + .wMaxSegmentSize = __constant_cpu_to_le16 (ETH_FRAME_LEN), .wNumberMCFilters = __constant_cpu_to_le16 (0), .bNumberPowerFilters = 0, }; -#ifdef EP_STATUS_NUM +#endif + +#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) -/* include the status endpoint if we can, even though it's optional. +/* include the status endpoint if we can, even where it's optional. + * use small wMaxPacketSize, since many "interrupt" endpoints have + * very small fifos and it's no big deal if CDC_NOTIFY_SPEED_CHANGE + * takes two packets. also default to a big transfer interval, to + * waste less bandwidth. * - * some drivers (like current Linux cdc-ether!) "need" it to exist even + * some drivers (like Linux 2.4 cdc-ether!) "need" it to exist even * if they ignore the connect/disconnect notifications that real aether * can provide. more advanced cdc configurations might want to support * encapsulated commands (vendor-specific, using control-OUT). + * + * RNDIS requires the status endpoint, since it uses that encapsulation + * mechanism for its funky RPC scheme. */ -#define LOG2_STATUS_INTERVAL_MSEC 6 -#define STATUS_BYTECOUNT 16 /* 8 byte header + data */ -static const struct usb_endpoint_descriptor +#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ +#define STATUS_BYTECOUNT 8 /* 8 byte header + data */ + +static struct usb_endpoint_descriptor fs_status_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_STATUS_NUM | USB_DIR_IN, + .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = __constant_cpu_to_le16 (STATUS_BYTECOUNT), .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, }; #endif +#ifdef DEV_CONFIG_CDC + /* the default data interface has no endpoints ... */ static const struct usb_interface_descriptor @@ -543,10 +576,9 @@ .bInterfaceClass = USB_CLASS_CDC_DATA, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, - .iInterface = STRING_DATA, }; -/* ... but the "real" data interface has two full speed bulk endpoints */ +/* ... but the "real" data interface has two bulk endpoints */ static const struct usb_interface_descriptor data_intf = { @@ -561,16 +593,39 @@ .bInterfaceProtocol = 0, .iInterface = STRING_DATA, }; -#else + +#endif + +#ifdef CONFIG_USB_ETH_RNDIS + +/* RNDIS doesn't activate by changing to the "real" altsetting */ + +static const struct usb_interface_descriptor +rndis_data_intf = { + .bLength = sizeof rndis_data_intf, + .bDescriptorType = USB_DT_INTERFACE, + + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_CDC_DATA, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = STRING_DATA, +}; + +#endif + +#ifdef DEV_CONFIG_SUBSET /* - * "Minimalist" non-CDC option is a simple vendor-neutral model that most + * "Simple" CDC-subset option is a simple vendor-neutral model that most * full speed controllers can handle: one interface, two bulk endpoints. */ static const struct usb_interface_descriptor -data_intf = { - .bLength = sizeof data_intf, +subset_data_intf = { + .bLength = sizeof subset_data_intf, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0, @@ -582,47 +637,73 @@ .iInterface = STRING_DATA, }; -#endif /* DEV_CONFIG_CDC */ +#endif /* SUBSET */ -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor fs_source_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_IN_NUM | USB_DIR_IN, + .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16 (64), }; -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor fs_sink_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_OUT_NUM, + .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16 (64), }; -static const struct usb_descriptor_header *fs_function [] = { +static const struct usb_descriptor_header *fs_eth_function [10] = { #ifdef DEV_CONFIG_CDC /* "cdc" mode descriptors */ (struct usb_descriptor_header *) &control_intf, (struct usb_descriptor_header *) &header_desc, (struct usb_descriptor_header *) &union_desc, (struct usb_descriptor_header *) ðer_desc, -#ifdef EP_STATUS_NUM + /* NOTE: status endpoint may need to be removed */ (struct usb_descriptor_header *) &fs_status_desc, -#endif + /* data interface, with altsetting */ (struct usb_descriptor_header *) &data_nop_intf, -#endif /* DEV_CONFIG_CDC */ - /* minimalist core */ (struct usb_descriptor_header *) &data_intf, (struct usb_descriptor_header *) &fs_source_desc, (struct usb_descriptor_header *) &fs_sink_desc, 0, +#endif /* DEV_CONFIG_CDC */ +}; + +static inline void __init fs_subset_descriptors(void) +{ +#ifdef DEV_CONFIG_SUBSET + fs_eth_function[0] = (struct usb_descriptor_header *) &subset_data_intf; + fs_eth_function[1] = (struct usb_descriptor_header *) &fs_source_desc; + fs_eth_function[2] = (struct usb_descriptor_header *) &fs_sink_desc; + fs_eth_function[3] = 0; +#else + fs_eth_function[0] = 0; +#endif +} + +#ifdef CONFIG_USB_ETH_RNDIS +static const struct usb_descriptor_header *fs_rndis_function [] = { + /* control interface matches ACM, not Ethernet */ + (struct usb_descriptor_header *) &rndis_control_intf, + (struct usb_descriptor_header *) &header_desc, + (struct usb_descriptor_header *) &call_mgmt_descriptor, + (struct usb_descriptor_header *) &acm_descriptor, + (struct usb_descriptor_header *) &union_desc, + (struct usb_descriptor_header *) &fs_status_desc, + /* data interface has no altsetting */ + (struct usb_descriptor_header *) &rndis_data_intf, + (struct usb_descriptor_header *) &fs_source_desc, + (struct usb_descriptor_header *) &fs_sink_desc, + 0, }; +#endif #ifdef CONFIG_USB_GADGET_DUALSPEED @@ -631,39 +712,34 @@ * descriptors, unless they only run at full speed. */ -#ifdef EP_STATUS_NUM -static const struct usb_endpoint_descriptor +#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) +static struct usb_endpoint_descriptor hs_status_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_STATUS_NUM | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = __constant_cpu_to_le16 (STATUS_BYTECOUNT), - .bInterval = LOG2_STATUS_INTERVAL_MSEC + 3, + .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, }; -#endif +#endif /* DEV_CONFIG_CDC */ -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor hs_source_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_IN_NUM | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16 (512), - .bInterval = 1, }; -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor hs_sink_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_OUT_NUM, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16 (512), - .bInterval = 1, }; static struct usb_qualifier_descriptor @@ -672,29 +748,57 @@ .bDescriptorType = USB_DT_DEVICE_QUALIFIER, .bcdUSB = __constant_cpu_to_le16 (0x0200), - .bDeviceClass = DEV_CONFIG_CLASS, + .bDeviceClass = USB_CLASS_COMM, .bNumConfigurations = 1, }; -static const struct usb_descriptor_header *hs_function [] = { +static const struct usb_descriptor_header *hs_eth_function [10] = { #ifdef DEV_CONFIG_CDC /* "cdc" mode descriptors */ (struct usb_descriptor_header *) &control_intf, (struct usb_descriptor_header *) &header_desc, (struct usb_descriptor_header *) &union_desc, (struct usb_descriptor_header *) ðer_desc, -#ifdef EP_STATUS_NUM + /* NOTE: status endpoint may need to be removed */ (struct usb_descriptor_header *) &hs_status_desc, -#endif + /* data interface, with altsetting */ (struct usb_descriptor_header *) &data_nop_intf, -#endif /* DEV_CONFIG_CDC */ - /* minimalist core */ (struct usb_descriptor_header *) &data_intf, (struct usb_descriptor_header *) &hs_source_desc, (struct usb_descriptor_header *) &hs_sink_desc, 0, +#endif /* DEV_CONFIG_CDC */ +}; + +static inline void __init hs_subset_descriptors(void) +{ +#ifdef DEV_CONFIG_SUBSET + hs_eth_function[0] = (struct usb_descriptor_header *) &subset_data_intf; + hs_eth_function[1] = (struct usb_descriptor_header *) &fs_source_desc; + hs_eth_function[2] = (struct usb_descriptor_header *) &fs_sink_desc; + hs_eth_function[3] = 0; +#else + hs_eth_function[0] = 0; +#endif +} + +#ifdef CONFIG_USB_ETH_RNDIS +static const struct usb_descriptor_header *hs_rndis_function [] = { + /* control interface matches ACM, not Ethernet */ + (struct usb_descriptor_header *) &rndis_control_intf, + (struct usb_descriptor_header *) &header_desc, + (struct usb_descriptor_header *) &call_mgmt_descriptor, + (struct usb_descriptor_header *) &acm_descriptor, + (struct usb_descriptor_header *) &union_desc, + (struct usb_descriptor_header *) &hs_status_desc, + /* data interface has no altsetting */ + (struct usb_descriptor_header *) &rndis_data_intf, + (struct usb_descriptor_header *) &hs_source_desc, + (struct usb_descriptor_header *) &hs_sink_desc, + 0, }; +#endif /* maxpacket and other transfer characteristics vary by speed. */ @@ -705,12 +809,19 @@ /* if there's no high speed support, maxpacket doesn't change. */ #define ep_desc(g,hs,fs) fs +static inline void __init hs_subset_descriptors(void) +{ +} + #endif /* !CONFIG_USB_GADGET_DUALSPEED */ /*-------------------------------------------------------------------------*/ /* descriptors that are built on-demand */ +static char manufacturer [40]; +static char product_desc [40] = DRIVER_DESC; + #ifdef DEV_CONFIG_CDC /* address that the host will use ... usually assigned at random */ static char ethaddr [2 * ETH_ALEN + 1]; @@ -718,13 +829,21 @@ /* static strings, in iso 8859/1 */ static struct usb_string strings [] = { - { STRING_MANUFACTURER, UTS_SYSNAME " " UTS_RELEASE "/" CHIP, }, - { STRING_PRODUCT, driver_desc, }, + { STRING_MANUFACTURER, manufacturer, }, + { STRING_PRODUCT, product_desc, }, + { STRING_DATA, "Ethernet Data", }, #ifdef DEV_CONFIG_CDC + { STRING_CDC, "CDC Ethernet", }, { STRING_ETHADDR, ethaddr, }, { STRING_CONTROL, "CDC Communications Control", }, #endif - { STRING_DATA, "Ethernet Data", }, +#ifdef DEV_CONFIG_SUBSET + { STRING_SUBSET, "CDC Ethernet Subset", }, +#endif +#ifdef CONFIG_USB_ETH_RNDIS + { STRING_RNDIS, "RNDIS", }, + { STRING_RNDIS_CONTROL, "RNDIS Communications Control", }, +#endif { } /* end of list */ }; @@ -741,20 +860,34 @@ config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index) { int len; - const struct usb_descriptor_header **function = fs_function; #ifdef CONFIG_USB_GADGET_DUALSPEED int hs = (speed == USB_SPEED_HIGH); if (type == USB_DT_OTHER_SPEED_CONFIG) hs = !hs; - if (hs) - function = hs_function; +#define which_config(t) (hs ? & t ## _config : & t ## _config) +#define which_fn(t) (hs ? & hs_ ## t ## _function : & fs_ ## t ## _function) +#else +#define which_config(t) (& t ## _config) +#define which_fn(t) (& fs_ ## t ## _function) #endif - /* a single configuration must always be index 0 */ - if (index > 0) + if (index >= device_desc.bNumConfigurations) return -EINVAL; - len = usb_gadget_config_buf (ð_config, buf, USB_BUFSIZ, function); + +#ifdef CONFIG_USB_ETH_RNDIS + /* list the RNDIS config first, to make Microsoft's drivers + * happy. DOCSIS 1.0 needs this too. + */ + if (device_desc.bNumConfigurations == 2 && index == 0) + len = usb_gadget_config_buf (which_config (rndis), buf, + USB_BUFSIZ, (const struct usb_descriptor_header **) + which_fn (rndis)); + else +#endif + len = usb_gadget_config_buf (which_config (eth), buf, + USB_BUFSIZ, (const struct usb_descriptor_header **) + which_fn (eth)); if (len < 0) return len; ((struct usb_config_descriptor *) buf)->bDescriptorType = type; @@ -766,6 +899,91 @@ static void eth_start (struct eth_dev *dev, int gfp_flags); static int alloc_requests (struct eth_dev *dev, unsigned n, int gfp_flags); +#ifdef DEV_CONFIG_CDC +static inline int ether_alt_ep_setup (struct eth_dev *dev, struct usb_ep *ep) +{ + const struct usb_endpoint_descriptor *d; + + /* With CDC, the host isn't allowed to use these two data + * endpoints in the default altsetting for the interface. + * so we don't activate them yet. Reset from SET_INTERFACE. + * + * Strictly speaking RNDIS should work the same: activation is + * a side effect of setting a packet filter. Deactivation is + * from REMOTE_NDIS_HALT_MSG, reset from REMOTE_NDIS_RESET_MSG. + */ + + /* one endpoint writes data back IN to the host */ + if (strcmp (ep->name, EP_IN_NAME) == 0) { + d = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc); + ep->driver_data = dev; + dev->in_ep = ep; + dev->in = d; + + /* one endpoint just reads OUT packets */ + } else if (strcmp (ep->name, EP_OUT_NAME) == 0) { + d = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc); + ep->driver_data = dev; + dev->out_ep = ep; + dev->out = d; + + /* optional status/notification endpoint */ + } else if (EP_STATUS_NAME && + strcmp (ep->name, EP_STATUS_NAME) == 0) { + int result; + + d = ep_desc (dev->gadget, &hs_status_desc, &fs_status_desc); + result = usb_ep_enable (ep, d); + if (result < 0) + return result; + + ep->driver_data = dev; + dev->status_ep = ep; + dev->status = d; + } + return 0; +} +#endif + +#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS) +static inline int ether_ep_setup (struct eth_dev *dev, struct usb_ep *ep) +{ + int result; + const struct usb_endpoint_descriptor *d; + + /* CDC subset is simpler: if the device is there, + * it's live with rx and tx endpoints. + * + * Do this as a shortcut for RNDIS too. + */ + + /* one endpoint writes data back IN to the host */ + if (strcmp (ep->name, EP_IN_NAME) == 0) { + d = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc); + result = usb_ep_enable (ep, d); + if (result < 0) + return result; + + ep->driver_data = dev; + dev->in_ep = ep; + dev->in = d; + + /* one endpoint just reads OUT packets */ + } else if (strcmp (ep->name, EP_OUT_NAME) == 0) { + d = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc); + result = usb_ep_enable (ep, d); + if (result < 0) + return result; + + ep->driver_data = dev; + dev->out_ep = ep; + dev->out = d; + } + + return 0; +} +#endif + static int set_ether_config (struct eth_dev *dev, int gfp_flags) { @@ -774,34 +992,17 @@ struct usb_gadget *gadget = dev->gadget; gadget_for_each_ep (ep, gadget) { - const struct usb_endpoint_descriptor *d; - #ifdef DEV_CONFIG_CDC - /* With CDC, the host isn't allowed to use these two data - * endpoints in the default altsetting for the interface. - * so we don't activate them yet. - */ + if (!dev->rndis && dev->cdc) { + result = ether_alt_ep_setup (dev, ep); + if (result == 0) + continue; + } +#endif - /* one endpoint writes data back IN to the host */ - if (strcmp (ep->name, EP_IN_NAME) == 0) { - d = ep_desc (gadget, &hs_source_desc, &fs_source_desc); - ep->driver_data = dev; - dev->in_ep = ep; - dev->in = d; - continue; - - /* one endpoint just reads OUT packets */ - } else if (strcmp (ep->name, EP_OUT_NAME) == 0) { - d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc); - ep->driver_data = dev; - dev->out_ep = ep; - dev->out = d; - continue; - } - -#ifdef EP_STATUS_NUM - /* optional status/notification endpoint */ - else if (strcmp (ep->name, EP_STATUS_NAME) == 0) { +#ifdef CONFIG_USB_ETH_RNDIS + if (dev->rndis && strcmp (ep->name, EP_STATUS_NAME) == 0) { + const struct usb_endpoint_descriptor *d; d = ep_desc (gadget, &hs_status_desc, &fs_status_desc); result = usb_ep_enable (ep, d); if (result == 0) { @@ -810,43 +1011,17 @@ dev->status = d; continue; } - } + } else #endif -#else /* !CONFIG_CDC_ETHER */ - - /* non-CDC is simpler: if the device is there, - * it's live with rx and tx endpoints. - */ - /* one endpoint writes data back IN to the host */ - if (strcmp (ep->name, EP_IN_NAME) == 0) { - d = ep_desc (gadget, &hs_source_desc, &fs_source_desc); - result = usb_ep_enable (ep, d); - if (result == 0) { - ep->driver_data = dev; - dev->in_ep = ep; - dev->in = d; + { +#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS) + result = ether_ep_setup (dev, ep); + if (result == 0) continue; - } - - /* one endpoint just reads OUT packets */ - } else if (strcmp (ep->name, EP_OUT_NAME) == 0) { - d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc); - result = usb_ep_enable (ep, d); - if (result == 0) { - ep->driver_data = dev; - dev->out_ep = ep; - dev->out = d; - continue; - } +#endif } -#endif /* !CONFIG_CDC_ETHER */ - - /* ignore any other endpoints */ - else - continue; - /* stop on error */ ERROR (dev, "can't enable %s, result %d\n", ep->name, result); break; @@ -857,23 +1032,41 @@ if (result == 0) result = alloc_requests (dev, qlen (gadget), gfp_flags); -#ifndef DEV_CONFIG_CDC - if (result == 0) { + /* on error, disable any endpoints */ + if (result < 0) { +#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) + if (dev->status_ep) + (void) usb_ep_disable (dev->status_ep); +#endif + dev->status_ep = 0; + dev->status = 0; +#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS) + if (dev->rndis || !dev->cdc) { + if (dev->in_ep) + (void) usb_ep_disable (dev->in_ep); + if (dev->out_ep) + (void) usb_ep_disable (dev->out_ep); + } +#endif + dev->in_ep = 0; + dev->in = 0; + dev->out_ep = 0; + dev->out = 0; + } else + + /* activate non-CDC configs right away + * this isn't strictly according to the RNDIS spec + */ +#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS) + if (dev->rndis || !dev->cdc) { netif_carrier_on (dev->net); if (netif_running (dev->net)) { spin_unlock (&dev->lock); eth_start (dev, GFP_ATOMIC); spin_lock (&dev->lock); } - } else { - (void) usb_ep_disable (dev->in_ep); - dev->in_ep = 0; - dev->in = 0; - (void) usb_ep_disable (dev->out_ep); - dev->out_ep = 0; - dev->out = 0; } -#endif /* !CONFIG_CDC_ETHER */ +#endif if (result == 0) DEBUG (dev, "qlen %d\n", qlen (gadget)); @@ -918,12 +1111,10 @@ dev->out_ep = 0; } -#ifdef EP_STATUS_NUM if (dev->status_ep) { usb_ep_disable (dev->status_ep); dev->status_ep = 0; } -#endif dev->config = 0; } @@ -939,20 +1130,26 @@ if (number == dev->config) return 0; -#ifdef CONFIG_USB_GADGET_SA1100 - if (dev->config && atomic_read (&dev->tx_qlen) != 0) { + if (gadget_is_sa1100 (gadget) + && dev->config + && atomic_read (&dev->tx_qlen) != 0) { /* tx fifo is full, but we can't clear it...*/ INFO (dev, "can't change configurations\n"); return -ESPIPE; } -#endif eth_reset_config (dev); - hw_optimize (gadget); switch (number) { case DEV_CONFIG_VALUE: + dev->rndis = 0; + result = set_ether_config (dev, gfp_flags); + break; +#ifdef CONFIG_USB_ETH_RNDIS + case DEV_RNDIS_CONFIG_VALUE: + dev->rndis = 1; result = set_ether_config (dev, gfp_flags); break; +#endif default: result = -EINVAL; /* FALL THROUGH */ @@ -974,21 +1171,29 @@ } dev->config = number; - INFO (dev, "%s speed config #%d: %s\n", speed, number, - driver_desc); + INFO (dev, "%s speed config #%d: %s, using %s\n", + speed, number, driver_desc, + dev->rndis + ? "RNDIS" + : (dev->cdc + ? "CDC Ethernet" + : "CDC Ethernet Subset")); } return result; } /*-------------------------------------------------------------------------*/ -#ifdef EP_STATUS_NUM - -/* section 3.8.2 table 11 of the CDC spec lists Ethernet notifications */ +/* section 3.8.2 table 11 of the CDC spec lists Ethernet notifications + * section 3.6.2.1 table 5 specifies ACM notifications, accepted by RNDIS + * and RNDIS also defines its own bit-incompatible notifications + */ #define CDC_NOTIFY_NETWORK_CONNECTION 0x00 /* required; 6.3.1 */ #define CDC_NOTIFY_RESPONSE_AVAILABLE 0x01 /* optional; 6.3.2 */ #define CDC_NOTIFY_SPEED_CHANGE 0x2a /* required; 6.3.8 */ +#ifdef DEV_CONFIG_CDC + struct cdc_notification { u8 bmRequestType; u8 bNotificationType; @@ -1103,19 +1308,46 @@ /* see section 3.8.2 table 10 of the CDC spec for more ethernet * requests, mostly for filters (multicast, pm) and statistics + * section 3.6.2.1 table 4 has ACM requests; RNDIS requires the + * encapsulated command mechanism. */ -#define CDC_SEND_ENCAPSULATED_REQUEST 0x00 /* optional */ +#define CDC_SEND_ENCAPSULATED_COMMAND 0x00 /* optional */ #define CDC_GET_ENCAPSULATED_RESPONSE 0x01 /* optional */ #define CDC_SET_ETHERNET_PACKET_FILTER 0x43 /* required */ +#ifdef CONFIG_USB_ETH_RNDIS + +static void rndis_response_complete (struct usb_ep *ep, struct usb_request *req) +{ + struct eth_dev *dev = ep->driver_data; + + if (req->status || req->actual != req->length) + DEBUG (dev, "rndis response complete --> %d, %d/%d\n", + req->status, req->actual, req->length); + + /* done sending after CDC_GET_ENCAPSULATED_RESPONSE */ + rndis_free_response (dev->rndis_config, req->buf); +} + +static void rndis_command_complete (struct usb_ep *ep, struct usb_request *req) +{ + struct eth_dev *dev = ep->driver_data; + + /* received RNDIS command from CDC_SEND_ENCAPSULATED_COMMAND */ + if (rndis_msg_parser (dev->rndis_config, (u8 *) req->buf)) + ERROR(dev, "%s: rndis parse error\n", __FUNCTION__ ); +} + +#endif /* RNDIS */ + /* * The setup() callback implements all the ep0 functionality that's not * handled lower down. CDC has a number of less-common features: * * - two interfaces: control, and ethernet data - * - data interface has two altsettings: default, and active + * - Ethernet data interface has two altsettings: default, and active * - class-specific descriptors for the control interface - * - a mandatory class-specific control request + * - class-specific control requests */ static int eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) @@ -1175,17 +1407,6 @@ value = eth_set_config (dev, ctrl->wValue, GFP_ATOMIC); spin_unlock (&dev->lock); break; -#ifdef CONFIG_USB_GADGET_PXA2XX - /* PXA UDC prevents us from using SET_INTERFACE in normal ways. - * And it hides GET_CONFIGURATION and GET_INTERFACE too. - */ - case USB_REQ_SET_INTERFACE: - spin_lock (&dev->lock); - value = eth_set_config (dev, DEV_CONFIG_VALUE, GFP_ATOMIC); - spin_unlock (&dev->lock); - break; - -#else /* hardware that that stays out of our way */ case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != USB_DIR_IN) break; @@ -1198,17 +1419,28 @@ || !dev->config || ctrl->wIndex > 1) break; + if (!dev->cdc && ctrl->wIndex != 0) + break; spin_lock (&dev->lock); + + /* PXA hardware partially handles SET_INTERFACE; + * we need to kluge around that interference. + */ + if (gadget_is_pxa (gadget)) { + value = eth_set_config (dev, DEV_CONFIG_VALUE, + GFP_ATOMIC); + goto done_set_intf; + } + +#ifdef DEV_CONFIG_CDC switch (ctrl->wIndex) { case 0: /* control/master intf */ if (ctrl->wValue != 0) break; -#ifdef EP_STATUS_NUM if (dev->status_ep) { usb_ep_disable (dev->status_ep); usb_ep_enable (dev->status_ep, dev->status); } -#endif value = 0; break; case 1: /* data intf */ @@ -1225,9 +1457,8 @@ usb_ep_enable (dev->in_ep, dev->in); usb_ep_enable (dev->out_ep, dev->out); netif_carrier_on (dev->net); -#ifdef EP_STATUS_NUM - issue_start_status (dev); -#endif + if (dev->status_ep) + issue_start_status (dev); if (netif_running (dev->net)) { spin_unlock (&dev->lock); eth_start (dev, GFP_ATOMIC); @@ -1240,6 +1471,14 @@ value = 0; break; } +#else + /* FIXME this is wrong, as is the assumption that + * all non-PXA hardware talks real CDC ... + */ + dev_warn (&gadget->dev, "set_interface ignored!\n"); +#endif /* DEV_CONFIG_CDC */ + +done_set_intf: spin_unlock (&dev->lock); break; case USB_REQ_GET_INTERFACE: @@ -1247,6 +1486,8 @@ || !dev->config || ctrl->wIndex > 1) break; + if (!dev->cdc && ctrl->wIndex != 0) + break; /* if carrier is on, data interface is active. */ *(u8 *)req->buf = @@ -1255,7 +1496,6 @@ : 0, value = min (ctrl->wLength, (u16) 1); break; -#endif #ifdef DEV_CONFIG_CDC case CDC_SET_ETHERNET_PACKET_FILTER: @@ -1263,8 +1503,11 @@ * wValue = packet filter bitmap */ if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE) + || !dev->cdc + || dev->rndis || ctrl->wLength != 0 || ctrl->wIndex > 1) + break; DEBUG (dev, "NOP packet filter %04x\n", ctrl->wValue); /* NOTE: table 62 has 5 filter bits to reduce traffic, * and we "must" support multicast and promiscuous. @@ -1274,6 +1517,45 @@ break; #endif /* DEV_CONFIG_CDC */ +#ifdef CONFIG_USB_ETH_RNDIS + /* RNDIS uses the CDC command encapsulation mechanism to implement + * an RPC scheme, with much getting/setting of attributes by OID. + */ + case CDC_SEND_ENCAPSULATED_COMMAND: + if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE) + || !dev->rndis + || ctrl->wLength > USB_BUFSIZ + || ctrl->wValue + || rndis_control_intf.bInterfaceNumber + != ctrl->wIndex) + break; + /* read the request, then process it */ + value = ctrl->wLength; + req->complete = rndis_command_complete; + /* later, rndis_control_ack () sends a notification */ + break; + + case CDC_GET_ENCAPSULATED_RESPONSE: + if ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE) + == ctrl->bRequestType + && dev->rndis + // && ctrl->wLength >= 0x0400 + && !ctrl->wValue + && rndis_control_intf.bInterfaceNumber + == ctrl->wIndex) { + u8 *buf; + + /* return the result */ + buf = rndis_get_next_response (dev->rndis_config, + &value); + if (buf) { + memcpy (req->buf, buf, value); + req->complete = rndis_response_complete; + } + } + break; +#endif /* RNDIS */ + default: VDEBUG (dev, "unknown control req%02x.%02x v%04x i%04x l%d\n", @@ -1321,7 +1603,9 @@ { struct eth_dev *dev = (struct eth_dev *) net->priv; - if (new_mtu <= MIN_PACKET || new_mtu > MAX_PACKET) + // FIXME if rndis, don't change while link's live + + if (new_mtu <= ETH_HLEN || new_mtu > ETH_FRAME_LEN) return -ERANGE; /* no zero-length packet read wanted after mtu-sized packets */ if (((new_mtu + sizeof (struct ethhdr)) % dev->in_ep->maxpacket) == 0) @@ -1351,7 +1635,8 @@ info.cmd = ETHTOOL_GDRVINFO; strlcpy (info.driver, shortname, sizeof info.driver); strlcpy (info.version, DRIVER_VERSION, sizeof info.version); - strlcpy (info.fw_version, CHIP, sizeof info.fw_version); + strlcpy (info.fw_version, dev->gadget->name, + sizeof info.fw_version); strlcpy (info.bus_info, dev->gadget->dev.bus_id, sizeof info.bus_info); if (copy_to_user (useraddr, &info, sizeof (info))) @@ -1402,7 +1687,27 @@ int retval = -ENOMEM; size_t size; + /* Padding up to RX_EXTRA handles minor disagreements with host. + * Normally we use the USB "terminate on short read" convention; + * so allow up to (N*maxpacket)-1, since that memory is normally + * already allocated. Major loss of synch means -EOVERFLOW; any + * obviously corrupted packets will automatically be discarded. + * + * RNDIS uses internal framing, and explicitly allows senders to + * pad to end-of-packet. That's potentially nice for speed, + * but means receivers can't recover synch on their own. + */ size = (sizeof (struct ethhdr) + dev->net->mtu + RX_EXTRA); + size += dev->out_ep->maxpacket - 1; +#ifdef CONFIG_USB_ETH_RNDIS + if (dev->rndis) + size += sizeof (struct rndis_packet_msg_type); +#endif + size -= size % dev->out_ep->maxpacket; +#ifdef CONFIG_USB_ETH_RNDIS + if (!dev->rndis) +#endif + size--; if ((skb = alloc_skb (size, gfp_flags)) == 0) { DEBUG (dev, "no rx skb\n"); @@ -1439,8 +1744,12 @@ /* normal completion */ case 0: skb_put (skb, req->actual); - if (MIN_PACKET > skb->len - || skb->len > (MAX_PACKET + ETH_HLEN)) { +#ifdef CONFIG_USB_ETH_RNDIS + /* we know MaxPacketsPerTransfer == 1 here */ + if (dev->rndis) + rndis_rm_hdr (req->buf, &(skb->len)); +#endif + if (ETH_HLEN > skb->len || skb->len > ETH_FRAME_LEN) { dev->stats.rx_errors++; dev->stats.rx_length_errors++; DEBUG (dev, "rx length %d\n", skb->len); @@ -1637,21 +1946,35 @@ /* no buffer copies needed, unless the network stack did it * or the hardware can't use skb buffers. + * or there's not enough space for any RNDIS headers we need */ +#ifdef CONFIG_USB_ETH_RNDIS + if (dev->rndis) { + struct sk_buff *skb_rndis; + + skb_rndis = skb_realloc_headroom (skb, + sizeof (struct rndis_packet_msg_type)); + if (!skb_rndis) + goto drop; + + dev_kfree_skb_any (skb); + skb = skb_rndis; + rndis_add_hdr (skb); + length = skb->len; + } +#endif req->buf = skb->data; req->context = skb; req->complete = tx_complete; -#ifdef CONFIG_USB_GADGET_SA1100 - /* don't demand zlp (req->zero) support from all hardware */ - if ((length % dev->in_ep->maxpacket) == 0) - length++; -#else /* use zlp framing on tx for strict CDC-Ether conformance, * though any robust network rx path ignores extra padding. + * and some hardware doesn't like to write zlps. */ req->zero = 1; -#endif + if (!dev->zlp && (length % dev->in_ep->maxpacket) == 0) + length++; + req->length = length; #ifdef CONFIG_USB_GADGET_DUALSPEED @@ -1672,6 +1995,9 @@ } if (retval) { +#ifdef CONFIG_USB_ETH_RNDIS +drop: +#endif dev->stats.tx_dropped++; dev_kfree_skb_any (skb); spin_lock_irqsave (&dev->lock, flags); @@ -1683,6 +2009,71 @@ return 0; } +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_USB_ETH_RNDIS + +static void rndis_send_media_state (struct eth_dev *dev, int connect) +{ + if (!dev) + return; + + if (connect) { + if (rndis_signal_connect (dev->rndis_config)) + return; + } else { + if (rndis_signal_disconnect (dev->rndis_config)) + return; + } +} + +static int rndis_control_ack (struct net_device *net) +{ + struct eth_dev *dev = (struct eth_dev *) net->priv; + u32 length; + struct usb_request *resp; + + /* in case RNDIS calls this after disconnect */ + if (!dev->status_ep) { + DEBUG (dev, "status ENODEV\n"); + return -ENODEV; + } + + /* Allocate memory for notification ie. ACK */ + resp = usb_ep_alloc_request (dev->status_ep, GFP_ATOMIC); + if (!resp) { + DEBUG (dev, "status ENOMEM\n"); + return -ENOMEM; + } + + resp->buf = usb_ep_alloc_buffer (dev->status_ep, 8, + &resp->dma, GFP_ATOMIC); + if (!resp->buf) { + DEBUG (dev, "status buf ENOMEM\n"); + usb_ep_free_request (dev->status_ep, resp); + return -ENOMEM; + } + + /* Send RNDIS RESPONSE_AVAILABLE notification; + * CDC_NOTIFY_RESPONSE_AVAILABLE should work too + */ + resp->length = 8; + resp->complete = rndis_response_complete; + + *((u32 *) resp->buf) = __constant_cpu_to_le32 (1); + *((u32 *) resp->buf + 1) = __constant_cpu_to_le32 (0); + + length = usb_ep_queue (dev->status_ep, resp, GFP_ATOMIC); + if (length < 0) { + resp->status = 0; + rndis_response_complete (dev->status_ep, resp); + } + + return 0; +} + +#endif /* RNDIS */ + static void eth_start (struct eth_dev *dev, int gfp_flags) { DEBUG (dev, "%s\n", __FUNCTION__); @@ -1693,6 +2084,14 @@ /* and open the tx floodgates */ atomic_set (&dev->tx_qlen, 0); netif_wake_queue (dev->net); +#ifdef CONFIG_USB_ETH_RNDIS + if (dev->rndis) { + rndis_set_param_medium (dev->rndis_config, + NDIS_MEDIUM_802_3, + BITRATE(dev->gadget)); + rndis_send_media_state (dev, 1); + } +#endif } static int eth_open (struct net_device *net) @@ -1727,11 +2126,19 @@ usb_ep_enable (dev->in_ep, dev->in); usb_ep_enable (dev->out_ep, dev->out); } -#ifdef EP_STATUS_NUM - usb_ep_disable (dev->status_ep); - usb_ep_enable (dev->status_ep, dev->status); -#endif + if (dev->status_ep) { + usb_ep_disable (dev->status_ep); + usb_ep_enable (dev->status_ep, dev->status); + } + } + +#ifdef CONFIG_USB_ETH_RNDIS + if (dev->rndis) { + rndis_set_param_medium (dev->rndis_config, + NDIS_MEDIUM_802_3, 0); + rndis_send_media_state (dev, 0); } +#endif return 0; } @@ -1744,6 +2151,10 @@ struct eth_dev *dev = get_gadget_data (gadget); DEBUG (dev, "unbind\n"); +#ifdef CONFIG_USB_ETH_RNDIS + rndis_deregister (dev->rndis_config); + rndis_exit (); +#endif /* we've already been disconnected ... no i/o is active */ if (dev->req) { @@ -1762,30 +2173,183 @@ set_gadget_data (gadget, 0); } -static int +static int __init eth_bind (struct usb_gadget *gadget) { struct eth_dev *dev; struct net_device *net; + u8 cdc = 1, zlp = 1, rndis = 1; + struct usb_ep *ep; int status = -ENOMEM; -#ifdef DEV_CONFIG_CDC - u8 node_id [ETH_ALEN]; - /* just one upstream link at a time */ - if (ethaddr [0] != 0) + /* these flags are only ever cleared; compiler take note */ +#ifndef DEV_CONFIG_CDC + cdc = 0; +#endif +#ifndef CONFIG_USB_ETH_RNDIS + rndis = 0; +#endif + + /* Because most host side USB stacks handle CDC Ethernet, that + * standard protocol is _strongly_ preferred for interop purposes. + * (By everyone except Microsoft.) + */ + if (gadget_is_net2280 (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201); + } else if (gadget_is_dummy (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0202); + } else if (gadget_is_pxa (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0203); + /* pxa doesn't support altsettings */ + cdc = 0; + } else if (gadget_is_sh(gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0204); + /* sh doesn't support multiple interfaces or configs */ + cdc = 0; + rndis = 0; + } else if (gadget_is_sa1100 (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0205); + /* hardware can't write zlps */ + zlp = 0; + /* sa1100 CAN do CDC, without status endpoint ... we use + * non-CDC to be compatible with ARM Linux-2.4 "usb-eth". + */ + cdc = 0; + } else if (gadget_is_goku (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0206); + } else if (gadget_is_mq11xx (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207); + } else if (gadget_is_omap (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208); + } else { + /* can't assume CDC works. don't want to default to + * anything less functional on CDC-capable hardware, + * so we fail in this case. + */ + dev_err (&gadget->dev, + "controller '%s' not recognized\n", + gadget->name); + return -ENODEV; + } + snprintf (manufacturer, sizeof manufacturer, + UTS_SYSNAME " " UTS_RELEASE "/%s", + gadget->name); + + /* CDC subset ... recognized by Linux since 2.4.10, but Windows + * drivers aren't widely available. + */ + if (!cdc) { + device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC; + device_desc.idVendor = + __constant_cpu_to_le16(SIMPLE_VENDOR_NUM); + device_desc.idProduct = + __constant_cpu_to_le16(SIMPLE_PRODUCT_NUM); + } + + /* If there's an RNDIS configuration, that's what Windows wants to + * be using ... so use these product IDs here and in the "linux.inf" + * needed to install MSFT drivers. Current Linux kernels will use + * the second configuration if it's CDC Ethernet, and need some help + * to choose the right configuration otherwise. + */ + if (rndis) { + device_desc.idVendor = + __constant_cpu_to_le16(RNDIS_VENDOR_NUM); + device_desc.idProduct = + __constant_cpu_to_le16(RNDIS_PRODUCT_NUM); + snprintf (product_desc, sizeof product_desc, + "RNDIS/%s", driver_desc); + } + + /* support optional vendor/distro customization */ + if (idVendor) { + if (!idProduct) { + dev_err (&gadget->dev, "idVendor needs idProduct!\n"); + return -ENODEV; + } + device_desc.idVendor = cpu_to_le16(idVendor); + device_desc.idProduct = cpu_to_le16(idProduct); + if (bcdDevice) + device_desc.bcdDevice = cpu_to_le16(bcdDevice); + } + if (iManufacturer) + strlcpy (manufacturer, iManufacturer, sizeof manufacturer); + if (iProduct) + strlcpy (product_desc, iProduct, sizeof product_desc); + + /* all we really need is bulk IN/OUT */ + usb_ep_autoconfig_reset (gadget); + ep = usb_ep_autoconfig (gadget, &fs_source_desc); + if (!ep) { +autoconf_fail: + dev_err (&gadget->dev, + "can't autoconfigure on %s\n", + gadget->name); return -ENODEV; + } + EP_IN_NAME = ep->name; + ep->driver_data = ep; /* claim */ + + ep = usb_ep_autoconfig (gadget, &fs_sink_desc); + if (!ep) + goto autoconf_fail; + EP_OUT_NAME = ep->name; + ep->driver_data = ep; /* claim */ + + /* CDC Ethernet control interface doesn't require a status endpoint. + * Since some hosts expect one, try to allocate one anyway. + */ + if (cdc || rndis) { + ep = usb_ep_autoconfig (gadget, &fs_status_desc); + if (ep) { + EP_STATUS_NAME = ep->name; + ep->driver_data = ep; /* claim */ + } else if (rndis) { + dev_err (&gadget->dev, + "can't run RNDIS on %s\n", + gadget->name); + return -ENODEV; +#ifdef DEV_CONFIG_CDC + } else if (cdc) { + control_intf.bNumEndpoints = 0; + /* FIXME remove endpoint from descriptor list */ #endif + } + } + + /* one config: cdc, else minimal subset */ + if (!cdc) { + eth_config.bNumInterfaces = 1; + eth_config.iConfiguration = STRING_SUBSET; + fs_subset_descriptors(); + hs_subset_descriptors(); + } + + /* For now RNDIS is always a second config */ + if (rndis) + device_desc.bNumConfigurations = 2; - device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; #ifdef CONFIG_USB_GADGET_DUALSPEED + if (rndis) + dev_qualifier.bNumConfigurations = 2; + else if (!cdc) + dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC; + /* assumes ep0 uses the same value for both speeds ... */ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + + /* and that all endpoints are dual-speed */ + hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; + hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; +#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) + if (EP_STATUS_NAME) + hs_status_desc.bEndpointAddress = + fs_status_desc.bEndpointAddress; #endif +#endif /* DUALSPEED */ -#ifdef SELFPOWERED - eth_config.bmAttributes |= USB_CONFIG_ATT_SELFPOWERED; + device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; usb_gadget_set_selfpowered (gadget); -#endif net = alloc_etherdev (sizeof *dev); if (!net) @@ -1800,6 +2364,12 @@ dev->net = net; SET_MODULE_OWNER (net); strcpy (net->name, "usb%d"); + dev->cdc = cdc; + dev->zlp = zlp; + + /* FIXME make these addresses configurable with module params. + * also the manufacturer and product strings. + */ /* one random address for the gadget device ... both of these could * reasonably come from an id prom or a module parameter. @@ -1812,14 +2382,27 @@ /* ... another address for the host, on the other end of the * link, gets exported through CDC (see CDC spec table 41) */ - get_random_bytes (node_id, sizeof node_id); - node_id [0] &= 0xfe; // clear multicast bit - node_id [0] |= 0x02; // set local assignment bit (IEEE802) - snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X", - node_id [0], node_id [1], node_id [2], - node_id [3], node_id [4], node_id [5]); + if (cdc) { + u8 node_id [ETH_ALEN]; + + get_random_bytes (node_id, sizeof node_id); + node_id [0] &= 0xfe; // clear multicast bit + node_id [0] |= 0x02; // set local assignment bit (IEEE802) + snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X", + node_id [0], node_id [1], node_id [2], + node_id [3], node_id [4], node_id [5]); + } #endif + if (rndis) { + status = rndis_init(); + if (status < 0) { + dev_err (&gadget->dev, "can't init RNDIS, %d\n", + status); + goto fail; + } + } + net->change_mtu = eth_change_mtu; net->get_stats = eth_get_stats; net->hard_start_xmit = eth_start_xmit; @@ -1855,15 +2438,57 @@ // SET_NETDEV_DEV (dev->net, &gadget->dev); status = register_netdev (dev->net); - if (status == 0) { + if (status < 0) + goto fail1; + + INFO (dev, "%s, version: " DRIVER_VERSION "\n", driver_desc); + INFO (dev, "using %s, OUT %s IN %s%s%s\n", gadget->name, + EP_OUT_NAME, EP_IN_NAME, + EP_STATUS_NAME ? " STATUS " : "", + EP_STATUS_NAME ? EP_STATUS_NAME : "" + ); + INFO (dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + net->dev_addr [0], net->dev_addr [1], + net->dev_addr [2], net->dev_addr [3], + net->dev_addr [4], net->dev_addr [5]); - INFO (dev, "%s, " CHIP ", version: " DRIVER_VERSION "\n", - driver_desc); #ifdef DEV_CONFIG_CDC + if (cdc) INFO (dev, "CDC host enet %s\n", ethaddr); #endif - return status; + +#ifdef CONFIG_USB_ETH_RNDIS + if (rndis) { + u32 vendorID = 0; + + /* FIXME RNDIS vendor id == "vendor NIC code" == ? */ + + dev->rndis_config = rndis_register (rndis_control_ack); + if (dev->rndis_config < 0) { +fail0: + unregister_netdev (dev->net); + status = -ENODEV; + goto fail; + } + + /* these set up a lot of the OIDs that RNDIS needs */ + if (rndis_set_param_dev (dev->rndis_config, dev->net, + &dev->stats)) + goto fail0; + if (rndis_set_param_vendor (dev->rndis_config, vendorID, + manufacturer)) + goto fail0; + if (rndis_set_param_medium (dev->rndis_config, + NDIS_MEDIUM_802_3, + 0)) + goto fail0; + INFO (dev, "RNDIS ready\n"); } +#endif + + return status; + +fail1: dev_dbg(&gadget->dev, "register_netdev failed, %d\n", status); fail: eth_unbind (gadget); @@ -1894,7 +2519,7 @@ }; MODULE_DESCRIPTION (DRIVER_DESC); -MODULE_AUTHOR ("David Brownell"); +MODULE_AUTHOR ("David Brownell, Benedikt Spanger"); MODULE_LICENSE ("GPL"); diff -Nru a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c --- a/drivers/usb/gadget/file_storage.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/gadget/file_storage.c Tue Apr 6 17:22:26 2004 @@ -239,12 +239,14 @@ #include #include +#include "gadget_chips.h" + /*-------------------------------------------------------------------------*/ #define DRIVER_DESC "File-backed Storage Gadget" #define DRIVER_NAME "g_file_storage" -#define DRIVER_VERSION "26 January 2004" +#define DRIVER_VERSION "21 March 2004" static const char longname[] = DRIVER_DESC; static const char shortname[] = DRIVER_NAME; @@ -261,165 +263,11 @@ #define DRIVER_PRODUCT_ID 0xa4a5 // Linux-USB File-backed Storage Gadget -/*-------------------------------------------------------------------------*/ - -/* - * Hardware-specific configuration, controlled by which device - * controller driver was configured. - * - * CHIP ... hardware identifier - * DRIVER_VERSION_NUM ... alerts the host side driver to differences - * EP_*_NAME ... which endpoints do we use for which purpose? - * EP_*_NUM ... numbers for them (often limited by hardware) - * FS_BULK_IN_MAXPACKET ... maxpacket value for full-speed bulk-in ep - * FS_BULK_OUT_MAXPACKET ... maxpacket value for full-speed bulk-out ep - * HIGHSPEED ... define if ep0 and descriptors need high speed support - * MAX_USB_POWER ... define if we use other than 100 mA bus current - * SELFPOWER ... if we can run on bus power, zero - * NO_BULK_STALL ... bulk endpoint halts don't work well so avoid them - */ - - -/* - * NetChip 2280, PCI based. - * - * This has half a dozen configurable endpoints, four with dedicated - * DMA channels to manage their FIFOs. It supports high speed. - * Those endpoints can be arranged in any desired configuration. - */ -#ifdef CONFIG_USB_GADGET_NET2280 -#define CHIP "net2280" -#define DRIVER_VERSION_NUM 0x0201 -static const char EP_BULK_IN_NAME[] = "ep-a"; -#define EP_BULK_IN_NUM 1 -#define FS_BULK_IN_MAXPACKET 64 -static const char EP_BULK_OUT_NAME[] = "ep-b"; -#define EP_BULK_OUT_NUM 2 -#define FS_BULK_OUT_MAXPACKET 64 -static const char EP_INTR_IN_NAME[] = "ep-e"; -#define EP_INTR_IN_NUM 5 -#define HIGHSPEED -#endif - - -/* - * Dummy_hcd, software-based loopback controller. - * - * This imitates the abilities of the NetChip 2280, so we will use - * the same configuration. - */ -#ifdef CONFIG_USB_GADGET_DUMMY_HCD -#define CHIP "dummy" -#define DRIVER_VERSION_NUM 0x0202 -static const char EP_BULK_IN_NAME[] = "ep-a"; -#define EP_BULK_IN_NUM 1 -#define FS_BULK_IN_MAXPACKET 64 -static const char EP_BULK_OUT_NAME[] = "ep-b"; -#define EP_BULK_OUT_NUM 2 -#define FS_BULK_OUT_MAXPACKET 64 -static const char EP_INTR_IN_NAME[] = "ep-e"; -#define EP_INTR_IN_NUM 5 -#define HIGHSPEED -#endif - - -/* - * PXA-2xx UDC: widely used in second gen Linux-capable PDAs. - * - * This has fifteen fixed-function full speed endpoints, and it - * can support all USB transfer types. - * - * These supports three or four configurations, with fixed numbers. - * The hardware interprets SET_INTERFACE, net effect is that you - * can't use altsettings or reset the interfaces independently. - * So stick to a single interface. - */ -#ifdef CONFIG_USB_GADGET_PXA2XX -#define CHIP "pxa2xx" -#define DRIVER_VERSION_NUM 0x0203 -static const char EP_BULK_IN_NAME[] = "ep1in-bulk"; -#define EP_BULK_IN_NUM 1 -#define FS_BULK_IN_MAXPACKET 64 -static const char EP_BULK_OUT_NAME[] = "ep2out-bulk"; -#define EP_BULK_OUT_NUM 2 -#define FS_BULK_OUT_MAXPACKET 64 -static const char EP_INTR_IN_NAME[] = "ep6in-bulk"; -#define EP_INTR_IN_NUM 6 -#endif - - /* - * SuperH UDC: UDC built-in to some Renesas SH processors. - * - * This has three fixed-function full speed bulk/interrupt endpoints. - * - * Only one configuration and interface is supported (SET_CONFIGURATION - * and SET_INTERFACE are handled completely by the hardware). - */ -#ifdef CONFIG_USB_GADGET_SUPERH -#define CHIP "superh" -#define DRIVER_VERSION_NUM 0x0205 -static const char EP_BULK_IN_NAME[] = "ep2in-bulk"; -#define EP_BULK_IN_NUM 2 -#define FS_BULK_IN_MAXPACKET 64 -static const char EP_BULK_OUT_NAME[] = "ep1out-bulk"; -#define EP_BULK_OUT_NUM 1 -#define FS_BULK_OUT_MAXPACKET 64 -static const char EP_INTR_IN_NAME[] = "ep3in-bulk"; -#define EP_INTR_IN_NUM 3 -#define NO_BULK_STALL -#endif - - -/* - * Toshiba TC86C001 ("Goku-S") UDC - * - * This has three semi-configurable full speed bulk/interrupt endpoints. - */ -#ifdef CONFIG_USB_GADGET_GOKU -#define CHIP "goku" -#define DRIVER_VERSION_NUM 0x0206 -static const char EP_BULK_OUT_NAME [] = "ep1-bulk"; -#define EP_BULK_OUT_NUM 1 -#define FS_BULK_IN_MAXPACKET 64 -static const char EP_BULK_IN_NAME [] = "ep2-bulk"; -#define EP_BULK_IN_NUM 2 -#define FS_BULK_OUT_MAXPACKET 64 -static const char EP_INTR_IN_NAME [] = "ep3-bulk"; -#define EP_INTR_IN_NUM 3 -#endif - - -/*-------------------------------------------------------------------------*/ - -#ifndef CHIP -# error Configure some USB peripheral controller driver! -#endif - -/* Power usage is config specific. - * Hardware that supports remote wakeup defaults to disabling it. + * This driver assumes self-powered hardware and has no way for users to + * trigger remote wakeup. It uses autoconfiguration to select endpoints + * and endpoint addresses. */ -#ifndef SELFPOWER -/* default: say we're self-powered */ -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER -/* else: - * - SELFPOWER value must be zero - * - MAX_USB_POWER may be nonzero. - */ -#endif - -#ifndef MAX_USB_POWER -/* Any hub supports this steady state bus power consumption */ -#define MAX_USB_POWER 100 /* mA */ -#endif - -/* We don't support remote wake-up */ - -#ifdef NO_BULK_STALL -#define CAN_STALL 0 -#else -#define CAN_STALL 1 -#endif /*-------------------------------------------------------------------------*/ @@ -511,9 +359,9 @@ .removable = 0, .vendor = DRIVER_VENDOR_ID, .product = DRIVER_PRODUCT_ID, - .release = DRIVER_VERSION_NUM, + .release = 0xffff, // Use controller chip type .buflen = 16384, - .can_stall = CAN_STALL, + .can_stall = 1, }; @@ -1002,7 +850,7 @@ /* The next three values can be overridden by module parameters */ .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_ID), .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_ID), - .bcdDevice = __constant_cpu_to_le16(DRIVER_VERSION_NUM), + .bcdDevice = __constant_cpu_to_le16(0xffff), .iManufacturer = STRING_MANUFACTURER, .iProduct = STRING_PRODUCT, @@ -1015,11 +863,11 @@ .bLength = sizeof config_desc, .bDescriptorType = USB_DT_CONFIG, - /* wTotalLength adjusted during bind() */ + /* wTotalLength computed by usb_gadget_config_buf() */ .bNumInterfaces = 1, .bConfigurationValue = CONFIG_VALUE, - .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER, - .bMaxPower = (MAX_USB_POWER + 1) / 2, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 1, // self-powered }; /* There is only one interface. */ @@ -1029,47 +877,56 @@ .bLength = sizeof intf_desc, .bDescriptorType = USB_DT_INTERFACE, - .bNumEndpoints = 2, // Adjusted during bind() + .bNumEndpoints = 2, // Adjusted during fsg_bind() .bInterfaceClass = USB_CLASS_MASS_STORAGE, - .bInterfaceSubClass = USB_SC_SCSI, // Adjusted during bind() - .bInterfaceProtocol = USB_PR_BULK, // Adjusted during bind() + .bInterfaceSubClass = USB_SC_SCSI, // Adjusted during fsg_bind() + .bInterfaceProtocol = USB_PR_BULK, // Adjusted during fsg_bind() }; /* Three full-speed endpoint descriptors: bulk-in, bulk-out, * and interrupt-in. */ -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor fs_bulk_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_BULK_IN_NUM | USB_DIR_IN, + .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(FS_BULK_IN_MAXPACKET), + /* wMaxPacketSize set by autoconfiguration */ }; -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor fs_bulk_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_BULK_OUT_NUM, + .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(FS_BULK_OUT_MAXPACKET), + /* wMaxPacketSize set by autoconfiguration */ }; -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor fs_intr_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_INTR_IN_NUM | USB_DIR_IN, + .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = __constant_cpu_to_le16(2), .bInterval = 32, // frames -> 32 ms }; -#ifdef HIGHSPEED +static const struct usb_descriptor_header *fs_function[] = { + (struct usb_descriptor_header *) &intf_desc, + (struct usb_descriptor_header *) &fs_bulk_in_desc, + (struct usb_descriptor_header *) &fs_bulk_out_desc, + (struct usb_descriptor_header *) &fs_intr_in_desc, + NULL, +}; + + +#ifdef CONFIG_USB_GADGET_DUALSPEED /* * USB 2.0 devices need to expose both high speed and full speed @@ -1079,47 +936,55 @@ * and a "device qualifier" ... plus more construction options * for the config descriptor. */ -static const struct usb_endpoint_descriptor +static struct usb_qualifier_descriptor +dev_qualifier = { + .bLength = sizeof dev_qualifier, + .bDescriptorType = USB_DT_DEVICE_QUALIFIER, + + .bcdUSB = __constant_cpu_to_le16(0x0200), + .bDeviceClass = USB_CLASS_PER_INTERFACE, + + .bNumConfigurations = 1, +}; + +static struct usb_endpoint_descriptor hs_bulk_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_BULK_IN_NUM | USB_DIR_IN, + /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */ .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16(512), }; -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor hs_bulk_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_BULK_OUT_NUM, + /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */ .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16(512), .bInterval = 1, // NAK every 1 uframe }; -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor hs_intr_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_INTR_IN_NUM | USB_DIR_IN, + /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */ .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = __constant_cpu_to_le16(2), .bInterval = 9, // 2**(9-1) = 256 uframes -> 32 ms }; -static struct usb_qualifier_descriptor -dev_qualifier = { - .bLength = sizeof dev_qualifier, - .bDescriptorType = USB_DT_DEVICE_QUALIFIER, - - .bcdUSB = __constant_cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_PER_INTERFACE, - - .bNumConfigurations = 1, +static const struct usb_descriptor_header *hs_function[] = { + (struct usb_descriptor_header *) &intf_desc, + (struct usb_descriptor_header *) &hs_bulk_in_desc, + (struct usb_descriptor_header *) &hs_bulk_out_desc, + (struct usb_descriptor_header *) &hs_intr_in_desc, + NULL, }; /* Maxpacket and other transfer characteristics vary by speed. */ @@ -1127,22 +992,23 @@ #else -/* If there's no high speed support, maxpacket doesn't change. */ +/* If there's no high speed support, always use the full-speed descriptor. */ #define ep_desc(g,fs,hs) fs -#endif /* !HIGHSPEED */ +#endif /* !CONFIG_USB_GADGET_DUALSPEED */ /* The CBI specification limits the serial string to 12 uppercase hexadecimal * characters. */ +static char manufacturer[40]; static char serial[13]; -/* Static strings, in ISO 8859/1 */ +/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ static struct usb_string strings[] = { - { STRING_MANUFACTURER, UTS_SYSNAME " " UTS_RELEASE " with " CHIP, }, - { STRING_PRODUCT, longname, }, - { STRING_SERIAL, serial, }, - { } // end of list + {STRING_MANUFACTURER, manufacturer}, + {STRING_PRODUCT, longname}, + {STRING_SERIAL, serial}, + {} }; static struct usb_gadget_strings stringtab = { @@ -1152,61 +1018,33 @@ /* - * Config descriptors are handcrafted. They must agree with the code - * that sets configurations and with code managing interfaces and their - * altsettings. They must also handle different speeds and other-speed - * requests. + * Config descriptors must agree with the code that sets configurations + * and with code managing interfaces and their altsettings. They must + * also handle different speeds and other-speed requests. */ static int populate_config_buf(enum usb_device_speed speed, - u8 *buf0, u8 type, unsigned index) + u8 *buf, u8 type, unsigned index) { - u8 *buf = buf0; -#ifdef HIGHSPEED - int hs; -#endif + int len; + const struct usb_descriptor_header **function; if (index > 0) return -EINVAL; - if (config_desc.wTotalLength > EP0_BUFSIZE) - return -EDOM; - /* Config (or other speed config) */ - memcpy(buf, &config_desc, USB_DT_CONFIG_SIZE); - buf[1] = type; - buf += USB_DT_CONFIG_SIZE; - - /* Interface */ - memcpy(buf, &intf_desc, USB_DT_INTERFACE_SIZE); - buf += USB_DT_INTERFACE_SIZE; - - /* The endpoints in the interface (at that speed) */ -#ifdef HIGHSPEED - hs = (speed == USB_SPEED_HIGH); +#ifdef CONFIG_USB_GADGET_DUALSPEED if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; - if (hs) { - memcpy(buf, &hs_bulk_in_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - memcpy(buf, &hs_bulk_out_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - if (transport_is_cbi()) { - memcpy(buf, &hs_intr_in_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - } - } else + speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed; + if (speed == USB_SPEED_HIGH) + function = hs_function; + else #endif - { - memcpy(buf, &fs_bulk_in_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - memcpy(buf, &fs_bulk_out_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - if (transport_is_cbi()) { - memcpy(buf, &fs_intr_in_desc, USB_DT_ENDPOINT_SIZE); - buf += USB_DT_ENDPOINT_SIZE; - } - } + function = fs_function; - return buf - buf0; + 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; } @@ -1505,22 +1343,26 @@ value = min(ctrl->wLength, (u16) sizeof device_desc); memcpy(req->buf, &device_desc, value); break; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: VDBG(fsg, "get device qualifier\n"); + if (!fsg->gadget->is_dualspeed) + break; value = min(ctrl->wLength, (u16) sizeof dev_qualifier); memcpy(req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: VDBG(fsg, "get other-speed config descriptor\n"); + if (!fsg->gadget->is_dualspeed) + break; goto get_config; -#endif /* HIGHSPEED */ +#endif case USB_DT_CONFIG: VDBG(fsg, "get configuration descriptor\n"); -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED get_config: -#endif /* HIGHSPEED */ +#endif value = populate_config_buf(fsg->gadget->speed, req->buf, ctrl->wValue >> 8, @@ -2164,7 +2006,7 @@ buf[4] = 31; // Additional length // No special options sprintf(buf + 8, "%-8s%-16s%04x", vendor_id, product_id, - DRIVER_VERSION_NUM); + mod_data.release); return 36; } @@ -3258,6 +3100,7 @@ if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0) goto reset; fsg->bulk_out_enabled = 1; + fsg->bulk_out_maxpacket = d->wMaxPacketSize; if (transport_is_cbi()) { d = ep_desc(fsg->gadget, &fs_intr_in_desc, &hs_intr_in_desc); @@ -3842,6 +3685,34 @@ mod_data.protocol_type = USB_SC_SCSI; mod_data.protocol_name = "Transparent SCSI"; + if (gadget_is_sh(fsg->gadget)) + mod_data.can_stall = 0; + + if (mod_data.release == 0xffff) { // Parameter wasn't set + if (gadget_is_net2280(fsg->gadget)) + mod_data.release = __constant_cpu_to_le16(0x0301); + else if (gadget_is_dummy(fsg->gadget)) + mod_data.release = __constant_cpu_to_le16(0x0302); + else if (gadget_is_pxa(fsg->gadget)) + mod_data.release = __constant_cpu_to_le16(0x0303); + else if (gadget_is_sh(fsg->gadget)) + mod_data.release = __constant_cpu_to_le16(0x0304); + + /* The sa1100 controller is not supported */ + + else if (gadget_is_goku(fsg->gadget)) + mod_data.release = __constant_cpu_to_le16(0x0306); + else if (gadget_is_mq11xx(fsg->gadget)) + mod_data.release = __constant_cpu_to_le16(0x0307); + else if (gadget_is_omap(fsg->gadget)) + mod_data.release = __constant_cpu_to_le16(0x0308); + else { + WARN(fsg, "controller '%s' not recognized\n", + fsg->gadget->name); + mod_data.release = __constant_cpu_to_le16(0x0399); + } + } + prot = simple_strtol(mod_data.protocol_parm, NULL, 0); #ifdef CONFIG_USB_FILE_STORAGE_TEST @@ -3854,7 +3725,7 @@ mod_data.transport_type = USB_PR_CBI; mod_data.transport_name = "Control-Bulk-Interrupt"; } else { - INFO(fsg, "invalid transport: %s\n", mod_data.transport_parm); + ERROR(fsg, "invalid transport: %s\n", mod_data.transport_parm); return -EINVAL; } @@ -3883,13 +3754,13 @@ mod_data.protocol_type = USB_SC_8070; mod_data.protocol_name = "8070i"; } else { - INFO(fsg, "invalid protocol: %s\n", mod_data.protocol_parm); + ERROR(fsg, "invalid protocol: %s\n", mod_data.protocol_parm); return -EINVAL; } mod_data.buflen &= PAGE_CACHE_MASK; if (mod_data.buflen <= 0) { - INFO(fsg, "invalid buflen\n"); + ERROR(fsg, "invalid buflen\n"); return -ETOOSMALL; } #endif /* CONFIG_USB_FILE_STORAGE_TEST */ @@ -3927,7 +3798,7 @@ if (i == 0) i = max(mod_data.num_filenames, 1); if (i > MAX_LUNS) { - INFO(fsg, "invalid number of LUNs: %d\n", i); + ERROR(fsg, "invalid number of LUNs: %d\n", i); rc = -EINVAL; goto out; } @@ -3956,45 +3827,56 @@ if ((rc = open_backing_file(curlun, file[i])) != 0) goto out; } else if (!mod_data.removable) { - INFO(fsg, "no file given for LUN%d\n", i); + ERROR(fsg, "no file given for LUN%d\n", i); rc = -EINVAL; goto out; } } + /* Find all the endpoints we will use */ + ep = usb_ep_autoconfig(gadget, &fs_bulk_in_desc); + if (!ep) + goto autoconf_fail; + ep->driver_data = fsg; // claim the endpoint + fsg->bulk_in = ep; + + ep = usb_ep_autoconfig(gadget, &fs_bulk_out_desc); + if (!ep) + goto autoconf_fail; + ep->driver_data = fsg; // claim the endpoint + fsg->bulk_out = ep; + + if (transport_is_cbi()) { + ep = usb_ep_autoconfig(gadget, &fs_intr_in_desc); + if (!ep) + goto autoconf_fail; + ep->driver_data = fsg; // claim the endpoint + fsg->intr_in = ep; + } + /* Fix up the descriptors */ device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket; -#ifdef HIGHSPEED - dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; // ??? -#endif device_desc.idVendor = cpu_to_le16(mod_data.vendor); device_desc.idProduct = cpu_to_le16(mod_data.product); device_desc.bcdDevice = cpu_to_le16(mod_data.release); i = (transport_is_cbi() ? 3 : 2); // Number of endpoints - config_desc.wTotalLength = USB_DT_CONFIG_SIZE + USB_DT_INTERFACE_SIZE - + USB_DT_ENDPOINT_SIZE * i; intf_desc.bNumEndpoints = i; intf_desc.bInterfaceSubClass = mod_data.protocol_type; intf_desc.bInterfaceProtocol = mod_data.transport_type; + fs_function[i+1] = NULL; - /* Find all the endpoints we will use */ - gadget_for_each_ep(ep, gadget) { - if (strcmp(ep->name, EP_BULK_IN_NAME) == 0) - fsg->bulk_in = ep; - else if (strcmp(ep->name, EP_BULK_OUT_NAME) == 0) - fsg->bulk_out = ep; - else if (strcmp(ep->name, EP_INTR_IN_NAME) == 0) - fsg->intr_in = ep; - } - if (!fsg->bulk_in || !fsg->bulk_out || - (transport_is_cbi() && !fsg->intr_in)) { - DBG(fsg, "unable to find all endpoints\n"); - rc = -ENOTSUPP; - goto out; - } - fsg->bulk_out_maxpacket = (gadget->speed == USB_SPEED_HIGH ? 512 : - FS_BULK_OUT_MAXPACKET); +#ifdef CONFIG_USB_GADGET_DUALSPEED + hs_function[i+1] = NULL; + + /* Assume ep0 uses the same maxpacket value for both speeds */ + dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; + + /* Assume that all endpoint addresses are the same for both speeds */ + hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress; + hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress; + hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress; +#endif rc = -ENOMEM; @@ -4023,6 +3905,10 @@ /* This should reflect the actual gadget power source */ usb_gadget_set_selfpowered(gadget); + snprintf(manufacturer, sizeof manufacturer, + UTS_SYSNAME " " UTS_RELEASE " with %s", + gadget->name); + /* On a real device, serial[] would be loaded from permanent * storage. We just encode it from the driver version string. */ for (i = 0; i < sizeof(serial) - 2; i += 2) { @@ -4071,6 +3957,10 @@ DBG(fsg, "I/O thread pid: %d\n", fsg->thread_pid); return 0; +autoconf_fail: + ERROR(fsg, "unable to autoconfigure all endpoints\n"); + rc = -ENOTSUPP; + out: fsg->state = FSG_STATE_TERMINATED; // The thread is dead fsg_unbind(gadget); @@ -4082,7 +3972,7 @@ /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver fsg_driver = { -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED .speed = USB_SPEED_HIGH, #else .speed = USB_SPEED_FULL, diff -Nru a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h --- a/drivers/usb/gadget/gadget_chips.h Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/gadget/gadget_chips.h Tue Apr 6 17:22:26 2004 @@ -14,6 +14,12 @@ #define gadget_is_net2280(g) 0 #endif +#ifdef CONFIG_USB_GADGET_DUMMY_HCD +#define gadget_is_dummy(g) !strcmp("dummy_udc", (g)->name) +#else +#define gadget_is_dummy(g) 0 +#endif + #ifdef CONFIG_USB_GADGET_PXA #define gadget_is_pxa(g) !strcmp("pxa2xx_udc", (g)->name) #else diff -Nru a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c --- a/drivers/usb/gadget/goku_udc.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/gadget/goku_udc.c Tue Apr 6 17:22:26 2004 @@ -1562,8 +1562,7 @@ if (dev->ep[tmp].is_in) goto stall; } - /* endpoint halt */ - if (ctrl.wValue != 0) + if (ctrl.wValue != USB_ENDPOINT_HALT) goto stall; if (tmp) goku_clear_halt(&dev->ep[tmp]); diff -Nru a/drivers/usb/gadget/ndis.h b/drivers/usb/gadget/ndis.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/gadget/ndis.h Tue Apr 6 17:22:26 2004 @@ -0,0 +1,187 @@ +/* + * ndis.h + * + * ntddndis.h modified by Benedikt Spranger + * + * Thanks to the cygwin development team, + * espacially to Casper S. Hornstrup + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef _LINUX_NDIS_H +#define _LINUX_NDIS_H + + +#define NDIS_STATUS_MULTICAST_FULL 0xC0010009 +#define NDIS_STATUS_MULTICAST_EXISTS 0xC001000A +#define NDIS_STATUS_MULTICAST_NOT_FOUND 0xC001000B + +/* NDIS_PNP_CAPABILITIES.Flags constants */ +#define NDIS_DEVICE_WAKE_UP_ENABLE 0x00000001 +#define NDIS_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE 0x00000002 +#define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE 0x00000004 + +/* Required Object IDs (OIDs) */ +#define OID_GEN_SUPPORTED_LIST 0x00010101 +#define OID_GEN_HARDWARE_STATUS 0x00010102 +#define OID_GEN_MEDIA_SUPPORTED 0x00010103 +#define OID_GEN_MEDIA_IN_USE 0x00010104 +#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105 +#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106 +#define OID_GEN_LINK_SPEED 0x00010107 +#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108 +#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109 +#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A +#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B +#define OID_GEN_VENDOR_ID 0x0001010C +#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D +#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E +#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F +#define OID_GEN_DRIVER_VERSION 0x00010110 +#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111 +#define OID_GEN_PROTOCOL_OPTIONS 0x00010112 +#define OID_GEN_MAC_OPTIONS 0x00010113 +#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114 +#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115 +#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116 +#define OID_GEN_SUPPORTED_GUIDS 0x00010117 +#define OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118 +#define OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119 +#define OID_GEN_MACHINE_NAME 0x0001021A +#define OID_GEN_RNDIS_CONFIG_PARAMETER 0x0001021B +#define OID_GEN_VLAN_ID 0x0001021C + +/* Optional OIDs */ +#define OID_GEN_MEDIA_CAPABILITIES 0x00010201 +#define OID_GEN_PHYSICAL_MEDIUM 0x00010202 + +/* Required statistics OIDs */ +#define OID_GEN_XMIT_OK 0x00020101 +#define OID_GEN_RCV_OK 0x00020102 +#define OID_GEN_XMIT_ERROR 0x00020103 +#define OID_GEN_RCV_ERROR 0x00020104 +#define OID_GEN_RCV_NO_BUFFER 0x00020105 + +/* Optional statistics OIDs */ +#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 +#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202 +#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203 +#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204 +#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205 +#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206 +#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207 +#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208 +#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209 +#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A +#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B +#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C +#define OID_GEN_RCV_CRC_ERROR 0x0002020D +#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E +#define OID_GEN_GET_TIME_CAPS 0x0002020F +#define OID_GEN_GET_NETCARD_TIME 0x00020210 +#define OID_GEN_NETCARD_LOAD 0x00020211 +#define OID_GEN_DEVICE_PROFILE 0x00020212 +#define OID_GEN_INIT_TIME_MS 0x00020213 +#define OID_GEN_RESET_COUNTS 0x00020214 +#define OID_GEN_MEDIA_SENSE_COUNTS 0x00020215 +#define OID_GEN_FRIENDLY_NAME 0x00020216 +#define OID_GEN_MINIPORT_INFO 0x00020217 +#define OID_GEN_RESET_VERIFY_PARAMETERS 0x00020218 + +/* IEEE 802.3 (Ethernet) OIDs */ +#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001 + +#define OID_802_3_PERMANENT_ADDRESS 0x01010101 +#define OID_802_3_CURRENT_ADDRESS 0x01010102 +#define OID_802_3_MULTICAST_LIST 0x01010103 +#define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104 +#define OID_802_3_MAC_OPTIONS 0x01010105 +#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101 +#define OID_802_3_XMIT_ONE_COLLISION 0x01020102 +#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103 +#define OID_802_3_XMIT_DEFERRED 0x01020201 +#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202 +#define OID_802_3_RCV_OVERRUN 0x01020203 +#define OID_802_3_XMIT_UNDERRUN 0x01020204 +#define OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205 +#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206 +#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207 + +/* OID_GEN_MINIPORT_INFO constants */ +#define NDIS_MINIPORT_BUS_MASTER 0x00000001 +#define NDIS_MINIPORT_WDM_DRIVER 0x00000002 +#define NDIS_MINIPORT_SG_LIST 0x00000004 +#define NDIS_MINIPORT_SUPPORTS_MEDIA_QUERY 0x00000008 +#define NDIS_MINIPORT_INDICATES_PACKETS 0x00000010 +#define NDIS_MINIPORT_IGNORE_PACKET_QUEUE 0x00000020 +#define NDIS_MINIPORT_IGNORE_REQUEST_QUEUE 0x00000040 +#define NDIS_MINIPORT_IGNORE_TOKEN_RING_ERRORS 0x00000080 +#define NDIS_MINIPORT_INTERMEDIATE_DRIVER 0x00000100 +#define NDIS_MINIPORT_IS_NDIS_5 0x00000200 +#define NDIS_MINIPORT_IS_CO 0x00000400 +#define NDIS_MINIPORT_DESERIALIZE 0x00000800 +#define NDIS_MINIPORT_REQUIRES_MEDIA_POLLING 0x00001000 +#define NDIS_MINIPORT_SUPPORTS_MEDIA_SENSE 0x00002000 +#define NDIS_MINIPORT_NETBOOT_CARD 0x00004000 +#define NDIS_MINIPORT_PM_SUPPORTED 0x00008000 +#define NDIS_MINIPORT_SUPPORTS_MAC_ADDRESS_OVERWRITE 0x00010000 +#define NDIS_MINIPORT_USES_SAFE_BUFFER_APIS 0x00020000 +#define NDIS_MINIPORT_HIDDEN 0x00040000 +#define NDIS_MINIPORT_SWENUM 0x00080000 +#define NDIS_MINIPORT_SURPRISE_REMOVE_OK 0x00100000 +#define NDIS_MINIPORT_NO_HALT_ON_SUSPEND 0x00200000 +#define NDIS_MINIPORT_HARDWARE_DEVICE 0x00400000 +#define NDIS_MINIPORT_SUPPORTS_CANCEL_SEND_PACKETS 0x00800000 +#define NDIS_MINIPORT_64BITS_DMA 0x01000000 + +#define NDIS_MEDIUM_802_3 0x00000000 +#define NDIS_MEDIUM_802_5 0x00000001 +#define NDIS_MEDIUM_FDDI 0x00000002 +#define NDIS_MEDIUM_WAN 0x00000003 +#define NDIS_MEDIUM_LOCAL_TALK 0x00000004 +#define NDIS_MEDIUM_DIX 0x00000005 +#define NDIS_MEDIUM_ARCENT_RAW 0x00000006 +#define NDIS_MEDIUM_ARCENT_878_2 0x00000007 +#define NDIS_MEDIUM_ATM 0x00000008 +#define NDIS_MEDIUM_WIRELESS_LAN 0x00000009 +#define NDIS_MEDIUM_IRDA 0x0000000A +#define NDIS_MEDIUM_BPC 0x0000000B +#define NDIS_MEDIUM_CO_WAN 0x0000000C +#define NDIS_MEDIUM_1394 0x0000000D + +#define NDIS_PACKET_TYPE_DIRECTED 0x00000001 +#define NDIS_PACKET_TYPE_MULTICAST 0x00000002 +#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 +#define NDIS_PACKET_TYPE_BROADCAST 0x00000008 +#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010 +#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020 +#define NDIS_PACKET_TYPE_SMT 0x00000040 +#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080 +#define NDIS_PACKET_TYPE_GROUP 0x00000100 +#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00000200 +#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400 +#define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800 + +#define NDIS_MEDIA_STATE_CONNECTED 0x00000000 +#define NDIS_MEDIA_STATE_DISCONNECTED 0x00000001 + +#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA 0x00000001 +#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED 0x00000002 +#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND 0x00000004 +#define NDIS_MAC_OPTION_NO_LOOPBACK 0x00000008 +#define NDIS_MAC_OPTION_FULL_DUPLEX 0x00000010 +#define NDIS_MAC_OPTION_EOTX_INDICATION 0x00000020 +#define NDIS_MAC_OPTION_8021P_PRIORITY 0x00000040 +#define NDIS_MAC_OPTION_RESERVED 0x80000000 + +#endif /* _LINUX_NDIS_H */ diff -Nru a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c --- a/drivers/usb/gadget/net2280.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/gadget/net2280.c Tue Apr 6 17:22:26 2004 @@ -2401,7 +2401,7 @@ /* hw handles device features */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wValue != 0 /* HALT feature */ + if (u.r.wValue != USB_ENDPOINT_HALT || u.r.wLength != 0) goto do_stall; if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0) @@ -2418,7 +2418,7 @@ /* hw handles device features */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; - if (u.r.wValue != 0 /* HALT feature */ + if (u.r.wValue != USB_ENDPOINT_HALT || u.r.wLength != 0) goto do_stall; if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0) diff -Nru a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c --- a/drivers/usb/gadget/pxa2xx_udc.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/gadget/pxa2xx_udc.c Tue Apr 6 17:22:26 2004 @@ -94,7 +94,7 @@ #define UDC_PROC_FILE #endif -#ifdef CONFIG_ARCH_IXP425 +#ifdef CONFIG_ARCH_IXP4XX #undef USE_DMA /* cpu-specific register addresses are compiled in to this code */ @@ -2374,8 +2374,8 @@ #if defined(CONFIG_ARCH_PXA) #define CP15R0_XSCALE_VALUE 0x69052000 /* intel/arm/xscale */ -#elif defined(CONFIG_ARCH_IXP425) -#define CP15R0_XSCALE_VALUE 0x69054000 /* intel/arm/ixp425 */ +#elif defined(CONFIG_ARCH_IXP4XX) +#define CP15R0_XSCALE_VALUE 0x69054000 /* intel/arm/ixp4xx */ #endif @@ -2434,7 +2434,7 @@ /* fall through */ case PXA250_C0: case PXA210_C0: break; -#elif defined(CONFIG_ARCH_IXP425) +#elif defined(CONFIG_ARCH_IXP4XX) case IXP425_A0: out_dma = 0; break; diff -Nru a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/gadget/rndis.c Tue Apr 6 17:22:26 2004 @@ -0,0 +1,1368 @@ +/* + * RNDIS MSG parser + * + * Version: $Id: rndis.c,v 1.19 2004/03/25 21:33:46 robert Exp $ + * + * Authors: Benedikt Spranger, Pengutronix + * Robert Schwebel, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2, as published by the Free Software Foundation. + * + * This software was originally developed in conformance with + * Microsoft's Remote NDIS Specification License Agreement. + * + * 03/12/2004 Kai-Uwe Bloem + * Fixed message length bug in init_response + * + * 03/25/2004 Kai-Uwe Bloem + * Fixed rndis_rm_hdr length bug. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "rndis.h" + + +#if 0 +#define DEBUG if (rndis_debug) printk +static int rndis_debug = 0; + +MODULE_PARM (rndis_debug, "i"); +MODULE_PARM_DESC (rndis_debug, "enable debugging"); + +#else +#define DEBUG(str,args...) do{}while(0) +#endif + +#define RNDIS_MAX_CONFIGS 1 + +static struct proc_dir_entry *rndis_connect_dir; +static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS]; + +static rndis_params rndis_per_dev_params [RNDIS_MAX_CONFIGS]; + +/* Driver Version */ +static const u32 rndis_driver_version = __constant_cpu_to_le32 (1); + +/* Function Prototypes */ +static int rndis_init_response (int configNr, rndis_init_msg_type *buf); +static int rndis_query_response (int configNr, rndis_query_msg_type *buf); +static int rndis_set_response (int configNr, rndis_set_msg_type *buf); +static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf); +static int rndis_keepalive_response (int configNr, + rndis_keepalive_msg_type *buf); + +static rndis_resp_t *rndis_add_response (int configNr, u32 length); + +/* helper functions */ +static u32 devFlags2currentFilter (struct net_device *dev) +{ + u32 filter = 0; + + if (!dev) return 0; + + if (dev->flags & IFF_MULTICAST) + filter |= NDIS_PACKET_TYPE_MULTICAST; + if (dev->flags & IFF_BROADCAST) + filter |= NDIS_PACKET_TYPE_BROADCAST; + if (dev->flags & IFF_ALLMULTI) + filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; + if (dev->flags & IFF_PROMISC) + filter |= NDIS_PACKET_TYPE_PROMISCUOUS; + + return filter; +} + +static void currentFilter2devFlags (u32 currentFilter, struct net_device *dev) +{ + if (!dev) return; + + if (currentFilter & NDIS_PACKET_TYPE_MULTICAST) + dev->flags |= IFF_MULTICAST; + if (currentFilter & NDIS_PACKET_TYPE_BROADCAST) + dev->flags |= IFF_BROADCAST; + if (currentFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) + dev->flags |= IFF_ALLMULTI; + if (currentFilter & NDIS_PACKET_TYPE_PROMISCUOUS) + dev->flags |= IFF_PROMISC; +} + + +/* NDIS Functions */ +static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r) +{ + int retval = -ENOTSUPP; + u32 length = 0; + rndis_query_cmplt_type *resp; + + if (!r) return -ENOMEM; + resp = (rndis_query_cmplt_type *) r->buf; + + if (!resp) return -ENOMEM; + + if (!resp) return -ENOMEM; + + switch (OID) { + /* mandatory */ + case OID_GEN_SUPPORTED_LIST: + DEBUG ("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__); + length = sizeof (oid_supported_list); + memcpy ((u8 *) resp + 24, oid_supported_list, length); + retval = 0; + break; + + /* mandatory */ + case OID_GEN_HARDWARE_STATUS: + DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__); + length = 4; + /* Bogus question! + * Hardware must be ready to recieve high level protocols. + * BTW: + * reddite ergo quae sunt Caesaris Caesari + * et quae sunt Dei Deo! + */ + *((u32 *) resp + 6) = 0; + retval = 0; + break; + + /* mandatory */ + case OID_GEN_MEDIA_SUPPORTED: + DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__); + length = 4; + *((u32 *) resp + 6) = rndis_per_dev_params [configNr].medium; + retval = 0; + break; + + /* mandatory */ + case OID_GEN_MEDIA_IN_USE: + DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__); + length = 4; + /* one medium, one transport... (maybe you do it better) */ + *((u32 *) resp + 6) = rndis_per_dev_params [configNr].medium; + retval = 0; + break; + + case OID_GEN_MAXIMUM_LOOKAHEAD: + DEBUG("%s: OID_GEN_MAXIMUM_LOOKAHEAD\n", __FUNCTION__); + break; + + /* mandatory */ + case OID_GEN_MAXIMUM_FRAME_SIZE: + DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].dev) { + length = 4; + *((u32 *) resp + 6) = rndis_per_dev_params [configNr] + .dev->mtu; + retval = 0; + } else { + *((u32 *) resp + 6) = 0; + retval = 0; + } + break; + + /* mandatory */ + case OID_GEN_LINK_SPEED: + DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__); + length = 4; + if (rndis_per_dev_params [configNr].media_state) + *((u32 *) resp + 6) = 0; + else + *((u32 *) resp + 6) = rndis_per_dev_params [configNr].speed; + retval = 0; + break; + + case OID_GEN_TRANSMIT_BUFFER_SPACE: + DEBUG("%s: OID_GEN_TRANSMIT_BUFFER_SPACE\n", __FUNCTION__); + length = 4; + *((u32 *) resp + 6) = 0; + retval = 0; + break; + + case OID_GEN_RECEIVE_BUFFER_SPACE: + DEBUG("%s: OID_GEN_RECEIVE_BUFFER_SPACE\n", __FUNCTION__); + break; + + /* mandatory */ + case OID_GEN_TRANSMIT_BLOCK_SIZE: + DEBUG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].dev) { + length = 4; + *((u32 *) resp + 6) = rndis_per_dev_params [configNr] + .dev->mtu; + retval = 0; + } + break; + + /* mandatory */ + case OID_GEN_RECEIVE_BLOCK_SIZE: + DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].dev) { + length = 4; + *((u32 *) resp + 6) = rndis_per_dev_params [configNr] + .dev->mtu; + retval = 0; + } + break; + + /* mandatory */ + case OID_GEN_VENDOR_ID: + DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__); + length = 4; + *((u32 *) resp + 6) = rndis_per_dev_params [configNr].vendorID; + retval = 0; + break; + + /* mandatory */ + case OID_GEN_VENDOR_DESCRIPTION: + DEBUG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__); + length = strlen (rndis_per_dev_params [configNr].vendorDescr); + memcpy ((u8 *) resp + 24, + rndis_per_dev_params [configNr].vendorDescr, length); + retval = 0; + break; + + /* mandatory */ + case OID_GEN_CURRENT_PACKET_FILTER: + DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__); + length = 4; + *((u32 *) resp + 6) = devFlags2currentFilter ( + rndis_per_dev_params [configNr].dev); + retval = 0; + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + DEBUG("%s: OID_GEN_CURRENT_LOOKAHEAD\n", __FUNCTION__); + break; + + case OID_GEN_DRIVER_VERSION: + DEBUG("%s: OID_GEN_DRIVER_VERSION\n", __FUNCTION__); + break; + + /* mandatory */ + case OID_GEN_MAXIMUM_TOTAL_SIZE: + DEBUG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__); + length = 4; + *((u32 *) resp + 6) = RNDIS_MAX_TOTAL_SIZE; + retval = 0; + break; + + case OID_GEN_PROTOCOL_OPTIONS: + DEBUG("%s: OID_GEN_PROTOCOL_OPTIONS\n", __FUNCTION__); + break; + + case OID_GEN_MAC_OPTIONS: + DEBUG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__); + length = 4; + *((u32 *) resp + 6) = NDIS_MAC_OPTION_RECEIVE_SERIALIZED | + NDIS_MAC_OPTION_FULL_DUPLEX; + retval = 0; + break; + + /* mandatory */ + case OID_GEN_MEDIA_CONNECT_STATUS: + DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__); + length = 4; + *((u32 *) resp + 6) = rndis_per_dev_params [configNr] + .media_state; + retval = 0; + break; + + case OID_GEN_MAXIMUM_SEND_PACKETS: + DEBUG("%s: OID_GEN_MAXIMUM_SEND_PACKETS\n", __FUNCTION__); + break; + + /* mandatory */ + case OID_GEN_VENDOR_DRIVER_VERSION: + DEBUG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__); + length = 4; + *((u32 *) resp + 6) = rndis_driver_version; + retval = 0; + break; + + case OID_GEN_SUPPORTED_GUIDS: + DEBUG("%s: OID_GEN_SUPPORTED_GUIDS\n", __FUNCTION__); + break; + + case OID_GEN_NETWORK_LAYER_ADDRESSES: + DEBUG("%s: OID_GEN_NETWORK_LAYER_ADDRESSES\n", __FUNCTION__); + break; + + case OID_GEN_TRANSPORT_HEADER_OFFSET: + DEBUG("%s: OID_GEN_TRANSPORT_HEADER_OFFSET\n", __FUNCTION__); + break; + + case OID_GEN_MACHINE_NAME: + DEBUG("%s: OID_GEN_MACHINE_NAME\n", __FUNCTION__); + break; + + case OID_GEN_RNDIS_CONFIG_PARAMETER: + DEBUG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER\n", __FUNCTION__); + length = 4; + *((u32 *) resp + 6) = 0; + retval = 0; + break; + + case OID_GEN_VLAN_ID: + DEBUG("%s: OID_GEN_VLAN_ID\n", __FUNCTION__); + break; + + case OID_GEN_MEDIA_CAPABILITIES: + DEBUG("%s: OID_GEN_MEDIA_CAPABILITIES\n", __FUNCTION__); + break; + + case OID_GEN_PHYSICAL_MEDIUM: + DEBUG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__); + length = 4; + *((u32 *) resp + 6) = 0; + retval = 0; + break; + + /* mandatory */ + case OID_GEN_XMIT_OK: + DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].stats) { + length = 4; + *((u32 *) resp + 6) = rndis_per_dev_params [configNr] + .stats->tx_packets - + rndis_per_dev_params [configNr].stats->tx_errors - + rndis_per_dev_params [configNr].stats->tx_dropped; + retval = 0; + } else { + *((u32 *) resp + 6) = 0; + retval = 0; + } + break; + + /* mandatory */ + case OID_GEN_RCV_OK: + DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].stats) { + length = 4; + *((u32 *) resp + 6) = rndis_per_dev_params [configNr]. + stats->rx_packets - + rndis_per_dev_params [configNr].stats->rx_errors - + rndis_per_dev_params [configNr].stats->rx_dropped; + retval = 0; + } else { + *((u32 *) resp + 6) = 0; + retval = 0; + } + break; + + /* mandatory */ + case OID_GEN_XMIT_ERROR: + DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].stats) { + length = 4; + *((u32 *) resp + 6) = rndis_per_dev_params [configNr]. + stats->tx_errors; + retval = 0; + } else { + *((u32 *) resp + 6) = 0; + retval = 0; + } + break; + + /* mandatory */ + case OID_GEN_RCV_ERROR: + DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].stats) { + *((u32 *) resp + 6) = rndis_per_dev_params [configNr]. + stats->rx_errors; + retval = 0; + } else { + *((u32 *) resp + 6) = 0; + retval = 0; + } + break; + + /* mandatory */ + case OID_GEN_RCV_NO_BUFFER: + DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].stats) { + *((u32 *) resp + 6) = rndis_per_dev_params [configNr]. + stats->rx_dropped; + retval = 0; + } else { + *((u32 *) resp + 6) = 0; + retval = 0; + } + break; + + case OID_GEN_DIRECTED_BYTES_XMIT: + DEBUG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __FUNCTION__); + /* + * Aunt Tilly's size of shoes + * minus antarctica count of penguins + * divided by weight of Alpha Centauri + */ + if (rndis_per_dev_params [configNr].stats) { + length = 4; + *((u32 *) resp + 6) = (rndis_per_dev_params [configNr]. + stats->tx_packets - + rndis_per_dev_params [configNr].stats->tx_errors - + rndis_per_dev_params [configNr].stats->tx_dropped) + *123; + retval = 0; + } else { + *((u32 *) resp + 6) = 0; + retval = 0; + } + break; + + case OID_GEN_DIRECTED_FRAMES_XMIT: + DEBUG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__); + /* dito */ + if (rndis_per_dev_params [configNr].stats) { + length = 4; + *((u32 *) resp + 6) = (rndis_per_dev_params [configNr]. + stats->tx_packets - + rndis_per_dev_params [configNr].stats->tx_errors - + rndis_per_dev_params [configNr].stats->tx_dropped) + /123; + retval = 0; + } else { + *((u32 *) resp + 6) = 0; + retval = 0; + } + break; + + case OID_GEN_MULTICAST_BYTES_XMIT: + DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].stats) { + *((u32 *) resp + 6) = rndis_per_dev_params [configNr]. + stats->multicast*1234; + retval = 0; + } else { + *((u32 *) resp + 6) = 0; + retval = 0; + } + break; + + case OID_GEN_MULTICAST_FRAMES_XMIT: + DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].stats) { + *((u32 *) resp + 6) = rndis_per_dev_params [configNr]. + stats->multicast; + retval = 0; + } else { + *((u32 *) resp + 6) = 0; + retval = 0; + } + break; + + case OID_GEN_BROADCAST_BYTES_XMIT: + DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].stats) { + *((u32 *) resp + 6) = rndis_per_dev_params [configNr]. + stats->tx_packets/42*255; + retval = 0; + } else { + *((u32 *) resp + 6) = 0; + retval = 0; + } + break; + + case OID_GEN_BROADCAST_FRAMES_XMIT: + DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].stats) { + *((u32 *) resp + 6) = rndis_per_dev_params [configNr]. + stats->tx_packets/42; + retval = 0; + } else { + *((u32 *) resp + 6) = 0; + retval = 0; + } + break; + + case OID_GEN_DIRECTED_BYTES_RCV: + DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__); + *((u32 *) resp + 6) = 0; + retval = 0; + break; + + case OID_GEN_DIRECTED_FRAMES_RCV: + DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__); + *((u32 *) resp + 6) = 0; + retval = 0; + break; + + case OID_GEN_MULTICAST_BYTES_RCV: + DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].stats) { + *((u32 *) resp + 6) = rndis_per_dev_params [configNr]. + stats->multicast*1111; + retval = 0; + } else { + *((u32 *) resp + 6) = 0; + retval = 0; + } + break; + + case OID_GEN_MULTICAST_FRAMES_RCV: + DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].stats) { + *((u32 *) resp + 6) = rndis_per_dev_params [configNr]. + stats->multicast; + retval = 0; + } else { + *((u32 *) resp + 6) = 0; + retval = 0; + } + break; + + case OID_GEN_BROADCAST_BYTES_RCV: + DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].stats) { + *((u32 *) resp + 6) = rndis_per_dev_params [configNr]. + stats->rx_packets/42*255; + retval = 0; + } else { + *((u32 *) resp + 6) = 0; + retval = 0; + } + break; + + case OID_GEN_BROADCAST_FRAMES_RCV: + DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].stats) { + *((u32 *) resp + 6) = rndis_per_dev_params [configNr]. + stats->rx_packets/42; + retval = 0; + } else { + *((u32 *) resp + 6) = 0; + retval = 0; + } + break; + + case OID_GEN_RCV_CRC_ERROR: + DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].stats) { + *((u32 *) resp + 6) = rndis_per_dev_params [configNr]. + stats->rx_crc_errors; + retval = 0; + } else { + *((u32 *) resp + 6) = 0; + retval = 0; + } + break; + + case OID_GEN_TRANSMIT_QUEUE_LENGTH: + DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__); + *((u32 *) resp + 6) = 0; + retval = 0; + break; + + case OID_GEN_GET_TIME_CAPS: + DEBUG("%s: OID_GEN_GET_TIME_CAPS\n", __FUNCTION__); + break; + + case OID_GEN_GET_NETCARD_TIME: + DEBUG("%s: OID_GEN_GET_NETCARD_TIME\n", __FUNCTION__); + break; + + case OID_GEN_NETCARD_LOAD: + DEBUG("%s: OID_GEN_NETCARD_LOAD\n", __FUNCTION__); + break; + + case OID_GEN_DEVICE_PROFILE: + DEBUG("%s: OID_GEN_DEVICE_PROFILE\n", __FUNCTION__); + break; + + case OID_GEN_INIT_TIME_MS: + DEBUG("%s: OID_GEN_INIT_TIME_MS\n", __FUNCTION__); + break; + + case OID_GEN_RESET_COUNTS: + DEBUG("%s: OID_GEN_RESET_COUNTS\n", __FUNCTION__); + break; + + case OID_GEN_MEDIA_SENSE_COUNTS: + DEBUG("%s: OID_GEN_MEDIA_SENSE_COUNTS\n", __FUNCTION__); + break; + + case OID_GEN_FRIENDLY_NAME: + DEBUG("%s: OID_GEN_FRIENDLY_NAME\n", __FUNCTION__); + break; + + case OID_GEN_MINIPORT_INFO: + DEBUG("%s: OID_GEN_MINIPORT_INFO\n", __FUNCTION__); + break; + + case OID_GEN_RESET_VERIFY_PARAMETERS: + DEBUG("%s: OID_GEN_RESET_VERIFY_PARAMETERS\n", __FUNCTION__); + break; + + /* mandatory */ + case OID_802_3_PERMANENT_ADDRESS: + DEBUG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].dev) { + length = 6; + memcpy ((u8 *) resp + 24, + rndis_per_dev_params [configNr].dev->dev_addr, + length); + /* + * we need a MAC address and hope that + * (our MAC + 1) is not in use + */ + *((u8 *) resp + 29) += 1; + retval = 0; + } else { + *((u32 *) resp + 6) = 0; + retval = 0; + } + break; + + /* mandatory */ + case OID_802_3_CURRENT_ADDRESS: + DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].dev) { + length = 6; + memcpy ((u8 *) resp + 24, + rndis_per_dev_params [configNr].dev->dev_addr, + length); + /* + * we need a MAC address and hope that + * (our MAC + 1) is not in use + */ + *((u8 *) resp + 29) += 1; + retval = 0; + } + break; + + /* mandatory */ + case OID_802_3_MULTICAST_LIST: + DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__); + length = 4; + /* Multicast base address only */ + *((u32 *) resp + 6) = 0xE0000000; + retval = 0; + break; + + /* mandatory */ + case OID_802_3_MAXIMUM_LIST_SIZE: + DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__); + length = 4; + /* Multicast base address only */ + *((u32 *) resp + 6) = 1; + retval = 0; + break; + + case OID_802_3_MAC_OPTIONS: + DEBUG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__); + break; + + /* mandatory */ + case OID_802_3_RCV_ERROR_ALIGNMENT: + DEBUG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__); + if (rndis_per_dev_params [configNr].stats) + { + length = 4; + *((u32 *) resp + 6) = rndis_per_dev_params [configNr] + .stats->rx_frame_errors; + retval = 0; + } + break; + + /* mandatory */ + case OID_802_3_XMIT_ONE_COLLISION: + DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__); + length = 4; + *((u32 *) resp + 6) = 0; + retval = 0; + break; + + /* mandatory */ + case OID_802_3_XMIT_MORE_COLLISIONS: + DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__); + length = 4; + *((u32 *) resp + 6) = 0; + retval = 0; + break; + + case OID_802_3_XMIT_DEFERRED: + DEBUG("%s: OID_802_3_XMIT_DEFERRED\n", __FUNCTION__); + /* TODO */ + break; + + case OID_802_3_XMIT_MAX_COLLISIONS: + DEBUG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __FUNCTION__); + /* TODO */ + break; + + case OID_802_3_RCV_OVERRUN: + DEBUG("%s: OID_802_3_RCV_OVERRUN\n", __FUNCTION__); + /* TODO */ + break; + + case OID_802_3_XMIT_UNDERRUN: + DEBUG("%s: OID_802_3_XMIT_UNDERRUN\n", __FUNCTION__); + /* TODO */ + break; + + case OID_802_3_XMIT_HEARTBEAT_FAILURE: + DEBUG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __FUNCTION__); + /* TODO */ + break; + + case OID_802_3_XMIT_TIMES_CRS_LOST: + DEBUG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __FUNCTION__); + /* TODO */ + break; + + case OID_802_3_XMIT_LATE_COLLISIONS: + DEBUG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__); + /* TODO */ + break; + + default: printk (KERN_ERR "%s: unknown OID 0x%08X\n", + __FUNCTION__, OID); + } + + resp->InformationBufferOffset = 16; + resp->InformationBufferLength = length; + resp->MessageLength = 24 + length; + r->length = 24 + length; + return retval; +} + +static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, + rndis_resp_t *r) +{ + rndis_set_cmplt_type *resp; + int i, retval = -ENOTSUPP; + struct rndis_config_parameter *param; + + if (!r) return -ENOMEM; + resp = (rndis_set_cmplt_type *) r->buf; + + if (!resp) return -ENOMEM; + + switch (OID) { + case OID_GEN_CURRENT_PACKET_FILTER: + DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__); + currentFilter2devFlags ((u32) ((u8 *) resp + 28), + rndis_per_dev_params [configNr].dev); + retval = 0; + if ((u32) ((u8 *) resp + 28)) + rndis_per_dev_params [configNr].state = RNDIS_INITIALIZED; + else + rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED; + break; + + case OID_802_3_MULTICAST_LIST: + /* I think we can ignore this */ + DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__); + retval = 0; + break; + + case OID_GEN_RNDIS_CONFIG_PARAMETER: + DEBUG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER\n", __FUNCTION__); + param = (struct rndis_config_parameter *) buf; + if (param) { + for (i = 0; i < param->ParameterNameLength; i++) { + DEBUG ("%c", + *(buf + param->ParameterNameOffset + i)); + } + DEBUG ("\n"); + } + + retval = 0; + break; + + default: printk (KERN_ERR "%s: unknown OID 0x%08X\n", + __FUNCTION__, OID); + } + + return retval; +} + +/* + * Response Functions + */ + +static int rndis_init_response (int configNr, rndis_init_msg_type *buf) +{ + rndis_init_cmplt_type *resp; + rndis_resp_t *r; + + if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP; + + r = rndis_add_response (configNr, sizeof (rndis_init_cmplt_type)); + + if (!r) return -ENOMEM; + + resp = (rndis_init_cmplt_type *) r->buf; + + if (!resp) return -ENOMEM; + + resp->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT; + resp->MessageLength = 52; + resp->RequestID = buf->RequestID; + resp->Status = RNDIS_STATUS_SUCCESS; + resp->MajorVersion = RNDIS_MAJOR_VERSION; + resp->MinorVersion = RNDIS_MINOR_VERSION; + resp->DeviceFlags = RNDIS_DF_CONNECTIONLESS; + resp->Medium = RNDIS_MEDIUM_802_3; + resp->MaxPacketsPerTransfer = 1; + resp->MaxTransferSize = rndis_per_dev_params [configNr].dev->mtu + + sizeof (struct ethhdr) + + sizeof (struct rndis_packet_msg_type) + + 22; + resp->PacketAlignmentFactor = 0; + resp->AFListOffset = 0; + resp->AFListSize = 0; + + if (rndis_per_dev_params [configNr].ack) + rndis_per_dev_params [configNr].ack ( + rndis_per_dev_params [configNr].dev); + + return 0; +} + +static int rndis_query_response (int configNr, rndis_query_msg_type *buf) +{ + rndis_query_cmplt_type *resp; + rndis_resp_t *r; + + DEBUG("%s: OID = %08X\n", __FUNCTION__, buf->OID); + if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP; + + /* + * we need more memory: + * oid_supported_list is the largest answer + */ + r = rndis_add_response (configNr, sizeof (oid_supported_list)); + + if (!r) return -ENOMEM; + resp = (rndis_query_cmplt_type *) r->buf; + + if (!resp) return -ENOMEM; + + resp->MessageType = REMOTE_NDIS_QUERY_CMPLT; + resp->MessageLength = 24; + resp->RequestID = buf->RequestID; + + if (gen_ndis_query_resp (configNr, buf->OID, r)) { + /* OID not supported */ + resp->Status = RNDIS_STATUS_NOT_SUPPORTED; + resp->InformationBufferLength = 0; + resp->InformationBufferOffset = 0; + } else + resp->Status = RNDIS_STATUS_SUCCESS; + + if (rndis_per_dev_params [configNr].ack) + rndis_per_dev_params [configNr].ack ( + rndis_per_dev_params [configNr].dev); + return 0; +} + +static int rndis_set_response (int configNr, rndis_set_msg_type *buf) +{ + rndis_set_cmplt_type *resp; + rndis_resp_t *r; + int i; + + r = rndis_add_response (configNr, sizeof (rndis_set_cmplt_type)); + + if (!r) return -ENOMEM; + resp = (rndis_set_cmplt_type *) r->buf; + if (!resp) return -ENOMEM; + + DEBUG("%s: Length: %d\n", __FUNCTION__, buf->InformationBufferLength); + DEBUG("%s: Offset: %d\n", __FUNCTION__, buf->InformationBufferOffset); + DEBUG("%s: InfoBuffer: ", __FUNCTION__); + + for (i = 0; i < buf->InformationBufferLength; i++) { + DEBUG ("%02x ", *(((u8 *) buf) + i + 12 + + buf->InformationBufferOffset)); + } + + DEBUG ("\n"); + + resp->MessageType = REMOTE_NDIS_SET_CMPLT; + resp->MessageLength = 16; + resp->RequestID = buf->RequestID; + if (gen_ndis_set_resp (configNr, buf->OID, + ((u8 *) buf) + 28, + buf->InformationBufferLength, r)) + resp->Status = RNDIS_STATUS_NOT_SUPPORTED; + else resp->Status = RNDIS_STATUS_SUCCESS; + + if (rndis_per_dev_params [configNr].ack) + rndis_per_dev_params [configNr].ack (rndis_per_dev_params [configNr].dev); + + return 0; +} + +static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf) +{ + rndis_reset_cmplt_type *resp; + rndis_resp_t *r; + + r = rndis_add_response (configNr, sizeof (rndis_reset_cmplt_type)); + + if (!r) return -ENOMEM; + resp = (rndis_reset_cmplt_type *) r->buf; + if (!resp) return -ENOMEM; + + resp->MessageType = REMOTE_NDIS_RESET_CMPLT; + resp->MessageLength = 16; + resp->Status = RNDIS_STATUS_SUCCESS; + resp->AddressingReset = 1; /* resent information */ + + if (rndis_per_dev_params [configNr].ack) + rndis_per_dev_params [configNr].ack ( + rndis_per_dev_params [configNr].dev); + + return 0; +} + +static int rndis_keepalive_response (int configNr, + rndis_keepalive_msg_type *buf) +{ + rndis_keepalive_cmplt_type *resp; + rndis_resp_t *r; + + /* respond only in RNDIS_INITIALIZED state */ + if (rndis_per_dev_params [configNr].state != RNDIS_INITIALIZED) + return 0; + r = rndis_add_response (configNr, sizeof (rndis_keepalive_cmplt_type)); + resp = (rndis_keepalive_cmplt_type *) r->buf; + if (!resp) return -ENOMEM; + + resp->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT; + resp->MessageLength = 16; + resp->RequestID = buf->RequestID; + resp->Status = RNDIS_STATUS_SUCCESS; + + if (rndis_per_dev_params [configNr].ack) + rndis_per_dev_params [configNr].ack ( + rndis_per_dev_params [configNr].dev); + + return 0; +} + + +/* + * Device to Host Comunication + */ +static int rndis_indicate_status_msg (int configNr, u32 status) +{ + rndis_indicate_status_msg_type *resp; + rndis_resp_t *r; + + if (rndis_per_dev_params [configNr].state == RNDIS_UNINITIALIZED) + return -ENOTSUPP; + + r = rndis_add_response (configNr, + sizeof (rndis_indicate_status_msg_type)); + if (!r) return -ENOMEM; + + resp = (rndis_indicate_status_msg_type *) r->buf; + if (!resp) return -ENOMEM; + + resp->MessageType = REMOTE_NDIS_INDICATE_STATUS_MSG; + resp->MessageLength = 20; + resp->Status = status; + resp->StatusBufferLength = 0; + resp->StatusBufferOffset = 0; + + if (rndis_per_dev_params [configNr].ack) + rndis_per_dev_params [configNr].ack ( + rndis_per_dev_params [configNr].dev); + return 0; +} + +int rndis_signal_connect (int configNr) +{ + rndis_per_dev_params [configNr].media_state + = NDIS_MEDIA_STATE_CONNECTED; + return rndis_indicate_status_msg (configNr, + RNDIS_STATUS_MEDIA_CONNECT); +} + +int rndis_signal_disconnect (int configNr) +{ + rndis_per_dev_params [configNr].media_state + = NDIS_MEDIA_STATE_DISCONNECTED; + return rndis_indicate_status_msg (configNr, + RNDIS_STATUS_MEDIA_DISCONNECT); +} + +/* + * Message Parser + */ +int rndis_msg_parser (u8 configNr, u8 *buf) +{ + u32 MsgType, MsgLength, *tmp; + + if (!buf) return -ENOMEM; + + tmp = (u32 *) buf; + MsgType = *tmp; + MsgLength = *(tmp + 1); + + if (configNr >= RNDIS_MAX_CONFIGS) return -ENOTSUPP; + + switch (MsgType) + { + case REMOTE_NDIS_INIZIALIZE_MSG: + DEBUG(KERN_INFO "%s: REMOTE_NDIS_INIZIALIZE_MSG\n", + __FUNCTION__ ); + rndis_per_dev_params [configNr].state = RNDIS_INITIALIZED; + return rndis_init_response (configNr, + (rndis_init_msg_type *) buf); + break; + + case REMOTE_NDIS_HALT_MSG: + DEBUG(KERN_INFO "%s: REMOTE_NDIS_HALT_MSG\n", + __FUNCTION__ ); + rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED; + return 0; + + case REMOTE_NDIS_QUERY_MSG: + DEBUG(KERN_INFO "%s: REMOTE_NDIS_QUERY_MSG\n", + __FUNCTION__ ); + return rndis_query_response (configNr, + (rndis_query_msg_type *) buf); + break; + + case REMOTE_NDIS_SET_MSG: + DEBUG(KERN_INFO "%s: REMOTE_NDIS_SET_MSG\n", + __FUNCTION__ ); + return rndis_set_response (configNr, + (rndis_set_msg_type *) buf); + break; + + case REMOTE_NDIS_RESET_MSG: + DEBUG(KERN_INFO "%s: REMOTE_NDIS_RESET_MSG\n", + __FUNCTION__ ); + return rndis_reset_response (configNr, + (rndis_reset_msg_type *) buf); + break; + + case REMOTE_NDIS_KEEPALIVE_MSG: + DEBUG(KERN_INFO "%s: REMOTE_NDIS_KEEPALIVE_MSG\n", + __FUNCTION__ ); + return rndis_keepalive_response (configNr, + (rndis_keepalive_msg_type *) + buf); + break; + + default: + printk (KERN_ERR "%s: unknown RNDIS Message Type 0x%08X\n", + __FUNCTION__ , MsgType); + break; + } + + return -ENOTSUPP; +} + +int rndis_register (int (* rndis_control_ack) (struct net_device *)) +{ + u8 i; + DEBUG("%s: ", __FUNCTION__ ); + + for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { + if (!rndis_per_dev_params [i].used) { + rndis_per_dev_params [i].used = 1; + rndis_per_dev_params [i].ack = rndis_control_ack; + DEBUG("configNr = %d\n", i); + return i; + } + } + DEBUG("failed\n"); + + return -1; +} + +void rndis_deregister (int configNr) +{ + DEBUG("%s: \n", __FUNCTION__ ); + + if (configNr >= RNDIS_MAX_CONFIGS) return; + rndis_per_dev_params [configNr].used = 0; + + return; +} + +int rndis_set_param_dev (u8 configNr, struct net_device *dev, + struct net_device_stats *stats) +{ + DEBUG("%s:\n", __FUNCTION__ ); + if (!dev || !stats) return -1; + if (configNr >= RNDIS_MAX_CONFIGS) return -1; + + rndis_per_dev_params [configNr].dev = dev; + rndis_per_dev_params [configNr].stats = stats; + + return 0; +} + +int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr) +{ + DEBUG("%s:\n", __FUNCTION__ ); + if (!vendorDescr) return -1; + if (configNr >= RNDIS_MAX_CONFIGS) return -1; + + rndis_per_dev_params [configNr].vendorID = vendorID; + rndis_per_dev_params [configNr].vendorDescr = vendorDescr; + + return 0; +} + +int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed) +{ + DEBUG("%s:\n", __FUNCTION__ ); + if (configNr >= RNDIS_MAX_CONFIGS) return -1; + + rndis_per_dev_params [configNr].medium = medium; + rndis_per_dev_params [configNr].speed = speed; + + return 0; +} + +void rndis_add_hdr (struct sk_buff *skb) +{ + if (!skb) return; + skb_push (skb, sizeof (struct rndis_packet_msg_type)); + memset (skb->data, 0, sizeof (struct rndis_packet_msg_type)); + *((u32 *) skb->data) = 1; + *((u32 *) skb->data + 1) = skb->len; + *((u32 *) skb->data + 2) = 36; + *((u32 *) skb->data + 3) = skb->len - 44; + + return; +} + +void rndis_free_response (int configNr, u8 *buf) +{ + rndis_resp_t *r; + struct list_head *act, *tmp; + + list_for_each_safe (act, tmp, + &(rndis_per_dev_params [configNr].resp_queue)) + { + r = list_entry (act, rndis_resp_t, list); + if (r && r->buf == buf) { + list_del (&r->list); + kfree (r); + } + } +} + +u8 *rndis_get_next_response (int configNr, u32 *length) +{ + rndis_resp_t *r; + struct list_head *act, *tmp; + + if (!length) return NULL; + + list_for_each_safe (act, tmp, + &(rndis_per_dev_params [configNr].resp_queue)) + { + r = list_entry (act, rndis_resp_t, list); + if (!r->send) { + r->send = 1; + *length = r->length; + return r->buf; + } + } + + return NULL; +} + +static rndis_resp_t *rndis_add_response (int configNr, u32 length) +{ + rndis_resp_t *r; + + r = kmalloc (sizeof (rndis_resp_t) + length, GFP_ATOMIC); + if (!r) return NULL; + + r->buf = (u8 *) (r + 1); + r->length = length; + r->send = 0; + + list_add_tail (&r->list, + &(rndis_per_dev_params [configNr].resp_queue)); + return r; +} + +int rndis_rm_hdr (u8 *buf, u32 *length) +{ + u32 i, messageLen, dataOffset; + + if (!buf || !length) return -1; + if (*((u32 *) buf) != 1) return -1; + + messageLen = *((u32 *) buf + 1); + + dataOffset = *((u32 *) buf + 2) + 8; + if (messageLen < dataOffset || messageLen > *length) return -1; + + for (i = dataOffset; i < messageLen; i++) + buf [i - dataOffset] = buf [i]; + + *length = messageLen - dataOffset; + + return 0; +} + +int rndis_proc_read (char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + char *out = page; + int len; + rndis_params *param = (rndis_params *) data; + + out += snprintf (out, count, + "Config Nr. %d\n" + "used : %s\n" + "state : %s\n" + "medium : 0x%08X\n" + "speed : %d\n" + "cable : %s\n" + "vendor ID : 0x%08X\n" + "vendor : %s\n", + param->confignr, (param->used) ? "y" : "n", + (param->state) + ? "RNDIS_INITIALIZED" + : "RNDIS_UNINITIALIZED", + param->medium, + (param->media_state) ? 0 : param->speed*100, + (param->media_state) ? "disconnected" : "connected", + param->vendorID, param->vendorDescr); + + len = out - page; + len -= off; + + if (len < count) { + *eof = 1; + if (len <= 0) + return 0; + } else + len = count; + + *start = page + off; + return len; +} + +int rndis_proc_write (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + u32 speed = 0; + int i, fl_speed = 0; + + for (i = 0; i < count; i++) { + switch (*buffer) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + fl_speed = 1; + speed = speed*10 + *buffer - '0'; + break; + case 'C': + case 'c': + rndis_signal_connect (((rndis_params *) data) + ->confignr); + break; + case 'D': + case 'd': + rndis_signal_disconnect (((rndis_params *) data) + ->confignr); + break; + default: + if (fl_speed) ((rndis_params *) data)->speed = speed; + else DEBUG ("%c is not valid\n", *buffer); + break; + } + + buffer++; + } + + return count; +} + +int __init rndis_init (void) +{ + u8 i; + char name [4]; + + /* FIXME this should probably be /proc/driver/rndis, + * and only if debugging is enabled + */ + + if (!(rndis_connect_dir = proc_mkdir ("rndis", NULL))) { + printk (KERN_ERR "%s: couldn't create /proc/rndis entry", + __FUNCTION__); + return -EIO; + } + + for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { + sprintf (name, "%03d", i); + if (!(rndis_connect_state [i] + = create_proc_entry (name, 0660, + rndis_connect_dir))) + { + DEBUG ("%s :remove entries", __FUNCTION__); + for (i--; i > 0; i--) { + sprintf (name, "%03d", i); + remove_proc_entry (name, rndis_connect_dir); + } + DEBUG ("\n"); + + remove_proc_entry ("000", rndis_connect_dir); + remove_proc_entry ("rndis", NULL); + return -EIO; + } + rndis_connect_state [i]->nlink = 1; + rndis_connect_state [i]->write_proc = rndis_proc_write; + rndis_connect_state [i]->read_proc = rndis_proc_read; + rndis_connect_state [i]->data = (void *) + (rndis_per_dev_params + i); + rndis_per_dev_params [i].confignr = i; + rndis_per_dev_params [i].used = 0; + rndis_per_dev_params [i].state = RNDIS_UNINITIALIZED; + rndis_per_dev_params [i].media_state + = NDIS_MEDIA_STATE_DISCONNECTED; + INIT_LIST_HEAD (&(rndis_per_dev_params [i].resp_queue)); + } + + return 0; +} + +void __exit rndis_exit (void) +{ + u8 i; + char name [4]; + + for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { + sprintf (name, "%03d", i); + remove_proc_entry (name, rndis_connect_dir); + } + remove_proc_entry ("rndis", NULL); + return; +} + diff -Nru a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/gadget/rndis.h Tue Apr 6 17:22:26 2004 @@ -0,0 +1,311 @@ +/* + * RNDIS Definitions for Remote NDIS + * + * Version: $Id: rndis.h,v 1.15 2004/03/25 21:33:46 robert Exp $ + * + * Authors: Benedikt Spranger, Pengutronix + * Robert Schwebel, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2, as published by the Free Software Foundation. + * + * This software was originally developed in conformance with + * Microsoft's Remote NDIS Specification License Agreement. + */ + +#ifndef _LINUX_RNDIS_H +#define _LINUX_RNDIS_H + +#include "ndis.h" + +#define RNDIS_MAXIMUM_FRAME_SIZE 1518 +#define RNDIS_MAX_TOTAL_SIZE 1558 + +/* Remote NDIS Versions */ +#define RNDIS_MAJOR_VERSION 1 +#define RNDIS_MINOR_VERSION 0 + +/* Status Values */ +#define RNDIS_STATUS_SUCCESS 0x00000000U /* Success */ +#define RNDIS_STATUS_FAILURE 0xC0000001U /* Unspecified error */ +#define RNDIS_STATUS_INVALID_DATA 0xC0010015U /* Invalid data */ +#define RNDIS_STATUS_NOT_SUPPORTED 0xC00000BBU /* Unsupported request */ +#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000BU /* Device connected */ +#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000CU /* Device disconnected */ +/* For all not specified status messages: + * RNDIS_STATUS_Xxx -> NDIS_STATUS_Xxx + */ + +/* Message Set for Connectionless (802.3) Devices */ +#define REMOTE_NDIS_INIZIALIZE_MSG 0x00000002U /* Initialize device */ +#define REMOTE_NDIS_HALT_MSG 0x00000003U +#define REMOTE_NDIS_QUERY_MSG 0x00000004U +#define REMOTE_NDIS_SET_MSG 0x00000005U +#define REMOTE_NDIS_RESET_MSG 0x00000006U +#define REMOTE_NDIS_INDICATE_STATUS_MSG 0x00000007U +#define REMOTE_NDIS_KEEPALIVE_MSG 0x00000008U + +/* Message completion */ +#define REMOTE_NDIS_INITIALIZE_CMPLT 0x80000002U +#define REMOTE_NDIS_QUERY_CMPLT 0x80000004U +#define REMOTE_NDIS_SET_CMPLT 0x80000005U +#define REMOTE_NDIS_RESET_CMPLT 0x80000006U +#define REMOTE_NDIS_KEEPALIVE_CMPLT 0x80000008U + +/* Device Flags */ +#define RNDIS_DF_CONNECTIONLESS 0x00000001U +#define RNDIS_DF_CONNECTION_ORIENTED 0x00000002U + +#define RNDIS_MEDIUM_802_3 0x00000000U + +/* supported OIDs */ +static const u32 oid_supported_list [] = +{ + /* mandatory general */ + /* the general stuff */ + OID_GEN_SUPPORTED_LIST, + OID_GEN_HARDWARE_STATUS, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_MAXIMUM_FRAME_SIZE, + OID_GEN_LINK_SPEED, + OID_GEN_TRANSMIT_BUFFER_SPACE, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_VENDOR_ID, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_VENDOR_DRIVER_VERSION, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_MAC_OPTIONS, + OID_GEN_MEDIA_CONNECT_STATUS, + OID_GEN_PHYSICAL_MEDIUM, + OID_GEN_RNDIS_CONFIG_PARAMETER, + + /* the statistical stuff */ + OID_GEN_XMIT_OK, + OID_GEN_RCV_OK, + OID_GEN_XMIT_ERROR, + OID_GEN_RCV_ERROR, + OID_GEN_RCV_NO_BUFFER, + OID_GEN_DIRECTED_BYTES_XMIT, + OID_GEN_DIRECTED_FRAMES_XMIT, + OID_GEN_MULTICAST_BYTES_XMIT, + OID_GEN_MULTICAST_FRAMES_XMIT, + OID_GEN_BROADCAST_BYTES_XMIT, + OID_GEN_BROADCAST_FRAMES_XMIT, + OID_GEN_DIRECTED_BYTES_RCV, + OID_GEN_DIRECTED_FRAMES_RCV, + OID_GEN_MULTICAST_BYTES_RCV, + OID_GEN_MULTICAST_FRAMES_RCV, + OID_GEN_BROADCAST_BYTES_RCV, + OID_GEN_BROADCAST_FRAMES_RCV, + OID_GEN_RCV_CRC_ERROR, + OID_GEN_TRANSMIT_QUEUE_LENGTH, + + /* mandatory 802.3 */ + /* the general stuff */ + OID_802_3_PERMANENT_ADDRESS, + OID_802_3_CURRENT_ADDRESS, + OID_802_3_MULTICAST_LIST, + OID_802_3_MAC_OPTIONS, + OID_802_3_MAXIMUM_LIST_SIZE, + + /* the statistical stuff */ + OID_802_3_RCV_ERROR_ALIGNMENT, + OID_802_3_XMIT_ONE_COLLISION, + OID_802_3_XMIT_MORE_COLLISIONS +}; + + +typedef struct rndis_init_msg_type +{ + u32 MessageType; + u32 MessageLength; + u32 RequestID; + u32 MajorVersion; + u32 MinorVersion; + u32 MaxTransferSize; +} rndis_init_msg_type; + +typedef struct rndis_init_cmplt_type +{ + u32 MessageType; + u32 MessageLength; + u32 RequestID; + u32 Status; + u32 MajorVersion; + u32 MinorVersion; + u32 DeviceFlags; + u32 Medium; + u32 MaxPacketsPerTransfer; + u32 MaxTransferSize; + u32 PacketAlignmentFactor; + u32 AFListOffset; + u32 AFListSize; +} rndis_init_cmplt_type; + +typedef struct rndis_halt_msg_type +{ + u32 MessageType; + u32 MessageLength; + u32 RequestID; +} rndis_halt_msg_type; + +typedef struct rndis_query_msg_type +{ + u32 MessageType; + u32 MessageLength; + u32 RequestID; + u32 OID; + u32 InformationBufferLength; + u32 InformationBufferOffset; + u32 DeviceVcHandle; +} rndis_query_msg_type; + +typedef struct rndis_query_cmplt_type +{ + u32 MessageType; + u32 MessageLength; + u32 RequestID; + u32 Status; + u32 InformationBufferLength; + u32 InformationBufferOffset; +} rndis_query_cmplt_type; + +typedef struct rndis_set_msg_type +{ + u32 MessageType; + u32 MessageLength; + u32 RequestID; + u32 OID; + u32 InformationBufferLength; + u32 InformationBufferOffset; + u32 DeviceVcHandle; +} rndis_set_msg_type; + +typedef struct rndis_set_cmplt_type +{ + u32 MessageType; + u32 MessageLength; + u32 RequestID; + u32 Status; +} rndis_set_cmplt_type; + +typedef struct rndis_reset_msg_type +{ + u32 MessageType; + u32 MessageLength; + u32 Reserved; +} rndis_reset_msg_type; + +typedef struct rndis_reset_cmplt_type +{ + u32 MessageType; + u32 MessageLength; + u32 Status; + u32 AddressingReset; +} rndis_reset_cmplt_type; + +typedef struct rndis_indicate_status_msg_type +{ + u32 MessageType; + u32 MessageLength; + u32 Status; + u32 StatusBufferLength; + u32 StatusBufferOffset; +} rndis_indicate_status_msg_type; + +typedef struct rndis_keepalive_msg_type +{ + u32 MessageType; + u32 MessageLength; + u32 RequestID; +} rndis_keepalive_msg_type; + +typedef struct rndis_keepalive_cmplt_type +{ + u32 MessageType; + u32 MessageLength; + u32 RequestID; + u32 Status; +} rndis_keepalive_cmplt_type; + +struct rndis_packet_msg_type +{ + u32 MessageType; + u32 MessageLength; + u32 DataOffset; + u32 DataLength; + u32 OOBDataOffset; + u32 OOBDataLength; + u32 NumOOBDataElements; + u32 PerPacketInfoOffset; + u32 PerPacketInfoLength; + u32 VcHandle; + u32 Reserved; +}; + +struct rndis_config_parameter +{ + u32 ParameterNameOffset; + u32 ParameterNameLength; + u32 ParameterType; + u32 ParameterValueOffset; + u32 ParameterValueLength; +}; + +/* implementation specific */ +enum rndis_state +{ + RNDIS_UNINITIALIZED, + RNDIS_INITIALIZED, + RNDIS_DATA_INITIALIZED, +}; + +typedef struct rndis_resp_t +{ + struct list_head list; + u8 *buf; + u32 length; + int send; +} rndis_resp_t; + +typedef struct rndis_params +{ + u8 confignr; + int used; + enum rndis_state state; + u32 medium; + u32 speed; + u32 media_state; + struct net_device *dev; + struct net_device_stats *stats; + u32 vendorID; + const char *vendorDescr; + int (*ack) (struct net_device *); + struct list_head resp_queue; +} rndis_params; + +/* RNDIS Message parser and other useless functions */ +int rndis_msg_parser (u8 configNr, u8 *buf); +int rndis_register (int (*rndis_control_ack) (struct net_device *)); +void rndis_deregister (int configNr); +int rndis_set_param_dev (u8 configNr, struct net_device *dev, + struct net_device_stats *stats); +int rndis_set_param_vendor (u8 configNr, u32 vendorID, + const char *vendorDescr); +int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed); +void rndis_add_hdr (struct sk_buff *skb); +int rndis_rm_hdr (u8 *buf, u32 *length); +u8 *rndis_get_next_response (int configNr, u32 *length); +void rndis_free_response (int configNr, u8 *buf); +int rndis_signal_connect (int configNr); +int rndis_signal_disconnect (int configNr); +int rndis_state (int configNr); + +int __init rndis_init (void); +void __exit rndis_exit (void); + +#endif /* _LINUX_RNDIS_H */ diff -Nru a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c --- a/drivers/usb/gadget/serial.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/gadget/serial.c Tue Apr 6 17:22:26 2004 @@ -207,6 +207,27 @@ /* + * Dummy_hcd, software-based loopback controller. + * + * This imitates the abilities of the NetChip 2280, so we will use + * the same configuration. + */ +#ifdef CONFIG_USB_GADGET_DUMMY_HCD +#define CHIP "dummy" +#define EP0_MAXPACKET 64 +static const char EP_OUT_NAME[] = "ep-a"; +#define EP_OUT_NUM 2 +static const char EP_IN_NAME[] = "ep-b"; +#define EP_IN_NUM 2 +#define HIGHSPEED +#define SELFPOWER USB_CONFIG_ATT_SELFPOWER + +/* no hw optimizations to apply */ +#define hw_optimize(g) do {} while (0) +#endif + + +/* * PXA-2xx UDC: widely used in second gen Linux-capable PDAs. * * This has fifteen fixed-function full speed endpoints, and it diff -Nru a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c --- a/drivers/usb/gadget/usbstring.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/gadget/usbstring.c Tue Apr 6 17:22:26 2004 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include diff -Nru a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c --- a/drivers/usb/gadget/zero.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/gadget/zero.c Tue Apr 6 17:22:26 2004 @@ -89,10 +89,12 @@ #include #include +#include "gadget_chips.h" + /*-------------------------------------------------------------------------*/ -#define DRIVER_VERSION "Bastille Day 2003" +#define DRIVER_VERSION "St Patrick's Day 2004" static const char shortname [] = "zero"; static const char longname [] = "Gadget Zero"; @@ -105,100 +107,12 @@ /* * driver assumes self-powered hardware, and * has no way for users to trigger remote wakeup. - */ - -/* - * hardware-specific configuration, controlled by which device - * controller driver was configured. - * - * CHIP ... hardware identifier - * DRIVER_VERSION_NUM ... alerts the host side driver to differences - * EP_*_NAME ... which endpoints do we use for which purpose? - * EP_*_NUM ... numbers for them (often limited by hardware) - * - * add other defines for other portability issues, like hardware that - * for some reason doesn't handle full speed bulk maxpacket of 64. - */ - -/* - * DRIVER_VERSION_NUM 0x0000 (?): Martin Diehl's ezusb an21/fx code - */ - -/* - * NetChip 2280, PCI based. - * - * This has half a dozen configurable endpoints, four with dedicated - * DMA channels to manage their FIFOs. It supports high speed. - * Those endpoints can be arranged in any desired configuration. - */ -#if defined(CONFIG_USB_GADGET_NET2280) || defined(CONFIG_USB_GADGET_DUMMY_HCD) -#define CHIP "net2280" -#define DRIVER_VERSION_NUM 0x0101 -static const char EP_OUT_NAME [] = "ep-a"; -#define EP_OUT_NUM 2 -static const char EP_IN_NAME [] = "ep-b"; -#define EP_IN_NUM 2 -#endif - -/* - * PXA-2xx UDC: widely used in second gen Linux-capable PDAs. * - * This has fifteen fixed-function full speed endpoints, and it - * can support all USB transfer types. - * - * These supports three or four configurations, with fixed numbers. - * The hardware interprets SET_INTERFACE, net effect is that you - * can't use altsettings or reset the interfaces independently. - * So stick to a single interface. + * this version autoconfigures as much as possible, + * which is reasonable for most "bulk-only" drivers. */ -#ifdef CONFIG_USB_GADGET_PXA2XX -#define CHIP "pxa2xx" -#define DRIVER_VERSION_NUM 0x0103 -static const char EP_OUT_NAME [] = "ep12out-bulk"; -#define EP_OUT_NUM 12 -static const char EP_IN_NAME [] = "ep11in-bulk"; -#define EP_IN_NUM 11 -#endif - -/* - * SA-1100 UDC: widely used in first gen Linux-capable PDAs. - * - * This has only two fixed function endpoints, which can only - * be used for bulk (or interrupt) transfers. (Plus control.) - * - * Since it can't flush its TX fifos without disabling the UDC, - * the current configuration or altsettings can't change except - * in special situations. So this is a case of "choose it right - * during enumeration" ... - */ -#ifdef CONFIG_USB_GADGET_SA1100 -#define CHIP "sa1100" -#define DRIVER_VERSION_NUM 0x0105 -static const char EP_OUT_NAME [] = "ep1out-bulk"; -#define EP_OUT_NUM 1 -static const char EP_IN_NAME [] = "ep2in-bulk"; -#define EP_IN_NUM 2 -#endif - -/* - * Toshiba TC86C001 ("Goku-S") UDC - * - * This has three semi-configurable full speed bulk/interrupt endpoints. - */ -#ifdef CONFIG_USB_GADGET_GOKU -#define CHIP "goku" -#define DRIVER_VERSION_NUM 0x0106 -static const char EP_OUT_NAME [] = "ep1-bulk"; -#define EP_OUT_NUM 1 -static const char EP_IN_NAME [] = "ep2-bulk"; -#define EP_IN_NUM 2 -#endif - -/*-------------------------------------------------------------------------*/ - -#ifndef EP_OUT_NUM -# error Configure some USB peripheral controller driver! -#endif +static const char *EP_IN_NAME; /* source */ +static const char *EP_OUT_NAME; /* sink */ /*-------------------------------------------------------------------------*/ @@ -222,20 +136,19 @@ dev_printk(level , &(d)->gadget->dev , fmt , ## args) #ifdef DEBUG -#undef DEBUG -#define DEBUG(dev,fmt,args...) \ +#define DBG(dev,fmt,args...) \ xprintk(dev , KERN_DEBUG , fmt , ## args) #else -#define DEBUG(dev,fmt,args...) \ +#define DBG(dev,fmt,args...) \ do { } while (0) #endif /* DEBUG */ #ifdef VERBOSE -#define VDEBUG DEBUG +#define VDBG DBG #else -#define VDEBUG(dev,fmt,args...) \ +#define VDBG(dev,fmt,args...) \ do { } while (0) -#endif /* DEBUG */ +#endif /* VERBOSE */ #define ERROR(dev,fmt,args...) \ xprintk(dev , KERN_ERR , fmt , ## args) @@ -305,7 +218,6 @@ .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM), .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM), - .bcdDevice = __constant_cpu_to_le16 (DRIVER_VERSION_NUM), .iManufacturer = STRING_MANUFACTURER, .iProduct = STRING_PRODUCT, .iSerialNumber = STRING_SERIAL, @@ -362,24 +274,22 @@ /* two full speed bulk endpoints; their use is config-dependent */ -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor fs_source_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_IN_NUM | USB_DIR_IN, + .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16 (64), }; -static const struct usb_endpoint_descriptor +static struct usb_endpoint_descriptor fs_sink_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_OUT_NUM, + .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16 (64), }; static const struct usb_descriptor_header *fs_source_sink_function [] = { @@ -643,7 +553,7 @@ case -ECONNABORTED: /* hardware forced ep reset */ case -ECONNRESET: /* request dequeued */ case -ESHUTDOWN: /* disconnect from host */ - VDEBUG (dev, "%s gone (%d), %d/%d\n", ep->name, status, + VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status, req->actual, req->length); if (ep == dev->out_ep) check_read_data (dev, ep, req); @@ -656,7 +566,7 @@ */ default: #if 1 - DEBUG (dev, "%s complete --> %d, %d/%d\n", ep->name, + DBG (dev, "%s complete --> %d, %d/%d\n", ep->name, status, req->actual, req->length); #endif case -EREMOTEIO: /* short read */ @@ -747,7 +657,7 @@ break; } if (result == 0) - DEBUG (dev, "buflen %d\n", buflen); + DBG (dev, "buflen %d\n", buflen); /* caller is responsible for cleanup on error */ return result; @@ -858,14 +768,14 @@ req->complete = loopback_complete; result = usb_ep_queue (ep, req, GFP_ATOMIC); if (result) - DEBUG (dev, "%s queue req --> %d\n", + DBG (dev, "%s queue req --> %d\n", ep->name, result); } else result = -ENOMEM; } } if (result == 0) - DEBUG (dev, "qlen %d, buflen %d\n", qlen, buflen); + DBG (dev, "qlen %d, buflen %d\n", qlen, buflen); /* caller is responsible for cleanup on error */ return result; @@ -878,7 +788,7 @@ if (dev->config == 0) return; - DEBUG (dev, "reset config\n"); + DBG (dev, "reset config\n"); /* just disable endpoints, forcing completion of pending i/o. * all our completion handlers free their requests in this case. @@ -913,13 +823,11 @@ if (number == dev->config) return 0; -#ifdef CONFIG_USB_GADGET_SA1100 - if (dev->config) { + if (gadget_is_sa1100 (gadget) && dev->config) { /* tx fifo is full, but we can't clear it...*/ INFO (dev, "can't change configurations\n"); return -ESPIPE; } -#endif zero_reset_config (dev); switch (number) { @@ -963,7 +871,7 @@ static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req) { if (req->status || req->actual != req->length) - DEBUG ((struct zero_dev *) ep->driver_data, + DBG ((struct zero_dev *) ep->driver_data, "setup complete --> %d, %d/%d\n", req->status, req->actual, req->length); } @@ -1111,7 +1019,7 @@ default: unknown: - VDEBUG (dev, + VDBG (dev, "unknown control req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, ctrl->wIndex, ctrl->wLength); @@ -1122,7 +1030,7 @@ req->length = value; value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC); if (value < 0) { - DEBUG (dev, "ep_queue --> %d\n", value); + DBG (dev, "ep_queue --> %d\n", value); req->status = 0; zero_setup_complete (gadget->ep0, req); } @@ -1159,7 +1067,7 @@ { struct zero_dev *dev = get_gadget_data (gadget); - DEBUG (dev, "unbind\n"); + DBG (dev, "unbind\n"); /* we've already been disconnected ... no i/o is active */ if (dev->req) @@ -1172,7 +1080,70 @@ zero_bind (struct usb_gadget *gadget) { struct zero_dev *dev; + struct usb_ep *ep; + /* Bulk-only drivers like this one SHOULD be able to + * autoconfigure on any sane usb controller driver, + * but there may also be important quirks to address. + */ + usb_ep_autoconfig_reset (gadget); + ep = usb_ep_autoconfig (gadget, &fs_source_desc); + if (!ep) { +autoconf_fail: + printk (KERN_ERR "%s: can't autoconfigure on %s\n", + shortname, gadget->name); + return -ENODEV; + } + EP_IN_NAME = ep->name; + ep->driver_data = ep; /* claim */ + + ep = usb_ep_autoconfig (gadget, &fs_sink_desc); + if (!ep) + goto autoconf_fail; + EP_OUT_NAME = ep->name; + ep->driver_data = ep; /* claim */ + + + /* + * DRIVER POLICY CHOICE: you may want to do this differently. + * One thing to avoid is reusing a bcdDevice revision code + * with different host-visible configurations or behavior + * restrictions -- using ep1in/ep2out vs ep1out/ep3in, etc + */ + if (gadget_is_net2280 (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201); + } else if (gadget_is_pxa (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0203); +#if 0 + } else if (gadget_is_sh(gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0204); + /* SH has only one configuration; see "loopdefault" */ + device_desc.bNumConfigurations = 1; + /* FIXME make 1 == default.bConfigurationValue */ +#endif + } else if (gadget_is_sa1100 (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0205); + } else if (gadget_is_goku (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0206); + } else if (gadget_is_mq11xx (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207); + } else if (gadget_is_omap (gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208); + } else { + /* gadget zero is so simple (for now, no altsettings) that + * it SHOULD NOT have problems with bulk-capable hardware. + * so warn about unrcognized controllers, don't panic. + * + * things like configuration and altsetting numbering + * can need hardware-specific attention though. + */ + printk (KERN_WARNING "%s: controller '%s' not recognized\n", + shortname, gadget->name); + device_desc.bcdDevice = __constant_cpu_to_le16 (0x9999); + } + + + /* ok, we made sense of the hardware ... */ dev = kmalloc (sizeof *dev, SLAB_KERNEL); if (!dev) return -ENOMEM; @@ -1202,6 +1173,8 @@ hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; #endif + + usb_gadget_set_selfpowered (gadget); gadget->ep0->driver_data = dev; diff -Nru a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig --- a/drivers/usb/host/Kconfig Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/host/Kconfig Tue Apr 6 17:22:26 2004 @@ -38,6 +38,17 @@ EHCI or USB 2.0 transaction translator implementations. It should work for ISO-OUT transfers, like audio. +config USB_EHCI_ROOT_HUB_TT + bool "Root Hub Transaction Translators (EXPERIMENTAL)" + depends on USB_EHCI_HCD && EXPERIMENTAL + ---help--- + Some EHCI chips have vendor-specific extensions to integrate + transaction translators, so that no OHCI or UHCI companion + controller is needed. It's safe to say "y" even if your + controller doesn't support this feature. + + This supports the EHCI implementation from ARC International. + config USB_OHCI_HCD tristate "OHCI HCD support" depends on USB diff -Nru a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c --- a/drivers/usb/host/ehci-dbg.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/host/ehci-dbg.c Tue Apr 6 17:22:26 2004 @@ -628,8 +628,10 @@ /* Capability Registers */ i = HC_VERSION(readl (&ehci->caps->hc_capbase)); temp = scnprintf (next, size, - "PCI device %s\nEHCI %x.%02x, hcd state %d (driver " DRIVER_VERSION ")\n", - pci_name(to_pci_dev(hcd->self.controller)), + "bus %s device %s\n" + "EHCI %x.%02x, hcd state %d (driver " DRIVER_VERSION ")\n", + hcd->self.controller->bus->name, + hcd->self.controller->bus_id, i >> 8, i & 0x0ff, ehci->hcd.state); size -= temp; next += temp; diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c --- a/drivers/usb/host/ehci-hcd.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/host/ehci-hcd.c Tue Apr 6 17:22:26 2004 @@ -279,6 +279,8 @@ spin_unlock_irqrestore (&ehci->lock, flags); } +#ifdef CONFIG_PCI + /* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/... * off the controller (maybe it can boot from highspeed USB disks). */ @@ -307,6 +309,8 @@ return 0; } +#endif + static int ehci_reboot (struct notifier_block *self, unsigned long code, void *null) { @@ -335,8 +339,12 @@ dbg_hcs_params (ehci, "reset"); dbg_hcc_params (ehci, "reset"); +#ifdef CONFIG_PCI /* EHCI 0.96 and later may have "extended capabilities" */ - temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params)); + if (hcd->self.controller->bus == &pci_bus_type) + temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params)); + else + temp = 0; while (temp) { u32 cap; @@ -356,6 +364,7 @@ } temp = (cap >> 8) & 0xff; } +#endif /* cache this readonly data; minimize PCI reads */ ehci->hcs_params = readl (&ehci->caps->hcs_params); @@ -372,7 +381,11 @@ struct usb_bus *bus; int retval; u32 hcc_params; - u8 tempbyte; + u8 sbrn = 0; + + init_timer (&ehci->watchdog); + ehci->watchdog.function = ehci_watchdog; + ehci->watchdog.data = (unsigned long) ehci; /* * hw default: 1K periodic list heads, one per frame. @@ -402,6 +415,29 @@ writel (INTR_MASK, &ehci->regs->intr_enable); writel (ehci->periodic_dma, &ehci->regs->frame_list); +#ifdef CONFIG_PCI + if (hcd->self.controller->bus == &pci_bus_type) { + struct pci_dev *pdev; + + pdev = to_pci_dev(hcd->self.controller); + + /* Serial Bus Release Number is at PCI 0x60 offset */ + pci_read_config_byte(pdev, 0x60, &sbrn); + + /* help hc dma work well with cachelines */ + pci_set_mwi (pdev); + + /* chip-specific init */ + switch (pdev->vendor) { + case PCI_VENDOR_ID_ARC: + if (pdev->device == PCI_DEVICE_ID_ARC_EHCI) + ehci->is_arc_rh_tt = 1; + break; + } + + } +#endif + /* * dedicate a qh for the async ring head, since we couldn't unlink * a 'real' qh without stopping the async schedule [4.8]. use it @@ -439,9 +475,6 @@ #endif } - /* help hc dma work well with cachelines */ - pci_set_mwi (to_pci_dev(ehci->hcd.self.controller)); - /* clear interrupt enables, set irq latency */ temp = readl (&ehci->regs->command) & 0x0fff; if (log2_irq_thresh < 0 || log2_irq_thresh > 6) @@ -468,10 +501,6 @@ /* set async sleep time = 10 us ... ? */ - init_timer (&ehci->watchdog); - ehci->watchdog.function = ehci_watchdog; - ehci->watchdog.data = (unsigned long) ehci; - /* wire up the root hub */ bus = hcd_to_bus (hcd); bus->root_hub = udev = usb_alloc_dev (NULL, bus, 0); @@ -493,12 +522,10 @@ writel (FLAG_CF, &ehci->regs->configured_flag); readl (&ehci->regs->command); /* unblock posted write */ - /* PCI Serial Bus Release Number is at 0x60 offset */ - pci_read_config_byte(to_pci_dev(hcd->self.controller), 0x60, &tempbyte); temp = HC_VERSION(readl (&ehci->caps->hc_capbase)); ehci_info (ehci, "USB %x.%x enabled, EHCI %x.%02x, driver %s\n", - ((tempbyte & 0xf0)>>4), (tempbyte & 0x0f), + ((sbrn & 0xf0)>>4), (sbrn & 0x0f), temp >> 8, temp & 0xff, DRIVER_VERSION); /* @@ -995,7 +1022,9 @@ /*-------------------------------------------------------------------------*/ -/* EHCI spec says PCI is required. */ +/* EHCI 1.0 doesn't require PCI */ + +#ifdef CONFIG_PCI /* PCI driver selection metadata; PCI hotplugging uses this */ static const struct pci_device_id pci_ids [] = { { @@ -1020,6 +1049,9 @@ .resume = usb_hcd_pci_resume, #endif }; + +#endif /* PCI */ + #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC diff -Nru a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c --- a/drivers/usb/host/ehci-hub.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/host/ehci-hub.c Tue Apr 6 17:22:26 2004 @@ -40,6 +40,15 @@ /* if reset finished and it's still not enabled -- handoff */ if (!(port_status & PORT_PE)) { + + /* with integrated TT, there's nobody to hand it to! */ + if (ehci_is_ARC(ehci)) { + ehci_dbg (ehci, + "Failed to enable port %d on root hub TT\n", + index+1); + return port_status; + } + ehci_dbg (ehci, "port %d full speed --> companion\n", index + 1); @@ -257,7 +266,8 @@ if (!(temp & PORT_OWNER)) { if (temp & PORT_CONNECT) { status |= 1 << USB_PORT_FEAT_CONNECTION; - status |= 1 << USB_PORT_FEAT_HIGHSPEED; + // status may be from integrated TT + status |= ehci_port_speed(ehci, temp); } if (temp & PORT_PE) status |= 1 << USB_PORT_FEAT_ENABLE; @@ -307,8 +317,12 @@ &ehci->regs->port_status [wIndex]); break; case USB_PORT_FEAT_RESET: - /* line status bits may report this as low speed */ + /* line status bits may report this as low speed, + * which can be fine if this root hub has a + * transaction translator built in. + */ if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT + && !ehci_is_ARC(ehci) && PORT_USB11 (temp)) { ehci_dbg (ehci, "port %d low speed --> companion\n", diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c --- a/drivers/usb/host/ehci-q.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/host/ehci-q.c Tue Apr 6 17:22:26 2004 @@ -165,7 +165,10 @@ /* if async CSPLIT failed, try cleaning out the TT buffer */ } else if (urb->dev->tt && !usb_pipeint (urb->pipe) && ((token & QTD_STS_MMF) != 0 - || QTD_CERR(token) == 0)) { + || QTD_CERR(token) == 0) + && (!ehci_is_ARC(ehci) + || urb->dev->tt->hub != + ehci->hcd.self.root_hub)) { #ifdef DEBUG struct usb_device *tt = urb->dev->tt->hub; dev_dbg (&tt->dev, @@ -576,7 +579,7 @@ // when each interface/altsetting is established. Unlink // any previous qh and cancel its urbs first; endpoints are // implicitly reset then (data toggle too). -// That'd mean updating how usbcore talks to HCDs. (2.5?) +// That'd mean updating how usbcore talks to HCDs. (2.7?) /* @@ -674,7 +677,13 @@ info2 |= (EHCI_TUNE_MULT_TT << 30); info2 |= urb->dev->ttport << 23; - info2 |= urb->dev->tt->hub->devnum << 16; + + /* set the address of the TT; for ARC's integrated + * root hub tt, leave it zeroed. + */ + if (!ehci_is_ARC(ehci) + || urb->dev->tt->hub != ehci->hcd.self.root_hub) + info2 |= urb->dev->tt->hub->devnum << 16; /* NOTE: if (PIPE_INTERRUPT) { scheduler sets c-mask } */ diff -Nru a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h --- a/drivers/usb/host/ehci.h Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/host/ehci.h Tue Apr 6 17:22:26 2004 @@ -85,6 +85,8 @@ unsigned long actions; unsigned stamp; + unsigned is_arc_rh_tt:1; /* ARC roothub with TT */ + /* irq statistics */ #ifdef EHCI_STATS struct ehci_stats stats; @@ -549,6 +551,44 @@ dma_addr_t fstn_dma; union ehci_shadow fstn_next; /* ptr to periodic q entry */ } __attribute__ ((aligned (32))); + +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_USB_EHCI_ROOT_HUB_TT + +/* + * Some EHCI controllers have a Transaction Translator built into the + * root hub. This is a non-standard feature. Each controller will need + * to add code to the following inline functions, and call them as + * needed (mostly in root hub code). + */ + +#define ehci_is_ARC(e) ((e)->is_arc_rh_tt) + +/* Returns the speed of a device attached to a port on the root hub. */ +static inline unsigned int +ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) +{ + if (ehci_is_ARC(ehci)) { + switch ((portsc>>26)&3) { + case 0: + return 0; + case 1: + return (1<lock); if (urb->status != -EINPROGRESS) { spin_unlock (&urb->lock); - + urb->hcpriv = urb_priv; finish_urb (ohci, urb, 0); retval = 0; goto fail; @@ -344,8 +344,11 @@ if (!ed) goto done; - if (!HCD_IS_RUNNING (ohci->hcd.state)) + if (!HCD_IS_RUNNING (ohci->hcd.state)) { ed->state = ED_IDLE; + finish_unlinks (ohci, 0, 0); + } + switch (ed->state) { case ED_UNLINK: /* wait for hw to finish? */ /* major IRQ delivery trouble loses INTR_SF too... */ diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c --- a/drivers/usb/host/ohci-q.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/host/ohci-q.c Tue Apr 6 17:22:26 2004 @@ -156,6 +156,7 @@ wmb (); *prev = ed; *prev_p = cpu_to_le32p (&ed->dma); + wmb(); } ohci->load [i] += ed->load; } @@ -195,6 +196,7 @@ } ed->ed_prev = ohci->ed_controltail; if (!ohci->ed_controltail && !ohci->ed_rm_list) { + wmb(); ohci->hc_control |= OHCI_CTRL_CLE; writel (0, &ohci->regs->ed_controlcurrent); writel (ohci->hc_control, &ohci->regs->control); @@ -212,6 +214,7 @@ } ed->ed_prev = ohci->ed_bulktail; if (!ohci->ed_bulktail && !ohci->ed_rm_list) { + wmb(); ohci->hc_control |= OHCI_CTRL_BLE; writel (0, &ohci->regs->ed_bulkcurrent); writel (ohci->hc_control, &ohci->regs->control); @@ -868,6 +871,7 @@ td_dma = le32_to_cpup (&ohci->hcca->done_head); ohci->hcca->done_head = 0; + wmb(); /* get TD from hc's singly linked list, and * prepend to ours. ed->td_list changes later. @@ -1069,10 +1073,12 @@ finish_urb (ohci, urb, regs); /* clean schedule: unlink EDs that are no longer busy */ - if (list_empty (&ed->td_list) && ed->state == ED_OPER) - start_ed_unlink (ohci, ed); + if (list_empty (&ed->td_list)) { + if (ed->state == ED_OPER) + start_ed_unlink (ohci, ed); + /* ... reenabling halted EDs only after fault cleanup */ - else if ((ed->hwINFO & (ED_SKIP | ED_DEQUEUE)) == ED_SKIP) { + } else if ((ed->hwINFO & (ED_SKIP | ED_DEQUEUE)) == ED_SKIP) { td = list_entry (ed->td_list.next, struct td, td_list); if (!(td->hwINFO & TD_DONE)) { ed->hwINFO &= ~ED_SKIP; diff -Nru a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c --- a/drivers/usb/host/uhci-debug.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/host/uhci-debug.c Tue Apr 6 17:22:26 2004 @@ -27,7 +27,7 @@ p = strchr(buf, '\n'); if (p) *p = 0; - printk("%s\n", buf); + printk(KERN_DEBUG "%s\n", buf); buf = p; if (buf) buf++; @@ -210,7 +210,7 @@ "skel_int32_qh", "skel_int16_qh", "skel_int8_qh", "skel_int4_qh", "skel_int2_qh", "skel_int1_qh", - "skel_ls_control_qh", "skel_hs_control_qh", + "skel_ls_control_qh", "skel_fs_control_qh", "skel_bulk_qh", "skel_term_qh" }; @@ -328,21 +328,17 @@ //out += sprintf(out, "Inserttime=%lx ",urbp->inserttime); //out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime); - spin_lock(&urbp->urb->lock); count = 0; list_for_each(tmp, &urbp->td_list) count++; - spin_unlock(&urbp->urb->lock); out += sprintf(out, "TDs=%d ",count); if (urbp->queued) out += sprintf(out, "queued\n"); else { - spin_lock(&uhci->frame_list_lock); count = 0; list_for_each(tmp, &urbp->queue_list) count++; - spin_unlock(&uhci->frame_list_lock); out += sprintf(out, "queued URBs=%d\n", count); } @@ -352,12 +348,10 @@ static int uhci_show_lists(struct uhci_hcd *uhci, char *buf, int len) { char *out = buf; - unsigned long flags; struct list_head *head, *tmp; int count; out += sprintf(out, "Main list URBs:"); - spin_lock_irqsave(&uhci->urb_list_lock, flags); if (list_empty(&uhci->urb_list)) out += sprintf(out, " Empty\n"); else { @@ -373,10 +367,8 @@ tmp = tmp->next; } } - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); out += sprintf(out, "Remove list URBs:"); - spin_lock_irqsave(&uhci->urb_remove_list_lock, flags); if (list_empty(&uhci->urb_remove_list)) out += sprintf(out, " Empty\n"); else { @@ -392,10 +384,8 @@ tmp = tmp->next; } } - spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags); out += sprintf(out, "Complete list URBs:"); - spin_lock_irqsave(&uhci->complete_list_lock, flags); if (list_empty(&uhci->complete_list)) out += sprintf(out, " Empty\n"); else { @@ -411,7 +401,6 @@ tmp = tmp->next; } } - spin_unlock_irqrestore(&uhci->complete_list_lock, flags); return out - buf; } @@ -425,7 +414,7 @@ struct uhci_td *td; struct list_head *tmp, *head; - spin_lock_irqsave(&uhci->frame_list_lock, flags); + spin_lock_irqsave(&uhci->schedule_lock, flags); out += sprintf(out, "HC status\n"); out += uhci_show_status(uhci, out, len - (out - buf)); @@ -508,11 +497,11 @@ } } - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); - if (debug > 2) out += uhci_show_lists(uhci, out, len - (out - buf)); + spin_unlock_irqrestore(&uhci->schedule_lock, flags); + return out - buf; } @@ -623,4 +612,3 @@ .release = uhci_proc_release, }; #endif - diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c --- a/drivers/usb/host/uhci-hcd.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/host/uhci-hcd.c Tue Apr 6 17:22:26 2004 @@ -117,26 +117,18 @@ */ static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci) { - unsigned long flags; - - spin_lock_irqsave(&uhci->frame_list_lock, flags); uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC); - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci) { - spin_lock(&uhci->frame_list_lock); uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC); - spin_unlock(&uhci->frame_list_lock); } static inline void uhci_moveto_complete(struct uhci_hcd *uhci, struct urb_priv *urbp) { - spin_lock(&uhci->complete_list_lock); list_move_tail(&urbp->urb_list, &uhci->complete_list); - spin_unlock(&uhci->complete_list_lock); } static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *dev) @@ -178,12 +170,8 @@ */ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, unsigned framenum) { - unsigned long flags; - framenum %= UHCI_NUMFRAMES; - spin_lock_irqsave(&uhci->frame_list_lock, flags); - td->frame = framenum; /* Is there a TD already mapped there? */ @@ -204,18 +192,13 @@ uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle); uhci->fl->frame_cpu[framenum] = td; } - - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td) { - unsigned long flags; - /* If it's not inserted, don't remove it */ - spin_lock_irqsave(&uhci->frame_list_lock, flags); if (td->frame == -1 && list_empty(&td->fl_list)) - goto out; + return; if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) { if (list_empty(&td->fl_list)) { @@ -240,9 +223,6 @@ list_del_init(&td->fl_list); td->frame = -1; - -out: - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } /* @@ -339,12 +319,11 @@ /* * Append this urb's qh after the last qh in skelqh->list - * MUST be called with uhci->frame_list_lock acquired * * Note that urb_priv.queue_list doesn't have a separate queue head; * it's a ring with every element "live". */ -static void _uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb) +static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; struct list_head *tmp; @@ -396,36 +375,20 @@ list_add_tail(&urbp->qh->list, &skelqh->list); } -static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb) -{ - unsigned long flags; - - spin_lock_irqsave(&uhci->frame_list_lock, flags); - _uhci_insert_qh(uhci, skelqh, urb); - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); -} - /* * Start removal of QH from schedule; it finishes next frame. * TDs should be unlinked before this is called. */ static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) { - unsigned long flags; struct uhci_qh *pqh; if (!qh) return; - qh->urbp = NULL; - /* * Only go through the hoops if it's actually linked in - * Queued QHs are removed in uhci_delete_queued_urb, - * since (for queued URBs) the pqh is pointed to the next - * QH in the queue, not the next endpoint's QH. */ - spin_lock_irqsave(&uhci->frame_list_lock, flags); if (!list_empty(&qh->list)) { pqh = list_entry(qh->list.prev, struct uhci_qh, list); @@ -450,11 +413,19 @@ /* continue the rest of the schedule */ qh->element = UHCI_PTR_TERM; + /* If our queue is nonempty, make the next URB the head */ + if (!list_empty(&qh->urbp->queue_list)) { + struct urb_priv *nurbp; + + nurbp = list_entry(qh->urbp->queue_list.next, + struct urb_priv, queue_list); + nurbp->queued = 0; + list_add_tail(&nurbp->qh->list, &qh->list); + } list_del_init(&qh->list); } - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); - spin_lock_irqsave(&uhci->qh_remove_list_lock, flags); + qh->urbp = NULL; /* Check to see if the remove list is empty. Set the IOC bit */ /* to force an interrupt so we can remove the QH */ @@ -462,8 +433,6 @@ uhci_set_next_interrupt(uhci); list_add(&qh->remove_list, &uhci->qh_remove_list); - - spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags); } static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle) @@ -497,13 +466,10 @@ struct urb_priv *eurbp, *urbp, *furbp, *lurbp; struct list_head *tmp; struct uhci_td *lltd; - unsigned long flags; eurbp = eurb->hcpriv; urbp = urb->hcpriv; - spin_lock_irqsave(&uhci->frame_list_lock, flags); - /* Find the first URB in the queue */ if (eurbp->queued) { struct list_head *head = &eurbp->queue_list; @@ -543,8 +509,6 @@ list_add_tail(&urbp->queue_list, &furbp->queue_list); urbp->queued = 1; - - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } static void uhci_delete_queued_urb(struct uhci_hcd *uhci, struct urb *urb) @@ -554,14 +518,11 @@ struct urb_priv *purbp; struct uhci_td *pltd; unsigned int toggle; - unsigned long flags; urbp = urb->hcpriv; - spin_lock_irqsave(&uhci->frame_list_lock, flags); - if (list_empty(&urbp->queue_list)) - goto out; + return; nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list); @@ -603,39 +564,9 @@ usb_pipeout(urb->pipe), toggle); } - if (!urbp->queued) { - struct uhci_qh *pqh; - - nurbp->queued = 0; - - /* - * Fixup the previous QH's queue to link to the new head - * of this queue. - */ - pqh = list_entry(urbp->qh->list.prev, struct uhci_qh, list); - - if (pqh->urbp) { - struct list_head *head, *tmp; - - head = &pqh->urbp->queue_list; - tmp = head->next; - while (head != tmp) { - struct urb_priv *turbp = - list_entry(tmp, struct urb_priv, queue_list); - - tmp = tmp->next; - - turbp->qh->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH; - } - } - - pqh->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH; - - list_add_tail(&nurbp->qh->list, &urbp->qh->list); - list_del_init(&urbp->qh->list); - } else { - /* We're somewhere in the middle (or end). A bit trickier */ - /* than the head scenario */ + if (urbp->queued) { + /* We're somewhere in the middle (or end). The case where + * we're at the head is handled in uhci_remove_qh(). */ purbp = list_entry(urbp->queue_list.prev, struct urb_priv, queue_list); @@ -649,9 +580,6 @@ } list_del_init(&urbp->queue_list); - -out: - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *urb) @@ -679,9 +607,6 @@ return urbp; } -/* - * MUST be called with urb->lock acquired - */ static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; @@ -691,9 +616,6 @@ list_add_tail(&td->list, &urbp->td_list); } -/* - * MUST be called with urb->lock acquired - */ static void uhci_remove_td_from_urb(struct uhci_td *td) { if (list_empty(&td->list)) @@ -704,14 +626,10 @@ td->urb = NULL; } -/* - * MUST be called with urb->lock acquired - */ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) { struct list_head *head, *tmp; struct urb_priv *urbp; - unsigned long flags; urbp = (struct urb_priv *)urb->hcpriv; if (!urbp) @@ -721,8 +639,6 @@ dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list " "or uhci->remove_list!\n", urb); - spin_lock_irqsave(&uhci->td_remove_list_lock, flags); - /* Check to see if the remove list is empty. Set the IOC bit */ /* to force an interrupt so we can remove the TD's*/ if (list_empty(&uhci->td_remove_list)) @@ -740,42 +656,30 @@ list_add(&td->remove_list, &uhci->td_remove_list); } - spin_unlock_irqrestore(&uhci->td_remove_list_lock, flags); - urb->hcpriv = NULL; kmem_cache_free(uhci_up_cachep, urbp); } static void uhci_inc_fsbr(struct uhci_hcd *uhci, struct urb *urb) { - unsigned long flags; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - spin_lock_irqsave(&uhci->frame_list_lock, flags); - if ((!(urb->transfer_flags & URB_NO_FSBR)) && !urbp->fsbr) { urbp->fsbr = 1; if (!uhci->fsbr++ && !uhci->fsbrtimeout) - uhci->skel_term_qh->link = cpu_to_le32(uhci->skel_hs_control_qh->dma_handle) | UHCI_PTR_QH; + uhci->skel_term_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH; } - - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } static void uhci_dec_fsbr(struct uhci_hcd *uhci, struct urb *urb) { - unsigned long flags; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - spin_lock_irqsave(&uhci->frame_list_lock, flags); - if ((!(urb->transfer_flags & URB_NO_FSBR)) && urbp->fsbr) { urbp->fsbr = 0; if (!--uhci->fsbr) uhci->fsbrtimeout = jiffies + FSBR_DELAY; } - - spin_unlock_irqrestore(&uhci->frame_list_lock, flags); } /* @@ -840,13 +744,16 @@ urb->setup_dma); /* - * If direction is "send", change the frame from SETUP (0x2D) - * to OUT (0xE1). Else change it from SETUP to IN (0x69). + * If direction is "send", change the packet ID from SETUP (0x2D) + * to OUT (0xE1). Else change it from SETUP to IN (0x69) and + * set Short Packet Detect (SPD) for all data packets. */ - destination ^= (USB_PID_SETUP ^ usb_packetid(urb->pipe)); - - if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) + if (usb_pipeout(urb->pipe)) + destination ^= (USB_PID_SETUP ^ USB_PID_OUT); + else { + destination ^= (USB_PID_SETUP ^ USB_PID_IN); status |= TD_CTRL_SPD; + } /* * Build the DATA TD's @@ -910,7 +817,7 @@ if (urb->dev->speed == USB_SPEED_LOW) skelqh = uhci->skel_ls_control_qh; else { - skelqh = uhci->skel_hs_control_qh; + skelqh = uhci->skel_fs_control_qh; uhci_inc_fsbr(uhci, urb); } @@ -923,50 +830,23 @@ } /* - * If control was short, then end status packet wasn't sent, so this - * reorganize s so it's sent to finish the transfer. The original QH is - * removed from the skel and discarded; all TDs except the last (status) - * are deleted; the last (status) TD is put on a new QH which is reinserted - * into the skel. Since the last TD and urb_priv are reused, the TD->link - * and urb_priv maintain any queued QHs. + * If control-IN transfer was short, the status packet wasn't sent. + * This routine changes the element pointer in the QH to point at the + * status TD. It's safe to do this even while the QH is live, because + * the hardware only updates the element pointer following a successful + * transfer. The inactive TD for the short packet won't cause an update, + * so the pointer won't get overwritten. The next time the controller + * sees this QH, it will send the status packet. */ static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb) { - struct list_head *tmp, *head; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; + struct uhci_td *td; urbp->short_control_packet = 1; - /* Create a new QH to avoid pointer overwriting problems */ - uhci_remove_qh(uhci, urbp->qh); - - /* Delete all of the TD's except for the status TD at the end */ - head = &urbp->td_list; - tmp = head->next; - while (tmp != head && tmp->next != head) { - struct uhci_td *td = list_entry(tmp, struct uhci_td, list); - - tmp = tmp->next; - - uhci_remove_td_from_urb(td); - uhci_remove_td(uhci, td); - uhci_free_td(uhci, td); - } - - urbp->qh = uhci_alloc_qh(uhci, urb->dev); - if (!urbp->qh) - return -ENOMEM; - - urbp->qh->urbp = urbp; - - /* One TD, who cares about Breadth first? */ - uhci_insert_tds_in_qh(urbp->qh, urb, UHCI_PTR_DEPTH); - - /* Low-speed transfers get a different queue */ - if (urb->dev->speed == USB_SPEED_LOW) - uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb); - else - uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb); + td = list_entry(urbp->td_list.prev, struct uhci_td, list); + urbp->qh->element = td->dma_handle; return -EINPROGRESS; } @@ -1101,17 +981,20 @@ status = uhci_maxerr(3) | TD_CTRL_ACTIVE; if (urb->dev->speed == USB_SPEED_LOW) status |= TD_CTRL_LS; - if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) + if (usb_pipein(urb->pipe)) status |= TD_CTRL_SPD; /* * Build the DATA TD's */ do { /* Allow zero length packets */ - int pktsze = len; + int pktsze = maxsze; - if (pktsze > maxsze) - pktsze = maxsze; + if (pktsze >= len) { + pktsze = len; + if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) + status &= ~TD_CTRL_SPD; + } td = uhci_alloc_td(uhci, urb->dev); if (!td) @@ -1154,7 +1037,8 @@ } /* Set the flag on the last packet */ - td->status |= cpu_to_le32(TD_CTRL_IOC); + if (!(urb->transfer_flags & URB_NO_INTERRUPT)) + td->status |= cpu_to_le32(TD_CTRL_IOC); qh = uhci_alloc_qh(uhci, urb->dev); if (!qh) @@ -1409,9 +1293,6 @@ return ret; } -/* - * MUST be called with uhci->urb_list_lock acquired - */ static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb) { struct list_head *tmp, *head; @@ -1449,7 +1330,7 @@ struct urb *eurb; int bustime; - spin_lock_irqsave(&uhci->urb_list_lock, flags); + spin_lock_irqsave(&uhci->schedule_lock, flags); if (urb->status != -EINPROGRESS) /* URB already unlinked! */ goto out; @@ -1506,14 +1387,12 @@ ret = 0; out: - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + spin_unlock_irqrestore(&uhci->schedule_lock, flags); return ret; } /* * Return the result of a transfer - * - * MUST be called with urb_list_lock acquired */ static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb) { @@ -1549,7 +1428,6 @@ case PIPE_BULK: case PIPE_ISOCHRONOUS: /* Release bandwidth for Interrupt or Isoc. transfers */ - /* Spinlock needed ? */ if (urb->bandwidth) usb_release_bandwidth(urb->dev, urb, 1); uhci_unlink_generic(uhci, urb); @@ -1557,15 +1435,12 @@ case PIPE_INTERRUPT: /* Release bandwidth for Interrupt or Isoc. transfers */ /* Make sure we don't release if we have a queued URB */ - spin_lock(&uhci->frame_list_lock); - /* Spinlock needed ? */ if (list_empty(&urbp->queue_list) && urb->bandwidth) usb_release_bandwidth(urb->dev, urb, 0); else /* bandwidth was passed on to queued URB, */ /* so don't let usb_unlink_urb() release it */ urb->bandwidth = 0; - spin_unlock(&uhci->frame_list_lock); uhci_unlink_generic(uhci, urb); break; default: @@ -1581,9 +1456,6 @@ spin_unlock(&urb->lock); } -/* - * MUST be called with urb->lock acquired - */ static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb) { struct list_head *head, *tmp; @@ -1639,7 +1511,7 @@ unsigned long flags; struct urb_priv *urbp; - spin_lock_irqsave(&uhci->urb_list_lock, flags); + spin_lock_irqsave(&uhci->schedule_lock, flags); urbp = urb->hcpriv; if (!urbp) /* URB was never linked! */ goto done; @@ -1647,16 +1519,13 @@ uhci_unlink_generic(uhci, urb); - spin_lock(&uhci->urb_remove_list_lock); - /* If we're the first, set the next interrupt bit */ if (list_empty(&uhci->urb_remove_list)) uhci_set_next_interrupt(uhci); list_add_tail(&urbp->urb_list, &uhci->urb_remove_list); - spin_unlock(&uhci->urb_remove_list_lock); done: - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + spin_unlock_irqrestore(&uhci->schedule_lock, flags); return 0; } @@ -1718,7 +1587,7 @@ INIT_LIST_HEAD(&list); - spin_lock_irqsave(&uhci->urb_list_lock, flags); + spin_lock_irqsave(&uhci->schedule_lock, flags); head = &uhci->urb_list; tmp = head->next; while (tmp != head) { @@ -1734,12 +1603,15 @@ uhci_fsbr_timeout(uhci, u); /* Check if the URB timed out */ - if (u->timeout && time_after_eq(jiffies, up->inserttime + u->timeout)) + if (u->timeout && u->status == -EINPROGRESS && + time_after_eq(jiffies, up->inserttime + u->timeout)) { + u->status = -ETIMEDOUT; list_move_tail(&up->urb_list, &list); + } spin_unlock(&u->lock); } - spin_unlock_irqrestore(&uhci->urb_list_lock, flags); + spin_unlock_irqrestore(&uhci->schedule_lock, flags); head = &list; tmp = head->next; @@ -1781,7 +1653,6 @@ { struct list_head *tmp, *head; - spin_lock(&uhci->qh_remove_list_lock); head = &uhci->qh_remove_list; tmp = head->next; while (tmp != head) { @@ -1793,14 +1664,12 @@ uhci_free_qh(uhci, qh); } - spin_unlock(&uhci->qh_remove_list_lock); } static void uhci_free_pending_tds(struct uhci_hcd *uhci) { struct list_head *tmp, *head; - spin_lock(&uhci->td_remove_list_lock); head = &uhci->td_remove_list; tmp = head->next; while (tmp != head) { @@ -1812,18 +1681,17 @@ uhci_free_td(uhci, td); } - spin_unlock(&uhci->td_remove_list_lock); } static void uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - spin_lock(&urb->lock); uhci_destroy_urb_priv(uhci, urb); - spin_unlock(&urb->lock); + spin_unlock(&uhci->schedule_lock); usb_hcd_giveback_urb(hcd, urb, regs); + spin_lock(&uhci->schedule_lock); } static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs) @@ -1831,7 +1699,6 @@ struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct list_head *tmp, *head; - spin_lock(&uhci->complete_list_lock); head = &uhci->complete_list; tmp = head->next; while (tmp != head) { @@ -1839,26 +1706,18 @@ struct urb *urb = urbp->urb; list_del_init(&urbp->urb_list); - spin_unlock(&uhci->complete_list_lock); - uhci_finish_urb(hcd, urb, regs); - spin_lock(&uhci->complete_list_lock); head = &uhci->complete_list; tmp = head->next; } - spin_unlock(&uhci->complete_list_lock); } static void uhci_remove_pending_urbps(struct uhci_hcd *uhci) { - spin_lock(&uhci->urb_remove_list_lock); - spin_lock(&uhci->complete_list_lock); /* Splice the urb_remove_list onto the end of the complete_list */ list_splice_init(&uhci->urb_remove_list, uhci->complete_list.prev); - spin_unlock(&uhci->complete_list_lock); - spin_unlock(&uhci->urb_remove_list_lock); } static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) @@ -1895,16 +1754,15 @@ if (status & USBSTS_RD) uhci->resume_detect = 1; - uhci_free_pending_qhs(uhci); + spin_lock(&uhci->schedule_lock); + uhci_free_pending_qhs(uhci); uhci_free_pending_tds(uhci); - uhci_remove_pending_urbps(uhci); uhci_clear_next_interrupt(uhci); /* Walk the list of pending URB's to see which ones completed */ - spin_lock(&uhci->urb_list_lock); head = &uhci->urb_list; tmp = head->next; while (tmp != head) { @@ -1916,9 +1774,10 @@ /* Checks the status and does all of the magic necessary */ uhci_transfer_result(uhci, urb); } - spin_unlock(&uhci->urb_list_lock); - uhci_finish_completion(hcd, regs); + + spin_unlock(&uhci->schedule_lock); + return IRQ_HANDLED; } @@ -2208,23 +2067,17 @@ uhci->fsbr = 0; uhci->fsbrtimeout = 0; - spin_lock_init(&uhci->qh_remove_list_lock); + spin_lock_init(&uhci->schedule_lock); INIT_LIST_HEAD(&uhci->qh_remove_list); - spin_lock_init(&uhci->td_remove_list_lock); INIT_LIST_HEAD(&uhci->td_remove_list); - spin_lock_init(&uhci->urb_remove_list_lock); INIT_LIST_HEAD(&uhci->urb_remove_list); - spin_lock_init(&uhci->urb_list_lock); INIT_LIST_HEAD(&uhci->urb_list); - spin_lock_init(&uhci->complete_list_lock); INIT_LIST_HEAD(&uhci->complete_list); - spin_lock_init(&uhci->frame_list_lock); - uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl), &dma_handle, 0); if (!uhci->fl) { @@ -2311,8 +2164,8 @@ cpu_to_le32(uhci->skel_int1_qh->dma_handle) | UHCI_PTR_QH; uhci->skel_int1_qh->link = cpu_to_le32(uhci->skel_ls_control_qh->dma_handle) | UHCI_PTR_QH; - uhci->skel_ls_control_qh->link = cpu_to_le32(uhci->skel_hs_control_qh->dma_handle) | UHCI_PTR_QH; - uhci->skel_hs_control_qh->link = cpu_to_le32(uhci->skel_bulk_qh->dma_handle) | UHCI_PTR_QH; + uhci->skel_ls_control_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH; + uhci->skel_fs_control_qh->link = cpu_to_le32(uhci->skel_bulk_qh->dma_handle) | UHCI_PTR_QH; uhci->skel_bulk_qh->link = cpu_to_le32(uhci->skel_term_qh->dma_handle) | UHCI_PTR_QH; /* This dummy TD is to work around a bug in Intel PIIX controllers */ @@ -2416,7 +2269,6 @@ static void uhci_stop(struct usb_hcd *hcd) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - unsigned long flags; del_timer_sync(&uhci->stall_timer); @@ -2424,16 +2276,18 @@ * At this point, we're guaranteed that no new connects can be made * to this bus since there are no more parents */ - local_irq_save(flags); + + reset_hc(uhci); + + spin_lock_irq(&uhci->schedule_lock); uhci_free_pending_qhs(uhci); uhci_free_pending_tds(uhci); uhci_remove_pending_urbps(uhci); - - reset_hc(uhci); + uhci_finish_completion(hcd, NULL); uhci_free_pending_qhs(uhci); uhci_free_pending_tds(uhci); - local_irq_restore(flags); + spin_unlock_irq(&uhci->schedule_lock); release_uhci(uhci); } diff -Nru a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h --- a/drivers/usb/host/uhci-hcd.h Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/host/uhci-hcd.h Tue Apr 6 17:22:26 2004 @@ -254,7 +254,7 @@ #define skel_int2_qh skelqh[6] #define skel_int1_qh skelqh[7] #define skel_ls_control_qh skelqh[8] -#define skel_hs_control_qh skelqh[9] +#define skel_fs_control_qh skelqh[9] #define skel_bulk_qh skelqh[10] #define skel_term_qh skelqh[11] @@ -342,8 +342,8 @@ struct uhci_td *term_td; /* Terminating TD, see UHCI bug */ struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */ - spinlock_t frame_list_lock; - struct uhci_frame_list *fl; /* P: uhci->frame_list_lock */ + spinlock_t schedule_lock; + struct uhci_frame_list *fl; /* P: uhci->schedule_lock */ int fsbr; /* Full-speed bandwidth reclamation */ unsigned long fsbrtimeout; /* FSBR delay */ @@ -353,24 +353,19 @@ unsigned int saved_framenumber; /* Save during PM suspend */ /* Main list of URB's currently controlled by this HC */ - spinlock_t urb_list_lock; - struct list_head urb_list; /* P: uhci->urb_list_lock */ + struct list_head urb_list; /* P: uhci->schedule_lock */ /* List of QH's that are done, but waiting to be unlinked (race) */ - spinlock_t qh_remove_list_lock; - struct list_head qh_remove_list; /* P: uhci->qh_remove_list_lock */ + struct list_head qh_remove_list; /* P: uhci->schedule_lock */ /* List of TD's that are done, but waiting to be freed (race) */ - spinlock_t td_remove_list_lock; - struct list_head td_remove_list; /* P: uhci->td_remove_list_lock */ + struct list_head td_remove_list; /* P: uhci->schedule_lock */ /* List of asynchronously unlinked URB's */ - spinlock_t urb_remove_list_lock; - struct list_head urb_remove_list; /* P: uhci->urb_remove_list_lock */ + struct list_head urb_remove_list; /* P: uhci->schedule_lock */ /* List of URB's awaiting completion callback */ - spinlock_t complete_list_lock; - struct list_head complete_list; /* P: uhci->complete_list_lock */ + struct list_head complete_list; /* P: uhci->schedule_lock */ int rh_numports; @@ -401,26 +396,15 @@ /* * Locking in uhci.c * - * spinlocks are used extensively to protect the many lists and data - * structures we have. It's not that pretty, but it's necessary. We - * need to be done with all of the locks (except complete_list_lock) when - * we call urb->complete. I've tried to make it simple enough so I don't - * have to spend hours racking my brain trying to figure out if the - * locking is safe. + * Almost everything relating to the hardware schedule and processing + * of URBs is protected by uhci->schedule_lock. urb->status is protected + * by urb->lock; that's the one exception. * - * Here's the safe locking order to prevent deadlocks: + * To prevent deadlocks, never lock uhci->schedule_lock while holding + * urb->lock. The safe order of locking is: * - * #1 uhci->urb_list_lock + * #1 uhci->schedule_lock * #2 urb->lock - * #3 uhci->urb_remove_list_lock, uhci->frame_list_lock, - * uhci->qh_remove_list_lock - * #4 uhci->complete_list_lock - * - * If you're going to grab 2 or more locks at once, ALWAYS grab the lock - * at the lowest level FIRST and NEVER grab locks at the same level at the - * same time. - * - * So, if you need uhci->urb_list_lock, grab it before you grab urb->lock */ #endif diff -Nru a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig --- a/drivers/usb/input/Kconfig Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/input/Kconfig Tue Apr 6 17:22:26 2004 @@ -21,7 +21,7 @@ If unsure, say Y. To compile this driver as a module, choose M here: the - module will be called hid. + module will be called usbhid. comment "Input core support is needed for USB HID input layer or HIDBP support" depends on USB && INPUT=n diff -Nru a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile --- a/drivers/usb/input/Makefile Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/input/Makefile Tue Apr 6 17:22:26 2004 @@ -3,32 +3,32 @@ # # Multipart objects. -hid-objs := hid-core.o +usbhid-objs := hid-core.o # Optional parts of multipart objects. ifeq ($(CONFIG_USB_HIDDEV),y) - hid-objs += hiddev.o + usbhid-objs += hiddev.o endif ifeq ($(CONFIG_USB_HIDINPUT),y) - hid-objs += hid-input.o + usbhid-objs += hid-input.o endif ifeq ($(CONFIG_HID_PID),y) - hid-objs += pid.o + usbhid-objs += pid.o endif ifeq ($(CONFIG_LOGITECH_FF),y) - hid-objs += hid-lgff.o + usbhid-objs += hid-lgff.o endif ifeq ($(CONFIG_THRUSTMASTER_FF),y) - hid-objs += hid-tmff.o + usbhid-objs += hid-tmff.o endif ifeq ($(CONFIG_HID_FF),y) - hid-objs += hid-ff.o + usbhid-objs += hid-ff.o endif obj-$(CONFIG_USB_AIPTEK) += aiptek.o obj-$(CONFIG_USB_ATI_REMOTE) += ati_remote.o -obj-$(CONFIG_USB_HID) += hid.o +obj-$(CONFIG_USB_HID) += usbhid.o obj-$(CONFIG_USB_KBD) += usbkbd.o obj-$(CONFIG_USB_KBTAB) += kbtab.o obj-$(CONFIG_USB_MOUSE) += usbmouse.o diff -Nru a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c --- a/drivers/usb/input/aiptek.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/input/aiptek.c Tue Apr 6 17:22:26 2004 @@ -265,7 +265,7 @@ const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev (intf); - struct usb_host_interface *interface = intf->altsetting + 0; + struct usb_host_interface *interface = intf->cur_altsetting; struct usb_endpoint_descriptor *endpoint; struct aiptek *aiptek; int err = -ENOMEM; diff -Nru a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c --- a/drivers/usb/input/ati_remote.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/input/ati_remote.c Tue Apr 6 17:22:26 2004 @@ -99,7 +99,7 @@ #define DATA_BUFSIZE 63 /* size of URB data buffers */ #define ATI_INPUTNUM 1 /* Which input device to register as */ -unsigned long channel_mask = 0; +static unsigned long channel_mask = 0; module_param(channel_mask, ulong, 444); MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore"); @@ -139,6 +139,8 @@ */ #define FILTER_TIME (HZ >> 4) +static DECLARE_MUTEX(disconnect_sem); + struct ati_remote { struct input_dev idev; struct usb_device *udev; @@ -286,12 +288,12 @@ static void ati_remote_dump(unsigned char *data, unsigned int len) { if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00)) - warn("Weird byte 0x%02x\n", data[0]); + warn("Weird byte 0x%02x", data[0]); else if (len == 4) - warn("Weird key %02x %02x %02x %02x\n", + warn("Weird key %02x %02x %02x %02x", data[0], data[1], data[2], data[3]); else - warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...\n", + warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...", len, data[0], data[1], data[2], data[3], data[4], data[5]); } @@ -301,9 +303,12 @@ static int ati_remote_open(struct input_dev *inputdev) { struct ati_remote *ati_remote = inputdev->private; + int retval = 0; + + down(&disconnect_sem); if (ati_remote->open++) - return 0; + goto exit; /* On first open, submit the read urb which was set up previously. */ ati_remote->irq_urb->dev = ati_remote->udev; @@ -311,10 +316,12 @@ dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb failed!\n", __FUNCTION__); ati_remote->open--; - return -EIO; + retval = -EIO; } - return 0; +exit: + up(&disconnect_sem); + return retval; } /* @@ -354,8 +361,7 @@ ati_remote->send_flags |= SEND_FLAG_COMPLETE; wmb(); - if (waitqueue_active(&ati_remote->wait)) - wake_up(&ati_remote->wait); + wake_up(&ati_remote->wait); } /* @@ -377,18 +383,16 @@ ati_remote->out_urb->dev = ati_remote->udev; ati_remote->send_flags = SEND_FLAG_IN_PROGRESS; - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&ati_remote->wait, &wait); - - retval = usb_submit_urb(ati_remote->out_urb, GFP_KERNEL); + retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC); if (retval) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&ati_remote->wait, &wait); dev_dbg(&ati_remote->interface->dev, "sendpacket: usb_submit_urb failed: %d\n", retval); return retval; } + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&ati_remote->wait, &wait); + while (timeout && (ati_remote->out_urb->status == -EINPROGRESS) && !(ati_remote->send_flags & SEND_FLAG_COMPLETE)) { timeout = schedule_timeout(timeout); @@ -594,11 +598,7 @@ if (ati_remote->out_urb) usb_unlink_urb(ati_remote->out_urb); - if (ati_remote->irq_urb) - usb_free_urb(ati_remote->irq_urb); - - if (ati_remote->out_urb) - usb_free_urb(ati_remote->out_urb); + input_unregister_device(&ati_remote->idev); if (ati_remote->inbuf) usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, @@ -608,6 +608,12 @@ usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, ati_remote->inbuf, ati_remote->outbuf_dma); + if (ati_remote->irq_urb) + usb_free_urb(ati_remote->irq_urb); + + if (ati_remote->out_urb) + usb_free_urb(ati_remote->out_urb); + kfree(ati_remote); } @@ -779,14 +785,14 @@ usb_set_intfdata(interface, ati_remote); ati_remote->present = 1; - kfree(buf); - return 0; error: if (buf) kfree(buf); - ati_remote_delete(ati_remote); + if (retval) + ati_remote_delete(ati_remote); + return retval; } @@ -796,7 +802,9 @@ static void ati_remote_disconnect(struct usb_interface *interface) { struct ati_remote *ati_remote; - + + down(&disconnect_sem); + ati_remote = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); if (!ati_remote) { @@ -804,14 +812,14 @@ return; } - input_unregister_device(&ati_remote->idev); - /* Mark device as unplugged */ ati_remote->present = 0; /* If device is still open, ati_remote_close will call delete. */ if (!ati_remote->open) ati_remote_delete(ati_remote); + + up(&disconnect_sem); } /* diff -Nru a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c --- a/drivers/usb/input/hiddev.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/input/hiddev.c Tue Apr 6 17:22:26 2004 @@ -403,8 +403,8 @@ struct hiddev_collection_info cinfo; struct hiddev_report_info rinfo; struct hiddev_field_info finfo; - struct hiddev_usage_ref_multi uref_multi; - struct hiddev_usage_ref *uref = &uref_multi.uref; + struct hiddev_usage_ref_multi *uref_multi=NULL; + struct hiddev_usage_ref *uref; struct hiddev_devinfo dinfo; struct hid_report *report; struct hid_field *field; @@ -576,26 +576,31 @@ return 0; case HIDIOCGUCODE: - if (copy_from_user(uref, (void *) arg, sizeof(*uref))) - return -EFAULT; + uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); + if (!uref_multi) + return -ENOMEM; + uref = &uref_multi->uref; + if (copy_from_user(uref, (void *) arg, sizeof(*uref))) + goto fault; rinfo.report_type = uref->report_type; rinfo.report_id = uref->report_id; if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - return -EINVAL; + goto inval; if (uref->field_index >= report->maxfield) - return -EINVAL; + goto inval; field = report->field[uref->field_index]; if (uref->usage_index >= field->maxusage) - return -EINVAL; + goto inval; uref->usage_code = field->usage[uref->usage_index].hid; if (copy_to_user((void *) arg, uref, sizeof(*uref))) - return -EFAULT; + goto fault; + kfree(uref_multi); return 0; case HIDIOCGUSAGE: @@ -603,42 +608,46 @@ case HIDIOCGUSAGES: case HIDIOCSUSAGES: case HIDIOCGCOLLECTIONINDEX: + uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); + if (!uref_multi) + return -ENOMEM; + uref = &uref_multi->uref; if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { - if (copy_from_user(&uref_multi, (void *) arg, + if (copy_from_user(uref_multi, (void *) arg, sizeof(uref_multi))) - return -EFAULT; + goto fault; } else { if (copy_from_user(uref, (void *) arg, sizeof(*uref))) - return -EFAULT; + goto fault; } if (cmd != HIDIOCGUSAGE && cmd != HIDIOCGUSAGES && uref->report_type == HID_REPORT_TYPE_INPUT) - return -EINVAL; + goto inval; if (uref->report_id == HID_REPORT_ID_UNKNOWN) { field = hiddev_lookup_usage(hid, uref); if (field == NULL) - return -EINVAL; + goto inval; } else { rinfo.report_type = uref->report_type; rinfo.report_id = uref->report_id; if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - return -EINVAL; + goto inval; if (uref->field_index >= report->maxfield) - return -EINVAL; + goto inval; field = report->field[uref->field_index]; if (uref->usage_index >= field->maxusage) - return -EINVAL; + goto inval; if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { - if (uref_multi.num_values >= HID_MAX_USAGES || + if (uref_multi->num_values >= HID_MAX_USAGES || uref->usage_index >= field->maxusage || - (uref->usage_index + uref_multi.num_values) >= field->maxusage) - return -EINVAL; + (uref->usage_index + uref_multi->num_values) >= field->maxusage) + goto inval; } } @@ -646,31 +655,40 @@ case HIDIOCGUSAGE: uref->value = field->value[uref->usage_index]; if (copy_to_user((void *) arg, uref, sizeof(*uref))) - return -EFAULT; - return 0; + goto fault; + goto goodreturn; case HIDIOCSUSAGE: field->value[uref->usage_index] = uref->value; - return 0; + goto goodreturn; case HIDIOCGCOLLECTIONINDEX: + kfree(uref_multi); return field->usage[uref->usage_index].collection_index; case HIDIOCGUSAGES: - for (i = 0; i < uref_multi.num_values; i++) - uref_multi.values[i] = + for (i = 0; i < uref_multi->num_values; i++) + uref_multi->values[i] = field->value[uref->usage_index + i]; - if (copy_to_user((void *) arg, &uref_multi, - sizeof(uref_multi))) - return -EFAULT; - return 0; + if (copy_to_user((void *) arg, uref_multi, + sizeof(*uref_multi))) + goto fault; + goto goodreturn; case HIDIOCSUSAGES: - for (i = 0; i < uref_multi.num_values; i++) + for (i = 0; i < uref_multi->num_values; i++) field->value[uref->usage_index + i] = - uref_multi.values[i]; - return 0; + uref_multi->values[i]; + goto goodreturn; } +goodreturn: + kfree(uref_multi); return 0; +fault: + kfree(uref_multi); + return -EFAULT; +inval: + kfree(uref_multi); + return -EINVAL; case HIDIOCGCOLLECTIONINFO: if (copy_from_user(&cinfo, (void *) arg, sizeof(cinfo))) diff -Nru a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c --- a/drivers/usb/input/kbtab.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/input/kbtab.c Tue Apr 6 17:22:26 2004 @@ -182,7 +182,7 @@ kbtab->dev.dev = &intf->dev; kbtab->usbdev = dev; - endpoint = &intf->altsetting[0].endpoint[0].desc; + endpoint = &intf->cur_altsetting->endpoint[0].desc; usb_fill_int_urb(kbtab->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), diff -Nru a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c --- a/drivers/usb/input/powermate.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/input/powermate.c Tue Apr 6 17:22:26 2004 @@ -305,7 +305,7 @@ int pipe, maxp; char path[64]; - interface = intf->altsetting + 0; + interface = intf->cur_altsetting; endpoint = &interface->endpoint[0].desc; if (!(endpoint->bEndpointAddress & 0x80)) return -EIO; diff -Nru a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c --- a/drivers/usb/input/wacom.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/input/wacom.c Tue Apr 6 17:22:26 2004 @@ -698,7 +698,7 @@ wacom->dev.dev = &intf->dev; wacom->usbdev = dev; - endpoint = &intf->altsetting[0].endpoint[0].desc; + endpoint = &intf->cur_altsetting->endpoint[0].desc; if (wacom->features->pktlen > 10) BUG(); diff -Nru a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c --- a/drivers/usb/input/xpad.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/input/xpad.c Tue Apr 6 17:22:26 2004 @@ -252,7 +252,7 @@ return -ENOMEM; } - ep_irq_in = &intf->altsetting[0].endpoint[0].desc; + ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; usb_fill_int_urb(xpad->irq_in, udev, usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress), diff -Nru a/drivers/usb/media/Kconfig b/drivers/usb/media/Kconfig --- a/drivers/usb/media/Kconfig Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/media/Kconfig Tue Apr 6 17:22:26 2004 @@ -108,7 +108,7 @@ config USB_PWC tristate "USB Philips Cameras" - depends on USB && VIDEO_DEV + depends on USB && VIDEO_DEV && BROKEN ---help--- Say Y or M here if you want to use one of these Philips & OEM webcams: diff -Nru a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c --- a/drivers/usb/media/vicam.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/media/vicam.c Tue Apr 6 17:22:26 2004 @@ -1269,6 +1269,8 @@ /** * vicam_probe + * @intf: the interface + * @id: the device id * * Called by the usb core when a new device is connected that it thinks * this driver might be interested in. diff -Nru a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c --- a/drivers/usb/media/w9968cf.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/media/w9968cf.c Tue Apr 6 17:22:26 2004 @@ -905,8 +905,7 @@ spin_unlock(&cam->urb_lock); /* Wake up the user process */ - if (waitqueue_active(&cam->wait_queue)) - wake_up_interruptible(&cam->wait_queue); + wake_up_interruptible(&cam->wait_queue); } @@ -2690,6 +2689,7 @@ up(&cam->dev_sem); return -EWOULDBLOCK; } +retry: up(&cam->dev_sem); err = wait_event_interruptible(cam->open, cam->disconnected || (cam->users == 0)); @@ -2698,6 +2698,9 @@ if (cam->disconnected) return -ENODEV; down(&cam->dev_sem); + /*recheck - there may be several waiters */ + if (cam->users) + goto retry; } DBG(5, "Opening '%s', /dev/video%d ...", @@ -2758,8 +2761,7 @@ cam->users--; w9968cf_deallocate_memory(cam); - if (waitqueue_active(&cam->open)) - wake_up_interruptible(&cam->open); + wake_up_interruptible(&cam->open); DBG(5, "Video device closed.") up(&cam->dev_sem); @@ -3371,7 +3373,7 @@ if (copy_from_user(&tuner, arg, sizeof(tuner))) return -EFAULT; - if (tuner.tuner != 0); + if (tuner.tuner != 0) return -EINVAL; strcpy(tuner.name, "no_tuner"); diff -Nru a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig --- a/drivers/usb/misc/Kconfig Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/misc/Kconfig Tue Apr 6 17:22:26 2004 @@ -108,6 +108,19 @@ To compile this driver as a module, choose M here: the module will be called usbled. +config USB_CYTHERM + tristate "Cypress USB thermometer driver support" + depends on USB + help + Say Y here if you want to connect a Cypress USB thermometer + device to your computer's USB port. This device is also known + as the Cypress USB Starter kit or demo board. The Elektor + magazine published a modified version of this device in issue + #291. + + To compile this driver as a module, choose M here: the + module will be called cytherm. + config USB_SPEEDTOUCH tristate "Alcatel Speedtouch USB support" depends on USB && ATM diff -Nru a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile --- a/drivers/usb/misc/Makefile Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/misc/Makefile Tue Apr 6 17:22:26 2004 @@ -4,8 +4,9 @@ # obj-$(CONFIG_USB_AUERSWALD) += auerswald.o -obj-$(CONFIG_USB_EMI62) += emi62.o +obj-$(CONFIG_USB_CYTHERM) += cytherm.o obj-$(CONFIG_USB_EMI26) += emi26.o +obj-$(CONFIG_USB_EMI62) += emi62.o obj-$(CONFIG_USB_LCD) += usblcd.o obj-$(CONFIG_USB_LED) += usbled.o obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o diff -Nru a/drivers/usb/misc/cytherm.c b/drivers/usb/misc/cytherm.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/usb/misc/cytherm.c Tue Apr 6 17:22:26 2004 @@ -0,0 +1,433 @@ +/* -*- linux-c -*- + * Cypress USB Thermometer driver + * + * Copyright (c) 2004 Erik Rigtorp + * + * This driver works with Elektor magazine USB Interface as published in + * issue #291. It should also work with the original starter kit/demo board + * from Cypress. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + + +#include +#include +#include +#include +#include +#include + +#define DRIVER_VERSION "v1.0" +#define DRIVER_AUTHOR "Erik Rigtorp" +#define DRIVER_DESC "Cypress USB Thermometer driver" + +#define USB_SKEL_VENDOR_ID 0x04b4 +#define USB_SKEL_PRODUCT_ID 0x0002 + +static struct usb_device_id id_table [] = { + { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, + { } +}; +MODULE_DEVICE_TABLE (usb, id_table); + +/* Structure to hold all of our device specific stuff */ +struct usb_cytherm { + struct usb_device *udev; /* save off the usb device pointer */ + struct usb_interface *interface; /* the interface for this device */ + int brightness; +}; + + +/* local function prototypes */ +static int cytherm_probe(struct usb_interface *interface, + const struct usb_device_id *id); +static void cytherm_disconnect(struct usb_interface *interface); +int vendor_command(struct usb_device *dev, unsigned char request, + unsigned char value, unsigned char index, + void *buf, int size); + + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver cytherm_driver = { + .owner = THIS_MODULE, + .name = "cytherm", + .probe = cytherm_probe, + .disconnect = cytherm_disconnect, + .id_table = id_table, +}; + +/* Vendor requests */ +/* They all operate on one byte at a time */ +#define PING 0x00 +#define READ_ROM 0x01 /* Reads form ROM, value = address */ +#define READ_RAM 0x02 /* Reads form RAM, value = address */ +#define WRITE_RAM 0x03 /* Write to RAM, value = address, index = data */ +#define READ_PORT 0x04 /* Reads from port, value = address */ +#define WRITE_PORT 0x05 /* Write to port, value = address, index = data */ + + +/* Send a vendor command to device */ +int vendor_command(struct usb_device *dev, unsigned char request, + unsigned char value, unsigned char index, + void *buf, int size) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + request, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, + value, + index, buf, size, + HZ * USB_CTRL_GET_TIMEOUT); +} + + + +#define BRIGHTNESS 0x2c /* RAM location for brightness value */ +#define BRIGHTNESS_SEM 0x2b /* RAM location for brightness semaphore */ + +static ssize_t show_brightness(struct device *dev, char *buf) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_cytherm *cytherm = usb_get_intfdata(intf); + + return sprintf(buf, "%i", cytherm->brightness); +} + +static ssize_t set_brightness(struct device *dev, const char *buf, + size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_cytherm *cytherm = usb_get_intfdata(intf); + + unsigned char *buffer; + int retval; + + buffer = kmalloc(8, GFP_KERNEL); + if (!buffer) { + dev_err(&cytherm->udev->dev, "out of memory\n"); + return 0; + } + + cytherm->brightness = simple_strtoul(buf, NULL, 10); + + if (cytherm->brightness > 0xFF) + cytherm->brightness = 0xFF; + else if (cytherm->brightness < 0) + cytherm->brightness = 0; + + /* Set brightness */ + retval = vendor_command(cytherm->udev, WRITE_RAM, BRIGHTNESS, + cytherm->brightness, buffer, 8); + if (retval) + dev_dbg(&led->udev->dev, "retval = %d\n", retval); + /* Inform µC that we have changed the brightness setting */ + retval = vendor_command(cytherm->udev, WRITE_RAM, BRIGHTNESS_SEM, + 0x01, buffer, 8); + if (retval) + dev_dbg(&led->udev->dev, "retval = %d\n", retval); + + kfree(buffer); + + return count; +} + +static DEVICE_ATTR(brightness, S_IRUGO | S_IWUSR | S_IWGRP, + show_brightness, set_brightness); + + +#define TEMP 0x33 /* RAM location for temperature */ +#define SIGN 0x34 /* RAM location for temperature sign */ + +static ssize_t show_temp(struct device *dev, char *buf) +{ + + struct usb_interface *intf = to_usb_interface(dev); + struct usb_cytherm *cytherm = usb_get_intfdata(intf); + + int retval; + unsigned char *buffer; + + int temp, sign; + + buffer = kmalloc(8, GFP_KERNEL); + if (!buffer) { + dev_err(&cytherm->udev->dev, "out of memory\n"); + return 0; + } + + /* read temperature */ + retval = vendor_command(cytherm->udev, READ_RAM, TEMP, 0, buffer, 8); + if (retval) + dev_dbg(&led->udev->dev, "retval = %d\n", retval); + temp = buffer[1]; + + /* read sign */ + retval = vendor_command(cytherm->udev, READ_RAM, SIGN, 0, buffer, 8); + if (retval) + dev_dbg(&led->udev->dev, "retval = %d\n", retval); + sign = buffer[1]; + + kfree(buffer); + + return sprintf(buf, "%c%i.%i", sign ? '-' : '+', temp >> 1, + 5*(temp - ((temp >> 1) << 1))); +} + + +static ssize_t set_temp(struct device *dev, const char *buf, size_t count) +{ + return count; +} + +static DEVICE_ATTR(temp, S_IRUGO, show_temp, set_temp); + + +#define BUTTON 0x7a + +static ssize_t show_button(struct device *dev, char *buf) +{ + + struct usb_interface *intf = to_usb_interface(dev); + struct usb_cytherm *cytherm = usb_get_intfdata(intf); + + int retval; + unsigned char *buffer; + + buffer = kmalloc(8, GFP_KERNEL); + if (!buffer) { + dev_err(&cytherm->udev->dev, "out of memory\n"); + return 0; + } + + /* check button */ + retval = vendor_command(cytherm->udev, READ_RAM, BUTTON, 0, buffer, 8); + if (retval) + dev_dbg(&led->udev->dev, "retval = %d\n", retval); + + retval = buffer[1]; + + kfree(buffer); + + if (retval) + return sprintf(buf, "1"); + else + return sprintf(buf, "0"); +} + + +static ssize_t set_button(struct device *dev, const char *buf, size_t count) +{ + return count; +} + +static DEVICE_ATTR(button, S_IRUGO, show_button, set_button); + + +static ssize_t show_port0(struct device *dev, char *buf) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_cytherm *cytherm = usb_get_intfdata(intf); + + int retval; + unsigned char *buffer; + + buffer = kmalloc(8, GFP_KERNEL); + if (!buffer) { + dev_err(&cytherm->udev->dev, "out of memory\n"); + return 0; + } + + retval = vendor_command(cytherm->udev, READ_PORT, 0, 0, buffer, 8); + if (retval) + dev_dbg(&led->udev->dev, "retval = %d\n", retval); + + retval = buffer[1]; + + kfree(buffer); + + return sprintf(buf, "%d", retval); +} + + +static ssize_t set_port0(struct device *dev, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_cytherm *cytherm = usb_get_intfdata(intf); + + unsigned char *buffer; + int retval; + int tmp; + + buffer = kmalloc(8, GFP_KERNEL); + if (!buffer) { + dev_err(&cytherm->udev->dev, "out of memory\n"); + return 0; + } + + tmp = simple_strtoul(buf, NULL, 10); + + if (tmp > 0xFF) + tmp = 0xFF; + else if (tmp < 0) + tmp = 0; + + retval = vendor_command(cytherm->udev, WRITE_PORT, 0, + tmp, buffer, 8); + if (retval) + dev_dbg(&led->udev->dev, "retval = %d\n", retval); + + kfree(buffer); + + return count; +} + +static DEVICE_ATTR(port0, S_IRUGO | S_IWUSR | S_IWGRP, show_port0, set_port0); + +static ssize_t show_port1(struct device *dev, char *buf) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_cytherm *cytherm = usb_get_intfdata(intf); + + int retval; + unsigned char *buffer; + + buffer = kmalloc(8, GFP_KERNEL); + if (!buffer) { + dev_err(&cytherm->udev->dev, "out of memory\n"); + return 0; + } + + retval = vendor_command(cytherm->udev, READ_PORT, 1, 0, buffer, 8); + if (retval) + dev_dbg(&led->udev->dev, "retval = %d\n", retval); + + retval = buffer[1]; + + kfree(buffer); + + return sprintf(buf, "%d", retval); +} + + +static ssize_t set_port1(struct device *dev, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_cytherm *cytherm = usb_get_intfdata(intf); + + unsigned char *buffer; + int retval; + int tmp; + + buffer = kmalloc(8, GFP_KERNEL); + if (!buffer) { + dev_err(&cytherm->udev->dev, "out of memory\n"); + return 0; + } + + tmp = simple_strtoul(buf, NULL, 10); + + if (tmp > 0xFF) + tmp = 0xFF; + else if (tmp < 0) + tmp = 0; + + retval = vendor_command(cytherm->udev, WRITE_PORT, 1, + tmp, buffer, 8); + if (retval) + dev_dbg(&led->udev->dev, "retval = %d\n", retval); + + kfree(buffer); + + return count; +} + +static DEVICE_ATTR(port1, S_IRUGO | S_IWUSR | S_IWGRP, show_port1, set_port1); + + + +static int cytherm_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(interface); + struct usb_cytherm *dev = NULL; + int retval = -ENOMEM; + + dev = kmalloc (sizeof(struct usb_cytherm), GFP_KERNEL); + if (dev == NULL) { + dev_err (&interface->dev, "Out of memory\n"); + goto error; + } + memset (dev, 0x00, sizeof (*dev)); + + dev->udev = usb_get_dev(udev); + + usb_set_intfdata (interface, dev); + + dev->brightness = 0xFF; + + device_create_file(&interface->dev, &dev_attr_brightness); + device_create_file(&interface->dev, &dev_attr_temp); + device_create_file(&interface->dev, &dev_attr_button); + device_create_file(&interface->dev, &dev_attr_port0); + device_create_file(&interface->dev, &dev_attr_port1); + + dev_info (&interface->dev, + "Cypress thermometer device now attached\n"); + return 0; + + error: + kfree(dev); + return retval; +} + +static void cytherm_disconnect(struct usb_interface *interface) +{ + struct usb_cytherm *dev; + + dev = usb_get_intfdata (interface); + usb_set_intfdata (interface, NULL); + + device_remove_file(&interface->dev, &dev_attr_brightness); + device_remove_file(&interface->dev, &dev_attr_temp); + device_remove_file(&interface->dev, &dev_attr_button); + device_remove_file(&interface->dev, &dev_attr_port0); + device_remove_file(&interface->dev, &dev_attr_port1); + + usb_put_dev(dev->udev); + + kfree(dev); + + dev_info(&interface->dev, "Cypress thermometer now disconnected\n"); +} + + +static int __init usb_cytherm_init(void) +{ + int result; + + result = usb_register(&cytherm_driver); + if (result) + { + err("usb_register failed. Error number %d", result); + return result; + } + + info(DRIVER_VERSION ":" DRIVER_DESC); + return 0; +} + +static void __exit usb_cytherm_exit(void) +{ + usb_deregister(&cytherm_driver); +} + + +module_init (usb_cytherm_init); +module_exit (usb_cytherm_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c --- a/drivers/usb/misc/usbtest.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/misc/usbtest.c Tue Apr 6 17:22:26 2004 @@ -1169,7 +1169,8 @@ /* set halt (protocol test only), verify it worked */ retval = usb_control_msg (urb->dev, usb_sndctrlpipe (urb->dev, 0), - USB_REQ_SET_FEATURE, USB_RECIP_ENDPOINT, 0, ep, + USB_REQ_SET_FEATURE, USB_RECIP_ENDPOINT, + USB_ENDPOINT_HALT, ep, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); if (retval < 0) { dbg ("ep %02x couldn't set halt, %d", ep, retval); diff -Nru a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig --- a/drivers/usb/net/Kconfig Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/net/Kconfig Tue Apr 6 17:22:26 2004 @@ -69,7 +69,7 @@ config USB_PEGASUS tristate "USB Pegasus/Pegasus-II based ethernet device support" - depends on USB && NET_ETHERNET + depends on USB && NET select MII ---help--- Say Y here if you know you have Pegasus or Pegasus-II based adapter. diff -Nru a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c --- a/drivers/usb/net/rtl8150.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/net/rtl8150.c Tue Apr 6 17:22:26 2004 @@ -20,7 +20,7 @@ #include /* Version Information */ -#define DRIVER_VERSION "v0.5.7 (2002/12/31)" +#define DRIVER_VERSION "v0.6.1 (2004/03/13)" #define DRIVER_AUTHOR "Petko Manolov " #define DRIVER_DESC "rtl8150 based usb-ethernet driver" @@ -43,6 +43,8 @@ #define ANAR 0x0144 #define ANLP 0x0146 #define AER 0x0148 +#define CSCR 0x014C /* This one has the link status */ +#define CSCR_LINK_STATUS (1 << 3) #define IDR_EEPROM 0x1202 @@ -58,6 +60,60 @@ #define RTL8150_REQ_GET_REGS 0x05 #define RTL8150_REQ_SET_REGS 0x05 + +/* Transmit status register errors */ +#define TSR_ECOL (1<<5) +#define TSR_LCOL (1<<4) +#define TSR_LOSS_CRS (1<<3) +#define TSR_JBR (1<<2) +#define TSR_ERRORS (TSR_ECOL | TSR_LCOL | TSR_LOSS_CRS | TSR_JBR) +/* Receive status register errors */ +#define RSR_CRC (1<<2) +#define RSR_FAE (1<<1) +#define RSR_ERRORS (RSR_CRC | RSR_FAE) + +/* Media status register definitions */ +#define MSR_DUPLEX (1<<4) +#define MSR_SPEED (1<<3) +#define MSR_LINK (1<<2) + +/* Interrupt pipe data */ +#define INT_TSR 0x00 +#define INT_RSR 0x01 +#define INT_MSR 0x02 +#define INT_WAKSR 0x03 +#define INT_TXOK_CNT 0x04 +#define INT_RXLOST_CNT 0x05 +#define INT_CRERR_CNT 0x06 +#define INT_COL_CNT 0x07 + +/* Transmit status register errors */ +#define TSR_ECOL (1<<5) +#define TSR_LCOL (1<<4) +#define TSR_LOSS_CRS (1<<3) +#define TSR_JBR (1<<2) +#define TSR_ERRORS (TSR_ECOL | TSR_LCOL | TSR_LOSS_CRS | TSR_JBR) +/* Receive status register errors */ +#define RSR_CRC (1<<2) +#define RSR_FAE (1<<1) +#define RSR_ERRORS (RSR_CRC | RSR_FAE) + +/* Media status register definitions */ +#define MSR_DUPLEX (1<<4) +#define MSR_SPEED (1<<3) +#define MSR_LINK (1<<2) + +/* Interrupt pipe data */ +#define INT_TSR 0x00 +#define INT_RSR 0x01 +#define INT_MSR 0x02 +#define INT_WAKSR 0x03 +#define INT_TXOK_CNT 0x04 +#define INT_RXLOST_CNT 0x05 +#define INT_CRERR_CNT 0x06 +#define INT_COL_CNT 0x07 + + #define RTL8150_MTU 1540 #define RTL8150_TX_TIMEOUT (HZ) #define RX_SKB_POOL_SIZE 4 @@ -71,9 +127,13 @@ /* Define these values to match your device */ #define VENDOR_ID_REALTEK 0x0bda #define VENDOR_ID_MELCO 0x0411 +#define VENDOR_ID_MICRONET 0x3980 +#define VENDOR_ID_LONGSHINE 0x07b8 #define PRODUCT_ID_RTL8150 0x8150 #define PRODUCT_ID_LUAKTX 0x0012 +#define PRODUCT_ID_LCS8138TX 0x401a +#define PRODUCT_ID_SP128AR 0x0003 #undef EEPROM_WRITE @@ -81,6 +141,8 @@ static struct usb_device_id rtl8150_table[] = { {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150)}, {USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)}, + {USB_DEVICE(VENDOR_ID_MICRONET, PRODUCT_ID_SP128AR)}, + {USB_DEVICE(VENDOR_ID_LONGSHINE, PRODUCT_ID_LCS8138TX)}, {} }; @@ -368,6 +430,9 @@ if (!dev->rx_skb) goto resched; + /* protect against short packets (tell me why we got some?!?) */ + if (urb->actual_length < 4) + goto goon; res = urb->actual_length; rx_stat = le16_to_cpu(*(short *)(urb->transfer_buffer + res - 4)); @@ -454,6 +519,7 @@ void intr_callback(struct urb *urb, struct pt_regs *regs) { rtl8150_t *dev; + __u8 *d; int status; dev = urb->context; @@ -472,7 +538,28 @@ goto resubmit; } - /* FIXME if this doesn't do anything, don't submit the urb! */ + d = urb->transfer_buffer; + if (d[0] & TSR_ERRORS) { + dev->stats.tx_errors++; + if (d[INT_TSR] & (TSR_ECOL | TSR_JBR)) + dev->stats.tx_aborted_errors++; + if (d[INT_TSR] & TSR_LCOL) + dev->stats.tx_window_errors++; + if (d[INT_TSR] & TSR_LOSS_CRS) + dev->stats.tx_carrier_errors++; + } + /* Report link status changes to the network stack */ + if ((d[INT_MSR] & MSR_LINK) == 0) { + if (netif_carrier_ok(dev->netdev)) { + netif_carrier_off(dev->netdev); + dbg("%s: LINK LOST\n", __func__); + } + } else { + if (!netif_carrier_ok(dev->netdev)) { + netif_carrier_on(dev->netdev); + dbg("%s: LINK CAME BACK\n", __func__); + } + } resubmit: status = usb_submit_urb (urb, SLAB_ATOMIC); @@ -482,6 +569,7 @@ dev->udev->devpath, status); } + /* ** ** network related part of the code @@ -538,7 +626,7 @@ warn("%s - device reset failed", __FUNCTION__); } /* RCR bit7=1 attach Rx info at the end; =0 HW CRC (which is broken) */ - rcr = 0x9e; /* bit7=1 attach Rx info at the end */ + rcr = 0x9e; dev->rx_creg = cpu_to_le16(rcr); tcr = 0xd8; cr = 0x0c; @@ -626,6 +714,19 @@ return 0; } + +static void set_carrier(struct net_device *netdev) +{ + rtl8150_t *dev = netdev->priv; + short tmp; + + get_registers(dev, CSCR, 2, &tmp); + if (tmp & CSCR_LINK_STATUS) + netif_carrier_on(netdev); + else + netif_carrier_off(netdev); +} + static int rtl8150_open(struct net_device *netdev) { rtl8150_t *dev; @@ -653,6 +754,7 @@ warn("%s: intr_urb submit failed: %d", __FUNCTION__, res); netif_start_queue(netdev); enable_net_traffic(dev); + set_carrier(netdev); return res; } @@ -674,7 +776,7 @@ return res; } -static int rtl8150_ethtool_ioctl(struct net_device *netdev, void __user *uaddr) +static int rtl8150_ethtool_ioctl(struct net_device *netdev, void *uaddr) { rtl8150_t *dev; int cmd; @@ -759,7 +861,7 @@ switch (cmd) { case SIOCETHTOOL: - res = rtl8150_ethtool_ioctl(netdev, (void __user *)rq->ifr_data); + res = rtl8150_ethtool_ioctl(netdev, rq->ifr_data); break; case SIOCDEVPRIVATE: data[0] = dev->phy; @@ -774,6 +876,7 @@ default: res = -EOPNOTSUPP; } + return res; } @@ -796,7 +899,6 @@ kfree(dev); return -ENOMEM; } - netdev = alloc_etherdev(0); if (!netdev) { kfree(dev->intr_buff); @@ -837,7 +939,6 @@ info("%s: rtl8150 is detected", netdev->name); usb_set_intfdata(intf, dev); - SET_NETDEV_DEV(netdev, &intf->dev); if (register_netdev(netdev) != 0) { err("couldn't register the device"); diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c --- a/drivers/usb/net/usbnet.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/net/usbnet.c Tue Apr 6 17:22:26 2004 @@ -3104,7 +3104,7 @@ } if (status < 0) - goto out2; + goto out1; dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1); @@ -3127,7 +3127,6 @@ out3: if (info->unbind) info->unbind (dev, udev); -out2: free_netdev(net); out1: kfree(dev); diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c --- a/drivers/usb/serial/ftdi_sio.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/serial/ftdi_sio.c Tue Apr 6 17:22:26 2004 @@ -435,7 +435,28 @@ { USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E808_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E809_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80A_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80B_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80C_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80D_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80E_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80F_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E888_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E889_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88A_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88B_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88C_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88D_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_1_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_2_PID, 0x400, 0xffff) }, { } /* Terminating entry */ }; @@ -532,6 +553,11 @@ { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) }, { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) }, + { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_1_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_2_PID, 0x400, 0xffff) }, { } /* Terminating entry */ }; @@ -789,8 +815,14 @@ static int set_rts(struct usb_serial_port *port, int high_or_low) { struct ftdi_private *priv = usb_get_serial_port_data(port); - char buf[1]; + char *buf; unsigned ftdi_high_or_low; + int rv; + + buf = kmalloc(1, GFP_NOIO); + if (!buf) + return -ENOMEM; + if (high_or_low) { ftdi_high_or_low = FTDI_SIO_SET_RTS_HIGH; priv->last_dtr_rts |= TIOCM_RTS; @@ -798,20 +830,29 @@ ftdi_high_or_low = FTDI_SIO_SET_RTS_LOW; priv->last_dtr_rts &= ~TIOCM_RTS; } - return(usb_control_msg(port->serial->dev, + rv = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, ftdi_high_or_low, 0, - buf, 0, WDR_TIMEOUT)); + buf, 0, WDR_TIMEOUT); + + kfree(buf); + return rv; } static int set_dtr(struct usb_serial_port *port, int high_or_low) { struct ftdi_private *priv = usb_get_serial_port_data(port); - char buf[1]; + char *buf; unsigned ftdi_high_or_low; + int rv; + + buf = kmalloc(1, GFP_NOIO); + if (!buf) + return -ENOMEM; + if (high_or_low) { ftdi_high_or_low = FTDI_SIO_SET_DTR_HIGH; priv->last_dtr_rts |= TIOCM_DTR; @@ -819,12 +860,15 @@ ftdi_high_or_low = FTDI_SIO_SET_DTR_LOW; priv->last_dtr_rts &= ~TIOCM_DTR; } - return(usb_control_msg(port->serial->dev, + rv = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, ftdi_high_or_low, 0, - buf, 0, WDR_TIMEOUT)); + buf, 0, WDR_TIMEOUT); + + kfree(buf); + return rv; } @@ -833,21 +877,29 @@ static int change_speed(struct usb_serial_port *port) { - char buf[1]; + char *buf; __u16 urb_value; __u16 urb_index; __u32 urb_index_value; + int rv; + + buf = kmalloc(1, GFP_NOIO); + if (!buf) + return -ENOMEM; urb_index_value = get_ftdi_divisor(port); urb_value = (__u16)urb_index_value; urb_index = (__u16)(urb_index_value >> 16); - return (usb_control_msg(port->serial->dev, + rv = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_BAUDRATE_REQUEST, FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, urb_value, urb_index, - buf, 0, 100) < 0); + buf, 0, 100); + + kfree(buf); + return rv; } @@ -1309,15 +1361,16 @@ /* drop RTS */ if (set_rts(port, LOW) < 0) { err("Error from RTS LOW urb"); - } - /* shutdown our bulk read */ - if (port->read_urb) { - usb_unlink_urb (port->read_urb); } - /* unlink the running write urbs */ - + } /* Note change no line if hupcl is off */ + + /* shutdown our bulk read */ + if (port->read_urb) { + if (usb_unlink_urb (port->read_urb) < 0) { + err("Error unlinking read urb"); + } + } - } /* Note change no line is hupcl is off */ } /* if (serial->dev) */ diff -Nru a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h --- a/drivers/usb/serial/ftdi_sio.h Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/serial/ftdi_sio.h Tue Apr 6 17:22:26 2004 @@ -160,7 +160,36 @@ #define PROTEGO_SPECIAL_1 0xFC70 /* special/unknown device */ #define PROTEGO_R2X0 0xFC71 /* R200-USB TRNG unit (R210, R220, and R230) */ #define PROTEGO_SPECIAL_3 0xFC72 /* special/unknown device */ -#define PROTEGO_SPECIAL_4 0xFC73 /* special/unknown device */ +#define PROTEGO_SPECIAL_4 0xFC73 /* special/unknown device */ + +/* + * Gude Analog- und Digitalsysteme GmbH + */ +#define FTDI_GUDEADS_E808_PID 0xE808 +#define FTDI_GUDEADS_E809_PID 0xE809 +#define FTDI_GUDEADS_E80A_PID 0xE80A +#define FTDI_GUDEADS_E80B_PID 0xE80B +#define FTDI_GUDEADS_E80C_PID 0xE80C +#define FTDI_GUDEADS_E80D_PID 0xE80D +#define FTDI_GUDEADS_E80E_PID 0xE80E +#define FTDI_GUDEADS_E80F_PID 0xE80F +#define FTDI_GUDEADS_E888_PID 0xE888 /* Expert ISDN Control USB */ +#define FTDI_GUDEADS_E889_PID 0xE889 /* USB RS-232 OptoBridge */ +#define FTDI_GUDEADS_E88A_PID 0xE88A +#define FTDI_GUDEADS_E88B_PID 0xE88B +#define FTDI_GUDEADS_E88C_PID 0xE88C +#define FTDI_GUDEADS_E88D_PID 0xE88D +#define FTDI_GUDEADS_E88E_PID 0xE88E +#define FTDI_GUDEADS_E88F_PID 0xE88F + +/* + * Linx Technologies product ids + */ +#define LINX_SDMUSBQSS_PID 0xF448 /* Linx SDM-USB-QS-S */ +#define LINX_MASTERDEVEL2_PID 0xF449 /* Linx Master Development 2.0 */ +#define LINX_FUTURE_0_PID 0xF44A /* Linx future device */ +#define LINX_FUTURE_1_PID 0xF44B /* Linx future device */ +#define LINX_FUTURE_2_PID 0xF44C /* Linx future device */ /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */ diff -Nru a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c --- a/drivers/usb/serial/io_ti.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/serial/io_ti.c Tue Apr 6 17:22:26 2004 @@ -274,7 +274,7 @@ /** * TIReadDownloadMemory - Read edgeport memory from TI chip * @dev: usb device pointer - * @address: Device CPU address at which to read + * @start_address: Device CPU address at which to read * @length: Length of above data * @address_type: Can read both XDATA and I2C * @buffer: pointer to input data buffer diff -Nru a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c --- a/drivers/usb/serial/kobil_sct.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/serial/kobil_sct.c Tue Apr 6 17:22:26 2004 @@ -262,7 +262,7 @@ // allocate memory for transfer buffer transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL); if (! transfer_buffer) { - return -1; + return -ENOMEM; } else { memset(transfer_buffer, 0, transfer_buffer_length); } @@ -274,7 +274,7 @@ if (!port->write_urb) { dbg("%s - port %d usb_alloc_urb failed", __FUNCTION__, port->number); kfree(transfer_buffer); - return -1; + return -ENOMEM; } } @@ -282,7 +282,9 @@ port->write_urb->transfer_buffer = (unsigned char *) kmalloc(write_urb_transfer_buffer_length, GFP_KERNEL); if (! port->write_urb->transfer_buffer) { kfree(transfer_buffer); - return -1; + usb_free_urb(port->write_urb); + port->write_urb = NULL; + return -ENOMEM; } // get hardware version diff -Nru a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c --- a/drivers/usb/serial/omninet.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/serial/omninet.c Tue Apr 6 17:22:26 2004 @@ -61,11 +61,12 @@ * Version Information */ #define DRIVER_VERSION "v1.1" -#define DRIVER_AUTHOR "Anonymous" +#define DRIVER_AUTHOR "Alessandro Zummo" #define DRIVER_DESC "USB ZyXEL omni.net LCD PLUS Driver" #define ZYXEL_VENDOR_ID 0x0586 #define ZYXEL_OMNINET_ID 0x1000 +#define BT_IGNITIONPRO_ID 0x2000 /* This one seems to be a re-branded ZyXEL device */ /* function prototypes */ static int omninet_open (struct usb_serial_port *port, struct file *filp); @@ -78,6 +79,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) }, + { USB_DEVICE(ZYXEL_VENDOR_ID, BT_IGNITIONPRO_ID) }, { } /* Terminating entry */ }; diff -Nru a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c --- a/drivers/usb/serial/whiteheat.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/serial/whiteheat.c Tue Apr 6 17:22:26 2004 @@ -91,6 +91,10 @@ #include "whiteheat_fw.h" /* firmware for the ConnectTech WhiteHEAT device */ #include "whiteheat.h" /* WhiteHEAT specific commands */ +#ifndef CMSPAR +#define CMSPAR 0 +#endif + /* * Version Information */ @@ -1128,7 +1132,6 @@ struct usb_serial_port *command_port; struct whiteheat_command_private *command_info; struct whiteheat_private *info; - int timeout; __u8 *transfer_buffer; int retval = 0; unsigned long flags; @@ -1153,10 +1156,8 @@ } /* wait for the command to complete */ - timeout = COMMAND_TIMEOUT; - while (timeout && (command_info->command_finished == FALSE)) { - timeout = interruptible_sleep_on_timeout (&command_info->wait_command, timeout); - } + wait_event_interruptible_timeout(command_info->wait_command, + (command_info->command_finished != FALSE), COMMAND_TIMEOUT); spin_lock_irqsave(&command_info->lock, flags); diff -Nru a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c --- a/drivers/usb/storage/datafab.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/storage/datafab.c Tue Apr 6 17:22:26 2004 @@ -539,8 +539,8 @@ info->sectors, info->ssize); // build the reply - // - ((u32 *) ptr)[0] = cpu_to_be32(info->sectors); + // we need the last sector, not the number of sectors + ((u32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); ((u32 *) ptr)[1] = cpu_to_be32(info->ssize); usb_stor_set_xfer_buf(ptr, 8, srb); diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c --- a/drivers/usb/storage/transport.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/storage/transport.c Tue Apr 6 17:22:26 2004 @@ -256,8 +256,9 @@ endp |= USB_DIR_IN; result = usb_stor_control_msg(us, us->send_ctrl_pipe, - USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, - endp, NULL, 0, 3*HZ); + USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, + USB_ENDPOINT_HALT, endp, + NULL, 0, 3*HZ); /* reset the toggles and endpoint flags */ usb_endpoint_running(us->pusb_dev, usb_pipeendpoint(pipe), diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h --- a/drivers/usb/storage/unusual_devs.h Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/storage/unusual_devs.h Tue Apr 6 17:22:26 2004 @@ -160,7 +160,7 @@ UNUSUAL_DEV( 0x04da, 0x0901, 0x0100, 0x0200, "Panasonic", "LS-120 Camera", - US_SC_UFI, US_PR_CBI, NULL, 0), + US_SC_UFI, US_PR_DEVICE, NULL, 0), /* From Yukihiro Nakai, via zaitcev@yahoo.com. * This is needed for CB instead of CBI */ @@ -384,7 +384,7 @@ UNUSUAL_DEV( 0x05dc, 0xb002, 0x0000, 0x0113, "Lexar", "USB CF Reader", - US_SC_SCSI, US_PR_BULK, NULL, + US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), /* Reported by Carlos Villegas @@ -392,15 +392,15 @@ * That is the only reason this entry is needed. */ UNUSUAL_DEV( 0x05e3, 0x0700, 0x0000, 0xffff, - "SIIG", - "CompactFlash Card Reader", + "Genesys Logic", + "USB to IDE Card Reader", US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), /* Submitted Alexander Oltu */ UNUSUAL_DEV( 0x05e3, 0x0701, 0x0000, 0xffff, - "", - "USB TO IDE", + "Genesys Logic", + "USB to IDE Optical", US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_MODE_XLATE ), @@ -411,16 +411,9 @@ * * ST818 slim drives (rev 0.02) don't need special care. */ -UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0x0001, - "EagleTec", - "External Hard Disk", - US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_FIX_INQUIRY ), - -/* Reported by Henning Schild */ -UNUSUAL_DEV( 0x05e3, 0x0702, 0x0113, 0x0113, - "EagleTec", - "External Hard Disk", +UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0xffff, + "Genesys Logic", + "USB to IDE Disk", US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), @@ -725,6 +718,21 @@ "USB Cable 205", US_SC_ISD200, US_PR_BULK, isd200_Initialization, 0 ), +#endif + +#ifdef CONFIG_USB_STORAGE_DATAFAB +UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff, + "Acomdata", + "CF", + US_SC_SCSI, US_PR_DATAFAB, NULL, + US_FL_SINGLE_LUN ), +#endif +#ifdef CONFIG_USB_STORAGE_SDDR55 +UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff, + "Acomdata", + "SM", + US_SC_SCSI, US_PR_SDDR55, NULL, + US_FL_SINGLE_LUN ), #endif /* Submitted by Joris Struyve */ diff -Nru a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c --- a/drivers/usb/usb-skeleton.c Tue Apr 6 17:22:26 2004 +++ b/drivers/usb/usb-skeleton.c Tue Apr 6 17:22:26 2004 @@ -516,7 +516,7 @@ dev = kmalloc (sizeof(struct usb_skel), GFP_KERNEL); if (dev == NULL) { err ("Out of memory"); - goto error; + return -ENOMEM; } memset (dev, 0x00, sizeof (*dev)); diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h --- a/include/linux/pci_ids.h Tue Apr 6 17:22:26 2004 +++ b/include/linux/pci_ids.h Tue Apr 6 17:22:26 2004 @@ -1871,6 +1871,9 @@ #define PCI_DEVICE_ID_ALTIMA_AC9100 0x03ea #define PCI_DEVICE_ID_ALTIMA_AC1003 0x03eb +#define PCI_VENDOR_ID_ARC 0x192E +#define PCI_DEVICE_ID_ARC_EHCI 0x0101 + #define PCI_VENDOR_ID_SYMPHONY 0x1c1c #define PCI_DEVICE_ID_SYMPHONY_101 0x0001 diff -Nru a/include/linux/usb.h b/include/linux/usb.h --- a/include/linux/usb.h Tue Apr 6 17:22:26 2004 +++ b/include/linux/usb.h Tue Apr 6 17:22:26 2004 @@ -31,6 +31,7 @@ } struct usb_device; +struct usb_driver; /*-------------------------------------------------------------------------*/ @@ -86,8 +87,6 @@ * number from the USB core by calling usb_register_dev(). * @dev: driver model's view of this device * @class_dev: driver model's class view of this device. - * @released: wait for the interface to be released when changing - * configurations. * * USB device drivers attach to interfaces on a physical device. Each * interface encapsulates a single high level function, such as feeding @@ -123,11 +122,9 @@ * active alternate setting */ unsigned num_altsetting; /* number of alternate settings */ - struct usb_driver *driver; /* driver */ int minor; /* minor number this interface is bound to */ struct device dev; /* interface specific device info */ struct class_device *class_dev; - struct completion *released; /* wait for release */ }; #define to_usb_interface(d) container_of(d, struct usb_interface, dev) #define interface_to_usbdev(intf) \ @@ -143,6 +140,9 @@ dev_set_drvdata(&intf->dev, data); } +struct usb_interface *usb_get_intf(struct usb_interface *intf); +void usb_put_intf(struct usb_interface *intf); + /* this maximum is arbitrary */ #define USB_MAXINTERFACES 32 @@ -318,7 +318,21 @@ /* used these for multi-interface device registration */ extern int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv); -extern int usb_interface_claimed(struct usb_interface *iface); + +/** + * usb_interface_claimed - returns true iff an interface is claimed + * @iface: the interface being checked + * + * Returns true (nonzero) iff the interface is claimed, else false (zero). + * Callers must own the driver model's usb bus readlock. So driver + * probe() entries don't need extra locking, but other call contexts + * may need to explicitly claim that lock. + * + */ +static int inline usb_interface_claimed(struct usb_interface *iface) { + return (iface->dev.driver != NULL); +} + extern void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface); const struct usb_device_id *usb_match_id(struct usb_interface *interface, @@ -904,7 +918,6 @@ /* wrappers that also update important state inside usbcore */ extern int usb_clear_halt(struct usb_device *dev, int pipe); extern int usb_reset_configuration(struct usb_device *dev); -extern int usb_set_configuration(struct usb_device *dev, int configuration); extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate); /* diff -Nru a/include/linux/usb_ch9.h b/include/linux/usb_ch9.h --- a/include/linux/usb_ch9.h Tue Apr 6 17:22:26 2004 +++ b/include/linux/usb_ch9.h Tue Apr 6 17:22:26 2004 @@ -68,6 +68,20 @@ #define USB_REQ_SET_INTERFACE 0x0B #define USB_REQ_SYNCH_FRAME 0x0C +/* + * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and + * are read as a bit array returned by USB_REQ_GET_STATUS. (So there + * are at most sixteen features of each type.) + */ +#define USB_DEVICE_SELF_POWERED 0 /* (read only) */ +#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */ +#define USB_DEVICE_TEST_MODE 2 /* (high speed only) */ +#define USB_DEVICE_B_HNP_ENABLE 3 /* dev may initiate HNP */ +#define USB_DEVICE_A_HNP_SUPPORT 4 /* RH port supports HNP */ +#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* other RH port does */ + +#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */ + /** * struct usb_ctrlrequest - SETUP data for a USB device control request diff -Nru a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h --- a/include/linux/usb_gadget.h Tue Apr 6 17:22:26 2004 +++ b/include/linux/usb_gadget.h Tue Apr 6 17:22:26 2004 @@ -731,6 +731,15 @@ int usb_gadget_config_buf(const struct usb_config_descriptor *config, void *buf, unsigned buflen, const struct usb_descriptor_header **desc); +/*-------------------------------------------------------------------------*/ + +/* utility wrapping a simple endpoint selection policy */ + +extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *, + struct usb_endpoint_descriptor *) __init; + +extern void usb_ep_autoconfig_reset (struct usb_gadget *) __init; + #endif /* __KERNEL__ */ #endif /* __LINUX_USB_GADGET_H */