bk://kernel.bkbits.net/gregkh/linux/usb-2.6 greg@kroah.com|ChangeSet|20040812220306|48639 greg # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/08/15 01:35:04-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # include/linux/fs.h # 2004/08/15 01:35:01-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/08/12 15:03:06-07:00 greg@kroah.com # USB: hook the ub driver up to the sysfs tree so that tools like udev work better. # # Signed-off-by: Greg Kroah-Hartman # # drivers/block/ub.c # 2004/08/12 15:02:32-07:00 greg@kroah.com +1 -0 # USB: hook the ub driver up to the sysfs tree so that tools like udev work better. # # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2004/08/09 13:55:04-07:00 baldrick@free.fr # [PATCH] USB: usbfs: check the buffer size in proc_bulk # # Use the same check as proc_submiturb. # # Signed-off-by: Duncan Sands # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/core/devio.c # 2004/08/06 01:35:33-07:00 baldrick@free.fr +6 -2 # USB: usbfs: check the buffer size in proc_bulk # # ChangeSet # 2004/08/09 13:53:38-07:00 luca.risolia@studio.unibo.it # [PATCH] USB: SN9C10[12] driver update # # Changes: # - Correct calculation of R,G,B origin # - Gain fixes for PAS106B and PAS202BCB image sensors # # Signed-off-by: Luca Risolia # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/media/sn9c102_pas202bcb.c # 2004/08/07 22:50:38-07:00 luca.risolia@studio.unibo.it +1 -1 # USB: SN9C10[12] driver update # # drivers/usb/media/sn9c102_pas106b.c # 2004/08/07 22:50:30-07:00 luca.risolia@studio.unibo.it +1 -1 # USB: SN9C10[12] driver update # # drivers/usb/media/sn9c102_core.c # 2004/08/07 22:50:14-07:00 luca.risolia@studio.unibo.it +4 -2 # USB: SN9C10[12] driver update # # drivers/usb/media/sn9c102.h # 2004/08/07 22:50:22-07:00 luca.risolia@studio.unibo.it +2 -2 # USB: SN9C10[12] driver update # # ChangeSet # 2004/08/09 10:18:00-07:00 marcel@holtmann.org # [PATCH] USB: fix ub driver # # The problem is that the ub driver don't contain the terminating braces # for the device id entries. You need to apply the following patch to get # everything back to normal. # # From: Marcel Holtmann # Signed-off-by: Greg Kroah-Hartman # # drivers/block/ub.c # 2004/08/09 09:24:15-07:00 marcel@holtmann.org +1 -0 # USB: fix ub driver # # ChangeSet # 2004/08/08 14:55:28-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # drivers/usb/misc/tiglusb.c # 2004/08/08 14:55:24-07:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/misc/legousbtower.c # 2004/08/08 14:55:24-07:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/misc/auerswald.c # 2004/08/08 14:55:24-07:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/media/dabusb.c # 2004/08/08 14:55:24-07:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/class/usb-midi.c # 2004/08/08 14:55:24-07:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/class/audio.c # 2004/08/08 14:55:24-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/08/08 02:33:24-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # include/linux/fs.h # 2004/08/08 02:33:20-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/08/07 19:17:31-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # include/linux/fs.h # 2004/08/07 19:17:28-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/08/07 14:49:01-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # include/linux/fs.h # 2004/08/07 14:48:57-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/08/06 16:01:52-07:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6 # into bix.(none):/usr/src/bk-usb # # drivers/block/Kconfig # 2004/08/06 16:01:49-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/08/06 16:01:00-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # include/linux/fs.h # 2004/08/06 16:00:56-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/08/06 14:55:40-07:00 greg@kroah.com # USB: fix up gadget driver usage of MODULE_PARM # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/gadget/serial.c # 2004/08/06 14:54:45-07:00 greg@kroah.com +5 -5 # USB: fix up gadget driver usage of MODULE_PARM # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/gadget/pxa2xx_udc.c # 2004/08/06 14:54:45-07:00 greg@kroah.com +2 -2 # USB: fix up gadget driver usage of MODULE_PARM # # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2004/08/06 14:10:38-07:00 greg@kroah.com # USB: fix up ub.c due to usb_endpoint_running() going away. # # Signed-off-by: Greg Kroah-Hartman # # drivers/block/ub.c # 2004/08/06 14:10:17-07:00 greg@kroah.com +3 -8 # USB: fix up ub.c due to usb_endpoint_running() going away. # # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2004/08/06 14:05:26-07:00 zaitcev@redhat.com # [PATCH] USB: add ub driver # # From: Pete Zaitcev # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/storage/usb.c # 2004/08/06 00:59:29-07:00 zaitcev@redhat.com +4 -0 # USB: add ub driver # # drivers/usb/storage/unusual_devs.h # 2004/08/06 00:59:29-07:00 zaitcev@redhat.com +2 -0 # USB: add ub driver # # drivers/block/Makefile # 2004/08/06 01:00:45-07:00 zaitcev@redhat.com +1 -0 # USB: add ub driver # # drivers/block/Kconfig # 2004/08/06 00:59:29-07:00 zaitcev@redhat.com +9 -0 # USB: add ub driver # # drivers/block/ub.c # 2004/08/06 00:59:29-07:00 zaitcev@redhat.com +2040 -0 # USB: add ub driver # # drivers/block/ub.c # 2004/08/06 00:59:29-07:00 zaitcev@redhat.com +0 -0 # BitKeeper file /home/greg/linux/BK/usb-2.6/drivers/block/ub.c # # ChangeSet # 2004/08/06 13:55:57-07:00 baldrick@free.fr # [PATCH] USB: usbfs: drop the device semaphore in proc_bulk and proc_control # # usb_control_msg and usb_bulk_msg may sleep for a long time, so drop the per device # semaphore before calling them. This fixes OSDL bug 3108. Dropping the semaphore # is racy, but (1) the race is fairly harmless, (2) it can be occur elsewhere as an inevitable # consequence of the current usbfs api, this just makes it fractionally more likely. # # Signed-off-by: Duncan Sands # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/core/devio.c # 2004/08/06 00:58:22-07:00 baldrick@free.fr +8 -0 # USB: usbfs: drop the device semaphore in proc_bulk and proc_control # # ChangeSet # 2004/08/05 20:29:41-07:00 david-b@pacbell.net # [PATCH] USB: add # # Hardware implementing USB-OTG needs to use an OTG controller and/or # transceiver driver to switch the Mini-AB connector between the host # and peripheral side controller drivers (and the USB device role # supported by that driver). # # This patch adds a simple "otg_transceiver" interface that can abstract # implementation details for that port, as needed for some upcoming patches: # # - Neither host nor peripheral controller drivers need to know about # how the OTG controller is implemented. Example: is the transceiver # internal? If not, which external chip? # # - The OTG controller doesn't need to know if the Host Controller # is OHCI, EHCI, or something custom ... all it knows is that the # HCD looks like a "usb_bus". # # - In the same way, the peripheral controller is just a "usb_gadget". # # One implementation of this will be posted soon; the interface is by # no means cast in stone, other implementations may need to morph this # interface a bit. # # Signed-off-by: David Brownell # Signed-off-by: Greg Kroah-Hartman # # include/linux/usb_otg.h # 2004/07/13 17:08:45-07:00 david-b@pacbell.net +116 -0 # USB: add # # include/linux/usb_otg.h # 2004/07/13 17:08:45-07:00 david-b@pacbell.net +0 -0 # BitKeeper file /home/greg/linux/BK/usb-2.6/include/linux/usb_otg.h # # ChangeSet # 2004/08/05 20:29:03-07:00 david-b@pacbell.net # [PATCH] USB: autoconf for gadget serial # # Here is a patch to add endpoint autoconfiguration to the gadget # serial driver. I pretty much copied gadget zero autoconfig # for this. Tested with a NetChip 2280 development board. # # Signed-off-by: Al Borchers # Signed-off-by: David Brownell # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/gadget/serial.c # 2004/08/03 04:11:41-07:00 david-b@pacbell.net +96 -184 # USB: autoconf for gadget serial # # drivers/usb/gadget/Makefile # 2004/08/03 03:37:09-07:00 david-b@pacbell.net +1 -1 # USB: autoconf for gadget serial # # ChangeSet # 2004/08/05 20:16:41-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # include/linux/fs.h # 2004/08/05 20:16:38-07:00 akpm@bix.(none) +0 -0 # Auto merged # # MAINTAINERS # 2004/08/05 20:16:38-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/08/05 15:00:47-07:00 juergen@jstuber.net # [PATCH] USB: LEGO USB Tower, move reset from probe to open # # the following patch reduces the amount of garbage data sent by # the device after open (must be the heat here causing trouble). # # # Move the vendor-specific device reset from probe to open to # reduce spurious data. # # Signed-off-by: Juergen Stuber # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/misc/legousbtower.c # 2004/08/03 16:38:47-07:00 juergen@jstuber.net +21 -18 # USB: LEGO USB Tower, move reset from probe to open # # ChangeSet # 2004/08/05 15:00:22-07:00 baldrick@free.fr # [PATCH] USB: fix deadlock in hub_reset # # usb_reset_device takes hdev->serialize. However, hub_reset is # (only) called by hub_events, which already holds the lock. Thanks # to Tyler Nielsen for the bug report and helpful backtrace. # # Signed-off-by: Duncan Sands # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/core/hub.c # 2004/08/05 14:41:44-07:00 baldrick@free.fr +2 -2 # USB: fix deadlock in hub_reset # # ChangeSet # 2004/08/05 14:59:57-07:00 david-b@pacbell.net # [PATCH] USB: net2280 minor fixes # # Collection of small net2280 driver fixes: # # - Byteswap bug for big-endian PIO paths # From: Jon Neal # - Highspeed electrical conformance fix # From: Alex Sanks # - Support new usb_gadget_{connect,disconnect}() API calls so # that gadget drivers have softconnect control over the D+ pullup # From: Alex Sanks # # And minor cleanups by me. # # Signed-off-by: David Brownell # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/gadget/net2280.h # 2004/08/03 06:48:10-07:00 david-b@pacbell.net +1 -0 # USB: net2280 minor fixes # # drivers/usb/gadget/net2280.c # 2004/08/03 06:48:10-07:00 david-b@pacbell.net +31 -11 # USB: net2280 minor fixes # # ChangeSet # 2004/08/05 14:59:35-07:00 david-b@pacbell.net # [PATCH] USB: ehci and buggy BIOS handoff # # Be more forgiving of buggy BIOS code, which never hands the # EHCI controller to Linux. # # Signed-off-by: David Brownell # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/host/ehci-hcd.c # 2004/08/03 06:48:10-07:00 david-b@pacbell.net +5 -2 # USB: ehci and buggy BIOS handoff # # ChangeSet # 2004/08/05 14:59:08-07:00 stern@rowland.harvard.edu # [PATCH] USB: Disallow probing etc. for suspended devices # # This patch is a repeat of as335, as described in # # http://marc.theaimsgroup.com/?l=linux-usb-devel&m=108861892700869&w=2 # # but updated to match the current source. It should be non-controversial; # it has nothing to do with hubs or locking. Please apply. # # Alan Stern # # # # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/core/usb.c # 2004/08/03 07:18:53-07:00 stern@rowland.harvard.edu +2 -0 # USB: Disallow probing etc. for suspended devices # # drivers/usb/core/message.c # 2004/08/03 07:20:55-07:00 stern@rowland.harvard.edu +9 -0 # USB: Disallow probing etc. for suspended devices # # ChangeSet # 2004/08/05 14:57:26-07:00 stern@rowland.harvard.edu # [PATCH] USB: Don't track endpoint halts in usbcore # # This patch is a repeat of as331 as described in # # http://marc.theaimsgroup.com/?l=linux-usb-devel&m=108811725219677&w=2 # # It has been updated slightly to match the current source. It should be # non-controversial; it has nothing to do with hubs or locking. Please # apply. # # # # # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # include/linux/usb.h # 2004/08/03 07:17:59-07:00 stern@rowland.harvard.edu +0 -6 # USB: Don't track endpoint halts in usbcore # # drivers/usb/storage/transport.c # 2004/08/03 07:17:59-07:00 stern@rowland.harvard.edu +1 -3 # USB: Don't track endpoint halts in usbcore # # drivers/usb/image/microtek.c # 2004/08/03 07:17:59-07:00 stern@rowland.harvard.edu +2 -2 # USB: Don't track endpoint halts in usbcore # # drivers/usb/host/uhci-hcd.c # 2004/08/03 07:17:59-07:00 stern@rowland.harvard.edu +0 -4 # USB: Don't track endpoint halts in usbcore # # drivers/usb/host/ohci-q.c # 2004/08/03 07:17:59-07:00 stern@rowland.harvard.edu +0 -6 # USB: Don't track endpoint halts in usbcore # # drivers/usb/host/hc_simple.c # 2004/08/03 07:17:59-07:00 stern@rowland.harvard.edu +0 -5 # USB: Don't track endpoint halts in usbcore # # drivers/usb/host/ehci-q.c # 2004/08/03 07:17:59-07:00 stern@rowland.harvard.edu +2 -10 # USB: Don't track endpoint halts in usbcore # # drivers/usb/core/urb.c # 2004/08/03 07:17:59-07:00 stern@rowland.harvard.edu +0 -7 # USB: Don't track endpoint halts in usbcore # # drivers/usb/core/message.c # 2004/08/03 07:17:59-07:00 stern@rowland.harvard.edu +7 -17 # USB: Don't track endpoint halts in usbcore # # drivers/usb/core/hub.c # 2004/08/03 07:17:59-07:00 stern@rowland.harvard.edu +0 -2 # USB: Don't track endpoint halts in usbcore # # drivers/usb/core/hcd.h # 2004/08/03 07:17:59-07:00 stern@rowland.harvard.edu +0 -2 # USB: Don't track endpoint halts in usbcore # # drivers/usb/core/hcd.c # 2004/08/03 07:17:59-07:00 stern@rowland.harvard.edu +2 -5 # USB: Don't track endpoint halts in usbcore # # drivers/usb/core/devices.c # 2004/08/03 07:17:59-07:00 stern@rowland.harvard.edu +1 -2 # USB: Don't track endpoint halts in usbcore # # drivers/isdn/hisax/st5481_usb.c # 2004/08/03 07:17:59-07:00 stern@rowland.harvard.edu +0 -3 # USB: Don't track endpoint halts in usbcore # # ChangeSet # 2004/08/05 14:54:20-07:00 nas@e-trolley.de # [PATCH] USB: ipaq module: product id for HTC Himalaya # # This adds support for HTC Himalaya / XDA II # # Signed-off-by: Nabil Sayegh # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/serial/ipaq.h # 2004/07/29 05:39:46-07:00 nas@e-trolley.de +1 -0 # USB: ipaq module: product id for HTC Himalaya # # drivers/usb/serial/ipaq.c # 2004/07/29 05:49:48-07:00 nas@e-trolley.de +1 -0 # USB: ipaq module: product id for HTC Himalaya # # ChangeSet # 2004/08/05 14:15:00-07:00 luca.risolia@studio.unibo.it # [PATCH] USB: SN9C10[12] driver minor update # # Oops, one more. # # # Signed-off-by: Luca Risolia # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/media/Makefile # 2004/08/03 01:53:49-07:00 luca.risolia@studio.unibo.it +1 -1 # USB: SN9C10[12] driver minor update # # ChangeSet # 2004/08/05 14:13:39-07:00 luca.risolia@studio.unibo.it # [PATCH] USB: SN9C10[12] driver update # # This patch brings the driver up to the first stable version. # # Changes: # # * Remove "redblue" entry under /sys # * Better coding style for comments # * Fix the image downscaling factor calculation # * Fix default color settings for some image sensors # * Fix TAS5130D1B image sensor support # * Other small cleanups # * Remove "EXPERIMENTAL" symbol from KConfig # + Add support for PAS202BCB sensor (thanks to # Carlos Eduardo Medaglia Dyonisio) # # Signed-off-by: Luca Risolia # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/media/sn9c102_tas5130d1b.c # 2004/08/03 00:59:59-07:00 luca.risolia@studio.unibo.it +15 -20 # USB: SN9C10[12] driver update # # drivers/usb/media/sn9c102_tas5110c1b.c # 2004/08/03 00:59:53-07:00 luca.risolia@studio.unibo.it +18 -4 # USB: SN9C10[12] driver update # # drivers/usb/media/sn9c102_sensor.h # 2004/08/03 00:59:43-07:00 luca.risolia@studio.unibo.it +85 -48 # USB: SN9C10[12] driver update # # drivers/usb/media/sn9c102_pas106b.c # 2004/08/03 00:59:21-07:00 luca.risolia@studio.unibo.it +62 -16 # USB: SN9C10[12] driver update # # drivers/usb/media/sn9c102_core.c # 2004/08/03 00:59:02-07:00 luca.risolia@studio.unibo.it +38 -48 # USB: SN9C10[12] driver update # # drivers/usb/media/sn9c102.h # 2004/08/03 00:59:10-07:00 luca.risolia@studio.unibo.it +3 -2 # USB: SN9C10[12] driver update # # drivers/usb/media/Kconfig # 2004/08/03 01:09:38-07:00 luca.risolia@studio.unibo.it +4 -4 # USB: SN9C10[12] driver update # # Documentation/usb/sn9c102.txt # 2004/08/03 00:57:11-07:00 luca.risolia@studio.unibo.it +11 -10 # USB: SN9C10[12] driver update # # drivers/usb/media/sn9c102_pas202bcb.c # 2004/08/03 00:59:27-07:00 luca.risolia@studio.unibo.it +238 -0 # USB: SN9C10[12] driver update # # drivers/usb/media/sn9c102_pas202bcb.c # 2004/08/03 00:59:27-07:00 luca.risolia@studio.unibo.it +0 -0 # BitKeeper file /home/greg/linux/BK/usb-2.6/drivers/usb/media/sn9c102_pas202bcb.c # # ChangeSet # 2004/08/05 13:06:30-07:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6 # into bix.(none):/usr/src/bk-usb # # drivers/usb/media/ov511.c # 2004/08/05 13:06:26-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/08/04 18:37:48-07:00 greg@kroah.com # USB: finish up the last of MODULE_PARM to module_param conversions # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/media/ov511.c # 2004/08/04 18:37:13-07:00 greg@kroah.com +4 -3 # USB: finish up the last of MODULE_PARM to module_param conversions # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/media/ibmcam.c # 2004/08/04 18:37:13-07:00 greg@kroah.com +15 -15 # USB: finish up the last of MODULE_PARM to module_param conversions # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/media/dsbr100.c # 2004/08/04 18:37:13-07:00 greg@kroah.com +1 -1 # USB: finish up the last of MODULE_PARM to module_param conversions # # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2004/08/04 03:03:16-07:00 akpm@bix.(none) # Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6 # into bix.(none):/usr/src/bk-usb # # drivers/usb/misc/tiglusb.c # 2004/08/04 03:03:12-07:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/usb/media/ov511.c # 2004/08/04 03:03:12-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/08/03 21:52:38-07:00 greg@kroah.com # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/net/usbnet.c # 2004/08/03 21:51:50-07:00 greg@kroah.com +1 -1 # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/net/pegasus.c # 2004/08/03 21:51:50-07:00 greg@kroah.com +2 -2 # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/misc/tiglusb.c # 2004/08/03 21:51:50-07:00 greg@kroah.com +1 -1 # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/misc/legousbtower.c # 2004/08/03 21:51:49-07:00 greg@kroah.com +7 -7 # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/media/usbvideo.c # 2004/08/03 21:51:49-07:00 greg@kroah.com +1 -1 # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/media/ultracam.c # 2004/08/03 21:51:50-07:00 greg@kroah.com +8 -8 # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/media/stv680.c # 2004/08/03 21:51:50-07:00 greg@kroah.com +3 -3 # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/media/se401.c # 2004/08/03 21:51:50-07:00 greg@kroah.com +2 -2 # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/media/pwc-if.c # 2004/08/03 21:51:50-07:00 greg@kroah.com +16 -18 # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/media/ov511.c # 2004/08/03 21:51:51-07:00 greg@kroah.com +35 -35 # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/media/konicawc.c # 2004/08/03 21:51:50-07:00 greg@kroah.com +9 -9 # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/media/dabusb.c # 2004/08/03 21:51:50-07:00 greg@kroah.com +1 -1 # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/input/kbtab.c # 2004/08/03 21:51:50-07:00 greg@kroah.com +3 -4 # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/input/aiptek.c # 2004/08/03 21:51:49-07:00 greg@kroah.com +2 -2 # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/host/uhci-hcd.c # 2004/08/03 21:51:51-07:00 greg@kroah.com +1 -1 # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/host/ohci-omap.c # 2004/08/03 21:51:50-07:00 greg@kroah.com +1 -1 # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/host/hc_sl811.c # 2004/08/03 21:51:49-07:00 greg@kroah.com +4 -4 # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/class/usblp.c # 2004/08/03 21:51:49-07:00 greg@kroah.com +1 -1 # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/class/usb-midi.c # 2004/08/03 21:51:50-07:00 greg@kroah.com +10 -10 # USB: convert a lot of usb drivers from MODULE_PARM to module_param # # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2004/08/03 07:11:34-07:00 greg@kroah.com # USB: replace old usb-skeleton driver with a rewritten and simpler version. # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/usb-skeleton.c # 2004/08/03 07:11:11-07:00 greg@kroah.com +139 -483 # USB: replace old usb-skeleton driver with a rewritten and simpler version. # # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2004/08/02 16:24:51-07:00 greg@kroah.com # [PATCH] USB: fix build error from previous patch. # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/core/message.c # 2004/08/02 16:22:54-07:00 greg@kroah.com +1 -1 # USB: fix build error from previous patch. # # ChangeSet # 2004/08/02 16:24:29-07:00 david-b@pacbell.net # [PATCH] USB: hid intervals # # I noticed the HID driver had some potential misbehavior ... # # # Bugfix handling for HID devices at high speed (interrupt interval encoding # is log2 not linear), and for interrupt OUT transfers (use the interval # the hardware actually supports). # # Signed-off-by: David Brownell # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/input/hid-core.c # 2004/07/23 06:29:18-07:00 david-b@pacbell.net +8 -2 # USB: hid intervals # # ChangeSet # 2004/08/02 16:24:07-07:00 david-b@pacbell.net # [PATCH] USB: usb_get_descriptor, more error checks # # I've had different versions of this floating around for a while; # basically, the goal is to be more robust against devices that # misbehave by returning garbage descriptors in certain cases. # # Add an extra check when fetching descriptors: the type must be # correct. This guards against different types of firmware (or maybe # hardware) errors than the two checks already being made. # # Signed-off-by: David Brownell # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/core/message.c # 2004/07/14 05:05:11-07:00 david-b@pacbell.net +7 -2 # USB: usb_get_descriptor, more error checks # # ChangeSet # 2004/08/02 14:47:27-07:00 mdharm-usb@one-eyed-alien.net # [PATCH] USB Storage: cleanups, mostly # # This patch is originally from Christoph Hellwig. # # This patch coverts from Scsi_Foo typefs to struct scsi_cmnd, and moved from # the SCSI data direction constants to the DMA ones. # # It also switches to the proper (or so they tell me) use of # headers. This also includes some additional reshuffling to avoid useless # headers in the usb-storage local headers (to improve compile time). # # Signed-off-by: Matthew Dharm # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/storage/usb.h # 2004/07/20 16:30:35-07:00 mdharm-usb@one-eyed-alien.net +4 -5 # USB Storage: cleanups, mostly # # drivers/usb/storage/usb.c # 2004/07/20 16:30:34-07:00 mdharm-usb@one-eyed-alien.net +6 -1 # USB Storage: cleanups, mostly # # drivers/usb/storage/transport.h # 2004/07/20 16:30:38-07:00 mdharm-usb@one-eyed-alien.net +6 -5 # USB Storage: cleanups, mostly # # drivers/usb/storage/transport.c # 2004/07/20 16:30:37-07:00 mdharm-usb@one-eyed-alien.net +18 -13 # USB Storage: cleanups, mostly # # drivers/usb/storage/shuttle_usbat.h # 2004/07/20 16:30:37-07:00 mdharm-usb@one-eyed-alien.net +1 -1 # USB Storage: cleanups, mostly # # drivers/usb/storage/shuttle_usbat.c # 2004/07/20 16:30:36-07:00 mdharm-usb@one-eyed-alien.net +23 -19 # USB Storage: cleanups, mostly # # drivers/usb/storage/sddr55.h # 2004/07/20 16:30:36-07:00 mdharm-usb@one-eyed-alien.net +1 -1 # USB Storage: cleanups, mostly # # drivers/usb/storage/sddr55.c # 2004/07/20 16:30:33-07:00 mdharm-usb@one-eyed-alien.net +24 -20 # USB Storage: cleanups, mostly # # drivers/usb/storage/sddr09.h # 2004/07/20 16:30:35-07:00 mdharm-usb@one-eyed-alien.net +1 -1 # USB Storage: cleanups, mostly # # drivers/usb/storage/sddr09.c # 2004/07/20 16:30:33-07:00 mdharm-usb@one-eyed-alien.net +12 -9 # USB Storage: cleanups, mostly # # drivers/usb/storage/scsiglue.h # 2004/07/20 16:30:26-07:00 mdharm-usb@one-eyed-alien.net +3 -5 # USB Storage: cleanups, mostly # # drivers/usb/storage/scsiglue.c # 2004/07/20 16:30:25-07:00 mdharm-usb@one-eyed-alien.net +18 -11 # USB Storage: cleanups, mostly # # drivers/usb/storage/protocol.h # 2004/07/20 16:30:25-07:00 mdharm-usb@one-eyed-alien.net +10 -10 # USB Storage: cleanups, mostly # # drivers/usb/storage/protocol.c # 2004/07/20 16:30:24-07:00 mdharm-usb@one-eyed-alien.net +14 -11 # USB Storage: cleanups, mostly # # drivers/usb/storage/jumpshot.h # 2004/07/20 16:30:24-07:00 mdharm-usb@one-eyed-alien.net +1 -1 # USB Storage: cleanups, mostly # # drivers/usb/storage/jumpshot.c # 2004/07/20 16:30:23-07:00 mdharm-usb@one-eyed-alien.net +11 -7 # USB Storage: cleanups, mostly # # drivers/usb/storage/isd200.h # 2004/07/20 16:30:23-07:00 mdharm-usb@one-eyed-alien.net +1 -1 # USB Storage: cleanups, mostly # # drivers/usb/storage/isd200.c # 2004/07/20 16:30:22-07:00 mdharm-usb@one-eyed-alien.net +38 -33 # USB Storage: cleanups, mostly # # drivers/usb/storage/freecom.h # 2004/07/20 16:30:21-07:00 mdharm-usb@one-eyed-alien.net +1 -1 # USB Storage: cleanups, mostly # # drivers/usb/storage/freecom.c # 2004/07/20 16:30:21-07:00 mdharm-usb@one-eyed-alien.net +11 -7 # USB Storage: cleanups, mostly # # drivers/usb/storage/dpcm.h # 2004/07/20 16:30:20-07:00 mdharm-usb@one-eyed-alien.net +1 -1 # USB Storage: cleanups, mostly # # drivers/usb/storage/dpcm.c # 2004/07/20 16:30:20-07:00 mdharm-usb@one-eyed-alien.net +5 -1 # USB Storage: cleanups, mostly # # drivers/usb/storage/debug.h # 2004/07/20 16:30:19-07:00 mdharm-usb@one-eyed-alien.net +3 -3 # USB Storage: cleanups, mostly # # drivers/usb/storage/debug.c # 2004/07/20 16:30:18-07:00 mdharm-usb@one-eyed-alien.net +7 -1 # USB Storage: cleanups, mostly # # drivers/usb/storage/datafab.h # 2004/07/20 16:30:17-07:00 mdharm-usb@one-eyed-alien.net +1 -1 # USB Storage: cleanups, mostly # # drivers/usb/storage/datafab.c # 2004/07/20 16:30:17-07:00 mdharm-usb@one-eyed-alien.net +11 -8 # USB Storage: cleanups, mostly # # ChangeSet # 2004/08/02 14:47:07-07:00 mdharm-usb@one-eyed-alien.net # [PATCH] USB Storage: improve debugging output in usb-storage # # This patch started life as as294. All I did was to regenerate it to apply # cleanly against current kernels. # # This just adds a couple of lines to the debugging output with some useful # information, and removes some lines that nobody has looked at in a very # long time. # # Signed-off-by: Alan Stern # Signed-off-by: Matthew Dharm # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/storage/usb.c # 2004/08/01 10:17:28-07:00 mdharm-usb@one-eyed-alien.net +9 -10 # USB Storage: improve debugging output in usb-storage # # ChangeSet # 2004/08/02 14:46:49-07:00 mdharm-usb@one-eyed-alien.net # [PATCH] USB Storage: fix Genesys Logic based on info from vendor # # In theory, this is the fix we need to make Genesys Logic devices work. # This patch started life as as343, which was created based on some # information which a user finally coaxed out of Genesys Logic. Limited # end-user testing gives good results. # # As we expected, it's a bug in their device. This is really a workaround # for what is almost certainly a timing problem. Apparently, the 'popular' # OSes don't push the device as hard as Linux does. # # Although it is likely that this workaround is not needed for all Genesys # devices, Genesys was unable/unwilling to provide us with the explicit list # of VID/PIDs which required this -- thus we apply it to all Genesys devices. # # We have lots of good reports with max_sectors set to 128 with these # devices, but the official recommendation is to set that to 64. End-users # can experiment with higher values (for higher performance) via the runtime # sysfs interface to that parameter. # # I would like to give special thanks to the users who hounded Genesys into # giving up this information, and to Alan Stern for not giving up on this # vendor long after I had. # # Signed-off-by: Alan Stern # Signed-off-by: Matthew Dharm # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/storage/usb.h # 2004/08/01 10:32:35-07:00 mdharm-usb@one-eyed-alien.net +4 -0 # USB Storage: fix Genesys Logic based on info from vendor # # drivers/usb/storage/transport.c # 2004/08/01 10:32:35-07:00 mdharm-usb@one-eyed-alien.net +6 -0 # USB Storage: fix Genesys Logic based on info from vendor # # drivers/usb/storage/scsiglue.c # 2004/08/01 10:32:35-07:00 mdharm-usb@one-eyed-alien.net +8 -10 # USB Storage: fix Genesys Logic based on info from vendor # # ChangeSet # 2004/08/02 14:46:24-07:00 oliver@neukum.org # [PATCH] USB: ACM USB modem on Kernel 2.6.8-rc2 # # this adds a workaround for a broken USB modem. # # # Signed-Off-By: Oliver Neukum # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/class/cdc-acm.c # 2004/08/02 12:40:30-07:00 oliver@neukum.org +17 -11 # USB: ACM USB modem on Kernel 2.6.8-rc2 # # ChangeSet # 2004/08/02 14:29:51-07:00 nacc@us.ibm.com # [PATCH] USB: usbnet: replace schedule_timeout() with msleep() # # Use msleep() instead of schedule_timeout() to guarantee the task delays # for the desired time. Delete unused UNLINK_TIMEOUT_JIFFIES #define. # # Signed-off-by: Nishanth Aravamudan # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/net/usbnet.c # 2004/07/28 12:33:16-07:00 nacc@us.ibm.com +2 -3 # USB: usbnet: replace schedule_timeout() with msleep() # # ChangeSet # 2004/08/02 14:29:08-07:00 nacc@us.ibm.com # [PATCH] USB: auerswald: replace schedule_timeout() with msleep() # # Use msleep() instead of schedule_timeout() to # guarantee the task delays for the desired time. # # Signed-off-by: Nishanth Aravamudan # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/misc/auerswald.c # 2004/07/05 18:12:12-07:00 nacc@us.ibm.com +1 -2 # USB: auerswald: replace schedule_timeout() with msleep() # # ChangeSet # 2004/08/02 14:28:02-07:00 nacc@us.ibm.com # [PATCH] USB: ov511: replace schedule_timeout() with msleep() # # Use msleep() instead of schedule_timeout() to # guarantee the task delays for the desired time. # # Signed-off-by: Nishanth Aravamudan # Signed-off-by: Mark McClelland # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/media/ov511.c # 2004/07/13 13:29:29-07:00 nacc@us.ibm.com +3 -3 # USB: ov511: replace schedule_timeout() with msleep() # # ChangeSet # 2004/08/02 14:26:44-07:00 nacc@us.ibm.com # [PATCH] USB: pxa2xx_udc.c: replace schedule_timeout() with msleep() # # Use msleep() instead of schedule_timeout() to # guarantee the task delays for the desired time. # # Signed-off-by: Nishanth Aravamudan # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/gadget/pxa2xx_udc.c # 2004/07/13 13:31:07-07:00 nacc@us.ibm.com +1 -1 # USB: pxa2xx_udc.c: replace schedule_timeout() with msleep() # # ChangeSet # 2004/08/02 14:25:50-07:00 da-x@gmx.net # [PATCH] d_unhash consolidation # # This removes a copy of d_unhash() from drivers/usb/core/inode.c and # and exports d_unhash() from fs/namei.c as dentry_unhash(). # Tested - compiled and running. # # Signed-off-by: Dan Aloni # Signed-off-by: Greg Kroah-Hartman # # include/linux/fs.h # 2004/07/24 05:52:42-07:00 da-x@gmx.net +5 -0 # d_unhash consolidation # # fs/namei.c # 2004/07/24 06:14:13-07:00 da-x@gmx.net +4 -3 # d_unhash consolidation # # drivers/usb/core/inode.c # 2004/07/24 06:13:27-07:00 da-x@gmx.net +1 -18 # d_unhash consolidation # # ChangeSet # 2004/08/02 13:35:47-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb # # MAINTAINERS # 2004/08/02 13:35:43-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/07/30 16:55:46-07:00 greg@kroah.com # USB: fix build error in the cyberjack driver # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/serial/cyberjack.c # 2004/07/30 16:55:16-07:00 greg@kroah.com +1 -0 # USB: fix build error in the cyberjack driver # # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2004/07/30 16:38:58-07:00 luca.risolia@studio.unibo.it # [PATCH] USB: New entry in MAINTAINERS # # I forgot to add an entry in MAINTAINERS about the new SN9C10[12] driver. # # Signed-off-by: Luca Risolia # Signed-off-by: Greg Kroah-Hartman # # MAINTAINERS # 2004/07/15 04:04:07-07:00 luca.risolia@studio.unibo.it +7 -0 # USB: New entry in MAINTAINERS # # ChangeSet # 2004/07/30 16:38:38-07:00 stern@rowland.harvard.edu # [PATCH] USB: unusual_devs.h update # # In view of the comments below, I think we should modify this # unusual_devs.h entry to suppress the warning messages. Please apply. # # # # On Mon, 28 Jun 2004, Joël Bourquard wrote: # # > There seem to be two different flavors of ISD-300 (ie: 05ab,0060) # > devices, one of which needs this entry to work, and the other doesn't. # > # > I have a 2 1/2'' HDD enclosure which (just like your device) doesn't # > need the entry (so when I plug it, I get the same warning as you). # > # > However, I also happen to own two 5 1/4'' CD-ROM enclosures, for which # > this entry *is* necessary. I tried again, very recently to remove my # > unusual_devs.h entry, and it prevented them from working. # > # > So, I think the entry should be kept (it does more good than harm), but # > maybe it could get some tweaking ? If there's a way to recognize these # > "CD-ROM enclosure" bridge chips and exclude the others, I'm all for it. # # # # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/storage/unusual_devs.h # 2004/07/19 04:26:41-07:00 stern@rowland.harvard.edu +6 -2 # USB: unusual_devs.h update # # ChangeSet # 2004/07/30 16:38:21-07:00 stern@rowland.harvard.edu # [PATCH] USB: unusual_devs.h update # # Just like in as347, we have another example of descriptors that vary from # device to device. Please apply this patch to suppress the warning # message. # # On Fri, 16 Jul 2004, Ken Yap wrote: # # > Jul 16 21:44:20 media kernel: usb-storage: This device (090a,1001,0100 S 06 P 50) has an unneeded Protocol entry in unusual_devs.h # > Jul 16 21:44:20 media kernel: Please send a copy of this message to # # # # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/storage/unusual_devs.h # 2004/07/19 04:35:14-07:00 stern@rowland.harvard.edu +1 -1 # USB: unusual_devs.h update # # ChangeSet # 2004/07/30 16:38:02-07:00 johann.cardon@free.fr # [PATCH] USB: New unusual_devs.h entry # # Please merge this new entry for the unusual_devs.h database. # # From: Johann Cardon # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/storage/unusual_devs.h # 2004/07/19 04:43:38-07:00 johann.cardon@free.fr +9 -0 # USB: New unusual_devs.h entry # # ChangeSet # 2004/07/30 16:37:43-07:00 domen@coderock.org # [PATCH] USB: use list_for_each() in core/devices.c # # Signed-off-by: Maximilian Attems # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/core/devices.c # 2004/07/11 05:41:36-07:00 domen@coderock.org +1 -1 # USB: use list_for_each() in core/devices.c # # ChangeSet # 2004/07/30 16:37:24-07:00 domen@coderock.org # [PATCH] USB: use list_for_each() in class/usb-midi.c # # Signed-off-by: Maximilian Attems # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/class/usb-midi.c # 2004/07/11 05:41:39-07:00 domen@coderock.org +3 -3 # USB: use list_for_each() in class/usb-midi.c # # ChangeSet # 2004/07/30 16:37:05-07:00 domen@coderock.org # [PATCH] USB: use list_for_each() in class/audio.c # # Signed-off-by: Maximilian Attems # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/class/audio.c # 2004/07/11 05:41:32-07:00 domen@coderock.org +6 -6 # USB: use list_for_each() in class/audio.c # # ChangeSet # 2004/07/30 16:36:42-07:00 ganesh@veritas.com # [PATCH] USB: fix for ipaq.c # # as per pete and greg's input, fixing only the uninitialized variable. # # Signed-off-by: Ganesh Varadarajan # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/serial/ipaq.c # 2004/07/22 08:42:31-07:00 ganesh@veritas.com +1 -0 # USB: fix for ipaq.c # # ChangeSet # 2004/07/30 16:36:24-07:00 phil@ipom.com # [PATCH] USB: Debug fix in pl2303 # # This is a simple patch to fix a debug statement where the arguements are # in the wrong order. Resending it with a CC to Greg and a signed-off-by line. # # Signed-off-by: Phil Dibowitz # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/serial/pl2303.c # 2004/07/24 00:50:24-07:00 phil@ipom.com +1 -1 # USB: Debug fix in pl2303 # # ChangeSet # 2004/07/30 16:36:03-07:00 stern@rowland.harvard.edu # [PATCH] USB: Remove unneeded unusual_devs.h entry # # According to Jonas Fährmann, the very first entry in unusual_devs.h isn't # needed. In fact, I can't tell why it was there in the first place... # unless some earlier device in the product line had incorrect descriptor # values. # # # On Mon, 26 Jul 2004, Jonas Fährmann wrote: # # > usb-storage: This device (03ee,0000,0045 S 02 P 00) has unneeded SubClass and Protocol entries in unusual_devs.h # > Please send a copy of this message to # # # # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/storage/unusual_devs.h # 2004/07/27 04:39:20-07:00 stern@rowland.harvard.edu +0 -5 # USB: Remove unneeded unusual_devs.h entry # # ChangeSet # 2004/07/30 16:35:44-07:00 abbotti@mev.co.uk # [PATCH] USB: Add support for FT2232C chip to ftdi_sio # # This patch adds support for the FTDI FT2232C USB to dual serial port # converter to the ftdi_sio driver. # # The patch is based on a fork of the 2.4 ftdi_sio driver by Steven # Turner of FTDI, and a preliminary port of these changes to the 2.6 # ftdi_sio driver by Rus V. Brushkoff. I've tidied it up and fixed a # couple of things. # # I don't have a FT2232C to test it with, but Steven Turner of FTDI # has tested it. He mentioned a couple of known problems with the # driver, but nothing to do with this patch. # # # Signed-off-by: Ian Abbott # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/serial/ftdi_sio.h # 2004/07/27 11:12:46-07:00 abbotti@mev.co.uk +17 -0 # USB: Add support for FT2232C chip to ftdi_sio # # drivers/usb/serial/ftdi_sio.c # 2004/07/27 11:12:46-07:00 abbotti@mev.co.uk +102 -13 # USB: Add support for FT2232C chip to ftdi_sio # # ChangeSet # 2004/07/30 16:35:24-07:00 abbotti@mev.co.uk # [PATCH] USB: ftdi_sio doesn't re-assert DTR modem control line # # I've dredged up another old ftdi_sio patch that I never Cc'd to you # the first time. Please see Nathan's description below. # # It applies okay against your usb-2.6 tree, with or without the patch # I posted yesterday to support the FT2232C chip and neither patch # invalidates the other in any way. # # # On 25/06/2004 21:56, Croy, Nathan wrote: # > SUMMARY # > ======= # > ftdi_sio never reasserts modem control lines once the baud has been set to # > B0. # > # > DESCRIPTION # > =========== # > Setting the baud to B0 (hangup) drops DTR. When the baud is raised again, # > DTR is not raised. This can cause a modem to ignore any commands sent to it # > until the device is closed and reopened. This renders minicom (and other # > software) useless, unless you instruct the modem to ignore DTR. # > # > The following patch is intended to make ftdi_sio act like other serial # > devices I have used (i.e. the standard serial ports (/dev/ttyS*) and # > stallion ports (/dev/ttyE*)). Upon setting the baud to something other than # > B0, it ensures the modem control lines are set back to the way they were # > when the port was opened. # > # > Thanks to Ian Abbott for confirming my suspicions: # > http://sourceforge.net/mailarchive/forum.php?thread_id=4984710&forum_id=12120 # # Nathan's email suffered from a line-folding bug (blame M$, # probably!), so his patch came out corrupted. I'm reposting an # uncorrupted version. # # # Signed off by: Ian Abbott # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/serial/ftdi_sio.c # 2004/06/24 05:29:22-07:00 abbotti@mev.co.uk +7 -0 # USB: ftdi_sio doesn't re-assert DTR modem control line # # ChangeSet # 2004/07/30 16:35:06-07:00 laforge@netfilter.org # [PATCH] USB: Hackish fix for cyberjack driver # # The following patch is in use by REINER-SCT customres for some time and # works for them in about 90% of all cases. I would really appreciate # this going in before 2.6.8-final, since the device doesn't work at all # with current 2.6.x driver. # # Changes: # - bump version number # - open interrupt endpoint in startup() rather than open # # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/serial/cyberjack.c # 2004/07/28 08:40:57-07:00 laforge@netfilter.org +16 -17 # USB: Hackish fix for cyberjack driver # # ChangeSet # 2004/07/30 16:34:47-07:00 akpm@osdl.org # [PATCH] USB: gcc-3.5 fixes # # From: Andi Kleen # # Trivial gcc-3.5 build fixes. # # Signed-off-by: Andrew Morton # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/class/usblp.c # 2004/07/10 17:52:27-07:00 akpm@osdl.org +1 -1 # USB: gcc-3.5 fixes # # ChangeSet # 2004/07/30 16:34:27-07:00 david-b@pacbell.net # [PATCH] USB: usb hub docs and locktree() # # Please merge; the CONFIG_USB_SUSPEND patch depends on it. # # This hub patch: # # - updates internal docs about locking, matching current usage # for device state spinlock and dev->serialize semaphore # # - adds locktree() to use with signaling that affect everything # downstream of a given device ... right now just khubd uses it, # but usb_reset_device() should too (not just with hub resets...) # # - adds hub_quiesce()/hub_reactivate() ... former is used now # during shutdown, both are needed in suspend/resume paths # # Net change in behavior for current systems should be nothing. # # Signed-off-by: David Brownell # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/core/hub.h # 2004/07/29 01:31:30-07:00 david-b@pacbell.net +2 -0 # USB: usb hub docs and locktree() # # drivers/usb/core/hub.c # 2004/07/29 03:00:59-07:00 david-b@pacbell.net +105 -21 # USB: usb hub docs and locktree() # # ChangeSet # 2004/07/30 16:34:04-07:00 david-b@pacbell.net # [PATCH] USB: add CONFIG_USB_SUSPEND # # This is the core of the USB_SUSPEND functionality. Please merge. # # This adds an experimental CONFIG_USB_SUSPEND option, which supports the # USB "suspend" state. Linux-USB hosts have previously ignored that state. # # - New driver API calls, usb_suspend_device() and its # sibling usb_resume_device(). # # - Access to those calls through sysfs, such as # echo -n 2 > power/state # echo -n 0 > power/state # # That can be used to reduce the power consumption of any given USB device, # then re-activate it later. Eventually, most USB device drivers should # probably suspend idle USB devices. # # One problem with this patch: USB drivers without suspend() callbacks # may badly misbehave. Right now only hub drivers know suspend(). If the # driver core didn't self-deadlock when we try it, unbinding those drivers # from those devices (then re-enumerating on resume) would be perfect... # the current compromise is just to emit a warning message. # # In conjunction with host controller driver support (already merged for # OHCI and EHCI), PCI host controllers will issue the PME# wakeup signal # when a USB keyboard starts remote wakeup signaling. (But the keyboard # wasn't usable later, since HID doesn't try to suspend.) # # I understand some ACPI patches are circulating, and maybe already in # the MM tree, to make a suspended system wake up given PME# signaling. # It'd be great if someone made that work transparently with USB, but # for now I'm told it'll need some sysfs setup first. # # Signed-off-by: David Brownell # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/core/hub.c # 2004/07/29 03:00:59-07:00 david-b@pacbell.net +484 -1 # USB: add CONFIG_USB_SUSPEND # # drivers/usb/core/Kconfig # 2004/07/29 01:31:44-07:00 david-b@pacbell.net +11 -0 # USB: add CONFIG_USB_SUSPEND # # Documentation/DocBook/usb.tmpl # 2004/07/29 01:42:14-07:00 david-b@pacbell.net +1 -0 # USB: add CONFIG_USB_SUSPEND # # ChangeSet # 2004/07/30 16:33:45-07:00 stern@rowland.harvard.edu # [PATCH] USB: Make removable-LUN support a non-test option in the g_file_storage driver # # This patch follows the suggestions sent by Todd Fischer and Diego Dompe # for making removable-LUN support part of the normal non-testing version of # the g_file_storage driver. It also moves LUN device registration to the # correct place and eliminates a code path that stalls the bulk-out pipe in # a racy way. # # There are also some smaller changes: update some comments, add initial # debugging support for USB suspend/resume, and miscellaneous code cleanups. # Last but not least, the driver has been sufficiently stable for # sufficiently long that it's fair to remove the "(DEVELOPMENT)" warning in # Kconfig. # # # # Sent-by: Todd Fischer # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/gadget/file_storage.c # 2004/07/28 04:17:49-07:00 stern@rowland.harvard.edu +94 -75 # USB: Make removable-LUN support a non-test option in the g_file_storage driver # # drivers/usb/gadget/Kconfig # 2004/07/28 04:08:24-07:00 stern@rowland.harvard.edu +2 -2 # USB: Make removable-LUN support a non-test option in the g_file_storage driver # # ChangeSet # 2004/07/30 16:33:20-07:00 stern@rowland.harvard.edu # [PATCH] USB: Fix NULL-pointer bug in dummy_hcd # # This patch fixes a NULL-pointer-dereference bug in the dummy_hcd driver. # It also makes the code slightly more elegant and removes an unnecessary # buffer-overflow test. Unfortunately it's still a little bit racy, but # this is a fault it shares with other gadget controller drivers, like # net2280. # # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/gadget/dummy_hcd.c # 2004/07/29 05:10:55-07:00 stern@rowland.harvard.edu +4 -5 # USB: Fix NULL-pointer bug in dummy_hcd # diff -Nru a/Documentation/DocBook/usb.tmpl b/Documentation/DocBook/usb.tmpl --- a/Documentation/DocBook/usb.tmpl 2004-08-18 23:28:03 -07:00 +++ b/Documentation/DocBook/usb.tmpl 2004-08-18 23:28:03 -07:00 @@ -251,6 +251,7 @@ !Edrivers/usb/core/message.c !Edrivers/usb/core/file.c !Edrivers/usb/core/usb.c +!Edrivers/usb/core/hub.c Host Controller APIs diff -Nru a/Documentation/usb/sn9c102.txt b/Documentation/usb/sn9c102.txt --- a/Documentation/usb/sn9c102.txt 2004-08-18 23:28:03 -07:00 +++ b/Documentation/usb/sn9c102.txt 2004-08-18 23:28:03 -07:00 @@ -142,7 +142,7 @@ 1 = critical errors 2 = significant informations 3 = more verbose messages - Level 3 is useful for testing only, when just one device + Level 3 is useful for testing only, when only one device is used. Default: 2 ------------------------------------------------------------------------------- @@ -153,12 +153,10 @@ It is possible to read and write both the SN9C10[12] and the image sensor registers by using the "sysfs" filesystem interface. -Every time a supported device is recognized, read-only files named "redblue" -and "green" are created in the /sys/class/video4linux/videoX directory. You can -set the red, blue and green channel's gain by writing the desired value to -them. The value may range from 0 to 15 for each channel; this means that -"redblue" accepts 8-bit values, where the low 4 bits are reserved for red and -the others for blue. +Every time a supported device is recognized, a read-only file named "green" is +created in the /sys/class/video4linux/videoX directory. You can set the green +channel's gain by writing the desired value to it. The value may range from 0 +to 15. There are other four entries in the directory above for each registered camera: "reg", "val", "i2c_reg" and "i2c_val". The first two files control the @@ -217,6 +215,7 @@ Model Manufacturer ----- ------------ PAS106B PixArt Imaging Inc. +PAS202BCB PixArt Imaging Inc. TAS5110C1B Taiwan Advanced Sensor Corporation TAS5130D1B Taiwan Advanced Sensor Corporation @@ -239,8 +238,8 @@ (documentation is included there). As an example, have a look at the code in "sn9c102_pas106b.c", which uses the mentioned interface. -At the moment, not yet supported image sensors are: PAS202B (VGA), -HV7131[D|E1] (VGA), MI03 (VGA), OV7620 (VGA). +At the moment, not yet supported image sensors are: HV7131[D|E1] (VGA), +MI03 (VGA), OV7620 (VGA). 10. Note for V4L2 developers @@ -273,4 +272,6 @@ - Stefano Mozzi, who donated 45 EU; - Luca Capello for the donation of a webcam; -- Mizuno Takafumi for the donation of a webcam. +- Mizuno Takafumi for the donation of a webcam; +- Carlos Eduardo Medaglia Dyonisio, who added the support for the PAS202BCB + image sensor. diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS 2004-08-18 23:28:03 -07:00 +++ b/MAINTAINERS 2004-08-18 23:28:03 -07:00 @@ -2299,6 +2299,13 @@ W: http://www.connecttech.com S: Supported +USB SN9C10[12] DRIVER +P: Luca Risolia +M: luca.risolia@studio.unibo.it +L: linux-usb-devel@lists.sourceforge.net +W: http://go.lamarinapunto.com +S: Maintained + USB SUBSYSTEM P: Greg Kroah-Hartman M: greg@kroah.com diff -Nru a/drivers/block/Kconfig b/drivers/block/Kconfig --- a/drivers/block/Kconfig 2004-08-18 23:28:03 -07:00 +++ b/drivers/block/Kconfig 2004-08-18 23:28:03 -07:00 @@ -301,6 +301,15 @@ Use devices /dev/sx8/$N and /dev/sx8/$Np$M. +config BLK_DEV_UB + tristate "Low Performance USB Block driver" + depends on USB + help + This driver supports certain USB attached storage devices + such as flash keys. + + If unsure, say N. + config BLK_DEV_RAM tristate "RAM disk support" ---help--- diff -Nru a/drivers/block/Makefile b/drivers/block/Makefile --- a/drivers/block/Makefile 2004-08-18 23:28:03 -07:00 +++ b/drivers/block/Makefile 2004-08-18 23:28:03 -07:00 @@ -42,4 +42,5 @@ obj-$(CONFIG_VIODASD) += viodasd.o obj-$(CONFIG_BLK_DEV_SX8) += sx8.o +obj-$(CONFIG_BLK_DEV_UB) += ub.o diff -Nru a/drivers/block/ub.c b/drivers/block/ub.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/block/ub.c 2004-08-18 23:28:03 -07:00 @@ -0,0 +1,2037 @@ +/* + * The low performance USB storage driver (ub). + * + * Copyright (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * Copyright (C) 2004 Pete Zaitcev (zaitcev@yahoo.com) + * + * This work is a part of Linux kernel, is derived from it, + * and is not licensed separately. See file COPYING for details. + * + * TODO (sorted by decreasing priority) + * -- ZIP does "ub: resid 18 len 0 act 0" and whole transport quits (toggles?) + * -- set readonly flag for CDs, set removable flag for CF readers + * -- do inquiry and verify we got a disk and not a tape (for LUN mismatch) + * -- support pphaneuf's SDDR-75 with two LUNs (also broken capacity...) + * -- special case some senses, e.g. 3a/0 -> no media present, reduce retries + * -- do something about spin-down devices, they are extremely dangerous + * (ZIP is one. Needs spin-up command as well.) + * -- verify the 13 conditions and do bulk resets + * -- normal pool of commands instead of cmdv[]? + * -- kill last_pipe and simply do two-state clearing on both pipes + * -- verify protocol (bulk) from USB descriptors (maybe...) + * -- highmem and sg + * -- move top_sense and work_bcs into separate allocations (if they survive) + * for cache purists and esoteric architectures. + * -- prune comments, they are too volumnous + * -- Exterminate P3 printks + * -- Resove XXX's + */ +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "ub" +#define DEVFS_NAME DRV_NAME + +#define UB_MAJOR 125 /* Stolen from Experimental range for a week - XXX */ + +/* + * Definitions which have to be scattered once we understand the layout better. + */ + +/* Transport (despite PR in the name) */ +#define US_PR_BULK 0x50 /* bulk only */ + +/* Protocol */ +#define US_SC_SCSI 0x06 /* Transparent */ + +/* + */ +#define UB_MINORS_PER_MAJOR 8 + +#define UB_MAX_CDB_SIZE 16 /* Corresponds to Bulk */ + +#define UB_SENSE_SIZE 18 + +/* + */ + +/* command block wrapper */ +struct bulk_cb_wrap { + u32 Signature; /* contains 'USBC' */ + u32 Tag; /* unique per command id */ + u32 DataTransferLength; /* size of data */ + u8 Flags; /* direction in bit 0 */ + u8 Lun; /* LUN normally 0 */ + u8 Length; /* of of the CDB */ + u8 CDB[UB_MAX_CDB_SIZE]; /* max command */ +}; + +#define US_BULK_CB_WRAP_LEN 31 +#define US_BULK_CB_SIGN 0x43425355 /*spells out USBC */ +#define US_BULK_FLAG_IN 1 +#define US_BULK_FLAG_OUT 0 + +/* command status wrapper */ +struct bulk_cs_wrap { + u32 Signature; /* should = 'USBS' */ + u32 Tag; /* same as original command */ + u32 Residue; /* amount not transferred */ + u8 Status; /* see below */ +}; + +#define US_BULK_CS_WRAP_LEN 13 +#define US_BULK_CS_SIGN 0x53425355 /* spells out 'USBS' */ +/* This is for Olympus Camedia digital cameras */ +#define US_BULK_CS_OLYMPUS_SIGN 0x55425355 /* spells out 'USBU' */ +#define US_BULK_STAT_OK 0 +#define US_BULK_STAT_FAIL 1 +#define US_BULK_STAT_PHASE 2 + +/* bulk-only class specific requests */ +#define US_BULK_RESET_REQUEST 0xff +#define US_BULK_GET_MAX_LUN 0xfe + +/* + */ +struct ub_dev; + +#define UB_MAX_REQ_SG 1 +#define UB_MAX_SECTORS 64 + +/* + * A second ought to be enough for a 32K transfer (UB_MAX_SECTORS) + * even if a webcam hogs the bus (famous last words). + * Some CDs need a second to spin up though. + */ +#define UB_URB_TIMEOUT (HZ*2) +#define UB_CTRL_TIMEOUT (HZ/2) /* 500ms ought to be enough to clear a stall */ + +/* + * An instance of a SCSI command in transit. + */ +#define UB_DIR_NONE 0 +#define UB_DIR_READ 1 +#define UB_DIR_ILLEGAL2 2 +#define UB_DIR_WRITE 3 + +#define UB_DIR_CHAR(c) (((c)==UB_DIR_WRITE)? 'w': \ + (((c)==UB_DIR_READ)? 'r': 'n')) + +enum ub_scsi_cmd_state { + UB_CMDST_INIT, /* Initial state */ + UB_CMDST_CMD, /* Command submitted */ + UB_CMDST_DATA, /* Data phase */ + UB_CMDST_CLR2STS, /* Clearing before requesting status */ + UB_CMDST_STAT, /* Status phase */ + UB_CMDST_CLEAR, /* Clearing a stall (halt, actually) */ + UB_CMDST_SENSE, /* Sending Request Sense */ + UB_CMDST_DONE /* Final state */ +}; + +static char *ub_scsi_cmd_stname[] = { + ". ", + "Cmd", + "dat", + "c2s", + "sts", + "clr", + "Sen", + "fin" +}; + +struct ub_scsi_cmd { + unsigned char cdb[UB_MAX_CDB_SIZE]; + unsigned char cdb_len; + + unsigned char dir; /* 0 - none, 1 - read, 3 - write. */ + unsigned char trace_index; + enum ub_scsi_cmd_state state; + unsigned int tag; + struct ub_scsi_cmd *next; + + int error; /* Return code - valid upon done */ + int act_len; /* Return size */ + + int stat_count; /* Retries getting status. */ + + /* + * We do not support transfers from highmem pages + * because the underlying USB framework does not do what we need. + */ + char *data; /* Requested buffer */ + unsigned int len; /* Requested length */ + // struct scatterlist sgv[UB_MAX_REQ_SG]; + + void (*done)(struct ub_dev *, struct ub_scsi_cmd *); + void *back; +}; + +/* + */ +struct ub_capacity { + unsigned long nsec; /* Linux size - 512 byte sectors */ + unsigned int bsize; /* Linux hardsect_size */ + unsigned int bshift; /* Shift between 512 and hard sects */ +}; + +/* + * The SCSI command tracing structure. + */ + +#define SCMD_ST_HIST_SZ 8 +#define SCMD_TRACE_SZ 15 /* No more than 256 (trace_index) */ + +struct ub_scsi_cmd_trace { + int hcur; + unsigned int tag; + unsigned int req_size, act_size; + unsigned char op; + unsigned char dir; + unsigned char key, asc, ascq; + char st_hst[SCMD_ST_HIST_SZ]; +}; + +struct ub_scsi_trace { + int cur; + struct ub_scsi_cmd_trace vec[SCMD_TRACE_SZ]; +}; + +/* + * This is a direct take-off from linux/include/completion.h + * The difference is that I do not wait on this thing, just poll. + * When I want to wait (ub_probe), I just use the stock completion. + * + * Note that INIT_COMPLETION takes no lock. It is correct. But why + * in the bloody hell that thing takes struct instead of pointer to struct + * is quite beyond me. I just copied it from the stock completion. + */ +struct ub_completion { + unsigned int done; + spinlock_t lock; +}; + +static inline void ub_init_completion(struct ub_completion *x) +{ + x->done = 0; + spin_lock_init(&x->lock); +} + +#define UB_INIT_COMPLETION(x) ((x).done = 0) + +static void ub_complete(struct ub_completion *x) +{ + unsigned long flags; + + spin_lock_irqsave(&x->lock, flags); + x->done++; + spin_unlock_irqrestore(&x->lock, flags); +} + +static int ub_is_completed(struct ub_completion *x) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&x->lock, flags); + ret = x->done; + spin_unlock_irqrestore(&x->lock, flags); + return ret; +} + +/* + */ +struct ub_scsi_cmd_queue { + int qlen, qmax; + struct ub_scsi_cmd *head, *tail; +}; + +/* + * The UB device instance. + */ +struct ub_dev { + spinlock_t lock; + int id; /* Number among ub's */ + atomic_t poison; /* The USB device is disconnected */ + int openc; /* protected by ub_lock! */ + /* kref is too implicit for our taste */ + unsigned int tagcnt; + int changed; /* Media was changed */ + int removable; + int readonly; + char name[8]; + struct usb_device *dev; + struct usb_interface *intf; + + struct ub_capacity capacity; + struct gendisk *disk; + + unsigned int send_bulk_pipe; /* cached pipe values */ + unsigned int recv_bulk_pipe; + unsigned int send_ctrl_pipe; + unsigned int recv_ctrl_pipe; + + struct tasklet_struct tasklet; + + /* XXX Use Ingo's mempool (once we have more than one) */ + int cmda[1]; + struct ub_scsi_cmd cmdv[1]; + + struct ub_scsi_cmd_queue cmd_queue; + struct ub_scsi_cmd top_rqs_cmd; /* REQUEST SENSE */ + unsigned char top_sense[UB_SENSE_SIZE]; + + struct ub_completion work_done; + struct urb work_urb; + int last_pipe; /* What might need clearing */ + struct bulk_cb_wrap work_bcb; + struct bulk_cs_wrap work_bcs; + struct usb_ctrlrequest work_cr; + + struct ub_scsi_trace tr; +}; + +/* + */ +static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd); +static void ub_end_rq(struct request *rq, int uptodate); +static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd); +static void ub_urb_complete(struct urb *urb, struct pt_regs *pt); +static void ub_scsi_action(unsigned long _dev); +static void ub_scsi_dispatch(struct ub_dev *sc); +static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd); +static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc); +static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd); +static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd); +static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, + int stalled_pipe); +static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd); +static int ub_sync_tur(struct ub_dev *sc); +static int ub_sync_read_cap(struct ub_dev *sc, struct ub_capacity *ret); + +/* + */ +static struct usb_device_id ub_usb_ids[] = { + // { USB_DEVICE_VER(0x0781, 0x0002, 0x0009, 0x0009) }, /* SDDR-31 */ + { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) }, + { } +}; + +MODULE_DEVICE_TABLE(usb, ub_usb_ids); + +/* + * Find me a way to identify "next free minor" for add_disk(), + * and the array disappears the next day. However, the number of + * hosts has something to do with the naming and /proc/partitions. + * This has to be thought out in detail before changing. + * If UB_MAX_HOST was 1000, we'd use a bitmap. Or a better data structure. + */ +#define UB_MAX_HOSTS 26 +static char ub_hostv[UB_MAX_HOSTS]; +static spinlock_t ub_lock = SPIN_LOCK_UNLOCKED; /* Locks globals and ->openc */ + +/* + * The SCSI command tracing procedures. + */ + +static void ub_cmdtr_new(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + int n; + struct ub_scsi_cmd_trace *t; + + if ((n = sc->tr.cur + 1) == SCMD_TRACE_SZ) n = 0; + t = &sc->tr.vec[n]; + + memset(t, 0, sizeof(struct ub_scsi_cmd_trace)); + t->tag = cmd->tag; + t->op = cmd->cdb[0]; + t->dir = cmd->dir; + t->req_size = cmd->len; + t->st_hst[0] = cmd->state; + + sc->tr.cur = n; + cmd->trace_index = n; +} + +static void ub_cmdtr_state(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + int n; + struct ub_scsi_cmd_trace *t; + + t = &sc->tr.vec[cmd->trace_index]; + if (t->tag == cmd->tag) { + if ((n = t->hcur + 1) == SCMD_ST_HIST_SZ) n = 0; + t->st_hst[n] = cmd->state; + t->hcur = n; + } +} + +static void ub_cmdtr_act_len(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct ub_scsi_cmd_trace *t; + + t = &sc->tr.vec[cmd->trace_index]; + if (t->tag == cmd->tag) + t->act_size = cmd->act_len; +} + +static void ub_cmdtr_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd, + unsigned char *sense) +{ + struct ub_scsi_cmd_trace *t; + + t = &sc->tr.vec[cmd->trace_index]; + if (t->tag == cmd->tag) { + t->key = sense[2] & 0x0F; + t->asc = sense[12]; + t->ascq = sense[13]; + } +} + +static ssize_t ub_diag_show(struct device *dev, char *page) +{ + struct usb_interface *intf; + struct ub_dev *sc; + int cnt; + unsigned long flags; + int nc, nh; + int i, j; + struct ub_scsi_cmd_trace *t; + + intf = to_usb_interface(dev); + sc = usb_get_intfdata(intf); + if (sc == NULL) + return 0; + + cnt = 0; + spin_lock_irqsave(&sc->lock, flags); + + cnt += sprintf(page + cnt, + "qlen %d qmax %d changed %d removable %d readonly %d\n", + sc->cmd_queue.qlen, sc->cmd_queue.qmax, + sc->changed, sc->removable, sc->readonly); + + if ((nc = sc->tr.cur + 1) == SCMD_TRACE_SZ) nc = 0; + for (j = 0; j < SCMD_TRACE_SZ; j++) { + t = &sc->tr.vec[nc]; + + cnt += sprintf(page + cnt, "%08x %02x", t->tag, t->op); + if (t->op == REQUEST_SENSE) { + cnt += sprintf(page + cnt, " [sense %x %02x %02x]", + t->key, t->asc, t->ascq); + } else { + cnt += sprintf(page + cnt, " %c", UB_DIR_CHAR(t->dir)); + cnt += sprintf(page + cnt, " [%5d %5d]", + t->req_size, t->act_size); + } + if ((nh = t->hcur + 1) == SCMD_ST_HIST_SZ) nh = 0; + for (i = 0; i < SCMD_ST_HIST_SZ; i++) { + cnt += sprintf(page + cnt, " %s", + ub_scsi_cmd_stname[(int)t->st_hst[nh]]); + if (++nh == SCMD_ST_HIST_SZ) nh = 0; + } + cnt += sprintf(page + cnt, "\n"); + + if (++nc == SCMD_TRACE_SZ) nc = 0; + } + + spin_unlock_irqrestore(&sc->lock, flags); + return cnt; +} + +static DEVICE_ATTR(diag, S_IRUGO, ub_diag_show, NULL); /* N.B. World readable */ + +/* + * The id allocator. + * + * This also stores the host for indexing by minor, which is somewhat dirty. + */ +static int ub_id_get(void) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&ub_lock, flags); + for (i = 0; i < UB_MAX_HOSTS; i++) { + if (ub_hostv[i] == 0) { + ub_hostv[i] = 1; + spin_unlock_irqrestore(&ub_lock, flags); + return i; + } + } + spin_unlock_irqrestore(&ub_lock, flags); + return -1; +} + +static void ub_id_put(int id) +{ + + if (id < 0 || id >= UB_MAX_HOSTS) { + printk(KERN_ERR DRV_NAME ": bad host ID %d\n", id); + return; + } + if (ub_hostv[id] == 0) { + printk(KERN_ERR DRV_NAME ": freeing free host ID %d\n", id); + return; + } + ub_hostv[id] = 0; +} + +/* + * Final cleanup and deallocation. + * This must be called with ub_lock taken. + */ +static void ub_cleanup(struct ub_dev *sc) +{ + ub_id_put(sc->id); + kfree(sc); +} + +/* + * The "command allocator". + */ +static struct ub_scsi_cmd *ub_get_cmd(struct ub_dev *sc) +{ + struct ub_scsi_cmd *ret; + + if (sc->cmda[0]) + return NULL; + ret = &sc->cmdv[0]; + sc->cmda[0] = 1; + return ret; +} + +static void ub_put_cmd(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + if (cmd != &sc->cmdv[0]) { + printk(KERN_WARNING "%s: releasing a foreign cmd %p\n", + sc->name, cmd); + return; + } + if (!sc->cmda[0]) { + printk(KERN_WARNING "%s: releasing a free cmd\n", sc->name); + return; + } + sc->cmda[0] = 0; +} + +/* + * The command queue. + */ +static void ub_cmdq_add(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct ub_scsi_cmd_queue *t = &sc->cmd_queue; + + if (t->qlen++ == 0) { + t->head = cmd; + t->tail = cmd; + } else { + t->tail->next = cmd; + t->tail = cmd; + } + + if (t->qlen > t->qmax) + t->qmax = t->qlen; +} + +static void ub_cmdq_insert(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct ub_scsi_cmd_queue *t = &sc->cmd_queue; + + if (t->qlen++ == 0) { + t->head = cmd; + t->tail = cmd; + } else { + cmd->next = t->head; + t->head = cmd; + } + + if (t->qlen > t->qmax) + t->qmax = t->qlen; +} + +static struct ub_scsi_cmd *ub_cmdq_pop(struct ub_dev *sc) +{ + struct ub_scsi_cmd_queue *t = &sc->cmd_queue; + struct ub_scsi_cmd *cmd; + + if (t->qlen == 0) + return NULL; + if (--t->qlen == 0) + t->tail = NULL; + cmd = t->head; + t->head = cmd->next; + cmd->next = NULL; + return cmd; +} + +#define ub_cmdq_peek(sc) ((sc)->cmd_queue.head) + +/* + * The request function is our main entry point + */ + +static inline int ub_bd_rq_fn_1(request_queue_t *q) +{ +#if 0 + int writing = 0, pci_dir, i, n_elem; + u32 tmp; + unsigned int msg_size; +#endif + struct ub_dev *sc = q->queuedata; + struct request *rq; +#if 0 /* We use rq->buffer for now */ + struct scatterlist *sg; + int n_elem; +#endif + struct ub_scsi_cmd *cmd; + int ub_dir; + unsigned int block, nblks; + int rc; + + if ((rq = elv_next_request(q)) == NULL) + return 1; + + if (atomic_read(&sc->poison) || sc->changed) { + blkdev_dequeue_request(rq); + ub_end_rq(rq, 0); + return 0; + } + + if ((cmd = ub_get_cmd(sc)) == NULL) { + blk_stop_queue(q); + return 1; + } + + blkdev_dequeue_request(rq); + + if (rq_data_dir(rq) == WRITE) + ub_dir = UB_DIR_WRITE; + else + ub_dir = UB_DIR_READ; + + /* + * get scatterlist from block layer + */ +#if 0 /* We use rq->buffer for now */ + sg = &cmd->sgv[0]; + n_elem = blk_rq_map_sg(q, rq, sg); + if (n_elem <= 0) { + ub_put_cmd(sc, cmd); + ub_end_rq(rq, 0); + blk_start_queue(q); + return 0; /* request with no s/g entries? */ + } + + if (n_elem != 1) { /* Paranoia */ + printk(KERN_WARNING "%s: request with %d segments\n", + sc->name, n_elem); + ub_put_cmd(sc, cmd); + ub_end_rq(rq, 0); + blk_start_queue(q); + return 0; + } +#endif + /* + * XXX Unfortunately, this check does not work. It is quite possible + * to get bogus non-null rq->buffer if you allow sg by mistake. + */ + if (rq->buffer == NULL) { + /* + * This must not happen if we set the queue right. + * The block level must create bounce buffers for us. + */ + static int do_print = 1; + if (do_print) { + printk(KERN_WARNING "%s: unmapped request\n", sc->name); + do_print = 0; + } + ub_put_cmd(sc, cmd); + ub_end_rq(rq, 0); + blk_start_queue(q); + return 0; + } + + /* + * build the command + */ + block = rq->sector; + nblks = rq->nr_sectors; + + memset(cmd, 0, sizeof(struct ub_scsi_cmd)); + cmd->cdb[0] = (ub_dir == UB_DIR_READ)? READ_10: WRITE_10; + /* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */ + cmd->cdb[2] = block >> 24; + cmd->cdb[3] = block >> 16; + cmd->cdb[4] = block >> 8; + cmd->cdb[5] = block; + cmd->cdb[7] = nblks >> 8; + cmd->cdb[8] = nblks; + cmd->cdb_len = 10; + cmd->dir = ub_dir; + cmd->state = UB_CMDST_INIT; + cmd->data = rq->buffer; + cmd->len = nblks * 512; + cmd->done = ub_rw_cmd_done; + cmd->back = rq; + + cmd->tag = sc->tagcnt++; + if ((rc = ub_submit_scsi(sc, cmd)) != 0) { + ub_put_cmd(sc, cmd); + ub_end_rq(rq, 0); + blk_start_queue(q); + return 0; + } + + return 0; +} + +static void ub_bd_rq_fn(request_queue_t *q) +{ + do { } while (ub_bd_rq_fn_1(q) == 0); +} + +static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct request *rq = cmd->back; + struct gendisk *disk = sc->disk; + request_queue_t *q = disk->queue; + int uptodate; + + if (cmd->error == 0) + uptodate = 1; + else + uptodate = 0; + + ub_put_cmd(sc, cmd); + ub_end_rq(rq, uptodate); + blk_start_queue(q); +} + +static void ub_end_rq(struct request *rq, int uptodate) +{ + int rc; + + rc = end_that_request_first(rq, uptodate, rq->hard_nr_sectors); + // assert(rc == 0); + end_that_request_last(rq); +} + +/* + * Submit a regular SCSI operation (not an auto-sense). + * + * The Iron Law of Good Submit Routine is: + * Zero return - callback is done, Nonzero return - callback is not done. + * No exceptions. + * + * Host is assumed locked. + * + * XXX We only support Bulk for the moment. + */ +static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + + if (cmd->state != UB_CMDST_INIT || + (cmd->dir != UB_DIR_NONE && cmd->len == 0)) { + return -EINVAL; + } + + ub_cmdq_add(sc, cmd); + /* + * We can call ub_scsi_dispatch(sc) right away here, but it's a little + * safer to jump to a tasklet, in case upper layers do something silly. + */ + tasklet_schedule(&sc->tasklet); + return 0; +} + +/* + * Submit the first URB for the queued command. + * This function does not deal with queueing in any way. + */ +static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct bulk_cb_wrap *bcb; + int rc; + + bcb = &sc->work_bcb; + + /* set up the command wrapper */ + bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); + bcb->Tag = cmd->tag; /* Endianness is not important */ + bcb->DataTransferLength = cpu_to_le32(cmd->len); + bcb->Flags = (cmd->dir == UB_DIR_READ) ? 0x80 : 0; + bcb->Lun = 0; /* No multi-LUN yet */ + bcb->Length = cmd->cdb_len; + + /* copy the command payload */ + memcpy(bcb->CDB, cmd->cdb, UB_MAX_CDB_SIZE); + + UB_INIT_COMPLETION(sc->work_done); + + sc->last_pipe = sc->send_bulk_pipe; + usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe, + bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc); + sc->work_urb.timeout = UB_URB_TIMEOUT; + + /* Fill what we shouldn't be filling, because usb-storage did so. */ + sc->work_urb.actual_length = 0; + sc->work_urb.error_count = 0; + sc->work_urb.status = 0; + + if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { + /* XXX Clear stalls */ + printk("ub: cmd #%d start failed (%d)\n", cmd->tag, rc); /* P3 */ + ub_complete(&sc->work_done); + return rc; + } + + cmd->state = UB_CMDST_CMD; + ub_cmdtr_state(sc, cmd); + return 0; +} + +/* + * Completion routine for the work URB. + * + * This can be called directly from usb_submit_urb (while we have + * the sc->lock taken) and from an interrupt (while we do NOT have + * the sc->lock taken). Therefore, bounce this off to a tasklet. + */ +static void ub_urb_complete(struct urb *urb, struct pt_regs *pt) +{ + struct ub_dev *sc = urb->context; + + ub_complete(&sc->work_done); + tasklet_schedule(&sc->tasklet); +} + +static void ub_scsi_action(unsigned long _dev) +{ + struct ub_dev *sc = (struct ub_dev *) _dev; + unsigned long flags; + + spin_lock_irqsave(&sc->lock, flags); + ub_scsi_dispatch(sc); + spin_unlock_irqrestore(&sc->lock, flags); +} + +static void ub_scsi_dispatch(struct ub_dev *sc) +{ + struct ub_scsi_cmd *cmd; + int rc; + + while ((cmd = ub_cmdq_peek(sc)) != NULL) { + if (cmd->state == UB_CMDST_DONE) { + ub_cmdq_pop(sc); + (*cmd->done)(sc, cmd); + } else if (cmd->state == UB_CMDST_INIT) { + ub_cmdtr_new(sc, cmd); + if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0) + break; + cmd->error = rc; + cmd->state = UB_CMDST_DONE; + ub_cmdtr_state(sc, cmd); + } else { + if (!ub_is_completed(&sc->work_done)) + break; + ub_scsi_urb_compl(sc, cmd); + } + } +} + +static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct urb *urb = &sc->work_urb; + struct bulk_cs_wrap *bcs; + int pipe; + int rc; + +/* P3 */ /** printk("ub: urb status %d pipe 0x%08x len %d act %d\n", + urb->status, urb->pipe, urb->transfer_buffer_length, urb->actual_length); **/ + + if (atomic_read(&sc->poison)) { + /* A little too simplistic, I feel... */ + goto Bad_End; + } + + if (cmd->state == UB_CMDST_CLEAR) { + if (urb->status == -EPIPE) { + /* + * STALL while clearning STALL. + * A STALL is illegal on a control pipe! + * XXX Might try to reset the device here and retry. + */ + printk(KERN_NOTICE "%s: " + "stall on control pipe for device %u\n", + sc->name, sc->dev->devnum); + goto Bad_End; + } + + /* + * We ignore the result for the halt clear. + */ + + /* reset the endpoint toggle */ + usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe), + usb_pipeout(sc->last_pipe), 0); + + ub_state_sense(sc, cmd); + + } else if (cmd->state == UB_CMDST_CLR2STS) { + if (urb->status == -EPIPE) { + /* + * STALL while clearning STALL. + * A STALL is illegal on a control pipe! + * XXX Might try to reset the device here and retry. + */ + printk(KERN_NOTICE "%s: " + "stall on control pipe for device %u\n", + sc->name, sc->dev->devnum); + goto Bad_End; + } + + /* + * We ignore the result for the halt clear. + */ + + /* reset the endpoint toggle */ + usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe), + usb_pipeout(sc->last_pipe), 0); + + ub_state_stat(sc, cmd); + + } else if (cmd->state == UB_CMDST_CMD) { + if (urb->status == -EPIPE) { + rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); + if (rc != 0) { + printk(KERN_NOTICE "%s: " + "unable to submit clear for device %u (%d)\n", + sc->name, sc->dev->devnum, rc); + /* + * This is typically ENOMEM or some other such shit. + * Retrying is pointless. Just do Bad End on it... + */ + goto Bad_End; + } + cmd->state = UB_CMDST_CLEAR; + ub_cmdtr_state(sc, cmd); + return; + } + if (urb->status != 0) + goto Bad_End; + if (urb->actual_length != US_BULK_CB_WRAP_LEN) { + /* XXX Must do reset here to unconfuse the device */ + goto Bad_End; + } + + if (cmd->dir == UB_DIR_NONE) { + ub_state_stat(sc, cmd); + return; + } + + UB_INIT_COMPLETION(sc->work_done); + + if (cmd->dir == UB_DIR_READ) + pipe = sc->recv_bulk_pipe; + else + pipe = sc->send_bulk_pipe; + sc->last_pipe = pipe; + usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe, + cmd->data, cmd->len, ub_urb_complete, sc); + sc->work_urb.timeout = UB_URB_TIMEOUT; + sc->work_urb.actual_length = 0; + sc->work_urb.error_count = 0; + sc->work_urb.status = 0; + + if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { + /* XXX Clear stalls */ + printk("ub: data #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */ + ub_complete(&sc->work_done); + ub_state_done(sc, cmd, rc); + return; + } + + cmd->state = UB_CMDST_DATA; + ub_cmdtr_state(sc, cmd); + + } else if (cmd->state == UB_CMDST_DATA) { + if (urb->status == -EPIPE) { + rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); + if (rc != 0) { + printk(KERN_NOTICE "%s: " + "unable to submit clear for device %u (%d)\n", + sc->name, sc->dev->devnum, rc); + /* + * This is typically ENOMEM or some other such shit. + * Retrying is pointless. Just do Bad End on it... + */ + goto Bad_End; + } + cmd->state = UB_CMDST_CLR2STS; + ub_cmdtr_state(sc, cmd); + return; + } + if (urb->status == -EOVERFLOW) { + /* + * A babble? Failure, but we must transfer CSW now. + */ + cmd->error = -EOVERFLOW; /* A cheap trick... */ + } else { + if (urb->status != 0) + goto Bad_End; + } + + cmd->act_len = urb->actual_length; + ub_cmdtr_act_len(sc, cmd); + + ub_state_stat(sc, cmd); + + } else if (cmd->state == UB_CMDST_STAT) { + if (urb->status == -EPIPE) { + rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); + if (rc != 0) { + printk(KERN_NOTICE "%s: " + "unable to submit clear for device %u (%d)\n", + sc->name, sc->dev->devnum, rc); + /* + * This is typically ENOMEM or some other such shit. + * Retrying is pointless. Just do Bad End on it... + */ + goto Bad_End; + } + cmd->state = UB_CMDST_CLEAR; + ub_cmdtr_state(sc, cmd); + return; + } + if (urb->status != 0) + goto Bad_End; + + if (urb->actual_length == 0) { + /* + * Some broken devices add unnecessary zero-length + * packets to the end of their data transfers. + * Such packets show up as 0-length CSWs. If we + * encounter such a thing, try to read the CSW again. + */ + if (++cmd->stat_count >= 4) { + printk(KERN_NOTICE "%s: " + "unable to get CSW on device %u\n", + sc->name, sc->dev->devnum); + goto Bad_End; + } + + /* + * ub_state_stat only not dropping the count... + */ + UB_INIT_COMPLETION(sc->work_done); + + sc->last_pipe = sc->recv_bulk_pipe; + usb_fill_bulk_urb(&sc->work_urb, sc->dev, + sc->recv_bulk_pipe, &sc->work_bcs, + US_BULK_CS_WRAP_LEN, ub_urb_complete, sc); + sc->work_urb.timeout = UB_URB_TIMEOUT; + sc->work_urb.actual_length = 0; + sc->work_urb.error_count = 0; + sc->work_urb.status = 0; + + rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC); + if (rc != 0) { + /* XXX Clear stalls */ + printk("%s: CSW #%d submit failed (%d)\n", + sc->name, cmd->tag, rc); /* P3 */ + ub_complete(&sc->work_done); + ub_state_done(sc, cmd, rc); + return; + } + return; + } + + /* + * Check the returned Bulk protocol status. + */ + + bcs = &sc->work_bcs; + rc = le32_to_cpu(bcs->Residue); + if (rc != cmd->len - cmd->act_len) { + /* + * It is all right to transfer less, the caller has + * to check. But it's not all right if the device + * counts disagree with our counts. + */ + /* P3 */ printk("%s: resid %d len %d act %d\n", + sc->name, rc, cmd->len, cmd->act_len); + goto Bad_End; + } + + if (bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN) && + bcs->Signature != cpu_to_le32(US_BULK_CS_OLYMPUS_SIGN)) { + /* XXX Rate-limit, even for P3 tagged */ + /* P3 */ printk("ub: signature 0x%x\n", bcs->Signature); + /* Windows ignores signatures, so do we. */ + } + + if (bcs->Tag != cmd->tag) { + /* P3 */ printk("%s: tag orig 0x%x reply 0x%x\n", + sc->name, cmd->tag, bcs->Tag); + goto Bad_End; + } + + switch (bcs->Status) { + case US_BULK_STAT_OK: + break; + case US_BULK_STAT_FAIL: + ub_state_sense(sc, cmd); + return; + case US_BULK_STAT_PHASE: + /* XXX We must reset the transport here */ + /* P3 */ printk("%s: status PHASE\n", sc->name); + goto Bad_End; + default: + printk(KERN_INFO "%s: unknown CSW status 0x%x\n", + sc->name, bcs->Status); + goto Bad_End; + } + + /* Not zeroing error to preserve a babble indicator */ + cmd->state = UB_CMDST_DONE; + ub_cmdtr_state(sc, cmd); + ub_cmdq_pop(sc); + (*cmd->done)(sc, cmd); + + } else if (cmd->state == UB_CMDST_SENSE) { + /* + * We do not look at sense, because even if there was no sense, + * we get into UB_CMDST_SENSE from a STALL or CSW FAIL only. + * We request sense because we want to clear CHECK CONDITION + * on devices with delusions of SCSI, and not because we + * are curious in any way about the sense itself. + */ + /* if ((cmd->top_sense[2] & 0x0F) == NO_SENSE) { foo } */ + + ub_state_done(sc, cmd, -EIO); + } else { + printk(KERN_WARNING "%s: " + "wrong command state %d on device %u\n", + sc->name, cmd->state, sc->dev->devnum); + goto Bad_End; + } + return; + +Bad_End: /* Little Excel is dead */ + ub_state_done(sc, cmd, -EIO); +} + +/* + * Factorization helper for the command state machine: + * Finish the command. + */ +static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc) +{ + + cmd->error = rc; + cmd->state = UB_CMDST_DONE; + ub_cmdtr_state(sc, cmd); + ub_cmdq_pop(sc); + (*cmd->done)(sc, cmd); +} + +/* + * Factorization helper for the command state machine: + * Submit a CSW read and go to STAT state. + */ +static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + int rc; + + UB_INIT_COMPLETION(sc->work_done); + + sc->last_pipe = sc->recv_bulk_pipe; + usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe, + &sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc); + sc->work_urb.timeout = UB_URB_TIMEOUT; + sc->work_urb.actual_length = 0; + sc->work_urb.error_count = 0; + sc->work_urb.status = 0; + + if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { + /* XXX Clear stalls */ + printk("ub: CSW #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */ + ub_complete(&sc->work_done); + ub_state_done(sc, cmd, rc); + return; + } + + cmd->stat_count = 0; + cmd->state = UB_CMDST_STAT; + ub_cmdtr_state(sc, cmd); +} + +/* + * Factorization helper for the command state machine: + * Submit a REQUEST SENSE and go to SENSE state. + */ +static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct ub_scsi_cmd *scmd; + int rc; + + if (cmd->cdb[0] == REQUEST_SENSE) { + rc = -EPIPE; + goto error; + } + + memset(&sc->top_sense, 0, UB_SENSE_SIZE); + scmd = &sc->top_rqs_cmd; + scmd->cdb[0] = REQUEST_SENSE; + scmd->cdb_len = 6; + scmd->dir = UB_DIR_READ; + scmd->state = UB_CMDST_INIT; + scmd->data = sc->top_sense; + scmd->len = UB_SENSE_SIZE; + scmd->done = ub_top_sense_done; + scmd->back = cmd; + + scmd->tag = sc->tagcnt++; + + cmd->state = UB_CMDST_SENSE; + ub_cmdtr_state(sc, cmd); + + ub_cmdq_insert(sc, scmd); + return; + +error: + ub_state_done(sc, cmd, rc); +} + +/* + * A helper for the command's state machine: + * Submit a stall clear. + */ +static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, + int stalled_pipe) +{ + int endp; + struct usb_ctrlrequest *cr; + int rc; + + endp = usb_pipeendpoint(stalled_pipe); + if (usb_pipein (stalled_pipe)) + endp |= USB_DIR_IN; + + cr = &sc->work_cr; + cr->bRequestType = USB_RECIP_ENDPOINT; + cr->bRequest = USB_REQ_CLEAR_FEATURE; + cr->wValue = cpu_to_le16(USB_ENDPOINT_HALT); + cr->wIndex = cpu_to_le16(endp); + cr->wLength = cpu_to_le16(0); + + UB_INIT_COMPLETION(sc->work_done); + + usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, + (unsigned char*) cr, NULL, 0, + ub_urb_complete, sc); + sc->work_urb.timeout = UB_CTRL_TIMEOUT; + sc->work_urb.actual_length = 0; + sc->work_urb.error_count = 0; + sc->work_urb.status = 0; + + if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { + ub_complete(&sc->work_done); + return rc; + } + return 0; +} + +/* + */ +static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd) +{ + unsigned char *sense = scmd->data; + struct ub_scsi_cmd *cmd; + + ub_cmdtr_sense(sc, scmd, sense); + + if ((cmd = ub_cmdq_peek(sc)) == NULL) { + printk(KERN_WARNING "%s: sense done while idle\n", sc->name); + return; + } + if (cmd != scmd->back) { + printk(KERN_WARNING "%s: " + "sense done for wrong command 0x%x on device %u\n", + sc->name, cmd->tag, sc->dev->devnum); + return; + } + if (cmd->state != UB_CMDST_SENSE) { + printk(KERN_WARNING "%s: " + "sense done with bad cmd state %d on device %u\n", + sc->name, cmd->state, sc->dev->devnum); + return; + } + + ub_scsi_urb_compl(sc, cmd); +} + +#if 0 +/* Determine what the maximum LUN supported is */ +int usb_stor_Bulk_max_lun(struct us_data *us) +{ + int result; + + /* issue the command */ + result = usb_stor_control_msg(us, us->recv_ctrl_pipe, + US_BULK_GET_MAX_LUN, + USB_DIR_IN | USB_TYPE_CLASS | + USB_RECIP_INTERFACE, + 0, us->ifnum, us->iobuf, 1, HZ); + + /* + * Some devices (i.e. Iomega Zip100) need this -- apparently + * the bulk pipes get STALLed when the GetMaxLUN request is + * processed. This is, in theory, harmless to all other devices + * (regardless of if they stall or not). + */ + if (result < 0) { + usb_stor_clear_halt(us, us->recv_bulk_pipe); + usb_stor_clear_halt(us, us->send_bulk_pipe); + } + + US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", + result, us->iobuf[0]); + + /* if we have a successful request, return the result */ + if (result == 1) + return us->iobuf[0]; + + /* return the default -- no LUNs */ + return 0; +} +#endif + +/* + * This is called from a process context. + */ +static void ub_revalidate(struct ub_dev *sc) +{ + + sc->readonly = 0; /* XXX Query this from the device */ + + /* + * XXX sd.c sets capacity to zero in such case. However, it doesn't + * work for us. In case of zero capacity, block layer refuses to + * have the /dev/uba opened (why?) Set capacity to some random value. + */ + sc->capacity.nsec = 50; + sc->capacity.bsize = 512; + sc->capacity.bshift = 0; + + if (ub_sync_tur(sc) != 0) + return; /* Not ready */ + sc->changed = 0; + + if (ub_sync_read_cap(sc, &sc->capacity) != 0) { + /* + * The retry here means something is wrong, either with the + * device, with the transport, or with our code. + * We keep this because sd.c has retries for capacity. + */ + if (ub_sync_read_cap(sc, &sc->capacity) != 0) { + sc->capacity.nsec = 100; + sc->capacity.bsize = 512; + sc->capacity.bshift = 0; + } + } +} + +/* + * The open funcion. + * This is mostly needed to keep refcounting, but also to support + * media checks on removable media drives. + */ +static int ub_bd_open(struct inode *inode, struct file *filp) +{ + struct gendisk *disk = inode->i_bdev->bd_disk; + struct ub_dev *sc; + unsigned long flags; + int rc; + + if ((sc = disk->private_data) == NULL) + return -ENXIO; + spin_lock_irqsave(&ub_lock, flags); + if (atomic_read(&sc->poison)) { + spin_unlock_irqrestore(&ub_lock, flags); + return -ENXIO; + } + sc->openc++; + spin_unlock_irqrestore(&ub_lock, flags); + + if (sc->removable || sc->readonly) + check_disk_change(inode->i_bdev); + + /* XXX sd.c and floppy.c bail on open if media is not present. */ + + if (sc->readonly && (filp->f_mode & FMODE_WRITE)) { + rc = -EROFS; + goto err_open; + } + + return 0; + +err_open: + spin_lock_irqsave(&ub_lock, flags); + --sc->openc; + if (sc->openc == 0 && atomic_read(&sc->poison)) + ub_cleanup(sc); + spin_unlock_irqrestore(&ub_lock, flags); + return rc; +} + +/* + */ +static int ub_bd_release(struct inode *inode, struct file *filp) +{ + struct gendisk *disk = inode->i_bdev->bd_disk; + struct ub_dev *sc = disk->private_data; + unsigned long flags; + + spin_lock_irqsave(&ub_lock, flags); + --sc->openc; + if (sc->openc == 0 && atomic_read(&sc->poison)) + ub_cleanup(sc); + spin_unlock_irqrestore(&ub_lock, flags); + return 0; +} + +/* + * The ioctl interface. + */ +static int ub_bd_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ +// void __user *usermem = (void *) arg; +// struct carm_port *port = ino->i_bdev->bd_disk->private_data; +// struct hd_geometry geom; + +#if 0 + switch (cmd) { + case HDIO_GETGEO: + if (usermem == NULL) // XXX Bizzare. Why? + return -EINVAL; + + geom.heads = (u8) port->dev_geom_head; + geom.sectors = (u8) port->dev_geom_sect; + geom.cylinders = port->dev_geom_cyl; + geom.start = get_start_sect(ino->i_bdev); + + if (copy_to_user(usermem, &geom, sizeof(geom))) + return -EFAULT; + return 0; + + default: ; + } +#endif + + return -ENOTTY; +} + +/* + * This is called once a new disk was seen by the block layer or by ub_probe(). + * The main onjective here is to discover the features of the media such as + * the capacity, read-only status, etc. USB storage generally does not + * need to be spun up, but if we needed it, this would be the place. + * + * This call can sleep. + * + * The return code is not used. + */ +static int ub_bd_revalidate(struct gendisk *disk) +{ + struct ub_dev *sc = disk->private_data; + + ub_revalidate(sc); + /* This is pretty much a long term P3 */ + printk(KERN_INFO "%s: device %u capacity nsec %ld bsize %u\n", + sc->name, sc->dev->devnum, sc->capacity.nsec, sc->capacity.bsize); + + set_capacity(disk, sc->capacity.nsec); + // set_disk_ro(sdkp->disk, sc->readonly); + return 0; +} + +/* + * The check is called by the block layer to verify if the media + * is still available. It is supposed to be harmless, lightweight and + * non-intrusive in case the media was not changed. + * + * This call can sleep. + * + * The return code is bool! + */ +static int ub_bd_media_changed(struct gendisk *disk) +{ + struct ub_dev *sc = disk->private_data; + + if (!sc->removable) + return 0; + + /* + * We clean checks always after every command, so this is not + * as dangerous as it looks. If the TEST_UNIT_READY fails here, + * the device is actually not ready with operator or software + * intervention required. One dangerous item might be a drive which + * spins itself down, and come the time to write dirty pages, this + * will fail, then block layer discards the data. Since we never + * spin drives up, such devices simply cannot be used with ub anyway. + */ + if (ub_sync_tur(sc) != 0) { + sc->changed = 1; + /* P3 */ printk("%s: made changed\n", sc->name); + return 1; + } + + /* The sd.c clears this before returning (one-shot flag). Why? */ + /* P3 */ printk("%s: %s changed\n", sc->name, + sc->changed? "is": "was not"); + return sc->changed; +} + +static struct block_device_operations ub_bd_fops = { + .owner = THIS_MODULE, + .open = ub_bd_open, + .release = ub_bd_release, + .ioctl = ub_bd_ioctl, + .media_changed = ub_bd_media_changed, + .revalidate_disk = ub_bd_revalidate, +}; + +/* + * Common ->done routine for commands executed synchronously. + */ +static void ub_probe_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + struct completion *cop = cmd->back; + complete(cop); +} + +/* + * Test if the device has a check condition on it, synchronously. + */ +static int ub_sync_tur(struct ub_dev *sc) +{ + struct ub_scsi_cmd *cmd; + enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) }; + unsigned long flags; + struct completion compl; + int rc; + + init_completion(&compl); + + rc = -ENOMEM; + if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL) + goto err_alloc; + memset(cmd, 0, ALLOC_SIZE); + + cmd->cdb[0] = TEST_UNIT_READY; + cmd->cdb_len = 6; + cmd->dir = UB_DIR_NONE; + cmd->state = UB_CMDST_INIT; + cmd->done = ub_probe_done; + cmd->back = &compl; + + spin_lock_irqsave(&sc->lock, flags); + cmd->tag = sc->tagcnt++; + + rc = ub_submit_scsi(sc, cmd); + spin_unlock_irqrestore(&sc->lock, flags); + + if (rc != 0) { + printk("ub: testing ready: submit error (%d)\n", rc); /* P3 */ + goto err_submit; + } + + wait_for_completion(&compl); + + rc = cmd->error; + +err_submit: + kfree(cmd); +err_alloc: + return rc; +} + +/* + * Read the SCSI capacity synchronously (for probing). + */ +static int ub_sync_read_cap(struct ub_dev *sc, struct ub_capacity *ret) +{ + struct ub_scsi_cmd *cmd; + char *p; + enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) + 8 }; + unsigned long flags; + unsigned int bsize, shift; + unsigned long nsec; + struct completion compl; + int rc; + + init_completion(&compl); + + rc = -ENOMEM; + if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL) + goto err_alloc; + memset(cmd, 0, ALLOC_SIZE); + p = (char *)cmd + sizeof(struct ub_scsi_cmd); + + cmd->cdb[0] = 0x25; + cmd->cdb_len = 10; + cmd->dir = UB_DIR_READ; + cmd->state = UB_CMDST_INIT; + cmd->data = p; + cmd->len = 8; + cmd->done = ub_probe_done; + cmd->back = &compl; + + spin_lock_irqsave(&sc->lock, flags); + cmd->tag = sc->tagcnt++; + + rc = ub_submit_scsi(sc, cmd); + spin_unlock_irqrestore(&sc->lock, flags); + + if (rc != 0) { + printk("ub: reading capacity: submit error (%d)\n", rc); /* P3 */ + goto err_submit; + } + + wait_for_completion(&compl); + + if (cmd->error != 0) { + printk("ub: reading capacity: error %d\n", cmd->error); /* P3 */ + rc = -EIO; + goto err_read; + } + if (cmd->act_len != 8) { + printk("ub: reading capacity: size %d\n", cmd->act_len); /* P3 */ + rc = -EIO; + goto err_read; + } + + /* sd.c special-cases sector size of 0 to mean 512. Needed? Safe? */ + nsec = be32_to_cpu(*(u32 *)p) + 1; + bsize = be32_to_cpu(*(u32 *)(p + 4)); + switch (bsize) { + case 512: shift = 0; break; + case 1024: shift = 1; break; + case 2048: shift = 2; break; + case 4096: shift = 3; break; + default: + printk("ub: Bad sector size %u\n", bsize); /* P3 */ + rc = -EDOM; + goto err_inv_bsize; + } + + ret->bsize = bsize; + ret->bshift = shift; + ret->nsec = nsec << shift; + rc = 0; + +err_inv_bsize: +err_read: +err_submit: + kfree(cmd); +err_alloc: + return rc; +} + +/* + */ +static void ub_probe_urb_complete(struct urb *urb, struct pt_regs *pt) +{ + struct completion *cop = urb->context; + complete(cop); +} + +/* + * Clear initial stalls. + */ +static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe) +{ + int endp; + struct usb_ctrlrequest *cr; + struct completion compl; + int rc; + + init_completion(&compl); + + endp = usb_pipeendpoint(stalled_pipe); + if (usb_pipein (stalled_pipe)) + endp |= USB_DIR_IN; + + cr = &sc->work_cr; + cr->bRequestType = USB_RECIP_ENDPOINT; + cr->bRequest = USB_REQ_CLEAR_FEATURE; + cr->wValue = cpu_to_le16(USB_ENDPOINT_HALT); + cr->wIndex = cpu_to_le16(endp); + cr->wLength = cpu_to_le16(0); + + usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, + (unsigned char*) cr, NULL, 0, + ub_probe_urb_complete, &compl); + sc->work_urb.timeout = UB_CTRL_TIMEOUT; + sc->work_urb.actual_length = 0; + sc->work_urb.error_count = 0; + sc->work_urb.status = 0; + + if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) { + printk(KERN_WARNING + "%s: Unable to submit a probe clear (%d)\n", sc->name, rc); + return rc; + } + + wait_for_completion(&compl); + + /* reset the endpoint toggle */ + usb_settoggle(sc->dev, endp, usb_pipeout(sc->last_pipe), 0); + + return 0; +} + +/* + * Get the pipe settings. + */ +static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev, + struct usb_interface *intf) +{ + struct usb_host_interface *altsetting = intf->cur_altsetting; + struct usb_endpoint_descriptor *ep_in = NULL; + struct usb_endpoint_descriptor *ep_out = NULL; + struct usb_endpoint_descriptor *ep; + int i; + + /* + * Find the endpoints we need. + * We are expecting a minimum of 2 endpoints - in and out (bulk). + * We will ignore any others. + */ + for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { + ep = &altsetting->endpoint[i].desc; + + /* Is it a BULK endpoint? */ + if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_BULK) { + /* BULK in or out? */ + if (ep->bEndpointAddress & USB_DIR_IN) + ep_in = ep; + else + ep_out = ep; + } + } + + if (ep_in == NULL || ep_out == NULL) { + printk(KERN_NOTICE "%s: device %u failed endpoint check\n", + sc->name, sc->dev->devnum); + return -EIO; + } + + /* Calculate and store the pipe values */ + sc->send_ctrl_pipe = usb_sndctrlpipe(dev, 0); + sc->recv_ctrl_pipe = usb_rcvctrlpipe(dev, 0); + sc->send_bulk_pipe = usb_sndbulkpipe(dev, + ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + sc->recv_bulk_pipe = usb_rcvbulkpipe(dev, + ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + + return 0; +} + +/* + * Probing is done in the process context, which allows us to cheat + * and not to build a state machine for the discovery. + */ +static int ub_probe(struct usb_interface *intf, + const struct usb_device_id *dev_id) +{ + struct ub_dev *sc; + request_queue_t *q; + struct gendisk *disk; + int rc; + + rc = -ENOMEM; + if ((sc = kmalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL) + goto err_core; + memset(sc, 0, sizeof(struct ub_dev)); + spin_lock_init(&sc->lock); + usb_init_urb(&sc->work_urb); + tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc); + atomic_set(&sc->poison, 0); + + ub_init_completion(&sc->work_done); + sc->work_done.done = 1; /* A little yuk, but oh well... */ + + rc = -ENOSR; + if ((sc->id = ub_id_get()) == -1) + goto err_id; + snprintf(sc->name, 8, DRV_NAME "%c", sc->id + 'a'); + + sc->dev = interface_to_usbdev(intf); + sc->intf = intf; + // sc->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; + + usb_set_intfdata(intf, sc); + usb_get_dev(sc->dev); + // usb_get_intf(sc->intf); /* Do we need this? */ + + /* XXX Verify that we can handle the device (from descriptors) */ + + ub_get_pipes(sc, sc->dev, intf); + + if (device_create_file(&sc->intf->dev, &dev_attr_diag) != 0) + goto err_diag; + + /* + * At this point, all USB initialization is done, do upper layer. + * We really hate halfway initialized structures, so from the + * invariants perspective, this ub_dev is fully constructed at + * this point. + */ + + /* + * This is needed to clear toggles. It is a problem only if we do + * `rmmod ub && modprobe ub` without disconnects, but we like that. + */ + ub_probe_clear_stall(sc, sc->recv_bulk_pipe); + ub_probe_clear_stall(sc, sc->send_bulk_pipe); + + /* + * The way this is used by the startup code is a little specific. + * A SCSI check causes a USB stall. Our common case code sees it + * and clears the check, after which the device is ready for use. + * But if a check was not present, any command other than + * TEST_UNIT_READY ends with a lockup (including REQUEST_SENSE). + * + * If we neglect to clear the SCSI check, the first real command fails + * (which is the capacity readout). We clear that and retry, but why + * causing spurious retries for no reason. + * + * Revalidation may start with its own TEST_UNIT_READY, but that one + * has to succeed, so we clear checks with an additional one here. + * In any case it's not our business how revaliadation is implemented. + */ + ub_sync_tur(sc); + + sc->removable = 1; /* XXX Query this from the device */ + + ub_revalidate(sc); + /* This is pretty much a long term P3 */ + printk(KERN_INFO "%s: device %u capacity nsec %ld bsize %u\n", + sc->name, sc->dev->devnum, sc->capacity.nsec, sc->capacity.bsize); + + /* + * Just one disk per sc currently, but maybe more. + */ + rc = -ENOMEM; + if ((disk = alloc_disk(UB_MINORS_PER_MAJOR)) == NULL) + goto err_diskalloc; + + sc->disk = disk; + sprintf(disk->disk_name, DRV_NAME "%c", sc->id + 'a'); + sprintf(disk->devfs_name, DEVFS_NAME "/%c", sc->id + 'a'); + disk->major = UB_MAJOR; + disk->first_minor = sc->id * UB_MINORS_PER_MAJOR; + disk->fops = &ub_bd_fops; + disk->private_data = sc; + disk->driverfs_dev = &intf->dev; + + rc = -ENOMEM; + if ((q = blk_init_queue(ub_bd_rq_fn, &sc->lock)) == NULL) + goto err_blkqinit; + + disk->queue = q; + + // blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask); + blk_queue_max_hw_segments(q, UB_MAX_REQ_SG); + blk_queue_max_phys_segments(q, UB_MAX_REQ_SG); + // blk_queue_segment_boundary(q, CARM_SG_BOUNDARY); + blk_queue_max_sectors(q, UB_MAX_SECTORS); + // blk_queue_hardsect_size(q, xxxxx); + + /* + * This is a serious infraction, caused by a deficiency in the + * USB sg interface (usb_sg_wait()). We plan to remove this once + * we get mileage on the driver and can justify a change to USB API. + * See blk_queue_bounce_limit() to understand this part. + * + * XXX And I still need to be aware of the DMA mask in the HC. + */ + q->bounce_pfn = blk_max_low_pfn; + q->bounce_gfp = GFP_NOIO; + + q->queuedata = sc; + + set_capacity(disk, sc->capacity.nsec); + if (sc->removable) + disk->flags |= GENHD_FL_REMOVABLE; + + add_disk(disk); + + return 0; + +err_blkqinit: + put_disk(disk); +err_diskalloc: + device_remove_file(&sc->intf->dev, &dev_attr_diag); +err_diag: + usb_set_intfdata(intf, NULL); + // usb_put_intf(sc->intf); + usb_put_dev(sc->dev); + spin_lock_irq(&ub_lock); + ub_id_put(sc->id); + spin_unlock_irq(&ub_lock); +err_id: + kfree(sc); +err_core: + return rc; +} + +static void ub_disconnect(struct usb_interface *intf) +{ + struct ub_dev *sc = usb_get_intfdata(intf); + struct gendisk *disk = sc->disk; + request_queue_t *q = disk->queue; + unsigned long flags; + + /* + * Fence stall clearnings, operations triggered by unlinkings and so on. + * We do not attempt to unlink any URBs, because we do not trust the + * unlink paths in HC drivers. Also, we get -84 upon disconnect anyway. + */ + atomic_set(&sc->poison, 1); + + /* + * Blow away queued commands. + * + * Actually, this never works, because before we get here + * the HCD terminates outstanding URB(s). It causes our + * SCSI command queue to advance, commands fail to submit, + * and the whole queue drains. So, we just use this code to + * print warnings. + */ + spin_lock_irqsave(&sc->lock, flags); + { + struct ub_scsi_cmd *cmd; + int cnt = 0; + while ((cmd = ub_cmdq_pop(sc)) != NULL) { + cmd->error = -ENOTCONN; + cmd->state = UB_CMDST_DONE; + ub_cmdtr_state(sc, cmd); + ub_cmdq_pop(sc); + (*cmd->done)(sc, cmd); + cnt++; + } + if (cnt != 0) { + printk(KERN_WARNING "%s: " + "%d was queued after shutdown\n", sc->name, cnt); + } + } + spin_unlock_irqrestore(&sc->lock, flags); + + /* + * Unregister the upper layer, this waits for all commands to end. + */ + if (disk->flags & GENHD_FL_UP) + del_gendisk(disk); + if (q) + blk_cleanup_queue(q); + + /* + * If we zero disk->private_data BEFORE put_disk, we have to check + * for NULL all over the place in open, release, check_media and + * revalidate, because the block level semaphore is well inside the + * put_disk. But we cannot zero after the call, because *disk is gone. + * The sd.c is blatantly racy in this area. + */ + /* disk->private_data = NULL; */ + put_disk(disk); + sc->disk = NULL; + + /* + * We really expect blk_cleanup_queue() to wait, so no amount + * of paranoya is too much. + * + * Taking a lock on a structure which is about to be freed + * is very nonsensual. Here it is largely a way to do a debug freeze, + * and a bracket which shows where the nonsensual code segment ends. + * + * Testing for -EINPROGRESS is always a bug, so we are bending + * the rules a little. + */ + spin_lock_irqsave(&sc->lock, flags); + if (sc->work_urb.status == -EINPROGRESS) { /* janitors: ignore */ + printk(KERN_WARNING "%s: " + "URB is active after disconnect\n", sc->name); + } + spin_unlock_irqrestore(&sc->lock, flags); + + /* + * At this point there must be no commands coming from anyone + * and no URBs left in transit. + */ + + device_remove_file(&sc->intf->dev, &dev_attr_diag); + usb_set_intfdata(intf, NULL); + // usb_put_intf(sc->intf); + sc->intf = NULL; + usb_put_dev(sc->dev); + sc->dev = NULL; + + spin_lock_irqsave(&ub_lock, flags); + if (sc->openc == 0) + ub_cleanup(sc); + spin_unlock_irqrestore(&ub_lock, flags); +} + +struct usb_driver ub_driver = { + .owner = THIS_MODULE, + .name = "ub", + .probe = ub_probe, + .disconnect = ub_disconnect, + .id_table = ub_usb_ids, +}; + +static int __init ub_init(void) +{ + int rc; + + /* P3 */ printk("ub: sizeof ub_scsi_cmd %zu ub_dev %zu\n", + sizeof(struct ub_scsi_cmd), sizeof(struct ub_dev)); + + if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0) + goto err_regblkdev; + devfs_mk_dir(DEVFS_NAME); + + if ((rc = usb_register(&ub_driver)) != 0) + goto err_register; + + return 0; + +err_register: + devfs_remove(DEVFS_NAME); + unregister_blkdev(UB_MAJOR, DRV_NAME); +err_regblkdev: + return rc; +} + +static void __exit ub_exit(void) +{ + usb_deregister(&ub_driver); + + devfs_remove(DEVFS_NAME); + unregister_blkdev(UB_MAJOR, DRV_NAME); +} + +module_init(ub_init); +module_exit(ub_exit); + +MODULE_LICENSE("GPL"); diff -Nru a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c --- a/drivers/isdn/hisax/st5481_usb.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/isdn/hisax/st5481_usb.c 2004-08-18 23:28:03 -07:00 @@ -143,9 +143,6 @@ if (ctrl_msg->dr.bRequest == USB_REQ_CLEAR_FEATURE) { /* Special case handling for pipe reset */ le16_to_cpus(&ctrl_msg->dr.wIndex); - usb_endpoint_running(adapter->usb_dev, - ctrl_msg->dr.wIndex & ~USB_DIR_IN, - (ctrl_msg->dr.wIndex & USB_DIR_IN) == 0); /* toggle is reset on clear */ usb_settoggle(adapter->usb_dev, diff -Nru a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c --- a/drivers/usb/class/audio.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/class/audio.c 2004-08-18 23:28:03 -07:00 @@ -1954,9 +1954,9 @@ struct usb_audio_state *s; down(&open_sem); - for (devs = audiodevs.next; devs != &audiodevs; devs = devs->next) { + list_for_each(devs, &audiodevs) { s = list_entry(devs, struct usb_audio_state, audiodev); - for (mdevs = s->mixerlist.next; mdevs != &s->mixerlist; mdevs = mdevs->next) { + list_for_each(mdevs, &s->mixerlist) { ms = list_entry(mdevs, struct usb_mixerdev, list); if (ms->dev_mixer == minor) goto mixer_found; @@ -2640,9 +2640,9 @@ for (;;) { down(&open_sem); - for (devs = audiodevs.next; devs != &audiodevs; devs = devs->next) { + list_for_each(devs, &audiodevs) { s = list_entry(devs, struct usb_audio_state, audiodev); - for (adevs = s->audiolist.next; adevs != &s->audiolist; adevs = adevs->next) { + list_for_each(adevs, &s->audiolist) { as = list_entry(adevs, struct usb_audiodev, list); if (!((as->dev_audio ^ minor) & ~0xf)) goto device_found; @@ -3831,7 +3831,7 @@ usb_set_intfdata (intf, NULL); /* deregister all audio and mixer devices, so no new processes can open this device */ - for(list = s->audiolist.next; list != &s->audiolist; list = list->next) { + list_for_each(list, &s->audiolist) { as = list_entry(list, struct usb_audiodev, list); usbin_disc(as); usbout_disc(as); @@ -3843,7 +3843,7 @@ } as->dev_audio = -1; } - for(list = s->mixerlist.next; list != &s->mixerlist; list = list->next) { + list_for_each(list, &s->mixerlist) { ms = list_entry(list, struct usb_mixerdev, list); if (ms->dev_mixer >= 0) { unregister_sound_mixer(ms->dev_mixer); diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c --- a/drivers/usb/class/cdc-acm.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/class/cdc-acm.c 2004-08-18 23:28:03 -07:00 @@ -583,19 +583,25 @@ } if (!union_header) { - dev_dbg(&intf->dev,"No union descriptor, giving up\n"); - return -ENODEV; - } - - control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); - data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); - if (!control_interface || !data_interface) { - dev_dbg(&intf->dev,"no interfaces\n"); - return -ENODEV; + if (call_interface_num > 0) { + dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n"); + data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); + control_interface = intf; + } else { + dev_dbg(&intf->dev,"No union descriptor, giving up\n"); + return -ENODEV; + } + } else { + control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); + data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); + if (!control_interface || !data_interface) { + dev_dbg(&intf->dev,"no interfaces\n"); + return -ENODEV; + } } - if (data_interface_num != call_interface_num) - dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported."); + if (data_interface_num != call_interface_num) + dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported."); if (usb_interface_claimed(data_interface)) { /* valid in this context */ dev_dbg(&intf->dev,"The data interface isn't available\n"); diff -Nru a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c --- a/drivers/usb/class/usb-midi.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/class/usb-midi.c 2004-08-18 23:28:03 -07:00 @@ -55,39 +55,39 @@ /* ------------------------------------------------------------------------- */ static int singlebyte = 0; -MODULE_PARM(singlebyte,"i"); +module_param(singlebyte, int, 0); MODULE_PARM_DESC(singlebyte,"Enable sending MIDI messages with single message packet"); static int maxdevices = 4; -MODULE_PARM(maxdevices,"i"); +module_param(maxdevices, int, 0); MODULE_PARM_DESC(maxdevices,"Max number of allocatable MIDI device"); static int uvendor = -1; -MODULE_PARM(uvendor,"i"); +module_param(uvendor, int, 0); MODULE_PARM_DESC(uvendor, "The USB Vendor ID of a semi-compliant interface"); static int uproduct = -1; -MODULE_PARM(uproduct,"i"); +module_param(uproduct, int, 0); MODULE_PARM_DESC(uproduct, "The USB Product ID of a semi-compliant interface"); static int uinterface = -1; -MODULE_PARM(uinterface,"i"); +module_param(uinterface, int, 0); MODULE_PARM_DESC(uinterface, "The Interface number of a semi-compliant interface"); static int ualt = -1; -MODULE_PARM(ualt,"i"); +module_param(ualt, int, 0); MODULE_PARM_DESC(ualt, "The optional alternative setting of a semi-compliant interface"); static int umin = -1; -MODULE_PARM(umin,"i"); +module_param(umin, int, 0); MODULE_PARM_DESC(umin, "The input endpoint of a semi-compliant interface"); static int umout = -1; -MODULE_PARM(umout,"i"); +module_param(umout, int, 0); MODULE_PARM_DESC(umout, "The output endpoint of a semi-compliant interface"); static int ucable = -1; -MODULE_PARM(ucable,"i"); +module_param(ucable, int, 0); MODULE_PARM_DESC(ucable, "The cable number used for a semi-compliant interface"); /** Note -- the usb_string() returns only Latin-1 characters. @@ -95,7 +95,7 @@ * unicode16LE-to-JIS routine is needed to wrap around usb_get_string(). **/ static unsigned short ulangid = 0x0409; /** 0x0411 for Japanese **/ -MODULE_PARM(ulangid,"h"); +module_param(ulangid, ushort, 0); MODULE_PARM_DESC(ulangid, "The optional preferred USB Language ID for all devices"); MODULE_AUTHOR("NAGANO Daisuke "); @@ -817,9 +817,9 @@ for(;;) { down(&open_sem); - for (devs = mididevs.next; devs != &mididevs; devs = devs->next) { + list_for_each(devs, &mididevs) { s = list_entry(devs, struct usb_midi_state, mididev); - for (mdevs = s->midiDevList.next; mdevs != &s->midiDevList; mdevs = mdevs->next) { + list_for_each(mdevs, &s->midiDevList) { m = list_entry(mdevs, struct usb_mididev, list); if ( !((m->dev_midi ^ minor) & ~0xf) ) goto device_found; @@ -2012,7 +2012,7 @@ s->usbdev = NULL; usb_set_intfdata (intf, NULL); - for ( list = s->midiDevList.next; list != &s->midiDevList; list = list->next ) { + list_for_each(list, &s->midiDevList) { m = list_entry(list, struct usb_mididev, list); wake_up(&(m->min.ep->wait)); wake_up(&(m->mout.ep->wait)); diff -Nru a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c --- a/drivers/usb/class/usblp.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/class/usblp.c 2004-08-18 23:28:03 -07:00 @@ -221,7 +221,7 @@ static int usblp_cache_device_id_string(struct usblp *usblp); /* forward reference to make our lives easier */ -extern struct usb_driver usblp_driver; +static struct usb_driver usblp_driver; /* * Functions for usblp control messages. @@ -1208,6 +1208,6 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_PARM(proto_bias, "i"); +module_param(proto_bias, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(proto_bias, "Favourite protocol number"); MODULE_LICENSE("GPL"); diff -Nru a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig --- a/drivers/usb/core/Kconfig 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/core/Kconfig 2004-08-18 23:28:03 -07:00 @@ -60,3 +60,14 @@ If you are unsure about this, say N here. +config USB_SUSPEND + bool "USB suspend/resume (EXPERIMENTAL)" + depends on USB && PM && EXPERIMENTAL + help + If you say Y here, you can use driver calls or the sysfs + "power/state" file to suspend or resume individual USB + peripherals. There are many related features, such as + remote wakeup and driver-specific suspend processing, that + may not yet work as expected. + + If you are unsure about this, say N here. diff -Nru a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c --- a/drivers/usb/core/devices.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/core/devices.c 2004-08-18 23:28:03 -07:00 @@ -283,9 +283,8 @@ /* TBD: * 0. TBDs - * 1. marking active config and ifaces (code lists all, but should mark + * 1. marking active interface altsettings (code lists all, but should mark * which ones are active, if any) - * 2. add status to each endpoint line */ static char *usb_dump_config_descriptor(char *start, char *end, const struct usb_config_descriptor *desc, int active) @@ -584,7 +583,7 @@ /* enumerate busses */ down (&usb_bus_list_lock); - for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) { + list_for_each(buslist, &usb_bus_list) { /* print devices for this bus */ bus = list_entry(buslist, struct usb_bus, bus_list); diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c --- a/drivers/usb/core/devio.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/core/devio.c 2004-08-18 23:28:03 -07:00 @@ -72,6 +72,8 @@ } while (0) +#define MAX_USBFS_BUFFER_SIZE 16384 + static inline int connected (struct usb_device *dev) { return dev->state != USB_STATE_NOTATTACHED; @@ -555,8 +557,10 @@ snoop(&dev->dev, "control read: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n", ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex); + up(&dev->serialize); i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo); + down(&dev->serialize); if ((i > 0) && ctrl.wLength) { if (usbfs_snoop) { dev_info(&dev->dev, "control read: data "); @@ -584,8 +588,10 @@ printk ("%02x ", (unsigned char)(tbuf)[j]); printk("\n"); } + up(&dev->serialize); i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo); + down(&dev->serialize); } free_page((unsigned long)tbuf); if (i<0) { @@ -619,6 +625,8 @@ if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN))) return -EINVAL; len1 = bulk.len; + if (len1 > MAX_USBFS_BUFFER_SIZE) + return -EINVAL; if (!(tbuf = kmalloc(len1, GFP_KERNEL))) return -ENOMEM; tmo = (bulk.timeout * HZ + 999) / 1000; @@ -627,7 +635,9 @@ kfree(tbuf); return -EINVAL; } + up(&dev->serialize); i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); + down(&dev->serialize); if (!i && len2) { if (copy_to_user(bulk.data, tbuf, len2)) { kfree(tbuf); @@ -641,7 +651,9 @@ return -EFAULT; } } + up(&dev->serialize); i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); + down(&dev->serialize); } kfree(tbuf); if (i < 0) { @@ -849,7 +861,7 @@ case USBDEVFS_URB_TYPE_BULK: uurb.number_of_packets = 0; - if (uurb.buffer_length > 16384) + if (uurb.buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) return -EFAULT; @@ -891,7 +903,7 @@ interval = 1 << min (15, ep_desc->bInterval - 1); else interval = ep_desc->bInterval; - if (uurb.buffer_length > 16384) + if (uurb.buffer_length > MAX_USBFS_BUFFER_SIZE) return -EINVAL; if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) return -EFAULT; diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/core/hcd.c 2004-08-18 23:28:03 -07:00 @@ -1311,13 +1311,10 @@ rescan: /* (re)block new requests, as best we can */ - if (endpoint & USB_DIR_IN) { - usb_endpoint_halt (udev, epnum, 0); + if (endpoint & USB_DIR_IN) udev->epmaxpacketin [epnum] = 0; - } else { - usb_endpoint_halt (udev, epnum, 1); + else udev->epmaxpacketout [epnum] = 0; - } /* then kill any current requests */ spin_lock (&hcd_data_lock); diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h --- a/drivers/usb/core/hcd.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/core/hcd.h 2004-08-18 23:28:03 -07:00 @@ -376,8 +376,6 @@ extern int usb_find_interface_driver (struct usb_device *dev, struct usb_interface *interface); -#define usb_endpoint_halt(dev, ep, out) ((dev)->halted[out] |= (1 << (ep))) - #define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN)) /* diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/core/hub.c 2004-08-18 23:28:03 -07:00 @@ -36,7 +36,7 @@ #include "hcd.h" #include "hub.h" -/* Protect all struct usb_device state members */ +/* Protect struct usb_device state and children members */ static spinlock_t device_state_lock = SPIN_LOCK_UNLOCKED; /* Wakes up khubd */ @@ -143,7 +143,7 @@ unsigned changed = 0; int cursor = -1; - if (hdev->state != USB_STATE_CONFIGURED) + if (hdev->state != USB_STATE_CONFIGURED || hub->quiescing) return; for (i = 0; i < hub->descriptor->bNbrPorts; i++) { @@ -269,6 +269,9 @@ spin_unlock(&hub_event_lock); resubmit: + if (hub->quiescing) + return; + if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0 && status != -ENODEV && status != -EPERM) dev_err (&hub->intf->dev, "resubmit --> %d\n", status); @@ -623,6 +626,33 @@ static unsigned highspeed_hubs; +static void hub_quiesce(struct usb_hub *hub) +{ + /* stop khubd and related activity */ + hub->quiescing = 1; + usb_kill_urb(hub->urb); + if (hub->has_indicators) + cancel_delayed_work(&hub->leds); + if (hub->has_indicators || hub->tt.hub) + flush_scheduled_work(); +} + +#ifdef CONFIG_USB_SUSPEND + +static void hub_reactivate(struct usb_hub *hub) +{ + int status; + + hub->quiescing = 0; + status = usb_submit_urb(hub->urb, GFP_NOIO); + if (status < 0) + dev_err(&hub->intf->dev, "reactivate --> %d\n", status); + if (hub->has_indicators && blinkenlights) + schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD); +} + +#endif + static void hub_disconnect(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata (intf); @@ -637,22 +667,14 @@ usb_set_intfdata (intf, NULL); - if (hub->urb) { - usb_kill_urb(hub->urb); - usb_free_urb(hub->urb); - hub->urb = NULL; - } + hub_quiesce(hub); + usb_free_urb(hub->urb); + hub->urb = NULL; spin_lock_irq(&hub_event_lock); list_del_init(&hub->event_list); spin_unlock_irq(&hub_event_lock); - /* assuming we used keventd, it must quiesce too */ - if (hub->has_indicators) - cancel_delayed_work (&hub->leds); - if (hub->has_indicators || hub->tt.hub) - flush_scheduled_work (); - if (hub->descriptor) { kfree(hub->descriptor); hub->descriptor = NULL; @@ -772,6 +794,7 @@ } } +/* caller has locked the hub and must own the device lock */ static int hub_reset(struct usb_hub *hub) { struct usb_device *hdev = hub->hdev; @@ -789,7 +812,7 @@ else return -1; - if (usb_reset_device(hdev)) + if (__usb_reset_device(hdev)) return -1; hub->urb->dev = hdev; @@ -801,6 +824,7 @@ return 0; } +/* caller has locked the hub */ /* FIXME! This routine should be subsumed into hub_reset */ static void hub_start_disconnect(struct usb_device *hdev) { @@ -832,12 +856,65 @@ udev->state = USB_STATE_NOTATTACHED; } +/* grab device/port lock, returning index of that port (zero based). + * protects the upstream link used by this device from concurrent + * tree operations like suspend, resume, reset, and disconnect, which + * apply to everything downstream of a given port. + */ +static int locktree(struct usb_device *udev) +{ + int t; + struct usb_device *hdev; + + if (!udev) + return -ENODEV; + + /* root hub is always the first lock in the series */ + hdev = udev->parent; + if (!hdev) { + down(&udev->serialize); + return 0; + } + + /* on the path from root to us, lock everything from + * top down, dropping parent locks when not needed + * + * NOTE: if disconnect were to ignore the locking, we'd need + * to get extra refcounts to everything since hdev->children + * and udev->parent could be invalidated while we work... + */ + t = locktree(hdev); + if (t < 0) + return t; + spin_lock_irq(&device_state_lock); + for (t = 0; t < hdev->maxchild; t++) { + if (hdev->children[t] == udev) { + /* everything is fail-fast once disconnect + * processing starts + */ + if (udev->state == USB_STATE_NOTATTACHED) + break; + + /* when everyone grabs locks top->bottom, + * non-overlapping work may be concurrent + */ + spin_unlock_irq(&device_state_lock); + down(&udev->serialize); + up(&hdev->serialize); + return t; + } + } + spin_unlock_irq(&device_state_lock); + up(&hdev->serialize); + return -ENODEV; +} + /** * usb_set_device_state - change a device's current state (usbcore-internal) * @udev: pointer to device whose state should be changed * @new_state: new state value to be stored * - * udev->state is _not_ protected by the udev->serialize semaphore. This + * udev->state is _not_ protected by the device lock. This * is so that devices can be marked as disconnected as soon as possible, * without having to wait for the semaphore to be released. Instead, * changes to the state must be protected by the device_state_lock spinlock. @@ -897,7 +974,7 @@ /** * usb_disconnect - disconnect a device (usbcore-internal) - * @pdev: pointer to device being disconnected + * @pdev: pointer to device being disconnected, into a locked hub * Context: !in_interrupt () * * Something got disconnected. Get rid of it, and all of its children. @@ -921,7 +998,8 @@ } /* mark the device as inactive, so any further urb submissions for - * this device will fail. + * this device (and any of its children) will fail immediately. + * this quiesces everyting except pending urbs. */ usb_set_device_state(udev, USB_STATE_NOTATTACHED); @@ -940,6 +1018,7 @@ /* deallocate hcd/hardware state ... nuking all pending urbs and * cleaning up all state associated with the current configuration + * so that the hardware is now fully quiesced. */ usb_disable_device(udev, 0); @@ -952,7 +1031,7 @@ usbfs_remove_device(udev); usb_remove_sysfs_dev_files(udev); - /* Avoid races with recursively_mark_NOTATTACHED() */ + /* Avoid races with recursively_mark_NOTATTACHED() and locktree() */ spin_lock_irq(&device_state_lock); *pdev = NULL; spin_unlock_irq(&device_state_lock); @@ -1203,6 +1282,7 @@ if (status == -ENOTCONN || status == 0) { clear_port_feature(hdev, port + 1, USB_PORT_FEAT_C_RESET); + /* FIXME need disconnect() for NOTATTACHED device */ usb_set_device_state(udev, status ? USB_STATE_NOTATTACHED : USB_STATE_DEFAULT); @@ -1226,9 +1306,11 @@ { int ret; - if (hdev->children[port]) + if (hdev->children[port]) { + /* FIXME need disconnect() for NOTATTACHED device */ usb_set_device_state(hdev->children[port], USB_STATE_NOTATTACHED); + } ret = clear_port_feature(hdev, port + 1, USB_PORT_FEAT_ENABLE); if (ret) dev_err(hubdev(hdev), "cannot disable port %d (err = %d)\n", @@ -1239,7 +1321,490 @@ #ifdef CONFIG_USB_SUSPEND - /* no USB_SUSPEND yet! */ +/* + * Selective port suspend reduces power; most suspended devices draw + * less than 500 uA. It's also used in OTG, along with remote wakeup. + * All devices below the suspended port are also suspended. + * + * Devices leave suspend state when the host wakes them up. Some devices + * also support "remote wakeup", where the device can activate the USB + * tree above them to deliver data, such as a keypress or packet. In + * some cases, this wakes the USB host. + */ +static int hub_port_suspend(struct usb_device *hdev, int port) +{ + int status; + struct usb_device *udev; + + udev = hdev->children[port - 1]; + // dev_dbg(hubdev(hdev), "suspend port %d\n", port); + + /* enable remote wakeup when appropriate; this lets the device + * wake up the upstream hub (including maybe the root hub). + * + * NOTE: OTG devices may issue remote wakeup (or SRP) even when + * we don't explicitly enable it here. + */ + if (udev->actconfig + // && FIXME (remote wakeup enabled on this bus) + // ... currently assuming it's always appropriate + && (udev->actconfig->desc.bmAttributes + & USB_CONFIG_ATT_WAKEUP) != 0) { + status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, + USB_DEVICE_REMOTE_WAKEUP, 0, + NULL, 0, + USB_CTRL_SET_TIMEOUT); + if (status) + dev_dbg(&udev->dev, + "won't remote wakeup, status %d\n", + status); + } + + /* see 7.1.7.6 */ + status = set_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND); + if (status) { + dev_dbg(hubdev(hdev), + "can't suspend port %d, status %d\n", + port, status); + /* paranoia: "should not happen" */ + (void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, + USB_DEVICE_REMOTE_WAKEUP, 0, + NULL, 0, + USB_CTRL_SET_TIMEOUT); + } else { + /* device has up to 10 msec to fully suspend */ + dev_dbg(&udev->dev, "usb suspend\n"); + udev->state = USB_STATE_SUSPENDED; + msleep(10); + } + return status; +} + +/* + * Devices on USB hub ports have only one "suspend" state, corresponding + * to ACPI D2 (PM_SUSPEND_MEM), "may cause the device to lose some context". + * State transitions include: + * + * - suspend, resume ... when the VBUS power link stays live + * - suspend, disconnect ... VBUS lost + * + * Once VBUS drop breaks the circuit, the port it's using has to go through + * normal re-enumeration procedures, starting with enabling VBUS power. + * Other than re-initializing the hub (plug/unplug, except for root hubs), + * Linux (2.6) currently has NO mechanisms to initiate that: no khubd + * timer, no SRP, no requests through sysfs. + */ +static int __usb_suspend_device (struct usb_device *udev, int port, u32 state) +{ + int status; + + if (port < 0) + return port; + + /* NOTE: udev->serialize released on all real returns! */ + + if (state <= udev->dev.power.power_state + || state < PM_SUSPEND_MEM + || udev->state == USB_STATE_SUSPENDED + || udev->state == USB_STATE_NOTATTACHED) { + up(&udev->serialize); + return 0; + } + + /* suspend interface drivers; if this is a hub, it + * suspends the child devices + */ + if (udev->actconfig) { + int i; + + for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { + struct usb_interface *intf; + struct usb_driver *driver; + + intf = udev->actconfig->interface[i]; + if (state <= intf->dev.power.power_state) + continue; + if (!intf->dev.driver) + continue; + driver = to_usb_driver(intf->dev.driver); + + if (driver->suspend) { + status = driver->suspend(intf, state); + if (intf->dev.power.power_state != state + || status) + dev_err(&intf->dev, + "suspend %d fail, code %d\n", + state, status); + } + + /* only drivers with suspend() can ever resume(); + * and after power loss, even they won't. + * bus_rescan_devices() can rebind drivers later. + * + * FIXME the PM core self-deadlocks when unbinding + * drivers during suspend/resume ... everything grabs + * dpm_sem (not a spinlock, ugh). we want to unbind, + * since we know every driver's probe/disconnect works + * even for drivers that can't suspend. + */ + if (!driver->suspend || state > PM_SUSPEND_MEM) { +#if 1 + dev_warn(&intf->dev, "resume is unsafe!\n"); +#else + down_write(&usb_bus_type.rwsem); + device_release_driver(&intf->dev); + up_write(&usb_bus_type.rwsem); +#endif + } + } + } + + /* + * FIXME this needs port power off call paths too, to help force + * USB into the "generic" PM model. At least for devices on + * ports that aren't using ganged switching (usually root hubs). + * + * NOTE: SRP-capable links should adopt more aggressive poweroff + * policies (when HNP doesn't apply) once we have mechanisms to + * turn power back on! (Likely not before 2.7...) + */ + if (state > PM_SUSPEND_MEM) { + dev_warn(&udev->dev, "no poweroff yet, suspending instead\n"); + state = PM_SUSPEND_MEM; + } + + /* "global suspend" of the HC-to-USB interface (root hub), or + * "selective suspend" of just one hub-device link. + */ + if (!udev->parent) { + struct usb_bus *bus = udev->bus; + if (bus && bus->op->hub_suspend) + status = bus->op->hub_suspend (bus); + else + status = -EOPNOTSUPP; + } else + status = hub_port_suspend(udev->parent, port + 1); + + if (status == 0) + udev->dev.power.power_state = state; + up(&udev->serialize); + return status; +} + +/** + * usb_suspend_device - suspend a usb device + * @udev: device that's no longer in active use + * @state: PM_SUSPEND_MEM to suspend + * Context: must be able to sleep; device not locked + * + * Suspends a USB device that isn't in active use, conserving power. + * Devices may wake out of a suspend, if anything important happens, + * using the remote wakeup mechanism. They may also be taken out of + * suspend by the host, using usb_resume_device(). It's also routine + * to disconnect devices while they are suspended. + * + * Suspending OTG devices may trigger HNP, if that's been enabled + * between a pair of dual-role devices. That will change roles, such + * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral. + * + * Returns 0 on success, else negative errno. + */ +int usb_suspend_device(struct usb_device *udev, u32 state) +{ + return __usb_suspend_device(udev, locktree(udev), state); +} + +/* + * hardware resume signaling is finished, either because of selective + * resume (by host) or remote wakeup (by device) ... now see what changed + * in the tree that's rooted at this device. + */ +static int finish_port_resume(struct usb_device *udev) +{ + int status; + u16 devstatus; + + /* caller owns udev->serialize */ + dev_dbg(&udev->dev, "usb resume\n"); + udev->dev.power.power_state = PM_SUSPEND_ON; + + /* usb ch9 identifies four variants of SUSPENDED, based on what + * state the device resumes to. Linux currently won't see the + * first two on the host side; they'd be inside hub_port_init() + * during many timeouts, but khubd can't suspend until later. + */ + udev->state = udev->actconfig + ? USB_STATE_CONFIGURED + : USB_STATE_ADDRESS; + + /* 10.5.4.5 says be sure devices in the tree are still there. + * For now let's assume the device didn't go crazy on resume, + * and device drivers will know about any resume quirks. + */ + status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus); + if (status < 0) + dev_dbg(&udev->dev, + "gone after usb resume? status %d\n", + status); + else if (udev->actconfig) { + unsigned i; + + le16_to_cpus(&devstatus); + if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { + status = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + USB_REQ_CLEAR_FEATURE, + USB_RECIP_DEVICE, + USB_DEVICE_REMOTE_WAKEUP, 0, + NULL, 0, + USB_CTRL_SET_TIMEOUT); + if (status) { + dev_dbg(&udev->dev, "disable remote " + "wakeup, status %d\n", status); + status = 0; + } + } + + /* resume interface drivers; if this is a hub, it + * resumes the child devices + */ + for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { + struct usb_interface *intf; + struct usb_driver *driver; + + intf = udev->actconfig->interface[i]; + if (intf->dev.power.power_state == PM_SUSPEND_ON) + continue; + if (!intf->dev.driver) { + /* FIXME maybe force to alt 0 */ + continue; + } + driver = to_usb_driver(intf->dev.driver); + + /* bus_rescan_devices() may rebind drivers */ + if (!driver->resume) + continue; + + /* can we do better than just logging errors? */ + status = driver->resume(intf); + if (intf->dev.power.power_state != PM_SUSPEND_ON + || status) + dev_dbg(&intf->dev, + "resume fail, state %d code %d\n", + intf->dev.power.power_state, status); + } + status = 0; + + } else if (udev->devnum <= 0) { + dev_dbg(&udev->dev, "bogus resume!\n"); + status = -EINVAL; + } + return status; +} + +static int +hub_port_resume(struct usb_device *hdev, int port) +{ + int status; + struct usb_device *udev; + + udev = hdev->children[port - 1]; + // dev_dbg(hubdev(hdev), "resume port %d\n", port); + + /* see 7.1.7.7; affects power usage, but not budgeting */ + status = clear_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND); + if (status) { + dev_dbg(&hdev->actconfig->interface[0]->dev, + "can't resume port %d, status %d\n", + port, status); + } else { + u16 devstatus; + u16 portchange; + + /* drive resume for at least 20 msec */ + dev_dbg(&udev->dev, "RESUME\n"); + msleep(25); + +#define LIVE_FLAGS ( USB_PORT_STAT_POWER \ + | USB_PORT_STAT_ENABLE \ + | USB_PORT_STAT_CONNECTION) + + /* Virtual root hubs can trigger on GET_PORT_STATUS to + * stop resume signaling. Then finish the resume + * sequence. + */ + devstatus = portchange = 0; + status = hub_port_status(hdev, port - 1, + &devstatus, &portchange); + if (status < 0 + || (devstatus & LIVE_FLAGS) != LIVE_FLAGS + || (devstatus & USB_PORT_STAT_SUSPEND) != 0 + ) { + dev_dbg(&hdev->actconfig->interface[0]->dev, + "port %d status %04x.%04x after resume, %d\n", + port, portchange, devstatus, status); + } else { + /* TRSMRCY = 10 msec */ + msleep(10); + status = finish_port_resume(udev); + } + } + if (status < 0) + status = hub_port_disable(hdev, port); + + return status; +} + +static int hub_resume (struct usb_interface *intf); + +/** + * usb_resume_device - re-activate a suspended usb device + * @udev: device to re-activate + * Context: must be able to sleep; device not locked + * + * This will re-activate the suspended device, increasing power usage + * while letting drivers communicate again with its endpoints. + * USB resume explicitly guarantees that the power session between + * the host and the device is the same as it was when the device + * suspended. + * + * Returns 0 on success, else negative errno. + */ +int usb_resume_device(struct usb_device *udev) +{ + int port, status; + + port = locktree(udev); + if (port < 0) + return port; + + /* "global resume" of the HC-to-USB interface (root hub), or + * selective resume of one hub-to-device port + */ + if (!udev->parent) { + struct usb_bus *bus = udev->bus; + if (bus && bus->op->hub_resume) + status = bus->op->hub_resume (bus); + else + status = -EOPNOTSUPP; + if (status == 0) { + /* TRSMRCY = 10 msec */ + msleep(10); + status = hub_resume (bus->root_hub + ->actconfig->interface[0]); + } + } else if (udev->state == USB_STATE_SUSPENDED) { + status = hub_port_resume(udev->parent, port + 1); + } else { + status = 0; + udev->dev.power.power_state = PM_SUSPEND_ON; + } + if (status < 0) { + dev_dbg(&udev->dev, "can't resume, status %d\n", + status); + } + + up(&udev->serialize); + + /* rebind drivers that had no suspend() */ + bus_rescan_devices(&usb_bus_type); + + return status; +} + +static int remote_wakeup(struct usb_device *udev) +{ + int status = 0; + + /* don't repeat RESUME sequence if this device + * was already woken up by some other task + */ + down(&udev->serialize); + if (udev->state == USB_STATE_SUSPENDED) { + dev_dbg(&udev->dev, "RESUME (wakeup)\n"); + /* TRSMRCY = 10 msec */ + msleep(10); + status = finish_port_resume(udev); + } + up(&udev->serialize); + return status; +} + +static int hub_suspend(struct usb_interface *intf, u32 state) +{ + struct usb_hub *hub = usb_get_intfdata (intf); + struct usb_device *hdev = hub->hdev; + unsigned port; + int status; + + /* stop khubd and related activity */ + hub_quiesce(hub); + + /* then suspend every port */ + for (port = 0; port < hdev->maxchild; port++) { + struct usb_device *udev; + + udev = hdev->children [port]; + if (!udev) + continue; + down(&udev->serialize); + status = __usb_suspend_device(udev, port, state); + if (status < 0) + dev_dbg(&intf->dev, "suspend port %d --> %d\n", + port, status); + } + + intf->dev.power.power_state = state; + return 0; +} + +static int hub_resume(struct usb_interface *intf) +{ + struct usb_device *hdev = interface_to_usbdev(intf); + struct usb_hub *hub = usb_get_intfdata (intf); + unsigned port; + int status; + + for (port = 0; port < hdev->maxchild; port++) { + struct usb_device *udev; + u16 portstat, portchange; + + udev = hdev->children [port]; + status = hub_port_status(hdev, port, &portstat, &portchange); + if (status == 0) { + if (portchange & USB_PORT_STAT_C_SUSPEND) { + clear_port_feature(hdev, port + 1, + USB_PORT_FEAT_C_SUSPEND); + portchange &= ~USB_PORT_STAT_C_SUSPEND; + } + + /* let khubd handle disconnects etc */ + if (portchange) + continue; + } + + if (!udev) + continue; + down (&udev->serialize); + if (portstat & USB_PORT_STAT_SUSPEND) + status = hub_port_resume(hdev, port + 1); + else { + status = finish_port_resume(udev); + if (status < 0) + status = hub_port_disable(hdev, port); + if (status < 0) + dev_dbg(&intf->dev, "resume port %d --> %d\n", + port, status); + } + up(&udev->serialize); + } + intf->dev.power.power_state = PM_SUSPEND_ON; + + hub_reactivate(hub); + return 0; +} #else /* !CONFIG_USB_SUSPEND */ @@ -1479,8 +2044,6 @@ != udev->descriptor.bMaxPacketSize0)) { usb_disable_endpoint(udev, 0 + USB_DIR_IN); usb_disable_endpoint(udev, 0 + USB_DIR_OUT); - usb_endpoint_running(udev, 0, 1); - usb_endpoint_running(udev, 0, 0); udev->epmaxpacketin [0] = udev->descriptor.bMaxPacketSize0; udev->epmaxpacketout[0] = udev->descriptor.bMaxPacketSize0; } @@ -1574,6 +2137,7 @@ * a port enable-change occurs (often caused by EMI); * usb_reset_device() encounters changed descriptors (as from * a firmware download) + * caller already locked the hub */ static void hub_port_connect_change(struct usb_hub *hub, int port, u16 portstatus, u16 portchange) @@ -1780,7 +2344,8 @@ /* Lock the device, then check to see if we were * disconnected while waiting for the lock to succeed. */ - down(&hdev->serialize); + if (locktree(hdev) < 0) + break; if (hdev->state != USB_STATE_CONFIGURED || !hdev->actconfig || hub != usb_get_intfdata( @@ -2034,7 +2599,7 @@ } /** - * usb_reset_devce - perform a USB port reset to reinitialize a device + * usb_reset_device - perform a USB port reset to reinitialize a device * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) * * WARNING - don't reset any device unless drivers for all of its @@ -2123,7 +2688,7 @@ struct usb_interface *intf = udev->actconfig->interface[i]; struct usb_interface_descriptor *desc; - /* set_interface resets host side toggle and halt status even + /* set_interface resets host side toggle even * for altsetting zero. the interface may have no driver. */ desc = &intf->cur_altsetting->desc; diff -Nru a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h --- a/drivers/usb/core/hub.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/core/hub.h 2004-08-18 23:28:03 -07:00 @@ -214,6 +214,8 @@ u8 power_budget; /* in 2mA units; or zero */ + unsigned quiescing:1; + unsigned has_indicators:1; enum hub_led_mode indicator[USB_MAXCHILDREN]; struct work_struct leds; diff -Nru a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c --- a/drivers/usb/core/inode.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/core/inode.c 2004-08-18 23:28:03 -07:00 @@ -345,30 +345,13 @@ return 0; } -static void d_unhash(struct dentry *dentry) -{ - dget(dentry); - spin_lock(&dcache_lock); - switch (atomic_read(&dentry->d_count)) { - default: - spin_unlock(&dcache_lock); - shrink_dcache_parent(dentry); - spin_lock(&dcache_lock); - if (atomic_read(&dentry->d_count) != 2) - break; - case 2: - __d_drop(dentry); - } - spin_unlock(&dcache_lock); -} - static int usbfs_rmdir(struct inode *dir, struct dentry *dentry) { int error = -ENOTEMPTY; struct inode * inode = dentry->d_inode; down(&inode->i_sem); - d_unhash(dentry); + dentry_unhash(dentry); if (usbfs_empty(dentry)) { dentry->d_inode->i_nlink -= 2; dput(dentry); diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c --- a/drivers/usb/core/message.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/core/message.c 2004-08-18 23:28:03 -07:00 @@ -577,8 +577,13 @@ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, (type << 8) + index, 0, buf, size, HZ * USB_CTRL_GET_TIMEOUT); - if (!(result == 0 || result == -EPIPE)) - break; + if (result == 0 || result == -EPIPE) + continue; + if (result > 1 && ((u8 *)buf)[1] != type) { + result = -EPROTO; + continue; + } + break; } return result; } @@ -854,9 +859,8 @@ * the copy in usb-storage, for as long as we need two copies. */ - /* toggle was reset by the clear, then ep was reactivated */ + /* toggle was reset by the clear */ usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); - usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); return 0; } @@ -870,9 +874,8 @@ * Deallocates hcd/hardware state for this endpoint ... and nukes all * pending urbs. * - * If the HCD hasn't registered a disable() function, this marks the - * endpoint as halted and sets its maxpacket size to 0 to prevent - * further submissions. + * If the HCD hasn't registered a disable() function, this sets the + * endpoint's maxpacket size to 0 to prevent further submissions. */ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) { @@ -881,13 +884,10 @@ else { unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK; - if (usb_endpoint_out(epaddr)) { - usb_endpoint_halt(dev, epnum, 1); + if (usb_endpoint_out(epaddr)) dev->epmaxpacketout[epnum] = 0; - } else { - usb_endpoint_halt(dev, epnum, 0); + else dev->epmaxpacketin[epnum] = 0; - } } } @@ -930,7 +930,6 @@ usb_disable_endpoint(dev, i + USB_DIR_IN); } dev->toggle[0] = dev->toggle[1] = 0; - dev->halted[0] = dev->halted[1] = 0; /* getting rid of interfaces will disconnect * any drivers bound to them (a key side effect) @@ -966,9 +965,8 @@ * @dev: the device whose interface is being enabled * @epd: pointer to the endpoint descriptor * - * Marks the endpoint as running, resets its toggle, and stores - * its maxpacket value. For control endpoints, both the input - * and output sides are handled. + * Resets the endpoint toggle and stores its maxpacket value. + * For control endpoints, both the input and output sides are handled. */ void usb_enable_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *epd) @@ -980,12 +978,10 @@ USB_ENDPOINT_XFER_CONTROL); if (usb_endpoint_out(epaddr) || is_control) { - usb_endpoint_running(dev, epnum, 1); usb_settoggle(dev, epnum, 1, 0); dev->epmaxpacketout[epnum] = maxsize; } if (!usb_endpoint_out(epaddr) || is_control) { - usb_endpoint_running(dev, epnum, 0); usb_settoggle(dev, epnum, 0, 0); dev->epmaxpacketin[epnum] = maxsize; } @@ -1048,6 +1044,9 @@ int ret; int manual = 0; + if (dev->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; + iface = usb_ifnum_to_if(dev, interface); if (!iface) { dev_dbg(&dev->dev, "selecting invalid interface %d\n", @@ -1145,6 +1144,9 @@ int i, retval; struct usb_host_config *config; + if (dev->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; + /* caller must own dev->serialize (config won't change) * and the usb bus readlock (so driver bindings are stable); * so calls during probe() are fine @@ -1166,7 +1168,6 @@ } dev->toggle[0] = dev->toggle[1] = 0; - dev->halted[0] = dev->halted[1] = 0; /* re-init hc/hcd interface/endpoint state */ for (i = 0; i < config->desc.bNumInterfaces; i++) { @@ -1257,6 +1258,9 @@ */ if (cp && configuration == 0) dev_warn(&dev->dev, "config 0 descriptor??\n"); + + if (dev->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; /* Allocate memory for new interfaces before doing anything else, * so that if we run out then nothing will have changed. */ diff -Nru a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c --- a/drivers/usb/core/urb.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/core/urb.c 2004-08-18 23:28:03 -07:00 @@ -256,13 +256,6 @@ if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED) return -ENODEV; - /* (actually HCDs may need to duplicate this, endpoint might yet - * stall due to queued bulk/intr transactions that complete after - * we check) - */ - if (usb_endpoint_halted (dev, usb_pipeendpoint (pipe), is_out)) - return -EPIPE; - /* FIXME there should be a sharable lock protecting us against * config/altsetting changes and disconnects, kicking in here. * (here == before maxpacket, and eventually endpoint type, diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/core/usb.c 2004-08-18 23:28:03 -07:00 @@ -93,6 +93,8 @@ if (!driver->probe) return error; + if (interface_to_usbdev(intf)->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; id = usb_match_id (intf, driver->id_table); if (id) { diff -Nru a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig --- a/drivers/usb/gadget/Kconfig 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/gadget/Kconfig 2004-08-18 23:28:03 -07:00 @@ -275,7 +275,7 @@ dynamically linked module called "gadgetfs". config USB_FILE_STORAGE - tristate "File-backed Storage Gadget (DEVELOPMENT)" + tristate "File-backed Storage Gadget" # we don't support the SA1100 because of its limitations depends on USB_GADGET_SA1100 = n help @@ -288,7 +288,7 @@ dynamically linked module called "g_file_storage". config USB_FILE_STORAGE_TEST - bool "File-backed Storage Gadget test version" + bool "File-backed Storage Gadget testing version" depends on USB_FILE_STORAGE default n help diff -Nru a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile --- a/drivers/usb/gadget/Makefile 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/gadget/Makefile 2004-08-18 23:28:03 -07:00 @@ -11,7 +11,7 @@ # 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 +g_serial-objs := serial.o usbstring.o epautoconf.o gadgetfs-objs := inode.o g_file_storage-objs := file_storage.o usbstring.o config.o \ epautoconf.o diff -Nru a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c --- a/drivers/usb/gadget/dummy_hcd.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/gadget/dummy_hcd.c 2004-08-18 23:28:03 -07:00 @@ -596,14 +596,13 @@ /* "function" sysfs attribute */ static ssize_t -show_function (struct device *_dev, char *buf) +show_function (struct device *dev, char *buf) { - struct dummy *dum = the_controller; + struct dummy *dum = gadget_dev_to_dummy (dev); - if (!dum->driver->function - || strlen (dum->driver->function) > PAGE_SIZE) + if (!dum->driver || !dum->driver->function) return 0; - return snprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function); + return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function); } DEVICE_ATTR (function, S_IRUGO, show_function, NULL); diff -Nru a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c --- a/drivers/usb/gadget/file_storage.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/gadget/file_storage.c 2004-08-18 23:28:03 -07:00 @@ -46,17 +46,16 @@ * * Backing storage is provided by a regular file or a block device, specified * by the "file" module parameter. Access can be limited to read-only by - * setting the optional "ro" module parameter. + * setting the optional "ro" module parameter. The gadget will indicate that + * it has removable media if the optional "removable" module parameter is set. * * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI), * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected * by the optional "transport" module parameter. It also supports the * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03), * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by - * the optional "protocol" module parameter. For testing purposes the - * gadget will indicate that it has removable media if the optional - * "removable" module parameter is set. In addition, the default Vendor ID, - * Product ID, and release number can be overridden. + * the optional "protocol" module parameter. In addition, the default + * Vendor ID, Product ID, and release number can be overridden. * * There is support for multiple logical units (LUNs), each of which has * its own backing file. The number of LUNs can be set using the optional @@ -79,13 +78,13 @@ * the files or block devices used for * backing storage * ro=b[,b...] Default false, booleans for read-only access + * removable Default false, boolean for removable media * luns=N Default N = number of filenames, number of * LUNs to support * transport=XXX Default BBB, transport name (CB, CBI, or BBB) * protocol=YYY Default SCSI, protocol name (RBC, 8020 or * ATAPI, QIC, UFI, 8070, or SCSI; * also 1 - 6) - * removable Default false, boolean for removable media * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID * release=0xRRRR Override the USB release number (bcdDevice) @@ -97,16 +96,16 @@ * boolean to permit the driver to halt * bulk endpoints * - * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file" and "ro" - * options are available; default values are used for everything else. + * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro", + * "removable", and "luns" options are available; default values are used + * for everything else. * * The pathnames of the backing files and the ro settings are available in * the attribute files "file" and "ro" in the lun subdirectory of the - * gadget's sysfs directory. If CONFIG_USB_FILE_STORAGE_TEST and the - * "removable" option are both set, writing to these files will simulate - * ejecting/loading the medium (writing an empty line means eject) and - * adjusting a write-enable tab. Changes to the ro setting are not allowed - * when the medium is loaded. + * gadget's sysfs directory. If the "removable" option is set, writing to + * these files will simulate ejecting/loading the medium (writing an empty + * line means eject) and adjusting a write-enable tab. Changes to the ro + * setting are not allowed when the medium is loaded. * * This gadget driver is heavily based on "Gadget Zero" by David Brownell. */ @@ -178,7 +177,10 @@ * Bulk-only specification requires a stall. In such cases the driver * will halt the endpoint and set a flag indicating that it should clear * the halt in software during the next device reset. Hopefully this - * will permit everything to work correctly. + * will permit everything to work correctly. Furthermore, although the + * specification allows the bulk-out endpoint to halt when the host sends + * too much data, implementing this would cause an unavoidable race. + * The driver will always use the "no-stall" approach for OUT transfers. * * One subtle point concerns sending status-stage responses for ep0 * requests. Some of these requests, such as device reset, can involve @@ -246,7 +248,7 @@ #define DRIVER_DESC "File-backed Storage Gadget" #define DRIVER_NAME "g_file_storage" -#define DRIVER_VERSION "21 March 2004" +#define DRIVER_VERSION "28 July 2004" static const char longname[] = DRIVER_DESC; static const char shortname[] = DRIVER_NAME; @@ -371,14 +373,17 @@ module_param_array(ro, bool, mod_data.num_ros, S_IRUGO); MODULE_PARM_DESC(ro, "true to force read-only"); +module_param_named(luns, mod_data.nluns, uint, S_IRUGO); +MODULE_PARM_DESC(luns, "number of LUNs"); -/* In the non-TEST version, only the file and ro module parameters +module_param_named(removable, mod_data.removable, bool, S_IRUGO); +MODULE_PARM_DESC(removable, "true to simulate removable media"); + + +/* In the non-TEST version, only the module parameters listed above * are available. */ #ifdef CONFIG_USB_FILE_STORAGE_TEST -module_param_named(luns, mod_data.nluns, uint, S_IRUGO); -MODULE_PARM_DESC(luns, "number of LUNs"); - module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO); MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)"); @@ -386,9 +391,6 @@ MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, " "8070, or SCSI)"); -module_param_named(removable, mod_data.removable, bool, S_IRUGO); -MODULE_PARM_DESC(removable, "true to simulate removable media"); - module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO); MODULE_PARM_DESC(vendor, "USB Vendor ID"); @@ -525,11 +527,6 @@ * parts of the driver that aren't used in the non-TEST version. Even gcc * can recognize when a test of a constant expression yields a dead code * path. - * - * Also, in the non-TEST version, open_backing_file() is only used during - * initialization and the sysfs attribute store_xxx routines aren't used - * at all. We will define NORMALLY_INIT to mark them as __init so they - * don't occupy kernel code space unnecessarily. */ #ifdef CONFIG_USB_FILE_STORAGE_TEST @@ -537,16 +534,12 @@ #define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK) #define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI) #define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI) -#define backing_file_is_open(curlun) ((curlun)->filp != NULL) -#define NORMALLY_INIT #else #define transport_is_bbb() 1 #define transport_is_cbi() 0 #define protocol_is_scsi() 1 -#define backing_file_is_open(curlun) 1 -#define NORMALLY_INIT __init #endif /* CONFIG_USB_FILE_STORAGE_TEST */ @@ -567,6 +560,8 @@ struct device dev; }; +#define backing_file_is_open(curlun) ((curlun)->filp != NULL) + static inline struct lun *dev_to_lun(struct device *dev) { return container_of(dev, struct lun, dev); @@ -659,6 +654,7 @@ unsigned long atomic_bitflags; #define REGISTERED 0 #define CLEAR_BULK_HALTS 1 +#define SUSPENDED 2 struct usb_ep *bulk_in; struct usb_ep *bulk_out; @@ -1041,8 +1037,6 @@ function = fs_function; len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); - if (len < 0) - return len; ((struct usb_config_descriptor *) buf)->bDescriptorType = type; return len; } @@ -1172,9 +1166,10 @@ wakeup_thread(fsg); } + +#ifdef CONFIG_USB_FILE_STORAGE_TEST static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) { -#ifdef CONFIG_USB_FILE_STORAGE_TEST struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; @@ -1190,17 +1185,21 @@ bh->state = BUF_STATE_EMPTY; spin_unlock(&fsg->lock); wakeup_thread(fsg); -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ } +#else +static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) +{} +#endif /* CONFIG_USB_FILE_STORAGE_TEST */ + /*-------------------------------------------------------------------------*/ /* Ep0 class-specific handlers. These always run in_irq. */ +#ifdef CONFIG_USB_FILE_STORAGE_TEST static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) { -#ifdef CONFIG_USB_FILE_STORAGE_TEST struct usb_request *req = fsg->ep0req; static u8 cbi_reset_cmnd[6] = { SC_SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff}; @@ -1238,9 +1237,13 @@ spin_unlock(&fsg->lock); wakeup_thread(fsg); -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ } +#else +static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) +{} +#endif /* CONFIG_USB_FILE_STORAGE_TEST */ + static int class_setup_req(struct fsg_dev *fsg, const struct usb_ctrlrequest *ctrl) @@ -1465,8 +1468,8 @@ /* Respond with data/status or defer until later? */ if (rc >= 0 && rc != DELAYED_STATUS) { fsg->ep0req->length = rc; - fsg->ep0req->zero = rc < ctrl->wLength - && (rc % gadget->ep0->maxpacket) == 0; + fsg->ep0req->zero = (rc < ctrl->wLength && + (rc % gadget->ep0->maxpacket) == 0); fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ? "ep0-in" : "ep0-out"); rc = ep0_queue(fsg); @@ -2443,14 +2446,19 @@ rc = -EINTR; } - /* We haven't processed all the incoming data. If we are - * allowed to stall, halt the bulk-out endpoint and cancel - * any outstanding requests. */ + /* We haven't processed all the incoming data. Even though + * we may be allowed to stall, doing so would cause a race. + * The controller may already have ACK'ed all the remaining + * bulk-out packets, in which case the host wouldn't see a + * STALL. Not realizing the endpoint was halted, it wouldn't + * clear the halt -- leading to problems later on. */ +#if 0 else if (mod_data.can_stall) { fsg_set_halt(fsg, fsg->bulk_out); raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); rc = -EINTR; } +#endif /* We can't stall. Read in the excess data and throw it * all away. */ @@ -2513,7 +2521,7 @@ } else if (mod_data.transport_type == USB_PR_CB) { - /* Control-Bulk transport has no status stage! */ + /* Control-Bulk transport has no status phase! */ return 0; } else { // USB_PR_CBI @@ -2603,8 +2611,10 @@ fsg->residue = fsg->usb_amount_left = fsg->data_size; /* Conflicting data directions is a phase error */ - if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) - goto phase_error; + if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) { + fsg->phase_error = 1; + return -EINVAL; + } /* Verify the length of the command itself */ if (cmnd_size != fsg->cmnd_size) { @@ -2613,8 +2623,10 @@ * with cbw->Length == 12 (it should be 6). */ if (fsg->cmnd[0] == SC_REQUEST_SENSE && fsg->cmnd_size == 12) cmnd_size = fsg->cmnd_size; - else - goto phase_error; + else { + fsg->phase_error = 1; + return -EINVAL; + } } /* Check that the LUN values are oonsistent */ @@ -2674,10 +2686,6 @@ } return 0; - -phase_error: - fsg->phase_error = 1; - return -EINVAL; } @@ -3424,8 +3432,7 @@ /* If the next two routines are called while the gadget is registered, * the caller must own fsg->filesem for writing. */ -static int NORMALLY_INIT open_backing_file(struct lun *curlun, - const char *filename) +static int open_backing_file(struct lun *curlun, const char *filename) { int ro; struct file *filp = NULL; @@ -3550,8 +3557,7 @@ } -ssize_t NORMALLY_INIT store_ro(struct device *dev, const char *buf, - size_t count) +ssize_t store_ro(struct device *dev, const char *buf, size_t count) { ssize_t rc = count; struct lun *curlun = dev_to_lun(dev); @@ -3575,8 +3581,7 @@ return rc; } -ssize_t NORMALLY_INIT store_file(struct device *dev, const char *buf, - size_t count) +ssize_t store_file(struct device *dev, const char *buf, size_t count) { struct lun *curlun = dev_to_lun(dev); struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); @@ -3805,9 +3810,8 @@ goto out; } - /* Create the LUNs and open their backing files. We can't register - * the LUN devices until the gadget itself is registered, which - * doesn't happen until after fsg_bind() returns. */ + /* Create the LUNs, open their backing files, and register the + * LUN devices in sysfs. */ fsg->luns = kmalloc(i * sizeof(struct lun), GFP_KERNEL); if (!fsg->luns) { rc = -ENOMEM; @@ -3825,6 +3829,15 @@ snprintf(curlun->dev.bus_id, BUS_ID_SIZE, "%s-lun%d", gadget->dev.bus_id, i); + if ((rc = device_register(&curlun->dev)) != 0) + INFO(fsg, "failed to register LUN%d: %d\n", i, rc); + else { + curlun->registered = 1; + curlun->dev.release = lun_release; + device_create_file(&curlun->dev, &dev_attr_ro); + device_create_file(&curlun->dev, &dev_attr_file); + } + if (file[i] && *file[i]) { if ((rc = open_backing_file(curlun, file[i])) != 0) goto out; @@ -3974,6 +3987,25 @@ /*-------------------------------------------------------------------------*/ +static void fsg_suspend(struct usb_gadget *gadget) +{ + struct fsg_dev *fsg = get_gadget_data(gadget); + + DBG(fsg, "suspend\n"); + set_bit(SUSPENDED, &fsg->atomic_bitflags); +} + +static void fsg_resume(struct usb_gadget *gadget) +{ + struct fsg_dev *fsg = get_gadget_data(gadget); + + DBG(fsg, "resume\n"); + clear_bit(SUSPENDED, &fsg->atomic_bitflags); +} + + +/*-------------------------------------------------------------------------*/ + static struct usb_gadget_driver fsg_driver = { #ifdef CONFIG_USB_GADGET_DUALSPEED .speed = USB_SPEED_HIGH, @@ -3985,6 +4017,8 @@ .unbind = fsg_unbind, .disconnect = fsg_disconnect, .setup = fsg_setup, + .suspend = fsg_suspend, + .resume = fsg_resume, .driver = { .name = (char *) shortname, @@ -4024,8 +4058,6 @@ { int rc; struct fsg_dev *fsg; - int i; - struct lun *curlun; if ((rc = fsg_alloc()) != 0) return rc; @@ -4035,19 +4067,6 @@ return rc; } set_bit(REGISTERED, &fsg->atomic_bitflags); - - /* Register the LUN devices and their attribute files */ - for (i = 0; i < fsg->nluns; ++i) { - curlun = &fsg->luns[i]; - if ((rc = device_register(&curlun->dev)) != 0) - INFO(fsg, "failed to register LUN%d: %d\n", i, rc); - else { - curlun->registered = 1; - curlun->dev.release = lun_release; - device_create_file(&curlun->dev, &dev_attr_ro); - device_create_file(&curlun->dev, &dev_attr_file); - } - } /* Tell the thread to start working */ complete(&fsg->thread_notifier); diff -Nru a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c --- a/drivers/usb/gadget/net2280.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/gadget/net2280.c 2004-08-18 23:28:03 -07:00 @@ -7,13 +7,9 @@ * * CODE STATUS HIGHLIGHTS * - * Used with a gadget driver like "zero.c" this enumerates fine to Windows - * or Linux hosts; handles disconnect, reconnect, and reset, for full or - * high speed operation; and passes USB-IF "chapter 9" tests. - * - * Handles standard stress loads from the Linux "usbtest" driver, with - * either DMA (default) or PIO (use_dma=n) used for ep-{a,b,c,d}. Testing - * with "ttcp" (and the "ether.c" driver) behaves nicely too. + * This driver should work well with most "gadget" drivers, including + * the File Storage, Serial, and Ethernet/RNDIS gadget drivers + * as well as Gadget Zero and Gadgetfs. * * DMA is enabled by default. Drivers using transfer queues might use * DMA chaining to remove IRQ latencies between transfers. (Except when @@ -678,7 +674,7 @@ } if (count) { tmp = readl (®s->ep_data); - cpu_to_le32s (&tmp); + /* LE conversion is implicit here: */ do { *buf++ = (u8) tmp; tmp >>= 8; @@ -1419,10 +1415,34 @@ return 0; } +static int net2280_pullup(struct usb_gadget *_gadget, int is_on) +{ + struct net2280 *dev; + u32 tmp; + unsigned long flags; + + if (!_gadget) + return -ENODEV; + dev = container_of (_gadget, struct net2280, gadget); + + spin_lock_irqsave (&dev->lock, flags); + tmp = readl (&dev->usb->usbctl); + dev->softconnect = (is_on != 0); + if (is_on) + tmp |= (1 << USB_DETECT_ENABLE); + else + tmp &= ~(1 << USB_DETECT_ENABLE); + writel (tmp, &dev->usb->usbctl); + spin_unlock_irqrestore (&dev->lock, flags); + + return 0; +} + static const struct usb_gadget_ops net2280_ops = { .get_frame = net2280_get_frame, .wakeup = net2280_wakeup, .set_selfpowered = net2280_set_selfpowered, + .pullup = net2280_pullup, }; /*-------------------------------------------------------------------------*/ @@ -1807,8 +1827,6 @@ { u32 tmp; - /* force immediate bus disconnect, and synch through pci */ - writel (0, &dev->usb->usbctl); dev->gadget.speed = USB_SPEED_UNKNOWN; (void) readl (&dev->usb->usbctl); @@ -1905,7 +1923,7 @@ /* erratum 0102 workaround */ | ((dev->chiprev == 0100) ? 0 : 1) << SUSPEND_IMMEDIATELY | (1 << REMOTE_WAKEUP_SUPPORT) - | (1 << USB_DETECT_ENABLE) + | (dev->softconnect << USB_DETECT_ENABLE) | (1 << SELF_POWERED_STATUS) , &dev->usb->usbctl); @@ -1957,6 +1975,7 @@ dev->ep [i].irqs = 0; /* hook up the driver ... */ + dev->softconnect = 1; driver->driver.bus = NULL; dev->driver = driver; dev->gadget.dev.driver = &driver->driver; @@ -2788,6 +2807,7 @@ dev->epregs = (struct net2280_ep_regs *) (base + 0x0300); /* put into initial config, link up all endpoints */ + writel (0, &dev->usb->usbctl); usb_reset (dev); usb_reinit (dev); diff -Nru a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h --- a/drivers/usb/gadget/net2280.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/gadget/net2280.h 2004-08-18 23:28:03 -07:00 @@ -559,6 +559,7 @@ struct usb_gadget_driver *driver; unsigned enabled : 1, protocol_stall : 1, + softconnect : 1, got_irq : 1, region : 1; u16 chiprev; diff -Nru a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c --- a/drivers/usb/gadget/pxa2xx_udc.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/gadget/pxa2xx_udc.c 2004-08-18 23:28:03 -07:00 @@ -116,7 +116,7 @@ #ifdef USE_DMA static int use_dma = 1; -MODULE_PARM (use_dma, "i"); +module_param(use_dma, bool, 0); MODULE_PARM_DESC (use_dma, "true to use dma"); static void dma_nodesc_handler (int dmach, void *_ep, struct pt_regs *r); @@ -146,7 +146,7 @@ * ... so mode = 3 (or 7, 15, etc) does it for both */ static ushort fifo_mode = 0; -MODULE_PARM (fifo_mode, "h"); +module_param(fifo_mode, ushort, 0); MODULE_PARM_DESC (fifo_mode, "pxa2xx udc fifo mode"); #endif @@ -1508,7 +1508,7 @@ /* caller must be able to sleep in order to cope * with startup transients. */ - schedule_timeout(HZ/10); + msleep(100); /* enable suspend/resume and reset irqs */ udc_clear_mask_UDCCR(UDCCR_SRM | UDCCR_REM); diff -Nru a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c --- a/drivers/usb/gadget/serial.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/gadget/serial.c 2004-08-18 23:28:03 -07:00 @@ -48,6 +48,8 @@ #include #include +#include "gadget_chips.h" + /* Wait Cond */ @@ -123,8 +125,8 @@ /* Defines */ -#define GS_VERSION_STR "v0.1" -#define GS_VERSION_NUM 0x0001 +#define GS_VERSION_STR "v1.0" +#define GS_VERSION_NUM 0x0100 #define GS_LONG_NAME "Gadget Serial" #define GS_SHORT_NAME "g_serial" @@ -173,164 +175,6 @@ #endif /* G_SERIAL_DEBUG */ -/* USB Controllers */ - -/* - * 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 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 - -extern int net2280_set_fifo_mode(struct usb_gadget *gadget, int mode); - -static inline void hw_optimize(struct usb_gadget *gadget) -{ - /* we can have bigger ep-a/ep-b fifos (2KB each, 4 packets - * for highspeed bulk) because we're not using ep-c/ep-d. - */ - net2280_set_fifo_mode (gadget, 1); -} -#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 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 - * 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 EP0_MAXPACKET 16 -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 -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER - -/* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0) -#endif - -#ifdef CONFIG_USB_GADGET_OMAP -#define CHIP "omap" -#define EP0_MAXPACKET 64 -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 -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER -/* supports remote wakeup, but this driver doesn't */ - -/* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0) -#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 EP0_MAXPACKET 8 -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 -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER - -/* 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 0x0116 -#define EP0_MAXPACKET 8 -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 -#define SELFPOWER USB_CONFIG_ATT_SELFPOWER - -/* no hw optimizations to apply */ -#define hw_optimize(g) do {} while (0) -#endif - -/* - * USB Controller Defaults - */ -#ifndef EP0_MAXPACKET -#error Configure some USB peripheral controller for g_serial! -#endif - -#ifndef SELFPOWER -/* default: say we rely on bus power */ -#define SELFPOWER 0 -/* else value must be USB_CONFIG_ATT_SELFPOWER */ -#endif - -#ifndef MAX_USB_POWER -/* any hub supports this steady state bus power consumption */ -#define MAX_USB_POWER 100 /* mA */ -#endif - -#ifndef WAKEUP -/* default: this driver won't do remote wakeup */ -#define WAKEUP 0 -/* else value must be USB_CONFIG_ATT_WAKEUP */ -#endif /* Thanks to NetChip Technologies for donating this product ID. * @@ -449,11 +293,17 @@ static unsigned int gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count); +/* external functions */ +extern int net2280_set_fifo_mode(struct usb_gadget *gadget, int mode); + /* Globals */ static struct gs_dev *gs_device; +static const char *EP_IN_NAME; +static const char *EP_OUT_NAME; + static struct semaphore gs_open_close_sem[GS_NUM_PORTS]; static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE; @@ -483,7 +333,7 @@ /* gadget driver struct */ static struct usb_gadget_driver gs_gadget_driver = { -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED .speed = USB_SPEED_HIGH, #else .speed = USB_SPEED_FULL, @@ -510,8 +360,9 @@ #define GS_CONFIG_STR_ID 4 /* static strings, in iso 8859/1 */ +static char manufacturer[40]; static struct usb_string gs_strings[] = { - { GS_MANUFACTURER_STR_ID, UTS_SYSNAME " " UTS_RELEASE " with " CHIP }, + { GS_MANUFACTURER_STR_ID, manufacturer }, { GS_PRODUCT_STR_ID, GS_LONG_NAME }, { GS_SERIAL_STR_ID, "0" }, { GS_CONFIG_STR_ID, "Bulk" }, @@ -523,15 +374,13 @@ .strings = gs_strings, }; -static const struct usb_device_descriptor gs_device_desc = { +static struct usb_device_descriptor gs_device_desc = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, .bcdUSB = __constant_cpu_to_le16(0x0200), .bDeviceClass = USB_CLASS_VENDOR_SPEC, - .bMaxPacketSize0 = EP0_MAXPACKET, .idVendor = __constant_cpu_to_le16(GS_VENDOR_ID), .idProduct = __constant_cpu_to_le16(GS_PRODUCT_ID), - .bcdDevice = __constant_cpu_to_le16(GS_VERSION_NUM), .iManufacturer = GS_MANUFACTURER_STR_ID, .iProduct = GS_PRODUCT_STR_ID, .iSerialNumber = GS_SERIAL_STR_ID, @@ -545,8 +394,8 @@ .bNumInterfaces = GS_NUM_INTERFACES, .bConfigurationValue = GS_BULK_CONFIG_ID, .iConfiguration = GS_CONFIG_STR_ID, - .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP, - .bMaxPower = (MAX_USB_POWER + 1) / 2, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .bMaxPower = 1, }; static const struct usb_interface_descriptor gs_interface_desc = { @@ -557,46 +406,41 @@ .iInterface = GS_CONFIG_STR_ID, }; -static const struct usb_endpoint_descriptor gs_fullspeed_in_desc = { +static struct usb_endpoint_descriptor gs_fullspeed_in_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 gs_fullspeed_out_desc = { +static struct usb_endpoint_descriptor gs_fullspeed_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_OUT_NUM | USB_DIR_OUT, + .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(64), }; -static const struct usb_endpoint_descriptor gs_highspeed_in_desc = { +static struct usb_endpoint_descriptor gs_highspeed_in_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), }; -static const struct usb_endpoint_descriptor gs_highspeed_out_desc = { +static struct usb_endpoint_descriptor gs_highspeed_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = EP_OUT_NUM | USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16(512), }; -#ifdef HIGHSPEED -static const struct usb_qualifier_descriptor gs_qualifier_desc = { +#ifdef CONFIG_USB_GADGET_DUALSPEED +static struct usb_qualifier_descriptor gs_qualifier_desc = { .bLength = sizeof(struct usb_qualifier_descriptor), .bDescriptorType = USB_DT_DEVICE_QUALIFIER, .bcdUSB = __constant_cpu_to_le16 (0x0200), .bDeviceClass = USB_CLASS_VENDOR_SPEC, /* assumes ep0 uses the same value for both speeds ... */ - .bMaxPacketSize0 = EP0_MAXPACKET, .bNumConfigurations = GS_NUM_CONFIGS, }; #endif @@ -608,17 +452,17 @@ MODULE_LICENSE("GPL"); #if G_SERIAL_DEBUG -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on"); +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on, larger values for more messages"); #endif -MODULE_PARM(read_q_size, "i"); +module_param(read_q_size, int, 0); MODULE_PARM_DESC(read_q_size, "Read request queue size, default=32"); -MODULE_PARM(write_q_size, "i"); +module_param(write_q_size, int, 0); MODULE_PARM_DESC(write_q_size, "Write request queue size, default=32"); -MODULE_PARM(write_buf_size, "i"); +module_param(write_buf_size, int, 0); MODULE_PARM_DESC(write_buf_size, "Write buffer size, default=8192"); module_init(gs_module_init); @@ -1416,18 +1260,78 @@ static int gs_bind(struct usb_gadget *gadget) { int ret; + struct usb_ep *ep; struct gs_dev *dev; + usb_ep_autoconfig_reset(gadget); + + ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc); + if (!ep) + goto autoconf_fail; + EP_IN_NAME = ep->name; + ep->driver_data = ep; /* claim the endpoint */ + + ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc); + if (!ep) + goto autoconf_fail; + EP_OUT_NAME = ep->name; + ep->driver_data = ep; /* claim the endpoint */ + + /* device specific bcdDevice value in device descriptor */ + if (gadget_is_net2280(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0001); + } else if (gadget_is_pxa(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0002); + } else if (gadget_is_sh(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0003); + } else if (gadget_is_sa1100(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0004); + } else if (gadget_is_goku(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0005); + } else if (gadget_is_mq11xx(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0006); + } else if (gadget_is_omap(gadget)) { + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0007); + } else { + printk(KERN_WARNING "gs_bind: controller '%s' not recognized\n", + gadget->name); + /* unrecognized, but safe unless bulk is REALLY quirky */ + gs_device_desc.bcdDevice = + __constant_cpu_to_le16(GS_VERSION_NUM|0x0099); + } + + gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; +#ifdef CONFIG_USB_GADGET_DUALSPEED + /* assume ep0 uses the same packet size for both speeds */ + gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0; + /* assume endpoints are dual-speed */ + gs_highspeed_in_desc.bEndpointAddress = + gs_fullspeed_in_desc.bEndpointAddress; + gs_highspeed_out_desc.bEndpointAddress = + gs_fullspeed_out_desc.bEndpointAddress; +#endif /* CONFIG_USB_GADGET_DUALSPEED */ + + usb_gadget_set_selfpowered(gadget); + gs_device = dev = kmalloc(sizeof(struct gs_dev), GFP_KERNEL); if (dev == NULL) return -ENOMEM; - set_gadget_data(gadget, dev); + snprintf (manufacturer, sizeof(manufacturer), + UTS_SYSNAME " " UTS_RELEASE " with %s", gadget->name); memset(dev, 0, sizeof(struct gs_dev)); dev->dev_gadget = gadget; spin_lock_init(&dev->dev_lock); INIT_LIST_HEAD(&dev->dev_req_list); + set_gadget_data(gadget, dev); if ((ret=gs_alloc_ports(dev, GFP_KERNEL)) != 0) { printk(KERN_ERR "gs_bind: cannot allocate ports\n"); @@ -1450,6 +1354,10 @@ GS_LONG_NAME, GS_VERSION_STR); return 0; + +autoconf_fail: + printk(KERN_ERR "gs_bind: cannot autoconfigure on %s\n", gadget->name); + return -ENODEV; } /* @@ -1505,15 +1413,17 @@ memcpy(req->buf, &gs_device_desc, ret); break; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: + if (!gadget->is_dualspeed) + break; ret = min(ctrl->wLength, (u16)sizeof(struct usb_qualifier_descriptor)); memcpy(req->buf, &gs_qualifier_desc, ret); break; case USB_DT_OTHER_SPEED_CONFIG: -#endif /* HIGHSPEED */ +#endif /* CONFIG_USB_GADGET_DUALSPEED */ case USB_DT_CONFIG: ret = gs_build_config_desc(req->buf, gadget->speed, ctrl->wValue >> 8, ctrl->wValue & 0xff); @@ -1677,7 +1587,9 @@ if (config != GS_BULK_CONFIG_ID) return -EINVAL; - hw_optimize(gadget); + /* device specific optimizations */ + if (gadget_is_net2280(gadget)) + net2280_set_fifo_mode(gadget, 1); gadget_for_each_ep(ep, gadget) { diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c --- a/drivers/usb/host/ehci-hcd.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/host/ehci-hcd.c 2004-08-18 23:28:03 -07:00 @@ -289,7 +289,7 @@ static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap) { if (cap & (1 << 16)) { - int msec = 500; + int msec = 5000; struct pci_dev *pdev = to_pci_dev(ehci->hcd.self.controller); /* request handoff to OS */ @@ -305,7 +305,10 @@ if (cap & (1 << 16)) { ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n", where, cap); - return 1; + // some BIOS versions seem buggy... + // return 1; + ehci_warn (ehci, "continuing after BIOS bug...\n"); + return 0; } ehci_dbg (ehci, "BIOS handoff succeeded\n"); } diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c --- a/drivers/usb/host/ehci-q.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/host/ehci-q.c 2004-08-18 23:28:03 -07:00 @@ -153,17 +153,9 @@ usb_pipein (urb->pipe) ? "in" : "out", token, urb->status); - /* stall indicates some recovery action is needed */ - if (urb->status == -EPIPE) { - int pipe = urb->pipe; - - if (!usb_pipecontrol (pipe)) - usb_endpoint_halt (urb->dev, - usb_pipeendpoint (pipe), - usb_pipeout (pipe)); - /* if async CSPLIT failed, try cleaning out the TT buffer */ - } else if (urb->dev->tt && !usb_pipeint (urb->pipe) + if (urb->status != -EPIPE + && urb->dev->tt && !usb_pipeint (urb->pipe) && ((token & QTD_STS_MMF) != 0 || QTD_CERR(token) == 0) && (!ehci_is_ARC(ehci) diff -Nru a/drivers/usb/host/hc_simple.c b/drivers/usb/host/hc_simple.c --- a/drivers/usb/host/hc_simple.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/host/hc_simple.c 2004-08-18 23:28:03 -07:00 @@ -146,11 +146,6 @@ if (!urb->dev || !urb->dev->bus || urb->hcpriv) return -EINVAL; - if (usb_endpoint_halted - (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe))) { - printk ("hci_submit_urb: endpoint_halted\n"); - return -EPIPE; - } hci = (hci_t *) urb->dev->bus->hcpriv; /* a request to the virtual root hub */ diff -Nru a/drivers/usb/host/hc_sl811.c b/drivers/usb/host/hc_sl811.c --- a/drivers/usb/host/hc_sl811.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/host/hc_sl811.c 2004-08-18 23:28:03 -07:00 @@ -106,14 +106,14 @@ static int sofWaitCnt = 0; -MODULE_PARM (urb_debug, "i"); +module_param(urb_debug, int, 0); MODULE_PARM_DESC (urb_debug, "debug urb messages, default is 0 (no)"); -MODULE_PARM (base_addr, "i"); +module_param(base_addr, int, 0); MODULE_PARM_DESC (base_addr, "sl811 base address 0xd3800000"); -MODULE_PARM (data_reg_addr, "i"); +module_param(data_reg_addr, int, 0); MODULE_PARM_DESC (data_reg_addr, "sl811 data register address 0xd3810000"); -MODULE_PARM (irq, "i"); +module_param(irq, int, 0); MODULE_PARM_DESC (irq, "IRQ 34 (default)"); static int hc_reset (hci_t * hci); diff -Nru a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c --- a/drivers/usb/host/ohci-omap.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/host/ohci-omap.c 2004-08-18 23:28:03 -07:00 @@ -658,7 +658,7 @@ return ret; } -MODULE_PARM(hmc_mode, "hmc_mode"); +module_param(hmc_mode, int, 0); static void __exit ohci_hcd_omap_cleanup (void) { diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c --- a/drivers/usb/host/ohci-q.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/host/ohci-q.c 2004-08-18 23:28:03 -07:00 @@ -751,12 +751,6 @@ cc = TD_CC_GET (tdINFO); - /* control endpoints only have soft stalls */ - if (type != PIPE_CONTROL && cc == TD_CC_STALL) - usb_endpoint_halt (urb->dev, - usb_pipeendpoint (urb->pipe), - usb_pipeout (urb->pipe)); - /* update packet status if needed (short is normally ok) */ if (cc == TD_DATAUNDERRUN && !(urb->transfer_flags & URB_SHORT_NOT_OK)) diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c --- a/drivers/usb/host/uhci-hcd.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/host/uhci-hcd.c 2004-08-18 23:28:03 -07:00 @@ -82,7 +82,7 @@ #else static int debug = 0; #endif -MODULE_PARM(debug, "i"); +module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level"); static char *errbuf; #define ERRBUF_LEN (32 * 1024) @@ -1120,10 +1120,6 @@ td_error: ret = uhci_map_status(status, uhci_packetout(td_token(td))); - if (ret == -EPIPE) - /* endpoint has stalled - mark it halted */ - usb_endpoint_halt(urb->dev, uhci_endpoint(td_token(td)), - uhci_packetout(td_token(td))); err: /* diff -Nru a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c --- a/drivers/usb/image/microtek.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/image/microtek.c 2004-08-18 23:28:03 -07:00 @@ -214,8 +214,8 @@ #ifdef MTS_DO_DEBUG static inline void mts_debug_dump(struct mts_desc* desc) { - MTS_DEBUG("desc at 0x%x: halted = %02x%02x, toggle = %02x%02x\n", - (int)desc,(int)desc->usb_dev->halted[1],(int)desc->usb_dev->halted[0], + MTS_DEBUG("desc at 0x%x: toggle = %02x%02x\n", + (int)desc, (int)desc->usb_dev->toggle[1],(int)desc->usb_dev->toggle[0] ); MTS_DEBUG("ep_out=%x ep_response=%x ep_image=%x\n", diff -Nru a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c --- a/drivers/usb/input/aiptek.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/input/aiptek.c 2004-08-18 23:28:03 -07:00 @@ -2289,9 +2289,9 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_PARM(programmableDelay, "i"); +module_param(programmableDelay, int, 0); MODULE_PARM_DESC(programmableDelay, "delay used during tablet programming"); -MODULE_PARM(jitterDelay, "i"); +module_param(jitterDelay, int, 0); MODULE_PARM_DESC(jitterDelay, "stylus/mouse settlement delay"); module_init(aiptek_init); diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c --- a/drivers/usb/input/hid-core.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/input/hid-core.c 2004-08-18 23:28:03 -07:00 @@ -1619,11 +1619,17 @@ struct usb_endpoint_descriptor *endpoint; int pipe; + int interval; endpoint = &interface->endpoint[n].desc; if ((endpoint->bmAttributes & 3) != 3) /* Not an interrupt endpoint */ continue; + /* handle potential highspeed HID correctly */ + interval = endpoint->bInterval; + if (dev->speed == USB_SPEED_HIGH) + interval = 1 << (interval - 1); + if (endpoint->bEndpointAddress & USB_DIR_IN) { int len; @@ -1636,7 +1642,7 @@ if (len > HID_BUFFER_SIZE) len = HID_BUFFER_SIZE; usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, len, - hid_irq_in, hid, endpoint->bInterval); + hid_irq_in, hid, interval); hid->urbin->transfer_dma = hid->inbuf_dma; hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; } else { @@ -1646,7 +1652,7 @@ goto fail; pipe = usb_sndintpipe(dev, endpoint->bEndpointAddress); usb_fill_int_urb(hid->urbout, dev, pipe, hid->outbuf, 0, - hid_irq_out, hid, 1); + hid_irq_out, hid, interval); hid->urbout->transfer_dma = hid->outbuf_dma; hid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; } diff -Nru a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c --- a/drivers/usb/input/kbtab.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/input/kbtab.c 2004-08-18 23:28:03 -07:00 @@ -26,10 +26,9 @@ #define USB_VENDOR_ID_KBGEAR 0x084e -static int kb_pressure_click = 0x10; -MODULE_PARM (kb_pressure_click,"i"); -MODULE_PARM_DESC(kb_pressure_click, - "pressure threshold for clicks"); +static int kb_pressure_click = 0x10; +module_param(kb_pressure_click, int, 0); +MODULE_PARM_DESC(kb_pressure_click, "pressure threshold for clicks"); struct kbtab { signed char *data; diff -Nru a/drivers/usb/media/Kconfig b/drivers/usb/media/Kconfig --- a/drivers/usb/media/Kconfig 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/media/Kconfig 2004-08-18 23:28:03 -07:00 @@ -163,11 +163,11 @@ module will be called se401. config USB_SN9C102 - tristate "USB SN9C10[12] PC Camera Controller support (EXPERIMENTAL)" - depends on USB && VIDEO_DEV && EXPERIMENTAL + tristate "USB SN9C10[12] PC Camera Controller support" + depends on USB && VIDEO_DEV ---help--- - Say Y here if you want support for cameras based on SN9C101 and - SN9C102 PC Camera Controllers. + Say Y here if you want support for cameras based on SONiX SN9C101 + or SN9C102 PC Camera Controllers. See for more informations. diff -Nru a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile --- a/drivers/usb/media/Makefile 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/media/Makefile 2004-08-18 23:28:03 -07:00 @@ -3,7 +3,7 @@ # pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o -sn9c102-objs := sn9c102_core.o sn9c102_pas106b.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o +sn9c102-objs := sn9c102_core.o sn9c102_pas106b.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o sn9c102_pas202bcb.o obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_DSBR) += dsbr100.o diff -Nru a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c --- a/drivers/usb/media/dabusb.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/media/dabusb.c 2004-08-18 23:28:03 -07:00 @@ -868,7 +868,7 @@ MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); -MODULE_PARM (buffers, "i"); +module_param(buffers, int, 0); MODULE_PARM_DESC (buffers, "Number of buffers (default=256)"); module_init (dabusb_init); diff -Nru a/drivers/usb/media/dsbr100.c b/drivers/usb/media/dsbr100.c --- a/drivers/usb/media/dsbr100.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/media/dsbr100.c 2004-08-18 23:28:03 -07:00 @@ -107,7 +107,7 @@ static int usb_dsbr100_close(struct inode *inode, struct file *file); static int radio_nr = -1; -MODULE_PARM(radio_nr, "i"); +module_param(radio_nr, int, 0); /* Data for one (physical) device */ typedef struct { diff -Nru a/drivers/usb/media/ibmcam.c b/drivers/usb/media/ibmcam.c --- a/drivers/usb/media/ibmcam.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/media/ibmcam.c 2004-08-18 23:28:03 -07:00 @@ -124,38 +124,38 @@ /* Settings for camera model 3 */ static int init_model3_input = 0; -MODULE_PARM(debug, "i"); +module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); -MODULE_PARM(flags, "i"); +module_param(flags, int, 0); MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, 1=B/W, 2=show hints, 3=show stats, 4=test pattern, 5=separate frames, 6=clean frames"); -MODULE_PARM(framerate, "i"); +module_param(framerate, int, 0); MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)"); -MODULE_PARM(lighting, "i"); +module_param(lighting, int, 0); MODULE_PARM_DESC(lighting, "Photosensitivity: 0=bright, 1=medium (default), 2=low light"); -MODULE_PARM(sharpness, "i"); +module_param(sharpness, int, 0); MODULE_PARM_DESC(sharpness, "Model1 noise reduction: 0=smooth, 6=sharp (default=4)"); -MODULE_PARM(size, "i"); +module_param(size, int, 0); MODULE_PARM_DESC(size, "Image size: 0=128x96 1=160x120 2=176x144 3=320x240 4=352x240 5=352x288 6=640x480 (default=5)"); -MODULE_PARM(init_brightness, "i"); +module_param(init_brightness, int, 0); MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)"); -MODULE_PARM(init_contrast, "i"); +module_param(init_contrast, int, 0); MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)"); -MODULE_PARM(init_color, "i"); +module_param(init_color, int, 0); MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)"); -MODULE_PARM(init_hue, "i"); +module_param(init_hue, int, 0); MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)"); -MODULE_PARM(hue_correction, "i"); +module_param(hue_correction, int, 0); MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)"); -MODULE_PARM(init_model2_rg2, "i"); +module_param(init_model2_rg2, int, 0); MODULE_PARM_DESC(init_model2_rg2, "Model2 preconfiguration: 0-255 (default=47)"); -MODULE_PARM(init_model2_sat, "i"); +module_param(init_model2_sat, int, 0); MODULE_PARM_DESC(init_model2_sat, "Model2 preconfiguration: 0-255 (default=52)"); -MODULE_PARM(init_model2_yb, "i"); +module_param(init_model2_yb, int, 0); MODULE_PARM_DESC(init_model2_yb, "Model2 preconfiguration: 0-255 (default=160)"); /* 01.01.08 - Added for RCA video in support -LO */ -MODULE_PARM(init_model3_input, "i"); +module_param(init_model3_input, int, 0); MODULE_PARM_DESC(init_model3_input, "Model3 input: 0=CCD 1=RCA"); MODULE_AUTHOR ("Dmitri"); diff -Nru a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c --- a/drivers/usb/media/konicawc.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/media/konicawc.c 2004-08-18 23:28:03 -07:00 @@ -68,7 +68,7 @@ /* Some default values for initial camera settings, can be set by modprobe */ -static enum frame_sizes size; +static int size; static int speed = 6; /* Speed (fps) 0 (slowest) to 6 (fastest) */ static int brightness = MAX_BRIGHTNESS/2; static int contrast = MAX_CONTRAST/2; @@ -928,23 +928,23 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Simon Evans "); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_PARM(speed, "i"); +module_param(speed, int, 0); MODULE_PARM_DESC(speed, "Initial speed: 0 (slowest) - 6 (fastest)"); -MODULE_PARM(size, "i"); +module_param(size, int, 0); MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 160x136 2: 176x144 3: 320x240"); -MODULE_PARM(brightness, "i"); +module_param(brightness, int, 0); MODULE_PARM_DESC(brightness, "Initial brightness 0 - 108"); -MODULE_PARM(contrast, "i"); +module_param(contrast, int, 0); MODULE_PARM_DESC(contrast, "Initial contrast 0 - 108"); -MODULE_PARM(saturation, "i"); +module_param(saturation, int, 0); MODULE_PARM_DESC(saturation, "Initial saturation 0 - 108"); -MODULE_PARM(sharpness, "i"); +module_param(sharpness, int, 0); MODULE_PARM_DESC(sharpness, "Initial brightness 0 - 108"); -MODULE_PARM(whitebal, "i"); +module_param(whitebal, int, 0); MODULE_PARM_DESC(whitebal, "Initial white balance 0 - 363"); #ifdef CONFIG_USB_DEBUG -MODULE_PARM(debug, "i"); +module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); #endif diff -Nru a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c --- a/drivers/usb/media/ov511.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/media/ov511.c 2004-08-18 23:28:03 -07:00 @@ -119,78 +119,79 @@ static int mirror; static int ov518_color; -MODULE_PARM(autobright, "i"); +module_param(autobright, int, 0); MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness"); -MODULE_PARM(autogain, "i"); +module_param(autogain, int, 0); MODULE_PARM_DESC(autogain, "Sensor automatically changes gain"); -MODULE_PARM(autoexp, "i"); +module_param(autoexp, int, 0); MODULE_PARM_DESC(autoexp, "Sensor automatically changes exposure"); -MODULE_PARM(debug, "i"); +module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max"); -MODULE_PARM(snapshot, "i"); +module_param(snapshot, int, 0); MODULE_PARM_DESC(snapshot, "Enable snapshot mode"); -MODULE_PARM(cams, "i"); +module_param(cams, int, 0); MODULE_PARM_DESC(cams, "Number of simultaneous cameras"); -MODULE_PARM(compress, "i"); +module_param(compress, int, 0); MODULE_PARM_DESC(compress, "Turn on compression"); -MODULE_PARM(testpat, "i"); +module_param(testpat, int, 0); MODULE_PARM_DESC(testpat, "Replace image with vertical bar testpattern (only partially working)"); -MODULE_PARM(dumppix, "i"); +module_param(dumppix, int, 0); MODULE_PARM_DESC(dumppix, "Dump raw pixel data"); -MODULE_PARM(led, "i"); +module_param(led, int, 0); MODULE_PARM_DESC(led, "LED policy (OV511+ or later). 0=off, 1=on (default), 2=auto (on when open)"); -MODULE_PARM(dump_bridge, "i"); +module_param(dump_bridge, int, 0); MODULE_PARM_DESC(dump_bridge, "Dump the bridge registers"); -MODULE_PARM(dump_sensor, "i"); +module_param(dump_sensor, int, 0); MODULE_PARM_DESC(dump_sensor, "Dump the sensor registers"); -MODULE_PARM(printph, "i"); +module_param(printph, int, 0); MODULE_PARM_DESC(printph, "Print frame start/end headers"); -MODULE_PARM(phy, "i"); +module_param(phy, int, 0); MODULE_PARM_DESC(phy, "Prediction range (horiz. Y)"); -MODULE_PARM(phuv, "i"); +module_param(phuv, int, 0); MODULE_PARM_DESC(phuv, "Prediction range (horiz. UV)"); -MODULE_PARM(pvy, "i"); +module_param(pvy, int, 0); MODULE_PARM_DESC(pvy, "Prediction range (vert. Y)"); -MODULE_PARM(pvuv, "i"); +module_param(pvuv, int, 0); MODULE_PARM_DESC(pvuv, "Prediction range (vert. UV)"); -MODULE_PARM(qhy, "i"); +module_param(qhy, int, 0); MODULE_PARM_DESC(qhy, "Quantization threshold (horiz. Y)"); -MODULE_PARM(qhuv, "i"); +module_param(qhuv, int, 0); MODULE_PARM_DESC(qhuv, "Quantization threshold (horiz. UV)"); -MODULE_PARM(qvy, "i"); +module_param(qvy, int, 0); MODULE_PARM_DESC(qvy, "Quantization threshold (vert. Y)"); -MODULE_PARM(qvuv, "i"); +module_param(qvuv, int, 0); MODULE_PARM_DESC(qvuv, "Quantization threshold (vert. UV)"); -MODULE_PARM(lightfreq, "i"); +module_param(lightfreq, int, 0); MODULE_PARM_DESC(lightfreq, "Light frequency. Set to 50 or 60 Hz, or zero for default settings"); -MODULE_PARM(bandingfilter, "i"); +module_param(bandingfilter, int, 0); MODULE_PARM_DESC(bandingfilter, "Enable banding filter (to reduce effects of fluorescent lighting)"); -MODULE_PARM(clockdiv, "i"); +module_param(clockdiv, int, 0); MODULE_PARM_DESC(clockdiv, "Force pixel clock divisor to a specific value"); -MODULE_PARM(packetsize, "i"); +module_param(packetsize, int, 0); MODULE_PARM_DESC(packetsize, "Force a specific isoc packet size"); -MODULE_PARM(framedrop, "i"); +module_param(framedrop, int, 0); MODULE_PARM_DESC(framedrop, "Force a specific frame drop register setting"); -MODULE_PARM(fastset, "i"); +module_param(fastset, int, 0); MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately"); -MODULE_PARM(force_palette, "i"); +module_param(force_palette, int, 0); MODULE_PARM_DESC(force_palette, "Force the palette to a specific value"); -MODULE_PARM(backlight, "i"); +module_param(backlight, int, 0); MODULE_PARM_DESC(backlight, "For objects that are lit from behind"); -MODULE_PARM(unit_video, "1-" __MODULE_STRING(OV511_MAX_UNIT_VIDEO) "i"); +static int num_uv; +module_param_array(unit_video, int, num_uv, 0); MODULE_PARM_DESC(unit_video, "Force use of specific minor number(s). 0 is not allowed."); -MODULE_PARM(remove_zeros, "i"); +module_param(remove_zeros, int, 0); MODULE_PARM_DESC(remove_zeros, "Remove zero-padding from uncompressed incoming data"); -MODULE_PARM(mirror, "i"); +module_param(mirror, int, 0); MODULE_PARM_DESC(mirror, "Reverse image horizontally"); -MODULE_PARM(ov518_color, "i"); +module_param(ov518_color, int, 0); MODULE_PARM_DESC(ov518_color, "Enable OV518 color (experimental)"); MODULE_AUTHOR(DRIVER_AUTHOR); @@ -1169,7 +1170,7 @@ return -EIO; /* Wait for it to initialize */ - schedule_timeout(1 + 150 * HZ / 1000); + msleep(150); for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && @@ -1182,7 +1183,7 @@ if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO; /* Wait for it to initialize */ - schedule_timeout(1 + 150 * HZ / 1000); + msleep(150); /* Dummy read to sync I2C */ if (i2c_r(ov, 0x00) < 0) return -EIO; @@ -4947,7 +4948,7 @@ return -1; /* Wait for it to initialize */ - schedule_timeout(1 + 150 * HZ / 1000); + msleep(150); i = 0; success = 0; diff -Nru a/drivers/usb/media/pwc-if.c b/drivers/usb/media/pwc-if.c --- a/drivers/usb/media/pwc-if.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/media/pwc-if.c 2004-08-18 23:28:03 -07:00 @@ -2009,33 +2009,35 @@ * Initialization code & module stuff */ -static char *size = NULL; +static char size[PSZ_MAX]; static int fps = 0; static int fbufs = 0; static int mbufs = 0; static int trace = -1; static int compression = -1; -static int leds[2] = { -1, -1 }; static char *dev_hint[MAX_DEV_HINTS] = { }; -MODULE_PARM(size, "s"); +module_param_string(size, size, PSZ_MAX, 0); MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga"); -MODULE_PARM(fps, "i"); +module_param(fps, int, 0); MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30"); -MODULE_PARM(fbufs, "i"); +module_param(fbufs, int, 0); MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve"); -MODULE_PARM(mbufs, "i"); +module_param(mbufs, int, 0); MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers"); -MODULE_PARM(trace, "i"); +module_param(trace, int, 0); MODULE_PARM_DESC(trace, "For debugging purposes"); -MODULE_PARM(power_save, "i"); +module_param(power_save, int, 0); MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off"); -MODULE_PARM(compression, "i"); +module_param(compression, int, 0); MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); -MODULE_PARM(leds, "2i"); -MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); -MODULE_PARM(dev_hint, "0-20s"); -MODULE_PARM_DESC(dev_hint, "Device node hints"); +module_param(led_on, int, 0); +MODULE_PARM_DESC(led_on, "LED on time in milliseconds"); +module_param(led_off, int, 0); +MODULE_PARM_DESC(led_off, "LED off time in milliseconds"); +/* Commented out, as you should be using udev instead of crud like this... */ +/* MODULE_PARM(dev_hint, "0-20s"); */ +/* MODULE_PARM_DESC(dev_hint, "Device node hints"); */ MODULE_DESCRIPTION("Philips & OEM USB webcam driver"); MODULE_AUTHOR("Nemosoft Unv. "); @@ -2060,7 +2062,7 @@ Info("Default framerate set to %d.\n", default_fps); } - if (size) { + if (strlen(size)) { /* string; try matching with array */ for (sz = 0; sz < PSZ_MAX; sz++) { if (!strcmp(sizenames[sz], size)) { /* Found! */ @@ -2104,10 +2106,6 @@ } if (power_save) Info("Enabling power save on open/close.\n"); - if (leds[0] >= 0) - led_on = leds[0]; - if (leds[1] >= 0) - led_off = leds[1]; /* Big device node whoopla. Basicly, it allows you to assign a device node (/dev/videoX) to a camera, based on its type diff -Nru a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c --- a/drivers/usb/media/se401.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/media/se401.c 2004-08-18 23:28:03 -07:00 @@ -53,9 +53,9 @@ MODULE_AUTHOR("Jeroen Vreeken "); MODULE_DESCRIPTION("SE401 USB Camera Driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(flickerless, "i"); +module_param(flickerless, int, 0); MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)"); -MODULE_PARM(video_nr, "i"); +module_param(video_nr, int, 0); static struct usb_driver se401_driver; diff -Nru a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h --- a/drivers/usb/media/sn9c102.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/media/sn9c102.h 2004-08-18 23:28:03 -07:00 @@ -31,6 +31,7 @@ #include #include #include +#include #include "sn9c102_sensor.h" @@ -51,8 +52,8 @@ #define SN9C102_MODULE_AUTHOR "(C) 2004 Luca Risolia" #define SN9C102_AUTHOR_EMAIL "" #define SN9C102_MODULE_LICENSE "GPL" -#define SN9C102_MODULE_VERSION "1:1.01-beta" -#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 1) +#define SN9C102_MODULE_VERSION "1:1.07" +#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 7) SN9C102_ID_TABLE; SN9C102_SENSOR_TABLE; diff -Nru a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c --- a/drivers/usb/media/sn9c102_core.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/media/sn9c102_core.c 2004-08-18 23:28:03 -07:00 @@ -83,7 +83,7 @@ /*****************************************************************************/ -typedef char sn9c102_sof_header_t[7]; +typedef char sn9c102_sof_header_t[12]; typedef char sn9c102_eof_header_t[4]; static sn9c102_sof_header_t sn9c102_sof_header[] = { @@ -91,8 +91,6 @@ {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01}, }; -/* Number of random bytes that complete the SOF above headers */ -#define SN9C102_SOFLEN 5 static sn9c102_eof_header_t sn9c102_eof_header[] = { {0x00, 0x00, 0x00, 0x00}, @@ -237,9 +235,6 @@ u8* buff = cam->control_buffer; int res; - if (index == 0x18) - value = (value & 0xcf) | (cam->reg[0x18] & 0x30); - *buff = value; res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, @@ -443,14 +438,15 @@ static void* sn9c102_find_sof_header(void* mem, size_t len) { - size_t soflen=sizeof(sn9c102_sof_header_t), SOFLEN=SN9C102_SOFLEN, i; + size_t soflen = sizeof(sn9c102_sof_header_t), i; u8 j, n = sizeof(sn9c102_sof_header) / soflen; - for (i = 0; (len >= soflen+SOFLEN) && (i <= len-soflen-SOFLEN); i++) + for (i = 0; (len >= soflen) && (i <= len - soflen); i++) for (j = 0; j < n; j++) - if (!memcmp(mem + i, sn9c102_sof_header[j], soflen)) + /* It's enough to compare 7 bytes */ + if (!memcmp(mem + i, sn9c102_sof_header[j], 7)) /* Skips the header */ - return mem + i + soflen + SOFLEN; + return mem + i + soflen; return NULL; } @@ -517,10 +513,12 @@ PDBGG("Isochrnous frame: length %u, #%u i", len, i) - /* NOTE: It is probably correct to assume that SOF and EOF + /* + NOTE: It is probably correct to assume that SOF and EOF headers do not occur between two consecutive packets, but who knows..Whatever is the truth, this assumption - doesn't introduce bugs. */ + doesn't introduce bugs. + */ redo: sof = sn9c102_find_sof_header(pos, len); @@ -764,9 +762,11 @@ return (u8)val; } -/* NOTE 1: being inside one of the following methods implies that the v4l +/* + NOTE 1: being inside one of the following methods implies that the v4l device exists for sure (see kobjects and reference counters) - NOTE 2: buffers are PAGE_SIZE long */ + NOTE 2: buffers are PAGE_SIZE long +*/ static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf) { @@ -1019,24 +1019,6 @@ static ssize_t -sn9c102_store_redblue(struct class_device* cd, const char* buf, size_t len) -{ - ssize_t res = 0; - u8 value; - ssize_t count; - - value = sn9c102_strtou8(buf, len, &count); - if (!count) - return -EINVAL; - - if ((res = sn9c102_store_reg(cd, "0x10", 4)) >= 0) - res = sn9c102_store_val(cd, buf, len); - - return res; -} - - -static ssize_t sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) { ssize_t res = 0; @@ -1062,7 +1044,6 @@ sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, sn9c102_show_i2c_val, sn9c102_store_i2c_val); -static CLASS_DEVICE_ATTR(redblue, S_IWUGO, NULL, sn9c102_store_redblue); static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green); @@ -1072,7 +1053,6 @@ video_device_create_file(v4ldev, &class_device_attr_reg); video_device_create_file(v4ldev, &class_device_attr_val); - video_device_create_file(v4ldev, &class_device_attr_redblue); video_device_create_file(v4ldev, &class_device_attr_green); if (cam->sensor->slave_write_id && cam->sensor->slave_read_id) { video_device_create_file(v4ldev, &class_device_attr_i2c_reg); @@ -1118,10 +1098,6 @@ ae_endy = v_size / 2; int err = 0; - /* These are a sort of stroboscopic signal for some sensors */ - err += sn9c102_write_reg(cam, h_size, 0x1a); - err += sn9c102_write_reg(cam, v_size, 0x1b); - err += sn9c102_write_reg(cam, h_start, 0x12); err += sn9c102_write_reg(cam, v_start, 0x13); err += sn9c102_write_reg(cam, h_size, 0x15); @@ -1134,8 +1110,7 @@ return -EIO; PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size " - "%u %u %u %u %u %u", h_start, v_start, h_size, v_size, ho_size, - vo_size) + "%u %u %u %u", h_start, v_start, h_size, v_size) return 0; } @@ -1229,7 +1204,10 @@ struct sn9c102_device* cam; int err = 0; - /* This the only safe way to prevent race conditions with disconnect */ + /* + This is the only safe way to prevent race conditions with + disconnect + */ if (!down_read_trylock(&sn9c102_disconnect)) return -ERESTARTSYS; @@ -1727,6 +1705,12 @@ return -EINVAL; } + /* Preserve R,G or B origin */ + rect->left = (s->_rect.left & 1L) ? + rect->left | 1L : rect->left & ~1L; + rect->top = (s->_rect.top & 1L) ? + rect->top | 1L : rect->top & ~1L; + if (rect->width < 16) rect->width = 16; if (rect->height < 16) @@ -1747,12 +1731,12 @@ rect->width &= ~15L; rect->height &= ~15L; - { /* calculate the scaling factor */ + { /* calculate the actual scaling factor */ u32 a, b; a = rect->width * rect->height; b = pix_format->width * pix_format->height; - scale = b ? (u8)((a / b) <= 1 ? 1 : ((a / b) == 3 ? 2 : - ((a / b) > 4 ? 4 : (a / b)))) : 1; + scale = b ? (u8)((a / b) < 4 ? 1 : + ((a / b) < 16 ? 2 : 4)) : 1; } if (cam->stream == STREAM_ON) { @@ -1879,12 +1863,12 @@ memcpy(&rect, &(s->_rect), sizeof(rect)); - { /* calculate the scaling factor */ + { /* calculate the actual scaling factor */ u32 a, b; a = rect.width * rect.height; b = pix->width * pix->height; - scale = b ? (u8)((a / b) <= 1 ? 1 : ((a / b) == 3 ? 2 : - ((a / b) > 4 ? 4 : (a / b)))) : 1; + scale = b ? (u8)((a / b) < 4 ? 1 : + ((a / b) < 16 ? 2 : 4)) : 1; } rect.width = scale * pix->width; @@ -1895,12 +1879,20 @@ if (rect.height < 16) rect.height = 16; if (rect.width > bounds->left + bounds->width - rect.left) - rect.width = bounds->left+bounds->width - rect.left; + rect.width = bounds->left + bounds->width - rect.left; if (rect.height > bounds->top + bounds->height - rect.top) rect.height = bounds->top + bounds->height - rect.top; rect.width &= ~15L; rect.height &= ~15L; + + { /* adjust the scaling factor */ + u32 a, b; + a = rect.width * rect.height; + b = pix->width * pix->height; + scale = b ? (u8)((a / b) < 4 ? 1 : + ((a / b) < 16 ? 2 : 4)) : 1; + } pix->width = rect.width / scale; pix->height = rect.height / scale; diff -Nru a/drivers/usb/media/sn9c102_pas106b.c b/drivers/usb/media/sn9c102_pas106b.c --- a/drivers/usb/media/sn9c102_pas106b.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/media/sn9c102_pas106b.c 2004-08-18 23:28:03 -07:00 @@ -40,13 +40,12 @@ err += sn9c102_i2c_write(cam, 0x02, 0x0c); err += sn9c102_i2c_write(cam, 0x03, 0x12); err += sn9c102_i2c_write(cam, 0x04, 0x05); - err += sn9c102_i2c_write(cam, 0x05, 0x22); - err += sn9c102_i2c_write(cam, 0x06, 0xac); - err += sn9c102_i2c_write(cam, 0x07, 0x00); + err += sn9c102_i2c_write(cam, 0x05, 0x5a); + err += sn9c102_i2c_write(cam, 0x06, 0x88); + err += sn9c102_i2c_write(cam, 0x07, 0x80); err += sn9c102_i2c_write(cam, 0x08, 0x01); - err += sn9c102_i2c_write(cam, 0x0a, 0x00); + err += sn9c102_i2c_write(cam, 0x0a, 0x01); err += sn9c102_i2c_write(cam, 0x0b, 0x00); - err += sn9c102_i2c_write(cam, 0x0d, 0x00); err += sn9c102_i2c_write(cam, 0x10, 0x06); err += sn9c102_i2c_write(cam, 0x11, 0x06); err += sn9c102_i2c_write(cam, 0x12, 0x00); @@ -64,11 +63,30 @@ { switch (ctrl->id) { case V4L2_CID_RED_BALANCE: - return (ctrl->value = sn9c102_i2c_read(cam, 0x0c))<0 ? -EIO:0; + if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0) + return -EIO; + ctrl->value &= 0x1f; + return 0; case V4L2_CID_BLUE_BALANCE: - return (ctrl->value = sn9c102_i2c_read(cam, 0x09))<0 ? -EIO:0; + if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) + return -EIO; + ctrl->value &= 0x1f; + return 0; + case V4L2_CID_GAIN: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x0e)) < 0) + return -EIO; + ctrl->value &= 0x1f; + return 0; case V4L2_CID_BRIGHTNESS: - return (ctrl->value = sn9c102_i2c_read(cam, 0x0e))<0 ? -EIO:0; + if ((ctrl->value = sn9c102_i2c_read(cam, 0x0d)) < 0) + return -EIO; + ctrl->value &= 0x1f; + return 0; + case V4L2_CID_CONTRAST: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0) + return -EIO; + ctrl->value &= 0x07; + return 0; default: return -EINVAL; } @@ -87,9 +105,15 @@ case V4L2_CID_BLUE_BALANCE: err += sn9c102_i2c_write(cam, 0x09, ctrl->value & 0x1f); break; - case V4L2_CID_BRIGHTNESS: + case V4L2_CID_GAIN: err += sn9c102_i2c_write(cam, 0x0e, ctrl->value & 0x1f); break; + case V4L2_CID_BRIGHTNESS: + err += sn9c102_i2c_write(cam, 0x0d, ctrl->value & 0x1f); + break; + case V4L2_CID_CONTRAST: + err += sn9c102_i2c_write(cam, 0x0f, ctrl->value & 0x03); + break; default: return -EINVAL; } @@ -130,7 +154,7 @@ .minimum = 0x00, .maximum = 0x1f, .step = 0x01, - .default_value = 0x03, + .default_value = 0x04, .flags = 0, }, { @@ -140,17 +164,37 @@ .minimum = 0x00, .maximum = 0x1f, .step = 0x01, - .default_value = 0x02, + .default_value = 0x06, + .flags = 0, + }, + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "global gain", + .minimum = 0x00, + .maximum = 0x1f, + .step = 0x01, + .default_value = 0x0d, .flags = 0, }, { .id = V4L2_CID_BRIGHTNESS, .type = V4L2_CTRL_TYPE_INTEGER, - .name = "brightness", + .name = "darkness", .minimum = 0x00, .maximum = 0x1f, .step = 0x01, - .default_value = 0x06, + .default_value = 0x00, + .flags = 0, + }, + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "contrast", + .minimum = 0x00, + .maximum = 0x07, + .step = 0x01, + .default_value = 0x00, /* 0x00~0x03 have same effect */ .flags = 0, }, }, @@ -185,11 +229,13 @@ int r0 = 0, r1 = 0, err = 0; unsigned int pid = 0; - /* Minimal initialization to enable the I2C communication - NOTE: do NOT change the values! */ + /* + Minimal initialization to enable the I2C communication + NOTE: do NOT change the values! + */ err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */ err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */ - err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 48 MHz */ + err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */ if (err) return -EIO; diff -Nru a/drivers/usb/media/sn9c102_pas202bcb.c b/drivers/usb/media/sn9c102_pas202bcb.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/usb/media/sn9c102_pas202bcb.c 2004-08-18 23:28:03 -07:00 @@ -0,0 +1,238 @@ +/*************************************************************************** + * Driver for PAS202BCB image sensor connected to the SN9C10[12] PC Camera * + * Controllers * + * * + * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio * + * * + * http://cadu.homelinux.com:8080/ * + * * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * + ***************************************************************************/ + +#include +#include "sn9c102_sensor.h" + + +static struct sn9c102_sensor pas202bcb; + + +static int pas202bcb_init(struct sn9c102_device* cam) +{ + int err = 0; + + err += sn9c102_write_reg(cam, 0x00, 0x10); + err += sn9c102_write_reg(cam, 0x00, 0x11); + err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x20, 0x17); + err += sn9c102_write_reg(cam, 0x20, 0x19); + err += sn9c102_write_reg(cam, 0x09, 0x18); + + err += sn9c102_i2c_write(cam, 0x02, 0x0c); + err += sn9c102_i2c_write(cam, 0x03, 0x40); + err += sn9c102_i2c_write(cam, 0x04, 0x07); + err += sn9c102_i2c_write(cam, 0x05, 0x25); + err += sn9c102_i2c_write(cam, 0x0d, 0x2c); + err += sn9c102_i2c_write(cam, 0x0e, 0x01); + err += sn9c102_i2c_write(cam, 0x0f, 0xa9); + err += sn9c102_i2c_write(cam, 0x08, 0x01); + err += sn9c102_i2c_write(cam, 0x0b, 0x01); + err += sn9c102_i2c_write(cam, 0x13, 0x63); + err += sn9c102_i2c_write(cam, 0x15, 0x70); + err += sn9c102_i2c_write(cam, 0x11, 0x01); + + msleep(400); + + return err; +} + + +static int pas202bcb_get_ctrl(struct sn9c102_device* cam, + struct v4l2_control* ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_RED_BALANCE: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0) + return -EIO; + ctrl->value &= 0x0f; + return 0; + case V4L2_CID_BLUE_BALANCE: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0) + return -EIO; + ctrl->value &= 0x0f; + return 0; + case V4L2_CID_GAIN: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0) + return -EIO; + ctrl->value &= 0x1f; + return 0; + case V4L2_CID_BRIGHTNESS: + if ((ctrl->value = sn9c102_i2c_read(cam, 0x06)) < 0) + return -EIO; + ctrl->value &= 0x0f; + return 0; + default: + return -EINVAL; + } +} + + +static int pas202bcb_set_ctrl(struct sn9c102_device* cam, + const struct v4l2_control* ctrl) +{ + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_RED_BALANCE: + err += sn9c102_i2c_write(cam, 0x09, ctrl->value & 0x0f); + break; + case V4L2_CID_BLUE_BALANCE: + err += sn9c102_i2c_write(cam, 0x07, ctrl->value & 0x0f); + break; + case V4L2_CID_GAIN: + err += sn9c102_i2c_write(cam, 0x10, ctrl->value & 0x1f); + break; + case V4L2_CID_BRIGHTNESS: + err += sn9c102_i2c_write(cam, 0x06, ctrl->value & 0x0f); + break; + default: + return -EINVAL; + } + err += sn9c102_i2c_write(cam, 0x11, 0x01); + + return err; +} + + +static int pas202bcb_set_crop(struct sn9c102_device* cam, + const struct v4l2_rect* rect) +{ + struct sn9c102_sensor* s = &pas202bcb; + int err = 0; + u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4, + v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3; + + err += sn9c102_write_reg(cam, h_start, 0x12); + err += sn9c102_write_reg(cam, v_start, 0x13); + + return err; +} + + +static struct sn9c102_sensor pas202bcb = { + .name = "PAS202BCB", + .maintainer = "Carlos Eduardo Medaglia Dyonisio " + "", + .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, + .interface = SN9C102_I2C_2WIRES, + .slave_read_id = 0x40, + .slave_write_id = 0x40, + .init = &pas202bcb_init, + .qctrl = { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "red balance", + .minimum = 0x00, + .maximum = 0x0f, + .step = 0x01, + .default_value = 0x01, + .flags = 0, + }, + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "blue balance", + .minimum = 0x00, + .maximum = 0x0f, + .step = 0x01, + .default_value = 0x05, + .flags = 0, + }, + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "global gain", + .minimum = 0x00, + .maximum = 0x1f, + .step = 0x01, + .default_value = 0x0c, + .flags = 0, + }, + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "darkness", + .minimum = 0x00, + .maximum = 0x0f, + .step = 0x01, + .default_value = 0x00, + .flags = 0, + }, + }, + .get_ctrl = &pas202bcb_get_ctrl, + .set_ctrl = &pas202bcb_set_ctrl, + .cropcap = { + .bounds = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + .defrect = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + }, + .set_crop = &pas202bcb_set_crop, + .pix_format = { + .width = 640, + .height = 480, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .priv = 8, + } +}; + + +int sn9c102_probe_pas202bcb(struct sn9c102_device* cam) +{ + int r0 = 0, r1 = 0, err = 0; + unsigned int pid = 0; + + /* + * Minimal initialization to enable the I2C communication + * NOTE: do NOT change the values! + */ + err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */ + err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */ + err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */ + if (err) + return -EIO; + + r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00); + r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01); + + if (r0 < 0 || r1 < 0) + return -EIO; + + pid = (r0 << 4) | ((r1 & 0xf0) >> 4); + if (pid != 0x017) + return -ENODEV; + + sn9c102_attach_sensor(cam, &pas202bcb); + + return 0; +} diff -Nru a/drivers/usb/media/sn9c102_sensor.h b/drivers/usb/media/sn9c102_sensor.h --- a/drivers/usb/media/sn9c102_sensor.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/media/sn9c102_sensor.h 2004-08-18 23:28:03 -07:00 @@ -33,7 +33,8 @@ /*****************************************************************************/ -/* OVERVIEW. +/* + OVERVIEW. This is a small interface that allows you to add support for any CCD/CMOS image sensors connected to the SN9C10X bridges. The entire API is documented below. In the most general case, to support a sensor there are three steps @@ -48,26 +49,33 @@ "sn9c102_pas106b.c" is an example of all this stuff. Remember that you do NOT need to touch the source code of the core module for the things to work properly, unless you find bugs or flaws in it. Finally, do not forget to - read the V4L2 API for completeness. */ + read the V4L2 API for completeness. +*/ /*****************************************************************************/ - -/* Probing functions: on success, you must attach the sensor to the camera + +/* + Probing functions: on success, you must attach the sensor to the camera by calling sn9c102_attach_sensor() provided below. To enable the I2C communication, you might need to perform a really basic initialization of the SN9C10X chip by using the write function declared ahead. - Functions must return 0 on success, the appropriate error otherwise. */ + Functions must return 0 on success, the appropriate error otherwise. +*/ extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); +extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); -/* Add the above entries to this table. Be sure to add the entry in the right +/* + Add the above entries to this table. Be sure to add the entry in the right place, since, on failure, the next probing routine is called according to - the order of the list below, from top to bottom */ + the order of the list below, from top to bottom. +*/ #define SN9C102_SENSOR_TABLE \ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { \ - &sn9c102_probe_pas106b, /* strong detection based on SENSOR vid/pid */\ + &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ \ + &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ \ &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \ &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \ NULL, \ @@ -81,28 +89,29 @@ /* Each SN9C10X camera has proper PID/VID identifiers. Add them here in case.*/ #define SN9C102_ID_TABLE \ static const struct usb_device_id sn9c102_id_table[] = { \ - { USB_DEVICE(0xc45, 0x6001), }, \ + { USB_DEVICE(0xc45, 0x6001), }, /* TAS5110C1B */ \ { USB_DEVICE(0xc45, 0x6005), }, /* TAS5110C1B */ \ { USB_DEVICE(0xc45, 0x6009), }, /* PAS106B */ \ { USB_DEVICE(0xc45, 0x600d), }, /* PAS106B */ \ { USB_DEVICE(0xc45, 0x6024), }, \ - { USB_DEVICE(0xc45, 0x6025), }, /* TAS5130D1B Maybe also TAS5110C1B */\ - { USB_DEVICE(0xc45, 0x6028), }, /* Maybe PAS202B */ \ - { USB_DEVICE(0xc45, 0x6029), }, \ - { USB_DEVICE(0xc45, 0x602a), }, /* Maybe HV7131[D|E1] */ \ - { USB_DEVICE(0xc45, 0x602c), }, /* Maybe OV7620 */ \ - { USB_DEVICE(0xc45, 0x6030), }, /* Maybe MI03 */ \ - { USB_DEVICE(0xc45, 0x8001), }, \ + { USB_DEVICE(0xc45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */ \ + { USB_DEVICE(0xc45, 0x6028), }, /* PAS202BCB */ \ + { USB_DEVICE(0xc45, 0x6029), }, /* PAS106B */ \ + { USB_DEVICE(0xc45, 0x602a), }, /* HV7131[D|E1] */ \ + { USB_DEVICE(0xc45, 0x602c), }, /* OV7620 */ \ + { USB_DEVICE(0xc45, 0x6030), }, /* MI03 */ \ { } \ }; /*****************************************************************************/ -/* Read/write routines: they always return -1 on error, 0 or the read value +/* + Read/write routines: they always return -1 on error, 0 or the read value otherwise. NOTE that a real read operation is not supported by the SN9C10X chip for some of its registers. To work around this problem, a pseudo-read call is provided instead: it returns the last successfully written value - on the register (0 if it has never been written), the usual -1 on error. */ + on the register (0 if it has never been written), the usual -1 on error. +*/ /* The "try" I2C I/O versions are used when probing the sensor */ extern int sn9c102_i2c_try_write(struct sn9c102_device*,struct sn9c102_sensor*, @@ -110,10 +119,12 @@ extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*, u8 address); -/* This must be used if and only if the sensor doesn't implement the standard - I2C protocol, like the TASC sensors. There a number of good reasons why you - must use the single-byte versions of this function: do not abuse. It writes - n bytes, from data0 to datan, (registers 0x09 - 0x09+n of SN9C10X chip) */ +/* + This must be used if and only if the sensor doesn't implement the standard + I2C protocol. There a number of good reasons why you must use the + single-byte versions of this function: do not abuse. It writes n bytes, + from data0 to datan, (registers 0x09 - 0x09+n of SN9C10X chip). +*/ extern int sn9c102_i2c_try_raw_write(struct sn9c102_device* cam, struct sn9c102_sensor* sensor, u8 n, u8 data0, u8 data1, u8 data2, u8 data3, @@ -127,12 +138,14 @@ extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index); extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index); -/* NOTE: there are no debugging functions here. To uniform the output you must +/* + NOTE: there are no debugging functions here. To uniform the output you must use the dev_info()/dev_warn()/dev_err() macros defined in device.h, already included here, the argument being the struct device 'dev' of the sensor structure. Do NOT use these macros before the sensor is attached or the kernel will crash! However you should not need to notify the user about - common errors or other messages, since this is done by the master module. */ + common errors or other messages, since this is done by the master module. +*/ /*****************************************************************************/ @@ -150,24 +163,31 @@ char name[32], /* sensor name */ maintainer[64]; /* name of the mantainer */ - /* These sensor capabilities must be provided if the SN9C10X controller + /* + These sensor capabilities must be provided if the SN9C10X controller needs to communicate through the sensor serial interface by using - at least one of the i2c functions available */ + at least one of the i2c functions available. + */ enum sn9c102_i2c_frequency frequency; enum sn9c102_i2c_interface interface; - /* These identifiers must be provided if the image sensor implements + /* + These identifiers must be provided if the image sensor implements the standard I2C protocol. TASC sensors don't, although they have a serial interface: so this is a case where the "raw" I2C version - could be helpful. */ + could be helpful. + */ u8 slave_read_id, slave_write_id; /* reg. 0x09 */ - /* NOTE: Where not noted,most of the functions below are not mandatory. + /* + NOTE: Where not noted,most of the functions below are not mandatory. Set to null if you do not implement them. If implemented, - they must return 0 on success, the proper error otherwise. */ + they must return 0 on success, the proper error otherwise. + */ int (*init)(struct sn9c102_device* cam); - /* This function is called after the sensor has been attached. + /* + This function is called after the sensor has been attached. It should be used to initialize the sensor only, but may also configure part of the SN9C10X chip if necessary. You don't need to setup picture settings like brightness, contrast, etc.. here, if @@ -177,23 +197,29 @@ specified in the v4l2_queryctrl list of supported controls; Same suggestions apply for other settings, _if_ the corresponding methods are present; if not, the initialization must configure the - sensor according to the default configuration structures below. */ + sensor according to the default configuration structures below. + */ struct v4l2_queryctrl qctrl[V4L2_CID_LASTP1-V4L2_CID_BASE]; - /* Optional list of default controls, defined as indicated in the - V4L2 API. Menu type controls are not handled by this interface. */ + /* + Optional list of default controls, defined as indicated in the + V4L2 API. Menu type controls are not handled by this interface. + */ int (*get_ctrl)(struct sn9c102_device* cam, struct v4l2_control* ctrl); int (*set_ctrl)(struct sn9c102_device* cam, const struct v4l2_control* ctrl); - /* You must implement at least the set_ctrl method if you have defined + /* + You must implement at least the set_ctrl method if you have defined the list above. The returned value must follow the V4L2 specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER are not supported by this driver, so do not implement them. Also, - passed values are NOT checked to see if they are out of bounds. */ + passed values are NOT checked to see if they are out of bounds. + */ struct v4l2_cropcap cropcap; - /* Think the image sensor as a grid of R,G,B monochromatic pixels + /* + Think the image sensor as a grid of R,G,B monochromatic pixels disposed according to a particular Bayer pattern, which describes the complete array of pixels, from (0,0) to (xmax, ymax). We will use this coordinate system from now on. It is assumed the sensor @@ -221,11 +247,13 @@ NOTE: once you have defined the bounds of the active window (struct cropcap.bounds) you must not change them.anymore. Only 'bounds' and 'defrect' fields are mandatory, other fields - will be ignored. */ + will be ignored. + */ int (*set_crop)(struct sn9c102_device* cam, const struct v4l2_rect* rect); - /* To be called on VIDIOC_C_SETCROP. The core module always calls a + /* + To be called on VIDIOC_C_SETCROP. The core module always calls a default routine which configures the appropriate SN9C10X regs (also scaling), but you may need to override/adjust specific stuff. 'rect' contains width and height values that are multiple of 16: in @@ -237,10 +265,12 @@ frame after each HSYNC or VSYNC, so that the image starts with real RGB data (see regs 0x12,0x13) (having set H_SIZE and, V_SIZE you don't have to care about blank pixels or blank - lines at the end of each line or frame). */ + lines at the end of each line or frame). + */ struct v4l2_pix_format pix_format; - /* What you have to define here are: initial 'width' and 'height' of + /* + What you have to define here are: initial 'width' and 'height' of the target rectangle, the bayer 'pixelformat' and 'priv' which we'll be used to indicate the number of bits per pixel, 8 or 9. Nothing more. @@ -249,20 +279,27 @@ suggest 1/1. NOTE 2: as said above, you have to program the SN9C10X chip to get rid of any blank pixels, so that the output of the sensor - matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR). */ + matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR). + */ const struct device* dev; - /* This is the argument for dev_err(), dev_info() and dev_warn(). It + /* + This is the argument for dev_err(), dev_info() and dev_warn(). It is used for debugging purposes. You must not access the struct - before the sensor is attached. */ + before the sensor is attached. + */ const struct usb_device* usbdev; - /* Points to the usb_device struct after the sensor is attached. - Do not touch unless you know what you are doing. */ + /* + Points to the usb_device struct after the sensor is attached. + Do not touch unless you know what you are doing. + */ - /* Do NOT write to the data below, it's READ ONLY. It is used by the + /* + Do NOT write to the data below, it's READ ONLY. It is used by the core module to store successfully updated values of the above - settings, for rollbacks..etc..in case of errors during atomic I/O */ + settings, for rollbacks..etc..in case of errors during atomic I/O + */ struct v4l2_queryctrl _qctrl[V4L2_CID_LASTP1-V4L2_CID_BASE]; struct v4l2_rect _rect; }; diff -Nru a/drivers/usb/media/sn9c102_tas5110c1b.c b/drivers/usb/media/sn9c102_tas5110c1b.c --- a/drivers/usb/media/sn9c102_tas5110c1b.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/media/sn9c102_tas5110c1b.c 2004-08-18 23:28:03 -07:00 @@ -27,16 +27,22 @@ static int tas5110c1b_init(struct sn9c102_device* cam) { + const u8 DARKNESS = 0xb7; int err = 0; err += sn9c102_write_reg(cam, 0x01, 0x01); err += sn9c102_write_reg(cam, 0x44, 0x01); err += sn9c102_write_reg(cam, 0x00, 0x10); err += sn9c102_write_reg(cam, 0x00, 0x11); - err += sn9c102_write_reg(cam, 0x00, 0x14); + err += sn9c102_write_reg(cam, 0x0a, 0x14); err += sn9c102_write_reg(cam, 0x60, 0x17); err += sn9c102_write_reg(cam, 0x06, 0x18); - err += sn9c102_write_reg(cam, 0xcb, 0x19); + err += sn9c102_write_reg(cam, 0xfb, 0x19); + + err += sn9c102_i2c_try_raw_write(cam, &tas5110c1b, 4, 0x11, 0x00, 0xc0, + 0x80, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, &tas5110c1b, 4, 0x11, 0x02, 0x20, + DARKNESS, 0, 0); return err; } @@ -53,6 +59,11 @@ err += sn9c102_write_reg(cam, h_start, 0x12); err += sn9c102_write_reg(cam, v_start, 0x13); + /* Don't change ! */ + err += sn9c102_write_reg(cam, 0x14, 0x1a); + err += sn9c102_write_reg(cam, 0x0a, 0x1b); + err += sn9c102_write_reg(cam, 0xfb, 0x19); + return err; } @@ -60,6 +71,8 @@ static struct sn9c102_sensor tas5110c1b = { .name = "TAS5110C1B", .maintainer = "Luca Risolia ", + .frequency = SN9C102_I2C_100KHZ, + .interface = SN9C102_I2C_3WIRES, .init = &tas5110c1b_init, .cropcap = { .bounds = { @@ -90,8 +103,9 @@ /* This sensor has no identifiers, so let's attach it anyway */ sn9c102_attach_sensor(cam, &tas5110c1b); - /* At the moment, only devices whose PID is 0x6005 have this sensor */ - if (tas5110c1b.usbdev->descriptor.idProduct != 0x6005) + /* At the moment, sensor detection is based on USB pid/vid */ + if (tas5110c1b.usbdev->descriptor.idProduct != 0x6001 && + tas5110c1b.usbdev->descriptor.idProduct != 0x6005) return -ENODEV; return 0; diff -Nru a/drivers/usb/media/sn9c102_tas5130d1b.c b/drivers/usb/media/sn9c102_tas5130d1b.c --- a/drivers/usb/media/sn9c102_tas5130d1b.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/media/sn9c102_tas5130d1b.c 2004-08-18 23:28:03 -07:00 @@ -27,6 +27,7 @@ static int tas5130d1b_init(struct sn9c102_device* cam) { + const u8 DARKNESS = 0xff, CONTRAST = 0xb0, GAIN = 0x08; int err = 0; err += sn9c102_write_reg(cam, 0x01, 0x01); @@ -37,22 +38,15 @@ err += sn9c102_write_reg(cam, 0x00, 0x14); err += sn9c102_write_reg(cam, 0x60, 0x17); err += sn9c102_write_reg(cam, 0x07, 0x18); - err += sn9c102_write_reg(cam, 0x33, 0x19); - err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x40, - 0x47, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x02, 0x20, - 0xa9, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x80, + 0x00, 0, 0); err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0xc0, - 0x49, 0, 0); + GAIN, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x40, + CONTRAST, 0, 0); err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x02, 0x20, - 0x6c, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0xc0, - 0x08, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x20, - 0x00, 0, 0); - - err += sn9c102_write_reg(cam, 0x63, 0x19); + DARKNESS, 0, 0); return err; } @@ -62,13 +56,18 @@ const struct v4l2_rect* rect) { struct sn9c102_sensor* s = &tas5130d1b; - int err = 0; u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12; + int err = 0; err += sn9c102_write_reg(cam, h_start, 0x12); err += sn9c102_write_reg(cam, v_start, 0x13); + /* Do NOT change! */ + err += sn9c102_write_reg(cam, 0x1d, 0x1a); + err += sn9c102_write_reg(cam, 0x10, 0x1b); + err += sn9c102_write_reg(cam, 0xf3, 0x19); + return err; } @@ -108,13 +107,9 @@ /* This sensor has no identifiers, so let's attach it anyway */ sn9c102_attach_sensor(cam, &tas5130d1b); - /* At the moment, only devices whose PID is 0x6025 have this sensor */ + /* At the moment, sensor detection is based on USB pid/vid */ if (tas5130d1b.usbdev->descriptor.idProduct != 0x6025) return -ENODEV; - dev_info(tas5130d1b.dev, "TAS5130D1B detected, but the support for it " - "is disabled at the moment - needs further " - "testing -\n"); - - return -ENODEV; + return 0; } diff -Nru a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c --- a/drivers/usb/media/stv680.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/media/stv680.c 2004-08-18 23:28:03 -07:00 @@ -93,11 +93,11 @@ MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE ("GPL"); -MODULE_PARM (debug, "i"); +module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC (debug, "Debug enabled or not"); -MODULE_PARM (swapRGB_on, "i"); +module_param(swapRGB_on, int, 0); MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never"); -MODULE_PARM (video_nr, "i"); +module_param(video_nr, int, 0); /******************************************************************** * diff -Nru a/drivers/usb/media/ultracam.c b/drivers/usb/media/ultracam.c --- a/drivers/usb/media/ultracam.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/media/ultracam.c 2004-08-18 23:28:03 -07:00 @@ -60,9 +60,9 @@ static int init_hue = 128; static int hue_correction = 128; -MODULE_PARM(debug, "i"); +module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)"); -MODULE_PARM(flags, "i"); +module_param(flags, int, 0); MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, " "1=B/W, " @@ -71,18 +71,18 @@ "4=test pattern, " "5=separate frames, " "6=clean frames"); -MODULE_PARM(framerate, "i"); +module_param(framerate, int, 0); MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)"); -MODULE_PARM(init_brightness, "i"); +module_param(init_brightness, int, 0); MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)"); -MODULE_PARM(init_contrast, "i"); +module_param(init_contrast, int, 0); MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)"); -MODULE_PARM(init_color, "i"); +module_param(init_color, int, 0); MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)"); -MODULE_PARM(init_hue, "i"); +module_param(init_hue, int, 0); MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)"); -MODULE_PARM(hue_correction, "i"); +module_param(hue_correction, int, 0); MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)"); /* diff -Nru a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c --- a/drivers/usb/media/usbvideo.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/media/usbvideo.c 2004-08-18 23:28:03 -07:00 @@ -34,7 +34,7 @@ #endif static int video_nr = -1; -MODULE_PARM(video_nr, "i"); +module_param(video_nr, int, 0); /* * Local prototypes. diff -Nru a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c --- a/drivers/usb/misc/auerswald.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/misc/auerswald.c 2004-08-18 23:28:03 -07:00 @@ -1976,8 +1976,7 @@ dbg ("Version is %X", cp->version); /* allow some time to settle the device */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/3); + msleep(334); /* Try to get a suitable textual description of the device */ /* Device name:*/ diff -Nru a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c --- a/drivers/usb/misc/legousbtower.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/misc/legousbtower.c 2004-08-18 23:28:03 -07:00 @@ -71,6 +71,8 @@ * - make device locking interruptible * 2004-04-30 - 0.95 Juergen Stuber * - check for valid udev on resubmitting and unlinking urbs + * 2004-08-03 - 0.96 Juergen Stuber + * - move reset into open to clean out spurious data */ #include @@ -98,12 +100,12 @@ /* Version Information */ -#define DRIVER_VERSION "v0.95" +#define DRIVER_VERSION "v0.96" #define DRIVER_AUTHOR "Juergen Stuber " #define DRIVER_DESC "LEGO USB Tower Driver" /* Module parameters */ -MODULE_PARM(debug, "i"); +module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); /* The defaults are chosen to work with the latest versions of leJOS and NQC. @@ -114,7 +116,7 @@ * (417 for datalog uploads), and packet_timeout should be set. */ static size_t read_buffer_size = 480; -MODULE_PARM(read_buffer_size, "i"); +module_param(read_buffer_size, int, 0); MODULE_PARM_DESC(read_buffer_size, "Read buffer size"); /* Some legacy software likes to send packets in one piece. @@ -124,7 +126,7 @@ * if the software is not prepared to wait long enough. */ static size_t write_buffer_size = 480; -MODULE_PARM(write_buffer_size, "i"); +module_param(write_buffer_size, int, 0); MODULE_PARM_DESC(write_buffer_size, "Write buffer size"); /* Some legacy software expects reads to contain whole LASM packets. @@ -138,7 +140,7 @@ * Set it to 0 to disable. */ static int packet_timeout = 50; -MODULE_PARM(packet_timeout, "i"); +module_param(packet_timeout, int, 0); MODULE_PARM_DESC(packet_timeout, "Packet timeout in ms"); /* Some legacy software expects blocking reads to time out. @@ -146,7 +148,7 @@ * Set it to 0 to disable. */ static int read_timeout = 200; -MODULE_PARM(read_timeout, "i"); +module_param(read_timeout, int, 0); MODULE_PARM_DESC(read_timeout, "Read timeout in ms"); /* As of kernel version 2.6.4 ehci-hcd uses an @@ -159,11 +161,11 @@ * or set to 0 to use the standard interval from the endpoint descriptors. */ static int interrupt_in_interval = 2; -MODULE_PARM(interrupt_in_interval, "i"); +module_param(interrupt_in_interval, int, 0); MODULE_PARM_DESC(interrupt_in_interval, "Interrupt in interval in ms"); static int interrupt_out_interval = 8; -MODULE_PARM(interrupt_out_interval, "i"); +module_param(interrupt_out_interval, int, 0); MODULE_PARM_DESC(interrupt_out_interval, "Interrupt out interval in ms"); /* Define these values to match your device */ @@ -341,6 +343,8 @@ int subminor; int retval = 0; struct usb_interface *interface; + struct tower_reset_reply reset_reply; + int result; dbg(2, "%s: enter", __FUNCTION__); @@ -378,6 +382,22 @@ } dev->open_count = 1; + /* reset the tower */ + result = usb_control_msg (dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + LEGO_USB_TOWER_REQUEST_RESET, + USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, + 0, + 0, + &reset_reply, + sizeof(reset_reply), + HZ); + if (result < 0) { + err("LEGO USB Tower reset control request failed"); + retval = result; + goto unlock_exit; + } + /* initialize in direction */ dev->read_buffer_length = 0; dev->read_packet_length = 0; @@ -828,7 +848,6 @@ struct lego_usb_tower *dev = NULL; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor* endpoint; - struct tower_reset_reply reset_reply; struct tower_get_version_reply get_version_reply; int i; int retval = -ENOMEM; @@ -950,22 +969,6 @@ /* let the user know what node this device is now attached to */ info ("LEGO USB Tower #%d now attached to major %d minor %d", (dev->minor - LEGO_USB_TOWER_MINOR_BASE), USB_MAJOR, dev->minor); - - /* reset the tower */ - result = usb_control_msg (udev, - usb_rcvctrlpipe(udev, 0), - LEGO_USB_TOWER_REQUEST_RESET, - USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, - 0, - 0, - &reset_reply, - sizeof(reset_reply), - HZ); - if (result < 0) { - err("LEGO USB Tower reset control request failed"); - retval = result; - goto error; - } /* get the firmware version and log it */ result = usb_control_msg (udev, diff -Nru a/drivers/usb/misc/tiglusb.c b/drivers/usb/misc/tiglusb.c --- a/drivers/usb/misc/tiglusb.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/misc/tiglusb.c 2004-08-18 23:28:03 -07:00 @@ -560,7 +560,7 @@ MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE (DRIVER_LICENSE); -MODULE_PARM (timeout, "i"); +module_param(timeout, int, 0); MODULE_PARM_DESC (timeout, "Timeout in tenths of seconds (default=1.5 seconds)"); /* --------------------------------------------------------------------- */ diff -Nru a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c --- a/drivers/usb/net/pegasus.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/net/pegasus.c 2004-08-18 23:28:03 -07:00 @@ -78,8 +78,8 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_PARM(loopback, "i"); -MODULE_PARM(mii_mode, "i"); +module_param(loopback, bool, 0); +module_param(mii_mode, bool, 0); MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)"); MODULE_PARM_DESC(mii_mode, "Enable HomePNA mode (bit 0),default=MII mode = 0"); diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c --- a/drivers/usb/net/usbnet.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/net/usbnet.c 2004-08-18 23:28:03 -07:00 @@ -166,7 +166,7 @@ #define CONTROL_TIMEOUT_JIFFIES ((CONTROL_TIMEOUT_MS * HZ)/1000) // between wakeups -#define UNLINK_TIMEOUT_JIFFIES ((3 /*ms*/ * HZ)/1000) +#define UNLINK_TIMEOUT_MS 3 /*-------------------------------------------------------------------------*/ @@ -268,7 +268,7 @@ /* use ethtool to change the level for any given device */ static int msg_level = 1; -MODULE_PARM (msg_level, "i"); +module_param (msg_level, int, 0); MODULE_PARM_DESC (msg_level, "Initial message level (default = 1)"); @@ -2591,8 +2591,7 @@ while (skb_queue_len (&dev->rxq) && skb_queue_len (&dev->txq) && skb_queue_len (&dev->done)) { - set_current_state (TASK_UNINTERRUPTIBLE); - schedule_timeout (UNLINK_TIMEOUT_JIFFIES); + msleep(UNLINK_TIMEOUT_MS); devdbg (dev, "waited for %d urb completions", temp); } dev->wait = NULL; diff -Nru a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c --- a/drivers/usb/serial/cyberjack.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/serial/cyberjack.c 2004-08-18 23:28:03 -07:00 @@ -44,7 +44,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.0" +#define DRIVER_VERSION "v1.01" #define DRIVER_AUTHOR "Matthias Bruestle" #define DRIVER_DESC "REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver" @@ -111,6 +111,7 @@ static int cyberjack_startup (struct usb_serial *serial) { struct cyberjack_private *priv; + int i; dbg("%s", __FUNCTION__); @@ -128,6 +129,16 @@ init_waitqueue_head(&serial->port[0]->write_wait); + for (i = 0; i < serial->num_ports; ++i) { + int result; + serial->port[i]->interrupt_in_urb->dev = serial->dev; + result = usb_submit_urb(serial->port[i]->interrupt_in_urb, + GFP_KERNEL); + if (result) + err(" usb_submit_urb(read int) failed"); + dbg("%s - usb_submit_urb(int urb)", __FUNCTION__); + } + return( 0 ); } @@ -138,6 +149,7 @@ dbg("%s", __FUNCTION__); for (i=0; i < serial->num_ports; ++i) { + usb_unlink_urb (serial->port[i]->interrupt_in_urb); /* My special items, the standard routines free my urbs */ kfree(usb_get_serial_port_data(serial->port[i])); usb_set_serial_port_data(serial->port[i], NULL); @@ -168,17 +180,6 @@ priv->wrsent = 0; spin_unlock_irqrestore(&priv->lock, flags); - /* shutdown any bulk reads that might be going on */ - usb_unlink_urb (port->write_urb); - usb_unlink_urb (port->read_urb); - usb_unlink_urb (port->interrupt_in_urb); - - port->interrupt_in_urb->dev = port->serial->dev; - result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (result) - err(" usb_submit_urb(read int) failed"); - dbg("%s - usb_submit_urb(int urb)", __FUNCTION__); - return result; } @@ -190,11 +191,6 @@ /* shutdown any bulk reads that might be going on */ usb_unlink_urb (port->write_urb); usb_unlink_urb (port->read_urb); - usb_unlink_urb (port->interrupt_in_urb); - dbg("%s - usb_clear_halt", __FUNCTION__ ); - usb_clear_halt(port->serial->dev, port->write_urb->pipe); - usb_clear_halt(port->serial->dev, port->read_urb->pipe); - usb_clear_halt(port->serial->dev, port->interrupt_in_urb->pipe); } } @@ -376,6 +372,10 @@ } tty = port->tty; + if (!tty) { + dbg("%s - ignoring since device not open\n", __FUNCTION__); + return; + } if (urb->actual_length) { for (i = 0; i < urb->actual_length ; ++i) { /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c --- a/drivers/usb/serial/ftdi_sio.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/serial/ftdi_sio.c 2004-08-18 23:28:03 -07:00 @@ -17,6 +17,11 @@ * See http://ftdi-usb-sio.sourceforge.net for upto date testing info * and extra documentation * + * (21/Jul/2004) Ian Abbott + * Incorporated Steven Turner's code to add support for the FT2232C chip. + * The prelimilary port to the 2.6 kernel was by Rus V. Brushkoff. I have + * fixed a couple of things. + * * (27/May/2004) Ian Abbott * Improved throttling code, mostly stolen from the WhiteHEAT driver. * @@ -259,7 +264,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.4.0" +#define DRIVER_VERSION "v1.4.1" #define DRIVER_AUTHOR "Greg Kroah-Hartman , Bill Ryder , Kuba Ober " #define DRIVER_DESC "USB FTDI Serial Converters Driver" @@ -489,11 +494,18 @@ }; +static struct usb_device_id id_table_FT2232C[] = { + { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, + { } /* Terminating entry */ +}; + + static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, @@ -621,6 +633,8 @@ __u8 rx_flags; /* receive state flags (throttling) */ spinlock_t rx_lock; /* spinlock for receive state */ + __u16 interface; /* FT2232C port interface (0 for FT232/245) */ + int force_baud; /* if non-zero, force the baud rate to this value */ int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ }; @@ -637,6 +651,7 @@ static int ftdi_SIO_startup (struct usb_serial *serial); static int ftdi_8U232AM_startup (struct usb_serial *serial); static int ftdi_FT232BM_startup (struct usb_serial *serial); +static int ftdi_FT2232C_startup (struct usb_serial *serial); static int ftdi_USB_UIRT_startup (struct usb_serial *serial); static int ftdi_HE_TIRA1_startup (struct usb_serial *serial); static void ftdi_shutdown (struct usb_serial *serial); @@ -739,6 +754,32 @@ .shutdown = ftdi_shutdown, }; +static struct usb_serial_device_type ftdi_FT2232C_device = { + .owner = THIS_MODULE, + .name = "FTDI FT2232C Compatible", + .id_table = id_table_FT2232C, + .num_interrupt_in = 0, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = ftdi_open, + .close = ftdi_close, + .throttle = ftdi_throttle, + .unthrottle = ftdi_unthrottle, + .write = ftdi_write, + .write_room = ftdi_write_room, + .chars_in_buffer = ftdi_chars_in_buffer, + .read_bulk_callback = ftdi_read_bulk_callback, + .write_bulk_callback = ftdi_write_bulk_callback, + .tiocmget = ftdi_tiocmget, + .tiocmset = ftdi_tiocmset, + .ioctl = ftdi_ioctl, + .set_termios = ftdi_set_termios, + .break_ctl = ftdi_break_ctl, + .attach = ftdi_FT2232C_startup, + .shutdown = ftdi_shutdown, +}; + static struct usb_serial_device_type ftdi_USB_UIRT_device = { .owner = THIS_MODULE, .name = "USB-UIRT Infrared Tranceiver", @@ -866,7 +907,7 @@ usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - ftdi_high_or_low, 0, + ftdi_high_or_low, priv->interface, buf, 0, WDR_TIMEOUT); kfree(buf); @@ -896,7 +937,7 @@ usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - ftdi_high_or_low, 0, + ftdi_high_or_low, priv->interface, buf, 0, WDR_TIMEOUT); kfree(buf); @@ -909,6 +950,7 @@ static int change_speed(struct usb_serial_port *port) { + struct ftdi_private *priv = usb_get_serial_port_data(port); char *buf; __u16 urb_value; __u16 urb_index; @@ -922,6 +964,9 @@ urb_index_value = get_ftdi_divisor(port); urb_value = (__u16)urb_index_value; urb_index = (__u16)(urb_index_value >> 16); + if (priv->interface) { /* FT2232C */ + urb_index = (__u16)((urb_index << 8) | priv->interface); + } rv = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), @@ -1015,7 +1060,12 @@ } break; case FT232BM: /* FT232BM chip */ - chip_name = "FT232BM"; + case FT2232C: /* FT2232C chip */ + if (priv->chip_type == FT2232C) { + chip_name = "FT2232C"; + } else { + chip_name = "FT232BM"; + } if (baud <= 3000000) { div_value = ftdi_232bm_baud_to_divisor(baud); } else { @@ -1231,6 +1281,35 @@ return (0); } /* ftdi_FT232BM_startup */ +/* Startup for the FT2232C chip */ +/* Called from usbserial:serial_probe */ +static int ftdi_FT2232C_startup (struct usb_serial *serial) +{ /* ftdi_FT2232C_startup */ + struct ftdi_private *priv; + int err; + int inter; + + dbg("%s",__FUNCTION__); + err = ftdi_common_startup(serial); + if (err){ + return (err); + } + + priv = usb_get_serial_port_data(serial->port[0]); + priv->chip_type = FT2232C; + inter = serial->interface->altsetting->desc.bInterfaceNumber; + + if (inter) { + priv->interface = INTERFACE_B; + } + else { + priv->interface = INTERFACE_A; + } + priv->baud_base = 48000000 / 2; /* Would be / 16, but FT2232C supports multiple of 0.125 divisor fractions! */ + + return (0); +} /* ftdi_FT2232C_startup */ + /* Startup for the USB-UIRT device, which requires hardwired baudrate (38400 gets mapped to 312500) */ /* Called from usbserial:serial_probe */ static int ftdi_USB_UIRT_startup (struct usb_serial *serial) @@ -1323,7 +1402,7 @@ usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, FTDI_SIO_RESET_SIO, - 0, buf, 0, WDR_TIMEOUT); + priv->interface, buf, 0, WDR_TIMEOUT); /* Termios defaults are set by usb_serial_init. We don't change port->tty->termios - this would loose speed settings, etc. @@ -1373,6 +1452,7 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp) { /* ftdi_close */ unsigned int c_cflag = port->tty->termios->c_cflag; + struct ftdi_private *priv = usb_get_serial_port_data(port); char buf[1]; dbg("%s", __FUNCTION__); @@ -1383,7 +1463,8 @@ usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, 0, buf, 0, WDR_TIMEOUT) < 0) { + 0, priv->interface, buf, 0, + WDR_TIMEOUT) < 0) { err("error from flowcontrol urb"); } @@ -1796,7 +1877,7 @@ if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, - urb_value , 0, + urb_value , priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state); } @@ -1875,7 +1956,7 @@ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, - urb_value , 0, + urb_value , priv->interface, buf, 0, 100) < 0) { err("%s FAILED to set databits/stopbits/parity", __FUNCTION__); } @@ -1886,7 +1967,7 @@ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, 0, + 0, priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("%s error from disable flowcontrol urb", __FUNCTION__); } @@ -1903,6 +1984,13 @@ if (change_speed(port)) { err("%s urb failed to set baurdrate", __FUNCTION__); } + /* Ensure RTS and DTR are raised */ + else if (set_dtr(port, HIGH) < 0){ + err("%s Error from DTR HIGH urb", __FUNCTION__); + } + else if (set_rts(port, HIGH) < 0){ + err("%s Error from RTS HIGH urb", __FUNCTION__); + } } /* Set flow control */ @@ -1913,7 +2001,7 @@ usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0 , FTDI_SIO_RTS_CTS_HS, + 0 , (FTDI_SIO_RTS_CTS_HS | priv->interface), buf, 0, WDR_TIMEOUT) < 0) { err("urb failed to set to rts/cts flow control"); } @@ -1939,7 +2027,8 @@ usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - urb_value , FTDI_SIO_XON_XOFF_HS, + urb_value , (FTDI_SIO_XON_XOFF_HS + | priv->interface), buf, 0, WDR_TIMEOUT) < 0) { err("urb failed to set to xon/xoff flow control"); } @@ -1951,7 +2040,7 @@ usb_sndctrlpipe(dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, 0, + 0, priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("urb failed to clear flow control"); } @@ -1985,13 +2074,14 @@ break; case FT8U232AM: case FT232BM: + case FT2232C: /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same format as the data returned from the in point */ if ((ret = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), FTDI_SIO_GET_MODEM_STATUS_REQUEST, FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, - 0, 0, + 0, priv->interface, buf, 2, WDR_TIMEOUT)) < 0 ) { err("%s Could not get modem status of device - err: %d", __FUNCTION__, ret); @@ -2206,6 +2296,9 @@ retval = usb_serial_register(&ftdi_FT232BM_device); if (retval) goto failed_FT232BM_register; + retval = usb_serial_register(&ftdi_FT2232C_device); + if (retval) + goto failed_FT2232C_register; retval = usb_serial_register(&ftdi_USB_UIRT_device); if (retval) goto failed_USB_UIRT_register; @@ -2223,6 +2316,8 @@ failed_HE_TIRA1_register: usb_serial_deregister(&ftdi_USB_UIRT_device); failed_USB_UIRT_register: + usb_serial_deregister(&ftdi_FT2232C_device); +failed_FT2232C_register: usb_serial_deregister(&ftdi_FT232BM_device); failed_FT232BM_register: usb_serial_deregister(&ftdi_8U232AM_device); @@ -2241,6 +2336,7 @@ usb_deregister (&ftdi_driver); usb_serial_deregister (&ftdi_HE_TIRA1_device); usb_serial_deregister (&ftdi_USB_UIRT_device); + usb_serial_deregister (&ftdi_FT2232C_device); usb_serial_deregister (&ftdi_FT232BM_device); usb_serial_deregister (&ftdi_8U232AM_device); usb_serial_deregister (&ftdi_SIO_device); diff -Nru a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h --- a/drivers/usb/serial/ftdi_sio.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/serial/ftdi_sio.h 2004-08-18 23:28:03 -07:00 @@ -26,6 +26,7 @@ #define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ #define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */ #define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */ +#define FTDI_8U2232C_PID 0x6010 /* Dual channel device */ #define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */ #define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */ #define FTDI_NF_RIC_PID 0x0001 /* Product Id */ @@ -234,6 +235,21 @@ #define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ #define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ +/* Port interface code for FT2232C */ +#define INTERFACE_A 1 +#define INTERFACE_B 2 + + +/* + * BmRequestType: 1100 0000b + * bRequest: FTDI_E2_READ + * wValue: 0 + * wIndex: Address of word to read + * wLength: 2 + * Data: Will return a word of data from E2Address + * + */ + /* Port Identifier Table */ #define PIT_DEFAULT 0 /* SIOA */ #define PIT_SIOA 1 /* SIOA */ @@ -333,6 +349,7 @@ SIO = 1, FT8U232AM = 2, FT232BM = 3, + FT2232C = 4, } ftdi_chip_type_t; typedef enum { diff -Nru a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c --- a/drivers/usb/serial/ipaq.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/serial/ipaq.c 2004-08-18 23:28:03 -07:00 @@ -127,6 +127,7 @@ { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_E740_ID) }, { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_E335_ID) }, { USB_DEVICE(HTC_VENDOR_ID, HTC_PRODUCT_ID) }, + { USB_DEVICE(HTC_VENDOR_ID, HTC_HIMALAYA_ID) }, { USB_DEVICE(NEC_VENDOR_ID, NEC_PRODUCT_ID) }, { USB_DEVICE(ASUS_VENDOR_ID, ASUS_A600_PRODUCT_ID) }, { USB_DEVICE(ASUS_VENDOR_ID, ASUS_A620_PRODUCT_ID) }, @@ -188,6 +189,7 @@ usb_set_serial_port_data(port, priv); priv->active = 0; priv->queue_len = 0; + priv->free_len = 0; INIT_LIST_HEAD(&priv->queue); INIT_LIST_HEAD(&priv->freelist); diff -Nru a/drivers/usb/serial/ipaq.h b/drivers/usb/serial/ipaq.h --- a/drivers/usb/serial/ipaq.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/serial/ipaq.h 2004-08-18 23:28:03 -07:00 @@ -78,6 +78,7 @@ #define HTC_VENDOR_ID 0x0bb4 #define HTC_PRODUCT_ID 0x00ce +#define HTC_HIMALAYA_ID 0x0a02 #define NEC_VENDOR_ID 0x0409 #define NEC_PRODUCT_ID 0x00d5 diff -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c --- a/drivers/usb/serial/pl2303.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/serial/pl2303.c 2004-08-18 23:28:03 -07:00 @@ -659,7 +659,7 @@ state = BREAK_OFF; else state = BREAK_ON; - dbg("%s - turning break %s", state==BREAK_OFF ? "off" : "on", __FUNCTION__); + dbg("%s - turning break %s", __FUNCTION__, state==BREAK_OFF ? "off" : "on"); result = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), BREAK_REQUEST, BREAK_REQUEST_TYPE, state, diff -Nru a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c --- a/drivers/usb/storage/datafab.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/datafab.c 2004-08-18 23:28:03 -07:00 @@ -50,16 +50,19 @@ * in that routine. */ +#include +#include +#include + +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" #include "debug.h" #include "datafab.h" -#include -#include -#include - static int datafab_determine_lun(struct us_data *us, struct datafab_info *info); @@ -388,7 +391,7 @@ static int datafab_handle_mode_sense(struct us_data *us, - Scsi_Cmnd * srb, + struct scsi_cmnd * srb, int sense_6) { static unsigned char rw_err_page[12] = { @@ -498,7 +501,7 @@ // Transport for the Datafab MDCFE-B // -int datafab_transport(Scsi_Cmnd * srb, struct us_data *us) +int datafab_transport(struct scsi_cmnd * srb, struct us_data *us) { struct datafab_info *info; int rc; @@ -625,12 +628,12 @@ if (srb->cmnd[0] == MODE_SENSE) { US_DEBUGP("datafab_transport: MODE_SENSE_6 detected\n"); - return datafab_handle_mode_sense(us, srb, TRUE); + return datafab_handle_mode_sense(us, srb, 1); } if (srb->cmnd[0] == MODE_SENSE_10) { US_DEBUGP("datafab_transport: MODE_SENSE_10 detected\n"); - return datafab_handle_mode_sense(us, srb, FALSE); + return datafab_handle_mode_sense(us, srb, 0); } if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { diff -Nru a/drivers/usb/storage/datafab.h b/drivers/usb/storage/datafab.h --- a/drivers/usb/storage/datafab.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/datafab.h 2004-08-18 23:28:03 -07:00 @@ -24,7 +24,7 @@ #ifndef _USB_DATAFAB_MDCFE_B_H #define _USB_DATAFAB_MDCFE_B_H -extern int datafab_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int datafab_transport(struct scsi_cmnd *srb, struct us_data *us); struct datafab_info { unsigned long sectors; // total sector count diff -Nru a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c --- a/drivers/usb/storage/debug.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/debug.c 2004-08-18 23:28:03 -07:00 @@ -44,9 +44,15 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include +#include +#include + #include "debug.h" +#include "scsi.h" + -void usb_stor_show_command(Scsi_Cmnd *srb) +void usb_stor_show_command(struct scsi_cmnd *srb) { char *what = NULL; int i; diff -Nru a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h --- a/drivers/usb/storage/debug.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/debug.h 2004-08-18 23:28:03 -07:00 @@ -46,13 +46,13 @@ #include #include -#include -#include "usb.h" + +struct scsi_cmnd; #define USB_STORAGE "usb-storage: " #ifdef CONFIG_USB_STORAGE_DEBUG -void usb_stor_show_command(Scsi_Cmnd *srb); +void usb_stor_show_command(struct scsi_cmnd *srb); void usb_stor_show_sense( unsigned char key, unsigned char asc, unsigned char ascq ); #define US_DEBUGP(x...) printk( KERN_DEBUG USB_STORAGE x ) diff -Nru a/drivers/usb/storage/dpcm.c b/drivers/usb/storage/dpcm.c --- a/drivers/usb/storage/dpcm.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/dpcm.c 2004-08-18 23:28:03 -07:00 @@ -30,6 +30,10 @@ */ #include +#include +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" @@ -41,7 +45,7 @@ * Transport for the Microtech DPCM-USB * */ -int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us) +int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us) { int ret; diff -Nru a/drivers/usb/storage/dpcm.h b/drivers/usb/storage/dpcm.h --- a/drivers/usb/storage/dpcm.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/dpcm.h 2004-08-18 23:28:03 -07:00 @@ -29,6 +29,6 @@ #ifndef _MICROTECH_DPCM_USB_H #define _MICROTECH_DPCM_USB_H -extern int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us); #endif diff -Nru a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c --- a/drivers/usb/storage/freecom.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/freecom.c 2004-08-18 23:28:03 -07:00 @@ -29,12 +29,16 @@ */ #include +#include + +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" #include "debug.h" #include "freecom.h" -#include "linux/hdreg.h" #ifdef CONFIG_USB_STORAGE_DEBUG static void pdump (void *, int); @@ -105,7 +109,7 @@ #define FCM_STATUS_PACKET_LENGTH 4 static int -freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, +freecom_readdata (struct scsi_cmnd *srb, struct us_data *us, unsigned int ipipe, unsigned int opipe, int count) { struct freecom_xfer_wrap *fxfr = @@ -139,7 +143,7 @@ } static int -freecom_writedata (Scsi_Cmnd *srb, struct us_data *us, +freecom_writedata (struct scsi_cmnd *srb, struct us_data *us, int unsigned ipipe, unsigned int opipe, int count) { struct freecom_xfer_wrap *fxfr = @@ -176,7 +180,7 @@ * Transport for the Freecom USB/IDE adaptor. * */ -int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) +int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) { struct freecom_cb_wrap *fcb; struct freecom_status *fst; @@ -302,7 +306,7 @@ * move in. */ switch (us->srb->sc_data_direction) { - case SCSI_DATA_READ: + case DMA_FROM_DEVICE: /* catch bogus "read 0 length" case */ if (!length) break; @@ -334,7 +338,7 @@ US_DEBUGP("Transfer happy\n"); break; - case SCSI_DATA_WRITE: + case DMA_TO_DEVICE: /* catch bogus "write 0 length" case */ if (!length) break; @@ -364,7 +368,7 @@ break; - case SCSI_DATA_NONE: + case DMA_NONE: /* Easy, do nothing. */ break; diff -Nru a/drivers/usb/storage/freecom.h b/drivers/usb/storage/freecom.h --- a/drivers/usb/storage/freecom.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/freecom.h 2004-08-18 23:28:03 -07:00 @@ -29,7 +29,7 @@ #ifndef _FREECOM_USB_H #define _FREECOM_USB_H -extern int freecom_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int freecom_transport(struct scsi_cmnd *srb, struct us_data *us); extern int usb_stor_freecom_reset(struct us_data *us); extern int freecom_init (struct us_data *us); diff -Nru a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c --- a/drivers/usb/storage/isd200.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/isd200.c 2004-08-18 23:28:03 -07:00 @@ -44,6 +44,16 @@ /* Include files */ +#include +#include +#include +#include +#include + +#include +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" @@ -51,11 +61,6 @@ #include "scsiglue.h" #include "isd200.h" -#include -#include -#include -#include -#include /* Timeout defines (in Seconds) */ @@ -349,7 +354,7 @@ * RETURNS: * void */ -static void isd200_build_sense(struct us_data *us, Scsi_Cmnd *srb) +static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb) { struct isd200_info *info = (struct isd200_info *)us->extra; struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0]; @@ -427,7 +432,7 @@ ata.generic.RegisterSelect = REG_CYLINDER_LOW | REG_CYLINDER_HIGH | REG_STATUS | REG_ERROR; - srb->sc_data_direction = SCSI_DATA_READ; + srb->sc_data_direction = DMA_FROM_DEVICE; srb->request_buffer = pointer; srb->request_bufflen = value; break; @@ -439,7 +444,7 @@ ACTION_SELECT_5; ata.generic.RegisterSelect = REG_DEVICE_HEAD; ata.write.DeviceHeadByte = value; - srb->sc_data_direction = SCSI_DATA_NONE; + srb->sc_data_direction = DMA_NONE; break; case ACTION_RESET: @@ -448,7 +453,7 @@ ACTION_SELECT_3|ACTION_SELECT_4; ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER; - srb->sc_data_direction = SCSI_DATA_NONE; + srb->sc_data_direction = DMA_NONE; break; case ACTION_REENABLE: @@ -457,7 +462,7 @@ ACTION_SELECT_3|ACTION_SELECT_4; ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER; - srb->sc_data_direction = SCSI_DATA_NONE; + srb->sc_data_direction = DMA_NONE; break; case ACTION_SOFT_RESET: @@ -466,14 +471,14 @@ ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND; ata.write.DeviceHeadByte = info->DeviceHead; ata.write.CommandByte = WIN_SRST; - srb->sc_data_direction = SCSI_DATA_NONE; + srb->sc_data_direction = DMA_NONE; break; case ACTION_IDENTIFY: US_DEBUGP(" isd200_action(IDENTIFY)\n"); ata.generic.RegisterSelect = REG_COMMAND; ata.write.CommandByte = WIN_IDENTIFY; - srb->sc_data_direction = SCSI_DATA_READ; + srb->sc_data_direction = DMA_FROM_DEVICE; srb->request_buffer = (void *) info->id; srb->request_bufflen = sizeof(struct hd_driveid); break; @@ -535,7 +540,7 @@ * the device and receive the response. */ static void isd200_invoke_transport( struct us_data *us, - Scsi_Cmnd *srb, + struct scsi_cmnd *srb, union ata_cdb *ataCdb ) { int need_auto_sense = 0; @@ -839,7 +844,7 @@ unsigned long endTime; struct isd200_info *info = (struct isd200_info *)us->extra; unsigned char *regs = info->RegsBuf; - int recheckAsMaster = FALSE; + int recheckAsMaster = 0; if ( detect ) endTime = jiffies + ISD200_ENUM_DETECT_TIMEOUT * HZ; @@ -847,7 +852,7 @@ endTime = jiffies + ISD200_ENUM_BSY_TIMEOUT * HZ; /* loop until we detect !BSY or timeout */ - while(TRUE) { + while(1) { #ifdef CONFIG_USB_STORAGE_DEBUG char* mstr = master_slave == ATA_ADDRESS_DEVHEAD_STD ? "Master" : "Slave"; @@ -899,9 +904,9 @@ itself okay as a master also */ if ((master_slave & ATA_ADDRESS_DEVHEAD_SLAVE) && - (recheckAsMaster == FALSE)) { + !recheckAsMaster) { US_DEBUGP(" Identified ATAPI device as slave. Rechecking again as master\n"); - recheckAsMaster = TRUE; + recheckAsMaster = 1; master_slave = ATA_ADDRESS_DEVHEAD_STD; } else { US_DEBUGP(" Identified ATAPI device\n"); @@ -948,15 +953,15 @@ if (retStatus == ISD200_GOOD) { int isslave; /* master or slave? */ - retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, FALSE ); + retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, 0); if (retStatus == ISD200_GOOD) - retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_SLAVE, FALSE ); + retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_SLAVE, 0); if (retStatus == ISD200_GOOD) { retStatus = isd200_srst(us); if (retStatus == ISD200_GOOD) /* ata or atapi? */ - retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, TRUE ); + retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, 1); } isslave = (info->DeviceHead & ATA_ADDRESS_DEVHEAD_SLAVE) ? 1 : 0; @@ -1121,15 +1126,15 @@ * Translate SCSI commands to ATA commands. * * RETURNS: - * TRUE if the command needs to be sent to the transport layer - * FALSE otherwise + * 1 if the command needs to be sent to the transport layer + * 0 otherwise */ -static int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, +static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, union ata_cdb * ataCdb) { struct isd200_info *info = (struct isd200_info *)us->extra; struct hd_driveid *id = info->id; - int sendToTransport = TRUE; + int sendToTransport = 1; unsigned char sectnum, head; unsigned short cylinder; unsigned long lba; @@ -1147,7 +1152,7 @@ usb_stor_set_xfer_buf((unsigned char *) &info->InquiryData, sizeof(info->InquiryData), srb); srb->result = SAM_STAT_GOOD; - sendToTransport = FALSE; + sendToTransport = 0; break; case MODE_SENSE: @@ -1167,7 +1172,7 @@ } else { US_DEBUGP(" Media Status not supported, just report okay\n"); srb->result = SAM_STAT_GOOD; - sendToTransport = FALSE; + sendToTransport = 0; } break; @@ -1185,7 +1190,7 @@ } else { US_DEBUGP(" Media Status not supported, just report okay\n"); srb->result = SAM_STAT_GOOD; - sendToTransport = FALSE; + sendToTransport = 0; } break; @@ -1209,7 +1214,7 @@ usb_stor_set_xfer_buf((unsigned char *) &readCapacityData, sizeof(readCapacityData), srb); srb->result = SAM_STAT_GOOD; - sendToTransport = FALSE; + sendToTransport = 0; } break; @@ -1293,7 +1298,7 @@ } else { US_DEBUGP(" Not removeable media, just report okay\n"); srb->result = SAM_STAT_GOOD; - sendToTransport = FALSE; + sendToTransport = 0; } break; @@ -1319,14 +1324,14 @@ } else { US_DEBUGP(" Nothing to do, just report okay\n"); srb->result = SAM_STAT_GOOD; - sendToTransport = FALSE; + sendToTransport = 0; } break; default: US_DEBUGP("Unsupported SCSI command - 0x%X\n", srb->cmnd[0]); srb->result = DID_ERROR << 16; - sendToTransport = FALSE; + sendToTransport = 0; break; } @@ -1424,9 +1429,9 @@ * */ -void isd200_ata_command(Scsi_Cmnd *srb, struct us_data *us) +void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us) { - int sendToTransport = TRUE; + int sendToTransport = 1; union ata_cdb ataCdb; /* Make sure driver was initialized */ diff -Nru a/drivers/usb/storage/isd200.h b/drivers/usb/storage/isd200.h --- a/drivers/usb/storage/isd200.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/isd200.h 2004-08-18 23:28:03 -07:00 @@ -25,7 +25,7 @@ #ifndef _USB_ISD200_H #define _USB_ISD200_H -extern void isd200_ata_command(Scsi_Cmnd *srb, struct us_data *us); +extern void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us); extern int isd200_Initialization(struct us_data *us); #endif diff -Nru a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c --- a/drivers/usb/storage/jumpshot.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/jumpshot.c 2004-08-18 23:28:03 -07:00 @@ -47,15 +47,19 @@ * in that routine. */ +#include +#include +#include + +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" #include "debug.h" #include "jumpshot.h" -#include -#include -#include static inline int jumpshot_bulk_read(struct us_data *us, unsigned char *data, @@ -319,7 +323,7 @@ } static int jumpshot_handle_mode_sense(struct us_data *us, - Scsi_Cmnd * srb, + struct scsi_cmnd * srb, int sense_6) { static unsigned char rw_err_page[12] = { @@ -426,7 +430,7 @@ // Transport for the Lexar 'Jumpshot' // -int jumpshot_transport(Scsi_Cmnd * srb, struct us_data *us) +int jumpshot_transport(struct scsi_cmnd * srb, struct us_data *us) { struct jumpshot_info *info; int rc; @@ -551,12 +555,12 @@ if (srb->cmnd[0] == MODE_SENSE) { US_DEBUGP("jumpshot_transport: MODE_SENSE_6 detected\n"); - return jumpshot_handle_mode_sense(us, srb, TRUE); + return jumpshot_handle_mode_sense(us, srb, 1); } if (srb->cmnd[0] == MODE_SENSE_10) { US_DEBUGP("jumpshot_transport: MODE_SENSE_10 detected\n"); - return jumpshot_handle_mode_sense(us, srb, FALSE); + return jumpshot_handle_mode_sense(us, srb, 0); } if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { diff -Nru a/drivers/usb/storage/jumpshot.h b/drivers/usb/storage/jumpshot.h --- a/drivers/usb/storage/jumpshot.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/jumpshot.h 2004-08-18 23:28:03 -07:00 @@ -24,7 +24,7 @@ #ifndef _USB_JUMPSHOT_H #define _USB_JUMPSHOT_H -extern int jumpshot_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us); struct jumpshot_info { unsigned long sectors; // total sector count diff -Nru a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c --- a/drivers/usb/storage/protocol.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/protocol.c 2004-08-18 23:28:03 -07:00 @@ -45,6 +45,8 @@ */ #include +#include +#include #include "protocol.h" #include "usb.h" #include "debug.h" @@ -59,7 +61,7 @@ * Fix-up the return data from an INQUIRY command to show * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us */ -static void fix_inquiry_data(Scsi_Cmnd *srb) +static void fix_inquiry_data(struct scsi_cmnd *srb) { unsigned char databuf[3]; unsigned int index, offset; @@ -91,7 +93,7 @@ * Fix-up the return data from a READ CAPACITY command. My Feiya reader * returns a value that is 1 too large. */ -static void fix_read_capacity(Scsi_Cmnd *srb) +static void fix_read_capacity(struct scsi_cmnd *srb) { unsigned int index, offset; u32 c; @@ -120,11 +122,11 @@ * Protocol routines ***********************************************************************/ -void usb_stor_qic157_command(Scsi_Cmnd *srb, struct us_data *us) +void usb_stor_qic157_command(struct scsi_cmnd *srb, struct us_data *us) { /* Pad the ATAPI command with zeros * - * NOTE: This only works because a Scsi_Cmnd struct field contains + * NOTE: This only works because a scsi_cmnd struct field contains * a unsigned char cmnd[16], so we know we have storage available */ for (; srb->cmd_len<12; srb->cmd_len++) @@ -141,11 +143,11 @@ } } -void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us) +void usb_stor_ATAPI_command(struct scsi_cmnd *srb, struct us_data *us) { /* Pad the ATAPI command with zeros * - * NOTE: This only works because a Scsi_Cmnd struct field contains + * NOTE: This only works because a scsi_cmnd struct field contains * a unsigned char cmnd[16], so we know we have storage available */ @@ -166,12 +168,12 @@ } -void usb_stor_ufi_command(Scsi_Cmnd *srb, struct us_data *us) +void usb_stor_ufi_command(struct scsi_cmnd *srb, struct us_data *us) { /* fix some commands -- this is a form of mode translation * UFI devices only accept 12 byte long commands * - * NOTE: This only works because a Scsi_Cmnd struct field contains + * NOTE: This only works because a scsi_cmnd struct field contains * a unsigned char cmnd[16], so we know we have storage available */ @@ -213,7 +215,8 @@ } } -void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us) +void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb, + struct us_data *us) { /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); @@ -241,7 +244,7 @@ * pick up from where this one left off. */ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, - unsigned int buflen, Scsi_Cmnd *srb, unsigned int *index, + unsigned int buflen, struct scsi_cmnd *srb, unsigned int *index, unsigned int *offset, enum xfer_buf_dir dir) { unsigned int cnt; @@ -327,7 +330,7 @@ /* Store the contents of buffer into srb's transfer buffer and set the * SCSI residue. */ void usb_stor_set_xfer_buf(unsigned char *buffer, - unsigned int buflen, Scsi_Cmnd *srb) + unsigned int buflen, struct scsi_cmnd *srb) { unsigned int index = 0, offset = 0; diff -Nru a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h --- a/drivers/usb/storage/protocol.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/protocol.h 2004-08-18 23:28:03 -07:00 @@ -41,9 +41,8 @@ #ifndef _PROTOCOL_H_ #define _PROTOCOL_H_ -#include -#include "scsi.h" -#include "usb.h" +struct scsi_cmnd; +struct us_data; /* Sub Classes */ @@ -60,18 +59,19 @@ #define US_SC_DEVICE 0xff /* Use device's value */ /* Protocol handling routines */ -extern void usb_stor_ATAPI_command(Scsi_Cmnd*, struct us_data*); -extern void usb_stor_qic157_command(Scsi_Cmnd*, struct us_data*); -extern void usb_stor_ufi_command(Scsi_Cmnd*, struct us_data*); -extern void usb_stor_transparent_scsi_command(Scsi_Cmnd*, struct us_data*); +extern void usb_stor_ATAPI_command(struct scsi_cmnd*, struct us_data*); +extern void usb_stor_qic157_command(struct scsi_cmnd*, struct us_data*); +extern void usb_stor_ufi_command(struct scsi_cmnd*, struct us_data*); +extern void usb_stor_transparent_scsi_command(struct scsi_cmnd*, + struct us_data*); -/* Scsi_Cmnd transfer buffer access utilities */ +/* struct scsi_cmnd transfer buffer access utilities */ enum xfer_buf_dir {TO_XFER_BUF, FROM_XFER_BUF}; extern unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, - unsigned int buflen, Scsi_Cmnd *srb, unsigned int *index, + unsigned int buflen, struct scsi_cmnd *srb, unsigned int *index, unsigned int *offset, enum xfer_buf_dir dir); extern void usb_stor_set_xfer_buf(unsigned char *buffer, - unsigned int buflen, Scsi_Cmnd *srb); + unsigned int buflen, struct scsi_cmnd *srb); #endif diff -Nru a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c --- a/drivers/usb/storage/scsiglue.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/scsiglue.c 2004-08-18 23:28:03 -07:00 @@ -44,17 +44,23 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "scsiglue.h" -#include "usb.h" -#include "debug.h" -#include "transport.h" -#include "protocol.h" #include #include + +#include +#include #include +#include +#include #include +#include "scsiglue.h" +#include "usb.h" +#include "debug.h" +#include "transport.h" +#include "protocol.h" + /*********************************************************************** * Host functions ***********************************************************************/ @@ -92,17 +98,15 @@ * the end, scatter-gather buffers follow page boundaries. */ blk_queue_dma_alignment(sdev->request_queue, (512 - 1)); - /* Devices using Genesys Logic chips cause a lot of trouble for - * high-speed transfers; they die unpredictably when given more - * than 64 KB of data at a time. If we detect such a device, - * reduce the maximum transfer size to 64 KB = 128 sectors. */ - -#define USB_VENDOR_ID_GENESYS 0x05e3 // Needs a standard location - + /* According to the technical support people at Genesys Logic, + * devices using their chips have problems transferring more than + * 32 KB at a time. In practice people have found that 64 KB + * works okay and that's what Windows does. But we'll be + * conservative; people can always use the sysfs interface to + * increase max_sectors. */ if (us->pusb_dev->descriptor.idVendor == USB_VENDOR_ID_GENESYS && - us->pusb_dev->speed == USB_SPEED_HIGH && - sdev->request_queue->max_sectors > 128) - blk_queue_max_sectors(sdev->request_queue, 128); + sdev->request_queue->max_sectors > 64) + blk_queue_max_sectors(sdev->request_queue, 64); /* We can't put these settings in slave_alloc() because that gets * called before the device type is known. Consequently these @@ -146,7 +150,8 @@ /* queue a command */ /* This is always called with scsi_lock(srb->host) held */ -static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) +static int queuecommand(struct scsi_cmnd *srb, + void (*done)(struct scsi_cmnd *)) { struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; @@ -176,7 +181,7 @@ /* Command abort */ /* This is always called with scsi_lock(srb->host) held */ -static int command_abort( Scsi_Cmnd *srb ) +static int command_abort(struct scsi_cmnd *srb ) { struct Scsi_Host *host = srb->device->host; struct us_data *us = (struct us_data *) host->hostdata[0]; @@ -223,7 +228,7 @@ /* This invokes the transport reset mechanism to reset the state of the * device */ /* This is always called with scsi_lock(srb->host) held */ -static int device_reset( Scsi_Cmnd *srb ) +static int device_reset(struct scsi_cmnd *srb) { struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; int result; @@ -258,7 +263,7 @@ /* It refuses to work if there's more than one interface in * the device, so that other users are not affected. */ /* This is always called with scsi_lock(srb->host) held */ -static int bus_reset( Scsi_Cmnd *srb ) +static int bus_reset(struct scsi_cmnd *srb) { struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; int result; @@ -444,10 +449,10 @@ * periodically someone should test to see which setting is more * optimal. */ - .use_clustering = TRUE, + .use_clustering = 1, /* emulated HBA */ - .emulated = TRUE, + .emulated = 1, /* we do our own delay after a device or bus reset */ .skip_settle_delay = 1, diff -Nru a/drivers/usb/storage/scsiglue.h b/drivers/usb/storage/scsiglue.h --- a/drivers/usb/storage/scsiglue.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/scsiglue.h 2004-08-18 23:28:03 -07:00 @@ -41,17 +41,15 @@ #ifndef _SCSIGLUE_H_ #define _SCSIGLUE_H_ -#include -#include "scsi.h" #include -#include "usb.h" + +struct us_data; +struct scsi_cmnd; extern void usb_stor_report_device_reset(struct us_data *us); extern unsigned char usb_stor_sense_notready[18]; extern unsigned char usb_stor_sense_invalidCDB[18]; extern struct scsi_host_template usb_stor_host_template; -extern int usb_stor_scsiSense10to6(Scsi_Cmnd*); -extern int usb_stor_scsiSense6to10(Scsi_Cmnd*); #endif diff -Nru a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c --- a/drivers/usb/storage/sddr09.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/sddr09.c 2004-08-18 23:28:03 -07:00 @@ -41,16 +41,19 @@ * EF: compute checksum (?) */ +#include +#include +#include + +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" #include "debug.h" #include "sddr09.h" -#include -#include -#include -#include #define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) ) #define LSB_of(s) ((s)&0xFF) @@ -1401,7 +1404,7 @@ /* * Transport for the Sandisk SDDR-09 */ -int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us) +int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) { static unsigned char sensekey = 0, sensecode = 0; static unsigned char havefakesense = 0; @@ -1581,13 +1584,13 @@ if (srb->request_bufflen == 0) return USB_STOR_TRANSPORT_GOOD; - if (srb->sc_data_direction == SCSI_DATA_WRITE || - srb->sc_data_direction == SCSI_DATA_READ) { - unsigned int pipe = (srb->sc_data_direction == SCSI_DATA_WRITE) + if (srb->sc_data_direction == DMA_TO_DEVICE || + srb->sc_data_direction == DMA_FROM_DEVICE) { + unsigned int pipe = (srb->sc_data_direction == DMA_TO_DEVICE) ? us->send_bulk_pipe : us->recv_bulk_pipe; US_DEBUGP("SDDR09: %s %d bytes\n", - (srb->sc_data_direction == SCSI_DATA_WRITE) ? + (srb->sc_data_direction == DMA_TO_DEVICE) ? "sending" : "receiving", srb->request_bufflen); diff -Nru a/drivers/usb/storage/sddr09.h b/drivers/usb/storage/sddr09.h --- a/drivers/usb/storage/sddr09.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/sddr09.h 2004-08-18 23:28:03 -07:00 @@ -29,7 +29,7 @@ /* Sandisk SDDR-09 stuff */ -extern int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us); struct sddr09_card_info { unsigned long capacity; /* Size of card in bytes */ diff -Nru a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c --- a/drivers/usb/storage/sddr55.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/sddr55.c 2004-08-18 23:28:03 -07:00 @@ -24,15 +24,19 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include +#include +#include + +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" #include "debug.h" #include "sddr55.h" -#include -#include -#include #define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) ) #define LSB_of(s) ((s)&0xFF) @@ -74,7 +78,7 @@ sddr55_bulk_transport(struct us_data *us, int direction, unsigned char *data, unsigned int len) { struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra; - unsigned int pipe = (direction == SCSI_DATA_READ) ? + unsigned int pipe = (direction == DMA_FROM_DEVICE) ? us->recv_bulk_pipe : us->send_bulk_pipe; if (!len) @@ -99,7 +103,7 @@ command[5] = 0xB0; command[7] = 0x80; result = sddr55_bulk_transport(us, - SCSI_DATA_WRITE, command, 8); + DMA_TO_DEVICE, command, 8); US_DEBUGP("Result for send_command in status %d\n", result); @@ -110,7 +114,7 @@ } result = sddr55_bulk_transport(us, - SCSI_DATA_READ, status, 4); + DMA_FROM_DEVICE, status, 4); /* expect to get short transfer if no card fitted */ if (result == USB_STOR_XFER_SHORT || result == USB_STOR_XFER_STALLED) { @@ -139,7 +143,7 @@ /* now read status */ result = sddr55_bulk_transport(us, - SCSI_DATA_READ, status, 2); + DMA_FROM_DEVICE, status, 2); if (result != USB_STOR_XFER_GOOD) { set_sense_info (4, 0, 0); /* hardware error */ @@ -215,7 +219,7 @@ /* send command */ result = sddr55_bulk_transport(us, - SCSI_DATA_WRITE, command, 8); + DMA_TO_DEVICE, command, 8); US_DEBUGP("Result for send_command in read_data %d\n", result); @@ -227,7 +231,7 @@ /* read data */ result = sddr55_bulk_transport(us, - SCSI_DATA_READ, buffer, len); + DMA_FROM_DEVICE, buffer, len); if (result != USB_STOR_XFER_GOOD) { result = USB_STOR_TRANSPORT_ERROR; @@ -236,7 +240,7 @@ /* now read status */ result = sddr55_bulk_transport(us, - SCSI_DATA_READ, status, 2); + DMA_FROM_DEVICE, status, 2); if (result != USB_STOR_XFER_GOOD) { result = USB_STOR_TRANSPORT_ERROR; @@ -390,7 +394,7 @@ /* send command */ result = sddr55_bulk_transport(us, - SCSI_DATA_WRITE, command, 8); + DMA_TO_DEVICE, command, 8); if (result != USB_STOR_XFER_GOOD) { US_DEBUGP("Result for send_command in write_data %d\n", @@ -404,7 +408,7 @@ /* send the data */ result = sddr55_bulk_transport(us, - SCSI_DATA_WRITE, buffer, len); + DMA_TO_DEVICE, buffer, len); if (result != USB_STOR_XFER_GOOD) { US_DEBUGP("Result for send_data in write_data %d\n", @@ -417,7 +421,7 @@ } /* now read status */ - result = sddr55_bulk_transport(us, SCSI_DATA_READ, status, 6); + result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, status, 6); if (result != USB_STOR_XFER_GOOD) { US_DEBUGP("Result for get_status in write_data %d\n", @@ -483,7 +487,7 @@ memset(command, 0, 8); command[5] = 0xB0; command[7] = 0x84; - result = sddr55_bulk_transport(us, SCSI_DATA_WRITE, command, 8); + result = sddr55_bulk_transport(us, DMA_TO_DEVICE, command, 8); US_DEBUGP("Result of send_control for device ID is %d\n", result); @@ -492,7 +496,7 @@ return USB_STOR_TRANSPORT_ERROR; result = sddr55_bulk_transport(us, - SCSI_DATA_READ, content, 4); + DMA_FROM_DEVICE, content, 4); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -502,7 +506,7 @@ if (content[0] != 0xff) { result = sddr55_bulk_transport(us, - SCSI_DATA_READ, content, 2); + DMA_FROM_DEVICE, content, 2); } return USB_STOR_TRANSPORT_GOOD; @@ -624,21 +628,21 @@ command[6] = numblocks * 2 / 256; command[7] = 0x8A; - result = sddr55_bulk_transport(us, SCSI_DATA_WRITE, command, 8); + result = sddr55_bulk_transport(us, DMA_TO_DEVICE, command, 8); if ( result != USB_STOR_XFER_GOOD) { kfree (buffer); return -1; } - result = sddr55_bulk_transport(us, SCSI_DATA_READ, buffer, numblocks * 2); + result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, buffer, numblocks * 2); if ( result != USB_STOR_XFER_GOOD) { kfree (buffer); return -1; } - result = sddr55_bulk_transport(us, SCSI_DATA_READ, command, 2); + result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, command, 2); if ( result != USB_STOR_XFER_GOOD) { kfree (buffer); @@ -734,7 +738,7 @@ /* * Transport for the Sandisk SDDR-55 */ -int sddr55_transport(Scsi_Cmnd *srb, struct us_data *us) +int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us) { int result; static unsigned char inquiry_response[8] = { diff -Nru a/drivers/usb/storage/sddr55.h b/drivers/usb/storage/sddr55.h --- a/drivers/usb/storage/sddr55.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/sddr55.h 2004-08-18 23:28:03 -07:00 @@ -28,7 +28,7 @@ /* Sandisk SDDR-55 stuff */ -extern int sddr55_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us); extern int sddr55_reset(struct us_data *us); #endif diff -Nru a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c --- a/drivers/usb/storage/shuttle_usbat.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/shuttle_usbat.c 2004-08-18 23:28:03 -07:00 @@ -39,16 +39,20 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include +#include +#include +#include + +#include +#include + #include "transport.h" #include "protocol.h" #include "usb.h" #include "debug.h" #include "shuttle_usbat.h" -#include -#include -#include - #define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) ) #define LSB_of(s) ((s)&0xFF) #define MSB_of(s) ((s)>>8) @@ -275,7 +279,7 @@ int minutes) { int result; - unsigned int pipe = (direction == SCSI_DATA_READ) ? + unsigned int pipe = (direction == DMA_FROM_DEVICE) ? us->recv_bulk_pipe : us->send_bulk_pipe; // Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here, @@ -315,9 +319,9 @@ } else cmdlen = 8; - command[cmdlen-8] = (direction==SCSI_DATA_WRITE ? 0x40 : 0xC0); + command[cmdlen-8] = (direction==DMA_TO_DEVICE ? 0x40 : 0xC0); command[cmdlen-7] = access | - (direction==SCSI_DATA_WRITE ? 0x05 : 0x04); + (direction==DMA_TO_DEVICE ? 0x05 : 0x04); command[cmdlen-6] = data_reg; command[cmdlen-5] = status_reg; command[cmdlen-4] = timeout; @@ -355,7 +359,7 @@ //US_DEBUGP("Transfer %s %d bytes, sg buffers %d\n", - // direction == SCSI_DATA_WRITE ? "out" : "in", + // direction == DMA_TO_DEVICE ? "out" : "in", // len, use_sg); result = usb_stor_bulk_transfer_sg(us, @@ -388,7 +392,7 @@ * the bulk output pipe only the first time. */ - if (direction==SCSI_DATA_READ && i==0) { + if (direction==DMA_FROM_DEVICE && i==0) { if (usb_stor_clear_halt(us, us->send_bulk_pipe) < 0) return USB_STOR_TRANSPORT_ERROR; @@ -399,7 +403,7 @@ */ result = usbat_read(us, USBAT_ATA, - direction==SCSI_DATA_WRITE ? 0x17 : 0x0E, + direction==DMA_TO_DEVICE ? 0x17 : 0x0E, status); if (result!=USB_STOR_XFER_GOOD) @@ -410,7 +414,7 @@ return USB_STOR_TRANSPORT_FAILED; US_DEBUGP("Redoing %s\n", - direction==SCSI_DATA_WRITE ? "write" : "read"); + direction==DMA_TO_DEVICE ? "write" : "read"); } else if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -420,7 +424,7 @@ } US_DEBUGP("Bummer! %s bulk data 20 times failed.\n", - direction==SCSI_DATA_WRITE ? "Writing" : "Reading"); + direction==DMA_TO_DEVICE ? "Writing" : "Reading"); return USB_STOR_TRANSPORT_FAILED; } @@ -520,7 +524,7 @@ static int usbat_handle_read10(struct us_data *us, unsigned char *registers, unsigned char *data, - Scsi_Cmnd *srb) + struct scsi_cmnd *srb) { int result = USB_STOR_TRANSPORT_GOOD; unsigned char *buffer; @@ -537,7 +541,7 @@ result = usbat_rw_block_test(us, USBAT_ATA, registers, data, 19, 0x10, 0x17, 0xFD, 0x30, - SCSI_DATA_READ, + DMA_FROM_DEVICE, srb->request_buffer, srb->request_bufflen, srb->use_sg, 1); @@ -606,7 +610,7 @@ result = usbat_rw_block_test(us, USBAT_ATA, registers, data, 19, 0x10, 0x17, 0xFD, 0x30, - SCSI_DATA_READ, + DMA_FROM_DEVICE, buffer, len, 0, 1); @@ -803,7 +807,7 @@ /* * Transport for the HP 8200e */ -int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us) +int hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) { int result; unsigned char *status = us->iobuf; @@ -847,12 +851,12 @@ if (srb->cmnd[0] == TEST_UNIT_READY) transferred = 0; - if (srb->sc_data_direction == SCSI_DATA_WRITE) { + if (srb->sc_data_direction == DMA_TO_DEVICE) { result = usbat_rw_block_test(us, USBAT_ATA, registers, data, 19, 0x10, 0x17, 0xFD, 0x30, - SCSI_DATA_WRITE, + DMA_TO_DEVICE, srb->request_buffer, len, srb->use_sg, 10); @@ -900,7 +904,7 @@ // If there is response data to be read in // then do it here. - if (len != 0 && (srb->sc_data_direction == SCSI_DATA_READ)) { + if (len != 0 && (srb->sc_data_direction == DMA_FROM_DEVICE)) { // How many bytes to read in? Check cylL register diff -Nru a/drivers/usb/storage/shuttle_usbat.h b/drivers/usb/storage/shuttle_usbat.h --- a/drivers/usb/storage/shuttle_usbat.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/shuttle_usbat.h 2004-08-18 23:28:03 -07:00 @@ -53,7 +53,7 @@ #define USBAT_UIO_ADPRST 0x01 // Reset SCM chip /* HP 8200e stuff */ -extern int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us); +extern int hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us); extern int init_8200e(struct us_data *us); #endif diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c --- a/drivers/usb/storage/transport.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/transport.c 2004-08-18 23:28:03 -07:00 @@ -46,15 +46,20 @@ */ #include +#include +#include +#include + +#include +#include +#include + #include "transport.h" #include "protocol.h" #include "scsiglue.h" #include "usb.h" #include "debug.h" -#include -#include -#include /*********************************************************************** * Data transfer routines @@ -260,9 +265,7 @@ USB_ENDPOINT_HALT, endp, NULL, 0, 3*HZ); - /* reset the toggles and endpoint flags */ - usb_endpoint_running(us->pusb_dev, usb_pipeendpoint(pipe), - usb_pipeout(pipe)); + /* reset the endpoint toggle */ usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); @@ -522,7 +525,7 @@ * This is used by the protocol layers to actually send the message to * the device and receive the response. */ -void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) +void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) { int need_auto_sense; int result; @@ -569,7 +572,7 @@ * can signal most data-in errors by stalling the bulk-in pipe. */ if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) && - srb->sc_data_direction != SCSI_DATA_READ) { + srb->sc_data_direction != DMA_FROM_DEVICE) { US_DEBUGP("-- CB transport device requiring auto-sense\n"); need_auto_sense = 1; } @@ -629,7 +632,7 @@ /* set the transfer direction */ old_sc_data_direction = srb->sc_data_direction; - srb->sc_data_direction = SCSI_DATA_READ; + srb->sc_data_direction = DMA_FROM_DEVICE; /* use the new buffer we have */ old_request_buffer = srb->request_buffer; @@ -749,7 +752,7 @@ * Control/Bulk/Interrupt transport */ -int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) +int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us) { unsigned int transfer_length = srb->request_bufflen; unsigned int pipe = 0; @@ -778,7 +781,7 @@ /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ if (transfer_length) { - pipe = srb->sc_data_direction == SCSI_DATA_READ ? + pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe; result = usb_stor_bulk_transfer_sg(us, pipe, srb->request_buffer, transfer_length, @@ -849,7 +852,7 @@ /* * Control/Bulk transport */ -int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us) +int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us) { unsigned int transfer_length = srb->request_bufflen; int result; @@ -877,7 +880,7 @@ /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ if (transfer_length) { - unsigned int pipe = srb->sc_data_direction == SCSI_DATA_READ ? + unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe; result = usb_stor_bulk_transfer_sg(us, pipe, srb->request_buffer, transfer_length, @@ -939,7 +942,7 @@ return -1; } -int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) +int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) { struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf; @@ -952,7 +955,7 @@ /* set up the command wrapper */ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb->DataTransferLength = cpu_to_le32(transfer_length); - bcb->Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0; + bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ? 1 << 7 : 0; bcb->Tag = srb->serial_number; bcb->Lun = srb->device->lun; if (us->flags & US_FL_SCM_MULT_TARG) @@ -977,8 +980,14 @@ /* DATA STAGE */ /* send/receive data payload, if there is any */ + + /* Genesys Logic interface chips need a 100us delay between the + * command phase and the data phase */ + if (us->pusb_dev->descriptor.idVendor == USB_VENDOR_ID_GENESYS) + udelay(100); + if (transfer_length) { - unsigned int pipe = srb->sc_data_direction == SCSI_DATA_READ ? + unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe; result = usb_stor_bulk_transfer_sg(us, pipe, srb->request_buffer, transfer_length, diff -Nru a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h --- a/drivers/usb/storage/transport.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/transport.h 2004-08-18 23:28:03 -07:00 @@ -44,7 +44,8 @@ #include #include #include "usb.h" -#include "scsi.h" + +struct scsi_cmnd; /* Protocols */ @@ -150,16 +151,16 @@ #define US_CBI_ADSC 0 -extern int usb_stor_CBI_transport(Scsi_Cmnd*, struct us_data*); +extern int usb_stor_CBI_transport(struct scsi_cmnd *, struct us_data*); -extern int usb_stor_CB_transport(Scsi_Cmnd*, struct us_data*); +extern int usb_stor_CB_transport(struct scsi_cmnd *, struct us_data*); extern int usb_stor_CB_reset(struct us_data*); -extern int usb_stor_Bulk_transport(Scsi_Cmnd*, struct us_data*); +extern int usb_stor_Bulk_transport(struct scsi_cmnd *, struct us_data*); extern int usb_stor_Bulk_max_lun(struct us_data*); extern int usb_stor_Bulk_reset(struct us_data*); -extern void usb_stor_invoke_transport(Scsi_Cmnd*, struct us_data*); +extern void usb_stor_invoke_transport(struct scsi_cmnd *, struct us_data*); extern void usb_stor_stop_transport(struct us_data*); extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe, diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h --- a/drivers/usb/storage/unusual_devs.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/unusual_devs.h 2004-08-18 23:28:03 -07:00 @@ -45,11 +45,6 @@ * */ -UNUSUAL_DEV( 0x03ee, 0x0000, 0x0000, 0x0245, - "Mitsumi", - "CD-R/RW Drive", - US_SC_8020, US_PR_CBI, NULL, 0), - UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0100, "Mitsumi", "USB FDD", @@ -373,6 +368,15 @@ US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_SINGLE_LUN), +/* Reported by Johann Cardon + * This entry is needed only because the device reports + * bInterfaceClass = 0xff (vendor-specific) + */ +UNUSUAL_DEV( 0x057b, 0x0022, 0x0000, 0x9999, + "Y-E Data", + "Silicon Media R/W", + US_SC_DEVICE, US_PR_DEVICE, NULL, 0), + /* Fabrizio Fellini */ UNUSUAL_DEV( 0x0595, 0x4343, 0x0000, 0x2210, "Fujifilm", @@ -384,11 +388,15 @@ "USB Hard Disk", US_SC_RBC, US_PR_CB, NULL, 0 ), -/* Submitted by Jol Bourquard */ +/* Submitted by Joel Bourquard + * Some versions of this device need the SubClass and Protocol overrides + * while others don't. + */ UNUSUAL_DEV( 0x05ab, 0x0060, 0x1104, 0x1110, "In-System", "PyroGate External CD-ROM Enclosure (FCD-523)", - US_SC_SCSI, US_PR_BULK, NULL, 0 ), + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_NEED_OVERRIDE ), #ifdef CONFIG_USB_STORAGE_ISD200 UNUSUAL_DEV( 0x05ab, 0x0031, 0x0100, 0x0110, @@ -510,11 +518,13 @@ US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN ), +#if !defined(CONFIG_BLK_DEV_UB) && !defined(CONFIG_BLK_DEV_UB_MODULE) UNUSUAL_DEV( 0x0781, 0x0002, 0x0009, 0x0009, "Sandisk", "ImageMate SDDR-31", US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_SER ), +#endif UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x0100, "Sandisk", @@ -685,7 +695,7 @@ "Trumpion", "t33520 USB Flash Card Controller", US_SC_DEVICE, US_PR_BULK, NULL, - US_FL_MODE_XLATE), + US_FL_NEED_OVERRIDE | US_FL_MODE_XLATE), /* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */ UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999, diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c --- a/drivers/usb/storage/usb.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/usb.c 2004-08-18 23:28:03 -07:00 @@ -50,6 +50,11 @@ #include #include #include + +#include +#include +#include + #include "usb.h" #include "scsiglue.h" #include "transport.h" @@ -133,7 +138,9 @@ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_BULK) }, { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_BULK) }, { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_BULK) }, +#if !defined(CONFIG_BLK_DEV_UB) && !defined(CONFIG_BLK_DEV_UB_MODULE) { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) }, +#endif /* Terminating entry */ { } @@ -207,8 +214,10 @@ .useTransport = US_PR_BULK}, { .useProtocol = US_SC_8070, .useTransport = US_PR_BULK}, +#if !defined(CONFIG_BLK_DEV_UB) && !defined(CONFIG_BLK_DEV_UB_MODULE) { .useProtocol = US_SC_SCSI, .useTransport = US_PR_BULK}, +#endif /* Terminating entry */ { NULL } @@ -322,7 +331,7 @@ /* reject the command if the direction indicator * is UNKNOWN */ - if (us->srb->sc_data_direction == SCSI_DATA_UNKNOWN) { + if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) { US_DEBUGP("UNKNOWN data direction\n"); us->srb->result = DID_ERROR << 16; } @@ -423,6 +432,13 @@ us->pusb_dev = interface_to_usbdev(intf); us->pusb_intf = intf; us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; + US_DEBUGP("Vendor: 0x%04x, Product: 0x%04x, Revision: 0x%04x\n", + us->pusb_dev->descriptor.idVendor, + us->pusb_dev->descriptor.idProduct, + us->pusb_dev->descriptor.bcdDevice); + US_DEBUGP("Interface Subclass: 0x%02x, Protocol: 0x%02x\n", + intf->cur_altsetting->desc.bInterfaceSubClass, + intf->cur_altsetting->desc.bInterfaceProtocol); /* Store our private data in the interface */ usb_set_intfdata(intf, us); @@ -453,11 +469,6 @@ struct us_unusual_dev *unusual_dev = &us_unusual_dev_list[id_index]; struct usb_device_id *id = &storage_usb_ids[id_index]; - if (unusual_dev->vendorName) - US_DEBUGP("Vendor: %s\n", unusual_dev->vendorName); - if (unusual_dev->productName) - US_DEBUGP("Product: %s\n", unusual_dev->productName); - /* Store the entries */ us->unusual_dev = unusual_dev; us->subclass = (unusual_dev->useProtocol == US_SC_DEVICE) ? @@ -528,6 +539,8 @@ } if (strlen(us->serial) == 0) strcpy(us->serial, "None"); + + US_DEBUGP("Vendor: %s, Product: %s\n", us->vendor, us->product); } /* Get the transport settings */ @@ -715,8 +728,6 @@ ep_int = ep; } } - US_DEBUGP("Endpoints: In: 0x%p Out: 0x%p Int: 0x%p (Period %d)\n", - ep_in, ep_out, ep_int, ep_int ? ep_int->bInterval : 0); if (!ep_in || !ep_out || (us->protocol == US_PR_CBI && !ep_int)) { US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n"); @@ -880,9 +891,6 @@ int result; US_DEBUGP("USB Mass Storage device detected\n"); - US_DEBUGP("altsetting is %d, id_index is %d\n", - intf->cur_altsetting->desc.bAlternateSetting, - id_index); /* Allocate the us_data structure and initialize the mutexes */ us = (struct us_data *) kmalloc(sizeof(*us), GFP_KERNEL); diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h --- a/drivers/usb/storage/usb.h 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/storage/usb.h 2004-08-18 23:28:03 -07:00 @@ -48,10 +48,9 @@ #include #include #include -#include "scsi.h" -#include struct us_data; +struct scsi_cmnd; /* * Unusual device list definitions @@ -102,9 +101,9 @@ #define US_IOBUF_SIZE 64 /* Size of the DMA-mapped I/O buffer */ -typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*); +typedef int (*trans_cmnd)(struct scsi_cmnd *, struct us_data*); typedef int (*trans_reset)(struct us_data*); -typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*); +typedef void (*proto_cmnd)(struct scsi_cmnd*, struct us_data*); typedef void (*extra_data_destructor)(void *); /* extra data destructor */ /* we allocate one of these for every device that we remember */ @@ -144,7 +143,7 @@ /* SCSI interfaces */ struct Scsi_Host *host; /* our dummy host data */ - Scsi_Cmnd *srb; /* current srb */ + struct scsi_cmnd *srb; /* current srb */ /* thread information */ int pid; /* control thread */ @@ -179,5 +178,9 @@ * single queue element srb for write access */ #define scsi_unlock(host) spin_unlock_irq(host->host_lock) #define scsi_lock(host) spin_lock_irq(host->host_lock) + + +/* Vendor ID list for devices that require special handling */ +#define USB_VENDOR_ID_GENESYS 0x05e3 /* Genesys Logic */ #endif diff -Nru a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c --- a/drivers/usb/usb-skeleton.c 2004-08-18 23:28:03 -07:00 +++ b/drivers/usb/usb-skeleton.c 2004-08-18 23:28:03 -07:00 @@ -1,42 +1,15 @@ /* - * USB Skeleton driver - 1.1 + * USB Skeleton driver - 2.0 * - * Copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) * * 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. * - * - * This driver is to be used as a skeleton driver to be able to create a - * USB driver quickly. The design of it is based on the usb-serial and - * dc2xx drivers. - * - * Thanks to Oliver Neukum, David Brownell, and Alan Stern for their help - * in debugging this driver. - * - * - * History: - * - * 2003-05-06 - 1.1 - changes due to usb core changes with usb_register_dev() - * 2003-02-25 - 1.0 - fix races involving urb->status, unlink_urb(), and - * disconnect. Fix transfer amount in read(). Use - * macros instead of magic numbers in probe(). Change - * size variables to size_t. Show how to eliminate - * DMA bounce buffer. - * 2002_12_12 - 0.9 - compile fixes and got rid of fixed minor array. - * 2002_09_26 - 0.8 - changes due to USB core conversion to struct device - * driver. - * 2002_02_12 - 0.7 - zero out dev in probe function for devices that do - * not have both a bulk in and bulk out endpoint. - * Thanks to Holger Waechtler for the fix. - * 2001_11_05 - 0.6 - fix minor locking problem in skel_disconnect. - * Thanks to Pete Zaitcev for the fix. - * 2001_09_04 - 0.5 - fix devfs bug in skel_disconnect. Thanks to wim delvaux - * 2001_08_21 - 0.4 - more small bug fixes. - * 2001_05_29 - 0.3 - more bug fixes based on review from linux-usb-devel - * 2001_05_24 - 0.2 - bug fixes based on review from linux-usb-devel people - * 2001_05_01 - 0.1 - first version + * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c + * but has been rewritten to be easy to read and use, as no locks are now + * needed anymore. * */ @@ -46,31 +19,10 @@ #include #include #include -#include -#include +#include #include #include -#ifdef CONFIG_USB_DEBUG - static int debug = 1; -#else - static int debug; -#endif - -/* Use our own dbg macro */ -#undef dbg -#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0) - - -/* Version Information */ -#define DRIVER_VERSION "v1.0" -#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com" -#define DRIVER_DESC "USB Skeleton Driver" - -/* Module parameters */ -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - /* Define these values to match your devices */ #define USB_SKEL_VENDOR_ID 0xfff0 @@ -79,11 +31,8 @@ /* table of devices that work with this driver */ static struct usb_device_id skel_table [] = { { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, - /* "Gadget Zero" firmware runs under Linux */ - { USB_DEVICE(0x0525, 0xa4a0) }, { } /* Terminating entry */ }; - MODULE_DEVICE_TABLE (usb, skel_table); @@ -92,413 +41,195 @@ /* Structure to hold all of our device specific stuff */ struct usb_skel { - struct usb_device * udev; /* save off the usb device pointer */ + struct usb_device * udev; /* the usb device for this device */ struct usb_interface * interface; /* the interface for this device */ - unsigned char minor; /* the starting minor number for this device */ - unsigned char num_ports; /* the number of ports this device has */ - char num_interrupt_in; /* number of interrupt in endpoints we have */ - char num_bulk_in; /* number of bulk in endpoints we have */ - char num_bulk_out; /* number of bulk out endpoints we have */ - unsigned char * bulk_in_buffer; /* the buffer to receive data */ size_t bulk_in_size; /* the size of the receive buffer */ __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ - - unsigned char * bulk_out_buffer; /* the buffer to send data */ - size_t bulk_out_size; /* the size of the send buffer */ - struct urb * write_urb; /* the urb used to send data */ __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ - atomic_t write_busy; /* true iff write urb is busy */ - struct completion write_finished; /* wait for the write to finish */ - - int open; /* if the port is open or not */ - int present; /* if the device is not disconnected */ - struct semaphore sem; /* locks this structure */ + struct kref kref; }; +#define to_skel_dev(d) container_of(d, struct usb_skel, kref) +static struct usb_driver skel_driver; -/* prevent races between open() and disconnect() */ -static DECLARE_MUTEX (disconnect_sem); - -/* local function prototypes */ -static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t *ppos); -static ssize_t skel_write (struct file *file, const char *buffer, size_t count, loff_t *ppos); -static int skel_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); -static int skel_open (struct inode *inode, struct file *file); -static int skel_release (struct inode *inode, struct file *file); - -static int skel_probe (struct usb_interface *interface, const struct usb_device_id *id); -static void skel_disconnect (struct usb_interface *interface); - -static void skel_write_bulk_callback (struct urb *urb, struct pt_regs *regs); - -/* - * File operations needed when we register this driver. - * This assumes that this driver NEEDS file operations, - * of course, which means that the driver is expected - * to have a node in the /dev directory. If the USB - * device were for a network interface then the driver - * would use "struct net_driver" instead, and a serial - * device would use "struct tty_driver". - */ -static struct file_operations skel_fops = { - /* - * The owner field is part of the module-locking - * mechanism. The idea is that the kernel knows - * which module to increment the use-counter of - * BEFORE it calls the device's open() function. - * This also means that the kernel can decrement - * the use-counter again before calling release() - * or should the open() function fail. - */ - .owner = THIS_MODULE, - - .read = skel_read, - .write = skel_write, - .ioctl = skel_ioctl, - .open = skel_open, - .release = skel_release, -}; - -/* - * usb class driver info in order to get a minor number from the usb core, - * and to have the device registered with devfs and the driver core - */ -static struct usb_class_driver skel_class = { - .name = "usb/skel%d", - .fops = &skel_fops, - .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, - .minor_base = USB_SKEL_MINOR_BASE, -}; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver skel_driver = { - .owner = THIS_MODULE, - .name = "skeleton", - .probe = skel_probe, - .disconnect = skel_disconnect, - .id_table = skel_table, -}; - - -/** - * usb_skel_debug_data - */ -static inline void usb_skel_debug_data (const char *function, int size, const unsigned char *data) -{ - int i; - - if (!debug) - return; - - printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", - function, size); - for (i = 0; i < size; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); -} - +static void skel_delete(struct kref *kref) +{ + struct usb_skel *dev = to_skel_dev(kref); -/** - * skel_delete - */ -static inline void skel_delete (struct usb_skel *dev) -{ + usb_put_dev(dev->udev); kfree (dev->bulk_in_buffer); - usb_buffer_free (dev->udev, dev->bulk_out_size, - dev->bulk_out_buffer, - dev->write_urb->transfer_dma); - usb_free_urb (dev->write_urb); kfree (dev); } - -/** - * skel_open - */ -static int skel_open (struct inode *inode, struct file *file) +static int skel_open(struct inode *inode, struct file *file) { - struct usb_skel *dev = NULL; + struct usb_skel *dev; struct usb_interface *interface; int subminor; int retval = 0; - dbg("%s", __FUNCTION__); - subminor = iminor(inode); - /* prevent disconnects */ - down (&disconnect_sem); - - interface = usb_find_interface (&skel_driver, subminor); + interface = usb_find_interface(&skel_driver, subminor); if (!interface) { err ("%s - error, can't find device for minor %d", __FUNCTION__, subminor); retval = -ENODEV; - goto exit_no_device; + goto exit; } dev = usb_get_intfdata(interface); if (!dev) { retval = -ENODEV; - goto exit_no_device; + goto exit; } - /* lock this device */ - down (&dev->sem); - - /* increment our usage count for the driver */ - ++dev->open; + /* increment our usage count for the device */ + kref_get(&dev->kref); /* save our object in the file's private structure */ file->private_data = dev; - /* unlock this device */ - up (&dev->sem); - -exit_no_device: - up (&disconnect_sem); +exit: return retval; } - -/** - * skel_release - */ -static int skel_release (struct inode *inode, struct file *file) +static int skel_release(struct inode *inode, struct file *file) { struct usb_skel *dev; - int retval = 0; dev = (struct usb_skel *)file->private_data; - if (dev == NULL) { - dbg ("%s - object is NULL", __FUNCTION__); + if (dev == NULL) return -ENODEV; - } - - dbg("%s - minor %d", __FUNCTION__, dev->minor); - - /* lock our device */ - down (&dev->sem); - - if (dev->open <= 0) { - dbg ("%s - device not opened", __FUNCTION__); - retval = -ENODEV; - goto exit_not_opened; - } - - /* wait for any bulk writes that might be going on to finish up */ - if (atomic_read (&dev->write_busy)) - wait_for_completion (&dev->write_finished); - - --dev->open; - if (!dev->present && !dev->open) { - /* the device was unplugged before the file was released */ - up (&dev->sem); - skel_delete (dev); - return 0; - } - -exit_not_opened: - up (&dev->sem); - - return retval; + /* decrement the count on our device */ + kref_put(&dev->kref, skel_delete); + return 0; } - -/** - * skel_read - */ -static ssize_t skel_read (struct file *file, char *buffer, size_t count, loff_t *ppos) +static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct usb_skel *dev; int retval = 0; dev = (struct usb_skel *)file->private_data; - - dbg("%s - minor %d, count = %d", __FUNCTION__, dev->minor, count); - - /* lock this object */ - down (&dev->sem); - - /* verify that the device wasn't unplugged */ - if (!dev->present) { - up (&dev->sem); - return -ENODEV; - } - + /* do a blocking bulk read to get data from the device */ - retval = usb_bulk_msg (dev->udev, - usb_rcvbulkpipe (dev->udev, - dev->bulk_in_endpointAddr), - dev->bulk_in_buffer, - min (dev->bulk_in_size, count), - &count, HZ*10); + retval = usb_bulk_msg(dev->udev, + usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr), + dev->bulk_in_buffer, + min(dev->bulk_in_size, count), + &count, HZ*10); /* if the read was successful, copy the data to userspace */ if (!retval) { - if (copy_to_user (buffer, dev->bulk_in_buffer, count)) + if (copy_to_user(buffer, dev->bulk_in_buffer, count)) retval = -EFAULT; else retval = count; } - /* unlock the device */ - up (&dev->sem); return retval; } +static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs) +{ + struct usb_skel *dev; -/** - * skel_write - * - * A device driver has to decide how to report I/O errors back to the - * user. The safest course is to wait for the transfer to finish before - * returning so that any errors will be reported reliably. skel_read() - * works like this. But waiting for I/O is slow, so many drivers only - * check for errors during I/O initiation and do not report problems - * that occur during the actual transfer. That's what we will do here. - * - * A driver concerned with maximum I/O throughput would use double- - * buffering: Two urbs would be devoted to write transfers, so that - * one urb could always be active while the other was waiting for the - * user to send more data. - */ -static ssize_t skel_write (struct file *file, const char *buffer, size_t count, loff_t *ppos) + dev = (struct usb_skel *)urb->context; + + /* sync/async unlink faults aren't errors */ + if (urb->status && + !(urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -ESHUTDOWN)) { + dbg("%s - nonzero write bulk status received: %d", + __FUNCTION__, urb->status); + } + + /* free up our allocated buffer */ + usb_buffer_free(urb->dev, urb->transfer_buffer_length, + urb->transfer_buffer, urb->transfer_dma); +} + +static ssize_t skel_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos) { struct usb_skel *dev; - ssize_t bytes_written = 0; int retval = 0; + struct urb *urb = NULL; + char *buf = NULL; dev = (struct usb_skel *)file->private_data; - dbg("%s - minor %d, count = %d", __FUNCTION__, dev->minor, count); - - /* lock this object */ - down (&dev->sem); - - /* verify that the device wasn't unplugged */ - if (!dev->present) { - retval = -ENODEV; + /* verify that we actually have some data to write */ + if (count == 0) goto exit; + + /* create a urb, and a buffer for it, and copy the data to the urb */ + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + retval = -ENOMEM; + goto error; } - /* verify that we actually have some data to write */ - if (count == 0) { - dbg("%s - write request of 0 bytes", __FUNCTION__); - goto exit; + buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma); + if (!buf) { + retval = -ENOMEM; + goto error; } - /* wait for a previous write to finish up; we don't use a timeout - * and so a nonresponsive device can delay us indefinitely. - */ - if (atomic_read (&dev->write_busy)) - wait_for_completion (&dev->write_finished); - - /* we can only write as much as our buffer will hold */ - bytes_written = min (dev->bulk_out_size, count); - - /* copy the data from userspace into our transfer buffer; - * this is the only copy required. - */ - if (copy_from_user(dev->write_urb->transfer_buffer, buffer, - bytes_written)) { + if (copy_from_user(buf, user_buffer, count)) { retval = -EFAULT; - goto exit; + goto error; } - usb_skel_debug_data (__FUNCTION__, bytes_written, - dev->write_urb->transfer_buffer); - - /* this urb was already set up, except for this write size */ - dev->write_urb->transfer_buffer_length = bytes_written; + /* initialize the urb properly */ + usb_fill_bulk_urb(urb, dev->udev, + usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), + buf, count, skel_write_bulk_callback, dev); + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* send the data out the bulk port */ - /* a character device write uses GFP_KERNEL, - unless a spinlock is held */ - init_completion (&dev->write_finished); - atomic_set (&dev->write_busy, 1); - retval = usb_submit_urb(dev->write_urb, GFP_KERNEL); + retval = usb_submit_urb(urb, GFP_KERNEL); if (retval) { - atomic_set (&dev->write_busy, 0); - err("%s - failed submitting write urb, error %d", - __FUNCTION__, retval); - } else { - retval = bytes_written; + err("%s - failed submitting write urb, error %d", __FUNCTION__, retval); + goto error; } + /* release our reference to this urb, the USB core will eventually free it entirely */ + usb_free_urb(urb); + exit: - /* unlock the device */ - up (&dev->sem); + return count; +error: + usb_buffer_free(dev->udev, count, buf, urb->transfer_dma); + usb_free_urb(urb); return retval; } +static struct file_operations skel_fops = { + .owner = THIS_MODULE, + .read = skel_read, + .write = skel_write, + .open = skel_open, + .release = skel_release, +}; -/** - * skel_ioctl - */ -static int skel_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct usb_skel *dev; - - dev = (struct usb_skel *)file->private_data; - - /* lock this object */ - down (&dev->sem); - - /* verify that the device wasn't unplugged */ - if (!dev->present) { - up (&dev->sem); - return -ENODEV; - } - - dbg("%s - minor %d, cmd 0x%.4x, arg %ld", __FUNCTION__, - dev->minor, cmd, arg); - - /* fill in your device specific stuff here */ - - /* unlock the device */ - up (&dev->sem); - - /* return that we did not understand this ioctl call */ - return -ENOTTY; -} - - -/** - * skel_write_bulk_callback +/* + * usb class driver info in order to get a minor number from the usb core, + * and to have the device registered with devfs and the driver core */ -static void skel_write_bulk_callback (struct urb *urb, struct pt_regs *regs) -{ - struct usb_skel *dev = (struct usb_skel *)urb->context; - - dbg("%s - minor %d", __FUNCTION__, dev->minor); - - /* sync/async unlink faults aren't errors */ - if (urb->status && !(urb->status == -ENOENT || - urb->status == -ECONNRESET)) { - dbg("%s - nonzero write bulk status received: %d", - __FUNCTION__, urb->status); - } - - /* notify anyone waiting that the write has finished */ - atomic_set (&dev->write_busy, 0); - complete (&dev->write_finished); -} - +static struct usb_class_driver skel_class = { + .name = "usb/skel%d", + .fops = &skel_fops, + .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, + .minor_base = USB_SKEL_MINOR_BASE, +}; -/** - * skel_probe - * - * Called by the usb core when a new device is connected that it thinks - * this driver might be interested in. - */ static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id) { - struct usb_device *udev = interface_to_usbdev(interface); struct usb_skel *dev = NULL; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; @@ -506,28 +237,21 @@ int i; int retval = -ENOMEM; - /* See if the device offered us matches what we can accept */ - if ((udev->descriptor.idVendor != USB_SKEL_VENDOR_ID) || - (udev->descriptor.idProduct != USB_SKEL_PRODUCT_ID)) { - return -ENODEV; - } - /* allocate memory for our device state and initialize it */ - dev = kmalloc (sizeof(struct usb_skel), GFP_KERNEL); + dev = kmalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { - err ("Out of memory"); - return -ENOMEM; + err("Out of memory"); + goto error; } - memset (dev, 0x00, sizeof (*dev)); + memset(dev, 0x00, sizeof(*dev)); + kref_init(&dev->kref); - init_MUTEX (&dev->sem); - dev->udev = udev; + dev->udev = usb_get_dev(interface_to_usbdev(interface)); dev->interface = interface; /* set up the endpoint information */ - /* check out the endpoints */ /* use only the first bulk-in and bulk-out endpoints */ - iface_desc = &interface->altsetting[0]; + iface_desc = interface->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; @@ -539,9 +263,9 @@ buffer_size = endpoint->wMaxPacketSize; dev->bulk_in_size = buffer_size; dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; - dev->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL); + dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!dev->bulk_in_buffer) { - err("Couldn't allocate bulk_in_buffer"); + err("Could not allocate bulk_in_buffer"); goto error; } } @@ -551,153 +275,85 @@ ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) { /* we found a bulk out endpoint */ - /* a probe() may sleep and has no restrictions on memory allocations */ - dev->write_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->write_urb) { - err("No free urbs available"); - goto error; - } dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; - - /* on some platforms using this kind of buffer alloc - * call eliminates a dma "bounce buffer". - * - * NOTE: you'd normally want i/o buffers that hold - * more than one packet, so that i/o delays between - * packets don't hurt throughput. - */ - buffer_size = endpoint->wMaxPacketSize; - dev->bulk_out_size = buffer_size; - dev->write_urb->transfer_flags = (URB_NO_TRANSFER_DMA_MAP | - URB_ASYNC_UNLINK); - dev->bulk_out_buffer = usb_buffer_alloc (udev, - buffer_size, GFP_KERNEL, - &dev->write_urb->transfer_dma); - if (!dev->bulk_out_buffer) { - err("Couldn't allocate bulk_out_buffer"); - goto error; - } - usb_fill_bulk_urb(dev->write_urb, udev, - usb_sndbulkpipe(udev, - endpoint->bEndpointAddress), - dev->bulk_out_buffer, buffer_size, - skel_write_bulk_callback, dev); } } if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { - err("Couldn't find both bulk-in and bulk-out endpoints"); + err("Could not find both bulk-in and bulk-out endpoints"); goto error; } - /* allow device read, write and ioctl */ - dev->present = 1; + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, dev); /* we can register the device now, as it is ready */ - usb_set_intfdata (interface, dev); - retval = usb_register_dev (interface, &skel_class); + retval = usb_register_dev(interface, &skel_class); if (retval) { /* something prevented us from registering this driver */ - err ("Not able to get a minor for this device."); - usb_set_intfdata (interface, NULL); + err("Not able to get a minor for this device."); + usb_set_intfdata(interface, NULL); goto error; } - dev->minor = interface->minor; - /* let the user know what node this device is now attached to */ - info ("USB Skeleton device now attached to USBSkel-%d", dev->minor); + info("USB Skeleton device now attached to USBSkel-%d", interface->minor); return 0; error: - skel_delete (dev); + if (dev) + kref_put(&dev->kref, skel_delete); return retval; } - -/** - * skel_disconnect - * - * Called by the usb core when the device is removed from the system. - * - * This routine guarantees that the driver will not submit any more urbs - * by clearing dev->udev. It is also supposed to terminate any currently - * active urbs. Unfortunately, usb_bulk_msg(), used in skel_read(), does - * not provide any way to do this. But at least we can cancel an active - * write. - */ static void skel_disconnect(struct usb_interface *interface) { struct usb_skel *dev; - int minor; + int minor = interface->minor; - /* prevent races with open() */ - down (&disconnect_sem); + /* prevent skel_open() from racing skel_disconnect() */ + lock_kernel(); - dev = usb_get_intfdata (interface); - usb_set_intfdata (interface, NULL); - - down (&dev->sem); - - minor = dev->minor; + dev = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); /* give back our minor */ - usb_deregister_dev (interface, &skel_class); + usb_deregister_dev(interface, &skel_class); - /* terminate an ongoing write */ - if (atomic_read (&dev->write_busy)) { - usb_unlink_urb (dev->write_urb); - wait_for_completion (&dev->write_finished); - } - - /* prevent device read, write and ioctl */ - dev->present = 0; - - up (&dev->sem); + unlock_kernel(); - /* if the device is opened, skel_release will clean this up */ - if (!dev->open) - skel_delete (dev); - - up (&disconnect_sem); + /* decrement our usage count */ + kref_put(&dev->kref, skel_delete); info("USB Skeleton #%d now disconnected", minor); } +static struct usb_driver skel_driver = { + .owner = THIS_MODULE, + .name = "skeleton", + .probe = skel_probe, + .disconnect = skel_disconnect, + .id_table = skel_table, +}; - -/** - * usb_skel_init - */ static int __init usb_skel_init(void) { int result; /* register this driver with the USB subsystem */ result = usb_register(&skel_driver); - if (result) { - err("usb_register failed. Error number %d", - result); - return result; - } + if (result) + err("usb_register failed. Error number %d", result); - info(DRIVER_DESC " " DRIVER_VERSION); - return 0; + return result; } - -/** - * usb_skel_exit - */ static void __exit usb_skel_exit(void) { /* deregister this driver with the USB subsystem */ usb_deregister(&skel_driver); } - module_init (usb_skel_init); module_exit (usb_skel_exit); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff -Nru a/fs/namei.c b/fs/namei.c --- a/fs/namei.c 2004-08-18 23:28:03 -07:00 +++ b/fs/namei.c 2004-08-18 23:28:03 -07:00 @@ -1659,7 +1659,7 @@ * if it cannot handle the case of removing a directory * that is still in use by something else.. */ -static void d_unhash(struct dentry *dentry) +void dentry_unhash(struct dentry *dentry) { dget(dentry); spin_lock(&dcache_lock); @@ -1689,7 +1689,7 @@ DQUOT_INIT(dir); down(&dentry->d_inode->i_sem); - d_unhash(dentry); + dentry_unhash(dentry); if (d_mountpoint(dentry)) error = -EBUSY; else { @@ -2032,7 +2032,7 @@ target = new_dentry->d_inode; if (target) { down(&target->i_sem); - d_unhash(new_dentry); + dentry_unhash(new_dentry); } if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) error = -EBUSY; @@ -2410,4 +2410,5 @@ EXPORT_SYMBOL(vfs_rmdir); EXPORT_SYMBOL(vfs_symlink); EXPORT_SYMBOL(vfs_unlink); +EXPORT_SYMBOL(dentry_unhash); EXPORT_SYMBOL(generic_readlink); diff -Nru a/include/linux/fs.h b/include/linux/fs.h --- a/include/linux/fs.h 2004-08-18 23:28:03 -07:00 +++ b/include/linux/fs.h 2004-08-18 23:28:03 -07:00 @@ -811,6 +811,11 @@ extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); /* + * VFS dentry helper functions. + */ +extern void dentry_unhash(struct dentry *dentry); + +/* * File types * * NOTE! These match bits 12..15 of stat.st_mode diff -Nru a/include/linux/usb.h b/include/linux/usb.h --- a/include/linux/usb.h 2004-08-18 23:28:03 -07:00 +++ b/include/linux/usb.h 2004-08-18 23:28:03 -07:00 @@ -294,8 +294,6 @@ struct semaphore serialize; unsigned int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */ - unsigned int halted[2]; /* endpoint halts; one bit per endpoint # & direction; */ - /* [0] = IN, [1] = OUT */ int epmaxpacketin[16]; /* INput endpoint specific maximums */ int epmaxpacketout[16]; /* OUTput endpoint specific maximums */ @@ -1083,10 +1081,6 @@ #define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1) #define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << (ep))) #define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | ((bit) << (ep))) - -/* Endpoint halt control/status ... likewise USE WITH CAUTION */ -#define usb_endpoint_running(dev, ep, out) ((dev)->halted[out] &= ~(1 << (ep))) -#define usb_endpoint_halted(dev, ep, out) ((dev)->halted[out] & (1 << (ep))) static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint) diff -Nru a/include/linux/usb_otg.h b/include/linux/usb_otg.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/include/linux/usb_otg.h 2004-08-18 23:28:03 -07:00 @@ -0,0 +1,116 @@ +// include/linux/usb_otg.h + +/* + * These APIs may be used between USB controllers. USB device drivers + * (for either host or peripheral roles) don't use these calls; they + * continue to use just usb_device and usb_gadget. + */ + + +/* OTG defines lots of enumeration states before device reset */ +enum usb_otg_state { + OTG_STATE_UNDEFINED = 0, + + /* single-role peripheral, and dual-role default-b */ + OTG_STATE_B_IDLE, + OTG_STATE_B_SRP_INIT, + OTG_STATE_B_PERIPHERAL, + + /* extra dual-role default-b states */ + OTG_STATE_B_WAIT_ACON, + OTG_STATE_B_HOST, + + /* dual-role default-a */ + OTG_STATE_A_IDLE, + OTG_STATE_A_WAIT_VRISE, + OTG_STATE_A_WAIT_BCON, + OTG_STATE_A_HOST, + OTG_STATE_A_SUSPEND, + OTG_STATE_A_PERIPHERAL, + OTG_STATE_A_WAIT_VFALL, + OTG_STATE_A_VBUS_ERR, +}; + +/* + * the otg driver needs to interact with both device side and host side + * usb controllers. it decides which controller is active at a given + * moment, using the transceiver, ID signal, HNP and sometimes static + * configuration information (including "board isn't wired for otg"). + */ +struct otg_transceiver { + struct device *dev; + const char *label; + + u8 default_a; + enum usb_otg_state state; + + struct usb_bus *host; + struct usb_gadget *gadget; + + /* to pass extra port status to the root hub */ + u16 port_status; + u16 port_change; + + /* bind/unbind the host controller */ + int (*set_host)(struct otg_transceiver *otg, + struct usb_bus *host); + + /* bind/unbind the peripheral controller */ + int (*set_peripheral)(struct otg_transceiver *otg, + struct usb_gadget *gadget); + + /* effective for B devices, ignored for A-peripheral */ + int (*set_power)(struct otg_transceiver *otg, + unsigned mA); + + /* for B devices only: start session with A-Host */ + int (*start_srp)(struct otg_transceiver *otg); + + /* start or continue HNP role switch */ + int (*start_hnp)(struct otg_transceiver *otg); + +}; + + +/* for board-specific init logic */ +extern int otg_set_transceiver(struct otg_transceiver *); + + +/* for usb host and peripheral controller drivers */ +extern struct otg_transceiver *otg_get_transceiver(void); + +static inline int +otg_start_hnp(struct otg_transceiver *otg) +{ + return otg->start_hnp(otg); +} + + +/* for HCDs */ +static inline int +otg_set_host(struct otg_transceiver *otg, struct usb_bus *host) +{ + return otg->set_host(otg, host); +} + + +/* for usb peripheral controller drivers */ +static inline int +otg_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *periph) +{ + return otg->set_peripheral(otg, periph); +} + +static inline int +otg_set_power(struct otg_transceiver *otg, unsigned mA) +{ + return otg->set_power(otg, mA); +} + +static inline int +otg_start_srp(struct otg_transceiver *otg) +{ + return otg->start_srp(otg); +} + +