浏览代码

Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6: (81 commits)
  [PATCH] USB: omninet: fix up debugging comments
  [PATCH] USB serial: add navman driver
  [PATCH] USB: Fix irda-usb use after use
  [PATCH] USB: rtl8150 small fix
  [PATCH] USB: ftdi_sio: add Icom ID1 USB product and vendor ids
  [PATCH] USB: cp2101: add new device IDs
  [PATCH] USB: fix check_ctrlrecip to allow control transfers in state ADDRESS
  [PATCH] USB: vicam.c: fix a NULL pointer dereference
  [PATCH] USB: ZC0301 driver bugfix
  [PATCH] USB: add support for Creativelabs Silvercrest USB keyboard
  [PATCH] USB: storage: new unusual_devs.h entry: Mitsumi 7in1 Card Reader
  [PATCH] USB: storage: unusual_devs.h entry 0420:0001
  [PATCH] USB: storage: another unusual_devs.h entry
  [PATCH] USB: storage: sandisk unusual_devices entry
  [PATCH] USB: fix initdata issue in isp116x-hcd
  [PATCH] USB: usbcore: usb_set_configuration oops (NULL ptr dereference)
  [PATCH] USB: usbcore: Don't assume a USB configuration includes any interfaces
  [PATCH] USB: ub 03 drop stall clearing
  [PATCH] USB: ub 02 remove diag
  [PATCH] USB: ub 01 remove first_open
  ...
Linus Torvalds 19 年之前
父节点
当前提交
2bf2154c6b
共有 100 个文件被更改,包括 5414 次插入8142 次删除
  1. 2 0
      CREDITS
  2. 9 1
      Documentation/usb/et61x251.txt
  3. 11 0
      Documentation/usb/sn9c102.txt
  4. 254 0
      Documentation/usb/zc0301.txt
  5. 8 0
      MAINTAINERS
  6. 1 1
      arch/mips/au1000/common/cputable.c
  7. 1 3
      arch/mips/au1000/common/platform.c
  8. 9 236
      drivers/block/ub.c
  9. 3 2
      drivers/net/irda/irda-usb.c
  10. 9 0
      drivers/usb/Kconfig
  11. 2 2
      drivers/usb/Makefile
  12. 0 47
      drivers/usb/class/Kconfig
  13. 0 2
      drivers/usb/class/Makefile
  14. 0 3869
      drivers/usb/class/audio.c
  15. 0 110
      drivers/usb/class/audio.h
  16. 12 11
      drivers/usb/class/cdc-acm.c
  17. 0 2153
      drivers/usb/class/usb-midi.c
  18. 0 164
      drivers/usb/class/usb-midi.h
  19. 8 7
      drivers/usb/class/usblp.c
  20. 4 3
      drivers/usb/core/devices.c
  21. 10 14
      drivers/usb/core/devio.c
  22. 8 3
      drivers/usb/core/hcd-pci.c
  23. 85 68
      drivers/usb/core/hcd.c
  24. 1 3
      drivers/usb/core/hcd.h
  25. 28 17
      drivers/usb/core/hub.c
  26. 9 8
      drivers/usb/core/message.c
  27. 8 7
      drivers/usb/core/notify.c
  28. 3 2
      drivers/usb/core/usb.c
  29. 17 0
      drivers/usb/gadget/Kconfig
  30. 1 0
      drivers/usb/gadget/Makefile
  31. 1773 0
      drivers/usb/gadget/at91_udc.c
  32. 181 0
      drivers/usb/gadget/at91_udc.h
  33. 1 2
      drivers/usb/gadget/dummy_hcd.c
  34. 39 14
      drivers/usb/gadget/ether.c
  35. 2 2
      drivers/usb/gadget/file_storage.c
  36. 28 2
      drivers/usb/gadget/gadget_chips.h
  37. 1 2
      drivers/usb/gadget/goku_udc.c
  38. 2 4
      drivers/usb/gadget/inode.c
  39. 1 2
      drivers/usb/gadget/lh7a40x_udc.c
  40. 1 2
      drivers/usb/gadget/net2280.c
  41. 2 4
      drivers/usb/gadget/omap_udc.c
  42. 1 2
      drivers/usb/gadget/pxa2xx_udc.c
  43. 4 5
      drivers/usb/gadget/serial.c
  44. 4 11
      drivers/usb/gadget/zero.c
  45. 1 1
      drivers/usb/host/Kconfig
  46. 297 0
      drivers/usb/host/ehci-au1xxx.c
  47. 366 0
      drivers/usb/host/ehci-fsl.c
  48. 37 0
      drivers/usb/host/ehci-fsl.h
  49. 12 1
      drivers/usb/host/ehci-hcd.c
  50. 4 0
      drivers/usb/host/ehci-hub.c
  51. 3 8
      drivers/usb/host/ehci-mem.c
  52. 24 1
      drivers/usb/host/ehci-pci.c
  53. 13 4
      drivers/usb/host/ehci-q.c
  54. 9 11
      drivers/usb/host/ehci-sched.c
  55. 17 1
      drivers/usb/host/ehci.h
  56. 4 8
      drivers/usb/host/hc_crisv10.c
  57. 2 3
      drivers/usb/host/isp116x-hcd.c
  58. 306 0
      drivers/usb/host/ohci-at91.c
  59. 87 15
      drivers/usb/host/ohci-au1xxx.c
  60. 32 22
      drivers/usb/host/ohci-hcd.c
  61. 6 6
      drivers/usb/host/ohci-hub.c
  62. 13 2
      drivers/usb/host/ohci-pci.c
  63. 1 2
      drivers/usb/host/sl811-hcd.c
  64. 123 233
      drivers/usb/host/uhci-debug.c
  65. 80 47
      drivers/usb/host/uhci-hcd.c
  66. 100 88
      drivers/usb/host/uhci-hcd.h
  67. 21 0
      drivers/usb/host/uhci-hub.c
  68. 316 360
      drivers/usb/host/uhci-q.c
  69. 33 34
      drivers/usb/image/mdc800.c
  70. 0 2
      drivers/usb/input/ati_remote.c
  71. 141 34
      drivers/usb/input/hid-core.c
  72. 2 4
      drivers/usb/input/hid-lgff.c
  73. 1 2
      drivers/usb/input/hid-tmff.c
  74. 10 0
      drivers/usb/input/hid.h
  75. 2 4
      drivers/usb/input/hiddev.c
  76. 15 0
      drivers/usb/media/Kconfig
  77. 6 1
      drivers/usb/media/Makefile
  78. 18 18
      drivers/usb/media/dabusb.c
  79. 1 1
      drivers/usb/media/dabusb.h
  80. 21 7
      drivers/usb/media/et61x251.h
  81. 170 146
      drivers/usb/media/et61x251_core.c
  82. 3 2
      drivers/usb/media/et61x251_sensor.h
  83. 7 3
      drivers/usb/media/et61x251_tas5130d1b.c
  84. 47 50
      drivers/usb/media/ov511.c
  85. 5 6
      drivers/usb/media/ov511.h
  86. 0 1
      drivers/usb/media/pwc/pwc-ctrl.c
  87. 2 7
      drivers/usb/media/pwc/pwc-if.c
  88. 7 9
      drivers/usb/media/se401.c
  89. 2 1
      drivers/usb/media/se401.h
  90. 21 7
      drivers/usb/media/sn9c102.h
  91. 175 146
      drivers/usb/media/sn9c102_core.c
  92. 19 14
      drivers/usb/media/sn9c102_ov7630.c
  93. 238 0
      drivers/usb/media/sn9c102_pas202bca.c
  94. 1 1
      drivers/usb/media/sn9c102_pas202bcb.c
  95. 8 7
      drivers/usb/media/sn9c102_sensor.h
  96. 9 5
      drivers/usb/media/sn9c102_tas5110c1b.c
  97. 8 4
      drivers/usb/media/sn9c102_tas5130d1b.c
  98. 9 11
      drivers/usb/media/stv680.c
  99. 1 1
      drivers/usb/media/stv680.h
  100. 15 16
      drivers/usb/media/usbvideo.c

+ 2 - 0
CREDITS

@@ -2813,6 +2813,8 @@ E: luca.risolia@studio.unibo.it
 P: 1024D/FCE635A4 88E8 F32F 7244 68BA 3958  5D40 99DA 5D2A FCE6 35A4
 P: 1024D/FCE635A4 88E8 F32F 7244 68BA 3958  5D40 99DA 5D2A FCE6 35A4
 D: V4L driver for W996[87]CF JPEG USB Dual Mode Camera Chips
 D: V4L driver for W996[87]CF JPEG USB Dual Mode Camera Chips
 D: V4L2 driver for SN9C10x PC Camera Controllers
 D: V4L2 driver for SN9C10x PC Camera Controllers
+D: V4L2 driver for ET61X151 and ET61X251 PC Camera Controllers
+D: V4L2 driver for ZC0301 Image Processor and Control Chip
 S: Via Liberta' 41/A
 S: Via Liberta' 41/A
 S: Osio Sotto, 24046, Bergamo
 S: Osio Sotto, 24046, Bergamo
 S: Italy
 S: Italy

+ 9 - 1
Documentation/usb/et61x251.txt

@@ -176,6 +176,14 @@ Description:    Force the application to unmap previously mapped buffer memory
                 1 = force memory unmapping (save memory)
                 1 = force memory unmapping (save memory)
 Default:        0
 Default:        0
 -------------------------------------------------------------------------------
 -------------------------------------------------------------------------------
+Name:           frame_timeout
+Type:           uint array (min = 0, max = 64)
+Syntax:         <n[,...]>
+Description:    Timeout for a video frame in seconds. This parameter is
+                specific for each detected camera. This parameter can be
+                changed at runtime thanks to the /sys filesystem interface.
+Default:        2
+-------------------------------------------------------------------------------
 Name:           debug
 Name:           debug
 Type:           ushort
 Type:           ushort
 Syntax:         <n>
 Syntax:         <n>
@@ -266,7 +274,7 @@ the V4L2 interface.
 
 
 
 
 10. Notes for V4L2 application developers
 10. Notes for V4L2 application developers
-========================================
+=========================================
 This driver follows the V4L2 API specifications. In particular, it enforces two
 This driver follows the V4L2 API specifications. In particular, it enforces two
 rules:
 rules:
 
 

+ 11 - 0
Documentation/usb/sn9c102.txt

@@ -196,6 +196,14 @@ Description:    Force the application to unmap previously mapped buffer memory
                 1 = force memory unmapping (save memory)
                 1 = force memory unmapping (save memory)
 Default:        0
 Default:        0
 -------------------------------------------------------------------------------
 -------------------------------------------------------------------------------
+Name:           frame_timeout
+Type:           uint array (min = 0, max = 64)
+Syntax:         <n[,...]>
+Description:    Timeout for a video frame in seconds. This parameter is
+                specific for each detected camera. This parameter can be
+                changed at runtime thanks to the /sys filesystem interface.
+Default:        2
+-------------------------------------------------------------------------------
 Name:           debug
 Name:           debug
 Type:           ushort
 Type:           ushort
 Syntax:         <n> 
 Syntax:         <n> 
@@ -321,6 +329,7 @@ Vendor ID  Product ID
 ---------  ----------
 ---------  ----------
 0x0c45     0x6001
 0x0c45     0x6001
 0x0c45     0x6005
 0x0c45     0x6005
+0x0c45     0x6007
 0x0c45     0x6009
 0x0c45     0x6009
 0x0c45     0x600d
 0x0c45     0x600d
 0x0c45     0x6024
 0x0c45     0x6024
@@ -370,6 +379,7 @@ HV7131D     Hynix Semiconductor, Inc.
 MI-0343     Micron Technology, Inc.
 MI-0343     Micron Technology, Inc.
 OV7630      OmniVision Technologies, Inc.
 OV7630      OmniVision Technologies, Inc.
 PAS106B     PixArt Imaging, Inc.
 PAS106B     PixArt Imaging, Inc.
+PAS202BCA   PixArt Imaging, Inc.
 PAS202BCB   PixArt Imaging, Inc.
 PAS202BCB   PixArt Imaging, Inc.
 TAS5110C1B  Taiwan Advanced Sensor Corporation
 TAS5110C1B  Taiwan Advanced Sensor Corporation
 TAS5130D1B  Taiwan Advanced Sensor Corporation
 TAS5130D1B  Taiwan Advanced Sensor Corporation
@@ -493,6 +503,7 @@ Many thanks to following persons for their contribute (listed in alphabetical
 order):
 order):
 
 
 - Luca Capello for the donation of a webcam;
 - Luca Capello for the donation of a webcam;
+- Philippe Coval for having helped testing the PAS202BCA image sensor;
 - Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the
 - Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the
   donation of a webcam;
   donation of a webcam;
 - Jon Hollstrom for the donation of a webcam;
 - Jon Hollstrom for the donation of a webcam;

+ 254 - 0
Documentation/usb/zc0301.txt

@@ -0,0 +1,254 @@
+
+                    ZC0301 Image Processor and Control Chip
+                                Driver for Linux
+                    =======================================
+
+                               - Documentation -
+
+
+Index
+=====
+1.  Copyright
+2.  Disclaimer
+3.  License
+4.  Overview and features
+5.  Module dependencies
+6.  Module loading
+7.  Module parameters
+8.  Supported devices
+9.  Notes for V4L2 application developers
+10. Contact information
+11. Credits
+
+
+1. Copyright
+============
+Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>
+
+
+2. Disclaimer
+=============
+This software is not developed or sponsored by Z-Star Microelectronics Corp.
+Trademarks are property of their respective owner.
+
+
+3. License
+==========
+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.
+
+
+4. Overview and features
+========================
+This driver supports the video interface of the devices mounting the ZC0301
+Image Processor and Control Chip.
+
+The driver relies on the Video4Linux2 and USB core modules. It has been
+designed to run properly on SMP systems as well.
+
+The latest version of the ZC0301 driver can be found at the following URL:
+http://www.linux-projects.org/
+
+Some of the features of the driver are:
+
+- full compliance with the Video4Linux2 API (see also "Notes for V4L2
+  application developers" paragraph);
+- available mmap or read/poll methods for video streaming through isochronous
+  data transfers;
+- automatic detection of image sensor;
+- video format is standard JPEG;
+- dynamic driver control thanks to various module parameters (see "Module
+  parameters" paragraph);
+- up to 64 cameras can be handled at the same time; they can be connected and
+  disconnected from the host many times without turning off the computer, if
+  the system supports hotplugging;
+
+
+5. Module dependencies
+======================
+For it to work properly, the driver needs kernel support for Video4Linux and
+USB.
+
+The following options of the kernel configuration file must be enabled and
+corresponding modules must be compiled:
+
+	# Multimedia devices
+	#
+	CONFIG_VIDEO_DEV=m
+
+	# USB support
+	#
+	CONFIG_USB=m
+
+In addition, depending on the hardware being used, the modules below are
+necessary:
+
+	# USB Host Controller Drivers
+	#
+	CONFIG_USB_EHCI_HCD=m
+	CONFIG_USB_UHCI_HCD=m
+	CONFIG_USB_OHCI_HCD=m
+
+The ZC0301 controller also provides a built-in microphone interface. It is
+supported by the USB Audio driver thanks to the ALSA API:
+
+	# Sound
+	#
+	CONFIG_SOUND=y
+
+	# Advanced Linux Sound Architecture
+	#
+	CONFIG_SND=m
+
+	# USB devices
+	#
+	CONFIG_SND_USB_AUDIO=m
+
+And finally:
+
+	# USB Multimedia devices
+	#
+	CONFIG_USB_ZC0301=m
+
+
+6. Module loading
+=================
+To use the driver, it is necessary to load the "zc0301" module into memory
+after every other module required: "videodev", "usbcore" and, depending on
+the USB host controller you have, "ehci-hcd", "uhci-hcd" or "ohci-hcd".
+
+Loading can be done as shown below:
+
+	[root@localhost home]# modprobe zc0301
+
+At this point the devices should be recognized. You can invoke "dmesg" to
+analyze kernel messages and verify that the loading process has gone well:
+
+	[user@localhost home]$ dmesg
+
+
+7. Module parameters
+====================
+Module parameters are listed below:
+-------------------------------------------------------------------------------
+Name:           video_nr
+Type:           short array (min = 0, max = 64)
+Syntax:         <-1|n[,...]>
+Description:    Specify V4L2 minor mode number:
+                -1 = use next available
+                 n = use minor number n
+                You can specify up to 64 cameras this way.
+                For example:
+                video_nr=-1,2,-1 would assign minor number 2 to the second
+                registered camera and use auto for the first one and for every
+                other camera.
+Default:        -1
+-------------------------------------------------------------------------------
+Name:           force_munmap
+Type:           bool array (min = 0, max = 64)
+Syntax:         <0|1[,...]>
+Description:    Force the application to unmap previously mapped buffer memory
+                before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+                all the applications support this feature. This parameter is
+                specific for each detected camera.
+                0 = do not force memory unmapping
+                1 = force memory unmapping (save memory)
+Default:        0
+-------------------------------------------------------------------------------
+Name:           frame_timeout
+Type:           uint array (min = 0, max = 64)
+Syntax:         <n[,...]>
+Description:    Timeout for a video frame in seconds. This parameter is
+                specific for each detected camera. This parameter can be
+                changed at runtime thanks to the /sys filesystem interface.
+Default:        2
+-------------------------------------------------------------------------------
+Name:           debug
+Type:           ushort
+Syntax:         <n>
+Description:    Debugging information level, from 0 to 3:
+                0 = none (use carefully)
+                1 = critical errors
+                2 = significant informations
+                3 = more verbose messages
+                Level 3 is useful for testing only, when only one device
+                is used at the same time. It also shows some more informations
+                about the hardware being detected. This module parameter can be
+                changed at runtime thanks to the /sys filesystem interface.
+Default:        2
+-------------------------------------------------------------------------------
+
+
+8. Supported devices
+====================
+None of the names of the companies as well as their products will be mentioned
+here. They have never collaborated with the author, so no advertising.
+
+From the point of view of a driver, what unambiguously identify a device are
+its vendor and product USB identifiers. Below is a list of known identifiers of
+devices mounting the ZC0301 Image Processor and Control Chips:
+
+Vendor ID  Product ID
+---------  ----------
+0x041e     0x4017
+0x041e     0x401c
+0x041e     0x401e
+0x041e     0x4034
+0x041e     0x4035
+0x046d     0x08ae
+0x0ac8     0x0301
+0x10fd     0x8050
+
+The list above does not imply that all those devices work with this driver: up
+until now only the ones that mount the following image sensors are supported;
+kernel messages will always tell you whether this is the case:
+
+Model       Manufacturer
+-----       ------------
+PAS202BCB   PixArt Imaging, Inc.
+
+
+9. Notes for V4L2 application developers
+========================================
+This driver follows the V4L2 API specifications. In particular, it enforces two
+rules:
+
+- exactly one I/O method, either "mmap" or "read", is associated with each
+file descriptor. Once it is selected, the application must close and reopen the
+device to switch to the other I/O method;
+
+- although it is not mandatory, previously mapped buffer memory should always
+be unmapped before calling any "VIDIOC_S_CROP" or "VIDIOC_S_FMT" ioctl's.
+The same number of buffers as before will be allocated again to match the size
+of the new video frames, so you have to map the buffers again before any I/O
+attempts on them.
+
+
+10. Contact information
+=======================
+The author may be contacted by e-mail at <luca.risolia@studio.unibo.it>.
+
+GPG/PGP encrypted e-mail's are accepted. The GPG key ID of the author is
+'FCE635A4'; the public 1024-bit key should be available at any keyserver;
+the fingerprint is: '88E8 F32F 7244 68BA 3958  5D40 99DA 5D2A FCE6 35A4'.
+
+
+11. Credits
+===========
+- Informations about the chip internals needed to enable the I2C protocol have
+  been taken from the documentation of the ZC030x Video4Linux1 driver written
+  by Andrew Birkett <andy@nobugs.org>;
+- The initialization values of the ZC0301 controller connected to the PAS202BCB
+  image sensor have been taken from the SPCA5XX driver maintained by
+  Michel Xhaard <mxhaard@magic.fr>.

+ 8 - 0
MAINTAINERS

@@ -2896,6 +2896,14 @@ L:	video4linux-list@redhat.com
 W:	http://www.linux-projects.org
 W:	http://www.linux-projects.org
 S:	Maintained
 S:	Maintained
 
 
+USB ZC0301 DRIVER
+P:	Luca Risolia
+M:	luca.risolia@studio.unibo.it
+L:	linux-usb-devel@lists.sourceforge.net
+L:	video4linux-list@redhat.com
+W:	http://www.linux-projects.org
+S:	Maintained
+
 USB ZD1201 DRIVER
 USB ZD1201 DRIVER
 P:	Jeroen Vreeken
 P:	Jeroen Vreeken
 M:	pe1rxq@amsat.org
 M:	pe1rxq@amsat.org

+ 1 - 1
arch/mips/au1000/common/cputable.c

@@ -38,7 +38,7 @@ struct cpu_spec	cpu_specs[] = {
     { 0xffffffff, 0x02030204, "Au1100 BE", 0, 1 },
     { 0xffffffff, 0x02030204, "Au1100 BE", 0, 1 },
     { 0xffffffff, 0x03030200, "Au1550 AA", 0, 1 },
     { 0xffffffff, 0x03030200, "Au1550 AA", 0, 1 },
     { 0xffffffff, 0x04030200, "Au1200 AB", 0, 0 },
     { 0xffffffff, 0x04030200, "Au1200 AB", 0, 0 },
-    { 0xffffffff, 0x04030201, "Au1200 AC", 0, 1 },
+    { 0xffffffff, 0x04030201, "Au1200 AC", 1, 0 },
     { 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0 },
     { 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0 },
 };
 };
 
 

+ 1 - 3
arch/mips/au1000/common/platform.c

@@ -20,7 +20,7 @@
 static struct resource au1xxx_usb_ohci_resources[] = {
 static struct resource au1xxx_usb_ohci_resources[] = {
 	[0] = {
 	[0] = {
 		.start		= USB_OHCI_BASE,
 		.start		= USB_OHCI_BASE,
-		.end		= USB_OHCI_BASE + USB_OHCI_LEN,
+		.end		= USB_OHCI_BASE + USB_OHCI_LEN - 1,
 		.flags		= IORESOURCE_MEM,
 		.flags		= IORESOURCE_MEM,
 	},
 	},
 	[1] = {
 	[1] = {
@@ -278,9 +278,7 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = {
 	&au1100_lcd_device,
 	&au1100_lcd_device,
 #endif
 #endif
 #ifdef CONFIG_SOC_AU1200
 #ifdef CONFIG_SOC_AU1200
-#if 0	/* fixme */
 	&au1xxx_usb_ehci_device,
 	&au1xxx_usb_ehci_device,
-#endif
 	&au1xxx_usb_gdt_device,
 	&au1xxx_usb_gdt_device,
 	&au1xxx_usb_otg_device,
 	&au1xxx_usb_otg_device,
 	&au1200_lcd_device,
 	&au1200_lcd_device,

+ 9 - 236
drivers/block/ub.c

@@ -8,7 +8,6 @@
  * and is not licensed separately. See file COPYING for details.
  * and is not licensed separately. See file COPYING for details.
  *
  *
  * TODO (sorted by decreasing priority)
  * TODO (sorted by decreasing priority)
- *  -- Kill first_open (Al Viro fixed the block layer now)
  *  -- set readonly flag for CDs, set removable flag for CF readers
  *  -- 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)
  *  -- do inquiry and verify we got a disk and not a tape (for LUN mismatch)
  *  -- special case some senses, e.g. 3a/0 -> no media present, reduce retries
  *  -- special case some senses, e.g. 3a/0 -> no media present, reduce retries
@@ -181,6 +180,7 @@ struct ub_dev;
 #define UB_DIR_ILLEGAL2	2
 #define UB_DIR_ILLEGAL2	2
 #define UB_DIR_WRITE	3
 #define UB_DIR_WRITE	3
 
 
+/* P3 */
 #define UB_DIR_CHAR(c)  (((c)==UB_DIR_WRITE)? 'w': \
 #define UB_DIR_CHAR(c)  (((c)==UB_DIR_WRITE)? 'w': \
 			 (((c)==UB_DIR_READ)? 'r': 'n'))
 			 (((c)==UB_DIR_READ)? 'r': 'n'))
 
 
@@ -196,24 +196,11 @@ enum ub_scsi_cmd_state {
 	UB_CMDST_DONE			/* Final state */
 	UB_CMDST_DONE			/* Final state */
 };
 };
 
 
-static char *ub_scsi_cmd_stname[] = {
-	".  ",
-	"Cmd",
-	"dat",
-	"c2s",
-	"sts",
-	"clr",
-	"crs",
-	"Sen",
-	"fin"
-};
-
 struct ub_scsi_cmd {
 struct ub_scsi_cmd {
 	unsigned char cdb[UB_MAX_CDB_SIZE];
 	unsigned char cdb[UB_MAX_CDB_SIZE];
 	unsigned char cdb_len;
 	unsigned char cdb_len;
 
 
 	unsigned char dir;		/* 0 - none, 1 - read, 3 - write. */
 	unsigned char dir;		/* 0 - none, 1 - read, 3 - write. */
-	unsigned char trace_index;
 	enum ub_scsi_cmd_state state;
 	enum ub_scsi_cmd_state state;
 	unsigned int tag;
 	unsigned int tag;
 	struct ub_scsi_cmd *next;
 	struct ub_scsi_cmd *next;
@@ -249,28 +236,6 @@ struct ub_capacity {
 	unsigned int bshift;		/* Shift between 512 and hard sects */
 	unsigned int bshift;		/* Shift between 512 and hard sects */
 };
 };
 
 
-/*
- * The SCSI command tracing structure.
- */
-
-#define SCMD_ST_HIST_SZ   8
-#define SCMD_TRACE_SZ    63		/* Less than 4KB of 61-byte lines */
-
-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
  * This is a direct take-off from linux/include/completion.h
  * The difference is that I do not wait on this thing, just poll.
  * The difference is that I do not wait on this thing, just poll.
@@ -334,7 +299,6 @@ struct ub_lun {
 	int changed;			/* Media was changed */
 	int changed;			/* Media was changed */
 	int removable;
 	int removable;
 	int readonly;
 	int readonly;
-	int first_open;			/* Kludge. See ub_bd_open. */
 
 
 	struct ub_request urq;
 	struct ub_request urq;
 
 
@@ -390,7 +354,6 @@ struct ub_dev {
 	wait_queue_head_t reset_wait;
 	wait_queue_head_t reset_wait;
 
 
 	int sg_stat[6];
 	int sg_stat[6];
-	struct ub_scsi_trace tr;
 };
 };
 
 
 /*
 /*
@@ -459,137 +422,6 @@ static int ub_qlock_next = 0;
 
 
 static DEFINE_SPINLOCK(ub_lock);	/* Locks globals and ->openc */
 static DEFINE_SPINLOCK(ub_lock);	/* 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, struct device_attribute *attr,
-    char *page)
-{
-	struct usb_interface *intf;
-	struct ub_dev *sc;
-	struct list_head *p;
-	struct ub_lun *lun;
-	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,
-	    "poison %d reset %d\n",
-	    atomic_read(&sc->poison), sc->reset);
-	cnt += sprintf(page + cnt,
-	    "qlen %d qmax %d\n",
-	    sc->cmd_queue.qlen, sc->cmd_queue.qmax);
-	cnt += sprintf(page + cnt,
-	    "sg %d %d %d %d %d .. %d\n",
-	    sc->sg_stat[0],
-	    sc->sg_stat[1],
-	    sc->sg_stat[2],
-	    sc->sg_stat[3],
-	    sc->sg_stat[4],
-	    sc->sg_stat[5]);
-
-	list_for_each (p, &sc->luns) {
-		lun = list_entry(p, struct ub_lun, link);
-		cnt += sprintf(page + cnt,
-		    "lun %u changed %d removable %d readonly %d\n",
-		    lun->num, lun->changed, lun->removable, lun->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.
  * The id allocator.
  *
  *
@@ -1092,7 +924,6 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 	add_timer(&sc->work_timer);
 	add_timer(&sc->work_timer);
 
 
 	cmd->state = UB_CMDST_CMD;
 	cmd->state = UB_CMDST_CMD;
-	ub_cmdtr_state(sc, cmd);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1145,12 +976,10 @@ static void ub_scsi_dispatch(struct ub_dev *sc)
 			ub_cmdq_pop(sc);
 			ub_cmdq_pop(sc);
 			(*cmd->done)(sc, cmd);
 			(*cmd->done)(sc, cmd);
 		} else if (cmd->state == UB_CMDST_INIT) {
 		} else if (cmd->state == UB_CMDST_INIT) {
-			ub_cmdtr_new(sc, cmd);
 			if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0)
 			if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0)
 				break;
 				break;
 			cmd->error = rc;
 			cmd->error = rc;
 			cmd->state = UB_CMDST_DONE;
 			cmd->state = UB_CMDST_DONE;
-			ub_cmdtr_state(sc, cmd);
 		} else {
 		} else {
 			if (!ub_is_completed(&sc->work_done))
 			if (!ub_is_completed(&sc->work_done))
 				break;
 				break;
@@ -1247,7 +1076,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 				return;
 				return;
 			}
 			}
 			cmd->state = UB_CMDST_CLEAR;
 			cmd->state = UB_CMDST_CLEAR;
-			ub_cmdtr_state(sc, cmd);
 			return;
 			return;
 		case -ESHUTDOWN:	/* unplug */
 		case -ESHUTDOWN:	/* unplug */
 		case -EILSEQ:		/* unplug timeout on uhci */
 		case -EILSEQ:		/* unplug timeout on uhci */
@@ -1279,7 +1107,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 				return;
 				return;
 			}
 			}
 			cmd->state = UB_CMDST_CLR2STS;
 			cmd->state = UB_CMDST_CLR2STS;
-			ub_cmdtr_state(sc, cmd);
 			return;
 			return;
 		}
 		}
 		if (urb->status == -EOVERFLOW) {
 		if (urb->status == -EOVERFLOW) {
@@ -1304,7 +1131,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 			if (urb->status != 0 ||
 			if (urb->status != 0 ||
 			    len != cmd->sgv[cmd->current_sg].length) {
 			    len != cmd->sgv[cmd->current_sg].length) {
 				cmd->act_len += len;
 				cmd->act_len += len;
-				ub_cmdtr_act_len(sc, cmd);
 
 
 				cmd->error = -EIO;
 				cmd->error = -EIO;
 				ub_state_stat(sc, cmd);
 				ub_state_stat(sc, cmd);
@@ -1331,7 +1157,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 		}
 		}
 
 
 		cmd->act_len += urb->actual_length;
 		cmd->act_len += urb->actual_length;
-		ub_cmdtr_act_len(sc, cmd);
 
 
 		if (++cmd->current_sg < cmd->nsg) {
 		if (++cmd->current_sg < cmd->nsg) {
 			ub_data_start(sc, cmd);
 			ub_data_start(sc, cmd);
@@ -1357,7 +1182,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 			cmd->error = -EIO;		/* A cheap trick... */
 			cmd->error = -EIO;		/* A cheap trick... */
 
 
 			cmd->state = UB_CMDST_CLRRS;
 			cmd->state = UB_CMDST_CLRRS;
-			ub_cmdtr_state(sc, cmd);
 			return;
 			return;
 		}
 		}
 
 
@@ -1441,7 +1265,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 			return;
 			return;
 		}
 		}
 		cmd->state = UB_CMDST_DONE;
 		cmd->state = UB_CMDST_DONE;
-		ub_cmdtr_state(sc, cmd);
 		ub_cmdq_pop(sc);
 		ub_cmdq_pop(sc);
 		(*cmd->done)(sc, cmd);
 		(*cmd->done)(sc, cmd);
 
 
@@ -1496,7 +1319,6 @@ static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 	add_timer(&sc->work_timer);
 	add_timer(&sc->work_timer);
 
 
 	cmd->state = UB_CMDST_DATA;
 	cmd->state = UB_CMDST_DATA;
-	ub_cmdtr_state(sc, cmd);
 }
 }
 
 
 /*
 /*
@@ -1508,7 +1330,6 @@ static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc)
 
 
 	cmd->error = rc;
 	cmd->error = rc;
 	cmd->state = UB_CMDST_DONE;
 	cmd->state = UB_CMDST_DONE;
-	ub_cmdtr_state(sc, cmd);
 	ub_cmdq_pop(sc);
 	ub_cmdq_pop(sc);
 	(*cmd->done)(sc, cmd);
 	(*cmd->done)(sc, cmd);
 }
 }
@@ -1554,7 +1375,6 @@ static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 
 
 	cmd->stat_count = 0;
 	cmd->stat_count = 0;
 	cmd->state = UB_CMDST_STAT;
 	cmd->state = UB_CMDST_STAT;
-	ub_cmdtr_state(sc, cmd);
 }
 }
 
 
 /*
 /*
@@ -1573,7 +1393,6 @@ static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 		return;
 		return;
 
 
 	cmd->state = UB_CMDST_STAT;
 	cmd->state = UB_CMDST_STAT;
-	ub_cmdtr_state(sc, cmd);
 }
 }
 
 
 /*
 /*
@@ -1611,7 +1430,6 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 	scmd->tag = sc->tagcnt++;
 	scmd->tag = sc->tagcnt++;
 
 
 	cmd->state = UB_CMDST_SENSE;
 	cmd->state = UB_CMDST_SENSE;
-	ub_cmdtr_state(sc, cmd);
 
 
 	ub_cmdq_insert(sc, scmd);
 	ub_cmdq_insert(sc, scmd);
 	return;
 	return;
@@ -1667,11 +1485,6 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
 	unsigned char *sense = sc->top_sense;
 	unsigned char *sense = sc->top_sense;
 	struct ub_scsi_cmd *cmd;
 	struct ub_scsi_cmd *cmd;
 
 
-	/*
-	 * Ignoring scmd->act_len, because the buffer was pre-zeroed.
-	 */
-	ub_cmdtr_sense(sc, scmd, sense);
-
 	/*
 	/*
 	 * Find the command which triggered the unit attention or a check,
 	 * Find the command which triggered the unit attention or a check,
 	 * save the sense into it, and advance its state machine.
 	 * save the sense into it, and advance its state machine.
@@ -1693,6 +1506,9 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
 		return;
 		return;
 	}
 	}
 
 
+	/*
+	 * Ignoring scmd->act_len, because the buffer was pre-zeroed.
+	 */
 	cmd->key = sense[2] & 0x0F;
 	cmd->key = sense[2] & 0x0F;
 	cmd->asc = sense[12];
 	cmd->asc = sense[12];
 	cmd->ascq = sense[13];
 	cmd->ascq = sense[13];
@@ -1849,26 +1665,6 @@ static int ub_bd_open(struct inode *inode, struct file *filp)
 	sc->openc++;
 	sc->openc++;
 	spin_unlock_irqrestore(&ub_lock, flags);
 	spin_unlock_irqrestore(&ub_lock, flags);
 
 
-	/*
-	 * This is a workaround for a specific problem in our block layer.
-	 * In 2.6.9, register_disk duplicates the code from rescan_partitions.
-	 * However, if we do add_disk with a device which persistently reports
-	 * a changed media, add_disk calls register_disk, which does do_open,
-	 * which will call rescan_paritions for changed media. After that,
-	 * register_disk attempts to do it all again and causes double kobject
-	 * registration and a eventually an oops on module removal.
-	 *
-	 * The bottom line is, Al Viro says that we should not allow
-	 * bdev->bd_invalidated to be set when doing add_disk no matter what.
-	 */
-	if (lun->first_open) {
-		lun->first_open = 0;
-		if (lun->changed) {
-			rc = -ENOMEDIUM;
-			goto err_open;
-		}
-	}
-
 	if (lun->removable || lun->readonly)
 	if (lun->removable || lun->readonly)
 		check_disk_change(inode->i_bdev);
 		check_disk_change(inode->i_bdev);
 
 
@@ -2007,9 +1803,8 @@ static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun)
 	init_completion(&compl);
 	init_completion(&compl);
 
 
 	rc = -ENOMEM;
 	rc = -ENOMEM;
-	if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
+	if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
 		goto err_alloc;
 		goto err_alloc;
-	memset(cmd, 0, ALLOC_SIZE);
 
 
 	cmd->cdb[0] = TEST_UNIT_READY;
 	cmd->cdb[0] = TEST_UNIT_READY;
 	cmd->cdb_len = 6;
 	cmd->cdb_len = 6;
@@ -2062,9 +1857,8 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
 	init_completion(&compl);
 	init_completion(&compl);
 
 
 	rc = -ENOMEM;
 	rc = -ENOMEM;
-	if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
+	if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
 		goto err_alloc;
 		goto err_alloc;
-	memset(cmd, 0, ALLOC_SIZE);
 	p = (char *)cmd + sizeof(struct ub_scsi_cmd);
 	p = (char *)cmd + sizeof(struct ub_scsi_cmd);
 
 
 	cmd->cdb[0] = 0x25;
 	cmd->cdb[0] = 0x25;
@@ -2405,9 +2199,8 @@ static int ub_probe(struct usb_interface *intf,
 		return -ENXIO;
 		return -ENXIO;
 
 
 	rc = -ENOMEM;
 	rc = -ENOMEM;
-	if ((sc = kmalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL)
+	if ((sc = kzalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL)
 		goto err_core;
 		goto err_core;
-	memset(sc, 0, sizeof(struct ub_dev));
 	sc->lock = ub_next_lock();
 	sc->lock = ub_next_lock();
 	INIT_LIST_HEAD(&sc->luns);
 	INIT_LIST_HEAD(&sc->luns);
 	usb_init_urb(&sc->work_urb);
 	usb_init_urb(&sc->work_urb);
@@ -2438,9 +2231,6 @@ static int ub_probe(struct usb_interface *intf,
 	if (ub_get_pipes(sc, sc->dev, intf) != 0)
 	if (ub_get_pipes(sc, sc->dev, intf) != 0)
 		goto err_dev_desc;
 		goto err_dev_desc;
 
 
-	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.
 	 * At this point, all USB initialization is done, do upper layer.
 	 * We really hate halfway initialized structures, so from the
 	 * We really hate halfway initialized structures, so from the
@@ -2480,19 +2270,8 @@ static int ub_probe(struct usb_interface *intf,
 
 
 	nluns = 1;
 	nluns = 1;
 	for (i = 0; i < 3; i++) {
 	for (i = 0; i < 3; i++) {
-		if ((rc = ub_sync_getmaxlun(sc)) < 0) {
-			/* 
-			 * This segment is taken from usb-storage. They say
-			 * that ZIP-100 needs this, but my own ZIP-100 works
-			 * fine without this.
-			 * Still, it does not seem to hurt anything.
-			 */
-			if (rc == -EPIPE) {
-				ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
-				ub_probe_clear_stall(sc, sc->send_bulk_pipe);
-			}
+		if ((rc = ub_sync_getmaxlun(sc)) < 0)
 			break;
 			break;
-		}
 		if (rc != 0) {
 		if (rc != 0) {
 			nluns = rc;
 			nluns = rc;
 			break;
 			break;
@@ -2505,8 +2284,6 @@ static int ub_probe(struct usb_interface *intf,
 	}
 	}
 	return 0;
 	return 0;
 
 
-	/* device_remove_file(&sc->intf->dev, &dev_attr_diag); */
-err_diag:
 err_dev_desc:
 err_dev_desc:
 	usb_set_intfdata(intf, NULL);
 	usb_set_intfdata(intf, NULL);
 	// usb_put_intf(sc->intf);
 	// usb_put_intf(sc->intf);
@@ -2524,9 +2301,8 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
 	int rc;
 	int rc;
 
 
 	rc = -ENOMEM;
 	rc = -ENOMEM;
-	if ((lun = kmalloc(sizeof(struct ub_lun), GFP_KERNEL)) == NULL)
+	if ((lun = kzalloc(sizeof(struct ub_lun), GFP_KERNEL)) == NULL)
 		goto err_alloc;
 		goto err_alloc;
-	memset(lun, 0, sizeof(struct ub_lun));
 	lun->num = lnum;
 	lun->num = lnum;
 
 
 	rc = -ENOSR;
 	rc = -ENOSR;
@@ -2541,7 +2317,6 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
 
 
 	lun->removable = 1;		/* XXX Query this from the device */
 	lun->removable = 1;		/* XXX Query this from the device */
 	lun->changed = 1;		/* ub_revalidate clears only */
 	lun->changed = 1;		/* ub_revalidate clears only */
-	lun->first_open = 1;
 	ub_revalidate(sc, lun);
 	ub_revalidate(sc, lun);
 
 
 	rc = -ENOMEM;
 	rc = -ENOMEM;
@@ -2636,7 +2411,6 @@ static void ub_disconnect(struct usb_interface *intf)
 		while ((cmd = ub_cmdq_peek(sc)) != NULL) {
 		while ((cmd = ub_cmdq_peek(sc)) != NULL) {
 			cmd->error = -ENOTCONN;
 			cmd->error = -ENOTCONN;
 			cmd->state = UB_CMDST_DONE;
 			cmd->state = UB_CMDST_DONE;
-			ub_cmdtr_state(sc, cmd);
 			ub_cmdq_pop(sc);
 			ub_cmdq_pop(sc);
 			(*cmd->done)(sc, cmd);
 			(*cmd->done)(sc, cmd);
 			cnt++;
 			cnt++;
@@ -2687,7 +2461,6 @@ static void ub_disconnect(struct usb_interface *intf)
 	 * and no URBs left in transit.
 	 * and no URBs left in transit.
 	 */
 	 */
 
 
-	device_remove_file(&sc->intf->dev, &dev_attr_diag);
 	usb_set_intfdata(intf, NULL);
 	usb_set_intfdata(intf, NULL);
 	// usb_put_intf(sc->intf);
 	// usb_put_intf(sc->intf);
 	sc->intf = NULL;
 	sc->intf = NULL;

+ 3 - 2
drivers/net/irda/irda-usb.c

@@ -740,7 +740,7 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
 	struct sk_buff *newskb;
 	struct sk_buff *newskb;
 	struct sk_buff *dataskb;
 	struct sk_buff *dataskb;
 	struct urb *next_urb;
 	struct urb *next_urb;
-	int		docopy;
+	unsigned int len, docopy;
 
 
 	IRDA_DEBUG(2, "%s(), len=%d\n", __FUNCTION__, urb->actual_length);
 	IRDA_DEBUG(2, "%s(), len=%d\n", __FUNCTION__, urb->actual_length);
 	
 	
@@ -851,10 +851,11 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
 	dataskb->dev = self->netdev;
 	dataskb->dev = self->netdev;
 	dataskb->mac.raw  = dataskb->data;
 	dataskb->mac.raw  = dataskb->data;
 	dataskb->protocol = htons(ETH_P_IRDA);
 	dataskb->protocol = htons(ETH_P_IRDA);
+	len = dataskb->len;
 	netif_rx(dataskb);
 	netif_rx(dataskb);
 
 
 	/* Keep stats up to date */
 	/* Keep stats up to date */
-	self->stats.rx_bytes += dataskb->len;
+	self->stats.rx_bytes += len;
 	self->stats.rx_packets++;
 	self->stats.rx_packets++;
 	self->netdev->last_rx = jiffies;
 	self->netdev->last_rx = jiffies;
 
 

+ 9 - 0
drivers/usb/Kconfig

@@ -10,6 +10,7 @@ menu "USB support"
 config USB_ARCH_HAS_HCD
 config USB_ARCH_HAS_HCD
 	boolean
 	boolean
 	default y if USB_ARCH_HAS_OHCI
 	default y if USB_ARCH_HAS_OHCI
+	default y if USB_ARCH_HAS_EHCI
 	default y if ARM				# SL-811
 	default y if ARM				# SL-811
 	default PCI
 	default PCI
 
 
@@ -22,6 +23,7 @@ config USB_ARCH_HAS_OHCI
 	default y if ARCH_LH7A404
 	default y if ARCH_LH7A404
 	default y if ARCH_S3C2410
 	default y if ARCH_S3C2410
 	default y if PXA27x
 	default y if PXA27x
+	default y if ARCH_AT91RM9200
 	# PPC:
 	# PPC:
 	default y if STB03xxx
 	default y if STB03xxx
 	default y if PPC_MPC52xx
 	default y if PPC_MPC52xx
@@ -30,6 +32,13 @@ config USB_ARCH_HAS_OHCI
 	# more:
 	# more:
 	default PCI
 	default PCI
 
 
+# some non-PCI hcds implement EHCI
+config USB_ARCH_HAS_EHCI
+	boolean
+	default y if PPC_83xx
+	default y if SOC_AU1200
+	default PCI
+
 # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
 # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
 config USB
 config USB
 	tristate "Support for Host-side USB"
 	tristate "Support for Host-side USB"

+ 2 - 2
drivers/usb/Makefile

@@ -15,10 +15,9 @@ obj-$(CONFIG_USB_OHCI_HCD)	+= host/
 obj-$(CONFIG_USB_UHCI_HCD)	+= host/
 obj-$(CONFIG_USB_UHCI_HCD)	+= host/
 obj-$(CONFIG_USB_SL811_HCD)	+= host/
 obj-$(CONFIG_USB_SL811_HCD)	+= host/
 obj-$(CONFIG_ETRAX_USB_HOST)	+= host/
 obj-$(CONFIG_ETRAX_USB_HOST)	+= host/
+obj-$(CONFIG_USB_OHCI_AT91)	+= host/
 
 
 obj-$(CONFIG_USB_ACM)		+= class/
 obj-$(CONFIG_USB_ACM)		+= class/
-obj-$(CONFIG_USB_AUDIO)		+= class/
-obj-$(CONFIG_USB_MIDI)		+= class/
 obj-$(CONFIG_USB_PRINTER)	+= class/
 obj-$(CONFIG_USB_PRINTER)	+= class/
 
 
 obj-$(CONFIG_USB_STORAGE)	+= storage/
 obj-$(CONFIG_USB_STORAGE)	+= storage/
@@ -48,6 +47,7 @@ obj-$(CONFIG_USB_SN9C102)	+= media/
 obj-$(CONFIG_USB_STV680)	+= media/
 obj-$(CONFIG_USB_STV680)	+= media/
 obj-$(CONFIG_USB_VICAM)		+= media/
 obj-$(CONFIG_USB_VICAM)		+= media/
 obj-$(CONFIG_USB_W9968CF)	+= media/
 obj-$(CONFIG_USB_W9968CF)	+= media/
+obj-$(CONFIG_USB_ZC0301)	+= media/
 
 
 obj-$(CONFIG_USB_CATC)		+= net/
 obj-$(CONFIG_USB_CATC)		+= net/
 obj-$(CONFIG_USB_KAWETH)	+= net/
 obj-$(CONFIG_USB_KAWETH)	+= net/

+ 0 - 47
drivers/usb/class/Kconfig

@@ -4,53 +4,6 @@
 comment "USB Device Class drivers"
 comment "USB Device Class drivers"
 	depends on USB
 	depends on USB
 
 
-config OBSOLETE_OSS_USB_DRIVER
-	bool "Obsolete OSS USB drivers"
-	depends on USB && SOUND
-	help
-	  This option enables support for the obsolete USB Audio and Midi
-	  drivers that are scheduled for removal in the near future since
-	  there are ALSA drivers for the same hardware.
-
-	  Please contact Adrian Bunk <bunk@stusta.de> if you had to
-	  say Y here because of missing support in the ALSA drivers.
-
-	  If unsure, say N.
-
-config USB_AUDIO
-	tristate "USB Audio support"
-	depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER
-	help
-	  Say Y here if you want to connect USB audio equipment such as
-	  speakers to your computer's USB port. You only need this if you use
-	  the OSS sound driver; ALSA has its own option for usb audio support.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called audio.
-
-config USB_MIDI
-	tristate "USB MIDI support"
-	depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER
-	---help---
-	  Say Y here if you want to connect a USB MIDI device to your
-	  computer's USB port.  You only need this if you use the OSS
-	  sound system; USB MIDI devices are supported by ALSA's USB
-	  audio driver. This driver is for devices that comply with
-	  'Universal Serial Bus Device Class Definition for MIDI Device'.
-
-	  The following devices are known to work:
-	  * Steinberg USB2MIDI
-	  * Roland MPU64
-	  * Roland PC-300
-	  * Roland SC8850
-	  * Roland UM-1
-	  * Roland UM-2
-	  * Roland UA-100
-	  * Yamaha MU1000
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called usb-midi.
-
 config USB_ACM
 config USB_ACM
 	tristate "USB Modem (CDC ACM) support"
 	tristate "USB Modem (CDC ACM) support"
 	depends on USB
 	depends on USB

+ 0 - 2
drivers/usb/class/Makefile

@@ -4,6 +4,4 @@
 #
 #
 
 
 obj-$(CONFIG_USB_ACM)		+= cdc-acm.o
 obj-$(CONFIG_USB_ACM)		+= cdc-acm.o
-obj-$(CONFIG_USB_AUDIO)		+= audio.o
-obj-$(CONFIG_USB_MIDI)		+= usb-midi.o
 obj-$(CONFIG_USB_PRINTER)	+= usblp.o
 obj-$(CONFIG_USB_PRINTER)	+= usblp.o

+ 0 - 3869
drivers/usb/class/audio.c

@@ -1,3869 +0,0 @@
-/*****************************************************************************/
-
-/*
- *	audio.c  --  USB Audio Class driver
- *
- *	Copyright (C) 1999, 2000, 2001, 2003, 2004
- *	    Alan Cox (alan@lxorguk.ukuu.org.uk)
- *	    Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- *	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.
- *
- * Debugging:
- * 	Use the 'lsusb' utility to dump the descriptors.
- *
- * 1999-09-07:  Alan Cox
- *		Parsing Audio descriptor patch
- * 1999-09-08:  Thomas Sailer
- *		Added OSS compatible data io functions; both parts of the
- *		driver remain to be glued together
- * 1999-09-10:  Thomas Sailer
- *		Beautified the driver. Added sample format conversions.
- *		Still not properly glued with the parsing code.
- *		The parsing code seems to have its problems btw,
- *		Since it parses all available configs but doesn't
- *		store which iface/altsetting belongs to which config.
- * 1999-09-20:  Thomas Sailer
- *		Threw out Alan's parsing code and implemented my own one.
- *		You cannot reasonnably linearly parse audio descriptors,
- *		especially the AudioClass descriptors have to be considered
- *		pointer lists. Mixer parsing untested, due to lack of device.
- *		First stab at synch pipe implementation, the Dallas USB DAC
- *		wants to use an Asynch out pipe. usb_audio_state now basically
- *		only contains lists of mixer and wave devices. We can therefore
- *		now have multiple mixer/wave devices per USB device.
- * 1999-10-28:  Thomas Sailer
- *		Converted to URB API. Fixed a taskstate/wakeup semantics mistake
- *		that made the driver consume all available CPU cycles.
- *		Now runs stable on UHCI-Acher/Fliegl/Sailer.
- * 1999-10-31:  Thomas Sailer
- *		Audio can now be unloaded if it is not in use by any mixer
- *		or dsp client (formerly you had to disconnect the audio devices
- *		from the USB port)
- *		Finally, about three months after ordering, my "Maxxtro SPK222"
- *		speakers arrived, isn't disdata a great mail order company 8-)
- *		Parse class specific endpoint descriptor of the audiostreaming
- *		interfaces and take the endpoint attributes from there.
- *		Unbelievably, the Philips USB DAC has a sampling rate range
- *		of over a decade, yet does not support the sampling rate control!
- *		No wonder it sounds so bad, has very audible sampling rate
- *		conversion distortion. Don't try to listen to it using
- *		decent headphones!
- *		"Let's make things better" -> but please Philips start with your
- *		own stuff!!!!
- * 1999-11-02:  Thomas Sailer
- *		It takes the Philips boxes several seconds to acquire synchronisation
- *		that means they won't play short sounds. Should probably maintain
- *		the ISO datastream even if there's nothing to play.
- *		Fix counting the total_bytes counter, RealPlayer G2 depends on it.
- * 1999-12-20:  Thomas Sailer
- *		Fix bad bug in conversion to per interface probing.
- *		disconnect was called multiple times for the audio device,
- *		leading to a premature freeing of the audio structures
- * 2000-05-13:  Thomas Sailer
- *		I don't remember who changed the find_format routine,
- *              but the change was completely broken for the Dallas
- *              chip. Anyway taking sampling rate into account in find_format
- *              is bad and should not be done unless there are devices with
- *              completely broken audio descriptors. Unless someone shows
- *              me such a descriptor, I will not allow find_format to
- *              take the sampling rate into account.
- *              Also, the former find_format made:
- *              - mpg123 play mono instead of stereo
- *              - sox completely fail for wav's with sample rates < 44.1kHz
- *                  for the Dallas chip.
- *              Also fix a rather long standing problem with applications that
- *              use "small" writes producing no sound at all.
- * 2000-05-15:  Thomas Sailer
- *		My fears came true, the Philips camera indeed has pretty stupid
- *              audio descriptors.
- * 2000-05-17:  Thomas Sailer
- *		Nemsoft spotted my stupid last minute change, thanks
- * 2000-05-19:  Thomas Sailer
- *		Fixed FEATURE_UNIT thinkos found thanks to the KC Technology
- *              Xtend device. Basically the driver treated FEATURE_UNIT's sourced
- *              by mono terminals as stereo.
- * 2000-05-20:  Thomas Sailer
- *		SELECTOR support (and thus selecting record channels from the mixer).
- *              Somewhat peculiar due to OSS interface limitations. Only works
- *              for channels where a "slider" is already in front of it (i.e.
- *              a MIXER unit or a FEATURE unit with volume capability).
- * 2000-11-26:  Thomas Sailer
- *              Workaround for Dallas DS4201. The DS4201 uses PCM8 as format tag for
- *              its 8 bit modes, but expects signed data (and should therefore have used PCM).
- * 2001-03-10:  Thomas Sailer
- *              provide abs function, prevent picking up a bogus kernel macro
- *              for abs. Bug report by Andrew Morton <andrewm@uow.edu.au>
- * 2001-06-16:  Bryce Nesbitt <bryce@obviously.com>
- *              Fix SNDCTL_DSP_STEREO API violation
- * 2003-04-08:	Oliver Neukum (oliver@neukum.name):
- *		Setting a configuration is done by usbcore and must not be overridden
- * 2004-02-27:  Workaround for broken synch descriptors
- * 2004-03-07:	Alan Stern <stern@rowland.harvard.edu>
- *		Add usb_ifnum_to_if() and usb_altnum_to_altsetting() support.
- *		Use the in-memory descriptors instead of reading them from the device.
- * 
- */
-
-/*
- * Strategy:
- *
- * Alan Cox and Thomas Sailer are starting to dig at opposite ends and
- * are hoping to meet in the middle, just like tunnel diggers :)
- * Alan tackles the descriptor parsing, Thomas the actual data IO and the
- * OSS compatible interface.
- *
- * Data IO implementation issues
- *
- * A mmap'able ring buffer per direction is implemented, because
- * almost every OSS app expects it. It is however impractical to
- * transmit/receive USB data directly into and out of the ring buffer,
- * due to alignment and synchronisation issues. Instead, the ring buffer
- * feeds a constant time delay line that handles the USB issues.
- *
- * Now we first try to find an alternate setting that exactly matches
- * the sample format requested by the user. If we find one, we do not
- * need to perform any sample rate conversions. If there is no matching
- * altsetting, we choose the closest one and perform sample format
- * conversions. We never do sample rate conversion; these are too
- * expensive to be performed in the kernel.
- *
- * Current status: no known HCD-specific issues.
- *
- * Generally: Due to the brokenness of the Audio Class spec
- * it seems generally impossible to write a generic Audio Class driver,
- * so a reasonable driver should implement the features that are actually
- * used.
- *
- * Parsing implementation issues
- *
- * One cannot reasonably parse the AudioClass descriptors linearly.
- * Therefore the current implementation features routines to look
- * for a specific descriptor in the descriptor list.
- *
- * How does the parsing work? First, all interfaces are searched
- * for an AudioControl class interface. If found, the config descriptor
- * that belongs to the current configuration is searched and
- * the HEADER descriptor is found. It contains a list of
- * all AudioStreaming and MIDIStreaming devices. This list is then walked,
- * and all AudioStreaming interfaces are classified into input and output
- * interfaces (according to the endpoint0 direction in altsetting1) (MIDIStreaming
- * is currently not supported). The input & output list is then used
- * to group inputs and outputs together and issued pairwise to the
- * AudioStreaming class parser. Finally, all OUTPUT_TERMINAL descriptors
- * are walked and issued to the mixer construction routine.
- *
- * The AudioStreaming parser simply enumerates all altsettings belonging
- * to the specified interface. It looks for AS_GENERAL and FORMAT_TYPE
- * class specific descriptors to extract the sample format/sample rate
- * data. Only sample format types PCM and PCM8 are supported right now, and
- * only FORMAT_TYPE_I is handled. The isochronous data endpoint needs to
- * be the first endpoint of the interface, and the optional synchronisation
- * isochronous endpoint the second one.
- *
- * Mixer construction works as follows: The various TERMINAL and UNIT
- * descriptors span a tree from the root (OUTPUT_TERMINAL) through the
- * intermediate nodes (UNITs) to the leaves (INPUT_TERMINAL). We walk
- * that tree in a depth first manner. FEATURE_UNITs may contribute volume,
- * bass and treble sliders to the mixer, MIXER_UNITs volume sliders.
- * The terminal type encoded in the INPUT_TERMINALs feeds a heuristic
- * to determine "meaningful" OSS slider numbers, however we will see
- * how well this works in practice. Other features are not used at the
- * moment, they seem less often used. Also, it seems difficult at least
- * to construct recording source switches from SELECTOR_UNITs, but
- * since there are not many USB ADC's available, we leave that for later.
- */
-
-/*****************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/module.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/list.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/bitops.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <linux/usb.h>
-
-#include "audio.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.0.0"
-#define DRIVER_AUTHOR "Alan Cox <alan@lxorguk.ukuu.org.uk>, Thomas Sailer (sailer@ife.ee.ethz.ch)"
-#define DRIVER_DESC "USB Audio Class driver"
-
-#define AUDIO_DEBUG 1
-
-#define SND_DEV_DSP16   5
-
-#define dprintk(x)
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Linked list of all audio devices...
- */
-static struct list_head audiodevs = LIST_HEAD_INIT(audiodevs);
-static DECLARE_MUTEX(open_sem);
-
-/*
- * wait queue for processes wanting to open an USB audio device
- */
-static DECLARE_WAIT_QUEUE_HEAD(open_wait);
-
-
-#define MAXFORMATS        MAX_ALT
-#define DMABUFSHIFT       17  /* 128k worth of DMA buffer */
-#define NRSGBUF           (1U<<(DMABUFSHIFT-PAGE_SHIFT))
-
-/*
- * This influences:
- * - Latency
- * - Interrupt rate
- * - Synchronisation behaviour
- * Don't touch this if you don't understand all of the above.
- */
-#define DESCFRAMES  5
-#define SYNCFRAMES  DESCFRAMES
-
-#define MIXFLG_STEREOIN   1
-#define MIXFLG_STEREOOUT  2
-
-struct mixerchannel {
-	__u16 value;
-	__u16 osschannel;  /* number of the OSS channel */
-	__s16 minval, maxval;
-	__u16 slctunitid;
-	__u8 unitid;
-	__u8 selector;
-	__u8 chnum;
-	__u8 flags;
-};
-
-struct audioformat {
-	unsigned int format;
-	unsigned int sratelo;
-	unsigned int sratehi;
-	unsigned char altsetting;
-	unsigned char attributes;
-};
-
-struct dmabuf {
-	/* buffer data format */
-	unsigned int format;
-	unsigned int srate;
-	/* physical buffer */
-	unsigned char *sgbuf[NRSGBUF];
-	unsigned bufsize;
-	unsigned numfrag;
-	unsigned fragshift;
-	unsigned wrptr, rdptr;
-	unsigned total_bytes;
-	int count;
-	unsigned error; /* over/underrun */
-	wait_queue_head_t wait;
-	/* redundant, but makes calculations easier */
-	unsigned fragsize;
-	unsigned dmasize;
-	/* OSS stuff */
-	unsigned mapped:1;
-	unsigned ready:1;
-	unsigned ossfragshift;
-	int ossmaxfrags;
-	unsigned subdivision;
-};
-
-struct usb_audio_state;
-
-#define FLG_URB0RUNNING   1
-#define FLG_URB1RUNNING   2
-#define FLG_SYNC0RUNNING  4
-#define FLG_SYNC1RUNNING  8
-#define FLG_RUNNING      16
-#define FLG_CONNECTED    32
-
-struct my_data_urb {
-	struct urb *urb;
-};
-
-struct my_sync_urb {
-	struct urb *urb;
-};
-
-
-struct usb_audiodev {
-	struct list_head list;
-	struct usb_audio_state *state;
-	
-	/* soundcore stuff */
-	int dev_audio;
-
-	/* wave stuff */
-	mode_t open_mode;
-	spinlock_t lock;         /* DMA buffer access spinlock */
-
-	struct usbin {
-		int interface;           /* Interface number, -1 means not used */
-		unsigned int format;     /* USB data format */
-		unsigned int datapipe;   /* the data input pipe */
-		unsigned int syncpipe;   /* the synchronisation pipe - 0 for anything but adaptive IN mode */
-		unsigned int syncinterval;  /* P for adaptive IN mode, 0 otherwise */
-		unsigned int freqn;      /* nominal sampling rate in USB format, i.e. fs/1000 in Q10.14 */
-		unsigned int freqmax;    /* maximum sampling rate, used for buffer management */
-		unsigned int phase;      /* phase accumulator */
-		unsigned int flags;      /* see FLG_ defines */
-		
-		struct my_data_urb durb[2];  /* ISO descriptors for the data endpoint */
-		struct my_sync_urb surb[2];  /* ISO sync pipe descriptor if needed */
-		
-		struct dmabuf dma;
-	} usbin;
-
-	struct usbout {
-		int interface;           /* Interface number, -1 means not used */
-		unsigned int format;     /* USB data format */
-		unsigned int datapipe;   /* the data input pipe */
-		unsigned int syncpipe;   /* the synchronisation pipe - 0 for anything but asynchronous OUT mode */
-		unsigned int syncinterval;  /* P for asynchronous OUT mode, 0 otherwise */
-		unsigned int freqn;      /* nominal sampling rate in USB format, i.e. fs/1000 in Q10.14 */
-		unsigned int freqm;      /* momentary sampling rate in USB format, i.e. fs/1000 in Q10.14 */
-		unsigned int freqmax;    /* maximum sampling rate, used for buffer management */
-		unsigned int phase;      /* phase accumulator */
-		unsigned int flags;      /* see FLG_ defines */
-
-		struct my_data_urb durb[2];  /* ISO descriptors for the data endpoint */
-		struct my_sync_urb surb[2];  /* ISO sync pipe descriptor if needed */
-		
-		struct dmabuf dma;
-	} usbout;
-
-
-	unsigned int numfmtin, numfmtout;
-	struct audioformat fmtin[MAXFORMATS];
-	struct audioformat fmtout[MAXFORMATS];
-};  
-
-struct usb_mixerdev {
-	struct list_head list;
-	struct usb_audio_state *state;
-
-	/* soundcore stuff */
-	int dev_mixer;
-
-	unsigned char iface;  /* interface number of the AudioControl interface */
-
-	/* USB format descriptions */
-	unsigned int numch, modcnt;
-
-	/* mixch is last and gets allocated dynamically */
-	struct mixerchannel ch[0];
-};
-
-struct usb_audio_state {
-	struct list_head audiodev;
-
-	/* USB device */
-	struct usb_device *usbdev;
-
-	struct list_head audiolist;
-	struct list_head mixerlist;
-
-	unsigned count;  /* usage counter; NOTE: the usb stack is also considered a user */
-};
-
-/* private audio format extensions */
-#define AFMT_STEREO        0x80000000
-#define AFMT_ISSTEREO(x)   ((x) & AFMT_STEREO)
-#define AFMT_IS16BIT(x)    ((x) & (AFMT_S16_LE|AFMT_S16_BE|AFMT_U16_LE|AFMT_U16_BE))
-#define AFMT_ISUNSIGNED(x) ((x) & (AFMT_U8|AFMT_U16_LE|AFMT_U16_BE))
-#define AFMT_BYTESSHIFT(x) ((AFMT_ISSTEREO(x) ? 1 : 0) + (AFMT_IS16BIT(x) ? 1 : 0))
-#define AFMT_BYTES(x)      (1<<AFMT_BYTESSHFIT(x))
-
-/* --------------------------------------------------------------------- */
-
-static inline unsigned ld2(unsigned int x)
-{
-	unsigned r = 0;
-	
-	if (x >= 0x10000) {
-		x >>= 16;
-		r += 16;
-	}
-	if (x >= 0x100) {
-		x >>= 8;
-		r += 8;
-	}
-	if (x >= 0x10) {
-		x >>= 4;
-		r += 4;
-	}
-	if (x >= 4) {
-		x >>= 2;
-		r += 2;
-	}
-	if (x >= 2)
-		r++;
-	return r;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * OSS compatible ring buffer management. The ring buffer may be mmap'ed into
- * an application address space.
- *
- * I first used the rvmalloc stuff copied from bttv. Alan Cox did not like it, so
- * we now use an array of pointers to a single page each. This saves us the
- * kernel page table manipulations, but we have to do a page table alike mechanism
- * (though only one indirection) in software.
- */
-
-static void dmabuf_release(struct dmabuf *db)
-{
-	unsigned int nr;
-	void *p;
-
-	for(nr = 0; nr < NRSGBUF; nr++) {
-		if (!(p = db->sgbuf[nr]))
-			continue;
-		ClearPageReserved(virt_to_page(p));
-		free_page((unsigned long)p);
-		db->sgbuf[nr] = NULL;
-	}
-	db->mapped = db->ready = 0;
-}
-
-static int dmabuf_init(struct dmabuf *db)
-{
-	unsigned int nr, bytepersec, bufs;
-	void *p;
-
-	/* initialize some fields */
-	db->rdptr = db->wrptr = db->total_bytes = db->count = db->error = 0;
-	/* calculate required buffer size */
-	bytepersec = db->srate << AFMT_BYTESSHIFT(db->format);
-	bufs = 1U << DMABUFSHIFT;
-	if (db->ossfragshift) {
-		if ((1000 << db->ossfragshift) < bytepersec)
-			db->fragshift = ld2(bytepersec/1000);
-		else
-			db->fragshift = db->ossfragshift;
-	} else {
-		db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
-		if (db->fragshift < 3)
-			db->fragshift = 3;
-	}
-	db->numfrag = bufs >> db->fragshift;
-	while (db->numfrag < 4 && db->fragshift > 3) {
-		db->fragshift--;
-		db->numfrag = bufs >> db->fragshift;
-	}
-	db->fragsize = 1 << db->fragshift;
-	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
-		db->numfrag = db->ossmaxfrags;
-	db->dmasize = db->numfrag << db->fragshift;
-	for(nr = 0; nr < NRSGBUF; nr++) {
-		if (!db->sgbuf[nr]) {
-			p = (void *)get_zeroed_page(GFP_KERNEL);
-			if (!p)
-				return -ENOMEM;
-			db->sgbuf[nr] = p;
-			SetPageReserved(virt_to_page(p));
-		}
-		memset(db->sgbuf[nr], AFMT_ISUNSIGNED(db->format) ? 0x80 : 0, PAGE_SIZE);
-		if ((nr << PAGE_SHIFT) >= db->dmasize)
-			break;
-	}
-	db->bufsize = nr << PAGE_SHIFT;
-	db->ready = 1;
-	dprintk((KERN_DEBUG "usbaudio: dmabuf_init bytepersec %d bufs %d ossfragshift %d ossmaxfrags %d "
-	         "fragshift %d fragsize %d numfrag %d dmasize %d bufsize %d fmt 0x%x srate %d\n",
-	         bytepersec, bufs, db->ossfragshift, db->ossmaxfrags, db->fragshift, db->fragsize,
-	         db->numfrag, db->dmasize, db->bufsize, db->format, db->srate));
-	return 0;
-}
-
-static int dmabuf_mmap(struct vm_area_struct *vma, struct dmabuf *db, unsigned long start, unsigned long size, pgprot_t prot)
-{
-	unsigned int nr;
-
-	if (!db->ready || db->mapped || (start | size) & (PAGE_SIZE-1) || size > db->bufsize)
-		return -EINVAL;
-	size >>= PAGE_SHIFT;
-	for(nr = 0; nr < size; nr++)
-		if (!db->sgbuf[nr])
-			return -EINVAL;
-	db->mapped = 1;
-	for(nr = 0; nr < size; nr++) {
-		unsigned long pfn;
-
-		pfn = virt_to_phys(db->sgbuf[nr]) >> PAGE_SHIFT;
-		if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, prot))
-			return -EAGAIN;
-		start += PAGE_SIZE;
-	}
-	return 0;
-}
-
-static void dmabuf_copyin(struct dmabuf *db, const void *buffer, unsigned int size)
-{
-	unsigned int pgrem, rem;
-
-	db->total_bytes += size;
-	for (;;) {
-		if (size <= 0)
-			return;
-		pgrem = ((~db->wrptr) & (PAGE_SIZE-1)) + 1;
-		if (pgrem > size)
-			pgrem = size;
-		rem = db->dmasize - db->wrptr;
-		if (pgrem > rem)
-			pgrem = rem;
-		memcpy((db->sgbuf[db->wrptr >> PAGE_SHIFT]) + (db->wrptr & (PAGE_SIZE-1)), buffer, pgrem);
-		size -= pgrem;
-		buffer += pgrem;
-		db->wrptr += pgrem;
-		if (db->wrptr >= db->dmasize)
-			db->wrptr = 0;
-	}
-}
-
-static void dmabuf_copyout(struct dmabuf *db, void *buffer, unsigned int size)
-{
-	unsigned int pgrem, rem;
-
-	db->total_bytes += size;
-	for (;;) {
-		if (size <= 0)
-			return;
-		pgrem = ((~db->rdptr) & (PAGE_SIZE-1)) + 1;
-		if (pgrem > size)
-			pgrem = size;
-		rem = db->dmasize - db->rdptr;
-		if (pgrem > rem)
-			pgrem = rem;
-		memcpy(buffer, (db->sgbuf[db->rdptr >> PAGE_SHIFT]) + (db->rdptr & (PAGE_SIZE-1)), pgrem);
-		size -= pgrem;
-		buffer += pgrem;
-		db->rdptr += pgrem;
-		if (db->rdptr >= db->dmasize)
-			db->rdptr = 0;
-	}
-}
-
-static int dmabuf_copyin_user(struct dmabuf *db, unsigned int ptr, const void __user *buffer, unsigned int size)
-{
-	unsigned int pgrem, rem;
-
-	if (!db->ready || db->mapped)
-		return -EINVAL;
-	for (;;) {
-		if (size <= 0)
-			return 0;
-		pgrem = ((~ptr) & (PAGE_SIZE-1)) + 1;
-		if (pgrem > size)
-			pgrem = size;
-		rem = db->dmasize - ptr;
-		if (pgrem > rem)
-			pgrem = rem;
-		if (copy_from_user((db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), buffer, pgrem))
-			return -EFAULT;
-		size -= pgrem;
-		buffer += pgrem;
-		ptr += pgrem;
-		if (ptr >= db->dmasize)
-			ptr = 0;
-	}
-}
-
-static int dmabuf_copyout_user(struct dmabuf *db, unsigned int ptr, void __user *buffer, unsigned int size)
-{
-	unsigned int pgrem, rem;
-
-	if (!db->ready || db->mapped)
-		return -EINVAL;
-	for (;;) {
-		if (size <= 0)
-			return 0;
-		pgrem = ((~ptr) & (PAGE_SIZE-1)) + 1;
-		if (pgrem > size)
-			pgrem = size;
-		rem = db->dmasize - ptr;
-		if (pgrem > rem)
-			pgrem = rem;
-		if (copy_to_user(buffer, (db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), pgrem))
-			return -EFAULT;
-		size -= pgrem;
-		buffer += pgrem;
-		ptr += pgrem;
-		if (ptr >= db->dmasize)
-			ptr = 0;
-	}
-}
-
-/* --------------------------------------------------------------------- */
-/*
- * USB I/O code. We do sample format conversion if necessary
- */
-
-static void usbin_stop(struct usb_audiodev *as)
-{
-	struct usbin *u = &as->usbin;
-	unsigned long flags;
-	unsigned int i, notkilled = 1;
-
-	spin_lock_irqsave(&as->lock, flags);
-	u->flags &= ~FLG_RUNNING;
-	i = u->flags;
-	spin_unlock_irqrestore(&as->lock, flags);
-	while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
-		if (notkilled)
-			schedule_timeout_interruptible(1);
-		else
-			schedule_timeout_uninterruptible(1);
-		spin_lock_irqsave(&as->lock, flags);
-		i = u->flags;
-		spin_unlock_irqrestore(&as->lock, flags);
-		if (notkilled && signal_pending(current)) {
-			if (i & FLG_URB0RUNNING)
-				usb_kill_urb(u->durb[0].urb);
-			if (i & FLG_URB1RUNNING)
-				usb_kill_urb(u->durb[1].urb);
-			if (i & FLG_SYNC0RUNNING)
-				usb_kill_urb(u->surb[0].urb);
-			if (i & FLG_SYNC1RUNNING)
-				usb_kill_urb(u->surb[1].urb);
-			notkilled = 0;
-		}
-	}
-	set_current_state(TASK_RUNNING);
-	kfree(u->durb[0].urb->transfer_buffer);
-	kfree(u->durb[1].urb->transfer_buffer);
-	kfree(u->surb[0].urb->transfer_buffer);
-	kfree(u->surb[1].urb->transfer_buffer);
-	u->durb[0].urb->transfer_buffer = u->durb[1].urb->transfer_buffer = 
-		u->surb[0].urb->transfer_buffer = u->surb[1].urb->transfer_buffer = NULL;
-}
-
-static inline void usbin_release(struct usb_audiodev *as)
-{
-	usbin_stop(as);
-}
-
-static void usbin_disc(struct usb_audiodev *as)
-{
-	struct usbin *u = &as->usbin;
-
-	unsigned long flags;
-
-	spin_lock_irqsave(&as->lock, flags);
-	u->flags &= ~(FLG_RUNNING | FLG_CONNECTED);
-	spin_unlock_irqrestore(&as->lock, flags);
-	usbin_stop(as);
-}
-
-static void conversion(const void *ibuf, unsigned int ifmt, void *obuf, unsigned int ofmt, void *tmp, unsigned int scnt)
-{
-	unsigned int cnt, i;
-	__s16 *sp, *sp2, s;
-	unsigned char *bp;
-
-	cnt = scnt;
-	if (AFMT_ISSTEREO(ifmt))
-		cnt <<= 1;
-	sp = ((__s16 *)tmp) + cnt;
-	switch (ifmt & ~AFMT_STEREO) {
-	case AFMT_U8:
-		for (bp = ((unsigned char *)ibuf)+cnt, i = 0; i < cnt; i++) {
-			bp--;
-			sp--;
-			*sp = (*bp ^ 0x80) << 8;
-		}
-		break;
-			
-	case AFMT_S8:
-		for (bp = ((unsigned char *)ibuf)+cnt, i = 0; i < cnt; i++) {
-			bp--;
-			sp--;
-			*sp = *bp << 8;
-		}
-		break;
-		
-	case AFMT_U16_LE:
-		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
-			bp -= 2;
-			sp--;
-			*sp = (bp[0] | (bp[1] << 8)) ^ 0x8000;
-		}
-		break;
-
-	case AFMT_U16_BE:
-		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
-			bp -= 2;
-			sp--;
-			*sp = (bp[1] | (bp[0] << 8)) ^ 0x8000;
-		}
-		break;
-
-	case AFMT_S16_LE:
-		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
-			bp -= 2;
-			sp--;
-			*sp = bp[0] | (bp[1] << 8);
-		}
-		break;
-
-	case AFMT_S16_BE:
-		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
-			bp -= 2;
-			sp--;
-			*sp = bp[1] | (bp[0] << 8);
-		}
-		break;
-	}
-	if (!AFMT_ISSTEREO(ifmt) && AFMT_ISSTEREO(ofmt)) {
-		/* expand from mono to stereo */
-		for (sp = ((__s16 *)tmp)+scnt, sp2 = ((__s16 *)tmp)+2*scnt, i = 0; i < scnt; i++) {
-			sp--;
-			sp2 -= 2;
-			sp2[0] = sp2[1] = sp[0];
-		}
-	}
-	if (AFMT_ISSTEREO(ifmt) && !AFMT_ISSTEREO(ofmt)) {
-		/* contract from stereo to mono */
-		for (sp = sp2 = ((__s16 *)tmp), i = 0; i < scnt; i++, sp++, sp2 += 2)
-			sp[0] = (sp2[0] + sp2[1]) >> 1;
-	}
-	cnt = scnt;
-	if (AFMT_ISSTEREO(ofmt))
-		cnt <<= 1;
-	sp = ((__s16 *)tmp);
-	bp = ((unsigned char *)obuf);
-	switch (ofmt & ~AFMT_STEREO) {
-	case AFMT_U8:
-		for (i = 0; i < cnt; i++, sp++, bp++)
-			*bp = (*sp >> 8) ^ 0x80;
-		break;
-
-	case AFMT_S8:
-		for (i = 0; i < cnt; i++, sp++, bp++)
-			*bp = *sp >> 8;
-		break;
-
-	case AFMT_U16_LE:
-		for (i = 0; i < cnt; i++, sp++, bp += 2) {
-			s = *sp;
-			bp[0] = s;
-			bp[1] = (s >> 8) ^ 0x80;
-		}
-		break;
-
-	case AFMT_U16_BE:
-		for (i = 0; i < cnt; i++, sp++, bp += 2) {
-			s = *sp;
-			bp[1] = s;
-			bp[0] = (s >> 8) ^ 0x80;
-		}
-		break;
-
-	case AFMT_S16_LE:
-		for (i = 0; i < cnt; i++, sp++, bp += 2) {
-			s = *sp;
-			bp[0] = s;
-			bp[1] = s >> 8;
-		}
-		break;
-
-	case AFMT_S16_BE:
-		for (i = 0; i < cnt; i++, sp++, bp += 2) {
-			s = *sp;
-			bp[1] = s;
-			bp[0] = s >> 8;
-		}
-		break;
-	}
-	
-}
-
-static void usbin_convert(struct usbin *u, unsigned char *buffer, unsigned int samples)
-{
-	union {
-		__s16 s[64];
-		unsigned char b[0];
-	} tmp;
-	unsigned int scnt, maxs, ufmtsh, dfmtsh;
-
-	ufmtsh = AFMT_BYTESSHIFT(u->format);
-	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
-	maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64;
-	while (samples > 0) {
-		scnt = samples;
-		if (scnt > maxs)
-			scnt = maxs;
-		conversion(buffer, u->format, tmp.b, u->dma.format, tmp.b, scnt);
-		dmabuf_copyin(&u->dma, tmp.b, scnt << dfmtsh);
-		buffer += scnt << ufmtsh;
-		samples -= scnt;
-	}
-}		
-
-static int usbin_prepare_desc(struct usbin *u, struct urb *urb)
-{
-	unsigned int i, maxsize, offs;
-
-	maxsize = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
-	//printk(KERN_DEBUG "usbin_prepare_desc: maxsize %d freq 0x%x format 0x%x\n", maxsize, u->freqn, u->format);
-	for (i = offs = 0; i < DESCFRAMES; i++, offs += maxsize) {
-		urb->iso_frame_desc[i].length = maxsize;
-		urb->iso_frame_desc[i].offset = offs;
-	}
-	urb->interval = 1;
-	return 0;
-}
-
-/*
- * return value: 0 if descriptor should be restarted, -1 otherwise
- * convert sample format on the fly if necessary
- */
-static int usbin_retire_desc(struct usbin *u, struct urb *urb)
-{
-	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, dmafree;
-	unsigned char *cp;
-
-	ufmtsh = AFMT_BYTESSHIFT(u->format);
-	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
-	for (i = 0; i < DESCFRAMES; i++) {
-		cp = ((unsigned char *)urb->transfer_buffer) + urb->iso_frame_desc[i].offset;
-		if (urb->iso_frame_desc[i].status) {
-			dprintk((KERN_DEBUG "usbin_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
-			continue;
-		}
-		scnt = urb->iso_frame_desc[i].actual_length >> ufmtsh;
-		if (!scnt)
-			continue;
-		cnt = scnt << dfmtsh;
-		if (!u->dma.mapped) {
-			dmafree = u->dma.dmasize - u->dma.count;
-			if (cnt > dmafree) {
-				scnt = dmafree >> dfmtsh;
-				cnt = scnt << dfmtsh;
-				err++;
-			}
-		}
-		u->dma.count += cnt;
-		if (u->format == u->dma.format) {
-			/* we do not need format conversion */
-			dprintk((KERN_DEBUG "usbaudio: no sample format conversion\n"));
-			dmabuf_copyin(&u->dma, cp, cnt);
-		} else {
-			/* we need sampling format conversion */
-			dprintk((KERN_DEBUG "usbaudio: sample format conversion %x != %x\n", u->format, u->dma.format));
-			usbin_convert(u, cp, scnt);
-		}
-	}
-	if (err)
-		u->dma.error++;
-	if (u->dma.count >= (signed)u->dma.fragsize)
-		wake_up(&u->dma.wait);
-	return err ? -1 : 0;
-}
-
-static void usbin_completed(struct urb *urb, struct pt_regs *regs)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
-	struct usbin *u = &as->usbin;
-	unsigned long flags;
-	unsigned int mask;
-	int suret = 0;
-
-#if 0
-	printk(KERN_DEBUG "usbin_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
-#endif
-	if (urb == u->durb[0].urb)
-		mask = FLG_URB0RUNNING;
-	else if (urb == u->durb[1].urb)
-		mask = FLG_URB1RUNNING;
-	else {
-		mask = 0;
-		printk(KERN_ERR "usbin_completed: panic: unknown URB\n");
-	}
-	urb->dev = as->state->usbdev;
-	spin_lock_irqsave(&as->lock, flags);
-	if (!usbin_retire_desc(u, urb) &&
-	    u->flags & FLG_RUNNING &&
-	    !usbin_prepare_desc(u, urb) && 
-	    (suret = usb_submit_urb(urb, GFP_ATOMIC)) == 0) {
-		u->flags |= mask;
-	} else {
-		u->flags &= ~(mask | FLG_RUNNING);
-		wake_up(&u->dma.wait);
-		printk(KERN_DEBUG "usbin_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret);
-	}
-	spin_unlock_irqrestore(&as->lock, flags);
-}
-
-/*
- * we output sync data
- */
-static int usbin_sync_prepare_desc(struct usbin *u, struct urb *urb)
-{
-	unsigned char *cp = urb->transfer_buffer;
-	unsigned int i, offs;
-	
-	for (i = offs = 0; i < SYNCFRAMES; i++, offs += 3, cp += 3) {
-		urb->iso_frame_desc[i].length = 3;
-		urb->iso_frame_desc[i].offset = offs;
-		cp[0] = u->freqn;
-		cp[1] = u->freqn >> 8;
-		cp[2] = u->freqn >> 16;
-	}
-	urb->interval = 1;
-	return 0;
-}
-
-/*
- * return value: 0 if descriptor should be restarted, -1 otherwise
- */
-static int usbin_sync_retire_desc(struct usbin *u, struct urb *urb)
-{
-	unsigned int i;
-	
-	for (i = 0; i < SYNCFRAMES; i++)
-		if (urb->iso_frame_desc[0].status)
-			dprintk((KERN_DEBUG "usbin_sync_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
-	return 0;
-}
-
-static void usbin_sync_completed(struct urb *urb, struct pt_regs *regs)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
-	struct usbin *u = &as->usbin;
-	unsigned long flags;
-	unsigned int mask;
-	int suret = 0;
-
-#if 0
-	printk(KERN_DEBUG "usbin_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
-#endif
-	if (urb == u->surb[0].urb)
-		mask = FLG_SYNC0RUNNING;
-	else if (urb == u->surb[1].urb)
-		mask = FLG_SYNC1RUNNING;
-	else {
-		mask = 0;
-		printk(KERN_ERR "usbin_sync_completed: panic: unknown URB\n");
-	}
-	urb->dev = as->state->usbdev;
-	spin_lock_irqsave(&as->lock, flags);
-	if (!usbin_sync_retire_desc(u, urb) &&
-	    u->flags & FLG_RUNNING &&
-	    !usbin_sync_prepare_desc(u, urb) && 
-	    (suret = usb_submit_urb(urb, GFP_ATOMIC)) == 0) {
-		u->flags |= mask;
-	} else {
-		u->flags &= ~(mask | FLG_RUNNING);
-		wake_up(&u->dma.wait);
-		dprintk((KERN_DEBUG "usbin_sync_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret));
-	}
-	spin_unlock_irqrestore(&as->lock, flags);
-}
-
-static int usbin_start(struct usb_audiodev *as)
-{
-	struct usb_device *dev = as->state->usbdev;
-	struct usbin *u = &as->usbin;
-	struct urb *urb;
-	unsigned long flags;
-	unsigned int maxsze, bufsz;
-
-#if 0
-	printk(KERN_DEBUG "usbin_start: device %d ufmt 0x%08x dfmt 0x%08x srate %d\n",
-	       dev->devnum, u->format, u->dma.format, u->dma.srate);
-#endif
-	/* allocate USB storage if not already done */
-	spin_lock_irqsave(&as->lock, flags);
-	if (!(u->flags & FLG_CONNECTED)) {
-		spin_unlock_irqrestore(&as->lock, flags);
-		return -EIO;
-	}
-	if (!(u->flags & FLG_RUNNING)) {
-		spin_unlock_irqrestore(&as->lock, flags);
-		u->freqn = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */
-		u->freqmax = u->freqn + (u->freqn >> 2);
-		u->phase = 0;
-		maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
-		bufsz = DESCFRAMES * maxsze;
-		kfree(u->durb[0].urb->transfer_buffer);
-		u->durb[0].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-		u->durb[0].urb->transfer_buffer_length = bufsz;
-		kfree(u->durb[1].urb->transfer_buffer);
-		u->durb[1].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-		u->durb[1].urb->transfer_buffer_length = bufsz;
-		if (u->syncpipe) {
-			kfree(u->surb[0].urb->transfer_buffer);
-			u->surb[0].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-			u->surb[0].urb->transfer_buffer_length = 3*SYNCFRAMES;
-			kfree(u->surb[1].urb->transfer_buffer);
-			u->surb[1].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-			u->surb[1].urb->transfer_buffer_length = 3*SYNCFRAMES;
-		}
-		if (!u->durb[0].urb->transfer_buffer || !u->durb[1].urb->transfer_buffer || 
-		    (u->syncpipe && (!u->surb[0].urb->transfer_buffer || !u->surb[1].urb->transfer_buffer))) {
-			printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
-			return 0;
-		}
-		spin_lock_irqsave(&as->lock, flags);
-	}
-	if (u->dma.count >= u->dma.dmasize && !u->dma.mapped) {
-		spin_unlock_irqrestore(&as->lock, flags);
-		return 0;
-	}
-	u->flags |= FLG_RUNNING;
-	if (!(u->flags & FLG_URB0RUNNING)) {
-		urb = u->durb[0].urb;
-		urb->dev = dev;
-		urb->pipe = u->datapipe;
-		urb->transfer_flags = URB_ISO_ASAP;
-		urb->number_of_packets = DESCFRAMES;
-		urb->context = as;
-		urb->complete = usbin_completed;
-		if (!usbin_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
-			u->flags |= FLG_URB0RUNNING;
-		else
-			u->flags &= ~FLG_RUNNING;
-	}
-	if (u->flags & FLG_RUNNING && !(u->flags & FLG_URB1RUNNING)) {
-		urb = u->durb[1].urb;
-		urb->dev = dev;
-		urb->pipe = u->datapipe;
-		urb->transfer_flags = URB_ISO_ASAP;
-		urb->number_of_packets = DESCFRAMES;
-		urb->context = as;
-		urb->complete = usbin_completed;
-		if (!usbin_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
-			u->flags |= FLG_URB1RUNNING;
-		else
-			u->flags &= ~FLG_RUNNING;
-	}
-	if (u->syncpipe) {
-		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC0RUNNING)) {
-			urb = u->surb[0].urb;
-			urb->dev = dev;
-			urb->pipe = u->syncpipe;
-			urb->transfer_flags = URB_ISO_ASAP;
-			urb->number_of_packets = SYNCFRAMES;
-			urb->context = as;
-			urb->complete = usbin_sync_completed;
-			/* stride: u->syncinterval */
-			if (!usbin_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
-				u->flags |= FLG_SYNC0RUNNING;
-			else
-				u->flags &= ~FLG_RUNNING;
-		}
-		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC1RUNNING)) {
-			urb = u->surb[1].urb;
-			urb->dev = dev;
-			urb->pipe = u->syncpipe;
-			urb->transfer_flags = URB_ISO_ASAP;
-			urb->number_of_packets = SYNCFRAMES;
-			urb->context = as;
-			urb->complete = usbin_sync_completed;
-			/* stride: u->syncinterval */
-			if (!usbin_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
-				u->flags |= FLG_SYNC1RUNNING;
-			else
-				u->flags &= ~FLG_RUNNING;
-		}
-	}
-	spin_unlock_irqrestore(&as->lock, flags);
-	return 0;
-}
-
-static void usbout_stop(struct usb_audiodev *as)
-{
-	struct usbout *u = &as->usbout;
-	unsigned long flags;
-	unsigned int i, notkilled = 1;
-
-	spin_lock_irqsave(&as->lock, flags);
-	u->flags &= ~FLG_RUNNING;
-	i = u->flags;
-	spin_unlock_irqrestore(&as->lock, flags);
-	while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
-		if (notkilled)
-			schedule_timeout_interruptible(1);
-		else
-			schedule_timeout_uninterruptible(1);
-		spin_lock_irqsave(&as->lock, flags);
-		i = u->flags;
-		spin_unlock_irqrestore(&as->lock, flags);
-		if (notkilled && signal_pending(current)) {
-			if (i & FLG_URB0RUNNING)
-				usb_kill_urb(u->durb[0].urb);
-			if (i & FLG_URB1RUNNING)
-				usb_kill_urb(u->durb[1].urb);
-			if (i & FLG_SYNC0RUNNING)
-				usb_kill_urb(u->surb[0].urb);
-			if (i & FLG_SYNC1RUNNING)
-				usb_kill_urb(u->surb[1].urb);
-			notkilled = 0;
-		}
-	}
-	set_current_state(TASK_RUNNING);
-	kfree(u->durb[0].urb->transfer_buffer);
-	kfree(u->durb[1].urb->transfer_buffer);
-	kfree(u->surb[0].urb->transfer_buffer);
-	kfree(u->surb[1].urb->transfer_buffer);
-	u->durb[0].urb->transfer_buffer = u->durb[1].urb->transfer_buffer = 
-		u->surb[0].urb->transfer_buffer = u->surb[1].urb->transfer_buffer = NULL;
-}
-
-static inline void usbout_release(struct usb_audiodev *as)
-{
-	usbout_stop(as);
-}
-
-static void usbout_disc(struct usb_audiodev *as)
-{
-	struct usbout *u = &as->usbout;
-	unsigned long flags;
-
-	spin_lock_irqsave(&as->lock, flags);
-	u->flags &= ~(FLG_RUNNING | FLG_CONNECTED);
-	spin_unlock_irqrestore(&as->lock, flags);
-	usbout_stop(as);
-}
-
-static void usbout_convert(struct usbout *u, unsigned char *buffer, unsigned int samples)
-{
-	union {
-		__s16 s[64];
-		unsigned char b[0];
-	} tmp;
-	unsigned int scnt, maxs, ufmtsh, dfmtsh;
-
-	ufmtsh = AFMT_BYTESSHIFT(u->format);
-	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
-	maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64;
-	while (samples > 0) {
-		scnt = samples;
-		if (scnt > maxs)
-			scnt = maxs;
-		dmabuf_copyout(&u->dma, tmp.b, scnt << dfmtsh);
-		conversion(tmp.b, u->dma.format, buffer, u->format, tmp.b, scnt);
-		buffer += scnt << ufmtsh;
-		samples -= scnt;
-	}
-}		
-
-static int usbout_prepare_desc(struct usbout *u, struct urb *urb)
-{
-	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, offs;
-	unsigned char *cp = urb->transfer_buffer;
-
-	ufmtsh = AFMT_BYTESSHIFT(u->format);
-	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
-	for (i = offs = 0; i < DESCFRAMES; i++) {
-		urb->iso_frame_desc[i].offset = offs;
-		u->phase = (u->phase & 0x3fff) + u->freqm;
-		scnt = u->phase >> 14;
-		if (!scnt) {
-			urb->iso_frame_desc[i].length = 0;
-			continue;
-		}
-		cnt = scnt << dfmtsh;
-		if (!u->dma.mapped) {
-			if (cnt > u->dma.count) {
-				scnt = u->dma.count >> dfmtsh;
-				cnt = scnt << dfmtsh;
-				err++;
-			}
-			u->dma.count -= cnt;
-		} else
-			u->dma.count += cnt;
-		if (u->format == u->dma.format) {
-			/* we do not need format conversion */
-			dmabuf_copyout(&u->dma, cp, cnt);
-		} else {
-			/* we need sampling format conversion */
-			usbout_convert(u, cp, scnt);
-		}
-		cnt = scnt << ufmtsh;
-		urb->iso_frame_desc[i].length = cnt;
-		offs += cnt;
-		cp += cnt;
-	}
-	urb->interval = 1;
-	if (err)
-		u->dma.error++;
-	if (u->dma.mapped) {
-		if (u->dma.count >= (signed)u->dma.fragsize)
-			wake_up(&u->dma.wait);
-	} else {
-		if ((signed)u->dma.dmasize >= u->dma.count + (signed)u->dma.fragsize)
-			wake_up(&u->dma.wait);
-	}
-	return err ? -1 : 0;
-}
-
-/*
- * return value: 0 if descriptor should be restarted, -1 otherwise
- */
-static int usbout_retire_desc(struct usbout *u, struct urb *urb)
-{
-	unsigned int i;
-
-	for (i = 0; i < DESCFRAMES; i++) {
-		if (urb->iso_frame_desc[i].status) {
-			dprintk((KERN_DEBUG "usbout_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
-			continue;
-		}
-	}
-	return 0;
-}
-
-static void usbout_completed(struct urb *urb, struct pt_regs *regs)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
-	struct usbout *u = &as->usbout;
-	unsigned long flags;
-	unsigned int mask;
-	int suret = 0;
-
-#if 0
-	printk(KERN_DEBUG "usbout_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
-#endif
-	if (urb == u->durb[0].urb)
-		mask = FLG_URB0RUNNING;
-	else if (urb == u->durb[1].urb)
-		mask = FLG_URB1RUNNING;
-	else {
-		mask = 0;
-		printk(KERN_ERR "usbout_completed: panic: unknown URB\n");
-	}
-	urb->dev = as->state->usbdev;
-	spin_lock_irqsave(&as->lock, flags);
-	if (!usbout_retire_desc(u, urb) &&
-	    u->flags & FLG_RUNNING &&
-	    !usbout_prepare_desc(u, urb) && 
-	    (suret = usb_submit_urb(urb, GFP_ATOMIC)) == 0) {
-		u->flags |= mask;
-	} else {
-		u->flags &= ~(mask | FLG_RUNNING);
-		wake_up(&u->dma.wait);
-		dprintk((KERN_DEBUG "usbout_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret));
-	}
-	spin_unlock_irqrestore(&as->lock, flags);
-}
-
-static int usbout_sync_prepare_desc(struct usbout *u, struct urb *urb)
-{
-	unsigned int i, offs;
-
-	for (i = offs = 0; i < SYNCFRAMES; i++, offs += 3) {
-		urb->iso_frame_desc[i].length = 3;
-		urb->iso_frame_desc[i].offset = offs;
-	}
-	urb->interval = 1;
-	return 0;
-}
-
-/*
- * return value: 0 if descriptor should be restarted, -1 otherwise
- */
-static int usbout_sync_retire_desc(struct usbout *u, struct urb *urb)
-{
-	unsigned char *cp = urb->transfer_buffer;
-	unsigned int f, i;
-
-	for (i = 0; i < SYNCFRAMES; i++, cp += 3) {
-		if (urb->iso_frame_desc[i].status) {
-			dprintk((KERN_DEBUG "usbout_sync_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
-			continue;
-		}
-		if (urb->iso_frame_desc[i].actual_length < 3) {
-			dprintk((KERN_DEBUG "usbout_sync_retire_desc: frame %u length %d\n", i, urb->iso_frame_desc[i].actual_length));
-			continue;
-		}
-		f = cp[0] | (cp[1] << 8) | (cp[2] << 16);
-		if (abs(f - u->freqn) > (u->freqn >> 3) || f > u->freqmax) {
-			printk(KERN_WARNING "usbout_sync_retire_desc: requested frequency %u (nominal %u) out of range!\n", f, u->freqn);
-			continue;
-		}
-		u->freqm = f;
-	}
-	return 0;
-}
-
-static void usbout_sync_completed(struct urb *urb, struct pt_regs *regs)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
-	struct usbout *u = &as->usbout;
-	unsigned long flags;
-	unsigned int mask;
-	int suret = 0;
-
-#if 0
-	printk(KERN_DEBUG "usbout_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
-#endif
-	if (urb == u->surb[0].urb)
-		mask = FLG_SYNC0RUNNING;
-	else if (urb == u->surb[1].urb)
-		mask = FLG_SYNC1RUNNING;
-	else {
-		mask = 0;
-		printk(KERN_ERR "usbout_sync_completed: panic: unknown URB\n");
-	}
-	urb->dev = as->state->usbdev;
-	spin_lock_irqsave(&as->lock, flags);
-	if (!usbout_sync_retire_desc(u, urb) &&
-	    u->flags & FLG_RUNNING &&
-	    !usbout_sync_prepare_desc(u, urb) && 
-	    (suret = usb_submit_urb(urb, GFP_ATOMIC)) == 0) {
-		u->flags |= mask;
-	} else {
-		u->flags &= ~(mask | FLG_RUNNING);
-		wake_up(&u->dma.wait);
-		dprintk((KERN_DEBUG "usbout_sync_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret));
-	}
-	spin_unlock_irqrestore(&as->lock, flags);
-}
-
-static int usbout_start(struct usb_audiodev *as)
-{
-	struct usb_device *dev = as->state->usbdev;
-	struct usbout *u = &as->usbout;
-	struct urb *urb;
-	unsigned long flags;
-	unsigned int maxsze, bufsz;
-
-#if 0
-	printk(KERN_DEBUG "usbout_start: device %d ufmt 0x%08x dfmt 0x%08x srate %d\n",
-	       dev->devnum, u->format, u->dma.format, u->dma.srate);
-#endif
-	/* allocate USB storage if not already done */
-	spin_lock_irqsave(&as->lock, flags);
-	if (!(u->flags & FLG_CONNECTED)) {
-		spin_unlock_irqrestore(&as->lock, flags);
-		return -EIO;
-	}
-	if (!(u->flags & FLG_RUNNING)) {
-		spin_unlock_irqrestore(&as->lock, flags);
-		u->freqn = u->freqm = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */
-		u->freqmax = u->freqn + (u->freqn >> 2);
-		u->phase = 0;
-		maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
-		bufsz = DESCFRAMES * maxsze;
-		kfree(u->durb[0].urb->transfer_buffer);
-		u->durb[0].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-		u->durb[0].urb->transfer_buffer_length = bufsz;
-		kfree(u->durb[1].urb->transfer_buffer);
-		u->durb[1].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-		u->durb[1].urb->transfer_buffer_length = bufsz;
-		if (u->syncpipe) {
-			kfree(u->surb[0].urb->transfer_buffer);
-			u->surb[0].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-			u->surb[0].urb->transfer_buffer_length = 3*SYNCFRAMES;
-			kfree(u->surb[1].urb->transfer_buffer);
-			u->surb[1].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-			u->surb[1].urb->transfer_buffer_length = 3*SYNCFRAMES;
-		}
-		if (!u->durb[0].urb->transfer_buffer || !u->durb[1].urb->transfer_buffer || 
-		    (u->syncpipe && (!u->surb[0].urb->transfer_buffer || !u->surb[1].urb->transfer_buffer))) {
-			printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
-			return 0;
-		}
-		spin_lock_irqsave(&as->lock, flags);
-	}
-	if (u->dma.count <= 0 && !u->dma.mapped) {
-		spin_unlock_irqrestore(&as->lock, flags);
-		return 0;
-	}
-       	u->flags |= FLG_RUNNING;
-	if (!(u->flags & FLG_URB0RUNNING)) {
-		urb = u->durb[0].urb;
-		urb->dev = dev;
-		urb->pipe = u->datapipe;
-		urb->transfer_flags = URB_ISO_ASAP;
-		urb->number_of_packets = DESCFRAMES;
-		urb->context = as;
-		urb->complete = usbout_completed;
-		if (!usbout_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC))
-			u->flags |= FLG_URB0RUNNING;
-		else
-			u->flags &= ~FLG_RUNNING;
-	}
-	if (u->flags & FLG_RUNNING && !(u->flags & FLG_URB1RUNNING)) {
-		urb = u->durb[1].urb;
-		urb->dev = dev;
-		urb->pipe = u->datapipe;
-		urb->transfer_flags = URB_ISO_ASAP;
-		urb->number_of_packets = DESCFRAMES;
-		urb->context = as;
-		urb->complete = usbout_completed;
-		if (!usbout_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC))
-			u->flags |= FLG_URB1RUNNING;
-		else
-			u->flags &= ~FLG_RUNNING;
-	}
-	if (u->syncpipe) {
-		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC0RUNNING)) {
-			urb = u->surb[0].urb;
-			urb->dev = dev;
-			urb->pipe = u->syncpipe;
-			urb->transfer_flags = URB_ISO_ASAP;
-			urb->number_of_packets = SYNCFRAMES;
-			urb->context = as;
-			urb->complete = usbout_sync_completed;
-			/* stride: u->syncinterval */
-			if (!usbout_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC))
-				u->flags |= FLG_SYNC0RUNNING;
-			else
-				u->flags &= ~FLG_RUNNING;
-		}
-		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC1RUNNING)) {
-			urb = u->surb[1].urb;
-			urb->dev = dev;
-			urb->pipe = u->syncpipe;
-			urb->transfer_flags = URB_ISO_ASAP;
-			urb->number_of_packets = SYNCFRAMES;
-			urb->context = as;
-			urb->complete = usbout_sync_completed;
-			/* stride: u->syncinterval */
-			if (!usbout_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC))
-				u->flags |= FLG_SYNC1RUNNING;
-			else
-				u->flags &= ~FLG_RUNNING;
-		}
-	}
-	spin_unlock_irqrestore(&as->lock, flags);
-	return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static unsigned int format_goodness(struct audioformat *afp, unsigned int fmt, unsigned int srate)
-{
-	unsigned int g = 0;
-
-	if (srate < afp->sratelo)
-		g += afp->sratelo - srate;
-	if (srate > afp->sratehi)
-		g += srate - afp->sratehi;
-	if (AFMT_ISSTEREO(afp->format) && !AFMT_ISSTEREO(fmt))
-		g += 0x100000;
-	if (!AFMT_ISSTEREO(afp->format) && AFMT_ISSTEREO(fmt))
-		g += 0x400000;
-	if (AFMT_IS16BIT(afp->format) && !AFMT_IS16BIT(fmt))
-		g += 0x100000;
-	if (!AFMT_IS16BIT(afp->format) && AFMT_IS16BIT(fmt))
-		g += 0x400000;
-	return g;
-}
-
-static int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt, unsigned int srate)
-{
-	unsigned int i, g, gb = ~0;
-	int j = -1; /* default to failure */
-
-	/* find "best" format (according to format_goodness) */
-	for (i = 0; i < nr; i++) {
-		g = format_goodness(&afp[i], fmt, srate);
-		if (g >= gb) 
-			continue;
-		j = i;
-		gb = g;
-	}
-       	return j;
-}
-
-static int set_format_in(struct usb_audiodev *as)
-{
-	struct usb_device *dev = as->state->usbdev;
-	struct usb_host_interface *alts;
-	struct usb_interface *iface;
-	struct usbin *u = &as->usbin;
-	struct dmabuf *d = &u->dma;
-	struct audioformat *fmt;
-	unsigned int ep;
-	unsigned char data[3];
-	int fmtnr, ret;
-
-	iface = usb_ifnum_to_if(dev, u->interface);
-	if (!iface)
-		return 0;
-
-	fmtnr = find_format(as->fmtin, as->numfmtin, d->format, d->srate);
-	if (fmtnr < 0) {
-		printk(KERN_ERR "usbaudio: set_format_in(): failed to find desired format/speed combination.\n");
-		return -1;
-	}
-
-	fmt = as->fmtin + fmtnr;
-	alts = usb_altnum_to_altsetting(iface, fmt->altsetting);
-	u->format = fmt->format;
-	u->datapipe = usb_rcvisocpipe(dev, alts->endpoint[0].desc.bEndpointAddress & 0xf);
-	u->syncpipe = u->syncinterval = 0;
-	if ((alts->endpoint[0].desc.bmAttributes & 0x0c) == 0x08) {
-		if (alts->desc.bNumEndpoints < 2 ||
-		    alts->endpoint[1].desc.bmAttributes != 0x01 ||
-		    alts->endpoint[1].desc.bSynchAddress != 0 ||
-		    alts->endpoint[1].desc.bEndpointAddress != (alts->endpoint[0].desc.bSynchAddress & 0x7f)) {
-			printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims adaptive in "
-			       "but has invalid synch pipe; treating as asynchronous in\n",
-			       dev->devnum, u->interface, fmt->altsetting);
-		} else {
-			u->syncpipe = usb_sndisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf);
-			u->syncinterval = alts->endpoint[1].desc.bRefresh;
-		}
-	}
-	if (d->srate < fmt->sratelo)
-		d->srate = fmt->sratelo;
-	if (d->srate > fmt->sratehi)
-		d->srate = fmt->sratehi;
-	dprintk((KERN_DEBUG "usbaudio: set_format_in: usb_set_interface %u %u\n",
-			u->interface, fmt->altsetting));
-	if (usb_set_interface(dev, alts->desc.bInterfaceNumber, fmt->altsetting) < 0) {
-		printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
-		       dev->devnum, u->interface, fmt->altsetting);
-		return -1;
-	}
-	if (fmt->sratelo == fmt->sratehi)
-		return 0;
-	ep = usb_pipeendpoint(u->datapipe) | (u->datapipe & USB_DIR_IN);
-	/* if endpoint has pitch control, enable it */
-	if (fmt->attributes & 0x02) {
-		data[0] = 1;
-		if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-					   PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) {
-			printk(KERN_ERR "usbaudio: failure (error %d) to set output pitch control device %d interface %u endpoint 0x%x to %u\n",
-			       ret, dev->devnum, u->interface, ep, d->srate);
-			return -1;
-		}
-	}
-	/* if endpoint has sampling rate control, set it */
-	if (fmt->attributes & 0x01) {
-		data[0] = d->srate;
-		data[1] = d->srate >> 8;
-		data[2] = d->srate >> 16;
-		if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
-			printk(KERN_ERR "usbaudio: failure (error %d) to set input sampling frequency device %d interface %u endpoint 0x%x to %u\n",
-			       ret, dev->devnum, u->interface, ep, d->srate);
-			return -1;
-		}
-		if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
-					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
-			printk(KERN_ERR "usbaudio: failure (error %d) to get input sampling frequency device %d interface %u endpoint 0x%x\n",
-			       ret, dev->devnum, u->interface, ep);
-			return -1;
-		}
-		dprintk((KERN_DEBUG "usbaudio: set_format_in: device %d interface %d altsetting %d srate req: %u real %u\n",
-		        dev->devnum, u->interface, fmt->altsetting, d->srate, data[0] | (data[1] << 8) | (data[2] << 16)));
-		d->srate = data[0] | (data[1] << 8) | (data[2] << 16);
-	}
-	dprintk((KERN_DEBUG "usbaudio: set_format_in: USB format 0x%x, DMA format 0x%x srate %u\n", u->format, d->format, d->srate));
-	return 0;
-}
-
-static int set_format_out(struct usb_audiodev *as)
-{
-	struct usb_device *dev = as->state->usbdev;
-	struct usb_host_interface *alts;
-	struct usb_interface *iface;	
-	struct usbout *u = &as->usbout;
-	struct dmabuf *d = &u->dma;
-	struct audioformat *fmt;
-	unsigned int ep;
-	unsigned char data[3];
-	int fmtnr, ret;
-
-	iface = usb_ifnum_to_if(dev, u->interface);
-	if (!iface)
-		return 0;
-
-	fmtnr = find_format(as->fmtout, as->numfmtout, d->format, d->srate);
-	if (fmtnr < 0) {
-		printk(KERN_ERR "usbaudio: set_format_out(): failed to find desired format/speed combination.\n");
-		return -1;
-	}
-
-	fmt = as->fmtout + fmtnr;
-	u->format = fmt->format;
-	alts = usb_altnum_to_altsetting(iface, fmt->altsetting);
-	u->datapipe = usb_sndisocpipe(dev, alts->endpoint[0].desc.bEndpointAddress & 0xf);
-	u->syncpipe = u->syncinterval = 0;
-	if ((alts->endpoint[0].desc.bmAttributes & 0x0c) == 0x04) {
-#if 0
-		printk(KERN_DEBUG "bNumEndpoints 0x%02x endpoint[1].bmAttributes 0x%02x\n"
-		       KERN_DEBUG "endpoint[1].bSynchAddress 0x%02x endpoint[1].bEndpointAddress 0x%02x\n"
-		       KERN_DEBUG "endpoint[0].bSynchAddress 0x%02x\n", alts->bNumEndpoints,
-		       alts->endpoint[1].bmAttributes, alts->endpoint[1].bSynchAddress,
-		       alts->endpoint[1].bEndpointAddress, alts->endpoint[0].bSynchAddress);
-#endif
-		if (alts->desc.bNumEndpoints < 2 ||
-		    alts->endpoint[1].desc.bmAttributes != 0x01 ||
-		    alts->endpoint[1].desc.bSynchAddress != 0 ||
-		    alts->endpoint[1].desc.bEndpointAddress != (alts->endpoint[0].desc.bSynchAddress | 0x80)) {
-			printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims asynch out "
-			       "but has invalid synch pipe; treating as adaptive out\n",
-			       dev->devnum, u->interface, fmt->altsetting);
-		} else {
-			u->syncpipe = usb_rcvisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf);
-			u->syncinterval = alts->endpoint[1].desc.bRefresh;
-		}
-	}
-	if (d->srate < fmt->sratelo)
-		d->srate = fmt->sratelo;
-	if (d->srate > fmt->sratehi)
-		d->srate = fmt->sratehi;
-	dprintk((KERN_DEBUG "usbaudio: set_format_out: usb_set_interface %u %u\n",
-			u->interface, fmt->altsetting));
-	if (usb_set_interface(dev, u->interface, fmt->altsetting) < 0) {
-		printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
-		       dev->devnum, u->interface, fmt->altsetting);
-		return -1;
-	}
-	if (fmt->sratelo == fmt->sratehi)
-		return 0;
-	ep = usb_pipeendpoint(u->datapipe) | (u->datapipe & USB_DIR_IN);
-	/* if endpoint has pitch control, enable it */
-	if (fmt->attributes & 0x02) {
-		data[0] = 1;
-		if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-					   PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) {
-			printk(KERN_ERR "usbaudio: failure (error %d) to set output pitch control device %d interface %u endpoint 0x%x to %u\n",
-			       ret, dev->devnum, u->interface, ep, d->srate);
-			return -1;
-		}
-	}
-	/* if endpoint has sampling rate control, set it */
-	if (fmt->attributes & 0x01) {
-		data[0] = d->srate;
-		data[1] = d->srate >> 8;
-		data[2] = d->srate >> 16;
-		if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
-			printk(KERN_ERR "usbaudio: failure (error %d) to set output sampling frequency device %d interface %u endpoint 0x%x to %u\n",
-			       ret, dev->devnum, u->interface, ep, d->srate);
-			return -1;
-		}
-		if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
-					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) {
-			printk(KERN_ERR "usbaudio: failure (error %d) to get output sampling frequency device %d interface %u endpoint 0x%x\n",
-			       ret, dev->devnum, u->interface, ep);
-			return -1;
-		}
-		dprintk((KERN_DEBUG "usbaudio: set_format_out: device %d interface %d altsetting %d srate req: %u real %u\n",
-		        dev->devnum, u->interface, fmt->altsetting, d->srate, data[0] | (data[1] << 8) | (data[2] << 16)));
-		d->srate = data[0] | (data[1] << 8) | (data[2] << 16);
-	}
-	dprintk((KERN_DEBUG "usbaudio: set_format_out: USB format 0x%x, DMA format 0x%x srate %u\n", u->format, d->format, d->srate));
-	return 0;
-}
-
-static int set_format(struct usb_audiodev *s, unsigned int fmode, unsigned int fmt, unsigned int srate)
-{
-	int ret1 = 0, ret2 = 0;
-
-	if (!(fmode & (FMODE_READ|FMODE_WRITE)))
-		return -EINVAL;
-	if (fmode & FMODE_READ) {
-		usbin_stop(s);
-		s->usbin.dma.ready = 0;
-		if (fmt == AFMT_QUERY)
-			fmt = s->usbin.dma.format;
-		else
-			s->usbin.dma.format = fmt;
-		if (!srate)
-			srate = s->usbin.dma.srate;
-		else
-			s->usbin.dma.srate = srate;
-	}
-	if (fmode & FMODE_WRITE) {
-		usbout_stop(s);
-		s->usbout.dma.ready = 0;
-		if (fmt == AFMT_QUERY)
-			fmt = s->usbout.dma.format;
-		else
-			s->usbout.dma.format = fmt;
-		if (!srate)
-			srate = s->usbout.dma.srate;
-		else
-			s->usbout.dma.srate = srate;
-	}
-	if (fmode & FMODE_READ)
-		ret1 = set_format_in(s);
-	if (fmode & FMODE_WRITE)
-		ret2 = set_format_out(s);
-	return ret1 ? ret1 : ret2;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
-{
-	struct usb_device *dev = ms->state->usbdev;
-	unsigned char data[2];
-	struct mixerchannel *ch;
-	int v1, v2, v3;
-
-	if (mixch >= ms->numch)
-		return -1;
-	ch = &ms->ch[mixch];
-	v3 = ch->maxval - ch->minval;
-	v1 = value & 0xff;
-	v2 = (value >> 8) & 0xff;
-	if (v1 > 100)
-		v1 = 100;
-	if (v2 > 100)
-		v2 = 100;
-	if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
-		v2 = v1;
-	ch->value = v1 | (v2 << 8);
-	v1 = (v1 * v3) / 100 + ch->minval;
-	v2 = (v2 * v3) / 100 + ch->minval;
-	switch (ch->selector) {
-	case 0:  /* mixer unit request */
-		data[0] = v1;
-		data[1] = v1 >> 8;
-		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (ch->chnum << 8) | 1, ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
-			goto err;
-		if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
-			return 0;
-		data[0] = v2;
-		data[1] = v2 >> 8;
-		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
-				    ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
-			goto err;
-		return 0;
-
-		/* various feature unit controls */
-	case VOLUME_CONTROL:
-		data[0] = v1;
-		data[1] = v1 >> 8;
-		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
-			goto err;
-		if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
-			return 0;
-		data[0] = v2;
-		data[1] = v2 >> 8;
-		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 2, 1000) < 0)
-			goto err;
-		return 0;
-                
-	case BASS_CONTROL:
-	case MID_CONTROL:
-	case TREBLE_CONTROL:
-		data[0] = v1 >> 8;
-		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, 1000) < 0)
-			goto err;
-		if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
-			return 0;
-		data[0] = v2 >> 8;
-		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 1, 1000) < 0)
-			goto err;
-		return 0;
-
-	default:
-		return -1;
-	}
-	return 0;
-
- err:
-	printk(KERN_ERR "usbaudio: mixer request device %u if %u unit %u ch %u selector %u failed\n", 
-		dev->devnum, ms->iface, ch->unitid, ch->chnum, ch->selector);
-	return -1;
-}
-
-static int get_rec_src(struct usb_mixerdev *ms)
-{
-	struct usb_device *dev = ms->state->usbdev;
-	unsigned int mask = 0, retmask = 0;
-	unsigned int i, j;
-	unsigned char buf;
-	int err = 0;
-
-	for (i = 0; i < ms->numch; i++) {
-		if (!ms->ch[i].slctunitid || (mask & (1 << i)))
-			continue;
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, 1000) < 0) {
-			err = -EIO;
-			printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n", 
-			       dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff);
-			continue;
-		}
-		for (j = i; j < ms->numch; j++) {
-			if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
-				continue;
-			mask |= 1 << j;
-			if (buf == (ms->ch[j].slctunitid >> 8))
-				retmask |= 1 << ms->ch[j].osschannel;
-		}
-	}
-	if (err)
-		return -EIO;
-	return retmask;
-}
-
-static int set_rec_src(struct usb_mixerdev *ms, int srcmask)
-{
-	struct usb_device *dev = ms->state->usbdev;
-	unsigned int mask = 0, smask, bmask;
-	unsigned int i, j;
-	unsigned char buf;
-	int err = 0;
-
-	for (i = 0; i < ms->numch; i++) {
-		if (!ms->ch[i].slctunitid || (mask & (1 << i)))
-			continue;
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, 1000) < 0) {
-			err = -EIO;
-			printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n", 
-			       dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff);
-			continue;
-		}
-		/* first generate smask */
-		smask = bmask = 0;
-		for (j = i; j < ms->numch; j++) {
-			if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
-				continue;
-			smask |= 1 << ms->ch[j].osschannel;
-			if (buf == (ms->ch[j].slctunitid >> 8))
-				bmask |= 1 << ms->ch[j].osschannel;
-			mask |= 1 << j;
-		}
-		/* check for multiple set sources */
-		j = hweight32(srcmask & smask);
-		if (j == 0)
-			continue;
-		if (j > 1)
-			srcmask &= ~bmask;
-		for (j = i; j < ms->numch; j++) {
-			if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
-				continue;
-			if (!(srcmask & (1 << ms->ch[j].osschannel)))
-				continue;
-			buf = ms->ch[j].slctunitid >> 8;
-			if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    0, ms->iface | (ms->ch[j].slctunitid << 8), &buf, 1, 1000) < 0) {
-				err = -EIO;
-				printk(KERN_ERR "usbaudio: selector write request device %u if %u unit %u failed\n", 
-				       dev->devnum, ms->iface, ms->ch[j].slctunitid & 0xff);
-				continue;
-			}
-		}
-	}
-	return err ? -EIO : 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * should be called with open_sem hold, so that no new processes
- * look at the audio device to be destroyed
- */
-
-static void release(struct usb_audio_state *s)
-{
-	struct usb_audiodev *as;
-	struct usb_mixerdev *ms;
-
-	s->count--;
-	if (s->count) {
-		up(&open_sem);
-		return;
-	}
-	up(&open_sem);
-	wake_up(&open_wait);
-	while (!list_empty(&s->audiolist)) {
-		as = list_entry(s->audiolist.next, struct usb_audiodev, list);
-		list_del(&as->list);
-		usbin_release(as);
-		usbout_release(as);
-		dmabuf_release(&as->usbin.dma);
-		dmabuf_release(&as->usbout.dma);
-		usb_free_urb(as->usbin.durb[0].urb);
-		usb_free_urb(as->usbin.durb[1].urb);
-		usb_free_urb(as->usbin.surb[0].urb);
-		usb_free_urb(as->usbin.surb[1].urb);
-		usb_free_urb(as->usbout.durb[0].urb);
-		usb_free_urb(as->usbout.durb[1].urb);
-		usb_free_urb(as->usbout.surb[0].urb);
-		usb_free_urb(as->usbout.surb[1].urb);
-		kfree(as);
-	}
-	while (!list_empty(&s->mixerlist)) {
-		ms = list_entry(s->mixerlist.next, struct usb_mixerdev, list);
-		list_del(&ms->list);
-		kfree(ms);
-	}
-	kfree(s);
-}
-
-static inline int prog_dmabuf_in(struct usb_audiodev *as)
-{
-	usbin_stop(as);
-	return dmabuf_init(&as->usbin.dma);
-}
-
-static inline int prog_dmabuf_out(struct usb_audiodev *as)
-{
-	usbout_stop(as);
-	return dmabuf_init(&as->usbout.dma);
-}
-
-/* --------------------------------------------------------------------- */
-
-static int usb_audio_open_mixdev(struct inode *inode, struct file *file)
-{
-	unsigned int minor = iminor(inode);
-	struct usb_mixerdev *ms;
-	struct usb_audio_state *s;
-
-	down(&open_sem);
-	list_for_each_entry(s, &audiodevs, audiodev) {
-		list_for_each_entry(ms, &s->mixerlist, list) {
-			if (ms->dev_mixer == minor)
-				goto mixer_found;
-		}
-	}
-	up(&open_sem);
-	return -ENODEV;
-
- mixer_found:
-	if (!s->usbdev) {
-		up(&open_sem);
-		return -EIO;
-	}
-	file->private_data = ms;
-	s->count++;
-
-	up(&open_sem);
-	return nonseekable_open(inode, file);
-}
-
-static int usb_audio_release_mixdev(struct inode *inode, struct file *file)
-{
-	struct usb_mixerdev *ms = (struct usb_mixerdev *)file->private_data;
-	struct usb_audio_state *s;
-
-	lock_kernel();
-	s = ms->state;
-	down(&open_sem);
-	release(s);
-	unlock_kernel();
-	return 0;
-}
-
-static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct usb_mixerdev *ms = (struct usb_mixerdev *)file->private_data;
-	int i, j, val;
-	int __user *user_arg = (int __user *)arg;
-
-	if (!ms->state->usbdev)
-		return -ENODEV;
-  
-	if (cmd == SOUND_MIXER_INFO) {
-		mixer_info info;
-
-		memset(&info, 0, sizeof(info));
-		strncpy(info.id, "USB_AUDIO", sizeof(info.id));
-		strncpy(info.name, "USB Audio Class Driver", sizeof(info.name));
-		info.modify_counter = ms->modcnt;
-		if (copy_to_user((void __user *)arg, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == SOUND_OLD_MIXER_INFO) {
-		_old_mixer_info info;
-
-		memset(&info, 0, sizeof(info));
-		strncpy(info.id, "USB_AUDIO", sizeof(info.id));
-		strncpy(info.name, "USB Audio Class Driver", sizeof(info.name));
-		if (copy_to_user((void __user *)arg, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == OSS_GETVERSION)
-		return put_user(SOUND_VERSION, user_arg);
-	if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
-		return -EINVAL;
-	if (_IOC_DIR(cmd) == _IOC_READ) {
-		switch (_IOC_NR(cmd)) {
-		case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-			val = get_rec_src(ms);
-			if (val < 0)
-				return val;
-			return put_user(val, user_arg);
-
-		case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
-			for (val = i = 0; i < ms->numch; i++)
-				val |= 1 << ms->ch[i].osschannel;
-			return put_user(val, user_arg);
-
-		case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
-			for (val = i = 0; i < ms->numch; i++)
-				if (ms->ch[i].slctunitid)
-					val |= 1 << ms->ch[i].osschannel;
-			return put_user(val, user_arg);
-
-		case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
-			for (val = i = 0; i < ms->numch; i++)
-				if (ms->ch[i].flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))
-					val |= 1 << ms->ch[i].osschannel;
-			return put_user(val, user_arg);
-			
-		case SOUND_MIXER_CAPS:
-			return put_user(SOUND_CAP_EXCL_INPUT, user_arg);
-
-		default:
-			i = _IOC_NR(cmd);
-			if (i >= SOUND_MIXER_NRDEVICES)
-				return -EINVAL;
-			for (j = 0; j < ms->numch; j++) {
-				if (ms->ch[j].osschannel == i) {
-					return put_user(ms->ch[j].value, user_arg);
-				}
-			}
-			return -EINVAL;
-		}
-	}
-	if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) 
-		return -EINVAL;
-	ms->modcnt++;
-	switch (_IOC_NR(cmd)) {
-	case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-		if (get_user(val, user_arg))
-			return -EFAULT;
-		return set_rec_src(ms, val);
-
-	default:
-		i = _IOC_NR(cmd);
-		if (i >= SOUND_MIXER_NRDEVICES)
-			return -EINVAL;
-		for (j = 0; j < ms->numch && ms->ch[j].osschannel != i; j++);
-		if (j >= ms->numch)
-			return -EINVAL;
-		if (get_user(val, user_arg))
-			return -EFAULT;
-		if (wrmixer(ms, j, val))
-			return -EIO;
-		return put_user(ms->ch[j].value, user_arg);
-	}
-}
-
-static /*const*/ struct file_operations usb_mixer_fops = {
-	.owner =	THIS_MODULE,
-	.llseek =	no_llseek,
-	.ioctl =	usb_audio_ioctl_mixdev,
-	.open =		usb_audio_open_mixdev,
-	.release =	usb_audio_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_out(struct usb_audiodev *as, int nonblock)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	int count, tmo;
-	
-	if (as->usbout.dma.mapped || !as->usbout.dma.ready)
-		return 0;
-	usbout_start(as);
-	add_wait_queue(&as->usbout.dma.wait, &wait);
-	for (;;) {
-		__set_current_state(TASK_INTERRUPTIBLE);
-		spin_lock_irqsave(&as->lock, flags);
-		count = as->usbout.dma.count;
-		spin_unlock_irqrestore(&as->lock, flags);
-		if (count <= 0)
-			break;
-		if (signal_pending(current))
-			break;
-		if (nonblock) {
-			remove_wait_queue(&as->usbout.dma.wait, &wait);
-			set_current_state(TASK_RUNNING);
-			return -EBUSY;
-		}
-		tmo = 3 * HZ * count / as->usbout.dma.srate;
-		tmo >>= AFMT_BYTESSHIFT(as->usbout.dma.format);
-		if (!schedule_timeout(tmo + 1)) {
-			printk(KERN_DEBUG "usbaudio: dma timed out??\n");
-			break;
-		}
-	}
-	remove_wait_queue(&as->usbout.dma.wait, &wait);
-	set_current_state(TASK_RUNNING);
-	if (signal_pending(current))
-		return -ERESTARTSYS;
-	return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t usb_audio_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret = 0;
-	unsigned long flags;
-	unsigned int ptr;
-	int cnt, err;
-
-	if (as->usbin.dma.mapped)
-		return -ENXIO;
-	if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as)))
-		return ret;
-	if (!access_ok(VERIFY_WRITE, buffer, count))
-		return -EFAULT;
-	add_wait_queue(&as->usbin.dma.wait, &wait);
-	while (count > 0) {
-		spin_lock_irqsave(&as->lock, flags);
-		ptr = as->usbin.dma.rdptr;
-		cnt = as->usbin.dma.count;
-		/* set task state early to avoid wakeup races */
-		if (cnt <= 0)
-			__set_current_state(TASK_INTERRUPTIBLE);
-		spin_unlock_irqrestore(&as->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			if (usbin_start(as)) {
-				if (!ret)
-					ret = -ENODEV;
-				break;
-			}
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				break;
-			}
-			schedule();
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				break;
-			}
-			continue;
-		}
-		if ((err = dmabuf_copyout_user(&as->usbin.dma, ptr, buffer, cnt))) {
-			if (!ret)
-				ret = err;
-			break;
-		}
-		ptr += cnt;
-		if (ptr >= as->usbin.dma.dmasize)
-			ptr -= as->usbin.dma.dmasize;
-		spin_lock_irqsave(&as->lock, flags);
-		as->usbin.dma.rdptr = ptr;
-		as->usbin.dma.count -= cnt;
-		spin_unlock_irqrestore(&as->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-	}
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&as->usbin.dma.wait, &wait);
-	return ret;
-}
-
-static ssize_t usb_audio_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret = 0;
-	unsigned long flags;
-	unsigned int ptr;
-	unsigned int start_thr;
-	int cnt, err;
-
-	if (as->usbout.dma.mapped)
-		return -ENXIO;
-	if (!as->usbout.dma.ready && (ret = prog_dmabuf_out(as)))
-		return ret;
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
-	start_thr = (as->usbout.dma.srate << AFMT_BYTESSHIFT(as->usbout.dma.format)) / (1000 / (3 * DESCFRAMES));
-	add_wait_queue(&as->usbout.dma.wait, &wait);
-	while (count > 0) {
-#if 0
-		printk(KERN_DEBUG "usb_audio_write: count %u dma: count %u rdptr %u wrptr %u dmasize %u fragsize %u flags 0x%02x taskst 0x%lx\n",
-		       count, as->usbout.dma.count, as->usbout.dma.rdptr, as->usbout.dma.wrptr, as->usbout.dma.dmasize, as->usbout.dma.fragsize,
-		       as->usbout.flags, current->state);
-#endif
-		spin_lock_irqsave(&as->lock, flags);
-		if (as->usbout.dma.count < 0) {
-			as->usbout.dma.count = 0;
-			as->usbout.dma.rdptr = as->usbout.dma.wrptr;
-		}
-		ptr = as->usbout.dma.wrptr;
-		cnt = as->usbout.dma.dmasize - as->usbout.dma.count;
-		/* set task state early to avoid wakeup races */
-		if (cnt <= 0)
-			__set_current_state(TASK_INTERRUPTIBLE);
-		spin_unlock_irqrestore(&as->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			if (usbout_start(as)) {
-				if (!ret)
-					ret = -ENODEV;
-				break;
-			}
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				break;
-			}
-			schedule();
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				break;
-			}
-			continue;
-		}
-		if ((err = dmabuf_copyin_user(&as->usbout.dma, ptr, buffer, cnt))) {
-			if (!ret)
-				ret = err;
-			break;
-		}
-		ptr += cnt;
-		if (ptr >= as->usbout.dma.dmasize)
-			ptr -= as->usbout.dma.dmasize;
-		spin_lock_irqsave(&as->lock, flags);
-		as->usbout.dma.wrptr = ptr;
-		as->usbout.dma.count += cnt;
-		spin_unlock_irqrestore(&as->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		if (as->usbout.dma.count >= start_thr && usbout_start(as)) {
-			if (!ret)
-				ret = -ENODEV;
-			break;
-		}
-	}
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&as->usbout.dma.wait, &wait);
-	return ret;
-}
-
-/* Called without the kernel lock - fine */
-static unsigned int usb_audio_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
-	unsigned long flags;
-	unsigned int mask = 0;
-
-	if (file->f_mode & FMODE_WRITE) {
-		if (!as->usbout.dma.ready)
-			prog_dmabuf_out(as);
-		poll_wait(file, &as->usbout.dma.wait, wait);
-	}
-	if (file->f_mode & FMODE_READ) {
-		if (!as->usbin.dma.ready)
-			prog_dmabuf_in(as);
-		poll_wait(file, &as->usbin.dma.wait, wait);
-	}
-	spin_lock_irqsave(&as->lock, flags);
-	if (file->f_mode & FMODE_READ) {
-		if (as->usbin.dma.count >= (signed)as->usbin.dma.fragsize)
-			mask |= POLLIN | POLLRDNORM;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		if (as->usbout.dma.mapped) {
-			if (as->usbout.dma.count >= (signed)as->usbout.dma.fragsize) 
-				mask |= POLLOUT | POLLWRNORM;
-		} else {
-			if ((signed)as->usbout.dma.dmasize >= as->usbout.dma.count + (signed)as->usbout.dma.fragsize)
-				mask |= POLLOUT | POLLWRNORM;
-		}
-	}
-	spin_unlock_irqrestore(&as->lock, flags);
-	return mask;
-}
-
-static int usb_audio_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
-	struct dmabuf *db;
-	int ret = -EINVAL;
-
-	lock_kernel();
-	if (vma->vm_flags & VM_WRITE) {
-		if ((ret = prog_dmabuf_out(as)) != 0)
-			goto out;
-		db = &as->usbout.dma;
-	} else if (vma->vm_flags & VM_READ) {
-		if ((ret = prog_dmabuf_in(as)) != 0)
-			goto out;
-		db = &as->usbin.dma;
-	} else
-		goto out;
-
-	ret = -EINVAL;
-	if (vma->vm_pgoff != 0)
-		goto out;
-
-	ret = dmabuf_mmap(vma, db,  vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot);
-out:
-	unlock_kernel();
-	return ret;
-}
-
-static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
-	struct usb_audio_state *s = as->state;
-	int __user *user_arg = (int __user *)arg;
-	unsigned long flags;
-	audio_buf_info abinfo;
-	count_info cinfo;
-	int val = 0;
-	int val2, mapped, ret;
-
-	if (!s->usbdev)
-		return -EIO;
-	mapped = ((file->f_mode & FMODE_WRITE) && as->usbout.dma.mapped) ||
-		((file->f_mode & FMODE_READ) && as->usbin.dma.mapped);
-#if 0
-	if (arg)
-		get_user(val, (int *)arg);
-	printk(KERN_DEBUG "usbaudio: usb_audio_ioctl cmd=%x arg=%lx *arg=%d\n", cmd, arg, val)
-#endif
-	switch (cmd) {
-	case OSS_GETVERSION:
-		return put_user(SOUND_VERSION, user_arg);
-
-	case SNDCTL_DSP_SYNC:
-		if (file->f_mode & FMODE_WRITE)
-			return drain_out(as, 0/*file->f_flags & O_NONBLOCK*/);
-		return 0;
-
-	case SNDCTL_DSP_SETDUPLEX:
-		return 0;
-
-	case SNDCTL_DSP_GETCAPS:
-		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | 
-				DSP_CAP_MMAP | DSP_CAP_BATCH, user_arg);
-
-	case SNDCTL_DSP_RESET:
-		if (file->f_mode & FMODE_WRITE) {
-			usbout_stop(as);
-			as->usbout.dma.rdptr = as->usbout.dma.wrptr = as->usbout.dma.count = as->usbout.dma.total_bytes = 0;
-		}
-		if (file->f_mode & FMODE_READ) {
-			usbin_stop(as);
-			as->usbin.dma.rdptr = as->usbin.dma.wrptr = as->usbin.dma.count = as->usbin.dma.total_bytes = 0;
-		}
-		return 0;
-
-	case SNDCTL_DSP_SPEED:
-		if (get_user(val, user_arg))
-			return -EFAULT;
-		if (val >= 0) {
-			if (val < 4000)
-				val = 4000;
-			if (val > 100000)
-				val = 100000;
-			if (set_format(as, file->f_mode, AFMT_QUERY, val))
-				return -EIO;
-		}
-		return put_user((file->f_mode & FMODE_READ) ? 
-				as->usbin.dma.srate : as->usbout.dma.srate,
-				user_arg);
-
-	case SNDCTL_DSP_STEREO:
-		if (get_user(val, user_arg))
-			return -EFAULT;
-		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-		if (val)
-			val2 |= AFMT_STEREO;
-		else
-			val2 &= ~AFMT_STEREO;
-		if (set_format(as, file->f_mode, val2, 0))
-			return -EIO;
-		return 0;
-
-	case SNDCTL_DSP_CHANNELS:
-		if (get_user(val, user_arg))
-			return -EFAULT;
-		if (val != 0) {
-			val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-			if (val == 1)
-				val2 &= ~AFMT_STEREO;
-			else
-				val2 |= AFMT_STEREO;
-			if (set_format(as, file->f_mode, val2, 0))
-				return -EIO;
-		}
-		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-		return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, user_arg);
-
-	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-		return put_user(AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
-				AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE, user_arg);
-
-	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-		if (get_user(val, user_arg))
-			return -EFAULT;
-		if (val != AFMT_QUERY) {
-			if (hweight32(val) != 1)
-				return -EINVAL;
-			if (!(val & (AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
-				     AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE)))
-				return -EINVAL;
-			val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-			val |= val2 & AFMT_STEREO;
-			if (set_format(as, file->f_mode, val, 0))
-				return -EIO;
-		}
-		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-		return put_user(val2 & ~AFMT_STEREO, user_arg);
-
-	case SNDCTL_DSP_POST:
-		return 0;
-
-	case SNDCTL_DSP_GETTRIGGER:
-		val = 0;
-		if (file->f_mode & FMODE_READ && as->usbin.flags & FLG_RUNNING) 
-			val |= PCM_ENABLE_INPUT;
-		if (file->f_mode & FMODE_WRITE && as->usbout.flags & FLG_RUNNING) 
-			val |= PCM_ENABLE_OUTPUT;
-		return put_user(val, user_arg);
-
-	case SNDCTL_DSP_SETTRIGGER:
-		if (get_user(val, user_arg))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			if (val & PCM_ENABLE_INPUT) {
-				if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as)))
-					return ret;
-				if (usbin_start(as))
-					return -ENODEV;
-			} else
-				usbin_stop(as);
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			if (val & PCM_ENABLE_OUTPUT) {
-				if (!as->usbout.dma.ready && (ret = prog_dmabuf_out(as)))
-					return ret;
-				if (usbout_start(as))
-					return -ENODEV;
-			} else
-				usbout_stop(as);
-		}
-		return 0;
-
-	case SNDCTL_DSP_GETOSPACE:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if (!(as->usbout.flags & FLG_RUNNING) && (val = prog_dmabuf_out(as)) != 0)
-			return val;
-		spin_lock_irqsave(&as->lock, flags);
-		abinfo.fragsize = as->usbout.dma.fragsize;
-		abinfo.bytes = as->usbout.dma.dmasize - as->usbout.dma.count;
-		abinfo.fragstotal = as->usbout.dma.numfrag;
-		abinfo.fragments = abinfo.bytes >> as->usbout.dma.fragshift;      
-		spin_unlock_irqrestore(&as->lock, flags);
-		return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETISPACE:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		if (!(as->usbin.flags & FLG_RUNNING) && (val = prog_dmabuf_in(as)) != 0)
-			return val;
-		spin_lock_irqsave(&as->lock, flags);
-		abinfo.fragsize = as->usbin.dma.fragsize;
-		abinfo.bytes = as->usbin.dma.count;
-		abinfo.fragstotal = as->usbin.dma.numfrag;
-		abinfo.fragments = abinfo.bytes >> as->usbin.dma.fragshift;      
-		spin_unlock_irqrestore(&as->lock, flags);
-		return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-		
-	case SNDCTL_DSP_NONBLOCK:
-		file->f_flags |= O_NONBLOCK;
-		return 0;
-
-	case SNDCTL_DSP_GETODELAY:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		spin_lock_irqsave(&as->lock, flags);
-		val = as->usbout.dma.count;
-		spin_unlock_irqrestore(&as->lock, flags);
-		return put_user(val, user_arg);
-
-	case SNDCTL_DSP_GETIPTR:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		spin_lock_irqsave(&as->lock, flags);
-		cinfo.bytes = as->usbin.dma.total_bytes;
-		cinfo.blocks = as->usbin.dma.count >> as->usbin.dma.fragshift;
-		cinfo.ptr = as->usbin.dma.wrptr;
-		if (as->usbin.dma.mapped)
-			as->usbin.dma.count &= as->usbin.dma.fragsize-1;
-		spin_unlock_irqrestore(&as->lock, flags);
-		if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo)))
-			return -EFAULT;
-		return 0;
-
-	case SNDCTL_DSP_GETOPTR:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		spin_lock_irqsave(&as->lock, flags);
-		cinfo.bytes = as->usbout.dma.total_bytes;
-		cinfo.blocks = as->usbout.dma.count >> as->usbout.dma.fragshift;
-		cinfo.ptr = as->usbout.dma.rdptr;
-		if (as->usbout.dma.mapped)
-			as->usbout.dma.count &= as->usbout.dma.fragsize-1;
-		spin_unlock_irqrestore(&as->lock, flags);
-		if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo)))
-			return -EFAULT;
-		return 0;
-
-       case SNDCTL_DSP_GETBLKSIZE:
-		if (file->f_mode & FMODE_WRITE) {
-			if ((val = prog_dmabuf_out(as)))
-				return val;
-			return put_user(as->usbout.dma.fragsize, user_arg);
-		}
-		if ((val = prog_dmabuf_in(as)))
-			return val;
-		return put_user(as->usbin.dma.fragsize, user_arg);
-
-	case SNDCTL_DSP_SETFRAGMENT:
-		if (get_user(val, user_arg))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			as->usbin.dma.ossfragshift = val & 0xffff;
-			as->usbin.dma.ossmaxfrags = (val >> 16) & 0xffff;
-			if (as->usbin.dma.ossfragshift < 4)
-				as->usbin.dma.ossfragshift = 4;
-			if (as->usbin.dma.ossfragshift > 15)
-				as->usbin.dma.ossfragshift = 15;
-			if (as->usbin.dma.ossmaxfrags < 4)
-				as->usbin.dma.ossmaxfrags = 4;
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			as->usbout.dma.ossfragshift = val & 0xffff;
-			as->usbout.dma.ossmaxfrags = (val >> 16) & 0xffff;
-			if (as->usbout.dma.ossfragshift < 4)
-				as->usbout.dma.ossfragshift = 4;
-			if (as->usbout.dma.ossfragshift > 15)
-				as->usbout.dma.ossfragshift = 15;
-			if (as->usbout.dma.ossmaxfrags < 4)
-				as->usbout.dma.ossmaxfrags = 4;
-		}
-		return 0;
-
-	case SNDCTL_DSP_SUBDIVIDE:
-		if ((file->f_mode & FMODE_READ && as->usbin.dma.subdivision) ||
-		    (file->f_mode & FMODE_WRITE && as->usbout.dma.subdivision))
-			return -EINVAL;
-		if (get_user(val, user_arg))
-			return -EFAULT;
-		if (val != 1 && val != 2 && val != 4)
-			return -EINVAL;
-		if (file->f_mode & FMODE_READ)
-			as->usbin.dma.subdivision = val;
-		if (file->f_mode & FMODE_WRITE)
-			as->usbout.dma.subdivision = val;
-		return 0;
-
-	case SOUND_PCM_READ_RATE:
-		return put_user((file->f_mode & FMODE_READ) ? 
-				as->usbin.dma.srate : as->usbout.dma.srate,
-				user_arg);
-
-	case SOUND_PCM_READ_CHANNELS:
-		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-		return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, user_arg);
-
-	case SOUND_PCM_READ_BITS:
-		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-		return put_user(AFMT_IS16BIT(val2) ? 16 : 8, user_arg);
-
-	case SOUND_PCM_WRITE_FILTER:
-	case SNDCTL_DSP_SETSYNCRO:
-	case SOUND_PCM_READ_FILTER:
-		return -EINVAL;
-	}
-	dprintk((KERN_DEBUG "usbaudio: usb_audio_ioctl - no command found\n"));
-	return -ENOIOCTLCMD;
-}
-
-static int usb_audio_open(struct inode *inode, struct file *file)
-{
-	unsigned int minor = iminor(inode);
-	DECLARE_WAITQUEUE(wait, current);
-	struct usb_audiodev *as;
-	struct usb_audio_state *s;
-
-	for (;;) {
-		down(&open_sem);
-		list_for_each_entry(s, &audiodevs, audiodev) {
-			list_for_each_entry(as, &s->audiolist, list) {
-				if (!((as->dev_audio ^ minor) & ~0xf))
-					goto device_found;
-			}
-		}
-		up(&open_sem);
-		return -ENODEV;
-
-	device_found:
-		if (!s->usbdev) {
-			up(&open_sem);
-			return -EIO;
-		}
-		/* wait for device to become free */
-		if (!(as->open_mode & file->f_mode))
-			break;
-		if (file->f_flags & O_NONBLOCK) {
-			up(&open_sem);
-			return -EBUSY;
-		}
-		__set_current_state(TASK_INTERRUPTIBLE);
-		add_wait_queue(&open_wait, &wait);
-		up(&open_sem);
-		schedule();
-		__set_current_state(TASK_RUNNING);
-		remove_wait_queue(&open_wait, &wait);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-	}
-	if (file->f_mode & FMODE_READ)
-		as->usbin.dma.ossfragshift = as->usbin.dma.ossmaxfrags = as->usbin.dma.subdivision = 0;
-	if (file->f_mode & FMODE_WRITE)
-		as->usbout.dma.ossfragshift = as->usbout.dma.ossmaxfrags = as->usbout.dma.subdivision = 0;
-	if (set_format(as, file->f_mode, ((minor & 0xf) == SND_DEV_DSP16) ? AFMT_S16_LE : AFMT_U8 /* AFMT_ULAW */, 8000)) {
-		up(&open_sem);
-		return -EIO;
-	}
-	file->private_data = as;
-	as->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	s->count++;
-	up(&open_sem);
-	return nonseekable_open(inode, file);
-}
-
-static int usb_audio_release(struct inode *inode, struct file *file)
-{
-	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
-	struct usb_audio_state *s;
-	struct usb_device *dev;
-
-	lock_kernel();
-	s = as->state;
-	dev = s->usbdev;
-	if (file->f_mode & FMODE_WRITE)
-		drain_out(as, file->f_flags & O_NONBLOCK);
-	down(&open_sem);
-	if (file->f_mode & FMODE_WRITE) {
-		usbout_stop(as);
-		if (dev && as->usbout.interface >= 0)
-			usb_set_interface(dev, as->usbout.interface, 0);
-		dmabuf_release(&as->usbout.dma);
-		usbout_release(as);
-	}
-	if (file->f_mode & FMODE_READ) {
-		usbin_stop(as);
-		if (dev && as->usbin.interface >= 0)
-			usb_set_interface(dev, as->usbin.interface, 0);
-		dmabuf_release(&as->usbin.dma);
-		usbin_release(as);
-	}
-	as->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
-	release(s);
-	wake_up(&open_wait);
-	unlock_kernel();
-	return 0;
-}
-
-static /*const*/ struct file_operations usb_audio_fops = {
-	.owner =	THIS_MODULE,
-	.llseek =	no_llseek,
-	.read =		usb_audio_read,
-	.write =	usb_audio_write,
-	.poll =		usb_audio_poll,
-	.ioctl =	usb_audio_ioctl,
-	.mmap =		usb_audio_mmap,
-	.open =		usb_audio_open,
-	.release =	usb_audio_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int usb_audio_probe(struct usb_interface *iface,
-			   const struct usb_device_id *id);
-static void usb_audio_disconnect(struct usb_interface *iface);
-
-static struct usb_device_id usb_audio_ids [] = {
-    { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
-      .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = 1},
-    { }						/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, usb_audio_ids);
-
-static struct usb_driver usb_audio_driver = {
-	.name =		"audio",
-	.probe =	usb_audio_probe,
-	.disconnect =	usb_audio_disconnect,
-	.id_table =	usb_audio_ids,
-};
-
-static void *find_descriptor(void *descstart, unsigned int desclen, void *after, 
-			     u8 dtype, int iface, int altsetting)
-{
-	u8 *p, *end, *next;
-	int ifc = -1, as = -1;
-
-	p = descstart;
-	end = p + desclen;
-	for (; p < end;) {
-		if (p[0] < 2)
-			return NULL;
-		next = p + p[0];
-		if (next > end)
-			return NULL;
-		if (p[1] == USB_DT_INTERFACE) {
-			/* minimum length of interface descriptor */
-			if (p[0] < 9)
-				return NULL;
-			ifc = p[2];
-			as = p[3];
-		}
-		if (p[1] == dtype && (!after || (void *)p > after) &&
-		    (iface == -1 || iface == ifc) && (altsetting == -1 || altsetting == as)) {
-			return p;
-		}
-		p = next;
-	}
-	return NULL;
-}
-
-static void *find_csinterface_descriptor(void *descstart, unsigned int desclen, void *after, u8 dsubtype, int iface, int altsetting)
-{
-	unsigned char *p;
-
-	p = find_descriptor(descstart, desclen, after, USB_DT_CS_INTERFACE, iface, altsetting);
-	while (p) {
-		if (p[0] >= 3 && p[2] == dsubtype)
-			return p;
-		p = find_descriptor(descstart, desclen, p, USB_DT_CS_INTERFACE, iface, altsetting);
-	}
-	return NULL;
-}
-
-static void *find_audiocontrol_unit(void *descstart, unsigned int desclen, void *after, u8 unit, int iface)
-{
-	unsigned char *p;
-
-	p = find_descriptor(descstart, desclen, after, USB_DT_CS_INTERFACE, iface, -1);
-	while (p) {
-		if (p[0] >= 4 && p[2] >= INPUT_TERMINAL && p[2] <= EXTENSION_UNIT && p[3] == unit)
-			return p;
-		p = find_descriptor(descstart, desclen, p, USB_DT_CS_INTERFACE, iface, -1);
-	}
-	return NULL;
-}
-
-static void usb_audio_parsestreaming(struct usb_audio_state *s, unsigned char *buffer, unsigned int buflen, int asifin, int asifout)
-{
-	struct usb_device *dev = s->usbdev;
-	struct usb_audiodev *as;
-	struct usb_host_interface *alts;
-	struct usb_interface *iface;
-	struct audioformat *fp;
-	unsigned char *fmt, *csep;
-	unsigned int i, j, k, format, idx;
-
-	if (!(as = kmalloc(sizeof(struct usb_audiodev), GFP_KERNEL)))
-		return;
-	memset(as, 0, sizeof(struct usb_audiodev));
-	init_waitqueue_head(&as->usbin.dma.wait);
-	init_waitqueue_head(&as->usbout.dma.wait);
-	spin_lock_init(&as->lock);
-	as->usbin.durb[0].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL);
-	as->usbin.durb[1].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL);
-	as->usbin.surb[0].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL);
-	as->usbin.surb[1].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL);
-	as->usbout.durb[0].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL);
-	as->usbout.durb[1].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL);
-	as->usbout.surb[0].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL);
-	as->usbout.surb[1].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL);
-	if ((!as->usbin.durb[0].urb) ||
-	    (!as->usbin.durb[1].urb) ||
-	    (!as->usbin.surb[0].urb) ||
-	    (!as->usbin.surb[1].urb) ||
-	    (!as->usbout.durb[0].urb) ||
-	    (!as->usbout.durb[1].urb) ||
-	    (!as->usbout.surb[0].urb) ||
-	    (!as->usbout.surb[1].urb)) {
-		usb_free_urb(as->usbin.durb[0].urb);
-		usb_free_urb(as->usbin.durb[1].urb);
-		usb_free_urb(as->usbin.surb[0].urb);
-		usb_free_urb(as->usbin.surb[1].urb);
-		usb_free_urb(as->usbout.durb[0].urb);
-		usb_free_urb(as->usbout.durb[1].urb);
-		usb_free_urb(as->usbout.surb[0].urb);
-		usb_free_urb(as->usbout.surb[1].urb);
-		kfree(as);
-		return;
-	}
-	as->state = s;
-	as->usbin.interface = asifin;
-	as->usbout.interface = asifout;
-	/* search for input formats */
-	if (asifin >= 0) {
-		as->usbin.flags = FLG_CONNECTED;
-		iface = usb_ifnum_to_if(dev, asifin);
-		for (idx = 0; idx < iface->num_altsetting; idx++) {
-			alts = &iface->altsetting[idx];
-			i = alts->desc.bAlternateSetting;
-			if (alts->desc.bInterfaceClass != USB_CLASS_AUDIO || alts->desc.bInterfaceSubClass != 2)
-				continue;
-			if (alts->desc.bNumEndpoints < 1) {
-				if (i != 0) {  /* altsetting 0 has no endpoints (Section B.3.4.1) */
-					printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u does not have an endpoint\n", 
-					       dev->devnum, asifin, i);
-				}
-				continue;
-			}
-			if ((alts->endpoint[0].desc.bmAttributes & 0x03) != 0x01 ||
-			    !(alts->endpoint[0].desc.bEndpointAddress & 0x80)) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u first endpoint not isochronous in\n", 
-				       dev->devnum, asifin, i);
-				continue;
-			}
-			fmt = find_csinterface_descriptor(buffer, buflen, NULL, AS_GENERAL, asifin, i);
-			if (!fmt) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
-				       dev->devnum, asifin, i);
-				continue;
-			}
-			if (fmt[0] < 7 || fmt[6] != 0 || (fmt[5] != 1 && fmt[5] != 2)) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u format not supported\n", 
-				       dev->devnum, asifin, i);
-				continue;
-			}
-			format = (fmt[5] == 2) ? (AFMT_U16_LE | AFMT_U8) : (AFMT_S16_LE | AFMT_S8);
-			fmt = find_csinterface_descriptor(buffer, buflen, NULL, FORMAT_TYPE, asifin, i);
-			if (!fmt) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
-				       dev->devnum, asifin, i);
-				continue;
-			}
-			if (fmt[0] < 8+3*(fmt[7] ? fmt[7] : 2) || fmt[3] != 1) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not supported\n", 
-				       dev->devnum, asifin, i);
-				continue;
-			}
-			if (fmt[4] < 1 || fmt[4] > 2 || fmt[5] < 1 || fmt[5] > 2) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n", 
-				       dev->devnum, asifin, i, fmt[4], fmt[5]);
-				continue;
-			}
-			csep = find_descriptor(buffer, buflen, NULL, USB_DT_CS_ENDPOINT, asifin, i);
-			if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u no or invalid class specific endpoint descriptor\n", 
-				       dev->devnum, asifin, i);
-				continue;
-			}
-			if (as->numfmtin >= MAXFORMATS)
-				continue;
-			fp = &as->fmtin[as->numfmtin++];
-			if (fmt[5] == 2)
-				format &= (AFMT_U16_LE | AFMT_S16_LE);
-			else
-				format &= (AFMT_U8 | AFMT_S8);
-			if (fmt[4] == 2)
-				format |= AFMT_STEREO;
-			fp->format = format;
-			fp->altsetting = i;
-			fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);
-			printk(KERN_INFO "usbaudio: valid input sample rate %u\n", fp->sratelo);
-			for (j = fmt[7] ? (fmt[7]-1) : 1; j > 0; j--) {
-				k = fmt[8+3*j] | (fmt[9+3*j] << 8) | (fmt[10+3*j] << 16);
-				printk(KERN_INFO "usbaudio: valid input sample rate %u\n", k);
-				if (k > fp->sratehi)
-					fp->sratehi = k;
-				if (k < fp->sratelo)
-					fp->sratelo = k;
-			}
-			fp->attributes = csep[3];
-			printk(KERN_INFO "usbaudio: device %u interface %u altsetting %u: format 0x%08x sratelo %u sratehi %u attributes 0x%02x\n", 
-			       dev->devnum, asifin, i, fp->format, fp->sratelo, fp->sratehi, fp->attributes);
-		}
-	}
-	/* search for output formats */
-	if (asifout >= 0) {
-		as->usbout.flags = FLG_CONNECTED;
-		iface = usb_ifnum_to_if(dev, asifout);
-		for (idx = 0; idx < iface->num_altsetting; idx++) {
-			alts = &iface->altsetting[idx];
-			i = alts->desc.bAlternateSetting;
-			if (alts->desc.bInterfaceClass != USB_CLASS_AUDIO || alts->desc.bInterfaceSubClass != 2)
-				continue;
-			if (alts->desc.bNumEndpoints < 1) {
-				/* altsetting 0 should never have iso EPs */
-				if (i != 0)
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u does not have an endpoint\n", 
-				       dev->devnum, asifout, i);
-				continue;
-			}
-			if ((alts->endpoint[0].desc.bmAttributes & 0x03) != 0x01 ||
-			    (alts->endpoint[0].desc.bEndpointAddress & 0x80)) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u first endpoint not isochronous out\n", 
-				       dev->devnum, asifout, i);
-				continue;
-			}
-			/* See USB audio formats manual, section 2 */
-			fmt = find_csinterface_descriptor(buffer, buflen, NULL, AS_GENERAL, asifout, i);
-			if (!fmt) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
-				       dev->devnum, asifout, i);
-				continue;
-			}
-			if (fmt[0] < 7 || fmt[6] != 0 || (fmt[5] != 1 && fmt[5] != 2)) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u format not supported\n", 
-				       dev->devnum, asifout, i);
-				continue;
-			}
-			format = (fmt[5] == 2) ? (AFMT_U16_LE | AFMT_U8) : (AFMT_S16_LE | AFMT_S8);
-			/* Dallas DS4201 workaround */
-			if (le16_to_cpu(dev->descriptor.idVendor) == 0x04fa && 
-			    le16_to_cpu(dev->descriptor.idProduct) == 0x4201)
-				format = (AFMT_S16_LE | AFMT_S8);
-			fmt = find_csinterface_descriptor(buffer, buflen, NULL, FORMAT_TYPE, asifout, i);
-			if (!fmt) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
-				       dev->devnum, asifout, i);
-				continue;
-			}
-			if (fmt[0] < 8+3*(fmt[7] ? fmt[7] : 2) || fmt[3] != 1) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not supported\n", 
-				       dev->devnum, asifout, i);
-				continue;
-			}
-			if (fmt[4] < 1 || fmt[4] > 2 || fmt[5] < 1 || fmt[5] > 2) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n", 
-				       dev->devnum, asifout, i, fmt[4], fmt[5]);
-				continue;
-			}
-			csep = find_descriptor(buffer, buflen, NULL, USB_DT_CS_ENDPOINT, asifout, i);
-			if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) {
-				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u no or invalid class specific endpoint descriptor\n", 
-				       dev->devnum, asifout, i);
-				continue;
-			}
-			if (as->numfmtout >= MAXFORMATS)
-				continue;
-			fp = &as->fmtout[as->numfmtout++];
-			if (fmt[5] == 2)
-				format &= (AFMT_U16_LE | AFMT_S16_LE);
-			else
-				format &= (AFMT_U8 | AFMT_S8);
-			if (fmt[4] == 2)
-				format |= AFMT_STEREO;
-			fp->format = format;
-			fp->altsetting = i;
-			fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);
-			printk(KERN_INFO "usbaudio: valid output sample rate %u\n", fp->sratelo);
-			for (j = fmt[7] ? (fmt[7]-1) : 1; j > 0; j--) {
-				k = fmt[8+3*j] | (fmt[9+3*j] << 8) | (fmt[10+3*j] << 16);
-				printk(KERN_INFO "usbaudio: valid output sample rate %u\n", k);
-				if (k > fp->sratehi)
-					fp->sratehi = k;
-				if (k < fp->sratelo)
-					fp->sratelo = k;
-			}
-			fp->attributes = csep[3];
-			printk(KERN_INFO "usbaudio: device %u interface %u altsetting %u: format 0x%08x sratelo %u sratehi %u attributes 0x%02x\n", 
-			       dev->devnum, asifout, i, fp->format, fp->sratelo, fp->sratehi, fp->attributes);
-		}
-	}
-	if (as->numfmtin == 0 && as->numfmtout == 0) {
-		usb_free_urb(as->usbin.durb[0].urb);
-		usb_free_urb(as->usbin.durb[1].urb);
-		usb_free_urb(as->usbin.surb[0].urb);
-		usb_free_urb(as->usbin.surb[1].urb);
-		usb_free_urb(as->usbout.durb[0].urb);
-		usb_free_urb(as->usbout.durb[1].urb);
-		usb_free_urb(as->usbout.surb[0].urb);
-		usb_free_urb(as->usbout.surb[1].urb);
-		kfree(as);
-		return;
-	}
-	if ((as->dev_audio = register_sound_dsp(&usb_audio_fops, -1)) < 0) {
-		printk(KERN_ERR "usbaudio: cannot register dsp\n");
-		usb_free_urb(as->usbin.durb[0].urb);
-		usb_free_urb(as->usbin.durb[1].urb);
-		usb_free_urb(as->usbin.surb[0].urb);
-		usb_free_urb(as->usbin.surb[1].urb);
-		usb_free_urb(as->usbout.durb[0].urb);
-		usb_free_urb(as->usbout.durb[1].urb);
-		usb_free_urb(as->usbout.surb[0].urb);
-		usb_free_urb(as->usbout.surb[1].urb);
-		kfree(as);
-		return;
-	}
-	printk(KERN_INFO "usbaudio: registered dsp 14,%d\n", as->dev_audio);
-	/* everything successful */
-	list_add_tail(&as->list, &s->audiolist);
-}
-
-struct consmixstate {
-	struct usb_audio_state *s;
-	unsigned char *buffer;
-	unsigned int buflen;
-	unsigned int ctrlif;
-	struct mixerchannel mixch[SOUND_MIXER_NRDEVICES];
-	unsigned int nrmixch;
-	unsigned int mixchmask;
-	unsigned long unitbitmap[32/sizeof(unsigned long)];
-	/* return values */
-	unsigned int nrchannels;
-	unsigned int termtype;
-	unsigned int chconfig;
-};
-
-static struct mixerchannel *getmixchannel(struct consmixstate *state, unsigned int nr)
-{
-	struct mixerchannel *c;
-
-	if (nr >= SOUND_MIXER_NRDEVICES) {
-		printk(KERN_ERR "usbaudio: invalid OSS mixer channel %u\n", nr);
-		return NULL;
-	}
-	if (!(state->mixchmask & (1 << nr))) {
-		printk(KERN_WARNING "usbaudio: OSS mixer channel %u already in use\n", nr);
-		return NULL;
-	}
-	c = &state->mixch[state->nrmixch++];
-	c->osschannel = nr;
-	state->mixchmask &= ~(1 << nr);
-	return c;
-}
-
-static unsigned int getvolchannel(struct consmixstate *state)
-{
-	unsigned int u;
-
-	if ((state->termtype & 0xff00) == 0x0000 && (state->mixchmask & SOUND_MASK_VOLUME))
-		return SOUND_MIXER_VOLUME;
-	if ((state->termtype & 0xff00) == 0x0100) {
-		if (state->mixchmask & SOUND_MASK_PCM)
-			return SOUND_MIXER_PCM;
-		if (state->mixchmask & SOUND_MASK_ALTPCM)
-			return SOUND_MIXER_ALTPCM;
-	}
-	if ((state->termtype & 0xff00) == 0x0200 && (state->mixchmask & SOUND_MASK_MIC))
-		return SOUND_MIXER_MIC;
-	if ((state->termtype & 0xff00) == 0x0300 && (state->mixchmask & SOUND_MASK_SPEAKER))
-		return SOUND_MIXER_SPEAKER;
-	if ((state->termtype & 0xff00) == 0x0500) {
-		if (state->mixchmask & SOUND_MASK_PHONEIN)
-			return SOUND_MIXER_PHONEIN;
-		if (state->mixchmask & SOUND_MASK_PHONEOUT)
-			return SOUND_MIXER_PHONEOUT;
-	}
-	if (state->termtype >= 0x710 && state->termtype <= 0x711 && (state->mixchmask & SOUND_MASK_RADIO))
-		return SOUND_MIXER_RADIO;
-	if (state->termtype >= 0x709 && state->termtype <= 0x70f && (state->mixchmask & SOUND_MASK_VIDEO))
-		return SOUND_MIXER_VIDEO;
-	u = ffs(state->mixchmask & (SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | SOUND_MASK_LINE3 |
-				    SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | SOUND_MASK_DIGITAL3));
-	return u-1;
-}
-
-static void prepmixch(struct consmixstate *state)
-{
-	struct usb_device *dev = state->s->usbdev;
-	struct mixerchannel *ch;
-	unsigned char *buf;
-	__s16 v1;
-	unsigned int v2, v3;
-
-	if (!state->nrmixch || state->nrmixch > SOUND_MIXER_NRDEVICES)
-		return;
-	buf = kmalloc(sizeof(*buf) * 2, GFP_KERNEL);
-	if (!buf) {
-		printk(KERN_ERR "prepmixch: out of memory\n") ;
-		return;
-	}
-
-	ch = &state->mixch[state->nrmixch-1];
-	switch (ch->selector) {
-	case 0:  /* mixer unit request */
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-			goto err;
-		ch->minval = buf[0] | (buf[1] << 8);
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-			goto err;
-		ch->maxval = buf[0] | (buf[1] << 8);
-		v2 = ch->maxval - ch->minval;
-		if (!v2)
-			v2 = 1;
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-			goto err;
-		v1 = buf[0] | (buf[1] << 8);
-		v3 = v1 - ch->minval;
-		v3 = 100 * v3 / v2;
-		if (v3 > 100)
-			v3 = 100;
-		ch->value = v3;
-		if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
-			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-					    ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
-					    state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-			goto err;
-			v1 = buf[0] | (buf[1] << 8);
-			v3 = v1 - ch->minval;
-			v3 = 100 * v3 / v2;
-			if (v3 > 100)
-				v3 = 100;
-		}
-		ch->value |= v3 << 8;
-		break;
-
-		/* various feature unit controls */
-	case VOLUME_CONTROL:
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-			goto err;
-		ch->minval = buf[0] | (buf[1] << 8);
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-			goto err;
-		ch->maxval = buf[0] | (buf[1] << 8);
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-			goto err;
-		v1 = buf[0] | (buf[1] << 8);
-		v2 = ch->maxval - ch->minval;
-		v3 = v1 - ch->minval;
-		if (!v2)
-			v2 = 1;
-		v3 = 100 * v3 / v2;
-		if (v3 > 100)
-			v3 = 100;
-		ch->value = v3;
-		if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
-			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, 1000) < 0)
-				goto err;
-			v1 = buf[0] | (buf[1] << 8);
-			v3 = v1 - ch->minval;
-			v3 = 100 * v3 / v2;
-			if (v3 > 100)
-				v3 = 100;
-		}
-		ch->value |= v3 << 8;
-		break;
-		
-	case BASS_CONTROL:
-	case MID_CONTROL:
-	case TREBLE_CONTROL:
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
-			goto err;
-		ch->minval = buf[0] << 8;
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
-			goto err;
-		ch->maxval = buf[0] << 8;
-		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
-			goto err;
-		v1 = buf[0] << 8;
-		v2 = ch->maxval - ch->minval;
-		v3 = v1 - ch->minval;
-		if (!v2)
-			v2 = 1;
-		v3 = 100 * v3 / v2;
-		if (v3 > 100)
-			v3 = 100;
-		ch->value = v3;
-		if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
-			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, 1000) < 0)
-				goto err;
-			v1 = buf[0] << 8;
-			v3 = v1 - ch->minval;
-			v3 = 100 * v3 / v2;
-			if (v3 > 100)
-				v3 = 100;
-		}
-		ch->value |= v3 << 8;
-		break;
-		
-	default:
-		goto err;
-	}
-
- freebuf:
-	kfree(buf);
-	return;
- err:
-	printk(KERN_ERR "usbaudio: mixer request device %u if %u unit %u ch %u selector %u failed\n", 
-	       dev->devnum, state->ctrlif, ch->unitid, ch->chnum, ch->selector);
-	if (state->nrmixch)
-		state->nrmixch--;
-	goto freebuf;
-}
-
-
-static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unitid);
-
-static inline int checkmixbmap(unsigned char *bmap, unsigned char flg, unsigned int inidx, unsigned int numoch)
-{
-	unsigned int idx;
-
-	idx = inidx*numoch;
-	if (!(bmap[-(idx >> 3)] & (0x80 >> (idx & 7))))
-		return 0;
-	if (!(flg & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
-		return 1;
-	idx = (inidx+!!(flg & MIXFLG_STEREOIN))*numoch+!!(flg & MIXFLG_STEREOOUT);
-	if (!(bmap[-(idx >> 3)] & (0x80 >> (idx & 7))))
-		return 0;
-	return 1;
-}
-
-static void usb_audio_mixerunit(struct consmixstate *state, unsigned char *mixer)
-{
-	unsigned int nroutch = mixer[5+mixer[4]];
-	unsigned int chidx[SOUND_MIXER_NRDEVICES+1];
-	unsigned int termt[SOUND_MIXER_NRDEVICES];
-	unsigned char flg = (nroutch >= 2) ? MIXFLG_STEREOOUT : 0;
-	unsigned char *bmap = &mixer[9+mixer[4]];
-	unsigned int bmapsize;
-	struct mixerchannel *ch;
-	unsigned int i;
-
-	if (!mixer[4]) {
-		printk(KERN_ERR "usbaudio: unit %u invalid MIXER_UNIT descriptor\n", mixer[3]);
-		return;
-	}
-	if (mixer[4] > SOUND_MIXER_NRDEVICES) {
-		printk(KERN_ERR "usbaudio: mixer unit %u: too many input pins\n", mixer[3]);
-		return;
-	}
-	chidx[0] = 0;
-	for (i = 0; i < mixer[4]; i++) {
-		usb_audio_recurseunit(state, mixer[5+i]);
-		chidx[i+1] = chidx[i] + state->nrchannels;
-		termt[i] = state->termtype;
-	}
-	state->termtype = 0;
-	state->chconfig = mixer[6+mixer[4]] | (mixer[7+mixer[4]] << 8);
-	bmapsize = (nroutch * chidx[mixer[4]] + 7) >> 3;
-	bmap += bmapsize - 1;
-	if (mixer[0] < 10+mixer[4]+bmapsize) {
-		printk(KERN_ERR "usbaudio: unit %u invalid MIXER_UNIT descriptor (bitmap too small)\n", mixer[3]);
-		return;
-	}
-	for (i = 0; i < mixer[4]; i++) {
-		state->termtype = termt[i];
-		if (chidx[i+1]-chidx[i] >= 2) {
-			flg |= MIXFLG_STEREOIN;
-			if (checkmixbmap(bmap, flg, chidx[i], nroutch)) {
-				ch = getmixchannel(state, getvolchannel(state));
-				if (ch) {
-					ch->unitid = mixer[3];
-					ch->selector = 0;
-					ch->chnum = chidx[i]+1;
-					ch->flags = flg;
-					prepmixch(state);
-				}
-				continue;
-			}
-		}
-		flg &= ~MIXFLG_STEREOIN;
-		if (checkmixbmap(bmap, flg, chidx[i], nroutch)) {
-			ch = getmixchannel(state, getvolchannel(state));
-			if (ch) {
-				ch->unitid = mixer[3];
-				ch->selector = 0;
-				ch->chnum = chidx[i]+1;
-				ch->flags = flg;
-				prepmixch(state);
-			}
-		}
-	}	
-	state->termtype = 0;
-}
-
-static struct mixerchannel *slctsrc_findunit(struct consmixstate *state, __u8 unitid)
-{
-	unsigned int i;
-	
-	for (i = 0; i < state->nrmixch; i++)
-		if (state->mixch[i].unitid == unitid)
-			return &state->mixch[i];
-	return NULL;
-}
-
-static void usb_audio_selectorunit(struct consmixstate *state, unsigned char *selector)
-{
-	unsigned int chnum, i, mixch;
-	struct mixerchannel *mch;
-
-	if (!selector[4]) {
-		printk(KERN_ERR "usbaudio: unit %u invalid SELECTOR_UNIT descriptor\n", selector[3]);
-		return;
-	}
-	mixch = state->nrmixch;
-	usb_audio_recurseunit(state, selector[5]);
-	if (state->nrmixch != mixch) {
-		mch = &state->mixch[state->nrmixch-1];
-		mch->slctunitid = selector[3] | (1 << 8);
-	} else if ((mch = slctsrc_findunit(state, selector[5]))) {
-		mch->slctunitid = selector[3] | (1 << 8);
-	} else {
-		printk(KERN_INFO "usbaudio: selector unit %u: ignoring channel 1\n", selector[3]);
-	}
-	chnum = state->nrchannels;
-	for (i = 1; i < selector[4]; i++) {
-		mixch = state->nrmixch;
-		usb_audio_recurseunit(state, selector[5+i]);
-		if (chnum != state->nrchannels) {
-			printk(KERN_ERR "usbaudio: selector unit %u: input pins with varying channel numbers\n", selector[3]);
-			state->termtype = 0;
-			state->chconfig = 0;
-			state->nrchannels = 0;
-			return;
-		}
-		if (state->nrmixch != mixch) {
-			mch = &state->mixch[state->nrmixch-1];
-			mch->slctunitid = selector[3] | ((i + 1) << 8);
-		} else if ((mch = slctsrc_findunit(state, selector[5+i]))) {
-			mch->slctunitid = selector[3] | ((i + 1) << 8);
-		} else {
-			printk(KERN_INFO "usbaudio: selector unit %u: ignoring channel %u\n", selector[3], i+1);
-		}
-	}
-	state->termtype = 0;
-	state->chconfig = 0;
-}
-
-/* in the future we might try to handle 3D etc. effect units */
-
-static void usb_audio_processingunit(struct consmixstate *state, unsigned char *proc)
-{
-	unsigned int i;
-
-	for (i = 0; i < proc[6]; i++)
-		usb_audio_recurseunit(state, proc[7+i]);
-	state->nrchannels = proc[7+proc[6]];
-	state->termtype = 0;
-	state->chconfig = proc[8+proc[6]] | (proc[9+proc[6]] << 8);
-}
-
-
-/* See Audio Class Spec, section 4.3.2.5 */
-static void usb_audio_featureunit(struct consmixstate *state, unsigned char *ftr)
-{
-	struct mixerchannel *ch;
-	unsigned short chftr, mchftr;
-#if 0
-	struct usb_device *dev = state->s->usbdev;
-	unsigned char data[1];
-#endif
-	unsigned char nr_logical_channels, i;
-
-	usb_audio_recurseunit(state, ftr[4]);
-
-	if (ftr[5] == 0 ) {
-		printk(KERN_ERR "usbaudio: wrong controls size in feature unit %u\n",ftr[3]);
-		return;
-	}
-
-	if (state->nrchannels == 0) {
-		printk(KERN_ERR "usbaudio: feature unit %u source has no channels\n", ftr[3]);
-		return;
-	}
-	if (state->nrchannels > 2)
-		printk(KERN_WARNING "usbaudio: feature unit %u: OSS mixer interface does not support more than 2 channels\n", ftr[3]);
-
-	nr_logical_channels=(ftr[0]-7)/ftr[5]-1;
-
-	if (nr_logical_channels != state->nrchannels) {
-		printk(KERN_WARNING "usbaudio: warning: found %d of %d logical channels.\n", state->nrchannels,nr_logical_channels);
-
-		if (state->nrchannels == 1 && nr_logical_channels==0) {
-			printk(KERN_INFO "usbaudio: assuming the channel found is the master channel (got a Philips camera?). Should be fine.\n");
-		} else if (state->nrchannels == 1 && nr_logical_channels==2) {
-			printk(KERN_INFO "usbaudio: assuming that a stereo channel connected directly to a mixer is missing in search (got Labtec headset?). Should be fine.\n");
-			state->nrchannels=nr_logical_channels;
-		} else {
-			printk(KERN_WARNING "usbaudio: no idea what's going on..., contact linux-usb-devel@lists.sourceforge.net\n");
-		}
-	}
-
-	/* There is always a master channel */
-	mchftr = ftr[6];
-	/* Binary AND over logical channels if they exist */
-	if (nr_logical_channels) {
-		chftr = ftr[6+ftr[5]];
-		for (i = 2; i <= nr_logical_channels; i++)
-			chftr &= ftr[6+i*ftr[5]];
-	} else {
-		chftr = 0;
-	}
-
-	/* volume control */
-	if (chftr & 2) {
-		ch = getmixchannel(state, getvolchannel(state));
-		if (ch) {
-			ch->unitid = ftr[3];
-			ch->selector = VOLUME_CONTROL;
-			ch->chnum = 1;
-			ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0;
-			prepmixch(state);
-		}
-	} else if (mchftr & 2) {
-		ch = getmixchannel(state, getvolchannel(state));
-		if (ch) {
-			ch->unitid = ftr[3];
-			ch->selector = VOLUME_CONTROL;
-			ch->chnum = 0;
-			ch->flags = 0;
-			prepmixch(state);
-		}
-	}
-	/* bass control */
-	if (chftr & 4) {
-		ch = getmixchannel(state, SOUND_MIXER_BASS);
-		if (ch) {
-			ch->unitid = ftr[3];
-			ch->selector = BASS_CONTROL;
-			ch->chnum = 1;
-			ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0;
-			prepmixch(state);
-		}
-	} else if (mchftr & 4) {
-		ch = getmixchannel(state, SOUND_MIXER_BASS);
-		if (ch) {
-			ch->unitid = ftr[3];
-			ch->selector = BASS_CONTROL;
-			ch->chnum = 0;
-			ch->flags = 0;
-			prepmixch(state);
-		}
-	}
-	/* treble control */
-	if (chftr & 16) {
-		ch = getmixchannel(state, SOUND_MIXER_TREBLE);
-		if (ch) {
-			ch->unitid = ftr[3];
-			ch->selector = TREBLE_CONTROL;
-			ch->chnum = 1;
-			ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0;
-			prepmixch(state);
-		}
-	} else if (mchftr & 16) {
-		ch = getmixchannel(state, SOUND_MIXER_TREBLE);
-		if (ch) {
-			ch->unitid = ftr[3];
-			ch->selector = TREBLE_CONTROL;
-			ch->chnum = 0;
-			ch->flags = 0;
-			prepmixch(state);
-		}
-	}
-#if 0
-	/* if there are mute controls, unmute them */
-	/* does not seem to be necessary, and the Dallas chip does not seem to support the "all" channel (255) */
-	if ((chftr & 1) || (mchftr & 1)) {
-		printk(KERN_DEBUG "usbaudio: unmuting feature unit %u interface %u\n", ftr[3], state->ctrlif);
-		data[0] = 0;
-		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (MUTE_CONTROL << 8) | 0xff, state->ctrlif | (ftr[3] << 8), data, 1, 1000) < 0)
-			printk(KERN_WARNING "usbaudio: failure to unmute feature unit %u interface %u\n", ftr[3], state->ctrlif);
- 	}
-#endif
-}
-
-static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unitid)
-{
-	unsigned char *p1;
-	unsigned int i, j;
-
-	if (test_and_set_bit(unitid, state->unitbitmap)) {
-		printk(KERN_INFO "usbaudio: mixer path revisits unit %d\n", unitid);
-		return;
-	}
-	p1 = find_audiocontrol_unit(state->buffer, state->buflen, NULL, unitid, state->ctrlif);
-	if (!p1) {
-		printk(KERN_ERR "usbaudio: unit %d not found!\n", unitid);
-		return;
-	}
-	state->nrchannels = 0;
-	state->termtype = 0;
-	state->chconfig = 0;
-	switch (p1[2]) {
-	case INPUT_TERMINAL:
-		if (p1[0] < 12) {
-			printk(KERN_ERR "usbaudio: unit %u: invalid INPUT_TERMINAL descriptor\n", unitid);
-			return;
-		}
-		state->nrchannels = p1[7];
-		state->termtype = p1[4] | (p1[5] << 8);
-		state->chconfig = p1[8] | (p1[9] << 8);
-		return;
-
-	case MIXER_UNIT:
-		if (p1[0] < 10 || p1[0] < 10+p1[4]) {
-			printk(KERN_ERR "usbaudio: unit %u: invalid MIXER_UNIT descriptor\n", unitid);
-			return;
-		}
-		usb_audio_mixerunit(state, p1);
-		return;
-
-	case SELECTOR_UNIT:
-		if (p1[0] < 6 || p1[0] < 6+p1[4]) {
-			printk(KERN_ERR "usbaudio: unit %u: invalid SELECTOR_UNIT descriptor\n", unitid);
-			return;
-		}
-		usb_audio_selectorunit(state, p1);
-		return;
-
-	case FEATURE_UNIT: /* See USB Audio Class Spec 4.3.2.5 */
-		if (p1[0] < 7 || p1[0] < 7+p1[5]) {
-			printk(KERN_ERR "usbaudio: unit %u: invalid FEATURE_UNIT descriptor\n", unitid);
-			return;
-		}
-		usb_audio_featureunit(state, p1);
-		return;		
-
-	case PROCESSING_UNIT:
-		if (p1[0] < 13 || p1[0] < 13+p1[6] || p1[0] < 13+p1[6]+p1[11+p1[6]]) {
-			printk(KERN_ERR "usbaudio: unit %u: invalid PROCESSING_UNIT descriptor\n", unitid);
-			return;
-		}
-		usb_audio_processingunit(state, p1);
-		return;		
-
-	case EXTENSION_UNIT:
-		if (p1[0] < 13 || p1[0] < 13+p1[6] || p1[0] < 13+p1[6]+p1[11+p1[6]]) {
-			printk(KERN_ERR "usbaudio: unit %u: invalid EXTENSION_UNIT descriptor\n", unitid);
-			return;
-		}
-		for (j = i = 0; i < p1[6]; i++) {
-			usb_audio_recurseunit(state, p1[7+i]);
-			if (!i)
-				j = state->termtype;
-			else if (j != state->termtype)
-				j = 0;
-		}
-		state->nrchannels = p1[7+p1[6]];
-		state->chconfig = p1[8+p1[6]] | (p1[9+p1[6]] << 8);
-		state->termtype = j;
-		return;
-
-	default:
-		printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]);
-		return;
-	}
-}
-
-static void usb_audio_constructmixer(struct usb_audio_state *s, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif, unsigned char *oterm)
-{
-	struct usb_mixerdev *ms;
-	struct consmixstate state;
-
-	memset(&state, 0, sizeof(state));
-	state.s = s;
-	state.nrmixch = 0;
-	state.mixchmask = ~0;
-	state.buffer = buffer;
-	state.buflen = buflen;
-	state.ctrlif = ctrlif;
-	set_bit(oterm[3], state.unitbitmap);  /* mark terminal ID as visited */
-	printk(KERN_DEBUG "usbaudio: constructing mixer for Terminal %u type 0x%04x\n",
-	       oterm[3], oterm[4] | (oterm[5] << 8));
-	usb_audio_recurseunit(&state, oterm[7]);
-	if (!state.nrmixch) {
-		printk(KERN_INFO "usbaudio: no mixer controls found for Terminal %u\n", oterm[3]);
-		return;
-	}
-	if (!(ms = kmalloc(sizeof(struct usb_mixerdev)+state.nrmixch*sizeof(struct mixerchannel), GFP_KERNEL)))
-		return;
-	memset(ms, 0, sizeof(struct usb_mixerdev));
-	memcpy(&ms->ch, &state.mixch, state.nrmixch*sizeof(struct mixerchannel));
-	ms->state = s;
-	ms->iface = ctrlif;
-	ms->numch = state.nrmixch;
-	if ((ms->dev_mixer = register_sound_mixer(&usb_mixer_fops, -1)) < 0) {
-		printk(KERN_ERR "usbaudio: cannot register mixer\n");
-		kfree(ms);
-		return;
-	}
-	printk(KERN_INFO "usbaudio: registered mixer 14,%d\n", ms->dev_mixer);
-	list_add_tail(&ms->list, &s->mixerlist);
-}
-
-/* arbitrary limit, we won't check more interfaces than this */
-#define USB_MAXINTERFACES	32
-
-static struct usb_audio_state *usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif)
-{
-	struct usb_audio_state *s;
-	struct usb_interface *iface;
-	struct usb_host_interface *alt;
-	unsigned char ifin[USB_MAXINTERFACES], ifout[USB_MAXINTERFACES];
-	unsigned char *p1;
-	unsigned int i, j, k, numifin = 0, numifout = 0;
-	
-	if (!(s = kmalloc(sizeof(struct usb_audio_state), GFP_KERNEL)))
-		return NULL;
-	memset(s, 0, sizeof(struct usb_audio_state));
-	INIT_LIST_HEAD(&s->audiolist);
-	INIT_LIST_HEAD(&s->mixerlist);
-	s->usbdev = dev;
-	s->count = 1;
-
-	/* find audiocontrol interface */
-	if (!(p1 = find_csinterface_descriptor(buffer, buflen, NULL, HEADER, ctrlif, -1))) {
-		printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u no HEADER found\n",
-		       dev->devnum, ctrlif);
-		goto ret;
-	}
-	if (p1[0] < 8 + p1[7]) {
-		printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u HEADER error\n",
-		       dev->devnum, ctrlif);
-		goto ret;
-	}
-	if (!p1[7])
-		printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u has no AudioStreaming and MidiStreaming interfaces\n",
-		       dev->devnum, ctrlif);
-	for (i = 0; i < p1[7]; i++) {
-		j = p1[8+i];
-		iface = usb_ifnum_to_if(dev, j);
-		if (!iface) {
-			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u does not exist\n",
-			       dev->devnum, ctrlif, j);
-			continue;
-		}
-		if (iface->num_altsetting == 1) {
-			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has only 1 altsetting.\n", dev->devnum, ctrlif);
-			continue;
-		}
-		alt = usb_altnum_to_altsetting(iface, 0);
-		if (!alt) {
-			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no altsetting 0\n",
-			       dev->devnum, ctrlif, j);
-			continue;
-		}
-		if (alt->desc.bInterfaceClass != USB_CLASS_AUDIO) {
-			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u is not an AudioClass interface\n",
-			       dev->devnum, ctrlif, j);
-			continue;
-		}
-		if (alt->desc.bInterfaceSubClass == 3) {
-			printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u interface %u MIDIStreaming not supported\n",
-			       dev->devnum, ctrlif, j);
-			continue;
-		}
-		if (alt->desc.bInterfaceSubClass != 2) {
-			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u invalid AudioClass subtype\n",
-			       dev->devnum, ctrlif, j);
-			continue;
-		}
-		if (alt->desc.bNumEndpoints > 0) {
-			/* Check all endpoints; should they all have a bandwidth of 0 ? */
-			for (k = 0; k < alt->desc.bNumEndpoints; k++) {
-				if (le16_to_cpu(alt->endpoint[k].desc.wMaxPacketSize) > 0) {
-					printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u endpoint %d does not have 0 bandwidth at alt[0]\n", dev->devnum, ctrlif, k);
-					break;
-				}
-			}
-			if (k < alt->desc.bNumEndpoints)
-				continue;
-		}
-
-		alt = usb_altnum_to_altsetting(iface, 1);
-		if (!alt) {
-			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no altsetting 1\n",
-			       dev->devnum, ctrlif, j);
-			continue;
-		}
-		if (alt->desc.bNumEndpoints < 1) {
-			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no endpoint\n",
-			       dev->devnum, ctrlif, j);
-			continue;
-		}
-		/* note: this requires the data endpoint to be ep0 and the optional sync
-		   ep to be ep1, which seems to be the case */
-		if (alt->endpoint[0].desc.bEndpointAddress & USB_DIR_IN) {
-			if (numifin < USB_MAXINTERFACES) {
-				ifin[numifin++] = j;
-				usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1);
-			}
-		} else {
-			if (numifout < USB_MAXINTERFACES) {
-				ifout[numifout++] = j;
-				usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1);
-			}
-		}
-	}
-	printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u has %u input and %u output AudioStreaming interfaces\n",
-	       dev->devnum, ctrlif, numifin, numifout);
-	for (i = 0; i < numifin && i < numifout; i++)
-		usb_audio_parsestreaming(s, buffer, buflen, ifin[i], ifout[i]);
-	for (j = i; j < numifin; j++)
-		usb_audio_parsestreaming(s, buffer, buflen, ifin[i], -1);
-	for (j = i; j < numifout; j++)
-		usb_audio_parsestreaming(s, buffer, buflen, -1, ifout[i]);
-	/* now walk through all OUTPUT_TERMINAL descriptors to search for mixers */
-	p1 = find_csinterface_descriptor(buffer, buflen, NULL, OUTPUT_TERMINAL, ctrlif, -1);
-	while (p1) {
-		if (p1[0] >= 9)
-			usb_audio_constructmixer(s, buffer, buflen, ctrlif, p1);
-		p1 = find_csinterface_descriptor(buffer, buflen, p1, OUTPUT_TERMINAL, ctrlif, -1);
-	}
-
-ret:
-	if (list_empty(&s->audiolist) && list_empty(&s->mixerlist)) {
-		kfree(s);
-		return NULL;
-	}
-	/* everything successful */
-	down(&open_sem);
-	list_add_tail(&s->audiodev, &audiodevs);
-	up(&open_sem);
-	printk(KERN_DEBUG "usb_audio_parsecontrol: usb_audio_state at %p\n", s);
-	return s;
-}
-
-/* we only care for the currently active configuration */
-
-static int usb_audio_probe(struct usb_interface *intf,
-			   const struct usb_device_id *id)
-{
-	struct usb_device *dev = interface_to_usbdev (intf);
-	struct usb_audio_state *s;
-	unsigned char *buffer;
-	unsigned int buflen;
-
-#if 0
-	printk(KERN_DEBUG "usbaudio: Probing if %i: IC %x, ISC %x\n", ifnum,
-	       config->interface[ifnum].altsetting[0].desc.bInterfaceClass,
-	       config->interface[ifnum].altsetting[0].desc.bInterfaceSubClass);
-#endif
-
-	/*
-	 * audiocontrol interface found
-	 * find which configuration number is active
-	 */
-	buffer = dev->rawdescriptors[dev->actconfig - dev->config];
-	buflen = le16_to_cpu(dev->actconfig->desc.wTotalLength);
-	s = usb_audio_parsecontrol(dev, buffer, buflen, intf->altsetting->desc.bInterfaceNumber);
-	if (s) {
-		usb_set_intfdata (intf, s);
-		return 0;
-	}
-	return -ENODEV;
-}
-
-
-/* a revoke facility would make things simpler */
-
-static void usb_audio_disconnect(struct usb_interface *intf)
-{
-	struct usb_audio_state *s = usb_get_intfdata (intf);
-	struct usb_audiodev *as;
-	struct usb_mixerdev *ms;
-
-	if (!s)
-		return;
-
-	/* we get called with -1 for every audiostreaming interface registered */
-	if (s == (struct usb_audio_state *)-1) {
-		dprintk((KERN_DEBUG "usbaudio: note, usb_audio_disconnect called with -1\n"));
-		return;
-	}
-	if (!s->usbdev) {
-		dprintk((KERN_DEBUG "usbaudio: error,  usb_audio_disconnect already called for %p!\n", s));
-		return;
-	}
-	down(&open_sem);
-	list_del_init(&s->audiodev);
-	s->usbdev = NULL;
-	usb_set_intfdata (intf, NULL);
-
-	/* deregister all audio and mixer devices, so no new processes can open this device */
-	list_for_each_entry(as, &s->audiolist, list) {
-		usbin_disc(as);
-		usbout_disc(as);
-		wake_up(&as->usbin.dma.wait);
-		wake_up(&as->usbout.dma.wait);
-		if (as->dev_audio >= 0) {
-			unregister_sound_dsp(as->dev_audio);
-			printk(KERN_INFO "usbaudio: unregister dsp 14,%d\n", as->dev_audio);
-		}
-		as->dev_audio = -1;
-	}
-	list_for_each_entry(ms, &s->mixerlist, list) {
-		if (ms->dev_mixer >= 0) {
-			unregister_sound_mixer(ms->dev_mixer);
-			printk(KERN_INFO "usbaudio: unregister mixer 14,%d\n", ms->dev_mixer);
-		}
-		ms->dev_mixer = -1;
-	}
-	release(s);
-	wake_up(&open_wait);
-}
-
-static int __init usb_audio_init(void)
-{
-	int result = usb_register(&usb_audio_driver);
-	if (result == 0) 
-		info(DRIVER_VERSION ":" DRIVER_DESC);
-	return result;
-}
-
-
-static void __exit usb_audio_cleanup(void)
-{
-	usb_deregister(&usb_audio_driver);
-}
-
-module_init(usb_audio_init);
-module_exit(usb_audio_cleanup);
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
-

+ 0 - 110
drivers/usb/class/audio.h

@@ -1,110 +0,0 @@
-#define CS_AUDIO_UNDEFINED		0x20
-#define CS_AUDIO_DEVICE			0x21
-#define CS_AUDIO_CONFIGURATION		0x22
-#define CS_AUDIO_STRING			0x23
-#define CS_AUDIO_INTERFACE		0x24
-#define CS_AUDIO_ENDPOINT		0x25
-
-#define HEADER				0x01
-#define INPUT_TERMINAL			0x02
-#define OUTPUT_TERMINAL			0x03
-#define MIXER_UNIT			0x04
-#define SELECTOR_UNIT			0x05
-#define FEATURE_UNIT			0x06
-#define PROCESSING_UNIT			0x07
-#define EXTENSION_UNIT			0x08
-
-#define AS_GENERAL			0x01
-#define FORMAT_TYPE			0x02
-#define FORMAT_SPECIFIC			0x03
-
-#define EP_GENERAL			0x01
-
-#define MAX_CHAN			9
-#define MAX_FREQ			16
-#define MAX_IFACE			8
-#define MAX_FORMAT			8
-#define MAX_ALT				32 	/* Sorry, we need quite a few for the Philips webcams */
-
-struct usb_audio_terminal
-{	
-	u8	flags;
-	u8	assoc;
-	u16	type;			/* Mic etc */
-	u8	channels;
-	u8	source;
-	u16	chancfg;
-};
-
-struct usb_audio_format
-{
-	u8	type;
-	u8	channels;
-	u8	num_freq;
-	u8	sfz;
-	u8	bits;
-	u16	freq[MAX_FREQ];
-};
-
-struct usb_audio_interface
-{
-	u8	terminal;
-	u8	delay;
-	u16	num_formats;
-	u16	format_type;
-	u8	flags;
-	u8	idleconf;	/* Idle config */
-#define AU_IFACE_FOUND	1
-	struct  usb_audio_format format[MAX_FORMAT];
-};
-
-struct usb_audio_device
-{
-	struct list_head list;
-	u8	mixer;
-	u8	selector;
-	void	*irq_handle;
-	u8	num_channels;
-	u8	num_dsp_iface;
-	u8	channel_map[MAX_CHAN];
-	struct usb_audio_terminal terminal[MAX_CHAN];
-	struct usb_audio_interface interface[MAX_IFACE][MAX_ALT];
-};
-
-
-
-/* Audio Class specific Request Codes */
-
-#define SET_CUR    0x01
-#define GET_CUR    0x81
-#define SET_MIN    0x02
-#define GET_MIN    0x82
-#define SET_MAX    0x03
-#define GET_MAX    0x83
-#define SET_RES    0x04
-#define GET_RES    0x84
-#define SET_MEM    0x05
-#define GET_MEM    0x85
-#define GET_STAT   0xff
-
-/* Terminal Control Selectors */
-
-#define COPY_PROTECT_CONTROL       0x01
-
-/* Feature Unit Control Selectors */
-
-#define MUTE_CONTROL               0x01
-#define VOLUME_CONTROL             0x02
-#define BASS_CONTROL               0x03
-#define MID_CONTROL                0x04
-#define TREBLE_CONTROL             0x05
-#define GRAPHIC_EQUALIZER_CONTROL  0x06
-#define AUTOMATIC_GAIN_CONTROL     0x07
-#define DELAY_CONTROL              0x08
-#define BASS_BOOST_CONTROL         0x09
-#define LOUDNESS_CONTROL           0x0a
-
-/* Endpoint Control Selectors */
-
-#define SAMPLING_FREQ_CONTROL      0x01
-#define PITCH_CONTROL              0x02

+ 12 - 11
drivers/usb/class/cdc-acm.c

@@ -60,6 +60,7 @@
 #include <linux/tty_flip.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/smp_lock.h>
 #include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
 #include <linux/usb_cdc.h>
 #include <linux/usb_cdc.h>
@@ -80,7 +81,7 @@ static struct usb_driver acm_driver;
 static struct tty_driver *acm_tty_driver;
 static struct tty_driver *acm_tty_driver;
 static struct acm *acm_table[ACM_TTY_MINORS];
 static struct acm *acm_table[ACM_TTY_MINORS];
 
 
-static DECLARE_MUTEX(open_sem);
+static DEFINE_MUTEX(open_mutex);
 
 
 #define ACM_READY(acm)	(acm && acm->dev && acm->used)
 #define ACM_READY(acm)	(acm && acm->dev && acm->used)
 
 
@@ -431,8 +432,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
 	int rv = -EINVAL;
 	int rv = -EINVAL;
 	int i;
 	int i;
 	dbg("Entering acm_tty_open.\n");
 	dbg("Entering acm_tty_open.\n");
-	
-	down(&open_sem);
+
+	mutex_lock(&open_mutex);
 
 
 	acm = acm_table[tty->index];
 	acm = acm_table[tty->index];
 	if (!acm || !acm->dev)
 	if (!acm || !acm->dev)
@@ -474,14 +475,14 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
 
 
 done:
 done:
 err_out:
 err_out:
-	up(&open_sem);
+	mutex_unlock(&open_mutex);
 	return rv;
 	return rv;
 
 
 full_bailout:
 full_bailout:
 	usb_kill_urb(acm->ctrlurb);
 	usb_kill_urb(acm->ctrlurb);
 bail_out:
 bail_out:
 	acm->used--;
 	acm->used--;
-	up(&open_sem);
+	mutex_unlock(&open_mutex);
 	return -EIO;
 	return -EIO;
 }
 }
 
 
@@ -507,7 +508,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
 	if (!acm || !acm->used)
 	if (!acm || !acm->used)
 		return;
 		return;
 
 
-	down(&open_sem);
+	mutex_lock(&open_mutex);
 	if (!--acm->used) {
 	if (!--acm->used) {
 		if (acm->dev) {
 		if (acm->dev) {
 			acm_set_control(acm, acm->ctrlout = 0);
 			acm_set_control(acm, acm->ctrlout = 0);
@@ -518,7 +519,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
 		} else
 		} else
 			acm_tty_unregister(acm);
 			acm_tty_unregister(acm);
 	}
 	}
-	up(&open_sem);
+	mutex_unlock(&open_mutex);
 }
 }
 
 
 static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
 static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -1013,9 +1014,9 @@ static void acm_disconnect(struct usb_interface *intf)
 		return;
 		return;
 	}
 	}
 
 
-	down(&open_sem);
+	mutex_lock(&open_mutex);
 	if (!usb_get_intfdata(intf)) {
 	if (!usb_get_intfdata(intf)) {
-		up(&open_sem);
+		mutex_unlock(&open_mutex);
 		return;
 		return;
 	}
 	}
 	acm->dev = NULL;
 	acm->dev = NULL;
@@ -1045,11 +1046,11 @@ static void acm_disconnect(struct usb_interface *intf)
 
 
 	if (!acm->used) {
 	if (!acm->used) {
 		acm_tty_unregister(acm);
 		acm_tty_unregister(acm);
-		up(&open_sem);
+		mutex_unlock(&open_mutex);
 		return;
 		return;
 	}
 	}
 
 
-	up(&open_sem);
+	mutex_unlock(&open_mutex);
 
 
 	if (acm->tty)
 	if (acm->tty)
 		tty_hangup(acm->tty);
 		tty_hangup(acm->tty);

+ 0 - 2153
drivers/usb/class/usb-midi.c

@@ -1,2153 +0,0 @@
-/*
-  usb-midi.c  --  USB-MIDI driver
-
-  Copyright (C) 2001 
-      NAGANO Daisuke <breeze.nagano@nifty.ne.jp>
-
-  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, 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.
-
-  This driver is based on:
-    - 'Universal Serial Bus Device Class Definition for MIDI Device'
-    - linux/drivers/sound/es1371.c, linux/drivers/usb/audio.c
-    - alsa/lowlevel/pci/cs64xx.c
-    - umidi.c for NetBSD
- */
-
-/* ------------------------------------------------------------------------- */
-
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/poll.h>
-#include <linux/sound.h>
-#include <linux/init.h>
-#include <asm/semaphore.h>
-
-#include "usb-midi.h"
-
-/* ------------------------------------------------------------------------- */
-
-/* More verbose on syslog */
-#undef MIDI_DEBUG
-
-#define MIDI_IN_BUFSIZ 1024
-
-#define HAVE_SUPPORT_USB_MIDI_CLASS
-
-#undef HAVE_SUPPORT_ALSA
-
-/* ------------------------------------------------------------------------- */
-
-static int singlebyte = 0;
-module_param(singlebyte, int, 0);
-MODULE_PARM_DESC(singlebyte,"Enable sending MIDI messages with single message packet");
-
-static int maxdevices = 4;
-module_param(maxdevices, int, 0);
-MODULE_PARM_DESC(maxdevices,"Max number of allocatable MIDI device");
-
-static int uvendor     = -1;
-module_param(uvendor, int, 0);
-MODULE_PARM_DESC(uvendor, "The USB Vendor ID of a semi-compliant interface");
-
-static int uproduct    = -1;
-module_param(uproduct, int, 0);
-MODULE_PARM_DESC(uproduct, "The USB Product ID of a semi-compliant interface");
-
-static int uinterface  = -1;
-module_param(uinterface, int, 0);
-MODULE_PARM_DESC(uinterface, "The Interface number of a semi-compliant interface");
-
-static int ualt        = -1;
-module_param(ualt, int, 0);
-MODULE_PARM_DESC(ualt, "The optional alternative setting of a semi-compliant interface");
-
-static int umin        = -1;
-module_param(umin, int, 0);
-MODULE_PARM_DESC(umin, "The input endpoint of a semi-compliant interface");
-
-static int umout       = -1;
-module_param(umout, int, 0);
-MODULE_PARM_DESC(umout, "The output endpoint of a semi-compliant interface");
-
-static int ucable      = -1;
-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.
- * (unicode chars <= 255). To support Japanese, a unicode16LE-to-EUC or
- * unicode16LE-to-JIS routine is needed to wrap around usb_get_string().
- **/
-static unsigned short ulangid      = 0x0409; /** 0x0411 for Japanese **/
-module_param(ulangid, ushort, 0);
-MODULE_PARM_DESC(ulangid, "The optional preferred USB Language ID for all devices");
-
-MODULE_AUTHOR("NAGANO Daisuke <breeze.nagano@nifty.ne.jp>");
-MODULE_DESCRIPTION("USB-MIDI driver");
-MODULE_LICENSE("GPL");
-
-/* ------------------------------------------------------------------------- */
-
-/** MIDIStreaming Class-Specific Interface Descriptor Subtypes **/
-
-#define MS_DESCRIPTOR_UNDEFINED	0
-#define MS_HEADER		1
-#define MIDI_IN_JACK		2
-#define MIDI_OUT_JACK		3
-/* Spec reads: ELEMENT */
-#define ELEMENT_DESCRIPTOR   	4
-
-#define MS_HEADER_LENGTH	7
-
-/** MIDIStreaming Class-Specific Endpoint Descriptor Subtypes **/
-
-#define DESCRIPTOR_UNDEFINED	0
-/* Spec reads: MS_GENERAL */
-#define MS_GENERAL_ENDPOINT	1
-
-/** MIDIStreaming MIDI IN and OUT Jack Types **/
-
-#define JACK_TYPE_UNDEFINED	0
-/* Spec reads: EMBEDDED */
-#define EMBEDDED_JACK		1
-/* Spec reads: EXTERNAL */
-#define EXTERNAL_JACK		2
-
-
-/* structure summary
-  
-      usb_midi_state     usb_device
-       |         |
-      *|        *|       per ep
-     in_ep     out_ep
-       |         |
-      *|        *|       per cable
-      min       mout
-       |         |       (cable to device pairing magic)
-       |         |
-       usb_midi_dev      dev_id (major,minor) == file->private_data
-
-*/
-
-/* usb_midi_state: corresponds to a USB-MIDI module */
-struct usb_midi_state {
-	struct list_head   mididev;
-	
-	struct usb_device *usbdev;
-	
-	struct list_head   midiDevList;
-	struct list_head   inEndpointList;
-	struct list_head   outEndpointList;
-	
-	spinlock_t         lock;
-	
-	unsigned int       count; /* usage counter */
-};
-
-/* midi_out_endpoint: corresponds to an output endpoint */
-struct midi_out_endpoint {
-	struct list_head  list;
-	
-	struct usb_device *usbdev;
-	int                endpoint;
-	spinlock_t         lock;
-	wait_queue_head_t  wait;
-	
-	unsigned char     *buf;
-	int                bufWrPtr;
-	int                bufSize;
-	
-	struct urb       *urb;
-};
-
-/* midi_in_endpoint: corresponds to an input endpoint */
-struct midi_in_endpoint {
-	struct list_head   list;
-
-	struct usb_device *usbdev;
-	int                endpoint;
-	spinlock_t         lock;
-	wait_queue_head_t  wait;
-
-	struct usb_mididev *cables[16];	// cables open for read
-	int                 readers;	// number of cables open for read
-
-	struct urb        *urb;
-	unsigned char     *recvBuf;
-	int                recvBufSize;
-	int                urbSubmitted;	//FIXME: == readers > 0
-};
-
-/* usb_mididev: corresponds to a logical device */
-struct usb_mididev {
-	struct list_head       list;
-
-	struct usb_midi_state *midi;
-	int                    dev_midi;
-	mode_t                 open_mode;
-
-	struct {
-		struct midi_in_endpoint *ep;
-		int              cableId;
-		
-// as we are pushing data from usb_bulk_read to usb_midi_read,
-// we need a larger, cyclic buffer here.
-		unsigned char    buf[MIDI_IN_BUFSIZ];
-		int              bufRdPtr;
-		int              bufWrPtr;
-		int              bufRemains;
-	} min;
-
-	struct {
-		struct midi_out_endpoint *ep;
-		int              cableId;
-		
-		unsigned char    buf[3];
-		int              bufPtr;
-		int              bufRemains;
-		
-		int              isInExclusive;
-		unsigned char    lastEvent;
-	} mout;
-
-	int singlebyte;
-};
-
-/** Map the high nybble of MIDI voice messages to number of Message bytes.
- * High nyble ranges from 0x8 to 0xe
- */
-
-static int remains_80e0[] = {
-	3,	/** 0x8X Note Off **/
-	3,	/** 0x9X Note On **/
-	3,	/** 0xAX Poly-key pressure **/
-	3,	/** 0xBX Control Change **/
-	2,	/** 0xCX Program Change **/
-	2,	/** 0xDX Channel pressure **/
-	3 	/** 0xEX PitchBend Change **/
-};
-
-/** Map the messages to a number of Message bytes.
- *
- **/
-static int remains_f0f6[] = {
-	0,	/** 0xF0 **/
-	2,	/** 0XF1 **/
-	3,	/** 0XF2 **/
-	2,	/** 0XF3 **/
-	2,	/** 0XF4 (Undefined by MIDI Spec, and subject to change) **/
-	2,	/** 0XF5 (Undefined by MIDI Spec, and subject to change) **/
-	1	/** 0XF6 **/
-};
-
-/** Map the messages to a CIN (Code Index Number).
- *
- **/
-static int cin_f0ff[] = {
-	4,	/** 0xF0 System Exclusive Message Start (special cases may be 6 or 7) */
-	2,	/** 0xF1 **/
-	3,	/** 0xF2 **/
-	2,	/** 0xF3 **/
-	2,	/** 0xF4 **/
-	2,	/** 0xF5 **/
-	5,	/** 0xF6 **/
-	5,	/** 0xF7 End of System Exclusive Message (May be 6 or 7) **/
-	5,	/** 0xF8 **/
-	5,	/** 0xF9 **/
-	5,	/** 0xFA **/
-	5,	/** 0xFB **/
-	5,	/** 0xFC **/
-	5,	/** 0xFD **/
-	5,	/** 0xFE **/
-	5	/** 0xFF **/
-};
-
-/** Map MIDIStreaming Event packet Code Index Number (low nybble of byte 0)
- * to the number of bytes of valid MIDI data.
- *
- * CIN of 0 and 1 are NOT USED in MIDIStreaming 1.0.
- *
- **/
-static int cin_to_len[] = {
-	0, 0, 2, 3,
-	3, 1, 2, 3,
-	3, 3, 3, 3,
-	2, 2, 3, 1
-};
-
-
-/* ------------------------------------------------------------------------- */
-
-static struct list_head mididevs = LIST_HEAD_INIT(mididevs);
-
-static DECLARE_MUTEX(open_sem);
-static DECLARE_WAIT_QUEUE_HEAD(open_wait);
-
-
-/* ------------------------------------------------------------------------- */
-
-static void usb_write_callback(struct urb *urb, struct pt_regs *regs)
-{
-	struct midi_out_endpoint *ep = (struct midi_out_endpoint *)urb->context;
-
-	if ( waitqueue_active( &ep->wait ) )
-		wake_up_interruptible( &ep->wait );
-}
-
-
-static int usb_write( struct midi_out_endpoint *ep, unsigned char *buf, int len )
-{
-	struct usb_device *d;
-	int pipe;
-	int ret = 0;
-	int status;
-	int maxretry = 50;
-	
-	DECLARE_WAITQUEUE(wait,current);
-	init_waitqueue_head(&ep->wait);
-
-	d = ep->usbdev;
-	pipe = usb_sndbulkpipe(d, ep->endpoint);
-	usb_fill_bulk_urb( ep->urb, d, pipe, (unsigned char*)buf, len,
-		       usb_write_callback, ep );
-
-	status = usb_submit_urb(ep->urb, GFP_KERNEL);
-    
-	if (status) {
-		printk(KERN_ERR "usbmidi: Cannot submit urb (%d)\n",status);
-		ret = -EIO;
-		goto error;
-	}
-
-	add_wait_queue( &ep->wait, &wait );
-	set_current_state( TASK_INTERRUPTIBLE );
-
-	while( ep->urb->status == -EINPROGRESS ) {
-		if ( maxretry-- < 0 ) {
-			printk(KERN_ERR "usbmidi: usb_bulk_msg timed out\n");
-			ret = -ETIME;
-			break;
-		}
-		interruptible_sleep_on_timeout( &ep->wait, 10 );
-	}
-	set_current_state( TASK_RUNNING );
-	remove_wait_queue( &ep->wait, &wait );
-
-error:
-	return ret;
-}
-
-
-/** Copy data from URB to In endpoint buf.
- * Discard if CIN == 0 or CIN = 1.
- *
- *
- **/
-
-static void usb_bulk_read(struct urb *urb, struct pt_regs *regs)
-{
-	struct midi_in_endpoint *ep = (struct midi_in_endpoint *)(urb->context);
-	unsigned char *data = urb->transfer_buffer;
-	int i, j, wake;
-
-	if ( !ep->urbSubmitted ) {
-		return;
-	}
-
-	if ( (urb->status == 0) && (urb->actual_length > 0) ) {
-		wake = 0;
-		spin_lock( &ep->lock );
-
-		for(j = 0; j < urb->actual_length; j += 4) {
-			int cin = (data[j]>>0)&0xf;
-			int cab = (data[j]>>4)&0xf;
-			struct usb_mididev *cable = ep->cables[cab];
-			if ( cable ) {
-				int len = cin_to_len[cin]; /** length of MIDI data **/
-				for (i = 0; i < len; i++) {
-					cable->min.buf[cable->min.bufWrPtr] = data[1+i+j];
-					cable->min.bufWrPtr = (cable->min.bufWrPtr+1)%MIDI_IN_BUFSIZ;
-					if (cable->min.bufRemains < MIDI_IN_BUFSIZ)
-						cable->min.bufRemains += 1;
-					else /** need to drop data **/
-						cable->min.bufRdPtr += (cable->min.bufRdPtr+1)%MIDI_IN_BUFSIZ;
-					wake = 1;
-				}
-			}
-		}
-
-		spin_unlock ( &ep->lock );
-		if ( wake ) {
-			wake_up( &ep->wait );
-		}
-	}
-
-	/* urb->dev must be reinitialized on 2.4.x kernels */
-	urb->dev = ep->usbdev;
-
-	urb->actual_length = 0;
-	usb_submit_urb(urb, GFP_ATOMIC);
-}
-
-
-
-/* ------------------------------------------------------------------------- */
-
-/* This routine must be called with spin_lock */
-
-/** Wrapper around usb_write().
- *  This routine must be called with spin_lock held on ep.
- *  Called by midiWrite(), putOneMidiEvent(), and  usb_midi_write();
- **/
-static int flush_midi_buffer( struct midi_out_endpoint *ep )
-{
-	int ret=0;
-
-	if ( ep->bufWrPtr > 0 ) {
-		ret = usb_write( ep, ep->buf, ep->bufWrPtr );
-		ep->bufWrPtr = 0;
-	}
-
-	return ret;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-
-/** Given a MIDI Event, determine size of data to be attached to 
- * USB-MIDI packet.
- * Returns 1, 2 or 3.
- * Called by midiWrite();
- * Uses remains_80e0 and remains_f0f6;
- **/
-static int get_remains(int event)
-{
-	int ret;
-
-	if ( event  < 0x80 ) {
-		ret = 1;
-	} else if ( event < 0xf0 ) {
-		ret = remains_80e0[((event-0x80)>>4)&0x0f];
-	} else if ( event < 0xf7 ) {
-		ret = remains_f0f6[event-0xf0];
-	} else {
-		ret = 1;
-	}
-
-	return ret;
-}
-
-/** Given the output MIDI data in the output buffer, computes a reasonable 
- * CIN.
- * Called by putOneMidiEvent().
- **/
-static int get_CIN( struct usb_mididev *m )
-{
-	int cin;
-
-	if ( m->mout.buf[0] == 0xf7 ) {
-		cin = 5;
-	}
-	else if ( m->mout.buf[1] == 0xf7 ) {
-		cin = 6;
-	}
-	else if ( m->mout.buf[2] == 0xf7 ) {
-		cin = 7;
-	}
-	else {
-		if ( m->mout.isInExclusive == 1 ) {
-			cin = 4;
-		} else if ( m->mout.buf[0] < 0x80 ) {
-			/** One byte that we know nothing about. **/
-			cin = 0xF; 
-		} else if ( m->mout.buf[0] < 0xf0 ) {
-			/** MIDI Voice messages 0x8X to 0xEX map to cin 0x8 to 0xE. **/
-			cin = (m->mout.buf[0]>>4)&0x0f; 
-		}
-		else {
-			/** Special lookup table exists for real-time events. **/
-			cin = cin_f0ff[m->mout.buf[0]-0xf0];
-		}
-	}
-
-	return cin;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-
-
-/** Move data to USB endpoint buffer.
- *
- **/
-static int put_one_midi_event(struct usb_mididev *m)
-{
-	int cin;
-	unsigned long flags;
-	struct midi_out_endpoint *ep = m->mout.ep;
-	int ret=0;
-
-	cin = get_CIN( m );
-	if ( cin > 0x0f || cin < 0 ) {
-		return -EINVAL;
-	}
-
-	spin_lock_irqsave( &ep->lock, flags );
-	ep->buf[ep->bufWrPtr++] = (m->mout.cableId<<4) | cin;
-	ep->buf[ep->bufWrPtr++] = m->mout.buf[0];
-	ep->buf[ep->bufWrPtr++] = m->mout.buf[1];
-	ep->buf[ep->bufWrPtr++] = m->mout.buf[2];
-	if ( ep->bufWrPtr >= ep->bufSize ) {
-		ret = flush_midi_buffer( ep );
-	}
-	spin_unlock_irqrestore( &ep->lock, flags);
-
-	m->mout.buf[0] = m->mout.buf[1] = m->mout.buf[2] = 0;
-	m->mout.bufPtr = 0;
-
-	return ret;
-}
-
-/** Write the MIDI message v on the midi device.
- *  Called by usb_midi_write();
- *  Responsible for packaging a MIDI data stream into USB-MIDI packets.
- **/
-
-static int midi_write( struct usb_mididev *m, int v )
-{
-	unsigned long flags;
-	struct midi_out_endpoint *ep = m->mout.ep;
-	int ret=0;
-	unsigned char c = (unsigned char)v;
-	unsigned char sysrt_buf[4];
-
-	if ( m->singlebyte != 0 ) {
-		/** Simple code to handle the single-byte USB-MIDI protocol. */
-		spin_lock_irqsave( &ep->lock, flags );
-		if ( ep->bufWrPtr+4 > ep->bufSize ) {
-			ret = flush_midi_buffer( ep );
-			if ( !ret ) {
-				spin_unlock_irqrestore( &ep->lock, flags );
-				return ret;
-			}
-		}
-		ep->buf[ep->bufWrPtr++] = (m->mout.cableId<<4) |  0x0f; /* single byte */
-		ep->buf[ep->bufWrPtr++] = c;
-		ep->buf[ep->bufWrPtr++] = 0;
-		ep->buf[ep->bufWrPtr++] = 0;
-		if ( ep->bufWrPtr >= ep->bufSize ) {
-			ret = flush_midi_buffer( ep );
-		}
-		spin_unlock_irqrestore( &ep->lock, flags );
-
-		return ret;
-	}
-	/** Normal USB-MIDI protocol begins here. */
-
-	if ( c > 0xf7 ) {	/* system: Realtime messages */
-		/** Realtime messages are written IMMEDIATELY. */
-		sysrt_buf[0] = (m->mout.cableId<<4) | 0x0f;
-		sysrt_buf[1] = c;
-		sysrt_buf[2] = 0;
-		sysrt_buf[3] = 0;
-		spin_lock_irqsave( &ep->lock, flags );
-		ret = usb_write( ep, sysrt_buf, 4 );
-		spin_unlock_irqrestore( &ep->lock, flags );
-		/* m->mout.lastEvent = 0; */
-
-		return ret;
-	}
-
-	if ( c >= 0x80 ) {
-		if ( c < 0xf0 ) {
-			m->mout.lastEvent = c;
-			m->mout.isInExclusive = 0;
-			m->mout.bufRemains = get_remains(c);
-		} else if ( c == 0xf0 ) {
-			/* m->mout.lastEvent = 0; */
-			m->mout.isInExclusive = 1;
-			m->mout.bufRemains = get_remains(c);
-		} else if ( c == 0xf7 && m->mout.isInExclusive == 1 ) {
-			/* m->mout.lastEvent = 0; */
-			m->mout.isInExclusive = 0;
-			m->mout.bufRemains = 1;
-		} else if ( c > 0xf0 ) {
-			/* m->mout.lastEvent = 0; */
-			m->mout.isInExclusive = 0;
-			m->mout.bufRemains = get_remains(c);
-		}
-    
-	} else if ( m->mout.bufRemains == 0 && m->mout.isInExclusive == 0 ) {
-		if ( m->mout.lastEvent == 0 ) {
-			return 0; /* discard, waiting for the first event */
-		}
-		/** track status **/
-		m->mout.buf[0] = m->mout.lastEvent;
-		m->mout.bufPtr = 1;
-		m->mout.bufRemains = get_remains(m->mout.lastEvent)-1;
-	}
-  
-	m->mout.buf[m->mout.bufPtr++] = c;
-	m->mout.bufRemains--;
-	if ( m->mout.bufRemains == 0 || m->mout.bufPtr >= 3) {
-		ret = put_one_midi_event(m);
-	}
-
-	return ret;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-/** Basic operation on /dev/midiXX as registered through struct file_operations.
- *
- *  Basic contract: Used to change the current read/write position in a file.
- *  On success, the non-negative position is reported.
- *  On failure, the negative of an error code is reported.
- *
- *  Because a MIDIStream is not a file, all seek operations are doomed to fail.
- *
- **/
-static loff_t usb_midi_llseek(struct file *file, loff_t offset, int origin)
-{
-	/** Tell user you cannot seek on a PIPE-like device. **/
-	return -ESPIPE;
-}
-
-
-/** Basic operation on /dev/midiXX as registered through struct file_operations.
- *
- * Basic contract: Block until count bytes have been read or an error occurs.
- *
- **/
-
-static ssize_t usb_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
-	struct midi_in_endpoint *ep = m->min.ep;
-	ssize_t ret;
-	DECLARE_WAITQUEUE(wait, current);
-
-	if ( !access_ok(VERIFY_READ, buffer, count) ) {
-		return -EFAULT;
-	}
-	if ( count == 0 ) {
-		return 0;
-	}
-
-	add_wait_queue( &ep->wait, &wait );
-	ret = 0;
-	while( count > 0 ) {
-		int cnt;
-		int d = (int)count;
-
-		cnt = m->min.bufRemains;
-		if ( cnt > d ) {
-			cnt = d;
-		}
-
-		if ( cnt <= 0 ) {
-			if ( file->f_flags & O_NONBLOCK ) {
-				if (!ret) 
-					ret = -EAGAIN;
-				break;
-			}
-			__set_current_state(TASK_INTERRUPTIBLE);
-			schedule();
-			if (signal_pending(current)) {
-				if(!ret)
-					ret=-ERESTARTSYS;
-				break;
-			}
-			continue;
-		}
-
-		{
-			int i;
-			unsigned long flags; /* used to synchronize access to the endpoint */
-			spin_lock_irqsave( &ep->lock, flags );
-			for (i = 0; i < cnt; i++) {
-				if ( copy_to_user( buffer+i, m->min.buf+m->min.bufRdPtr, 1 ) ) {
-					if ( !ret )
-						ret = -EFAULT;
-					break;
-				}
-				m->min.bufRdPtr = (m->min.bufRdPtr+1)%MIDI_IN_BUFSIZ;
-				m->min.bufRemains -= 1;
-			}
-			spin_unlock_irqrestore( &ep->lock, flags );
-		}
-
-		count-=cnt;
-		buffer+=cnt;
-		ret+=cnt;
-
-		break;
-	}
-
-	remove_wait_queue( &ep->wait, &wait );
-	set_current_state(TASK_RUNNING);
-
-	return ret;
-}
-
-
-/** Basic operation on /dev/midiXX as registered through struct file_operations.
- *
- *  Basic Contract: Take MIDI data byte-by-byte and pass it to
- *  writeMidi() which packages MIDI data into USB-MIDI stream.
- *  Then flushMidiData() is called to ensure all bytes have been written
- *  in a timely fashion.
- *
- **/
-
-static ssize_t usb_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
-	ssize_t ret;
-	unsigned long int flags;
-
-	if ( !access_ok(VERIFY_READ, buffer, count) ) {
-		return -EFAULT;
-	}
-	if ( count == 0 ) {
-		return 0;
-	}
-
-	ret = 0;
-	while( count > 0 ) {
-		unsigned char c;
-
-		if (copy_from_user((unsigned char *)&c, buffer, 1)) {
-			if ( ret == 0 )
-				ret = -EFAULT;
-			break;
-		}
-		if( midi_write(m, (int)c) ) {
-			if ( ret == 0 )
-				ret = -EFAULT;
-			break;
-		}
-		count--;
-		buffer++;
-		ret++;
-	}
-
-	spin_lock_irqsave( &m->mout.ep->lock, flags );
-	if ( flush_midi_buffer(m->mout.ep) < 0 ) {
-		ret = -EFAULT;
-	}
-	spin_unlock_irqrestore( &m->mout.ep->lock, flags );
-
-	return ret;
-}
-
-/** Basic operation on /dev/midiXX as registered through struct file_operations.
- *
- * Basic contract:  Wait (spin) until ready to read or write on the file.
- *
- **/
-static unsigned int usb_midi_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
-	struct midi_in_endpoint *iep = m->min.ep;
-	struct midi_out_endpoint *oep = m->mout.ep;
-	unsigned long flags;
-	unsigned int mask = 0;
-  
-	if ( file->f_mode & FMODE_READ ) {
-		poll_wait( file, &iep->wait, wait );
-		spin_lock_irqsave( &iep->lock, flags );
-		if ( m->min.bufRemains > 0 )
-			mask |= POLLIN | POLLRDNORM;
-		spin_unlock_irqrestore( &iep->lock, flags );
-	}
-
-	if ( file->f_mode & FMODE_WRITE ) {
-		poll_wait( file, &oep->wait, wait );
-		spin_lock_irqsave( &oep->lock, flags );
-		if ( oep->bufWrPtr < oep->bufSize )
-			mask |= POLLOUT | POLLWRNORM;
-		spin_unlock_irqrestore( &oep->lock, flags );
-	}
-
-	return mask;
-}
-
-
-/** Basic operation on /dev/midiXX as registered through struct file_operations.
- *
- * Basic contract: This is always the first operation performed on the
- * device node. If no method is defined, the open succeeds without any
- * notification given to the module.
- *
- **/
-
-static int usb_midi_open(struct inode *inode, struct file *file)
-{
-	int minor = iminor(inode);
-	DECLARE_WAITQUEUE(wait, current);
-	struct usb_midi_state *s;
-	struct usb_mididev    *m;
-	unsigned long flags;
-	int succeed = 0;
-
-#if 0
-	printk(KERN_INFO "usb-midi: Open minor= %d.\n", minor);
-#endif
-
-	for(;;) {
-		down(&open_sem);
-		list_for_each_entry(s, &mididevs, mididev) {
-			list_for_each_entry(m, &s->midiDevList, list) {
-				if ( !((m->dev_midi ^ minor) & ~0xf) )
-					goto device_found;
-			}
-		}
-		up(&open_sem);
-		return -ENODEV;
-
-	device_found:
-		if ( !s->usbdev ) {
-			up(&open_sem);
-			return -EIO;
-		}
-		if ( !(m->open_mode & file->f_mode) ) {
-			break;
-		}
-		if ( file->f_flags & O_NONBLOCK ) {
-			up(&open_sem);
-			return -EBUSY;
-		}
-		__set_current_state(TASK_INTERRUPTIBLE);
-		add_wait_queue( &open_wait, &wait );
-		up(&open_sem);
-		schedule();
-		remove_wait_queue( &open_wait, &wait );
-		if ( signal_pending(current) ) {
-			return -ERESTARTSYS;
-		}
-	}
-
-	file->private_data = m;
-	spin_lock_irqsave( &s->lock, flags );
-
-	if ( !(m->open_mode & (FMODE_READ | FMODE_WRITE)) ) {
-		//FIXME: intented semantics unclear here
-		m->min.bufRdPtr       = 0;
-		m->min.bufWrPtr       = 0;
-		m->min.bufRemains     = 0;
-		spin_lock_init(&m->min.ep->lock);
-
-		m->mout.bufPtr        = 0;
-		m->mout.bufRemains    = 0;
-		m->mout.isInExclusive = 0;
-		m->mout.lastEvent     = 0;
-		spin_lock_init(&m->mout.ep->lock);
-	}
-
-	if ( (file->f_mode & FMODE_READ) && m->min.ep != NULL ) {
-		unsigned long int flagsep;
-		spin_lock_irqsave( &m->min.ep->lock, flagsep );
-		m->min.ep->cables[m->min.cableId] = m;
-		m->min.ep->readers += 1;
-		m->min.bufRdPtr       = 0;
-		m->min.bufWrPtr       = 0;
-		m->min.bufRemains     = 0;
-		spin_unlock_irqrestore( &m->min.ep->lock, flagsep );
-
-		if ( !(m->min.ep->urbSubmitted)) {
-
-			/* urb->dev must be reinitialized on 2.4.x kernels */
-			m->min.ep->urb->dev = m->min.ep->usbdev;
-
-			if ( usb_submit_urb(m->min.ep->urb, GFP_ATOMIC) ) {
-				printk(KERN_ERR "usbmidi: Cannot submit urb for MIDI-IN\n");
-			}
-			m->min.ep->urbSubmitted = 1;
-		}
-		m->open_mode |= FMODE_READ;
-		succeed = 1;
-	}
-
-	if ( (file->f_mode & FMODE_WRITE) && m->mout.ep != NULL ) {
-		m->mout.bufPtr        = 0;
-		m->mout.bufRemains    = 0;
-		m->mout.isInExclusive = 0;
-		m->mout.lastEvent     = 0;
-		m->open_mode |= FMODE_WRITE;
-		succeed = 1;
-	}
-
-	spin_unlock_irqrestore( &s->lock, flags );
-
-	s->count++;
-	up(&open_sem);
-
-	/** Changed to prevent extra increments to USE_COUNT. **/
-	if (!succeed) {
-		return -EBUSY;
-	}
-
-#if 0
-	printk(KERN_INFO "usb-midi: Open Succeeded. minor= %d.\n", minor);
-#endif
-
-	return nonseekable_open(inode, file); /** Success. **/
-}
-
-
-/** Basic operation on /dev/midiXX as registered through struct file_operations.
- *
- *  Basic contract: Close an opened file and deallocate anything we allocated.
- *  Like open(), this can be missing. If open set file->private_data,
- *  release() must clear it.
- *
- **/
-
-static int usb_midi_release(struct inode *inode, struct file *file)
-{
-	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
-	struct usb_midi_state *s = (struct usb_midi_state *)m->midi;
-
-#if 0
-	printk(KERN_INFO "usb-midi: Close.\n");
-#endif
-
-	down(&open_sem);
-
-	if ( m->open_mode & FMODE_WRITE ) {
-		m->open_mode &= ~FMODE_WRITE;
-		usb_kill_urb( m->mout.ep->urb );
-	}
-
-	if ( m->open_mode & FMODE_READ ) {
-	        unsigned long int flagsep;
-	        spin_lock_irqsave( &m->min.ep->lock, flagsep );
-                m->min.ep->cables[m->min.cableId] = NULL; // discard cable
-                m->min.ep->readers -= 1;
-		m->open_mode &= ~FMODE_READ;
-		if ( m->min.ep->readers == 0 &&
-                     m->min.ep->urbSubmitted ) {
-			m->min.ep->urbSubmitted = 0;
-			usb_kill_urb(m->min.ep->urb);
-		}
-	        spin_unlock_irqrestore( &m->min.ep->lock, flagsep );
-	}
-
-	s->count--;
-
-	up(&open_sem);
-	wake_up(&open_wait);
-
-	file->private_data = NULL;
-	return 0;
-}
-
-static struct file_operations usb_midi_fops = {
-	.owner =	THIS_MODULE,
-	.llseek =	usb_midi_llseek,
-	.read =		usb_midi_read,
-	.write =	usb_midi_write,
-	.poll =		usb_midi_poll,
-	.open =		usb_midi_open,
-	.release =	usb_midi_release,
-};
-
-/* ------------------------------------------------------------------------- */
-
-/** Returns filled midi_in_endpoint structure or null on failure.
- *
- * Parameters:
- *	d        - a usb_device
- *	endPoint - An usb endpoint in the range 0 to 15.
- * Called by allocUsbMidiDev();
- *
- **/
-
-static struct midi_in_endpoint *alloc_midi_in_endpoint( struct usb_device *d, int endPoint )
-{
-	struct midi_in_endpoint *ep;
-	int bufSize;
-	int pipe;
-
-	endPoint &= 0x0f; /* Silently force endPoint to lie in range 0 to 15. */
-
-	pipe =  usb_rcvbulkpipe( d, endPoint );
-	bufSize = usb_maxpacket( d, pipe, 0 );
-	/* usb_pipein() = ! usb_pipeout() = true for an in Endpoint */
-
-	ep = (struct midi_in_endpoint *)kmalloc(sizeof(struct midi_in_endpoint), GFP_KERNEL);
-	if ( !ep ) {
-		printk(KERN_ERR "usbmidi: no memory for midi in-endpoint\n");
-		return NULL;
-	}
-	memset( ep, 0, sizeof(struct midi_in_endpoint) );
-//      this sets cables[] and readers to 0, too.
-//      for (i=0; i<16; i++) ep->cables[i] = 0; // discard cable
-//      ep->readers = 0;
-
-	ep->endpoint = endPoint;
-
-	ep->recvBuf = (unsigned char *)kmalloc(sizeof(unsigned char)*(bufSize), GFP_KERNEL);
-	if ( !ep->recvBuf ) {
-		printk(KERN_ERR "usbmidi: no memory for midi in-endpoint buffer\n");
-		kfree(ep);
-		return NULL;
-	}
-
-	ep->urb = usb_alloc_urb(0, GFP_KERNEL); /* no ISO */
-	if ( !ep->urb ) {
-		printk(KERN_ERR "usbmidi: no memory for midi in-endpoint urb\n");
-		kfree(ep->recvBuf);
-		kfree(ep);
-		return NULL;
-	}
-	usb_fill_bulk_urb( ep->urb, d, 
-		       usb_rcvbulkpipe(d, endPoint),
-		       (unsigned char *)ep->recvBuf, bufSize,
-		       usb_bulk_read, ep );
-
-	/* ep->bufRdPtr     = 0; */
-	/* ep->bufWrPtr     = 0; */
-	/* ep->bufRemains   = 0; */
-	/* ep->urbSubmitted = 0; */
-	ep->recvBufSize  = bufSize;
-
-	init_waitqueue_head(&ep->wait);
-
-	return ep;
-}
-
-static int remove_midi_in_endpoint( struct midi_in_endpoint *min )
-{
-	usb_kill_urb( min->urb );
-	usb_free_urb( min->urb );
-	kfree( min->recvBuf );
-	kfree( min );
-
-	return 0;
-}
-
-/** Returns filled midi_out_endpoint structure or null on failure.
- *
- * Parameters:
- *	d        - a usb_device
- *	endPoint - An usb endpoint in the range 0 to 15.
- * Called by allocUsbMidiDev();
- *
- **/
-static struct midi_out_endpoint *alloc_midi_out_endpoint( struct usb_device *d, int endPoint )
-{
-	struct midi_out_endpoint *ep = NULL;
-	int pipe;
-	int bufSize;
-
-	endPoint &= 0x0f;
-	pipe =  usb_sndbulkpipe( d, endPoint );
-	bufSize = usb_maxpacket( d, pipe, 1 );
-
-	ep = (struct midi_out_endpoint *)kmalloc(sizeof(struct midi_out_endpoint), GFP_KERNEL);
-	if ( !ep ) {
-		printk(KERN_ERR "usbmidi: no memory for midi out-endpoint\n");
-		return NULL;
-	}
-	memset( ep, 0, sizeof(struct midi_out_endpoint) );
-
-	ep->endpoint = endPoint;
-	ep->buf = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL);
-	if ( !ep->buf ) {
-		printk(KERN_ERR "usbmidi: no memory for midi out-endpoint buffer\n");
-		kfree(ep);
-		return NULL;
-	}
-
-	ep->urb = usb_alloc_urb(0, GFP_KERNEL); /* no ISO */
-	if ( !ep->urb ) {
-		printk(KERN_ERR "usbmidi: no memory for midi out-endpoint urb\n");
-		kfree(ep->buf);
-		kfree(ep);
-		return NULL;
-	}
-
-	ep->bufSize       = bufSize;
-	/* ep->bufWrPtr      = 0; */
-
-	init_waitqueue_head(&ep->wait);
-
-	return ep;
-}
-
-
-static int remove_midi_out_endpoint( struct midi_out_endpoint *mout )
-{
-	usb_kill_urb( mout->urb );
-	usb_free_urb( mout->urb );
-	kfree( mout->buf );
-	kfree( mout );
-
-	return 0;
-}
-
-
-/** Returns a filled usb_mididev structure, registered as a Linux MIDI device.
- *
- * Returns null if memory is not available or the device cannot be registered.
- * Called by allocUsbMidiDev();
- *
- **/
-static struct usb_mididev *allocMidiDev(
-	struct usb_midi_state *s,
-	struct midi_in_endpoint *min,
-	struct midi_out_endpoint *mout,
-	int inCableId,
-	int outCableId )
-{
-	struct usb_mididev *m;
-
-	m = (struct usb_mididev *)kmalloc(sizeof(struct usb_mididev), GFP_KERNEL);
-	if (!m) {
-		printk(KERN_ERR "usbmidi: no memory for midi device\n");
-		return NULL;
-	}
-
-	memset(m, 0, sizeof(struct usb_mididev));
-
-	if ((m->dev_midi = register_sound_midi(&usb_midi_fops, -1)) < 0) {
-		printk(KERN_ERR "usbmidi: cannot register midi device\n");
-		kfree(m);
-		return NULL;
-	}
-
-	m->midi               = s;
-	/* m->open_mode          = 0; */
-
-	if ( min ) {
-		m->min.ep             = min;
-		m->min.ep->usbdev     = s->usbdev;
-		m->min.cableId        = inCableId;
-	}
-	/* m->min.bufPtr         = 0; */
-	/* m->min.bufRemains     = 0; */
-
-	if ( mout ) {
-		m->mout.ep            = mout;
-		m->mout.ep->usbdev    = s->usbdev;
-		m->mout.cableId       = outCableId;
-	}
-	/* m->mout.bufPtr        = 0; */
-	/* m->mout.bufRemains    = 0; */
-	/* m->mout.isInExclusive = 0; */
-	/* m->mout.lastEvent     = 0; */
-
-	m->singlebyte         = singlebyte;
-
-	return m;
-}
-
-
-static void release_midi_device( struct usb_midi_state *s )
-{
-	struct usb_mididev *m;
-	struct midi_in_endpoint *min;
-	struct midi_out_endpoint *mout;
-
-	if ( s->count > 0 ) {
-		up(&open_sem);
-		return;
-	}
-	up( &open_sem );
-	wake_up( &open_wait );
-
-	while(!list_empty(&s->inEndpointList)) {
-		min = list_entry(s->inEndpointList.next, struct midi_in_endpoint, list);
-		list_del(&min->list);
-		remove_midi_in_endpoint(min);
-	}
-
-	while(!list_empty(&s->outEndpointList)) {
-		mout = list_entry(s->outEndpointList.next, struct midi_out_endpoint, list);
-		list_del(&mout->list);
-		remove_midi_out_endpoint(mout);
-	}
-
-	while(!list_empty(&s->midiDevList)) {
-		m = list_entry(s->midiDevList.next, struct usb_mididev, list);
-		list_del(&m->list);
-		kfree(m);
-	}
-
-	kfree(s);
-
-	return;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-/** Utility routine to find a descriptor in a dump of many descriptors.
- * Returns start of descriptor or NULL if not found. 
- * descStart pointer to list of interfaces.
- * descLength length (in bytes) of dump
- * after (ignored if NULL) this routine returns only descriptors after "after"
- * dtype (mandatory) The descriptor type.
- * iface (ignored if -1) returns descriptor at/following given interface
- * altSetting (ignored if -1) returns descriptor at/following given altSetting
- *
- *
- *  Called by parseDescriptor(), find_csinterface_descriptor();
- *
- */
-static void *find_descriptor( void *descStart, unsigned int descLength, void *after, unsigned char dtype, int iface, int altSetting )
-{
-	unsigned char *p, *end, *next;
-	int interfaceNumber = -1, altSet = -1;
-
-	p = descStart;
-	end = p + descLength;
-	for( ; p < end; ) {
-		if ( p[0] < 2 )
-			return NULL;
-		next = p + p[0];
-		if ( next > end )
-			return NULL;
-		if ( p[1] == USB_DT_INTERFACE ) {
-			if ( p[0] < USB_DT_INTERFACE_SIZE )
-				return NULL;
-			interfaceNumber = p[2];
-			altSet = p[3];
-		}
-		if ( p[1] == dtype &&
-		     ( !after || ( p > (unsigned char *)after) ) &&
-		     ( ( iface == -1) || (iface == interfaceNumber) ) &&
-		     ( (altSetting == -1) || (altSetting == altSet) )) {
-			return p;
-		}
-		p = next;
-	}
-	return NULL;
-}
-
-/** Utility to find a class-specific interface descriptor.
- *  dsubtype is a descriptor subtype
- *  Called by parseDescriptor();
- **/
-static void *find_csinterface_descriptor(void *descStart, unsigned int descLength, void *after, u8 dsubtype, int iface, int altSetting)
-{
-	unsigned char *p;
-  
-	p = find_descriptor( descStart, descLength, after, USB_DT_CS_INTERFACE, iface, altSetting );
-	while ( p ) {
-		if ( p[0] >= 3 && p[2] == dsubtype )
-			return p;
-		p = find_descriptor( descStart, descLength, p, USB_DT_CS_INTERFACE, 
-				     iface, altSetting );
-	}
-	return NULL;
-}
-
-
-/** The magic of making a new usb_midi_device from config happens here.
- *
- * The caller is responsible for free-ing this return value (if not NULL).
- *
- **/
-static struct usb_midi_device *parse_descriptor( struct usb_device *d, unsigned char *buffer, int bufSize, unsigned int ifnum , unsigned int altSetting, int quirks)
-{
-	struct usb_midi_device *u;
-	unsigned char *p1;
-	unsigned char *p2;
-	unsigned char *next;
-	int iep, oep;
-	int length;
-	unsigned long longBits;
-	int pins, nbytes, offset, shift, jack;
-#ifdef HAVE_JACK_STRINGS
-	/** Jacks can have associated names.  **/
-	unsigned char jack2string[256];
-#endif
-
-	u = NULL;
-	/* find audiocontrol interface */
-	p1 = find_csinterface_descriptor( buffer, bufSize, NULL,
-					  MS_HEADER, ifnum, altSetting);
-
-	if ( !p1 ) {
-		goto error_end;
-	}
-
-	if ( p1[0] < MS_HEADER_LENGTH ) {
-		goto error_end;
-	}
-
-	/* Assume success. Since the device corresponds to USB-MIDI spec, we assume
-	   that the rest of the USB 2.0 spec is obeyed. */
-
-	u = (struct usb_midi_device *)kmalloc( sizeof(struct usb_midi_device), GFP_KERNEL );
-	if ( !u ) {
-		return NULL;
-	}
-	u->deviceName = NULL;
-	u->idVendor = le16_to_cpu(d->descriptor.idVendor);
-	u->idProduct = le16_to_cpu(d->descriptor.idProduct);
-	u->interface = ifnum;
-	u->altSetting = altSetting;
-	u->in[0].endpoint = -1;
-	u->in[0].cableId = -1;
-	u->out[0].endpoint = -1;
-	u->out[0].cableId = -1;
-
-
-	printk(KERN_INFO "usb-midi: Found MIDIStreaming device corresponding to Release %d.%02d of spec.\n",
-	       (p1[4] >> 4) * 10 + (p1[4] & 0x0f ),
-	       (p1[3] >> 4) * 10 + (p1[3] & 0x0f )
-		);
-
-	length = p1[5] | (p1[6] << 8);
-
-#ifdef HAVE_JACK_STRINGS
-	memset(jack2string, 0, sizeof(unsigned char) * 256);
-#endif
-
-	length -= p1[0];
-	for (p2 = p1 + p1[0]; length > 0; p2 = next) {
-		next = p2 + p2[0];
-		length -= p2[0];
-
-		if (p2[0] < 2 )
-			break;
-		if (p2[1] != USB_DT_CS_INTERFACE)
-			break;
-		if (p2[2] == MIDI_IN_JACK && p2[0] >= 6 ) {
-			jack = p2[4];
-#ifdef HAVE_JACK_STRINGS
-			jack2string[jack] = p2[5];
-#endif
-			printk(KERN_INFO "usb-midi: Found IN Jack 0x%02x %s\n",
-			       jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL" );
-		} else if ( p2[2] == MIDI_OUT_JACK && p2[0] >= 6) {
-			pins = p2[5];
-			if ( p2[0] < (6 + 2 * pins) )
-				continue;
-			jack = p2[4];
-#ifdef HAVE_JACK_STRINGS
-			jack2string[jack] = p2[5 + 2 * pins];
-#endif
-			printk(KERN_INFO "usb-midi: Found OUT Jack 0x%02x %s, %d pins\n",
-			       jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL", pins );
-		} else if ( p2[2] == ELEMENT_DESCRIPTOR  && p2[0]  >= 10) {
-			pins = p2[4];
-			if ( p2[0] < (9 + 2 * pins ) )
-				continue;
-			nbytes = p2[8 + 2 * pins ];
-			if ( p2[0] < (10 + 2 * pins + nbytes) )
-				continue;
-			longBits = 0L;
-			for ( offset = 0, shift = 0; offset < nbytes && offset < 8; offset ++, shift += 8) {
-				longBits |= ((long)(p2[9 + 2 * pins + offset])) << shift;
-			}
-			jack = p2[3];
-#ifdef HAVE_JACK_STRINGS
-			jack2string[jack] = p2[9 + 2 * pins + nbytes];
-#endif
-			printk(KERN_INFO "usb-midi: Found ELEMENT 0x%02x, %d/%d pins in/out, bits: 0x%016lx\n",
-			       jack, pins, (int)(p2[5 + 2 * pins]), (long)longBits );
-		} else {
-		}
-	}
-
-	iep=0;
-	oep=0;
-
-	if (quirks==0) {
-		/* MIDISTREAM */
-		p2 = NULL;
-		for (p1 = find_descriptor(buffer, bufSize, NULL, USB_DT_ENDPOINT,
-					  ifnum, altSetting ); p1; p1 = next ) {
-			next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT,
-					       ifnum, altSetting ); 
-			p2 = find_descriptor(buffer, bufSize, p1, USB_DT_CS_ENDPOINT,
-					     ifnum, altSetting ); 
-
-			if ( p2 && next && ( p2 > next ) )
-				p2 = NULL;
-
-			if ( p1[0] < 9 || !p2 || p2[0] < 4 )
-				continue;
-
-			if ( (p1[2] & 0x80) == 0x80 ) {
-				if ( iep < 15 ) {
-					pins = p2[3]; /* not pins -- actually "cables" */
-					if ( pins > 16 )
-						pins = 16;
-					u->in[iep].endpoint = p1[2];
-					u->in[iep].cableId = ( 1 << pins ) - 1;
-					if ( u->in[iep].cableId )
-						iep ++;
-					if ( iep < 15 ) {
-						u->in[iep].endpoint = -1;
-						u->in[iep].cableId = -1;
-					}
-				}
-			} else {
-				if ( oep < 15 ) {
-					pins = p2[3]; /* not pins -- actually "cables" */
-					if ( pins > 16 )
-						pins = 16;
-					u->out[oep].endpoint = p1[2];
-					u->out[oep].cableId = ( 1 << pins ) - 1;
-					if ( u->out[oep].cableId )
-						oep ++;
-					if ( oep < 15 ) {
-						u->out[oep].endpoint = -1;
-						u->out[oep].cableId = -1;
-					}
-				}
-			}
-	
-		}
-	} else if (quirks==1) {
-		/* YAMAHA quirks */
-		for (p1 = find_descriptor(buffer, bufSize, NULL, USB_DT_ENDPOINT,
-					  ifnum, altSetting ); p1; p1 = next ) {
-			next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT,
-					       ifnum, altSetting ); 
-	
-			if ( p1[0] < 7 )
-				continue;
-
-			if ( (p1[2] & 0x80) == 0x80 ) {
-				if ( iep < 15 ) {
-					pins = iep+1;
-					if ( pins > 16 )
-						pins = 16;
-					u->in[iep].endpoint = p1[2];
-					u->in[iep].cableId = ( 1 << pins ) - 1;
-					if ( u->in[iep].cableId )
-						iep ++;
-					if ( iep < 15 ) {
-						u->in[iep].endpoint = -1;
-						u->in[iep].cableId = -1;
-					}
-				}
-			} else {
-				if ( oep < 15 ) {
-					pins = oep+1;
-					u->out[oep].endpoint = p1[2];
-					u->out[oep].cableId = ( 1 << pins ) - 1;
-					if ( u->out[oep].cableId )
-						oep ++;
-					if ( oep < 15 ) {
-						u->out[oep].endpoint = -1;
-						u->out[oep].cableId = -1;
-					}
-				}
-			}
-	
-		}
-	}
-
-	if ( !iep && ! oep ) {
-		goto error_end;
-	}
-
-	return u;
-
-error_end:
-	kfree(u);
-	return NULL;
-}
-
-/* ------------------------------------------------------------------------- */
-
-/** Returns number between 0 and 16.
- *
- **/
-static int on_bits( unsigned short v )
-{
-	int i;
-	int ret=0;
-
-	for ( i=0 ; i<16 ; i++ ) {
-		if ( v & (1<<i) )
-			ret++;
-	}
-
-	return ret;
-}
-
-
-/** USB-device will be interrogated for altSetting.
- *
- * Returns negative on error.
- * Called by allocUsbMidiDev();
- *
- **/
-
-static int get_alt_setting( struct usb_device *d, int ifnum )
-{
-	int alts, alt=0;
-	struct usb_interface *iface;
-	struct usb_host_interface *interface;
-	struct usb_endpoint_descriptor *ep;
-	int epin, epout;
-	int i;
-
-	iface = usb_ifnum_to_if( d, ifnum );
-	alts = iface->num_altsetting;
-
-	for ( alt=0 ; alt<alts ; alt++ ) {
-		interface = &iface->altsetting[alt];
-		epin = -1;
-		epout = -1;
-
-		for ( i=0 ; i<interface->desc.bNumEndpoints ; i++ ) {
-			ep = &interface->endpoint[i].desc;
-			if ( (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ) {
-				continue;
-			}
-			if ( (ep->bEndpointAddress & USB_DIR_IN) && epin < 0 ) {
-				epin = i;
-			} else if ( epout < 0 ) {
-				epout = i;
-			}
-			if ( epin >= 0 && epout >= 0 ) {
-				return interface->desc.bAlternateSetting;
-			}
-		}
-	}
-
-	return -ENODEV;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-
-/** Returns 0 if successful in allocating and registering internal structures.
- * Returns negative on failure.
- * Calls allocMidiDev which additionally registers /dev/midiXX devices.
- * Writes messages on success to indicate which /dev/midiXX is which physical
- * endpoint.
- *
- **/
-static int alloc_usb_midi_device( struct usb_device *d, struct usb_midi_state *s, struct usb_midi_device *u )
-{
-	struct usb_mididev **mdevs=NULL;
-	struct midi_in_endpoint *mins[15], *min;
-	struct midi_out_endpoint *mouts[15], *mout;
-	int inDevs=0, outDevs=0;
-	int inEndpoints=0, outEndpoints=0;
-	int inEndpoint, outEndpoint;
-	int inCableId, outCableId;
-	int i;
-	int devices = 0;
-	int alt = 0;
-
-	/* Obtain altSetting or die.. */
-	alt = u->altSetting;
-	if ( alt < 0 ) {
-		alt = get_alt_setting( d, u->interface );
-	}
-	if ( alt < 0 )
-		return -ENXIO;
-
-	/* Configure interface */
-	if ( usb_set_interface( d, u->interface, alt ) < 0 ) {
-		return -ENXIO;
-	}
-
-	for ( i = 0 ; i < 15 ; i++ ) {
-		mins[i] = NULL;
-		mouts[i] = NULL;
-	}
-
-	/* Begin Allocation */
-	while( inEndpoints < 15
-	       && inDevs < maxdevices
-	       && u->in[inEndpoints].cableId >= 0 ) {
-		inDevs += on_bits((unsigned short)u->in[inEndpoints].cableId);
-		mins[inEndpoints] = alloc_midi_in_endpoint( d, u->in[inEndpoints].endpoint );
-		if ( mins[inEndpoints] == NULL )
-			goto error_end;
-		inEndpoints++;
-	}
-
-	while( outEndpoints < 15
-	       && outDevs < maxdevices
-	       && u->out[outEndpoints].cableId >= 0 ) {
-		outDevs += on_bits((unsigned short)u->out[outEndpoints].cableId);
-		mouts[outEndpoints] = alloc_midi_out_endpoint( d, u->out[outEndpoints].endpoint );
-		if ( mouts[outEndpoints] == NULL )
-			goto error_end;
-		outEndpoints++;
-	}
-
-	devices = inDevs > outDevs ? inDevs : outDevs;
-	devices = maxdevices > devices ? devices : maxdevices;
-
-	/* obtain space for device name (iProduct) if not known. */
-	if ( ! u->deviceName ) {
-		mdevs = (struct usb_mididev **)
-			kmalloc(sizeof(struct usb_mididevs *)*devices
-				+ sizeof(char) * 256, GFP_KERNEL);
-	} else {
-		mdevs = (struct usb_mididev **)
-			kmalloc(sizeof(struct usb_mididevs *)*devices, GFP_KERNEL);
-	}
-
-	if ( !mdevs ) {
-		/* devices = 0; */
-		/* mdevs = NULL; */
-		goto error_end;
-	}
-	for ( i=0 ; i<devices ; i++ ) {
-		mdevs[i] = NULL;
-	}
-
-	/* obtain device name (iProduct) if not known. */
-	if ( ! u->deviceName ) {
-		u->deviceName = (char *) (mdevs + devices);
-		if ( ! d->have_langid && d->descriptor.iProduct) {
-			alt = usb_get_string(d, 0, 0, u->deviceName, 250);
-			if (alt < 0) {
-				printk(KERN_INFO "error getting string descriptor 0 (error=%d)\n", alt);
-			} else if (u->deviceName[0] < 4) {
-				printk(KERN_INFO "string descriptor 0 too short (length = %d)\n", alt);
-			} else {
-				printk(KERN_INFO "string descriptor 0 found (length = %d)\n", alt);
-				for(; alt >= 4; alt -= 2) {
-					i = u->deviceName[alt-2] | (u->deviceName[alt-1]<< 8);
-					printk(KERN_INFO "usb-midi: langid(%d) 0x%04x\n",
-					       (alt-4) >> 1, i);
-					if ( ( ( i ^ ulangid ) & 0xff ) == 0 ) {
-						d->have_langid = 1;
-						d->string_langid = i;
-						printk(KERN_INFO "usb-midi: langid(match) 0x%04x\n", i);
-						if ( i == ulangid )
-							break;
-					}
-				}
-			}
-		}
-		u->deviceName[0] = (char) 0;
-		if (d->descriptor.iProduct) {
-			printk(KERN_INFO "usb-midi: fetchString(%d)\n", d->descriptor.iProduct);
-			alt = usb_string(d, d->descriptor.iProduct, u->deviceName, 255);
-			if( alt < 0 ) {
-				u->deviceName[0] = (char) 0;
-			}
-			printk(KERN_INFO "usb-midi: fetchString = %d\n", alt);
-		} 
-		/* Failsafe */
-		if ( !u->deviceName[0] ) {
-			if (le16_to_cpu(d->descriptor.idVendor) == USB_VENDOR_ID_ROLAND ) {
-				strcpy(u->deviceName, "Unknown Roland");
-			} else if (le16_to_cpu(d->descriptor.idVendor) == USB_VENDOR_ID_STEINBERG  ) {
-				strcpy(u->deviceName, "Unknown Steinberg");
-			} else if (le16_to_cpu(d->descriptor.idVendor) == USB_VENDOR_ID_YAMAHA ) {
-				strcpy(u->deviceName, "Unknown Yamaha");
-			} else {
-				strcpy(u->deviceName, "Unknown");
-			}
-		}
-	}
-
-	inEndpoint  = 0; inCableId  = -1;
-	outEndpoint = 0; outCableId = -1;
-
-	for ( i=0 ; i<devices ; i++ ) {
-		for ( inCableId ++ ;
-		      inEndpoint <15
-			      && mins[inEndpoint] 
-			      && !(u->in[inEndpoint].cableId & (1<<inCableId)) ;
-		      inCableId++ ) {
-			if ( inCableId >= 16 ) {
-				inEndpoint  ++;
-				inCableId  = 0;
-			}
-		}
-		min  = mins[inEndpoint];
-		for ( outCableId ++ ;
-		      outEndpoint <15
-			      && mouts[outEndpoint] 
-			      && !(u->out[outEndpoint].cableId & (1<<outCableId)) ;
-		      outCableId++ ) {
-			if ( outCableId >= 16 ) {
-				outEndpoint  ++;
-				outCableId  = 0;
-			}
-		}
-		mout = mouts[outEndpoint];
-
-		mdevs[i] = allocMidiDev( s, min, mout, inCableId, outCableId );
-		if ( mdevs[i] == NULL )
-			goto error_end;
-
-	}
-
-	/* Success! */
-	for ( i=0 ; i<devices ; i++ ) {
-		list_add_tail( &mdevs[i]->list, &s->midiDevList );
-	}
-	for ( i=0 ; i<inEndpoints ; i++ ) {
-		list_add_tail( &mins[i]->list, &s->inEndpointList );
-	}
-	for ( i=0 ; i<outEndpoints ; i++ ) {
-		list_add_tail( &mouts[i]->list, &s->outEndpointList );
-	}
-
-	printk(KERN_INFO "usbmidi: found [ %s ] (0x%04x:0x%04x), attached:\n", u->deviceName, u->idVendor, u->idProduct );
-	for ( i=0 ; i<devices ; i++ ) {
-		int dm = (mdevs[i]->dev_midi-2)>>4;
-		if ( mdevs[i]->mout.ep != NULL && mdevs[i]->min.ep != NULL ) {
-			printk(KERN_INFO "usbmidi: /dev/midi%02d: in (ep:%02x cid:%2d bufsiz:%2d) out (ep:%02x cid:%2d bufsiz:%2d)\n", 
-			       dm,
-			       mdevs[i]->min.ep->endpoint|USB_DIR_IN, mdevs[i]->min.cableId, mdevs[i]->min.ep->recvBufSize,
-			       mdevs[i]->mout.ep->endpoint, mdevs[i]->mout.cableId, mdevs[i]->mout.ep->bufSize);
-		} else if ( mdevs[i]->min.ep != NULL ) {
-			printk(KERN_INFO "usbmidi: /dev/midi%02d: in (ep:%02x cid:%2d bufsiz:%02d)\n", 
-			       dm,
-			       mdevs[i]->min.ep->endpoint|USB_DIR_IN, mdevs[i]->min.cableId, mdevs[i]->min.ep->recvBufSize);
-		} else if ( mdevs[i]->mout.ep != NULL ) {
-			printk(KERN_INFO "usbmidi: /dev/midi%02d: out (ep:%02x cid:%2d bufsiz:%02d)\n", 
-			       dm,
-			       mdevs[i]->mout.ep->endpoint, mdevs[i]->mout.cableId, mdevs[i]->mout.ep->bufSize);
-		}
-	}
-
-	kfree(mdevs);
-	return 0;
-
- error_end:
-	if ( mdevs != NULL ) {
-		for ( i=0 ; i<devices ; i++ ) {
-			if ( mdevs[i] != NULL ) {
-				unregister_sound_midi( mdevs[i]->dev_midi );
-				kfree(mdevs[i]);
-			}
-		}
-		kfree(mdevs);
-	}
-
-	for ( i=0 ; i<15 ; i++ ) {
-		if ( mins[i] != NULL ) {
-			remove_midi_in_endpoint( mins[i] );
-		}
-		if ( mouts[i] != NULL ) {
-			remove_midi_out_endpoint( mouts[i] );
-		}
-	}
-
-	return -ENOMEM;
-}
-
-/* ------------------------------------------------------------------------- */
-
-/** Attempt to scan YAMAHA's device descriptor and detect correct values of
- *  them.
- *  Return 0 on succes, negative on failure.
- *  Called by usb_midi_probe();
- **/
-
-static int detect_yamaha_device( struct usb_device *d,
-		struct usb_interface *iface, unsigned int ifnum,
-		struct usb_midi_state *s)
-{
-	struct usb_host_interface *interface;
-	struct usb_midi_device *u;
-	unsigned char *buffer;
-	int bufSize;
-	int i;
-	int alts=-1;
-	int ret;
-
-	if (le16_to_cpu(d->descriptor.idVendor) != USB_VENDOR_ID_YAMAHA) {
-		return -EINVAL;
-	}
-
-	for ( i=0 ; i < iface->num_altsetting; i++ ) {
-		interface = iface->altsetting + i;
-
-		if ( interface->desc.bInterfaceClass != 255 ||
-		     interface->desc.bInterfaceSubClass != 0 )
-			continue;
-		alts = interface->desc.bAlternateSetting;
-	}
-	if ( alts == -1 ) {
-		return -EINVAL;
-	}
-
-	printk(KERN_INFO "usb-midi: Found YAMAHA USB-MIDI device on dev %04x:%04x, iface %d\n",
-	       le16_to_cpu(d->descriptor.idVendor),
-	       le16_to_cpu(d->descriptor.idProduct), ifnum);
-
-	i = d->actconfig - d->config;
-	buffer = d->rawdescriptors[i];
-	bufSize = le16_to_cpu(d->actconfig->desc.wTotalLength);
-
-	u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 1);
-	if ( u == NULL ) {
-		return -EINVAL;
-	}
-
-	ret = alloc_usb_midi_device( d, s, u );
-
-	kfree(u);
-
-	return ret;
-}
-
-
-/** Scan table of known devices which are only partially compliant with 
- * the MIDIStreaming specification.
- * Called by usb_midi_probe();
- *
- **/
-
-static int detect_vendor_specific_device( struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s )
-{
-	struct usb_midi_device *u;
-	int i;
-	int ret = -ENXIO;
-
-	for ( i=0; i<VENDOR_SPECIFIC_USB_MIDI_DEVICES ; i++ ) {
-		u=&(usb_midi_devices[i]);
-    
-		if ( le16_to_cpu(d->descriptor.idVendor) != u->idVendor ||
-		     le16_to_cpu(d->descriptor.idProduct) != u->idProduct ||
-		     ifnum != u->interface )
-			continue;
-
-		ret = alloc_usb_midi_device( d, s, u );
-		break;
-	}
-
-	return ret;
-}
-
-
-/** Attempt to match any config of an interface to a MIDISTREAMING interface.
- *  Returns 0 on success, negative on failure.
- * Called by usb_midi_probe();
- **/
-static int detect_midi_subclass(struct usb_device *d,
-		struct usb_interface *iface, unsigned int ifnum,
-		struct usb_midi_state *s)
-{
-	struct usb_host_interface *interface;
-	struct usb_midi_device *u;
-	unsigned char *buffer;
-	int bufSize;
-	int i;
-	int alts=-1;
-	int ret;
-
-	for ( i=0 ; i < iface->num_altsetting; i++ ) {
-		interface = iface->altsetting + i;
-
-		if ( interface->desc.bInterfaceClass != USB_CLASS_AUDIO ||
-		     interface->desc.bInterfaceSubClass != USB_SUBCLASS_MIDISTREAMING )
-			continue;
-		alts = interface->desc.bAlternateSetting;
-	}
-	if ( alts == -1 ) {
-		return -EINVAL;
-	}
-
-	printk(KERN_INFO "usb-midi: Found MIDISTREAMING on dev %04x:%04x, iface %d\n",
-	       le16_to_cpu(d->descriptor.idVendor), 
-	       le16_to_cpu(d->descriptor.idProduct), ifnum);
-
-
-	/* From USB Spec v2.0, Section 9.5.
-	   If the class or vendor specific descriptors use the same format
-	   as standard descriptors (e.g., start with a length byte and
-	   followed by a type byte), they must be returned interleaved with
-	   standard descriptors in the configuration information returned by
-	   a GetDescriptor(Configuration) request. In this case, the class
-	   or vendor-specific descriptors must follow a related standard
-	   descriptor they modify or extend.
-	*/
-
-	i = d->actconfig - d->config;
-	buffer = d->rawdescriptors[i];
-	bufSize = le16_to_cpu(d->actconfig->desc.wTotalLength);
-
-	u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 0);
-	if ( u == NULL ) {
-		return -EINVAL;
-	}
-
-	ret = alloc_usb_midi_device( d, s, u );
-
-	kfree(u);
-
-	return ret;
-}
-
-
-/** When user has requested a specific device, match it exactly.
- *
- * Uses uvendor, uproduct, uinterface, ualt, umin, umout and ucable.
- * Called by usb_midi_probe();
- *
- **/
-static int detect_by_hand(struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s)
-{
-	struct usb_midi_device u;
-
-	if ( le16_to_cpu(d->descriptor.idVendor) != uvendor ||
-	     le16_to_cpu(d->descriptor.idProduct) != uproduct ||
-	     ifnum != uinterface ) {
-		return -EINVAL;
-	}
-
-	if ( ualt < 0 )
-		ualt = -1;
-
-	if ( umin   < 0 || umin   > 15 )
-		umin   = 0x01 | USB_DIR_IN;
-	if ( umout  < 0 || umout  > 15 )
-		umout  = 0x01;
-	if ( ucable < 0 || ucable > 15 )
-		ucable = 0;
-
-	u.deviceName = NULL; /* A flag for alloc_usb_midi_device to get device
-				name from device. */
-	u.idVendor   = uvendor;
-	u.idProduct  = uproduct;
-	u.interface  = uinterface;
-	u.altSetting = ualt;
-
-	u.in[0].endpoint    = umin;
-	u.in[0].cableId     = (1<<ucable);
-
-	u.out[0].endpoint   = umout;
-	u.out[0].cableId    = (1<<ucable);
-
-	return alloc_usb_midi_device( d, s, &u );
-}
-
-
-
-/* ------------------------------------------------------------------------- */
-
-static int usb_midi_probe(struct usb_interface *intf, 
-			  const struct usb_device_id *id)
-{
-	struct usb_midi_state *s;
-	struct usb_device *dev = interface_to_usbdev(intf);
-	int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
-
-	s = (struct usb_midi_state *)kmalloc(sizeof(struct usb_midi_state), GFP_KERNEL);
-	if ( !s )
-		return -ENOMEM;
-
-	memset( s, 0, sizeof(struct usb_midi_state) );
-	INIT_LIST_HEAD(&s->midiDevList);
-	INIT_LIST_HEAD(&s->inEndpointList);
-	INIT_LIST_HEAD(&s->outEndpointList);
-	s->usbdev = dev;
-	s->count  = 0;
-	spin_lock_init(&s->lock);
-
-	if (
-		detect_by_hand( dev, ifnum, s ) &&
-		detect_midi_subclass( dev, intf, ifnum, s ) &&
-		detect_vendor_specific_device( dev, ifnum, s ) &&
-		detect_yamaha_device( dev, intf, ifnum, s) ) {
-		kfree(s);
-		return -EIO;
-	}
-
-	down(&open_sem);
-	list_add_tail(&s->mididev, &mididevs);
-	up(&open_sem);
-
-	usb_set_intfdata (intf, s);
-	return 0;
-}
-
-
-static void usb_midi_disconnect(struct usb_interface *intf)
-{
-	struct usb_midi_state *s = usb_get_intfdata (intf);
-	struct usb_mididev    *m;
-
-	if ( !s )
-		return;
-
-	if ( s == (struct usb_midi_state *)-1 ) {
-		return;
-	}
-	if ( !s->usbdev ) {
-		return;
-	}
-	down(&open_sem);
-	list_del(&s->mididev);
-	INIT_LIST_HEAD(&s->mididev);
-	s->usbdev = NULL;
-	usb_set_intfdata (intf, NULL);
-
-	list_for_each_entry(m, &s->midiDevList, list) {
-		wake_up(&(m->min.ep->wait));
-		wake_up(&(m->mout.ep->wait));
-		if ( m->dev_midi >= 0 ) {
-			unregister_sound_midi(m->dev_midi);
-		}
-		m->dev_midi = -1;
-	}
-	release_midi_device(s);
-	wake_up(&open_wait);
-}
-
-/* we want to look at all devices by hand */
-static struct usb_device_id id_table[] = {
-	{.driver_info = 42},
-	{}
-};
-
-static struct usb_driver usb_midi_driver = {
-	.name =		"midi",
-	.probe =	usb_midi_probe,
-	.disconnect =	usb_midi_disconnect,
-	.id_table =	id_table,
-};
-
-/* ------------------------------------------------------------------------- */
-
-static int __init usb_midi_init(void)
-{
-	return usb_register(&usb_midi_driver);
-}
-
-static void __exit usb_midi_exit(void)
-{
-	usb_deregister(&usb_midi_driver);
-}
-
-module_init(usb_midi_init) ;
-module_exit(usb_midi_exit) ;
-
-#ifdef HAVE_ALSA_SUPPORT
-#define SNDRV_MAIN_OBJECT_FILE
-#include "../../include/driver.h"
-#include "../../include/control.h"
-#include "../../include/info.h"
-#include "../../include/cs46xx.h"
-
-/* ------------------------------------------------------------------------- */
-
-static int snd_usbmidi_input_close(snd_rawmidi_substream_t * substream)
-{
-	return 0;
-}
-
-static int snd_usbmidi_input_open(snd_rawmidi_substream_t * substream )
-{
-	return 0;
-}
-
-static void snd_usbmidi_input_trigger(snd_rawmidi_substream_t * substream, int up)
-{
-	return 0;
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-static int snd_usbmidi_output_close(snd_rawmidi_substream_t * substream)
-{
-	return 0;
-}
-
-static int snd_usbmidi_output_open(snd_rawmidi_substream_t * substream)
-{
-	return 0;
-}
-
-static void snd_usb_midi_output_trigger(snd_rawmidi_substream_t * substream,
-					int up)
-{
-	return 0;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static snd_rawmidi_ops_t snd_usbmidi_output =
-{
-        .open =         snd_usbmidi_output_open,
-        .close =        snd_usbmidi_output_close,
-        .trigger =      snd_usbmidi_output_trigger,
-};
-static snd_rawmidi_ops_t snd_usbmidi_input =
-{
-        .open =         snd_usbmidi_input_open,
-        .close =        snd_usbmidi_input_close,
-        .trigger =      snd_usbmidi_input_trigger,
-};
-
-int snd_usbmidi_midi(cs46xx_t *chip, int device, snd_rawmidi_t **rrawmidi)
-{
-	snd_rawmidi_t *rmidi;
-	int err;
-
-	if (rrawmidi)
-		*rrawmidi = NULL;
-	if ((err = snd_rawmidi_new(chip->card, "USB-MIDI", device, 1, 1, &rmidi)) < 0)
-		return err;
-	strcpy(rmidi->name, "USB-MIDI");
-
-	snd_rawmidi_set_ops( rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_usbmidi_output );
-	snd_rawmidi_set_ops( rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_usbmidi_input );
-
-	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
-
-	rmidi->private_data = chip;
-	chip->rmidi = rmidi;
-	if (rrawmidi)
-		*rrawmidi = NULL;
-
-	return 0;
-}
-
-int snd_usbmidi_create( snd_card_t * card,
-			struct pci_dev * pci,
-			usbmidi_t ** rchip )
-{
-	usbmidi_t *chip;
-	int err, idx;
-	snd_region_t *region;
-	static snd_device_opt_t ops = {
-		.dev_free = snd_usbmidi_dev_free,
-	};
-
-	*rchip = NULL;
-	chip = snd_magic_kcalloc( usbmidi_t, 0, GFP_KERNEL );
-	if ( chip == NULL )
-		return -ENOMEM;
-}
-
-EXPORT_SYMBOL(snd_usbmidi_create);
-EXPORT_SYMBOL(snd_usbmidi_midi);
-#endif /* HAVE_ALSA_SUPPORT */
-

+ 0 - 164
drivers/usb/class/usb-midi.h

@@ -1,164 +0,0 @@
-/*
-  usb-midi.h  --  USB-MIDI driver
-
-  Copyright (C) 2001
-      NAGANO Daisuke <breeze.nagano@nifty.ne.jp>
-
-  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, 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.
- */
-
-/* ------------------------------------------------------------------------- */
-
-#ifndef _USB_MIDI_H_
-#define _USB_MIDI_H_
-
-#ifndef USB_SUBCLASS_MIDISTREAMING
-#define USB_SUBCLASS_MIDISTREAMING	3
-#endif
-
-/* ------------------------------------------------------------------------- */
-/* Roland MIDI Devices */
-
-#define USB_VENDOR_ID_ROLAND		0x0582
-#define USBMIDI_ROLAND_UA100G		0x0000
-#define USBMIDI_ROLAND_MPU64		0x0002
-#define USBMIDI_ROLAND_SC8850		0x0003
-#define USBMIDI_ROLAND_SC8820		0x0007
-#define USBMIDI_ROLAND_UM2		0x0005
-#define USBMIDI_ROLAND_UM1		0x0009
-#define USBMIDI_ROLAND_PC300		0x0008
-
-/* YAMAHA MIDI Devices */
-#define USB_VENDOR_ID_YAMAHA		0x0499
-#define USBMIDI_YAMAHA_MU1000		0x1001
-
-/* Steinberg MIDI Devices */
-#define USB_VENDOR_ID_STEINBERG		0x0763
-#define USBMIDI_STEINBERG_USB2MIDI	0x1001
-
-/* Mark of the Unicorn MIDI Devices */
-#define USB_VENDOR_ID_MOTU		0x07fd
-#define USBMIDI_MOTU_FASTLANE		0x0001
-
-/* ------------------------------------------------------------------------- */
-/* Supported devices */
-
-struct usb_midi_endpoint {
-	int  endpoint;
-	int  cableId; /* if bit-n == 1 then cableId-n is enabled (n: 0 - 15) */
-};
-
-struct usb_midi_device {
-	char  *deviceName;
-
-	u16    idVendor;
-	u16    idProduct;
-	int    interface;
-	int    altSetting; /* -1: auto detect */
-
-	struct usb_midi_endpoint in[15];
-	struct usb_midi_endpoint out[15];
-};
-
-static struct usb_midi_device usb_midi_devices[] = {
-  { /* Roland UM-1 */
-    "Roland UM-1",
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1, 2, -1,
-    { { 0x81, 1 }, {-1, -1} },
-    { { 0x01, 1,}, {-1, -1} },
-  },
-
-  { /* Roland UM-2 */
-    "Roland UM-2" ,
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2, 2, -1,
-    { { 0x81, 3 }, {-1, -1} },
-    { { 0x01, 3,}, {-1, -1} },
-  },
-
-/** Next entry courtesy research by Michael Minn <michael@michaelminn.com> **/
-  { /* Roland UA-100 */
-    "Roland UA-100",
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G, 2, -1,
-    { { 0x82, 7 }, {-1, -1} }, /** cables 0,1 and 2 for SYSEX **/
-    { { 0x02, 7 }, {-1, -1} },
-  },
-
-/** Next entry courtesy research by Michael Minn <michael@michaelminn.com> **/
-  { /* Roland SC8850 */
-    "Roland SC8850",
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850, 2, -1,
-    { { 0x81, 0x3f }, {-1, -1} },
-    { { 0x01, 0x3f }, {-1, -1} },
-  },
-
-  { /* Roland SC8820 */
-    "Roland SC8820",
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820, 2, -1,
-    { { 0x81, 0x13 }, {-1, -1} },
-    { { 0x01, 0x13 }, {-1, -1} },
-  },
-
-  { /* Roland SC8820 */
-    "Roland SC8820",
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820, 2, -1,
-    { { 0x81, 17 }, {-1, -1} },
-    { { 0x01, 17 }, {-1, -1} },
-  },
-
-  { /* YAMAHA MU1000 */
-    "YAMAHA MU1000",
-    USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000, 0, -1, 
-    { { 0x81, 1 }, {-1, -1} },
-    { { 0x01, 15 }, {-1, -1} },
-  },
-  { /* Roland PC-300 */
-    "Roland PC-300",
-    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300, 2, -1, 
-    { { 0x81, 1 }, {-1, -1} },
-    { { 0x01, 1 }, {-1, -1} },
-  },
-  { /* MOTU Fastlane USB */
-    "MOTU Fastlane USB",
-    USB_VENDOR_ID_MOTU, USBMIDI_MOTU_FASTLANE, 1, 0,
-    { { 0x82, 3 }, {-1, -1} },
-    { { 0x02, 3 }, {-1, -1} },
-  }
-};
-
-#define VENDOR_SPECIFIC_USB_MIDI_DEVICES (sizeof(usb_midi_devices)/sizeof(struct usb_midi_device))
-
-/* for Hot-Plugging */
-
-static struct usb_device_id usb_midi_ids [] = {
-	{ .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
-	  .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING},
-	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1    ) },
-	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2    ) },
-	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G ) },
-	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300 ) },
-	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850 ) },
-	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820 ) },
-	{ USB_DEVICE( USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000 ) },
-	{ USB_DEVICE( USB_VENDOR_ID_MOTU,   USBMIDI_MOTU_FASTLANE ) },
-/*	{ USB_DEVICE( USB_VENDOR_ID_STEINBERG, USBMIDI_STEINBERG_USB2MIDI ) },*/
-	{ } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, usb_midi_ids);
-
-/* ------------------------------------------------------------------------- */
-#endif /* _USB_MIDI_H_ */
-
-

+ 8 - 7
drivers/usb/class/usblp.c

@@ -55,6 +55,7 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/lp.h>
 #include <linux/lp.h>
+#include <linux/mutex.h>
 #undef DEBUG
 #undef DEBUG
 #include <linux/usb.h>
 #include <linux/usb.h>
 
 
@@ -223,7 +224,7 @@ static int usblp_cache_device_id_string(struct usblp *usblp);
 
 
 /* forward reference to make our lives easier */
 /* forward reference to make our lives easier */
 static struct usb_driver usblp_driver;
 static struct usb_driver usblp_driver;
-static DECLARE_MUTEX(usblp_sem);	/* locks the existence of usblp's */
+static DEFINE_MUTEX(usblp_mutex);	/* locks the existence of usblp's */
 
 
 /*
 /*
  * Functions for usblp control messages.
  * Functions for usblp control messages.
@@ -351,7 +352,7 @@ static int usblp_open(struct inode *inode, struct file *file)
 	if (minor < 0)
 	if (minor < 0)
 		return -ENODEV;
 		return -ENODEV;
 
 
-	down (&usblp_sem);
+	mutex_lock (&usblp_mutex);
 
 
 	retval = -ENODEV;
 	retval = -ENODEV;
 	intf = usb_find_interface(&usblp_driver, minor);
 	intf = usb_find_interface(&usblp_driver, minor);
@@ -399,7 +400,7 @@ static int usblp_open(struct inode *inode, struct file *file)
 		}
 		}
 	}
 	}
 out:
 out:
-	up (&usblp_sem);
+	mutex_unlock (&usblp_mutex);
 	return retval;
 	return retval;
 }
 }
 
 
@@ -425,13 +426,13 @@ static int usblp_release(struct inode *inode, struct file *file)
 {
 {
 	struct usblp *usblp = file->private_data;
 	struct usblp *usblp = file->private_data;
 
 
-	down (&usblp_sem);
+	mutex_lock (&usblp_mutex);
 	usblp->used = 0;
 	usblp->used = 0;
 	if (usblp->present) {
 	if (usblp->present) {
 		usblp_unlink_urbs(usblp);
 		usblp_unlink_urbs(usblp);
 	} else 		/* finish cleanup from disconnect */
 	} else 		/* finish cleanup from disconnect */
 		usblp_cleanup (usblp);
 		usblp_cleanup (usblp);
-	up (&usblp_sem);
+	mutex_unlock (&usblp_mutex);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1152,7 +1153,7 @@ static void usblp_disconnect(struct usb_interface *intf)
 
 
 	device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
 	device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
 
 
-	down (&usblp_sem);
+	mutex_lock (&usblp_mutex);
 	down (&usblp->sem);
 	down (&usblp->sem);
 	usblp->present = 0;
 	usblp->present = 0;
 	usb_set_intfdata (intf, NULL);
 	usb_set_intfdata (intf, NULL);
@@ -1166,7 +1167,7 @@ static void usblp_disconnect(struct usb_interface *intf)
 
 
 	if (!usblp->used)
 	if (!usblp->used)
 		usblp_cleanup (usblp);
 		usblp_cleanup (usblp);
-	up (&usblp_sem);
+	mutex_unlock (&usblp_mutex);
 }
 }
 
 
 static struct usb_device_id usblp_ids [] = {
 static struct usb_device_id usblp_ids [] = {

+ 4 - 3
drivers/usb/core/devices.c

@@ -57,6 +57,7 @@
 #include <linux/usb.h>
 #include <linux/usb.h>
 #include <linux/smp_lock.h>
 #include <linux/smp_lock.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/usbdevice_fs.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 
 
 #include "usb.h"
 #include "usb.h"
@@ -570,7 +571,7 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte
 	if (!access_ok(VERIFY_WRITE, buf, nbytes))
 	if (!access_ok(VERIFY_WRITE, buf, nbytes))
 		return -EFAULT;
 		return -EFAULT;
 
 
-	down (&usb_bus_list_lock);
+	mutex_lock(&usb_bus_list_lock);
 	/* print devices for all busses */
 	/* print devices for all busses */
 	list_for_each_entry(bus, &usb_bus_list, bus_list) {
 	list_for_each_entry(bus, &usb_bus_list, bus_list) {
 		/* recurse through all children of the root hub */
 		/* recurse through all children of the root hub */
@@ -580,12 +581,12 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte
 		ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0);
 		ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0);
 		usb_unlock_device(bus->root_hub);
 		usb_unlock_device(bus->root_hub);
 		if (ret < 0) {
 		if (ret < 0) {
-			up(&usb_bus_list_lock);
+			mutex_unlock(&usb_bus_list_lock);
 			return ret;
 			return ret;
 		}
 		}
 		total_written += ret;
 		total_written += ret;
 	}
 	}
-	up (&usb_bus_list_lock);
+	mutex_unlock(&usb_bus_list_lock);
 	return total_written;
 	return total_written;
 }
 }
 
 

+ 10 - 14
drivers/usb/core/devio.c

@@ -134,26 +134,21 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l
 	}
 	}
 
 
 	if (pos < sizeof(struct usb_device_descriptor)) {
 	if (pos < sizeof(struct usb_device_descriptor)) {
-		struct usb_device_descriptor *desc = kmalloc(sizeof(*desc), GFP_KERNEL);
-		if (!desc) {
-			ret = -ENOMEM;
-			goto err;
-		}
-		memcpy(desc, &dev->descriptor, sizeof(dev->descriptor));
-		le16_to_cpus(&desc->bcdUSB);
-		le16_to_cpus(&desc->idVendor);
-		le16_to_cpus(&desc->idProduct);
-		le16_to_cpus(&desc->bcdDevice);
+		struct usb_device_descriptor temp_desc ; /* 18 bytes - fits on the stack */
+
+		memcpy(&temp_desc, &dev->descriptor, sizeof(dev->descriptor));
+		le16_to_cpus(&temp_desc.bcdUSB);
+		le16_to_cpus(&temp_desc.idVendor);
+		le16_to_cpus(&temp_desc.idProduct);
+		le16_to_cpus(&temp_desc.bcdDevice);
 
 
 		len = sizeof(struct usb_device_descriptor) - pos;
 		len = sizeof(struct usb_device_descriptor) - pos;
 		if (len > nbytes)
 		if (len > nbytes)
 			len = nbytes;
 			len = nbytes;
-		if (copy_to_user(buf, ((char *)desc) + pos, len)) {
-			kfree(desc);
+		if (copy_to_user(buf, ((char *)&temp_desc) + pos, len)) {
 			ret = -EFAULT;
 			ret = -EFAULT;
 			goto err;
 			goto err;
 		}
 		}
-		kfree(desc);
 
 
 		*ppos += len;
 		*ppos += len;
 		buf += len;
 		buf += len;
@@ -498,7 +493,8 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
 {
 {
 	int ret = 0;
 	int ret = 0;
 
 
-	if (ps->dev->state != USB_STATE_CONFIGURED)
+	if (ps->dev->state != USB_STATE_ADDRESS
+	 && ps->dev->state != USB_STATE_CONFIGURED)
 		return -EHOSTUNREACH;
 		return -EHOSTUNREACH;
 	if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
 	if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
 		return 0;
 		return 0;

+ 8 - 3
drivers/usb/core/hcd-pci.c

@@ -264,14 +264,19 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
 		 */
 		 */
 		retval = pci_set_power_state (dev, PCI_D3hot);
 		retval = pci_set_power_state (dev, PCI_D3hot);
 		if (retval == 0) {
 		if (retval == 0) {
-			dev_dbg (hcd->self.controller, "--> PCI D3\n");
+			int wake = device_can_wakeup(&hcd->self.root_hub->dev);
+
+			wake = wake && device_may_wakeup(hcd->self.controller);
+
+			dev_dbg (hcd->self.controller, "--> PCI D3%s\n",
+					wake ? "/wakeup" : "");
 
 
 			/* Ignore these return values.  We rely on pci code to
 			/* Ignore these return values.  We rely on pci code to
 			 * reject requests the hardware can't implement, rather
 			 * reject requests the hardware can't implement, rather
 			 * than coding the same thing.
 			 * than coding the same thing.
 			 */
 			 */
-			(void) pci_enable_wake (dev, PCI_D3hot, hcd->remote_wakeup);
-			(void) pci_enable_wake (dev, PCI_D3cold, hcd->remote_wakeup);
+			(void) pci_enable_wake (dev, PCI_D3hot, wake);
+			(void) pci_enable_wake (dev, PCI_D3cold, wake);
 		} else {
 		} else {
 			dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n",
 			dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n",
 					retval);
 					retval);

+ 85 - 68
drivers/usb/core/hcd.c

@@ -34,6 +34,7 @@
 #include <asm/scatterlist.h>
 #include <asm/scatterlist.h>
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
+#include <linux/mutex.h>
 #include <asm/irq.h>
 #include <asm/irq.h>
 #include <asm/byteorder.h>
 #include <asm/byteorder.h>
 
 
@@ -93,7 +94,7 @@ struct usb_busmap {
 static struct usb_busmap busmap;
 static struct usb_busmap busmap;
 
 
 /* used when updating list of hcds */
 /* used when updating list of hcds */
-DECLARE_MUTEX (usb_bus_list_lock);	/* exported only for usbfs */
+DEFINE_MUTEX(usb_bus_list_lock);	/* exported only for usbfs */
 EXPORT_SYMBOL_GPL (usb_bus_list_lock);
 EXPORT_SYMBOL_GPL (usb_bus_list_lock);
 
 
 /* used for controlling access to virtual root hubs */
 /* used for controlling access to virtual root hubs */
@@ -366,21 +367,39 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
 
 
 	/* DEVICE REQUESTS */
 	/* DEVICE REQUESTS */
 
 
+	/* The root hub's remote wakeup enable bit is implemented using
+	 * driver model wakeup flags.  If this system supports wakeup
+	 * through USB, userspace may change the default "allow wakeup"
+	 * policy through sysfs or these calls.
+	 *
+	 * Most root hubs support wakeup from downstream devices, for
+	 * runtime power management (disabling USB clocks and reducing
+	 * VBUS power usage).  However, not all of them do so; silicon,
+	 * board, and BIOS bugs here are not uncommon, so these can't
+	 * be treated quite like external hubs.
+	 *
+	 * Likewise, not all root hubs will pass wakeup events upstream,
+	 * to wake up the whole system.  So don't assume root hub and
+	 * controller capabilities are identical.
+	 */
+
 	case DeviceRequest | USB_REQ_GET_STATUS:
 	case DeviceRequest | USB_REQ_GET_STATUS:
-		tbuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP)
+		tbuf [0] = (device_may_wakeup(&hcd->self.root_hub->dev)
+					<< USB_DEVICE_REMOTE_WAKEUP)
 				| (1 << USB_DEVICE_SELF_POWERED);
 				| (1 << USB_DEVICE_SELF_POWERED);
 		tbuf [1] = 0;
 		tbuf [1] = 0;
 		len = 2;
 		len = 2;
 		break;
 		break;
 	case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
 	case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
 		if (wValue == USB_DEVICE_REMOTE_WAKEUP)
 		if (wValue == USB_DEVICE_REMOTE_WAKEUP)
-			hcd->remote_wakeup = 0;
+			device_set_wakeup_enable(&hcd->self.root_hub->dev, 0);
 		else
 		else
 			goto error;
 			goto error;
 		break;
 		break;
 	case DeviceOutRequest | USB_REQ_SET_FEATURE:
 	case DeviceOutRequest | USB_REQ_SET_FEATURE:
-		if (hcd->can_wakeup && wValue == USB_DEVICE_REMOTE_WAKEUP)
-			hcd->remote_wakeup = 1;
+		if (device_can_wakeup(&hcd->self.root_hub->dev)
+				&& wValue == USB_DEVICE_REMOTE_WAKEUP)
+			device_set_wakeup_enable(&hcd->self.root_hub->dev, 1);
 		else
 		else
 			goto error;
 			goto error;
 		break;
 		break;
@@ -409,7 +428,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
 				bufp = fs_rh_config_descriptor;
 				bufp = fs_rh_config_descriptor;
 				len = sizeof fs_rh_config_descriptor;
 				len = sizeof fs_rh_config_descriptor;
 			}
 			}
-			if (hcd->can_wakeup)
+			if (device_can_wakeup(&hcd->self.root_hub->dev))
 				patch_wakeup = 1;
 				patch_wakeup = 1;
 			break;
 			break;
 		case USB_DT_STRING << 8:
 		case USB_DT_STRING << 8:
@@ -761,14 +780,14 @@ static int usb_register_bus(struct usb_bus *bus)
 {
 {
 	int busnum;
 	int busnum;
 
 
-	down (&usb_bus_list_lock);
+	mutex_lock(&usb_bus_list_lock);
 	busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
 	busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
 	if (busnum < USB_MAXBUS) {
 	if (busnum < USB_MAXBUS) {
 		set_bit (busnum, busmap.busmap);
 		set_bit (busnum, busmap.busmap);
 		bus->busnum = busnum;
 		bus->busnum = busnum;
 	} else {
 	} else {
 		printk (KERN_ERR "%s: too many buses\n", usbcore_name);
 		printk (KERN_ERR "%s: too many buses\n", usbcore_name);
-		up(&usb_bus_list_lock);
+		mutex_unlock(&usb_bus_list_lock);
 		return -E2BIG;
 		return -E2BIG;
 	}
 	}
 
 
@@ -776,7 +795,7 @@ static int usb_register_bus(struct usb_bus *bus)
 					     bus->controller, "usb_host%d", busnum);
 					     bus->controller, "usb_host%d", busnum);
 	if (IS_ERR(bus->class_dev)) {
 	if (IS_ERR(bus->class_dev)) {
 		clear_bit(busnum, busmap.busmap);
 		clear_bit(busnum, busmap.busmap);
-		up(&usb_bus_list_lock);
+		mutex_unlock(&usb_bus_list_lock);
 		return PTR_ERR(bus->class_dev);
 		return PTR_ERR(bus->class_dev);
 	}
 	}
 
 
@@ -784,7 +803,7 @@ static int usb_register_bus(struct usb_bus *bus)
 
 
 	/* Add it to the local list of buses */
 	/* Add it to the local list of buses */
 	list_add (&bus->bus_list, &usb_bus_list);
 	list_add (&bus->bus_list, &usb_bus_list);
-	up (&usb_bus_list_lock);
+	mutex_unlock(&usb_bus_list_lock);
 
 
 	usb_notify_add_bus(bus);
 	usb_notify_add_bus(bus);
 
 
@@ -809,9 +828,9 @@ static void usb_deregister_bus (struct usb_bus *bus)
 	 * controller code, as well as having it call this when cleaning
 	 * controller code, as well as having it call this when cleaning
 	 * itself up
 	 * itself up
 	 */
 	 */
-	down (&usb_bus_list_lock);
+	mutex_lock(&usb_bus_list_lock);
 	list_del (&bus->bus_list);
 	list_del (&bus->bus_list);
-	up (&usb_bus_list_lock);
+	mutex_unlock(&usb_bus_list_lock);
 
 
 	usb_notify_remove_bus(bus);
 	usb_notify_remove_bus(bus);
 
 
@@ -822,18 +841,17 @@ static void usb_deregister_bus (struct usb_bus *bus)
 
 
 /**
 /**
  * register_root_hub - called by usb_add_hcd() to register a root hub
  * register_root_hub - called by usb_add_hcd() to register a root hub
- * @usb_dev: the usb root hub device to be registered.
  * @hcd: host controller for this root hub
  * @hcd: host controller for this root hub
  *
  *
  * This function registers the root hub with the USB subsystem.  It sets up
  * This function registers the root hub with the USB subsystem.  It sets up
- * the device properly in the device tree and stores the root_hub pointer
- * in the bus structure, then calls usb_new_device() to register the usb
- * device.  It also assigns the root hub's USB address (always 1).
+ * the device properly in the device tree and then calls usb_new_device()
+ * to register the usb device.  It also assigns the root hub's USB address
+ * (always 1).
  */
  */
-static int register_root_hub (struct usb_device *usb_dev,
-		struct usb_hcd *hcd)
+static int register_root_hub(struct usb_hcd *hcd)
 {
 {
 	struct device *parent_dev = hcd->self.controller;
 	struct device *parent_dev = hcd->self.controller;
+	struct usb_device *usb_dev = hcd->self.root_hub;
 	const int devnum = 1;
 	const int devnum = 1;
 	int retval;
 	int retval;
 
 
@@ -844,14 +862,12 @@ static int register_root_hub (struct usb_device *usb_dev,
 	set_bit (devnum, usb_dev->bus->devmap.devicemap);
 	set_bit (devnum, usb_dev->bus->devmap.devicemap);
 	usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
 	usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
 
 
-	down (&usb_bus_list_lock);
-	usb_dev->bus->root_hub = usb_dev;
+	mutex_lock(&usb_bus_list_lock);
 
 
 	usb_dev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
 	usb_dev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
 	retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
 	retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
 	if (retval != sizeof usb_dev->descriptor) {
 	if (retval != sizeof usb_dev->descriptor) {
-		usb_dev->bus->root_hub = NULL;
-		up (&usb_bus_list_lock);
+		mutex_unlock(&usb_bus_list_lock);
 		dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
 		dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
 				usb_dev->dev.bus_id, retval);
 				usb_dev->dev.bus_id, retval);
 		return (retval < 0) ? retval : -EMSGSIZE;
 		return (retval < 0) ? retval : -EMSGSIZE;
@@ -859,11 +875,10 @@ static int register_root_hub (struct usb_device *usb_dev,
 
 
 	retval = usb_new_device (usb_dev);
 	retval = usb_new_device (usb_dev);
 	if (retval) {
 	if (retval) {
-		usb_dev->bus->root_hub = NULL;
 		dev_err (parent_dev, "can't register root hub for %s, %d\n",
 		dev_err (parent_dev, "can't register root hub for %s, %d\n",
 				usb_dev->dev.bus_id, retval);
 				usb_dev->dev.bus_id, retval);
 	}
 	}
-	up (&usb_bus_list_lock);
+	mutex_unlock(&usb_bus_list_lock);
 
 
 	if (retval == 0) {
 	if (retval == 0) {
 		spin_lock_irq (&hcd_root_hub_lock);
 		spin_lock_irq (&hcd_root_hub_lock);
@@ -1090,7 +1105,6 @@ static void urb_unlink (struct urb *urb)
 	spin_lock_irqsave (&hcd_data_lock, flags);
 	spin_lock_irqsave (&hcd_data_lock, flags);
 	list_del_init (&urb->urb_list);
 	list_del_init (&urb->urb_list);
 	spin_unlock_irqrestore (&hcd_data_lock, flags);
 	spin_unlock_irqrestore (&hcd_data_lock, flags);
-	usb_put_dev (urb->dev);
 }
 }
 
 
 
 
@@ -1130,7 +1144,6 @@ static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
 	case HC_STATE_RUNNING:
 	case HC_STATE_RUNNING:
 	case HC_STATE_RESUMING:
 	case HC_STATE_RESUMING:
 doit:
 doit:
-		usb_get_dev (urb->dev);
 		list_add_tail (&urb->urb_list, &ep->urb_list);
 		list_add_tail (&urb->urb_list, &ep->urb_list);
 		status = 0;
 		status = 0;
 		break;
 		break;
@@ -1771,12 +1784,10 @@ int usb_add_hcd(struct usb_hcd *hcd,
 
 
 	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 
 
-	/* till now HC has been in an indeterminate state ... */
-	if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
-		dev_err(hcd->self.controller, "can't reset\n");
-		return retval;
-	}
-
+	/* HC is in reset state, but accessible.  Now do the one-time init,
+	 * bottom up so that hcds can customize the root hubs before khubd
+	 * starts talking to them.  (Note, bus id is assigned early too.)
+	 */
 	if ((retval = hcd_buffer_create(hcd)) != 0) {
 	if ((retval = hcd_buffer_create(hcd)) != 0) {
 		dev_dbg(hcd->self.controller, "pool alloc failed\n");
 		dev_dbg(hcd->self.controller, "pool alloc failed\n");
 		return retval;
 		return retval;
@@ -1785,6 +1796,36 @@ int usb_add_hcd(struct usb_hcd *hcd,
 	if ((retval = usb_register_bus(&hcd->self)) < 0)
 	if ((retval = usb_register_bus(&hcd->self)) < 0)
 		goto err_register_bus;
 		goto err_register_bus;
 
 
+	if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
+		dev_err(hcd->self.controller, "unable to allocate root hub\n");
+		retval = -ENOMEM;
+		goto err_allocate_root_hub;
+	}
+	rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
+			USB_SPEED_FULL;
+	hcd->self.root_hub = rhdev;
+
+	/* "reset" is misnamed; its role is now one-time init. the controller
+	 * should already have been reset (and boot firmware kicked off etc).
+	 */
+	if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
+		dev_err(hcd->self.controller, "can't setup\n");
+		goto err_hcd_driver_setup;
+	}
+
+	/* wakeup flag init is in transition; for now we can't rely on PCI to
+	 * initialize these bits properly, so we let reset() override it.
+	 * This init should _precede_ the reset() once PCI behaves.
+	 */
+	device_init_wakeup(&rhdev->dev,
+			device_can_wakeup(hcd->self.controller));
+
+	/* NOTE: root hub and controller capabilities may not be the same */
+	if (device_can_wakeup(hcd->self.controller)
+			&& device_can_wakeup(&hcd->self.root_hub->dev))
+		dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
+
+	/* enable irqs just before we start the controller */
 	if (hcd->driver->irq) {
 	if (hcd->driver->irq) {
 		char	buf[8], *bufp = buf;
 		char	buf[8], *bufp = buf;
 
 
@@ -1816,56 +1857,32 @@ int usb_add_hcd(struct usb_hcd *hcd,
 					(unsigned long long)hcd->rsrc_start);
 					(unsigned long long)hcd->rsrc_start);
 	}
 	}
 
 
-	/* Allocate the root hub before calling hcd->driver->start(),
-	 * but don't register it until afterward so that the hardware
-	 * is running.
-	 */
-	if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
-		dev_err(hcd->self.controller, "unable to allocate root hub\n");
-		retval = -ENOMEM;
-		goto err_allocate_root_hub;
-	}
-
-	/* Although in principle hcd->driver->start() might need to use rhdev,
-	 * none of the current drivers do.
-	 */
 	if ((retval = hcd->driver->start(hcd)) < 0) {
 	if ((retval = hcd->driver->start(hcd)) < 0) {
 		dev_err(hcd->self.controller, "startup error %d\n", retval);
 		dev_err(hcd->self.controller, "startup error %d\n", retval);
 		goto err_hcd_driver_start;
 		goto err_hcd_driver_start;
 	}
 	}
 
 
-	/* hcd->driver->start() reported can_wakeup, probably with
-	 * assistance from board's boot firmware.
-	 * NOTE:  normal devices won't enable wakeup by default.
-	 */
-	if (hcd->can_wakeup)
-		dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
-	hcd->remote_wakeup = hcd->can_wakeup;
-
-	rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
-			USB_SPEED_FULL;
+	/* starting here, usbcore will pay attention to this root hub */
 	rhdev->bus_mA = min(500u, hcd->power_budget);
 	rhdev->bus_mA = min(500u, hcd->power_budget);
-	if ((retval = register_root_hub(rhdev, hcd)) != 0)
+	if ((retval = register_root_hub(hcd)) != 0)
 		goto err_register_root_hub;
 		goto err_register_root_hub;
 
 
 	if (hcd->uses_new_polling && hcd->poll_rh)
 	if (hcd->uses_new_polling && hcd->poll_rh)
 		usb_hcd_poll_rh_status(hcd);
 		usb_hcd_poll_rh_status(hcd);
 	return retval;
 	return retval;
 
 
- err_register_root_hub:
+err_register_root_hub:
 	hcd->driver->stop(hcd);
 	hcd->driver->stop(hcd);
-
- err_hcd_driver_start:
-	usb_put_dev(rhdev);
-
- err_allocate_root_hub:
+err_hcd_driver_start:
 	if (hcd->irq >= 0)
 	if (hcd->irq >= 0)
 		free_irq(irqnum, hcd);
 		free_irq(irqnum, hcd);
-
- err_request_irq:
+err_request_irq:
+err_hcd_driver_setup:
+	hcd->self.root_hub = NULL;
+	usb_put_dev(rhdev);
+err_allocate_root_hub:
 	usb_deregister_bus(&hcd->self);
 	usb_deregister_bus(&hcd->self);
-
- err_register_bus:
+err_register_bus:
 	hcd_buffer_destroy(hcd);
 	hcd_buffer_destroy(hcd);
 	return retval;
 	return retval;
 } 
 } 
@@ -1891,9 +1908,9 @@ void usb_remove_hcd(struct usb_hcd *hcd)
 	hcd->rh_registered = 0;
 	hcd->rh_registered = 0;
 	spin_unlock_irq (&hcd_root_hub_lock);
 	spin_unlock_irq (&hcd_root_hub_lock);
 
 
-	down(&usb_bus_list_lock);
+	mutex_lock(&usb_bus_list_lock);
 	usb_disconnect(&hcd->self.root_hub);
 	usb_disconnect(&hcd->self.root_hub);
-	up(&usb_bus_list_lock);
+	mutex_unlock(&usb_bus_list_lock);
 
 
 	hcd->poll_rh = 0;
 	hcd->poll_rh = 0;
 	del_timer_sync(&hcd->rh_timer);
 	del_timer_sync(&hcd->rh_timer);

+ 1 - 3
drivers/usb/core/hcd.h

@@ -78,8 +78,6 @@ struct usb_hcd {	/* usb_bus.hcpriv points to this */
 #define HCD_FLAG_HW_ACCESSIBLE	0x00000001
 #define HCD_FLAG_HW_ACCESSIBLE	0x00000001
 #define HCD_FLAG_SAW_IRQ	0x00000002
 #define HCD_FLAG_SAW_IRQ	0x00000002
 
 
-	unsigned		can_wakeup:1;	/* hw supports wakeup? */
-	unsigned		remote_wakeup:1;/* sw should use wakeup? */
 	unsigned		rh_registered:1;/* is root hub registered? */
 	unsigned		rh_registered:1;/* is root hub registered? */
 
 
 	/* The next flag is a stopgap, to be removed when all the HCDs
 	/* The next flag is a stopgap, to be removed when all the HCDs
@@ -364,7 +362,7 @@ extern void usb_set_device_state(struct usb_device *udev,
 /* exported only within usbcore */
 /* exported only within usbcore */
 
 
 extern struct list_head usb_bus_list;
 extern struct list_head usb_bus_list;
-extern struct semaphore usb_bus_list_lock;
+extern struct mutex usb_bus_list_lock;
 extern wait_queue_head_t usb_kill_urb_queue;
 extern wait_queue_head_t usb_kill_urb_queue;
 
 
 extern struct usb_bus *usb_bus_get (struct usb_bus *bus);
 extern struct usb_bus *usb_bus_get (struct usb_bus *bus);

+ 28 - 17
drivers/usb/core/hub.c

@@ -22,6 +22,7 @@
 #include <linux/usb.h>
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/kthread.h>
 #include <linux/kthread.h>
+#include <linux/mutex.h>
 
 
 #include <asm/semaphore.h>
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
@@ -1005,12 +1006,18 @@ void usb_set_device_state(struct usb_device *udev,
 		;	/* do nothing */
 		;	/* do nothing */
 	else if (new_state != USB_STATE_NOTATTACHED) {
 	else if (new_state != USB_STATE_NOTATTACHED) {
 		udev->state = new_state;
 		udev->state = new_state;
-		if (new_state == USB_STATE_CONFIGURED)
-			device_init_wakeup(&udev->dev,
-				(udev->actconfig->desc.bmAttributes
-				 & USB_CONFIG_ATT_WAKEUP));
-		else if (new_state != USB_STATE_SUSPENDED)
-			device_init_wakeup(&udev->dev, 0);
+
+		/* root hub wakeup capabilities are managed out-of-band
+		 * and may involve silicon errata ... ignore them here.
+		 */
+		if (udev->parent) {
+			if (new_state == USB_STATE_CONFIGURED)
+				device_init_wakeup(&udev->dev,
+					(udev->actconfig->desc.bmAttributes
+					 & USB_CONFIG_ATT_WAKEUP));
+			else if (new_state != USB_STATE_SUSPENDED)
+				device_init_wakeup(&udev->dev, 0);
+		}
 	} else
 	} else
 		recursively_mark_NOTATTACHED(udev);
 		recursively_mark_NOTATTACHED(udev);
 	spin_unlock_irqrestore(&device_state_lock, flags);
 	spin_unlock_irqrestore(&device_state_lock, flags);
@@ -1172,8 +1179,11 @@ static int choose_configuration(struct usb_device *udev)
 	c = udev->config;
 	c = udev->config;
 	num_configs = udev->descriptor.bNumConfigurations;
 	num_configs = udev->descriptor.bNumConfigurations;
 	for (i = 0; i < num_configs; (i++, c++)) {
 	for (i = 0; i < num_configs; (i++, c++)) {
-		struct usb_interface_descriptor	*desc =
-				&c->intf_cache[0]->altsetting->desc;
+		struct usb_interface_descriptor	*desc = NULL;
+
+		/* It's possible that a config has no interfaces! */
+		if (c->desc.bNumInterfaces > 0)
+			desc = &c->intf_cache[0]->altsetting->desc;
 
 
 		/*
 		/*
 		 * HP's USB bus-powered keyboard has only one configuration
 		 * HP's USB bus-powered keyboard has only one configuration
@@ -1208,7 +1218,8 @@ static int choose_configuration(struct usb_device *udev)
 		/* If the first config's first interface is COMM/2/0xff
 		/* If the first config's first interface is COMM/2/0xff
 		 * (MSFT RNDIS), rule it out unless Linux has host-side
 		 * (MSFT RNDIS), rule it out unless Linux has host-side
 		 * RNDIS support. */
 		 * RNDIS support. */
-		if (i == 0 && desc->bInterfaceClass == USB_CLASS_COMM
+		if (i == 0 && desc
+				&& desc->bInterfaceClass == USB_CLASS_COMM
 				&& desc->bInterfaceSubClass == 2
 				&& desc->bInterfaceSubClass == 2
 				&& desc->bInterfaceProtocol == 0xff) {
 				&& desc->bInterfaceProtocol == 0xff) {
 #ifndef CONFIG_USB_NET_RNDIS
 #ifndef CONFIG_USB_NET_RNDIS
@@ -1224,8 +1235,8 @@ static int choose_configuration(struct usb_device *udev)
 		 * than a vendor-specific driver. */
 		 * than a vendor-specific driver. */
 		else if (udev->descriptor.bDeviceClass !=
 		else if (udev->descriptor.bDeviceClass !=
 						USB_CLASS_VENDOR_SPEC &&
 						USB_CLASS_VENDOR_SPEC &&
-				desc->bInterfaceClass !=
-						USB_CLASS_VENDOR_SPEC) {
+				(!desc || desc->bInterfaceClass !=
+						USB_CLASS_VENDOR_SPEC)) {
 			best = c;
 			best = c;
 			break;
 			break;
 		}
 		}
@@ -1876,18 +1887,18 @@ int usb_resume_device(struct usb_device *udev)
 	if (udev->state == USB_STATE_NOTATTACHED)
 	if (udev->state == USB_STATE_NOTATTACHED)
 		return -ENODEV;
 		return -ENODEV;
 
 
-#ifdef	CONFIG_USB_SUSPEND
 	/* selective resume of one downstream hub-to-device port */
 	/* selective resume of one downstream hub-to-device port */
 	if (udev->parent) {
 	if (udev->parent) {
+#ifdef	CONFIG_USB_SUSPEND
 		if (udev->state == USB_STATE_SUSPENDED) {
 		if (udev->state == USB_STATE_SUSPENDED) {
 			// NOTE swsusp may bork us, device state being wrong...
 			// NOTE swsusp may bork us, device state being wrong...
 			// NOTE this fails if parent is also suspended...
 			// NOTE this fails if parent is also suspended...
 			status = hub_port_resume(hdev_to_hub(udev->parent),
 			status = hub_port_resume(hdev_to_hub(udev->parent),
 					udev->portnum, udev);
 					udev->portnum, udev);
 		} else
 		} else
+#endif
 			status = 0;
 			status = 0;
 	} else
 	} else
-#endif
 		status = finish_device_resume(udev);
 		status = finish_device_resume(udev);
 	if (status < 0)
 	if (status < 0)
 		dev_dbg(&udev->dev, "can't resume, status %d\n",
 		dev_dbg(&udev->dev, "can't resume, status %d\n",
@@ -2162,7 +2173,7 @@ static int
 hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 		int retry_counter)
 		int retry_counter)
 {
 {
-	static DECLARE_MUTEX(usb_address0_sem);
+	static DEFINE_MUTEX(usb_address0_mutex);
 
 
 	struct usb_device	*hdev = hub->hdev;
 	struct usb_device	*hdev = hub->hdev;
 	int			i, j, retval;
 	int			i, j, retval;
@@ -2183,7 +2194,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 	if (oldspeed == USB_SPEED_LOW)
 	if (oldspeed == USB_SPEED_LOW)
 		delay = HUB_LONG_RESET_TIME;
 		delay = HUB_LONG_RESET_TIME;
 
 
-	down(&usb_address0_sem);
+	mutex_lock(&usb_address0_mutex);
 
 
 	/* Reset the device; full speed may morph to high speed */
 	/* Reset the device; full speed may morph to high speed */
 	retval = hub_port_reset(hub, port1, udev, delay);
 	retval = hub_port_reset(hub, port1, udev, delay);
@@ -2381,7 +2392,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 fail:
 fail:
 	if (retval)
 	if (retval)
 		hub_port_disable(hub, port1, 0);
 		hub_port_disable(hub, port1, 0);
-	up(&usb_address0_sem);
+	mutex_unlock(&usb_address0_mutex);
 	return retval;
 	return retval;
 }
 }
 
 
@@ -3017,7 +3028,7 @@ int usb_reset_device(struct usb_device *udev)
 	parent_hub = hdev_to_hub(parent_hdev);
 	parent_hub = hdev_to_hub(parent_hdev);
 
 
 	/* If we're resetting an active hub, take some special actions */
 	/* If we're resetting an active hub, take some special actions */
-	if (udev->actconfig &&
+	if (udev->actconfig && udev->actconfig->desc.bNumInterfaces > 0 &&
 			udev->actconfig->interface[0]->dev.driver ==
 			udev->actconfig->interface[0]->dev.driver ==
 				&hub_driver.driver &&
 				&hub_driver.driver &&
 			(hub = hdev_to_hub(udev)) != NULL) {
 			(hub = hdev_to_hub(udev)) != NULL) {

+ 9 - 8
drivers/usb/core/message.c

@@ -631,8 +631,8 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char
  * Returns the number of bytes received on success, or else the status code
  * Returns the number of bytes received on success, or else the status code
  * returned by the underlying usb_control_msg() call.
  * returned by the underlying usb_control_msg() call.
  */
  */
-int usb_get_string(struct usb_device *dev, unsigned short langid,
-		unsigned char index, void *buf, int size)
+static int usb_get_string(struct usb_device *dev, unsigned short langid,
+			  unsigned char index, void *buf, int size)
 {
 {
 	int i;
 	int i;
 	int result;
 	int result;
@@ -1388,11 +1388,13 @@ free_interfaces:
 	if (dev->state != USB_STATE_ADDRESS)
 	if (dev->state != USB_STATE_ADDRESS)
 		usb_disable_device (dev, 1);	// Skip ep0
 		usb_disable_device (dev, 1);	// Skip ep0
 
 
-	i = dev->bus_mA - cp->desc.bMaxPower * 2;
-	if (i < 0)
-		dev_warn(&dev->dev, "new config #%d exceeds power "
-				"limit by %dmA\n",
-				configuration, -i);
+	if (cp) {
+		i = dev->bus_mA - cp->desc.bMaxPower * 2;
+		if (i < 0)
+			dev_warn(&dev->dev, "new config #%d exceeds power "
+					"limit by %dmA\n",
+					configuration, -i);
+	}
 
 
 	if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 	if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 			USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
 			USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
@@ -1488,7 +1490,6 @@ EXPORT_SYMBOL(usb_sg_wait);
 // synchronous control message convenience routines
 // synchronous control message convenience routines
 EXPORT_SYMBOL(usb_get_descriptor);
 EXPORT_SYMBOL(usb_get_descriptor);
 EXPORT_SYMBOL(usb_get_status);
 EXPORT_SYMBOL(usb_get_status);
-EXPORT_SYMBOL(usb_get_string);
 EXPORT_SYMBOL(usb_string);
 EXPORT_SYMBOL(usb_string);
 
 
 // synchronous calls that also maintain usbcore state
 // synchronous calls that also maintain usbcore state

+ 8 - 7
drivers/usb/core/notify.c

@@ -13,16 +13,17 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/notifier.h>
 #include <linux/notifier.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 #include "usb.h"
 #include "usb.h"
 
 
 
 
 static struct notifier_block *usb_notifier_list;
 static struct notifier_block *usb_notifier_list;
-static DECLARE_MUTEX(usb_notifier_lock);
+static DEFINE_MUTEX(usb_notifier_lock);
 
 
 static void usb_notifier_chain_register(struct notifier_block **list,
 static void usb_notifier_chain_register(struct notifier_block **list,
 					struct notifier_block *n)
 					struct notifier_block *n)
 {
 {
-	down(&usb_notifier_lock);
+	mutex_lock(&usb_notifier_lock);
 	while (*list) {
 	while (*list) {
 		if (n->priority > (*list)->priority)
 		if (n->priority > (*list)->priority)
 			break;
 			break;
@@ -30,13 +31,13 @@ static void usb_notifier_chain_register(struct notifier_block **list,
 	}
 	}
 	n->next = *list;
 	n->next = *list;
 	*list = n;
 	*list = n;
-	up(&usb_notifier_lock);
+	mutex_unlock(&usb_notifier_lock);
 }
 }
 
 
 static void usb_notifier_chain_unregister(struct notifier_block **nl,
 static void usb_notifier_chain_unregister(struct notifier_block **nl,
 				   struct notifier_block *n)
 				   struct notifier_block *n)
 {
 {
-	down(&usb_notifier_lock);
+	mutex_lock(&usb_notifier_lock);
 	while ((*nl)!=NULL) {
 	while ((*nl)!=NULL) {
 		if ((*nl)==n) {
 		if ((*nl)==n) {
 			*nl = n->next;
 			*nl = n->next;
@@ -45,7 +46,7 @@ static void usb_notifier_chain_unregister(struct notifier_block **nl,
 		nl=&((*nl)->next);
 		nl=&((*nl)->next);
 	}
 	}
 exit:
 exit:
-	up(&usb_notifier_lock);
+	mutex_unlock(&usb_notifier_lock);
 }
 }
 
 
 static int usb_notifier_call_chain(struct notifier_block **n,
 static int usb_notifier_call_chain(struct notifier_block **n,
@@ -54,7 +55,7 @@ static int usb_notifier_call_chain(struct notifier_block **n,
 	int ret=NOTIFY_DONE;
 	int ret=NOTIFY_DONE;
 	struct notifier_block *nb = *n;
 	struct notifier_block *nb = *n;
 
 
-	down(&usb_notifier_lock);
+	mutex_lock(&usb_notifier_lock);
 	while (nb) {
 	while (nb) {
 		ret = nb->notifier_call(nb,val,v);
 		ret = nb->notifier_call(nb,val,v);
 		if (ret&NOTIFY_STOP_MASK) {
 		if (ret&NOTIFY_STOP_MASK) {
@@ -63,7 +64,7 @@ static int usb_notifier_call_chain(struct notifier_block **n,
 		nb = nb->next;
 		nb = nb->next;
 	}
 	}
 exit:
 exit:
-	up(&usb_notifier_lock);
+	mutex_unlock(&usb_notifier_lock);
 	return ret;
 	return ret;
 }
 }
 
 

+ 3 - 2
drivers/usb/core/usb.c

@@ -33,6 +33,7 @@
 #include <linux/errno.h>
 #include <linux/errno.h>
 #include <linux/smp_lock.h>
 #include <linux/smp_lock.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 
 
 #include <asm/io.h>
 #include <asm/io.h>
 #include <asm/scatterlist.h>
 #include <asm/scatterlist.h>
@@ -639,7 +640,7 @@ struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
 	struct usb_bus *bus;
 	struct usb_bus *bus;
 	struct usb_device *dev = NULL;
 	struct usb_device *dev = NULL;
 	
 	
-	down(&usb_bus_list_lock);
+	mutex_lock(&usb_bus_list_lock);
 	for (buslist = usb_bus_list.next;
 	for (buslist = usb_bus_list.next;
 	     buslist != &usb_bus_list; 
 	     buslist != &usb_bus_list; 
 	     buslist = buslist->next) {
 	     buslist = buslist->next) {
@@ -653,7 +654,7 @@ struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
 			goto exit;
 			goto exit;
 	}
 	}
 exit:
 exit:
-	up(&usb_bus_list_lock);
+	mutex_unlock(&usb_bus_list_lock);
 	return dev;
 	return dev;
 }
 }
 
 

+ 17 - 0
drivers/usb/gadget/Kconfig

@@ -187,6 +187,23 @@ config USB_OTG
 
 
 	   Select this only if your OMAP board has a Mini-AB connector.
 	   Select this only if your OMAP board has a Mini-AB connector.
 
 
+config USB_GADGET_AT91
+	boolean "AT91 USB Device Port"
+	depends on ARCH_AT91RM9200
+	select USB_GADGET_SELECTED
+	help
+	   Many Atmel AT91 processors (such as the AT91RM2000) have a
+	   full speed USB Device Port with support for five configurable
+	   endpoints (plus endpoint zero).
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "at91_udc" and force all
+	   gadget drivers to also be dynamically linked.
+
+config USB_AT91
+	tristate
+	depends on USB_GADGET_AT91
+	default USB_GADGET
 
 
 config USB_GADGET_DUMMY_HCD
 config USB_GADGET_DUMMY_HCD
 	boolean "Dummy HCD (DEVELOPMENT)"
 	boolean "Dummy HCD (DEVELOPMENT)"

+ 1 - 0
drivers/usb/gadget/Makefile

@@ -7,6 +7,7 @@ obj-$(CONFIG_USB_PXA2XX)	+= pxa2xx_udc.o
 obj-$(CONFIG_USB_GOKU)		+= goku_udc.o
 obj-$(CONFIG_USB_GOKU)		+= goku_udc.o
 obj-$(CONFIG_USB_OMAP)		+= omap_udc.o
 obj-$(CONFIG_USB_OMAP)		+= omap_udc.o
 obj-$(CONFIG_USB_LH7A40X)	+= lh7a40x_udc.o
 obj-$(CONFIG_USB_LH7A40X)	+= lh7a40x_udc.o
+obj-$(CONFIG_USB_AT91)		+= at91_udc.o
 
 
 #
 #
 # USB gadget drivers
 # USB gadget drivers

+ 1773 - 0
drivers/usb/gadget/at91_udc.c

@@ -0,0 +1,1773 @@
+/*
+ * at91_udc -- driver for at91-series USB peripheral controller
+ *
+ * Copyright (C) 2004 by Thomas Rathbone
+ * Copyright (C) 2005 by HP Labs
+ * Copyright (C) 2005 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA  02111-1307, USA.
+ */
+
+#undef	DEBUG
+#undef	VERBOSE
+#undef	PACKET_TRACE
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/clk.h>
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/board.h>
+
+#include "at91_udc.h"
+
+
+/*
+ * This controller is simple and PIO-only.  It's used in many AT91-series
+ * ARMv4T controllers, including the at91rm9200 (arm920T, with MMU),
+ * at91sam9261 (arm926ejs, with MMU), and several no-mmu versions.
+ *
+ * This driver expects the board has been wired with two GPIOs suppporting
+ * a VBUS sensing IRQ, and a D+ pullup.  (They may be omitted, but the
+ * testing hasn't covered such cases.)  The pullup is most important; it
+ * provides software control over whether the host enumerates the device.
+ * The VBUS sensing helps during enumeration, and allows both USB clocks
+ * (and the transceiver) to stay gated off until they're necessary, saving
+ * power.  During USB suspend, the 48 MHz clock is gated off.
+ */
+
+#define	DRIVER_VERSION	"8 March 2005"
+
+static const char driver_name [] = "at91_udc";
+static const char ep0name[] = "ep0";
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Read from a UDP register.
+ */
+static inline unsigned long at91_udp_read(unsigned int reg)
+{
+	void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP;
+
+	return __raw_readl(udp_base + reg);
+}
+
+/*
+ * Write to a UDP register.
+ */
+static inline void at91_udp_write(unsigned int reg, unsigned long value)
+{
+	void __iomem *udp_base = (void __iomem *)AT91_VA_BASE_UDP;
+
+	__raw_writel(value, udp_base + reg);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+
+#include <linux/seq_file.h>
+
+static const char debug_filename[] = "driver/udc";
+
+#define FOURBITS "%s%s%s%s"
+#define EIGHTBITS FOURBITS FOURBITS
+
+static void proc_ep_show(struct seq_file *s, struct at91_ep *ep)
+{
+	static char		*types[] = {
+		"control", "out-iso", "out-bulk", "out-int",
+		"BOGUS",   "in-iso",  "in-bulk",  "in-int"};
+
+	u32			csr;
+	struct at91_request	*req;
+	unsigned long	flags;
+
+	local_irq_save(flags);
+
+	csr = __raw_readl(ep->creg);
+
+	/* NOTE:  not collecting per-endpoint irq statistics... */
+
+	seq_printf(s, "\n");
+	seq_printf(s, "%s, maxpacket %d %s%s %s%s\n",
+			ep->ep.name, ep->ep.maxpacket,
+			ep->is_in ? "in" : "out",
+			ep->is_iso ? " iso" : "",
+			ep->is_pingpong
+				? (ep->fifo_bank ? "pong" : "ping")
+				: "",
+			ep->stopped ? " stopped" : "");
+	seq_printf(s, "csr %08x rxbytes=%d %s %s %s" EIGHTBITS "\n",
+		csr,
+		(csr & 0x07ff0000) >> 16,
+		(csr & (1 << 15)) ? "enabled" : "disabled",
+		(csr & (1 << 11)) ? "DATA1" : "DATA0",
+		types[(csr & 0x700) >> 8],
+
+		/* iff type is control then print current direction */
+		(!(csr & 0x700))
+			? ((csr & (1 << 7)) ? " IN" : " OUT")
+			: "",
+		(csr & (1 << 6)) ? " rxdatabk1" : "",
+		(csr & (1 << 5)) ? " forcestall" : "",
+		(csr & (1 << 4)) ? " txpktrdy" : "",
+
+		(csr & (1 << 3)) ? " stallsent" : "",
+		(csr & (1 << 2)) ? " rxsetup" : "",
+		(csr & (1 << 1)) ? " rxdatabk0" : "",
+		(csr & (1 << 0)) ? " txcomp" : "");
+	if (list_empty (&ep->queue))
+		seq_printf(s, "\t(queue empty)\n");
+
+	else list_for_each_entry (req, &ep->queue, queue) {
+		unsigned	length = req->req.actual;
+
+		seq_printf(s, "\treq %p len %d/%d buf %p\n",
+				&req->req, length,
+				req->req.length, req->req.buf);
+	}
+	local_irq_restore(flags);
+}
+
+static void proc_irq_show(struct seq_file *s, const char *label, u32 mask)
+{
+	int i;
+
+	seq_printf(s, "%s %04x:%s%s" FOURBITS, label, mask,
+		(mask & (1 << 13)) ? " wakeup" : "",
+		(mask & (1 << 12)) ? " endbusres" : "",
+
+		(mask & (1 << 11)) ? " sofint" : "",
+		(mask & (1 << 10)) ? " extrsm" : "",
+		(mask & (1 << 9)) ? " rxrsm" : "",
+		(mask & (1 << 8)) ? " rxsusp" : "");
+	for (i = 0; i < 8; i++) {
+		if (mask & (1 << i))
+			seq_printf(s, " ep%d", i);
+	}
+	seq_printf(s, "\n");
+}
+
+static int proc_udc_show(struct seq_file *s, void *unused)
+{
+	struct at91_udc	*udc = s->private;
+	struct at91_ep	*ep;
+	u32		tmp;
+
+	seq_printf(s, "%s: version %s\n", driver_name, DRIVER_VERSION);
+
+	seq_printf(s, "vbus %s, pullup %s, %s powered%s, gadget %s\n\n",
+		udc->vbus ? "present" : "off",
+		udc->enabled
+			? (udc->vbus ? "active" : "enabled")
+			: "disabled",
+		udc->selfpowered ? "self" : "VBUS",
+		udc->suspended ? ", suspended" : "",
+		udc->driver ? udc->driver->driver.name : "(none)");
+
+	/* don't access registers when interface isn't clocked */
+	if (!udc->clocked) {
+		seq_printf(s, "(not clocked)\n");
+		return 0;
+	}
+
+	tmp = at91_udp_read(AT91_UDP_FRM_NUM);
+	seq_printf(s, "frame %05x:%s%s frame=%d\n", tmp,
+		(tmp & AT91_UDP_FRM_OK) ? " ok" : "",
+		(tmp & AT91_UDP_FRM_ERR) ? " err" : "",
+		(tmp & AT91_UDP_NUM));
+
+	tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+	seq_printf(s, "glbstate %02x:%s" FOURBITS "\n", tmp,
+		(tmp & AT91_UDP_RMWUPE) ? " rmwupe" : "",
+		(tmp & AT91_UDP_RSMINPR) ? " rsminpr" : "",
+		(tmp & AT91_UDP_ESR) ? " esr" : "",
+		(tmp & AT91_UDP_CONFG) ? " confg" : "",
+		(tmp & AT91_UDP_FADDEN) ? " fadden" : "");
+
+	tmp = at91_udp_read(AT91_UDP_FADDR);
+	seq_printf(s, "faddr   %03x:%s fadd=%d\n", tmp,
+		(tmp & AT91_UDP_FEN) ? " fen" : "",
+		(tmp & AT91_UDP_FADD));
+
+	proc_irq_show(s, "imr   ", at91_udp_read(AT91_UDP_IMR));
+	proc_irq_show(s, "isr   ", at91_udp_read(AT91_UDP_ISR));
+
+	if (udc->enabled && udc->vbus) {
+		proc_ep_show(s, &udc->ep[0]);
+		list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
+			if (ep->desc)
+				proc_ep_show(s, ep);
+		}
+	}
+	return 0;
+}
+
+static int proc_udc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, proc_udc_show, PDE(inode)->data);
+}
+
+static struct file_operations proc_ops = {
+	.open		= proc_udc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static void create_debug_file(struct at91_udc *udc)
+{
+	struct proc_dir_entry *pde;
+
+	pde = create_proc_entry (debug_filename, 0, NULL);
+	udc->pde = pde;
+	if (pde == NULL)
+		return;
+
+	pde->proc_fops = &proc_ops;
+	pde->data = udc;
+}
+
+static void remove_debug_file(struct at91_udc *udc)
+{
+	if (udc->pde)
+		remove_proc_entry(debug_filename, NULL);
+}
+
+#else
+
+static inline void create_debug_file(struct at91_udc *udc) {}
+static inline void remove_debug_file(struct at91_udc *udc) {}
+
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
+static void done(struct at91_ep *ep, struct at91_request *req, int status)
+{
+	unsigned	stopped = ep->stopped;
+
+	list_del_init(&req->queue);
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = status;
+	else
+		status = req->req.status;
+	if (status && status != -ESHUTDOWN)
+		VDBG("%s done %p, status %d\n", ep->ep.name, req, status);
+
+	ep->stopped = 1;
+	req->req.complete(&ep->ep, &req->req);
+	ep->stopped = stopped;
+
+	/* ep0 is always ready; other endpoints need a non-empty queue */
+	if (list_empty(&ep->queue) && ep->int_mask != (1 << 0))
+		at91_udp_write(AT91_UDP_IDR, ep->int_mask);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* bits indicating OUT fifo has data ready */
+#define	RX_DATA_READY	(AT91_UDP_RX_DATA_BK0 | AT91_UDP_RX_DATA_BK1)
+
+/*
+ * Endpoint FIFO CSR bits have a mix of bits, making it unsafe to just write
+ * back most of the value you just read (because of side effects, including
+ * bits that may change after reading and before writing).
+ *
+ * Except when changing a specific bit, always write values which:
+ *  - clear SET_FX bits (setting them could change something)
+ *  - set CLR_FX bits (clearing them could change something)
+ *
+ * There are also state bits like FORCESTALL, EPEDS, DIR, and EPTYPE
+ * that shouldn't normally be changed.
+ */
+#define	SET_FX	(AT91_UDP_TXPKTRDY)
+#define	CLR_FX	(RX_DATA_READY | AT91_UDP_RXSETUP | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)
+
+/* pull OUT packet data from the endpoint's fifo */
+static int read_fifo (struct at91_ep *ep, struct at91_request *req)
+{
+	u32 __iomem	*creg = ep->creg;
+	u8 __iomem	*dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
+	u32		csr;
+	u8		*buf;
+	unsigned int	count, bufferspace, is_done;
+
+	buf = req->req.buf + req->req.actual;
+	bufferspace = req->req.length - req->req.actual;
+
+	/*
+	 * there might be nothing to read if ep_queue() calls us,
+	 * or if we already emptied both pingpong buffers
+	 */
+rescan:
+	csr = __raw_readl(creg);
+	if ((csr & RX_DATA_READY) == 0)
+		return 0;
+
+	count = (csr & AT91_UDP_RXBYTECNT) >> 16;
+	if (count > ep->ep.maxpacket)
+		count = ep->ep.maxpacket;
+	if (count > bufferspace) {
+		DBG("%s buffer overflow\n", ep->ep.name);
+		req->req.status = -EOVERFLOW;
+		count = bufferspace;
+	}
+	__raw_readsb(dreg, buf, count);
+
+	/* release and swap pingpong mem bank */
+	csr |= CLR_FX;
+	if (ep->is_pingpong) {
+		if (ep->fifo_bank == 0) {
+			csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);
+			ep->fifo_bank = 1;
+		} else {
+			csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK1);
+			ep->fifo_bank = 0;
+		}
+	} else
+		csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);
+	__raw_writel(csr, creg);
+
+	req->req.actual += count;
+	is_done = (count < ep->ep.maxpacket);
+	if (count == bufferspace)
+		is_done = 1;
+
+	PACKET("%s %p out/%d%s\n", ep->ep.name, &req->req, count,
+			is_done ? " (done)" : "");
+
+	/*
+	 * avoid extra trips through IRQ logic for packets already in
+	 * the fifo ... maybe preventing an extra (expensive) OUT-NAK
+	 */
+	if (is_done)
+		done(ep, req, 0);
+	else if (ep->is_pingpong) {
+		bufferspace -= count;
+		buf += count;
+		goto rescan;
+	}
+
+	return is_done;
+}
+
+/* load fifo for an IN packet */
+static int write_fifo(struct at91_ep *ep, struct at91_request *req)
+{
+	u32 __iomem	*creg = ep->creg;
+	u32		csr = __raw_readl(creg);
+	u8 __iomem	*dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
+	unsigned	total, count, is_last;
+
+	/*
+	 * TODO: allow for writing two packets to the fifo ... that'll
+	 * reduce the amount of IN-NAKing, but probably won't affect
+	 * throughput much.  (Unlike preventing OUT-NAKing!)
+	 */
+
+	/*
+	 * If ep_queue() calls us, the queue is empty and possibly in
+	 * odd states like TXCOMP not yet cleared (we do it, saving at
+	 * least one IRQ) or the fifo not yet being free.  Those aren't
+	 * issues normally (IRQ handler fast path).
+	 */
+	if (unlikely(csr & (AT91_UDP_TXCOMP | AT91_UDP_TXPKTRDY))) {
+		if (csr & AT91_UDP_TXCOMP) {
+			csr |= CLR_FX;
+			csr &= ~(SET_FX | AT91_UDP_TXCOMP);
+			__raw_writel(csr, creg);
+			csr = __raw_readl(creg);
+		}
+		if (csr & AT91_UDP_TXPKTRDY)
+			return 0;
+	}
+
+	total = req->req.length - req->req.actual;
+	if (ep->ep.maxpacket < total) {
+		count = ep->ep.maxpacket;
+		is_last = 0;
+	} else {
+		count = total;
+		is_last = (count < ep->ep.maxpacket) || !req->req.zero;
+	}
+
+	/*
+	 * Write the packet, maybe it's a ZLP.
+	 *
+	 * NOTE:  incrementing req->actual before we receive the ACK means
+	 * gadget driver IN bytecounts can be wrong in fault cases.  That's
+	 * fixable with PIO drivers like this one (save "count" here, and
+	 * do the increment later on TX irq), but not for most DMA hardware.
+	 *
+	 * So all gadget drivers must accept that potential error.  Some
+	 * hardware supports precise fifo status reporting, letting them
+	 * recover when the actual bytecount matters (e.g. for USB Test
+	 * and Measurement Class devices).
+	 */
+	__raw_writesb(dreg, req->req.buf + req->req.actual, count);
+	csr &= ~SET_FX;
+	csr |= CLR_FX | AT91_UDP_TXPKTRDY;
+	__raw_writel(csr, creg);
+	req->req.actual += count;
+
+	PACKET("%s %p in/%d%s\n", ep->ep.name, &req->req, count,
+			is_last ? " (done)" : "");
+	if (is_last)
+		done(ep, req, 0);
+	return is_last;
+}
+
+static void nuke(struct at91_ep *ep, int status)
+{
+	struct at91_request *req;
+
+	// terminer chaque requete dans la queue
+	ep->stopped = 1;
+	if (list_empty(&ep->queue))
+		return;
+
+	VDBG("%s %s\n", __FUNCTION__, ep->ep.name);
+	while (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct at91_request, queue);
+		done(ep, req, status);
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int at91_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct at91_ep	*ep = container_of(_ep, struct at91_ep, ep);
+	struct at91_udc	*dev = ep->udc;
+	u16		maxpacket;
+	u32		tmp;
+	unsigned long	flags;
+
+	if (!_ep || !ep
+			|| !desc || ep->desc
+			|| _ep->name == ep0name
+			|| desc->bDescriptorType != USB_DT_ENDPOINT
+			|| (maxpacket = le16_to_cpu(desc->wMaxPacketSize)) == 0
+			|| maxpacket > ep->maxpacket) {
+		DBG("bad ep or descriptor\n");
+		return -EINVAL;
+	}
+
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
+		DBG("bogus device state\n");
+		return -ESHUTDOWN;
+	}
+
+	tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+	switch (tmp) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		DBG("only one control endpoint\n");
+		return -EINVAL;
+	case USB_ENDPOINT_XFER_INT:
+		if (maxpacket > 64)
+			goto bogus_max;
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		switch (maxpacket) {
+		case 8:
+		case 16:
+		case 32:
+		case 64:
+			goto ok;
+		}
+bogus_max:
+		DBG("bogus maxpacket %d\n", maxpacket);
+		return -EINVAL;
+	case USB_ENDPOINT_XFER_ISOC:
+		if (!ep->is_pingpong) {
+			DBG("iso requires double buffering\n");
+			return -EINVAL;
+		}
+		break;
+	}
+
+ok:
+	local_irq_save(flags);
+
+	/* initialize endpoint to match this descriptor */
+	ep->is_in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
+	ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC);
+	ep->stopped = 0;
+	if (ep->is_in)
+		tmp |= 0x04;
+	tmp <<= 8;
+	tmp |= AT91_UDP_EPEDS;
+	__raw_writel(tmp, ep->creg);
+
+	ep->desc = desc;
+	ep->ep.maxpacket = maxpacket;
+
+	/*
+	 * reset/init endpoint fifo.  NOTE:  leaves fifo_bank alone,
+	 * since endpoint resets don't reset hw pingpong state.
+	 */
+	at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
+	at91_udp_write(AT91_UDP_RST_EP, 0);
+
+	local_irq_restore(flags);
+	return 0;
+}
+
+static int at91_ep_disable (struct usb_ep * _ep)
+{
+	struct at91_ep	*ep = container_of(_ep, struct at91_ep, ep);
+	unsigned long	flags;
+
+	if (ep == &ep->udc->ep[0])
+		return -EINVAL;
+
+	local_irq_save(flags);
+
+	nuke(ep, -ESHUTDOWN);
+
+	/* restore the endpoint's pristine config */
+	ep->desc = NULL;
+	ep->ep.maxpacket = ep->maxpacket;
+
+	/* reset fifos and endpoint */
+	if (ep->udc->clocked) {
+		at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
+		at91_udp_write(AT91_UDP_RST_EP, 0);
+		__raw_writel(0, ep->creg);
+	}
+
+	local_irq_restore(flags);
+	return 0;
+}
+
+/*
+ * this is a PIO-only driver, so there's nothing
+ * interesting for request or buffer allocation.
+ */
+
+static struct usb_request *at91_ep_alloc_request (struct usb_ep *_ep, unsigned int gfp_flags)
+{
+	struct at91_request *req;
+
+	req = kcalloc(1, sizeof (struct at91_request), SLAB_KERNEL);
+	if (!req)
+		return NULL;
+
+	INIT_LIST_HEAD(&req->queue);
+	return &req->req;
+}
+
+static void at91_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct at91_request *req;
+
+	req = container_of(_req, struct at91_request, req);
+	BUG_ON(!list_empty(&req->queue));
+	kfree(req);
+}
+
+static void *at91_ep_alloc_buffer(
+	struct usb_ep *_ep,
+	unsigned bytes,
+	dma_addr_t *dma,
+	gfp_t gfp_flags)
+{
+	*dma = ~0;
+	return kmalloc(bytes, gfp_flags);
+}
+
+static void at91_ep_free_buffer(
+	struct usb_ep *ep,
+	void *buf,
+	dma_addr_t dma,
+	unsigned bytes)
+{
+	kfree(buf);
+}
+
+static int at91_ep_queue(struct usb_ep *_ep,
+			struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct at91_request	*req;
+	struct at91_ep		*ep;
+	struct at91_udc		*dev;
+	int			status;
+	unsigned long		flags;
+
+	req = container_of(_req, struct at91_request, req);
+	ep = container_of(_ep, struct at91_ep, ep);
+
+	if (!_req || !_req->complete
+			|| !_req->buf || !list_empty(&req->queue)) {
+		DBG("invalid request\n");
+		return -EINVAL;
+	}
+
+	if (!_ep || (!ep->desc && ep->ep.name != ep0name)) {
+		DBG("invalid ep\n");
+		return -EINVAL;
+	}
+
+	dev = ep->udc;
+
+	if (!dev || !dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {
+		DBG("invalid device\n");
+		return -EINVAL;
+	}
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	local_irq_save(flags);
+
+	/* try to kickstart any empty and idle queue */
+	if (list_empty(&ep->queue) && !ep->stopped) {
+		int	is_ep0;
+
+		/*
+		 * If this control request has a non-empty DATA stage, this
+		 * will start that stage.  It works just like a non-control
+		 * request (until the status stage starts, maybe early).
+		 *
+		 * If the data stage is empty, then this starts a successful
+		 * IN/STATUS stage.  (Unsuccessful ones use set_halt.)
+		 */
+		is_ep0 = (ep->ep.name == ep0name);
+		if (is_ep0) {
+			u32	tmp;
+
+			if (!dev->req_pending) {
+				status = -EINVAL;
+				goto done;
+			}
+
+			/*
+			 * defer changing CONFG until after the gadget driver
+			 * reconfigures the endpoints.
+			 */
+			if (dev->wait_for_config_ack) {
+				tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+				tmp ^= AT91_UDP_CONFG;
+				VDBG("toggle config\n");
+				at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+			}
+			if (req->req.length == 0) {
+ep0_in_status:
+				PACKET("ep0 in/status\n");
+				status = 0;
+				tmp = __raw_readl(ep->creg);
+				tmp &= ~SET_FX;
+				tmp |= CLR_FX | AT91_UDP_TXPKTRDY;
+				__raw_writel(tmp, ep->creg);
+				dev->req_pending = 0;
+				goto done;
+			}
+		}
+
+		if (ep->is_in)
+			status = write_fifo(ep, req);
+		else {
+			status = read_fifo(ep, req);
+
+			/* IN/STATUS stage is otherwise triggered by irq */
+			if (status && is_ep0)
+				goto ep0_in_status;
+		}
+	} else
+		status = 0;
+
+	if (req && !status) {
+		list_add_tail (&req->queue, &ep->queue);
+		at91_udp_write(AT91_UDP_IER, ep->int_mask);
+	}
+done:
+	local_irq_restore(flags);
+	return (status < 0) ? status : 0;
+}
+
+static int at91_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct at91_ep	*ep;
+	struct at91_request	*req;
+
+	ep = container_of(_ep, struct at91_ep, ep);
+	if (!_ep || ep->ep.name == ep0name)
+		return -EINVAL;
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry (req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req)
+		return -EINVAL;
+
+	done(ep, req, -ECONNRESET);
+	return 0;
+}
+
+static int at91_ep_set_halt(struct usb_ep *_ep, int value)
+{
+	struct at91_ep	*ep = container_of(_ep, struct at91_ep, ep);
+	u32 __iomem	*creg;
+	u32		csr;
+	unsigned long	flags;
+	int		status = 0;
+
+	if (!_ep || ep->is_iso || !ep->udc->clocked)
+		return -EINVAL;
+
+	creg = ep->creg;
+	local_irq_save(flags);
+
+	csr = __raw_readl(creg);
+
+	/*
+	 * fail with still-busy IN endpoints, ensuring correct sequencing
+	 * of data tx then stall.  note that the fifo rx bytecount isn't
+	 * completely accurate as a tx bytecount.
+	 */
+	if (ep->is_in && (!list_empty(&ep->queue) || (csr >> 16) != 0))
+		status = -EAGAIN;
+	else {
+		csr |= CLR_FX;
+		csr &= ~SET_FX;
+		if (value) {
+			csr |= AT91_UDP_FORCESTALL;
+			VDBG("halt %s\n", ep->ep.name);
+		} else {
+			at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
+			at91_udp_write(AT91_UDP_RST_EP, 0);
+			csr &= ~AT91_UDP_FORCESTALL;
+		}
+		__raw_writel(csr, creg);
+	}
+
+	local_irq_restore(flags);
+	return status;
+}
+
+static struct usb_ep_ops at91_ep_ops = {
+	.enable		= at91_ep_enable,
+	.disable	= at91_ep_disable,
+	.alloc_request	= at91_ep_alloc_request,
+	.free_request	= at91_ep_free_request,
+	.alloc_buffer	= at91_ep_alloc_buffer,
+	.free_buffer	= at91_ep_free_buffer,
+	.queue		= at91_ep_queue,
+	.dequeue	= at91_ep_dequeue,
+	.set_halt	= at91_ep_set_halt,
+	// there's only imprecise fifo status reporting
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int at91_get_frame(struct usb_gadget *gadget)
+{
+	if (!to_udc(gadget)->clocked)
+		return -EINVAL;
+	return at91_udp_read(AT91_UDP_FRM_NUM) & AT91_UDP_NUM;
+}
+
+static int at91_wakeup(struct usb_gadget *gadget)
+{
+	struct at91_udc	*udc = to_udc(gadget);
+	u32		glbstate;
+	int		status = -EINVAL;
+	unsigned long	flags;
+
+	DBG("%s\n", __FUNCTION__ );
+	local_irq_save(flags);
+
+	if (!udc->clocked || !udc->suspended)
+		goto done;
+
+	/* NOTE:  some "early versions" handle ESR differently ... */
+
+	glbstate = at91_udp_read(AT91_UDP_GLB_STAT);
+	if (!(glbstate & AT91_UDP_ESR))
+		goto done;
+	glbstate |= AT91_UDP_ESR;
+	at91_udp_write(AT91_UDP_GLB_STAT, glbstate);
+
+done:
+	local_irq_restore(flags);
+	return status;
+}
+
+/* reinit == restore inital software state */
+static void udc_reinit(struct at91_udc *udc)
+{
+	u32 i;
+
+	INIT_LIST_HEAD(&udc->gadget.ep_list);
+	INIT_LIST_HEAD(&udc->gadget.ep0->ep_list);
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		struct at91_ep *ep = &udc->ep[i];
+
+		if (i != 0)
+			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+		ep->desc = NULL;
+		ep->stopped = 0;
+		ep->fifo_bank = 0;
+		ep->ep.maxpacket = ep->maxpacket;
+		// initialiser une queue par endpoint
+		INIT_LIST_HEAD(&ep->queue);
+	}
+}
+
+static void stop_activity(struct at91_udc *udc)
+{
+	struct usb_gadget_driver *driver = udc->driver;
+	int i;
+
+	if (udc->gadget.speed == USB_SPEED_UNKNOWN)
+		driver = NULL;
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+
+	for (i = 0; i < NUM_ENDPOINTS; i++) {
+		struct at91_ep *ep = &udc->ep[i];
+		ep->stopped = 1;
+		nuke(ep, -ESHUTDOWN);
+	}
+	if (driver)
+		driver->disconnect(&udc->gadget);
+
+	udc_reinit(udc);
+}
+
+static void clk_on(struct at91_udc *udc)
+{
+	if (udc->clocked)
+		return;
+	udc->clocked = 1;
+	clk_enable(udc->iclk);
+	clk_enable(udc->fclk);
+}
+
+static void clk_off(struct at91_udc *udc)
+{
+	if (!udc->clocked)
+		return;
+	udc->clocked = 0;
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	clk_disable(udc->iclk);
+	clk_disable(udc->fclk);
+}
+
+/*
+ * activate/deactivate link with host; minimize power usage for
+ * inactive links by cutting clocks and transceiver power.
+ */
+static void pullup(struct at91_udc *udc, int is_on)
+{
+	if (!udc->enabled || !udc->vbus)
+		is_on = 0;
+	DBG("%sactive\n", is_on ? "" : "in");
+	if (is_on) {
+		clk_on(udc);
+		at91_udp_write(AT91_UDP_TXVC, 0);
+		at91_set_gpio_value(udc->board.pullup_pin, 1);
+	} else  {
+		stop_activity(udc);
+		at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
+		at91_set_gpio_value(udc->board.pullup_pin, 0);
+		clk_off(udc);
+
+		// REVISIT:  with transceiver disabled, will D- float
+		// so that a host would falsely detect a device?
+	}
+}
+
+/* vbus is here!  turn everything on that's ready */
+static int at91_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+	struct at91_udc	*udc = to_udc(gadget);
+	unsigned long	flags;
+
+	// VDBG("vbus %s\n", is_active ? "on" : "off");
+	local_irq_save(flags);
+	udc->vbus = (is_active != 0);
+	pullup(udc, is_active);
+	local_irq_restore(flags);
+	return 0;
+}
+
+static int at91_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct at91_udc	*udc = to_udc(gadget);
+	unsigned long	flags;
+
+	local_irq_save(flags);
+	udc->enabled = is_on = !!is_on;
+	pullup(udc, is_on);
+	local_irq_restore(flags);
+	return 0;
+}
+
+static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on)
+{
+	struct at91_udc	*udc = to_udc(gadget);
+	unsigned long	flags;
+
+	local_irq_save(flags);
+	udc->selfpowered = (is_on != 0);
+	local_irq_restore(flags);
+	return 0;
+}
+
+static const struct usb_gadget_ops at91_udc_ops = {
+	.get_frame		= at91_get_frame,
+	.wakeup			= at91_wakeup,
+	.set_selfpowered	= at91_set_selfpowered,
+	.vbus_session		= at91_vbus_session,
+	.pullup			= at91_pullup,
+
+	/*
+	 * VBUS-powered devices may also also want to support bigger
+	 * power budgets after an appropriate SET_CONFIGURATION.
+	 */
+	// .vbus_power		= at91_vbus_power,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int handle_ep(struct at91_ep *ep)
+{
+	struct at91_request	*req;
+	u32 __iomem		*creg = ep->creg;
+	u32			csr = __raw_readl(creg);
+
+	if (!list_empty(&ep->queue))
+		req = list_entry(ep->queue.next,
+			struct at91_request, queue);
+	else
+		req = NULL;
+
+	if (ep->is_in) {
+		if (csr & (AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)) {
+			csr |= CLR_FX;
+			csr &= ~(SET_FX | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP);
+			__raw_writel(csr, creg);
+		}
+		if (req)
+			return write_fifo(ep, req);
+
+	} else {
+		if (csr & AT91_UDP_STALLSENT) {
+			/* STALLSENT bit == ISOERR */
+			if (ep->is_iso && req)
+				req->req.status = -EILSEQ;
+			csr |= CLR_FX;
+			csr &= ~(SET_FX | AT91_UDP_STALLSENT);
+			__raw_writel(csr, creg);
+			csr = __raw_readl(creg);
+		}
+		if (req && (csr & RX_DATA_READY))
+			return read_fifo(ep, req);
+	}
+	return 0;
+}
+
+union setup {
+	u8			raw[8];
+	struct usb_ctrlrequest	r;
+};
+
+static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
+{
+	u32 __iomem	*creg = ep->creg;
+	u8 __iomem	*dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
+	unsigned	rxcount, i = 0;
+	u32		tmp;
+	union setup	pkt;
+	int		status = 0;
+
+	/* read and ack SETUP; hard-fail for bogus packets */
+	rxcount = (csr & AT91_UDP_RXBYTECNT) >> 16;
+	if (likely(rxcount == 8)) {
+		while (rxcount--)
+			pkt.raw[i++] = __raw_readb(dreg);
+		if (pkt.r.bRequestType & USB_DIR_IN) {
+			csr |= AT91_UDP_DIR;
+			ep->is_in = 1;
+		} else {
+			csr &= ~AT91_UDP_DIR;
+			ep->is_in = 0;
+		}
+	} else {
+		// REVISIT this happens sometimes under load; why??
+		ERR("SETUP len %d, csr %08x\n", rxcount, csr);
+		status = -EINVAL;
+	}
+	csr |= CLR_FX;
+	csr &= ~(SET_FX | AT91_UDP_RXSETUP);
+	__raw_writel(csr, creg);
+	udc->wait_for_addr_ack = 0;
+	udc->wait_for_config_ack = 0;
+	ep->stopped = 0;
+	if (unlikely(status != 0))
+		goto stall;
+
+#define w_index		le16_to_cpu(pkt.r.wIndex)
+#define w_value		le16_to_cpu(pkt.r.wValue)
+#define w_length	le16_to_cpu(pkt.r.wLength)
+
+	VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n",
+			pkt.r.bRequestType, pkt.r.bRequest,
+			w_value, w_index, w_length);
+
+	/*
+	 * A few standard requests get handled here, ones that touch
+	 * hardware ... notably for device and endpoint features.
+	 */
+	udc->req_pending = 1;
+	csr = __raw_readl(creg);
+	csr |= CLR_FX;
+	csr &= ~SET_FX;
+	switch ((pkt.r.bRequestType << 8) | pkt.r.bRequest) {
+
+	case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_SET_ADDRESS:
+		__raw_writel(csr | AT91_UDP_TXPKTRDY, creg);
+		udc->addr = w_value;
+		udc->wait_for_addr_ack = 1;
+		udc->req_pending = 0;
+		/* FADDR is set later, when we ack host STATUS */
+		return;
+
+	case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_SET_CONFIGURATION:
+		tmp = at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_CONFG;
+		if (pkt.r.wValue)
+			udc->wait_for_config_ack = (tmp == 0);
+		else
+			udc->wait_for_config_ack = (tmp != 0);
+		if (udc->wait_for_config_ack)
+			VDBG("wait for config\n");
+		/* CONFG is toggled later, if gadget driver succeeds */
+		break;
+
+	/*
+	 * Hosts may set or clear remote wakeup status, and
+	 * devices may report they're VBUS powered.
+	 */
+	case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_GET_STATUS:
+		tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
+		if (at91_udp_read(AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
+			tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP);
+		PACKET("get device status\n");
+		__raw_writeb(tmp, dreg);
+		__raw_writeb(0, dreg);
+		goto write_in;
+		/* then STATUS starts later, automatically */
+	case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_SET_FEATURE:
+		if (w_value != USB_DEVICE_REMOTE_WAKEUP)
+			goto stall;
+		tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+		tmp |= AT91_UDP_ESR;
+		at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+		goto succeed;
+	case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
+			| USB_REQ_CLEAR_FEATURE:
+		if (w_value != USB_DEVICE_REMOTE_WAKEUP)
+			goto stall;
+		tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+		tmp &= ~AT91_UDP_ESR;
+		at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+		goto succeed;
+
+	/*
+	 * Interfaces have no feature settings; this is pretty useless.
+	 * we won't even insist the interface exists...
+	 */
+	case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
+			| USB_REQ_GET_STATUS:
+		PACKET("get interface status\n");
+		__raw_writeb(0, dreg);
+		__raw_writeb(0, dreg);
+		goto write_in;
+		/* then STATUS starts later, automatically */
+	case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
+			| USB_REQ_SET_FEATURE:
+	case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
+			| USB_REQ_CLEAR_FEATURE:
+		goto stall;
+
+	/*
+	 * Hosts may clear bulk/intr endpoint halt after the gadget
+	 * driver sets it (not widely used); or set it (for testing)
+	 */
+	case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
+			| USB_REQ_GET_STATUS:
+		tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+		ep = &udc->ep[tmp];
+		if (tmp > NUM_ENDPOINTS || (tmp && !ep->desc))
+			goto stall;
+
+		if (tmp) {
+			if ((w_index & USB_DIR_IN)) {
+				if (!ep->is_in)
+					goto stall;
+			} else if (ep->is_in)
+				goto stall;
+		}
+		PACKET("get %s status\n", ep->ep.name);
+		if (__raw_readl(ep->creg) & AT91_UDP_FORCESTALL)
+			tmp = (1 << USB_ENDPOINT_HALT);
+		else
+			tmp = 0;
+		__raw_writeb(tmp, dreg);
+		__raw_writeb(0, dreg);
+		goto write_in;
+		/* then STATUS starts later, automatically */
+	case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
+			| USB_REQ_SET_FEATURE:
+		tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+		ep = &udc->ep[tmp];
+		if (w_value != USB_ENDPOINT_HALT || tmp > NUM_ENDPOINTS)
+			goto stall;
+		if (!ep->desc || ep->is_iso)
+			goto stall;
+		if ((w_index & USB_DIR_IN)) {
+			if (!ep->is_in)
+				goto stall;
+		} else if (ep->is_in)
+			goto stall;
+
+		tmp = __raw_readl(ep->creg);
+		tmp &= ~SET_FX;
+		tmp |= CLR_FX | AT91_UDP_FORCESTALL;
+		__raw_writel(tmp, ep->creg);
+		goto succeed;
+	case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
+			| USB_REQ_CLEAR_FEATURE:
+		tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
+		ep = &udc->ep[tmp];
+		if (w_value != USB_ENDPOINT_HALT || tmp > NUM_ENDPOINTS)
+			goto stall;
+		if (tmp == 0)
+			goto succeed;
+		if (!ep->desc || ep->is_iso)
+			goto stall;
+		if ((w_index & USB_DIR_IN)) {
+			if (!ep->is_in)
+				goto stall;
+		} else if (ep->is_in)
+			goto stall;
+
+		at91_udp_write(AT91_UDP_RST_EP, ep->int_mask);
+		at91_udp_write(AT91_UDP_RST_EP, 0);
+		tmp = __raw_readl(ep->creg);
+		tmp |= CLR_FX;
+		tmp &= ~(SET_FX | AT91_UDP_FORCESTALL);
+		__raw_writel(tmp, ep->creg);
+		if (!list_empty(&ep->queue))
+			handle_ep(ep);
+		goto succeed;
+	}
+
+#undef w_value
+#undef w_index
+#undef w_length
+
+	/* pass request up to the gadget driver */
+	status = udc->driver->setup(&udc->gadget, &pkt.r);
+	if (status < 0) {
+stall:
+		VDBG("req %02x.%02x protocol STALL; stat %d\n",
+				pkt.r.bRequestType, pkt.r.bRequest, status);
+		csr |= AT91_UDP_FORCESTALL;
+		__raw_writel(csr, creg);
+		udc->req_pending = 0;
+	}
+	return;
+
+succeed:
+	/* immediate successful (IN) STATUS after zero length DATA */
+	PACKET("ep0 in/status\n");
+write_in:
+	csr |= AT91_UDP_TXPKTRDY;
+	__raw_writel(csr, creg);
+	udc->req_pending = 0;
+	return;
+}
+
+static void handle_ep0(struct at91_udc *udc)
+{
+	struct at91_ep		*ep0 = &udc->ep[0];
+	u32 __iomem		*creg = ep0->creg;
+	u32			csr = __raw_readl(creg);
+	struct at91_request	*req;
+
+	if (unlikely(csr & AT91_UDP_STALLSENT)) {
+		nuke(ep0, -EPROTO);
+		udc->req_pending = 0;
+		csr |= CLR_FX;
+		csr &= ~(SET_FX | AT91_UDP_STALLSENT | AT91_UDP_FORCESTALL);
+		__raw_writel(csr, creg);
+		VDBG("ep0 stalled\n");
+		csr = __raw_readl(creg);
+	}
+	if (csr & AT91_UDP_RXSETUP) {
+		nuke(ep0, 0);
+		udc->req_pending = 0;
+		handle_setup(udc, ep0, csr);
+		return;
+	}
+
+	if (list_empty(&ep0->queue))
+		req = NULL;
+	else
+		req = list_entry(ep0->queue.next, struct at91_request, queue);
+
+	/* host ACKed an IN packet that we sent */
+	if (csr & AT91_UDP_TXCOMP) {
+		csr |= CLR_FX;
+		csr &= ~(SET_FX | AT91_UDP_TXCOMP);
+
+		/* write more IN DATA? */
+		if (req && ep0->is_in) {
+			if (handle_ep(ep0))
+				udc->req_pending = 0;
+
+		/*
+		 * Ack after:
+		 *  - last IN DATA packet (including GET_STATUS)
+		 *  - IN/STATUS for OUT DATA
+		 *  - IN/STATUS for any zero-length DATA stage
+		 * except for the IN DATA case, the host should send
+		 * an OUT status later, which we'll ack.
+		 */
+		} else {
+			udc->req_pending = 0;
+			__raw_writel(csr, creg);
+
+			/*
+			 * SET_ADDRESS takes effect only after the STATUS
+			 * (to the original address) gets acked.
+			 */
+			if (udc->wait_for_addr_ack) {
+				u32	tmp;
+
+				at91_udp_write(AT91_UDP_FADDR, AT91_UDP_FEN | udc->addr);
+				tmp = at91_udp_read(AT91_UDP_GLB_STAT);
+				tmp &= ~AT91_UDP_FADDEN;
+				if (udc->addr)
+					tmp |= AT91_UDP_FADDEN;
+				at91_udp_write(AT91_UDP_GLB_STAT, tmp);
+
+				udc->wait_for_addr_ack = 0;
+				VDBG("address %d\n", udc->addr);
+			}
+		}
+	}
+
+	/* OUT packet arrived ... */
+	else if (csr & AT91_UDP_RX_DATA_BK0) {
+		csr |= CLR_FX;
+		csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0);
+
+		/* OUT DATA stage */
+		if (!ep0->is_in) {
+			if (req) {
+				if (handle_ep(ep0)) {
+					/* send IN/STATUS */
+					PACKET("ep0 in/status\n");
+					csr = __raw_readl(creg);
+					csr &= ~SET_FX;
+					csr |= CLR_FX | AT91_UDP_TXPKTRDY;
+					__raw_writel(csr, creg);
+					udc->req_pending = 0;
+				}
+			} else if (udc->req_pending) {
+				/*
+				 * AT91 hardware has a hard time with this
+				 * "deferred response" mode for control-OUT
+				 * transfers.  (For control-IN it's fine.)
+				 *
+				 * The normal solution leaves OUT data in the
+				 * fifo until the gadget driver is ready.
+				 * We couldn't do that here without disabling
+				 * the IRQ that tells about SETUP packets,
+				 * e.g. when the host gets impatient...
+				 *
+				 * Working around it by copying into a buffer
+				 * would almost be a non-deferred response,
+				 * except that it wouldn't permit reliable
+				 * stalling of the request.  Instead, demand
+				 * that gadget drivers not use this mode.
+				 */
+				DBG("no control-OUT deferred responses!\n");
+				__raw_writel(csr | AT91_UDP_FORCESTALL, creg);
+				udc->req_pending = 0;
+			}
+
+		/* STATUS stage for control-IN; ack.  */
+		} else {
+			PACKET("ep0 out/status ACK\n");
+			__raw_writel(csr, creg);
+
+			/* "early" status stage */
+			if (req)
+				done(ep0, req, 0);
+		}
+	}
+}
+
+static irqreturn_t at91_udc_irq (int irq, void *_udc, struct pt_regs *r)
+{
+	struct at91_udc		*udc = _udc;
+	u32			rescans = 5;
+
+	while (rescans--) {
+		u32	status = at91_udp_read(AT91_UDP_ISR);
+
+		status &= at91_udp_read(AT91_UDP_IMR);
+		if (!status)
+			break;
+
+		/* USB reset irq:  not maskable */
+		if (status & AT91_UDP_ENDBUSRES) {
+			at91_udp_write(AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS);
+			at91_udp_write(AT91_UDP_IER, MINIMUS_INTERRUPTUS);
+			/* Atmel code clears this irq twice */
+			at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
+			at91_udp_write(AT91_UDP_ICR, AT91_UDP_ENDBUSRES);
+			VDBG("end bus reset\n");
+			udc->addr = 0;
+			stop_activity(udc);
+
+			/* enable ep0 */
+			at91_udp_write(AT91_UDP_CSR(0), AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL);
+			udc->gadget.speed = USB_SPEED_FULL;
+			udc->suspended = 0;
+			at91_udp_write(AT91_UDP_IER, AT91_UDP_EP(0));
+
+			/*
+			 * NOTE:  this driver keeps clocks off unless the
+			 * USB host is present.  That saves power, and also
+			 * eliminates IRQs (reset, resume, suspend) that can
+			 * otherwise flood from the controller.  If your
+			 * board doesn't support VBUS detection, suspend and
+			 * resume irq logic may need more attention...
+			 */
+
+		/* host initiated suspend (3+ms bus idle) */
+		} else if (status & AT91_UDP_RXSUSP) {
+			at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXSUSP);
+			at91_udp_write(AT91_UDP_IER, AT91_UDP_RXRSM);
+			at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXSUSP);
+			// VDBG("bus suspend\n");
+			if (udc->suspended)
+				continue;
+			udc->suspended = 1;
+
+			/*
+			 * NOTE:  when suspending a VBUS-powered device, the
+			 * gadget driver should switch into slow clock mode
+			 * and then into standby to avoid drawing more than
+			 * 500uA power (2500uA for some high-power configs).
+			 */
+			if (udc->driver && udc->driver->suspend)
+				udc->driver->suspend(&udc->gadget);
+
+		/* host initiated resume */
+		} else if (status & AT91_UDP_RXRSM) {
+			at91_udp_write(AT91_UDP_IDR, AT91_UDP_RXRSM);
+			at91_udp_write(AT91_UDP_IER, AT91_UDP_RXSUSP);
+			at91_udp_write(AT91_UDP_ICR, AT91_UDP_RXRSM);
+			// VDBG("bus resume\n");
+			if (!udc->suspended)
+				continue;
+			udc->suspended = 0;
+
+			/*
+			 * NOTE:  for a VBUS-powered device, the gadget driver
+			 * would normally want to switch out of slow clock
+			 * mode into normal mode.
+			 */
+			if (udc->driver && udc->driver->resume)
+				udc->driver->resume(&udc->gadget);
+
+		/* endpoint IRQs are cleared by handling them */
+		} else {
+			int		i;
+			unsigned	mask = 1;
+			struct at91_ep	*ep = &udc->ep[1];
+
+			if (status & mask)
+				handle_ep0(udc);
+			for (i = 1; i < NUM_ENDPOINTS; i++) {
+				mask <<= 1;
+				if (status & mask)
+					handle_ep(ep);
+				ep++;
+			}
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct at91_udc controller = {
+	.gadget = {
+		.ops = &at91_udc_ops,
+		.ep0 = &controller.ep[0].ep,
+		.name = driver_name,
+		.dev = {
+			.bus_id = "gadget"
+		}
+	},
+	.ep[0] = {
+		.ep = {
+			.name	= ep0name,
+			.ops	= &at91_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 8,
+		.creg		= (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(0)),
+		.int_mask	= 1 << 0,
+	},
+	.ep[1] = {
+		.ep = {
+			.name	= "ep1",
+			.ops	= &at91_ep_ops,
+		},
+		.udc		= &controller,
+		.is_pingpong	= 1,
+		.maxpacket	= 64,
+		.creg		= (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(1)),
+		.int_mask	= 1 << 1,
+	},
+	.ep[2] = {
+		.ep = {
+			.name	= "ep2",
+			.ops	= &at91_ep_ops,
+		},
+		.udc		= &controller,
+		.is_pingpong	= 1,
+		.maxpacket	= 64,
+		.creg		= (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(2)),
+		.int_mask	= 1 << 2,
+	},
+	.ep[3] = {
+		.ep = {
+			/* could actually do bulk too */
+			.name	= "ep3-int",
+			.ops	= &at91_ep_ops,
+		},
+		.udc		= &controller,
+		.maxpacket	= 8,
+		.creg		= (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(3)),
+		.int_mask	= 1 << 3,
+	},
+	.ep[4] = {
+		.ep = {
+			.name	= "ep4",
+			.ops	= &at91_ep_ops,
+		},
+		.udc		= &controller,
+		.is_pingpong	= 1,
+		.maxpacket	= 256,
+		.creg		= (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(4)),
+		.int_mask	= 1 << 4,
+	},
+	.ep[5] = {
+		.ep = {
+			.name	= "ep5",
+			.ops	= &at91_ep_ops,
+		},
+		.udc		= &controller,
+		.is_pingpong	= 1,
+		.maxpacket	= 256,
+		.creg		= (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(5)),
+		.int_mask	= 1 << 5,
+	},
+	/* ep6 and ep7 are also reserved */
+};
+
+static irqreturn_t at91_vbus_irq(int irq, void *_udc, struct pt_regs *r)
+{
+	struct at91_udc	*udc = _udc;
+	unsigned	value;
+
+	/* vbus needs at least brief debouncing */
+	udelay(10);
+	value = at91_get_gpio_value(udc->board.vbus_pin);
+	if (value != udc->vbus)
+		at91_vbus_session(&udc->gadget, value);
+
+	return IRQ_HANDLED;
+}
+
+int usb_gadget_register_driver (struct usb_gadget_driver *driver)
+{
+	struct at91_udc	*udc = &controller;
+	int		retval;
+
+	if (!driver
+			|| driver->speed != USB_SPEED_FULL
+			|| !driver->bind
+			|| !driver->unbind
+			|| !driver->setup) {
+		DBG("bad parameter.\n");
+		return -EINVAL;
+	}
+
+	if (udc->driver) {
+		DBG("UDC already has a gadget driver\n");
+		return -EBUSY;
+	}
+
+	udc->driver = driver;
+	udc->gadget.dev.driver = &driver->driver;
+	udc->gadget.dev.driver_data = &driver->driver;
+	udc->enabled = 1;
+	udc->selfpowered = 1;
+
+	retval = driver->bind(&udc->gadget);
+	if (retval) {
+		DBG("driver->bind() returned %d\n", retval);
+		udc->driver = NULL;
+		return retval;
+	}
+
+	local_irq_disable();
+	pullup(udc, 1);
+	local_irq_enable();
+
+	DBG("bound to %s\n", driver->driver.name);
+	return 0;
+}
+EXPORT_SYMBOL (usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+{
+	struct at91_udc *udc = &controller;
+
+	if (!driver || driver != udc->driver)
+		return -EINVAL;
+
+	local_irq_disable();
+	udc->enabled = 0;
+	pullup(udc, 0);
+	local_irq_enable();
+
+	driver->unbind(&udc->gadget);
+	udc->driver = NULL;
+
+	DBG("unbound from %s\n", driver->driver.name);
+	return 0;
+}
+EXPORT_SYMBOL (usb_gadget_unregister_driver);
+
+/*-------------------------------------------------------------------------*/
+
+static void at91udc_shutdown(struct platform_device *dev)
+{
+	/* force disconnect on reboot */
+	pullup(platform_get_drvdata(dev), 0);
+}
+
+static int __devinit at91udc_probe(struct platform_device *pdev)
+{
+	struct device	*dev = &pdev->dev;
+	struct at91_udc	*udc;
+	int		retval;
+
+	if (!dev->platform_data) {
+		/* small (so we copy it) but critical! */
+		DBG("missing platform_data\n");
+		return -ENODEV;
+	}
+
+	if (!request_mem_region(AT91_BASE_UDP, SZ_16K, driver_name)) {
+		DBG("someone's using UDC memory\n");
+		return -EBUSY;
+	}
+
+	/* init software state */
+	udc = &controller;
+	udc->gadget.dev.parent = dev;
+	udc->board = *(struct at91_udc_data *) dev->platform_data;
+	udc->pdev = pdev;
+	udc_reinit(udc);
+	udc->enabled = 0;
+
+	/* get interface and function clocks */
+	udc->iclk = clk_get(dev, "udc_clk");
+	udc->fclk = clk_get(dev, "udpck");
+	if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) {
+		DBG("clocks missing\n");
+		return -ENODEV;
+	}
+
+	retval = device_register(&udc->gadget.dev);
+	if (retval < 0)
+		goto fail0;
+
+	/* disable everything until there's a gadget driver and vbus */
+	pullup(udc, 0);
+
+	/* request UDC and maybe VBUS irqs */
+	if (request_irq(AT91_ID_UDP, at91_udc_irq, SA_INTERRUPT, driver_name, udc)) {
+		DBG("request irq %d failed\n", AT91_ID_UDP);
+		retval = -EBUSY;
+		goto fail1;
+	}
+	if (udc->board.vbus_pin > 0) {
+		if (request_irq(udc->board.vbus_pin, at91_vbus_irq, SA_INTERRUPT, driver_name, udc)) {
+			DBG("request vbus irq %d failed\n", udc->board.vbus_pin);
+			free_irq(AT91_ID_UDP, udc);
+			retval = -EBUSY;
+			goto fail1;
+		}
+	} else {
+		DBG("no VBUS detection, assuming always-on\n");
+		udc->vbus = 1;
+	}
+	dev_set_drvdata(dev, udc);
+	create_debug_file(udc);
+
+	INFO("%s version %s\n", driver_name, DRIVER_VERSION);
+	return 0;
+
+fail1:
+	device_unregister(&udc->gadget.dev);
+fail0:
+	release_mem_region(AT91_VA_BASE_UDP, SZ_16K);
+	DBG("%s probe failed, %d\n", driver_name, retval);
+	return retval;
+}
+
+static int __devexit at91udc_remove(struct platform_device *dev)
+{
+	struct at91_udc *udc = platform_get_drvdata(dev);
+
+	DBG("remove\n");
+
+	pullup(udc, 0);
+
+	if (udc->driver != 0)
+		usb_gadget_unregister_driver(udc->driver);
+
+	remove_debug_file(udc);
+	if (udc->board.vbus_pin > 0)
+		free_irq(udc->board.vbus_pin, udc);
+	free_irq(AT91_ID_UDP, udc);
+	device_unregister(&udc->gadget.dev);
+	release_mem_region(AT91_BASE_UDP, SZ_16K);
+
+	clk_put(udc->iclk);
+	clk_put(udc->fclk);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int at91udc_suspend(struct platform_device *dev, u32 state, u32 level)
+{
+	struct at91_udc *udc = platform_get_drvdata(dev);
+
+	/*
+	 * The "safe" suspend transitions are opportunistic ... e.g. when
+	 * the USB link is suspended (48MHz clock autogated off), or when
+	 * it's disconnected (programmatically gated off, elsewhere).
+	 * Then we can suspend, and the chip can enter slow clock mode.
+	 *
+	 * The problem case is some component (user mode?) suspending this
+	 * device while it's active, with the 48 MHz clock in use.  There
+	 * are two basic approaches:  (a) veto suspend levels involving slow
+	 * clock mode, (b) disconnect, so 48 MHz will no longer be in use
+	 * and we can enter slow clock mode.  This uses (b) for now, since
+	 * it's simplest until AT91 PM exists and supports the other option.
+	 */
+	if (udc->vbus && !udc->suspended)
+		pullup(udc, 0);
+	return 0;
+}
+
+static int at91udc_resume(struct platform_device *dev, u32 level)
+{
+	struct at91_udc *udc = platform_get_drvdata(dev);
+
+	/* maybe reconnect to host; if so, clocks on */
+	pullup(udc, 1);
+	return 0;
+}
+#else
+#define	at91udc_suspend	NULL
+#define	at91udc_resume	NULL
+#endif
+
+static struct platform_driver at91_udc = {
+	.probe		= at91udc_probe,
+	.remove		= __devexit_p(at91udc_remove),
+	.shutdown	= at91udc_shutdown,
+	.suspend	= at91udc_suspend,
+	.resume 	= at91udc_resume,
+	.driver		= {
+		.name	= (char *) driver_name,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __devinit udc_init_module(void)
+{
+	return platform_driver_register(&at91_udc);
+}
+module_init(udc_init_module);
+
+static void __devexit udc_exit_module(void)
+{
+	platform_driver_unregister(&at91_udc);
+}
+module_exit(udc_exit_module);
+
+MODULE_DESCRIPTION("AT91RM9200 udc driver");
+MODULE_AUTHOR("Thomas Rathbone, David Brownell");
+MODULE_LICENSE("GPL");

+ 181 - 0
drivers/usb/gadget/at91_udc.h

@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2004 by Thomas Rathbone, HP Labs
+ * Copyright (C) 2005 by Ivan Kokshaysky
+ * Copyright (C) 2006 by SAN People
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef AT91_UDC_H
+#define AT91_UDC_H
+
+/*
+ * USB Device Port (UDP) registers.
+ * Based on AT91RM9200 datasheet revision E.
+ */
+
+#define AT91_UDP_FRM_NUM	0x00		/* Frame Number Register */
+#define     AT91_UDP_NUM	(0x7ff <<  0)	/* Frame Number */
+#define     AT91_UDP_FRM_ERR	(1     << 16)	/* Frame Error */
+#define     AT91_UDP_FRM_OK	(1     << 17)	/* Frame OK */
+
+#define AT91_UDP_GLB_STAT	0x04		/* Global State Register */
+#define     AT91_UDP_FADDEN	(1 <<  0)	/* Function Address Enable */
+#define     AT91_UDP_CONFG	(1 <<  1)	/* Configured */
+#define     AT91_UDP_ESR	(1 <<  2)	/* Enable Send Resume */
+#define     AT91_UDP_RSMINPR	(1 <<  3)	/* Resume has been sent */
+#define     AT91_UDP_RMWUPE	(1 <<  4)	/* Remote Wake Up Enable */
+
+#define AT91_UDP_FADDR		0x08		/* Function Address Register */
+#define     AT91_UDP_FADD	(0x7f << 0)	/* Function Address Value */
+#define     AT91_UDP_FEN	(1    << 8)	/* Function Enable */
+
+#define AT91_UDP_IER		0x10		/* Interrupt Enable Register */
+#define AT91_UDP_IDR		0x14		/* Interrupt Disable Register */
+#define AT91_UDP_IMR		0x18		/* Interrupt Mask Register */
+
+#define AT91_UDP_ISR		0x1c		/* Interrupt Status Register */
+#define     AT91_UDP_EP(n)	(1 << (n))	/* Endpoint Interrupt Status */
+#define     AT91_UDP_RXSUSP	(1 <<  8) 	/* USB Suspend Interrupt Status */
+#define     AT91_UDP_RXRSM	(1 <<  9)	/* USB Resume Interrupt Status */
+#define     AT91_UDP_EXTRSM	(1 << 10)	/* External Resume Interrupt Status */
+#define     AT91_UDP_SOFINT	(1 << 11)	/* Start of Frame Interrupt Status */
+#define     AT91_UDP_ENDBUSRES	(1 << 12)	/* End of Bus Reset Interrpt Status */
+#define     AT91_UDP_WAKEUP	(1 << 13)	/* USB Wakeup Interrupt Status */
+
+#define AT91_UDP_ICR		0x20		/* Interrupt Clear Register */
+#define AT91_UDP_RST_EP		0x28		/* Reset Endpoint Register */
+
+#define AT91_UDP_CSR(n)		(0x30+((n)*4))	/* Endpoint Control/Status Registers 0-7 */
+#define     AT91_UDP_TXCOMP	(1 <<  0)	/* Generates IN packet with data previously written in DPR */
+#define     AT91_UDP_RX_DATA_BK0 (1 <<  1)	/* Receive Data Bank 0 */
+#define     AT91_UDP_RXSETUP	(1 <<  2)	/* Send STALL to the host */
+#define     AT91_UDP_STALLSENT	(1 <<  3)	/* Stall Sent / Isochronous error (Isochronous endpoints) */
+#define     AT91_UDP_TXPKTRDY	(1 <<  4)	/* Transmit Packet Ready */
+#define     AT91_UDP_FORCESTALL	(1 <<  5)	/* Force Stall */
+#define     AT91_UDP_RX_DATA_BK1 (1 <<  6)	/* Receive Data Bank 1 */
+#define     AT91_UDP_DIR	(1 <<  7)	/* Transfer Direction */
+#define     AT91_UDP_EPTYPE	(7 <<  8)	/* Endpoint Type */
+#define		AT91_UDP_EPTYPE_CTRL		(0 <<  8)
+#define		AT91_UDP_EPTYPE_ISO_OUT		(1 <<  8)
+#define		AT91_UDP_EPTYPE_BULK_OUT	(2 <<  8)
+#define		AT91_UDP_EPTYPE_INT_OUT		(3 <<  8)
+#define		AT91_UDP_EPTYPE_ISO_IN		(5 <<  8)
+#define		AT91_UDP_EPTYPE_BULK_IN		(6 <<  8)
+#define		AT91_UDP_EPTYPE_INT_IN		(7 <<  8)
+#define     AT91_UDP_DTGLE	(1 << 11)	/* Data Toggle */
+#define     AT91_UDP_EPEDS	(1 << 15)	/* Endpoint Enable/Disable */
+#define     AT91_UDP_RXBYTECNT	(0x7ff << 16)	/* Number of bytes in FIFO */
+
+#define AT91_UDP_FDR(n)		(0x50+((n)*4))	/* Endpoint FIFO Data Registers 0-7 */
+
+#define AT91_UDP_TXVC		0x74		/* Transceiver Control Register */
+#define     AT91_UDP_TXVC_TXVDIS (1 << 8)	/* Transceiver Disable */
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * controller driver data structures
+ */
+
+#define	NUM_ENDPOINTS	6
+
+/*
+ * hardware won't disable bus reset, or resume while the controller
+ * is suspended ... watching suspend helps keep the logic symmetric.
+ */
+#define	MINIMUS_INTERRUPTUS \
+	(AT91_UDP_ENDBUSRES | AT91_UDP_RXRSM | AT91_UDP_RXSUSP)
+
+struct at91_ep {
+	struct usb_ep			ep;
+	struct list_head		queue;
+	struct at91_udc			*udc;
+	void __iomem			*creg;
+
+	unsigned			maxpacket:16;
+	u8				int_mask;
+	unsigned			is_pingpong:1;
+
+	unsigned			stopped:1;
+	unsigned			is_in:1;
+	unsigned			is_iso:1;
+	unsigned			fifo_bank:1;
+
+	const struct usb_endpoint_descriptor
+					*desc;
+};
+
+/*
+ * driver is non-SMP, and just blocks IRQs whenever it needs
+ * access protection for chip registers or driver state
+ */
+struct at91_udc {
+	struct usb_gadget		gadget;
+	struct at91_ep			ep[NUM_ENDPOINTS];
+	struct usb_gadget_driver	*driver;
+	unsigned			vbus:1;
+	unsigned			enabled:1;
+	unsigned			clocked:1;
+	unsigned			suspended:1;
+	unsigned			req_pending:1;
+	unsigned			wait_for_addr_ack:1;
+	unsigned			wait_for_config_ack:1;
+	unsigned			selfpowered:1;
+	u8				addr;
+	struct at91_udc_data		board;
+	struct clk			*iclk, *fclk;
+	struct platform_device		*pdev;
+	struct proc_dir_entry		*pde;
+};
+
+static inline struct at91_udc *to_udc(struct usb_gadget *g)
+{
+	return container_of(g, struct at91_udc, gadget);
+}
+
+struct at91_request {
+	struct usb_request		req;
+	struct list_head		queue;
+};
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#define DBG(stuff...)		printk(KERN_DEBUG "udc: " stuff)
+#else
+#define DBG(stuff...)		do{}while(0)
+#endif
+
+#ifdef VERBOSE
+#    define VDBG		DBG
+#else
+#    define VDBG(stuff...)	do{}while(0)
+#endif
+
+#ifdef PACKET_TRACE
+#    define PACKET		VDBG
+#else
+#    define PACKET(stuff...)	do{}while(0)
+#endif
+
+#define ERR(stuff...)		printk(KERN_ERR "udc: " stuff)
+#define WARN(stuff...)		printk(KERN_WARNING "udc: " stuff)
+#define INFO(stuff...)		printk(KERN_INFO "udc: " stuff)
+
+#endif
+

+ 1 - 2
drivers/usb/gadget/dummy_hcd.c

@@ -478,10 +478,9 @@ dummy_alloc_request (struct usb_ep *_ep, gfp_t mem_flags)
 		return NULL;
 		return NULL;
 	ep = usb_ep_to_dummy_ep (_ep);
 	ep = usb_ep_to_dummy_ep (_ep);
 
 
-	req = kmalloc (sizeof *req, mem_flags);
+	req = kzalloc(sizeof(*req), mem_flags);
 	if (!req)
 	if (!req)
 		return NULL;
 		return NULL;
-	memset (req, 0, sizeof *req);
 	INIT_LIST_HEAD (&req->queue);
 	INIT_LIST_HEAD (&req->queue);
 	return &req->req;
 	return &req->req;
 }
 }

+ 39 - 14
drivers/usb/gadget/ether.c

@@ -182,33 +182,37 @@ struct eth_dev {
  * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
  * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
  */
  */
 
 
-static ushort __initdata idVendor;
+static ushort idVendor;
 module_param(idVendor, ushort, S_IRUGO);
 module_param(idVendor, ushort, S_IRUGO);
 MODULE_PARM_DESC(idVendor, "USB Vendor ID");
 MODULE_PARM_DESC(idVendor, "USB Vendor ID");
 
 
-static ushort __initdata idProduct;
+static ushort idProduct;
 module_param(idProduct, ushort, S_IRUGO);
 module_param(idProduct, ushort, S_IRUGO);
 MODULE_PARM_DESC(idProduct, "USB Product ID");
 MODULE_PARM_DESC(idProduct, "USB Product ID");
 
 
-static ushort __initdata bcdDevice;
+static ushort bcdDevice;
 module_param(bcdDevice, ushort, S_IRUGO);
 module_param(bcdDevice, ushort, S_IRUGO);
 MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
 MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
 
 
-static char *__initdata iManufacturer;
+static char *iManufacturer;
 module_param(iManufacturer, charp, S_IRUGO);
 module_param(iManufacturer, charp, S_IRUGO);
 MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
 MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
 
 
-static char *__initdata iProduct;
+static char *iProduct;
 module_param(iProduct, charp, S_IRUGO);
 module_param(iProduct, charp, S_IRUGO);
 MODULE_PARM_DESC(iProduct, "USB Product string");
 MODULE_PARM_DESC(iProduct, "USB Product string");
 
 
+static char *iSerialNumber;
+module_param(iSerialNumber, charp, S_IRUGO);
+MODULE_PARM_DESC(iSerialNumber, "SerialNumber");
+
 /* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */
 /* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */
-static char *__initdata dev_addr;
+static char *dev_addr;
 module_param(dev_addr, charp, S_IRUGO);
 module_param(dev_addr, charp, S_IRUGO);
 MODULE_PARM_DESC(dev_addr, "Device Ethernet Address");
 MODULE_PARM_DESC(dev_addr, "Device Ethernet Address");
 
 
 /* this address is invisible to ifconfig */
 /* this address is invisible to ifconfig */
-static char *__initdata host_addr;
+static char *host_addr;
 module_param(host_addr, charp, S_IRUGO);
 module_param(host_addr, charp, S_IRUGO);
 MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 
 
@@ -253,6 +257,14 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 #define DEV_CONFIG_CDC
 #define DEV_CONFIG_CDC
 #endif
 #endif
 
 
+#ifdef CONFIG_USB_GADGET_MUSBHSFC
+#define DEV_CONFIG_CDC
+#endif
+
+#ifdef CONFIG_USB_GADGET_MUSBHDRC
+#define DEV_CONFIG_CDC
+#endif
+
 
 
 /* For CDC-incapable hardware, choose the simple cdc subset.
 /* For CDC-incapable hardware, choose the simple cdc subset.
  * Anything that talks bulk (without notable bugs) can do this.
  * Anything that talks bulk (without notable bugs) can do this.
@@ -395,6 +407,7 @@ static inline int BITRATE(struct usb_gadget *g)
 #define STRING_CDC			7
 #define STRING_CDC			7
 #define STRING_SUBSET			8
 #define STRING_SUBSET			8
 #define STRING_RNDIS			9
 #define STRING_RNDIS			9
+#define STRING_SERIALNUMBER		10
 
 
 /* holds our biggest descriptor (or RNDIS response) */
 /* holds our biggest descriptor (or RNDIS response) */
 #define USB_BUFSIZ	256
 #define USB_BUFSIZ	256
@@ -862,6 +875,7 @@ static inline void __init hs_subset_descriptors(void)
 
 
 static char				manufacturer [50];
 static char				manufacturer [50];
 static char				product_desc [40] = DRIVER_DESC;
 static char				product_desc [40] = DRIVER_DESC;
+static char				serial_number [20];
 
 
 #ifdef	DEV_CONFIG_CDC
 #ifdef	DEV_CONFIG_CDC
 /* address that the host will use ... usually assigned at random */
 /* address that the host will use ... usually assigned at random */
@@ -872,6 +886,7 @@ static char				ethaddr [2 * ETH_ALEN + 1];
 static struct usb_string		strings [] = {
 static struct usb_string		strings [] = {
 	{ STRING_MANUFACTURER,	manufacturer, },
 	{ STRING_MANUFACTURER,	manufacturer, },
 	{ STRING_PRODUCT,	product_desc, },
 	{ STRING_PRODUCT,	product_desc, },
+	{ STRING_SERIALNUMBER,	serial_number, },
 	{ STRING_DATA,		"Ethernet Data", },
 	{ STRING_DATA,		"Ethernet Data", },
 #ifdef	DEV_CONFIG_CDC
 #ifdef	DEV_CONFIG_CDC
 	{ STRING_CDC,		"CDC Ethernet", },
 	{ STRING_CDC,		"CDC Ethernet", },
@@ -1549,7 +1564,8 @@ static int eth_change_mtu (struct net_device *net, int new_mtu)
 {
 {
 	struct eth_dev	*dev = netdev_priv(net);
 	struct eth_dev	*dev = netdev_priv(net);
 
 
-	// FIXME if rndis, don't change while link's live
+	if (dev->rndis)
+		return -EBUSY;
 
 
 	if (new_mtu <= ETH_HLEN || new_mtu > ETH_FRAME_LEN)
 	if (new_mtu <= ETH_HLEN || new_mtu > ETH_FRAME_LEN)
 		return -ERANGE;
 		return -ERANGE;
@@ -2116,7 +2132,7 @@ eth_req_free (struct usb_ep *ep, struct usb_request *req)
 }
 }
 
 
 
 
-static void
+static void __exit
 eth_unbind (struct usb_gadget *gadget)
 eth_unbind (struct usb_gadget *gadget)
 {
 {
 	struct eth_dev		*dev = get_gadget_data (gadget);
 	struct eth_dev		*dev = get_gadget_data (gadget);
@@ -2153,7 +2169,7 @@ static u8 __init nibble (unsigned char c)
 	return 0;
 	return 0;
 }
 }
 
 
-static void __init get_ether_addr (const char *str, u8 *dev_addr)
+static int __init get_ether_addr(const char *str, u8 *dev_addr)
 {
 {
 	if (str) {
 	if (str) {
 		unsigned	i;
 		unsigned	i;
@@ -2168,9 +2184,10 @@ static void __init get_ether_addr (const char *str, u8 *dev_addr)
 			dev_addr [i] = num;
 			dev_addr [i] = num;
 		}
 		}
 		if (is_valid_ether_addr (dev_addr))
 		if (is_valid_ether_addr (dev_addr))
-			return;
+			return 0;
 	}
 	}
 	random_ether_addr(dev_addr);
 	random_ether_addr(dev_addr);
+	return 1;
 }
 }
 
 
 static int __init
 static int __init
@@ -2268,6 +2285,10 @@ eth_bind (struct usb_gadget *gadget)
 		strlcpy (manufacturer, iManufacturer, sizeof manufacturer);
 		strlcpy (manufacturer, iManufacturer, sizeof manufacturer);
 	if (iProduct)
 	if (iProduct)
 		strlcpy (product_desc, iProduct, sizeof product_desc);
 		strlcpy (product_desc, iProduct, sizeof product_desc);
+	if (iSerialNumber) {
+		device_desc.iSerialNumber = STRING_SERIALNUMBER,
+		strlcpy(serial_number, iSerialNumber, sizeof serial_number);
+	}
 
 
 	/* all we really need is bulk IN/OUT */
 	/* all we really need is bulk IN/OUT */
 	usb_ep_autoconfig_reset (gadget);
 	usb_ep_autoconfig_reset (gadget);
@@ -2377,9 +2398,13 @@ autoconf_fail:
 	 * The host side address is used with CDC and RNDIS, and commonly
 	 * The host side address is used with CDC and RNDIS, and commonly
 	 * ends up in a persistent config database.
 	 * ends up in a persistent config database.
 	 */
 	 */
-	get_ether_addr(dev_addr, net->dev_addr);
+	if (get_ether_addr(dev_addr, net->dev_addr))
+		dev_warn(&gadget->dev,
+			"using random %s ethernet address\n", "self");
 	if (cdc || rndis) {
 	if (cdc || rndis) {
-		get_ether_addr(host_addr, dev->host_mac);
+		if (get_ether_addr(host_addr, dev->host_mac))
+			dev_warn(&gadget->dev,
+				"using random %s ethernet address\n", "host");
 #ifdef	DEV_CONFIG_CDC
 #ifdef	DEV_CONFIG_CDC
 		snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
 		snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
 			dev->host_mac [0], dev->host_mac [1],
 			dev->host_mac [0], dev->host_mac [1],
@@ -2523,7 +2548,7 @@ static struct usb_gadget_driver eth_driver = {
 
 
 	.function	= (char *) driver_desc,
 	.function	= (char *) driver_desc,
 	.bind		= eth_bind,
 	.bind		= eth_bind,
-	.unbind		= eth_unbind,
+	.unbind		= __exit_p(eth_unbind),
 
 
 	.setup		= eth_setup,
 	.setup		= eth_setup,
 	.disconnect	= eth_disconnect,
 	.disconnect	= eth_disconnect,

+ 2 - 2
drivers/usb/gadget/file_storage.c

@@ -3678,7 +3678,7 @@ static void lun_release(struct device *dev)
 	kref_put(&fsg->ref, fsg_release);
 	kref_put(&fsg->ref, fsg_release);
 }
 }
 
 
-static void fsg_unbind(struct usb_gadget *gadget)
+static void __exit fsg_unbind(struct usb_gadget *gadget)
 {
 {
 	struct fsg_dev		*fsg = get_gadget_data(gadget);
 	struct fsg_dev		*fsg = get_gadget_data(gadget);
 	int			i;
 	int			i;
@@ -4064,7 +4064,7 @@ static struct usb_gadget_driver		fsg_driver = {
 #endif
 #endif
 	.function	= (char *) longname,
 	.function	= (char *) longname,
 	.bind		= fsg_bind,
 	.bind		= fsg_bind,
-	.unbind		= fsg_unbind,
+	.unbind		= __exit_p(fsg_unbind),
 	.disconnect	= fsg_disconnect,
 	.disconnect	= fsg_disconnect,
 	.setup		= fsg_setup,
 	.setup		= fsg_setup,
 	.suspend	= fsg_suspend,
 	.suspend	= fsg_suspend,

+ 28 - 2
drivers/usb/gadget/gadget_chips.h

@@ -3,9 +3,9 @@
  * gadget drivers or other code that needs to deal with them, and which
  * gadget drivers or other code that needs to deal with them, and which
  * autoconfigures instead of using early binding to the hardware.
  * autoconfigures instead of using early binding to the hardware.
  *
  *
- * This could eventually work like the ARM mach_is_*() stuff, driven by
+ * This SHOULD eventually work like the ARM mach_is_*() stuff, driven by
  * some config file that gets updated as new hardware is supported.
  * some config file that gets updated as new hardware is supported.
- * (And avoiding the runtime comparisons in typical one-choice cases.)
+ * (And avoiding all runtime comparisons in typical one-choice configs!)
  *
  *
  * NOTE:  some of these controller drivers may not be available yet.
  * NOTE:  some of these controller drivers may not be available yet.
  */
  */
@@ -93,6 +93,26 @@
 #define gadget_is_imx(g)	0
 #define gadget_is_imx(g)	0
 #endif
 #endif
 
 
+/* Mentor high speed function controller */
+#ifdef CONFIG_USB_GADGET_MUSBHSFC
+#define gadget_is_musbhsfc(g)	!strcmp("musbhsfc_udc", (g)->name)
+#else
+#define gadget_is_musbhsfc(g)	0
+#endif
+
+/* Mentor high speed "dual role" controller, peripheral mode */
+#ifdef CONFIG_USB_GADGET_MUSBHDRC
+#define gadget_is_musbhdrc(g)	!strcmp("musbhdrc_udc", (g)->name)
+#else
+#define gadget_is_musbhdrc(g)	0
+#endif
+
+#ifdef CONFIG_USB_GADGET_MPC8272
+#define gadget_is_mpc8272(g)	!strcmp("mpc8272_udc", (g)->name)
+#else
+#define gadget_is_mpc8272(g)	0
+#endif
+
 // CONFIG_USB_GADGET_SX2
 // CONFIG_USB_GADGET_SX2
 // CONFIG_USB_GADGET_AU1X00
 // CONFIG_USB_GADGET_AU1X00
 // ...
 // ...
@@ -143,5 +163,11 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x13;
 		return 0x13;
 	else if (gadget_is_imx(gadget))
 	else if (gadget_is_imx(gadget))
 		return 0x14;
 		return 0x14;
+	else if (gadget_is_musbhsfc(gadget))
+		return 0x15;
+	else if (gadget_is_musbhdrc(gadget))
+		return 0x16;
+	else if (gadget_is_mpc8272(gadget))
+		return 0x17;
 	return -ENOENT;
 	return -ENOENT;
 }
 }

+ 1 - 2
drivers/usb/gadget/goku_udc.c

@@ -275,11 +275,10 @@ goku_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
 
 
 	if (!_ep)
 	if (!_ep)
 		return NULL;
 		return NULL;
-	req = kmalloc(sizeof *req, gfp_flags);
+	req = kzalloc(sizeof *req, gfp_flags);
 	if (!req)
 	if (!req)
 		return NULL;
 		return NULL;
 
 
-	memset(req, 0, sizeof *req);
 	req->req.dma = DMA_ADDR_INVALID;
 	req->req.dma = DMA_ADDR_INVALID;
 	INIT_LIST_HEAD(&req->queue);
 	INIT_LIST_HEAD(&req->queue);
 	return &req->req;
 	return &req->req;

+ 2 - 4
drivers/usb/gadget/inode.c

@@ -170,10 +170,9 @@ static struct dev_data *dev_new (void)
 {
 {
 	struct dev_data		*dev;
 	struct dev_data		*dev;
 
 
-	dev = kmalloc (sizeof *dev, GFP_KERNEL);
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev)
 	if (!dev)
 		return NULL;
 		return NULL;
-	memset (dev, 0, sizeof *dev);
 	dev->state = STATE_DEV_DISABLED;
 	dev->state = STATE_DEV_DISABLED;
 	atomic_set (&dev->count, 1);
 	atomic_set (&dev->count, 1);
 	spin_lock_init (&dev->lock);
 	spin_lock_init (&dev->lock);
@@ -1592,10 +1591,9 @@ static int activate_ep_files (struct dev_data *dev)
 	gadget_for_each_ep (ep, dev->gadget) {
 	gadget_for_each_ep (ep, dev->gadget) {
 		struct ep_data	*data;
 		struct ep_data	*data;
 
 
-		data = kmalloc (sizeof *data, GFP_KERNEL);
+		data = kzalloc(sizeof(*data), GFP_KERNEL);
 		if (!data)
 		if (!data)
 			goto enomem;
 			goto enomem;
-		memset (data, 0, sizeof data);
 		data->state = STATE_EP_DISABLED;
 		data->state = STATE_EP_DISABLED;
 		init_MUTEX (&data->lock);
 		init_MUTEX (&data->lock);
 		init_waitqueue_head (&data->wait);
 		init_waitqueue_head (&data->wait);

+ 1 - 2
drivers/usb/gadget/lh7a40x_udc.c

@@ -1114,11 +1114,10 @@ static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep,
 
 
 	DEBUG("%s, %p\n", __FUNCTION__, ep);
 	DEBUG("%s, %p\n", __FUNCTION__, ep);
 
 
-	req = kmalloc(sizeof *req, gfp_flags);
+	req = kzalloc(sizeof(*req), gfp_flags);
 	if (!req)
 	if (!req)
 		return 0;
 		return 0;
 
 
-	memset(req, 0, sizeof *req);
 	INIT_LIST_HEAD(&req->queue);
 	INIT_LIST_HEAD(&req->queue);
 
 
 	return &req->req;
 	return &req->req;

+ 1 - 2
drivers/usb/gadget/net2280.c

@@ -386,11 +386,10 @@ net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
 		return NULL;
 		return NULL;
 	ep = container_of (_ep, struct net2280_ep, ep);
 	ep = container_of (_ep, struct net2280_ep, ep);
 
 
-	req = kmalloc (sizeof *req, gfp_flags);
+	req = kzalloc(sizeof(*req), gfp_flags);
 	if (!req)
 	if (!req)
 		return NULL;
 		return NULL;
 
 
-	memset (req, 0, sizeof *req);
 	req->req.dma = DMA_ADDR_INVALID;
 	req->req.dma = DMA_ADDR_INVALID;
 	INIT_LIST_HEAD (&req->queue);
 	INIT_LIST_HEAD (&req->queue);
 
 

+ 2 - 4
drivers/usb/gadget/omap_udc.c

@@ -273,9 +273,8 @@ omap_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
 {
 {
 	struct omap_req	*req;
 	struct omap_req	*req;
 
 
-	req = kmalloc(sizeof *req, gfp_flags);
+	req = kzalloc(sizeof(*req), gfp_flags);
 	if (req) {
 	if (req) {
-		memset (req, 0, sizeof *req);
 		req->req.dma = DMA_ADDR_INVALID;
 		req->req.dma = DMA_ADDR_INVALID;
 		INIT_LIST_HEAD (&req->queue);
 		INIT_LIST_HEAD (&req->queue);
 	}
 	}
@@ -2586,11 +2585,10 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv)
 	/* UDC_PULLUP_EN gates the chip clock */
 	/* UDC_PULLUP_EN gates the chip clock */
 	// OTG_SYSCON_1_REG |= DEV_IDLE_EN;
 	// OTG_SYSCON_1_REG |= DEV_IDLE_EN;
 
 
-	udc = kmalloc (sizeof *udc, SLAB_KERNEL);
+	udc = kzalloc(sizeof(*udc), SLAB_KERNEL);
 	if (!udc)
 	if (!udc)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	memset(udc, 0, sizeof *udc);
 	spin_lock_init (&udc->lock);
 	spin_lock_init (&udc->lock);
 
 
 	udc->gadget.ops = &omap_gadget_ops;
 	udc->gadget.ops = &omap_gadget_ops;

+ 1 - 2
drivers/usb/gadget/pxa2xx_udc.c

@@ -335,11 +335,10 @@ pxa2xx_ep_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
 {
 {
 	struct pxa2xx_request *req;
 	struct pxa2xx_request *req;
 
 
-	req = kmalloc (sizeof *req, gfp_flags);
+	req = kzalloc(sizeof(*req), gfp_flags);
 	if (!req)
 	if (!req)
 		return NULL;
 		return NULL;
 
 
-	memset (req, 0, sizeof *req);
 	INIT_LIST_HEAD (&req->queue);
 	INIT_LIST_HEAD (&req->queue);
 	return &req->req;
 	return &req->req;
 }
 }

+ 4 - 5
drivers/usb/gadget/serial.c

@@ -369,7 +369,7 @@ static struct usb_gadget_driver gs_gadget_driver = {
 #endif /* CONFIG_USB_GADGET_DUALSPEED */
 #endif /* CONFIG_USB_GADGET_DUALSPEED */
 	.function =		GS_LONG_NAME,
 	.function =		GS_LONG_NAME,
 	.bind =			gs_bind,
 	.bind =			gs_bind,
-	.unbind =		gs_unbind,
+	.unbind =		__exit_p(gs_unbind),
 	.setup =		gs_setup,
 	.setup =		gs_setup,
 	.disconnect =		gs_disconnect,
 	.disconnect =		gs_disconnect,
 	.driver = {
 	.driver = {
@@ -1413,7 +1413,7 @@ requeue:
  * Called on module load.  Allocates and initializes the device
  * Called on module load.  Allocates and initializes the device
  * structure and a control request.
  * structure and a control request.
  */
  */
-static int gs_bind(struct usb_gadget *gadget)
+static int __init gs_bind(struct usb_gadget *gadget)
 {
 {
 	int ret;
 	int ret;
 	struct usb_ep *ep;
 	struct usb_ep *ep;
@@ -1538,7 +1538,7 @@ autoconf_fail:
  * Called on module unload.  Frees the control request and device
  * Called on module unload.  Frees the control request and device
  * structure.
  * structure.
  */
  */
-static void gs_unbind(struct usb_gadget *gadget)
+static void __exit gs_unbind(struct usb_gadget *gadget)
 {
 {
 	struct gs_dev *dev = get_gadget_data(gadget);
 	struct gs_dev *dev = get_gadget_data(gadget);
 
 
@@ -2178,10 +2178,9 @@ static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags)
 		return -EIO;
 		return -EIO;
 
 
 	for (i=0; i<GS_NUM_PORTS; i++) {
 	for (i=0; i<GS_NUM_PORTS; i++) {
-		if ((port=(struct gs_port *)kmalloc(sizeof(struct gs_port), kmalloc_flags)) == NULL)
+		if ((port=kzalloc(sizeof(struct gs_port), kmalloc_flags)) == NULL)
 			return -ENOMEM;
 			return -ENOMEM;
 
 
-		memset(port, 0, sizeof(struct gs_port));
 		port->port_dev = dev;
 		port->port_dev = dev;
 		port->port_num = i;
 		port->port_num = i;
 		port->port_line_coding.dwDTERate = cpu_to_le32(GS_DEFAULT_DTE_RATE);
 		port->port_line_coding.dwDTERate = cpu_to_le32(GS_DEFAULT_DTE_RATE);

+ 4 - 11
drivers/usb/gadget/zero.c

@@ -1119,7 +1119,7 @@ zero_autoresume (unsigned long _dev)
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-static void
+static void __exit
 zero_unbind (struct usb_gadget *gadget)
 zero_unbind (struct usb_gadget *gadget)
 {
 {
 	struct zero_dev		*dev = get_gadget_data (gadget);
 	struct zero_dev		*dev = get_gadget_data (gadget);
@@ -1136,7 +1136,7 @@ zero_unbind (struct usb_gadget *gadget)
 	set_gadget_data (gadget, NULL);
 	set_gadget_data (gadget, NULL);
 }
 }
 
 
-static int
+static int __init
 zero_bind (struct usb_gadget *gadget)
 zero_bind (struct usb_gadget *gadget)
 {
 {
 	struct zero_dev		*dev;
 	struct zero_dev		*dev;
@@ -1188,10 +1188,9 @@ autoconf_fail:
 
 
 
 
 	/* ok, we made sense of the hardware ... */
 	/* ok, we made sense of the hardware ... */
-	dev = kmalloc (sizeof *dev, SLAB_KERNEL);
+	dev = kzalloc(sizeof(*dev), SLAB_KERNEL);
 	if (!dev)
 	if (!dev)
 		return -ENOMEM;
 		return -ENOMEM;
-	memset (dev, 0, sizeof *dev);
 	spin_lock_init (&dev->lock);
 	spin_lock_init (&dev->lock);
 	dev->gadget = gadget;
 	dev->gadget = gadget;
 	set_gadget_data (gadget, dev);
 	set_gadget_data (gadget, dev);
@@ -1224,12 +1223,6 @@ autoconf_fail:
 		loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 		loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 	}
 	}
 
 
-	if (gadget->is_otg) {
-		otg_descriptor.bmAttributes |= USB_OTG_HNP,
-		source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-		loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-	}
-
 	usb_gadget_set_selfpowered (gadget);
 	usb_gadget_set_selfpowered (gadget);
 
 
 	init_timer (&dev->resume);
 	init_timer (&dev->resume);
@@ -1294,7 +1287,7 @@ static struct usb_gadget_driver zero_driver = {
 #endif
 #endif
 	.function	= (char *) longname,
 	.function	= (char *) longname,
 	.bind		= zero_bind,
 	.bind		= zero_bind,
-	.unbind		= zero_unbind,
+	.unbind		= __exit_p(zero_unbind),
 
 
 	.setup		= zero_setup,
 	.setup		= zero_setup,
 	.disconnect	= zero_disconnect,
 	.disconnect	= zero_disconnect,

+ 1 - 1
drivers/usb/host/Kconfig

@@ -6,7 +6,7 @@ comment "USB Host Controller Drivers"
 
 
 config USB_EHCI_HCD
 config USB_EHCI_HCD
 	tristate "EHCI HCD (USB 2.0) support"
 	tristate "EHCI HCD (USB 2.0) support"
-	depends on USB && PCI
+	depends on USB && USB_ARCH_HAS_EHCI
 	---help---
 	---help---
 	  The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
 	  The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
 	  "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware.
 	  "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware.

+ 297 - 0
drivers/usb/host/ehci-au1xxx.c

@@ -0,0 +1,297 @@
+/*
+ * EHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * Bus Glue for AMD Alchemy Au1xxx
+ *
+ * Based on "ohci-au1xxx.c" by Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Modified for AMD Alchemy Au1200 EHC
+ *  by K.Boge <karsten.boge@amd.com>
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/platform_device.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#ifndef CONFIG_SOC_AU1200
+#error "this Alchemy chip doesn't have EHCI"
+#else				/* Au1200 */
+
+#define USB_HOST_CONFIG   (USB_MSR_BASE + USB_MSR_MCFG)
+#define USB_MCFG_PFEN     (1<<31)
+#define USB_MCFG_RDCOMB   (1<<30)
+#define USB_MCFG_SSDEN    (1<<23)
+#define USB_MCFG_PHYPLLEN (1<<19)
+#define USB_MCFG_EHCCLKEN (1<<17)
+#define USB_MCFG_UCAM     (1<<7)
+#define USB_MCFG_EBMEN    (1<<3)
+#define USB_MCFG_EMEMEN   (1<<2)
+
+#define USBH_ENABLE_CE    (USB_MCFG_PHYPLLEN | USB_MCFG_EHCCLKEN)
+
+#ifdef CONFIG_DMA_COHERENT
+#define USBH_ENABLE_INIT  (USBH_ENABLE_CE \
+                         | USB_MCFG_PFEN | USB_MCFG_RDCOMB \
+                         | USB_MCFG_SSDEN | USB_MCFG_UCAM \
+                         | USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
+#else
+#define USBH_ENABLE_INIT  (USBH_ENABLE_CE \
+                         | USB_MCFG_PFEN | USB_MCFG_RDCOMB \
+                         | USB_MCFG_SSDEN \
+                         | USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
+#endif
+#define USBH_DISABLE      (USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
+
+#endif				/* Au1200 */
+
+extern int usb_disabled(void);
+
+/*-------------------------------------------------------------------------*/
+
+static void au1xxx_start_ehc(struct platform_device *dev)
+{
+	pr_debug(__FILE__ ": starting Au1xxx EHCI USB Controller\n");
+
+	/* write HW defaults again in case Yamon cleared them */
+	if (au_readl(USB_HOST_CONFIG) == 0) {
+		au_writel(0x00d02000, USB_HOST_CONFIG);
+		au_readl(USB_HOST_CONFIG);
+		udelay(1000);
+	}
+	/* enable host controller */
+	au_writel(USBH_ENABLE_CE | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+	au_readl(USB_HOST_CONFIG);
+	udelay(1000);
+	au_writel(USBH_ENABLE_INIT | au_readl(USB_HOST_CONFIG),
+		  USB_HOST_CONFIG);
+	au_readl(USB_HOST_CONFIG);
+	udelay(1000);
+
+	pr_debug(__FILE__ ": Clock to USB host has been enabled\n");
+}
+
+static void au1xxx_stop_ehc(struct platform_device *dev)
+{
+	pr_debug(__FILE__ ": stopping Au1xxx EHCI USB Controller\n");
+
+	/* Disable mem */
+	au_writel(~USBH_DISABLE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+	udelay(1000);
+	/* Disable clock */
+	au_writel(~USB_MCFG_EHCCLKEN & au_readl(USB_HOST_CONFIG),
+		  USB_HOST_CONFIG);
+	au_readl(USB_HOST_CONFIG);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * usb_ehci_au1xxx_probe - initialize Au1xxx-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ */
+int usb_ehci_au1xxx_probe(const struct hc_driver *driver,
+			  struct usb_hcd **hcd_out, struct platform_device *dev)
+{
+	int retval;
+	struct usb_hcd *hcd;
+	struct ehci_hcd *ehci;
+
+#if defined(CONFIG_SOC_AU1200) && defined(CONFIG_DMA_COHERENT)
+
+	/* Au1200 AB USB does not support coherent memory */
+	if (!(read_c0_prid() & 0xff)) {
+		pr_info("%s: this is chip revision AB!\n", dev->dev.name);
+		pr_info("%s: update your board or re-configure the kernel\n",
+			dev->dev.name);
+		return -ENODEV;
+	}
+#endif
+
+	au1xxx_start_ehc(dev);
+
+	if (dev->resource[1].flags != IORESOURCE_IRQ) {
+		pr_debug("resource[1] is not IORESOURCE_IRQ");
+		retval = -ENOMEM;
+	}
+	hcd = usb_create_hcd(driver, &dev->dev, "Au1xxx");
+	if (!hcd)
+		return -ENOMEM;
+	hcd->rsrc_start = dev->resource[0].start;
+	hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		pr_debug("request_mem_region failed");
+		retval = -EBUSY;
+		goto err1;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		pr_debug("ioremap failed");
+		retval = -ENOMEM;
+		goto err2;
+	}
+
+	ehci = hcd_to_ehci(hcd);
+	ehci->caps = hcd->regs;
+	ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+	/* cache this readonly data; minimize chip reads */
+	ehci->hcs_params = readl(&ehci->caps->hcs_params);
+
+	/* ehci_hcd_init(hcd_to_ehci(hcd)); */
+
+	retval =
+	    usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT | SA_SHIRQ);
+	if (retval == 0)
+		return retval;
+
+	au1xxx_stop_ehc(dev);
+	iounmap(hcd->regs);
+err2:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err1:
+	usb_put_hcd(hcd);
+	return retval;
+}
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_ehci_hcd_au1xxx_remove - shutdown processing for Au1xxx-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_ehci_hcd_au1xxx_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+void usb_ehci_au1xxx_remove(struct usb_hcd *hcd, struct platform_device *dev)
+{
+	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+	au1xxx_stop_ehc(dev);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ehci_au1xxx_hc_driver = {
+	.description = hcd_name,
+	.product_desc = "Au1xxx EHCI",
+	.hcd_priv_size = sizeof(struct ehci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq = ehci_irq,
+	.flags = HCD_MEMORY | HCD_USB2,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset = ehci_init,
+	.start = ehci_run,
+	.stop = ehci_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue = ehci_urb_enqueue,
+	.urb_dequeue = ehci_urb_dequeue,
+	.endpoint_disable = ehci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number = ehci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data = ehci_hub_status_data,
+	.hub_control = ehci_hub_control,
+#ifdef	CONFIG_PM
+	.hub_suspend = ehci_hub_suspend,
+	.hub_resume = ehci_hub_resume,
+#endif
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ehci_hcd_au1xxx_drv_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = NULL;
+	int ret;
+
+	pr_debug("In ehci_hcd_au1xxx_drv_probe\n");
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	ret = usb_ehci_au1xxx_probe(&ehci_au1xxx_hc_driver, &hcd, pdev);
+	return ret;
+}
+
+static int ehci_hcd_au1xxx_drv_remove(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	usb_ehci_au1xxx_remove(hcd, pdev);
+	return 0;
+}
+
+ /*TBD*/
+/*static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	return 0;
+}
+static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	return 0;
+}
+*/
+static struct device_driver ehci_hcd_au1xxx_driver = {
+	.name = "au1xxx-ehci",
+	.bus = &platform_bus_type,
+	.probe = ehci_hcd_au1xxx_drv_probe,
+	.remove = ehci_hcd_au1xxx_drv_remove,
+	/*.suspend      = ehci_hcd_au1xxx_drv_suspend, */
+	/*.resume       = ehci_hcd_au1xxx_drv_resume, */
+};
+
+static int __init ehci_hcd_au1xxx_init(void)
+{
+	pr_debug(DRIVER_INFO " (Au1xxx)\n");
+
+	return driver_register(&ehci_hcd_au1xxx_driver);
+}
+
+static void __exit ehci_hcd_au1xxx_cleanup(void)
+{
+	driver_unregister(&ehci_hcd_au1xxx_driver);
+}
+
+module_init(ehci_hcd_au1xxx_init);
+module_exit(ehci_hcd_au1xxx_cleanup);

+ 366 - 0
drivers/usb/host/ehci-fsl.c

@@ -0,0 +1,366 @@
+/*
+ * (C) Copyright David Brownell 2000-2002
+ * Copyright (c) 2005 MontaVista Software
+ *
+ * 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.
+ *
+ * Ported to 834x by Randy Vinson <rvinson@mvista.com> using code provided
+ * by Hunter Wu.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+
+#include "ehci-fsl.h"
+
+/* FIXME: Power Managment is un-ported so temporarily disable it */
+#undef CONFIG_PM
+
+/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * usb_hcd_fsl_probe - initialize FSL-based HCDs
+ * @drvier: Driver to be used for this HCD
+ * @pdev: USB Host Controller being probed
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller.
+ *
+ */
+int usb_hcd_fsl_probe(const struct hc_driver *driver,
+		      struct platform_device *pdev)
+{
+	struct fsl_usb2_platform_data *pdata;
+	struct usb_hcd *hcd;
+	struct resource *res;
+	int irq;
+	int retval;
+	unsigned int temp;
+
+	pr_debug("initializing FSL-SOC USB Controller\n");
+
+	/* Need platform data for setup */
+	pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev,
+			"No platform data for %s.\n", pdev->dev.bus_id);
+		return -ENODEV;
+	}
+
+	/*
+	 * This is a host mode driver, verify that we're supposed to be
+	 * in host mode.
+	 */
+	if (!((pdata->operating_mode == FSL_USB2_DR_HOST) ||
+	      (pdata->operating_mode == FSL_USB2_MPH_HOST))) {
+		dev_err(&pdev->dev,
+			"Non Host Mode configured for %s. Wrong driver linked.\n",
+			pdev->dev.bus_id);
+		return -ENODEV;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(&pdev->dev,
+			"Found HC with no IRQ. Check %s setup!\n",
+			pdev->dev.bus_id);
+		return -ENODEV;
+	}
+	irq = res->start;
+
+	hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id);
+	if (!hcd) {
+		retval = -ENOMEM;
+		goto err1;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev,
+			"Found HC with no register addr. Check %s setup!\n",
+			pdev->dev.bus_id);
+		retval = -ENODEV;
+		goto err2;
+	}
+	hcd->rsrc_start = res->start;
+	hcd->rsrc_len = res->end - res->start + 1;
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+				driver->description)) {
+		dev_dbg(&pdev->dev, "controller already in use\n");
+		retval = -EBUSY;
+		goto err2;
+	}
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+
+	if (hcd->regs == NULL) {
+		dev_dbg(&pdev->dev, "error mapping memory\n");
+		retval = -EFAULT;
+		goto err3;
+	}
+
+	/* Enable USB controller */
+	temp = in_be32(hcd->regs + 0x500);
+	out_be32(hcd->regs + 0x500, temp | 0x4);
+
+	/* Set to Host mode */
+	temp = in_le32(hcd->regs + 0x1a8);
+	out_le32(hcd->regs + 0x1a8, temp | 0x3);
+
+	retval = usb_add_hcd(hcd, irq, SA_SHIRQ);
+	if (retval != 0)
+		goto err4;
+	return retval;
+
+      err4:
+	iounmap(hcd->regs);
+      err3:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+      err2:
+	usb_put_hcd(hcd);
+      err1:
+	dev_err(&pdev->dev, "init %s fail, %d\n", pdev->dev.bus_id, retval);
+	return retval;
+}
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_fsl_remove - shutdown processing for FSL-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_fsl_probe().
+ *
+ */
+void usb_hcd_fsl_remove(struct usb_hcd *hcd, struct platform_device *pdev)
+{
+	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+}
+
+static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
+			      enum fsl_usb2_phy_modes phy_mode,
+			      unsigned int port_offset)
+{
+	u32 portsc = 0;
+	switch (phy_mode) {
+	case FSL_USB2_PHY_ULPI:
+		portsc |= PORT_PTS_ULPI;
+		break;
+	case FSL_USB2_PHY_SERIAL:
+		portsc |= PORT_PTS_SERIAL;
+		break;
+	case FSL_USB2_PHY_UTMI_WIDE:
+		portsc |= PORT_PTS_PTW;
+		/* fall through */
+	case FSL_USB2_PHY_UTMI:
+		portsc |= PORT_PTS_UTMI;
+		break;
+	case FSL_USB2_PHY_NONE:
+		break;
+	}
+	writel(portsc, &ehci->regs->port_status[port_offset]);
+}
+
+static void mpc83xx_usb_setup(struct usb_hcd *hcd)
+{
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	struct fsl_usb2_platform_data *pdata;
+	void __iomem *non_ehci = hcd->regs;
+
+	pdata =
+	    (struct fsl_usb2_platform_data *)hcd->self.controller->
+	    platform_data;
+	/* Enable PHY interface in the control reg. */
+	out_be32(non_ehci + FSL_SOC_USB_CTRL, 0x00000004);
+	out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
+
+	if (pdata->operating_mode == FSL_USB2_DR_HOST)
+		mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
+
+	if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
+		unsigned int chip, rev, svr;
+
+		svr = mfspr(SPRN_SVR);
+		chip = svr >> 16;
+		rev = (svr >> 4) & 0xf;
+
+		/* Deal with USB Erratum #14 on MPC834x Rev 1.0 & 1.1 chips */
+		if ((rev == 1) && (chip >= 0x8050) && (chip <= 0x8055))
+			ehci->has_fsl_port_bug = 1;
+
+		if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
+			mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
+		if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
+			mpc83xx_setup_phy(ehci, pdata->phy_mode, 1);
+	}
+
+	/* put controller in host mode. */
+	writel(0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
+	out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
+	out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
+	out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
+}
+
+/* called after powerup, by probe or system-pm "wakeup" */
+static int ehci_fsl_reinit(struct ehci_hcd *ehci)
+{
+	mpc83xx_usb_setup(ehci_to_hcd(ehci));
+	ehci_port_power(ehci, 0);
+
+	return 0;
+}
+
+/* called during probe() after chip reset completes */
+static int ehci_fsl_setup(struct usb_hcd *hcd)
+{
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	int retval;
+
+	/* EHCI registers start at offset 0x100 */
+	ehci->caps = hcd->regs + 0x100;
+	ehci->regs = hcd->regs + 0x100 +
+	    HC_LENGTH(readl(&ehci->caps->hc_capbase));
+	dbg_hcs_params(ehci, "reset");
+	dbg_hcc_params(ehci, "reset");
+
+	/* cache this readonly data; minimize chip reads */
+	ehci->hcs_params = readl(&ehci->caps->hcs_params);
+
+	retval = ehci_halt(ehci);
+	if (retval)
+		return retval;
+
+	/* data structure init */
+	retval = ehci_init(hcd);
+	if (retval)
+		return retval;
+
+	ehci->is_tdi_rh_tt = 1;
+
+	ehci->sbrn = 0x20;
+
+	ehci_reset(ehci);
+
+	retval = ehci_fsl_reinit(ehci);
+	return retval;
+}
+
+static const struct hc_driver ehci_fsl_hc_driver = {
+	.description = hcd_name,
+	.product_desc = "Freescale On-Chip EHCI Host Controller",
+	.hcd_priv_size = sizeof(struct ehci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq = ehci_irq,
+	.flags = HCD_USB2,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset = ehci_fsl_setup,
+	.start = ehci_run,
+#ifdef	CONFIG_PM
+	.suspend = ehci_bus_suspend,
+	.resume = ehci_bus_resume,
+#endif
+	.stop = ehci_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue = ehci_urb_enqueue,
+	.urb_dequeue = ehci_urb_dequeue,
+	.endpoint_disable = ehci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number = ehci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data = ehci_hub_status_data,
+	.hub_control = ehci_hub_control,
+	.bus_suspend = ehci_bus_suspend,
+	.bus_resume = ehci_bus_resume,
+};
+
+static int ehci_fsl_drv_probe(struct platform_device *pdev)
+{
+	if (usb_disabled())
+		return -ENODEV;
+
+	return usb_hcd_fsl_probe(&ehci_fsl_hc_driver, pdev);
+}
+
+static int ehci_fsl_drv_remove(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+	usb_hcd_fsl_remove(hcd, pdev);
+
+	return 0;
+}
+
+static struct platform_driver ehci_fsl_dr_driver = {
+	.probe = ehci_fsl_drv_probe,
+	.remove = ehci_fsl_drv_remove,
+	.driver = {
+		   .name = "fsl-usb2-dr",
+		   },
+};
+
+static struct platform_driver ehci_fsl_mph_driver = {
+	.probe = ehci_fsl_drv_probe,
+	.remove = ehci_fsl_drv_remove,
+	.driver = {
+		   .name = "fsl-usb2-mph",
+		   },
+};
+
+static int __init ehci_fsl_init(void)
+{
+	int retval;
+
+	pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n",
+		 hcd_name,
+		 sizeof(struct ehci_qh), sizeof(struct ehci_qtd),
+		 sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
+
+	retval = platform_driver_register(&ehci_fsl_dr_driver);
+	if (retval)
+		return retval;
+
+	return platform_driver_register(&ehci_fsl_mph_driver);
+}
+
+static void __exit ehci_fsl_cleanup(void)
+{
+	platform_driver_unregister(&ehci_fsl_mph_driver);
+	platform_driver_unregister(&ehci_fsl_dr_driver);
+}
+
+module_init(ehci_fsl_init);
+module_exit(ehci_fsl_cleanup);

+ 37 - 0
drivers/usb/host/ehci-fsl.h

@@ -0,0 +1,37 @@
+/* Copyright (c) 2005 freescale semiconductor
+ * Copyright (c) 2005 MontaVista Software
+ *
+ * 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.
+ */
+#ifndef _EHCI_FSL_H
+#define _EHCI_FSL_H
+
+/* offsets for the non-ehci registers in the FSL SOC USB controller */
+#define FSL_SOC_USB_ULPIVP	0x170
+#define FSL_SOC_USB_PORTSC1	0x184
+#define PORT_PTS_MSK		(3<<30)
+#define PORT_PTS_UTMI		(0<<30)
+#define PORT_PTS_ULPI		(2<<30)
+#define	PORT_PTS_SERIAL		(3<<30)
+#define PORT_PTS_PTW		(1<<28)
+#define FSL_SOC_USB_PORTSC2	0x188
+#define FSL_SOC_USB_USBMODE	0x1a8
+#define FSL_SOC_USB_SNOOP1	0x400	/* NOTE: big-endian */
+#define FSL_SOC_USB_SNOOP2	0x404	/* NOTE: big-endian */
+#define FSL_SOC_USB_AGECNTTHRSH	0x408	/* NOTE: big-endian */
+#define FSL_SOC_USB_SICTRL	0x40c	/* NOTE: big-endian */
+#define FSL_SOC_USB_PRICTRL	0x410	/* NOTE: big-endian */
+#define FSL_SOC_USB_CTRL	0x500	/* NOTE: big-endian */
+#endif				/* _EHCI_FSL_H */

+ 12 - 1
drivers/usb/host/ehci-hcd.c

@@ -889,8 +889,19 @@ MODULE_LICENSE ("GPL");
 
 
 #ifdef CONFIG_PCI
 #ifdef CONFIG_PCI
 #include "ehci-pci.c"
 #include "ehci-pci.c"
+#define	EHCI_BUS_GLUED
 #endif
 #endif
 
 
-#if !defined(CONFIG_PCI)
+#ifdef CONFIG_PPC_83xx
+#include "ehci-fsl.c"
+#define	EHCI_BUS_GLUED
+#endif
+
+#ifdef CONFIG_SOC_AU1X00
+#include "ehci-au1xxx.c"
+#define	EHCI_BUS_GLUED
+#endif
+
+#ifndef	EHCI_BUS_GLUED
 #error "missing bus glue for ehci-hcd"
 #error "missing bus glue for ehci-hcd"
 #endif
 #endif

+ 4 - 0
drivers/usb/host/ehci-hub.c

@@ -359,6 +359,8 @@ static int ehci_hub_control (
 		case USB_PORT_FEAT_SUSPEND:
 		case USB_PORT_FEAT_SUSPEND:
 			if (temp & PORT_RESET)
 			if (temp & PORT_RESET)
 				goto error;
 				goto error;
+			if (ehci->no_selective_suspend)
+				break;
 			if (temp & PORT_SUSPEND) {
 			if (temp & PORT_SUSPEND) {
 				if ((temp & PORT_PE) == 0)
 				if ((temp & PORT_PE) == 0)
 					goto error;
 					goto error;
@@ -514,6 +516,8 @@ static int ehci_hub_control (
 		temp &= ~PORT_RWC_BITS;
 		temp &= ~PORT_RWC_BITS;
 		switch (wValue) {
 		switch (wValue) {
 		case USB_PORT_FEAT_SUSPEND:
 		case USB_PORT_FEAT_SUSPEND:
+			if (ehci->no_selective_suspend)
+				break;
 			if ((temp & PORT_PE) == 0
 			if ((temp & PORT_PE) == 0
 					|| (temp & PORT_RESET) != 0)
 					|| (temp & PORT_RESET) != 0)
 				goto error;
 				goto error;

+ 3 - 8
drivers/usb/host/ehci-mem.c

@@ -75,7 +75,6 @@ static void qh_destroy (struct kref *kref)
 	}
 	}
 	if (qh->dummy)
 	if (qh->dummy)
 		ehci_qtd_free (ehci, qh->dummy);
 		ehci_qtd_free (ehci, qh->dummy);
-	usb_put_dev (qh->dev);
 	dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
 	dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
 }
 }
 
 
@@ -221,13 +220,9 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
 		ehci->periodic [i] = EHCI_LIST_END;
 		ehci->periodic [i] = EHCI_LIST_END;
 
 
 	/* software shadow of hardware table */
 	/* software shadow of hardware table */
-	ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *), flags);
-	if (ehci->pshadow == NULL) {
-		goto fail;
-	}
-	memset (ehci->pshadow, 0, ehci->periodic_size * sizeof (void *));
-
-	return 0;
+	ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags);
+	if (ehci->pshadow != NULL)
+		return 0;
 
 
 fail:
 fail:
 	ehci_dbg (ehci, "couldn't init memory\n");
 	ehci_dbg (ehci, "couldn't init memory\n");

+ 24 - 1
drivers/usb/host/ehci-pci.c

@@ -106,11 +106,11 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 		}
 		}
 		break;
 		break;
 	case PCI_VENDOR_ID_NVIDIA:
 	case PCI_VENDOR_ID_NVIDIA:
+		switch (pdev->device) {
 		/* NVidia reports that certain chips don't handle
 		/* NVidia reports that certain chips don't handle
 		 * QH, ITD, or SITD addresses above 2GB.  (But TD,
 		 * QH, ITD, or SITD addresses above 2GB.  (But TD,
 		 * data buffer, and periodic schedule are normal.)
 		 * data buffer, and periodic schedule are normal.)
 		 */
 		 */
-		switch (pdev->device) {
 		case 0x003c:	/* MCP04 */
 		case 0x003c:	/* MCP04 */
 		case 0x005b:	/* CK804 */
 		case 0x005b:	/* CK804 */
 		case 0x00d8:	/* CK8 */
 		case 0x00d8:	/* CK8 */
@@ -120,6 +120,14 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 				ehci_warn(ehci, "can't enable NVidia "
 				ehci_warn(ehci, "can't enable NVidia "
 					"workaround for >2GB RAM\n");
 					"workaround for >2GB RAM\n");
 			break;
 			break;
+		/* Some NForce2 chips have problems with selective suspend;
+		 * fixed in newer silicon.
+		 */
+		case 0x0068:
+			pci_read_config_dword(pdev, PCI_REVISION_ID, &temp);
+			if ((temp & 0xff) < 0xa4)
+				ehci->no_selective_suspend = 1;
+			break;
 		}
 		}
 		break;
 		break;
 	}
 	}
@@ -163,6 +171,21 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 			device_init_wakeup(&pdev->dev, 1);
 			device_init_wakeup(&pdev->dev, 1);
 	}
 	}
 
 
+#ifdef	CONFIG_USB_SUSPEND
+	/* REVISIT: the controller works fine for wakeup iff the root hub
+	 * itself is "globally" suspended, but usbcore currently doesn't
+	 * understand such things.
+	 *
+	 * System suspend currently expects to be able to suspend the entire
+	 * device tree, device-at-a-time.  If we failed selective suspend
+	 * reports, system suspend would fail; so the root hub code must claim
+	 * success.  That's lying to usbcore, and it matters for for runtime
+	 * PM scenarios with selective suspend and remote wakeup...
+	 */
+	if (ehci->no_selective_suspend && device_can_wakeup(&pdev->dev))
+		ehci_warn(ehci, "selective suspend/wakeup unavailable\n");
+#endif
+
 	retval = ehci_pci_reinit(ehci, pdev);
 	retval = ehci_pci_reinit(ehci, pdev);
 done:
 done:
 	return retval;
 	return retval;

+ 13 - 4
drivers/usb/host/ehci-q.c

@@ -702,7 +702,7 @@ qh_make (
 	}
 	}
 
 
 	/* support for tt scheduling, and access to toggles */
 	/* support for tt scheduling, and access to toggles */
-	qh->dev = usb_get_dev (urb->dev);
+	qh->dev = urb->dev;
 
 
 	/* using TT? */
 	/* using TT? */
 	switch (urb->dev->speed) {
 	switch (urb->dev->speed) {
@@ -721,7 +721,14 @@ qh_make (
 		info1 |= maxp << 16;
 		info1 |= maxp << 16;
 
 
 		info2 |= (EHCI_TUNE_MULT_TT << 30);
 		info2 |= (EHCI_TUNE_MULT_TT << 30);
-		info2 |= urb->dev->ttport << 23;
+
+		/* Some Freescale processors have an erratum in which the
+		 * port number in the queue head was 0..N-1 instead of 1..N.
+		 */
+		if (ehci_has_fsl_portno_bug(ehci))
+			info2 |= (urb->dev->ttport-1) << 23;
+		else
+			info2 |= urb->dev->ttport << 23;
 
 
 		/* set the address of the TT; for TDI's integrated
 		/* set the address of the TT; for TDI's integrated
 		 * root hub tt, leave it zeroed.
 		 * root hub tt, leave it zeroed.
@@ -1015,12 +1022,14 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 	/* stop async schedule right now? */
 	/* stop async schedule right now? */
 	if (unlikely (qh == ehci->async)) {
 	if (unlikely (qh == ehci->async)) {
 		/* can't get here without STS_ASS set */
 		/* can't get here without STS_ASS set */
-		if (ehci_to_hcd(ehci)->state != HC_STATE_HALT) {
+		if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
+				&& !ehci->reclaim) {
+			/* ... and CMD_IAAD clear */
 			writel (cmd & ~CMD_ASE, &ehci->regs->command);
 			writel (cmd & ~CMD_ASE, &ehci->regs->command);
 			wmb ();
 			wmb ();
 			// handshake later, if we need to
 			// handshake later, if we need to
+			timer_action_done (ehci, TIMER_ASYNC_OFF);
 		}
 		}
-		timer_action_done (ehci, TIMER_ASYNC_OFF);
 		return;
 		return;
 	} 
 	} 
 
 

+ 9 - 11
drivers/usb/host/ehci-sched.c

@@ -707,6 +707,7 @@ iso_stream_init (
 	} else {
 	} else {
 		u32		addr;
 		u32		addr;
 		int		think_time;
 		int		think_time;
+		int		hs_transfers;
 
 
 		addr = dev->ttport << 24;
 		addr = dev->ttport << 24;
 		if (!ehci_is_TDI(ehci)
 		if (!ehci_is_TDI(ehci)
@@ -719,6 +720,7 @@ iso_stream_init (
 		think_time = dev->tt ? dev->tt->think_time : 0;
 		think_time = dev->tt ? dev->tt->think_time : 0;
 		stream->tt_usecs = NS_TO_US (think_time + usb_calc_bus_time (
 		stream->tt_usecs = NS_TO_US (think_time + usb_calc_bus_time (
 				dev->speed, is_input, 1, maxp));
 				dev->speed, is_input, 1, maxp));
+		hs_transfers = max (1u, (maxp + 187) / 188);
 		if (is_input) {
 		if (is_input) {
 			u32	tmp;
 			u32	tmp;
 
 
@@ -727,12 +729,11 @@ iso_stream_init (
 			stream->usecs = HS_USECS_ISO (1);
 			stream->usecs = HS_USECS_ISO (1);
 			stream->raw_mask = 1;
 			stream->raw_mask = 1;
 
 
-			/* pessimistic c-mask */
-			tmp = usb_calc_bus_time (USB_SPEED_FULL, 1, 0, maxp)
-					/ (125 * 1000);
-			stream->raw_mask |= 3 << (tmp + 9);
+			/* c-mask as specified in USB 2.0 11.18.4 3.c */
+			tmp = (1 << (hs_transfers + 2)) - 1;
+			stream->raw_mask |= tmp << (8 + 2);
 		} else
 		} else
-			stream->raw_mask = smask_out [maxp / 188];
+			stream->raw_mask = smask_out [hs_transfers - 1];
 		bandwidth = stream->usecs + stream->c_usecs;
 		bandwidth = stream->usecs + stream->c_usecs;
 		bandwidth /= 1 << (interval + 2);
 		bandwidth /= 1 << (interval + 2);
 
 
@@ -863,9 +864,8 @@ iso_sched_alloc (unsigned packets, gfp_t mem_flags)
 	int			size = sizeof *iso_sched;
 	int			size = sizeof *iso_sched;
 
 
 	size += packets * sizeof (struct ehci_iso_packet);
 	size += packets * sizeof (struct ehci_iso_packet);
-	iso_sched = kmalloc (size, mem_flags);
+	iso_sched = kzalloc(size, mem_flags);
 	if (likely (iso_sched != NULL)) {
 	if (likely (iso_sched != NULL)) {
-		memset(iso_sched, 0, size);
 		INIT_LIST_HEAD (&iso_sched->td_list);
 		INIT_LIST_HEAD (&iso_sched->td_list);
 	}
 	}
 	return iso_sched;
 	return iso_sched;
@@ -1398,7 +1398,7 @@ itd_complete (
 	 */
 	 */
 
 
 	/* give urb back to the driver ... can be out-of-order */
 	/* give urb back to the driver ... can be out-of-order */
-	dev = usb_get_dev (urb->dev);
+	dev = urb->dev;
 	ehci_urb_done (ehci, urb, regs);
 	ehci_urb_done (ehci, urb, regs);
 	urb = NULL;
 	urb = NULL;
 
 
@@ -1417,7 +1417,6 @@ itd_complete (
 			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
 			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
 	}
 	}
 	iso_stream_put (ehci, stream);
 	iso_stream_put (ehci, stream);
-	usb_put_dev (dev);
 
 
 	return 1;
 	return 1;
 }
 }
@@ -1764,7 +1763,7 @@ sitd_complete (
 	 */
 	 */
 
 
 	/* give urb back to the driver */
 	/* give urb back to the driver */
-	dev = usb_get_dev (urb->dev);
+	dev = urb->dev;
 	ehci_urb_done (ehci, urb, regs);
 	ehci_urb_done (ehci, urb, regs);
 	urb = NULL;
 	urb = NULL;
 
 
@@ -1783,7 +1782,6 @@ sitd_complete (
 			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
 			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
 	}
 	}
 	iso_stream_put (ehci, stream);
 	iso_stream_put (ehci, stream);
-	usb_put_dev (dev);
 
 
 	return 1;
 	return 1;
 }
 }

+ 17 - 1
drivers/usb/host/ehci.h

@@ -88,7 +88,12 @@ struct ehci_hcd {			/* one per controller */
 	unsigned long		next_statechange;
 	unsigned long		next_statechange;
 	u32			command;
 	u32			command;
 
 
+	/* SILICON QUIRKS */
 	unsigned		is_tdi_rh_tt:1;	/* TDI roothub with TT */
 	unsigned		is_tdi_rh_tt:1;	/* TDI roothub with TT */
+	unsigned		no_selective_suspend:1;
+	unsigned		has_fsl_port_bug:1; /* FreeScale */
+
+	u8			sbrn;		/* packed release number */
 
 
 	/* irq statistics */
 	/* irq statistics */
 #ifdef EHCI_STATS
 #ifdef EHCI_STATS
@@ -97,7 +102,6 @@ struct ehci_hcd {			/* one per controller */
 #else
 #else
 #	define COUNT(x) do {} while (0)
 #	define COUNT(x) do {} while (0)
 #endif
 #endif
-	u8			sbrn;		/* packed release number */
 };
 };
 
 
 /* convert between an HCD pointer and the corresponding EHCI_HCD */ 
 /* convert between an HCD pointer and the corresponding EHCI_HCD */ 
@@ -636,6 +640,18 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
 #define	ehci_port_speed(ehci, portsc)	(1<<USB_PORT_FEAT_HIGHSPEED)
 #define	ehci_port_speed(ehci, portsc)	(1<<USB_PORT_FEAT_HIGHSPEED)
 #endif
 #endif
 
 
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_PPC_83xx
+/* Some Freescale processors have an erratum in which the TT
+ * port number in the queue head was 0..N-1 instead of 1..N.
+ */
+#define	ehci_has_fsl_portno_bug(e)		((e)->has_fsl_port_bug)
+#else
+#define	ehci_has_fsl_portno_bug(e)		(0)
+#endif
+
+
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 #ifndef DEBUG
 #ifndef DEBUG

+ 4 - 8
drivers/usb/host/hc_crisv10.c

@@ -2137,10 +2137,9 @@ static int etrax_usb_submit_bulk_urb(struct urb *urb)
 	urb->status = -EINPROGRESS;
 	urb->status = -EINPROGRESS;
 
 
 	/* Setup the hcpriv data. */
 	/* Setup the hcpriv data. */
-	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+	urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
 	assert(urb_priv != NULL);
 	assert(urb_priv != NULL);
 	/* This sets rx_offset to 0. */
 	/* This sets rx_offset to 0. */
-	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
 	urb_priv->urb_state = NOT_STARTED;
 	urb_priv->urb_state = NOT_STARTED;
 	urb->hcpriv = urb_priv;
 	urb->hcpriv = urb_priv;
 
 
@@ -2475,10 +2474,9 @@ static int etrax_usb_submit_ctrl_urb(struct urb *urb)
 	urb->status = -EINPROGRESS;
 	urb->status = -EINPROGRESS;
 
 
 	/* Setup the hcpriv data. */
 	/* Setup the hcpriv data. */
-	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+	urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
 	assert(urb_priv != NULL);
 	assert(urb_priv != NULL);
 	/* This sets rx_offset to 0. */
 	/* This sets rx_offset to 0. */
-	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
 	urb_priv->urb_state = NOT_STARTED;
 	urb_priv->urb_state = NOT_STARTED;
 	urb->hcpriv = urb_priv;
 	urb->hcpriv = urb_priv;
 
 
@@ -2767,9 +2765,8 @@ static void etrax_usb_add_to_intr_sb_list(struct urb *urb, int epid)
 	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
 	maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
 	interval = urb->interval;
 	interval = urb->interval;
 
 
-	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
+	urb_priv = kzalloc(sizeof(etrax_urb_priv_t), KMALLOC_FLAG);
 	assert(urb_priv != NULL);
 	assert(urb_priv != NULL);
-	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
 	urb->hcpriv = urb_priv;
 	urb->hcpriv = urb_priv;
 
 
 	first_ep = &TxIntrEPList[0];
 	first_ep = &TxIntrEPList[0];
@@ -2997,9 +2994,8 @@ static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid)
 
 
 	prev_sb_desc = next_sb_desc = temp_sb_desc = NULL;
 	prev_sb_desc = next_sb_desc = temp_sb_desc = NULL;
 
 
-	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC);
+	urb_priv = kzalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC);
 	assert(urb_priv != NULL);
 	assert(urb_priv != NULL);
-	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
 
 
 	urb->hcpriv = urb_priv;
 	urb->hcpriv = urb_priv;
 	urb_priv->epid = epid;
 	urb_priv->epid = epid;

+ 2 - 3
drivers/usb/host/isp116x-hcd.c

@@ -724,7 +724,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
 		ep = hep->hcpriv;
 		ep = hep->hcpriv;
 	else {
 	else {
 		INIT_LIST_HEAD(&ep->schedule);
 		INIT_LIST_HEAD(&ep->schedule);
-		ep->udev = usb_get_dev(udev);
+		ep->udev = udev;
 		ep->epnum = epnum;
 		ep->epnum = epnum;
 		ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out);
 		ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out);
 		usb_settoggle(udev, epnum, is_out, 0);
 		usb_settoggle(udev, epnum, is_out, 0);
@@ -891,7 +891,6 @@ static void isp116x_endpoint_disable(struct usb_hcd *hcd,
 	if (!list_empty(&hep->urb_list))
 	if (!list_empty(&hep->urb_list))
 		WARN("ep %p not empty?\n", ep);
 		WARN("ep %p not empty?\n", ep);
 
 
-	usb_put_dev(ep->udev);
 	kfree(ep);
 	kfree(ep);
 	hep->hcpriv = NULL;
 	hep->hcpriv = NULL;
 }
 }
@@ -1553,7 +1552,7 @@ static struct hc_driver isp116x_hc_driver = {
 
 
 /*----------------------------------------------------------------*/
 /*----------------------------------------------------------------*/
 
 
-static int __init_or_module isp116x_remove(struct platform_device *pdev)
+static int isp116x_remove(struct platform_device *pdev)
 {
 {
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 	struct isp116x *isp116x;
 	struct isp116x *isp116x;

+ 306 - 0
drivers/usb/host/ohci-at91.c

@@ -0,0 +1,306 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ *  Copyright (C) 2004 SAN People (Pty) Ltd.
+ *  Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org>
+ *
+ * AT91RM9200 Bus Glue
+ *
+ * Based on fragments of 2.4 driver by Rick Bronson.
+ * Based on ohci-omap.c
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/arch/board.h>
+
+#ifndef CONFIG_ARCH_AT91RM9200
+#error "This file is AT91RM9200 bus glue.  CONFIG_ARCH_AT91RM9200 must be defined."
+#endif
+
+/* interface and function clocks */
+static struct clk *iclk, *fclk;
+
+extern int usb_disabled(void);
+
+/*-------------------------------------------------------------------------*/
+
+static void at91_start_hc(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+	struct ohci_regs __iomem *regs = hcd->regs;
+
+	dev_dbg(&pdev->dev, "starting AT91RM9200 OHCI USB Controller\n");
+
+	/*
+	 * Start the USB clocks.
+	 */
+	clk_enable(iclk);
+	clk_enable(fclk);
+
+	/*
+	 * The USB host controller must remain in reset.
+	 */
+	writel(0, &regs->control);
+}
+
+static void at91_stop_hc(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+	struct ohci_regs __iomem *regs = hcd->regs;
+
+	dev_dbg(&pdev->dev, "stopping AT91RM9200 OHCI USB Controller\n");
+
+	/*
+	 * Put the USB host controller into reset.
+	 */
+	writel(0, &regs->control);
+
+	/*
+	 * Stop the USB clocks.
+	 */
+	clk_disable(fclk);
+	clk_disable(iclk);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *);
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+
+/**
+ * usb_hcd_at91_probe - initialize AT91RM9200-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ * Store this function in the HCD's struct pci_driver as probe().
+ */
+int usb_hcd_at91_probe (const struct hc_driver *driver, struct platform_device *pdev)
+{
+	int retval;
+	struct usb_hcd *hcd = NULL;
+
+	if (pdev->num_resources != 2) {
+		pr_debug("hcd probe: invalid num_resources");
+		return -ENODEV;
+	}
+
+	if ((pdev->resource[0].flags != IORESOURCE_MEM) || (pdev->resource[1].flags != IORESOURCE_IRQ)) {
+		pr_debug("hcd probe: invalid resource type\n");
+		return -ENODEV;
+	}
+
+	hcd = usb_create_hcd(driver, &pdev->dev, "at91rm9200");
+	if (!hcd)
+		return -ENOMEM;
+	hcd->rsrc_start = pdev->resource[0].start;
+	hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		pr_debug("request_mem_region failed\n");
+		retval = -EBUSY;
+		goto err1;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		pr_debug("ioremap failed\n");
+		retval = -EIO;
+		goto err2;
+	}
+
+	iclk = clk_get(&pdev->dev, "ohci_clk");
+	fclk = clk_get(&pdev->dev, "uhpck");
+
+	at91_start_hc(pdev);
+	ohci_hcd_init(hcd_to_ohci(hcd));
+
+	retval = usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT);
+	if (retval == 0)
+		return retval;
+
+	/* Error handling */
+	at91_stop_hc(pdev);
+
+	clk_put(fclk);
+	clk_put(iclk);
+
+	iounmap(hcd->regs);
+
+ err2:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+ err1:
+	usb_put_hcd(hcd);
+	return retval;
+}
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_at91_remove - shutdown processing for AT91RM9200-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_at91_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+static int usb_hcd_at91_remove (struct usb_hcd *hcd, struct platform_device *pdev)
+{
+	usb_remove_hcd(hcd);
+	at91_stop_hc(pdev);
+	iounmap(hcd->regs);
+ 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+ 	clk_put(fclk);
+ 	clk_put(iclk);
+ 	fclk = iclk = NULL;
+
+	dev_set_drvdata(&pdev->dev, NULL);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_at91_start (struct usb_hcd *hcd)
+{
+//	struct at91_ohci_data	*board = hcd->self.controller->platform_data;
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+	int			ret;
+
+	if ((ret = ohci_init(ohci)) < 0)
+		return ret;
+
+	if ((ret = ohci_run(ohci)) < 0) {
+		err("can't start %s", hcd->self.bus_name);
+		ohci_stop(hcd);
+		return ret;
+	}
+//	hcd->self.root_hub->maxchild = board->ports;
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_at91_hc_driver = {
+	.description =		hcd_name,
+	.product_desc =		"AT91RM9200 OHCI",
+	.hcd_priv_size =	sizeof(struct ohci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ohci_irq,
+	.flags =		HCD_USB11 | HCD_MEMORY,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.start =		ohci_at91_start,
+	.stop =			ohci_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ohci_urb_enqueue,
+	.urb_dequeue =		ohci_urb_dequeue,
+	.endpoint_disable =	ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ohci_hub_status_data,
+	.hub_control =		ohci_hub_control,
+
+#ifdef CONFIG_PM
+	.hub_suspend =		ohci_hub_suspend,
+	.hub_resume =		ohci_hub_resume,
+#endif
+	.start_port_reset =	ohci_start_port_reset,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hcd_at91_drv_probe(struct platform_device *dev)
+{
+	return usb_hcd_at91_probe(&ohci_at91_hc_driver, dev);
+}
+
+static int ohci_hcd_at91_drv_remove(struct platform_device *dev)
+{
+	return usb_hcd_at91_remove(platform_get_drvdata(dev), dev);
+}
+
+#ifdef CONFIG_PM
+static int ohci_hcd_at91_drv_suspend(struct platform_device *dev, u32 state, u32 level)
+{
+	printk("%s(%s:%d): not implemented yet\n",
+		__func__, __FILE__, __LINE__);
+
+	clk_disable(fclk);
+
+	return 0;
+}
+
+static int ohci_hcd_at91_drv_resume(struct platform_device *dev, u32 state)
+{
+	printk("%s(%s:%d): not implemented yet\n",
+		__func__, __FILE__, __LINE__);
+
+	clk_enable(fclk);
+
+	return 0;
+}
+#else
+#define ohci_hcd_at91_drv_suspend NULL
+#define ohci_hcd_at91_drv_resume  NULL
+#endif
+
+static struct platform_driver ohci_hcd_at91_driver = {
+	.probe		= ohci_hcd_at91_drv_probe,
+	.remove		= ohci_hcd_at91_drv_remove,
+	.suspend	= ohci_hcd_at91_drv_suspend,
+	.resume		= ohci_hcd_at91_drv_resume,
+	.driver		= {
+		.name	= "at91rm9200-ohci",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init ohci_hcd_at91_init (void)
+{
+	if (usb_disabled())
+		return -ENODEV;
+
+	return platform_driver_register(&ohci_hcd_at91_driver);
+}
+
+static void __exit ohci_hcd_at91_cleanup (void)
+{
+	platform_driver_unregister(&ohci_hcd_at91_driver);
+}
+
+module_init (ohci_hcd_at91_init);
+module_exit (ohci_hcd_at91_cleanup);

+ 87 - 15
drivers/usb/host/ohci-au1xxx.c

@@ -23,6 +23,8 @@
 
 
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-au1x00/au1000.h>
 
 
+#ifndef	CONFIG_SOC_AU1200
+
 #define USBH_ENABLE_BE (1<<0)
 #define USBH_ENABLE_BE (1<<0)
 #define USBH_ENABLE_C  (1<<1)
 #define USBH_ENABLE_C  (1<<1)
 #define USBH_ENABLE_E  (1<<2)
 #define USBH_ENABLE_E  (1<<2)
@@ -37,21 +39,68 @@
 #error not byte order defined
 #error not byte order defined
 #endif
 #endif
 
 
+#else   /* Au1200 */
+
+#define USB_HOST_CONFIG    (USB_MSR_BASE + USB_MSR_MCFG)
+#define USB_MCFG_PFEN     (1<<31)
+#define USB_MCFG_RDCOMB   (1<<30)
+#define USB_MCFG_SSDEN    (1<<23)
+#define USB_MCFG_OHCCLKEN (1<<16)
+#define USB_MCFG_UCAM     (1<<7)
+#define USB_MCFG_OBMEN    (1<<1)
+#define USB_MCFG_OMEMEN   (1<<0)
+
+#define USBH_ENABLE_CE    USB_MCFG_OHCCLKEN
+#ifdef CONFIG_DMA_COHERENT
+#define USBH_ENABLE_INIT  (USB_MCFG_OHCCLKEN \
+                         | USB_MCFG_PFEN | USB_MCFG_RDCOMB \
+                         | USB_MCFG_SSDEN | USB_MCFG_UCAM \
+                         | USB_MCFG_OBMEN | USB_MCFG_OMEMEN)
+#else
+#define USBH_ENABLE_INIT  (USB_MCFG_OHCCLKEN \
+                         | USB_MCFG_PFEN | USB_MCFG_RDCOMB \
+                         | USB_MCFG_SSDEN \
+                         | USB_MCFG_OBMEN | USB_MCFG_OMEMEN)
+#endif
+#define USBH_DISABLE      (USB_MCFG_OBMEN | USB_MCFG_OMEMEN)
+
+#endif  /* Au1200 */
+
 extern int usb_disabled(void);
 extern int usb_disabled(void);
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-static void au1xxx_start_hc(struct platform_device *dev)
+static void au1xxx_start_ohc(struct platform_device *dev)
 {
 {
 	printk(KERN_DEBUG __FILE__
 	printk(KERN_DEBUG __FILE__
 		": starting Au1xxx OHCI USB Controller\n");
 		": starting Au1xxx OHCI USB Controller\n");
 
 
 	/* enable host controller */
 	/* enable host controller */
+
+#ifndef CONFIG_SOC_AU1200
+
 	au_writel(USBH_ENABLE_CE, USB_HOST_CONFIG);
 	au_writel(USBH_ENABLE_CE, USB_HOST_CONFIG);
 	udelay(1000);
 	udelay(1000);
 	au_writel(USBH_ENABLE_INIT, USB_HOST_CONFIG);
 	au_writel(USBH_ENABLE_INIT, USB_HOST_CONFIG);
 	udelay(1000);
 	udelay(1000);
 
 
+#else   /* Au1200 */
+
+	/* write HW defaults again in case Yamon cleared them */
+	if (au_readl(USB_HOST_CONFIG) == 0) {
+		au_writel(0x00d02000, USB_HOST_CONFIG);
+		au_readl(USB_HOST_CONFIG);
+		udelay(1000);
+	}
+	au_writel(USBH_ENABLE_CE | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+	au_readl(USB_HOST_CONFIG);
+	udelay(1000);
+	au_writel(USBH_ENABLE_INIT | au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+	au_readl(USB_HOST_CONFIG);
+	udelay(1000);
+
+#endif  /* Au1200 */
+
 	/* wait for reset complete (read register twice; see au1500 errata) */
 	/* wait for reset complete (read register twice; see au1500 errata) */
 	while (au_readl(USB_HOST_CONFIG),
 	while (au_readl(USB_HOST_CONFIG),
 		!(au_readl(USB_HOST_CONFIG) & USBH_ENABLE_RD))
 		!(au_readl(USB_HOST_CONFIG) & USBH_ENABLE_RD))
@@ -61,13 +110,25 @@ static void au1xxx_start_hc(struct platform_device *dev)
 	": Clock to USB host has been enabled \n");
 	": Clock to USB host has been enabled \n");
 }
 }
 
 
-static void au1xxx_stop_hc(struct platform_device *dev)
+static void au1xxx_stop_ohc(struct platform_device *dev)
 {
 {
 	printk(KERN_DEBUG __FILE__
 	printk(KERN_DEBUG __FILE__
 	       ": stopping Au1xxx OHCI USB Controller\n");
 	       ": stopping Au1xxx OHCI USB Controller\n");
 
 
+#ifndef CONFIG_SOC_AU1200
+
 	/* Disable clock */
 	/* Disable clock */
 	au_writel(au_readl(USB_HOST_CONFIG) & ~USBH_ENABLE_CE, USB_HOST_CONFIG);
 	au_writel(au_readl(USB_HOST_CONFIG) & ~USBH_ENABLE_CE, USB_HOST_CONFIG);
+
+#else   /* Au1200 */
+
+	/* Disable mem */
+	au_writel(~USBH_DISABLE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+	udelay(1000);
+	/* Disable clock */
+	au_writel(~USBH_ENABLE_CE & au_readl(USB_HOST_CONFIG), USB_HOST_CONFIG);
+	au_readl(USB_HOST_CONFIG);
+#endif  /* Au1200 */
 }
 }
 
 
 
 
@@ -78,7 +139,7 @@ static void au1xxx_stop_hc(struct platform_device *dev)
 
 
 
 
 /**
 /**
- * usb_hcd_au1xxx_probe - initialize Au1xxx-based HCDs
+ * usb_ohci_au1xxx_probe - initialize Au1xxx-based HCDs
  * Context: !in_interrupt()
  * Context: !in_interrupt()
  *
  *
  * Allocates basic resources for this USB host controller, and
  * Allocates basic resources for this USB host controller, and
@@ -86,14 +147,25 @@ static void au1xxx_stop_hc(struct platform_device *dev)
  * through the hotplug entry's driver_data.
  * through the hotplug entry's driver_data.
  *
  *
  */
  */
-int usb_hcd_au1xxx_probe (const struct hc_driver *driver,
+static int usb_ohci_au1xxx_probe(const struct hc_driver *driver,
 			  struct platform_device *dev)
 			  struct platform_device *dev)
 {
 {
 	int retval;
 	int retval;
 	struct usb_hcd *hcd;
 	struct usb_hcd *hcd;
 
 
-	if(dev->resource[1].flags != IORESOURCE_IRQ) {
-		pr_debug ("resource[1] is not IORESOURCE_IRQ");
+#if defined(CONFIG_SOC_AU1200) && defined(CONFIG_DMA_COHERENT)
+	/* Au1200 AB USB does not support coherent memory */
+	if (!(read_c0_prid() & 0xff)) {
+		pr_info("%s: this is chip revision AB !!\n",
+			dev->dev.name);
+		pr_info("%s: update your board or re-configure the kernel\n",
+			dev->dev.name);
+		return -ENODEV;
+	}
+#endif
+
+	if (dev->resource[1].flags != IORESOURCE_IRQ) {
+		pr_debug("resource[1] is not IORESOURCE_IRQ\n");
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 
 
@@ -104,26 +176,26 @@ int usb_hcd_au1xxx_probe (const struct hc_driver *driver,
 	hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
 	hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
 
 
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		pr_debug("request_mem_region failed");
+		pr_debug("request_mem_region failed\n");
 		retval = -EBUSY;
 		retval = -EBUSY;
 		goto err1;
 		goto err1;
 	}
 	}
 
 
 	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 	if (!hcd->regs) {
 	if (!hcd->regs) {
-		pr_debug("ioremap failed");
+		pr_debug("ioremap failed\n");
 		retval = -ENOMEM;
 		retval = -ENOMEM;
 		goto err2;
 		goto err2;
 	}
 	}
 
 
-	au1xxx_start_hc(dev);
+	au1xxx_start_ohc(dev);
 	ohci_hcd_init(hcd_to_ohci(hcd));
 	ohci_hcd_init(hcd_to_ohci(hcd));
 
 
-	retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
+	retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT | SA_SHIRQ);
 	if (retval == 0)
 	if (retval == 0)
 		return retval;
 		return retval;
 
 
-	au1xxx_stop_hc(dev);
+	au1xxx_stop_ohc(dev);
 	iounmap(hcd->regs);
 	iounmap(hcd->regs);
  err2:
  err2:
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
@@ -146,10 +218,10 @@ int usb_hcd_au1xxx_probe (const struct hc_driver *driver,
  * context, normally "rmmod", "apmd", or something similar.
  * context, normally "rmmod", "apmd", or something similar.
  *
  *
  */
  */
-void usb_hcd_au1xxx_remove (struct usb_hcd *hcd, struct platform_device *dev)
+static void usb_ohci_au1xxx_remove(struct usb_hcd *hcd, struct platform_device *dev)
 {
 {
 	usb_remove_hcd(hcd);
 	usb_remove_hcd(hcd);
-	au1xxx_stop_hc(dev);
+	au1xxx_stop_ohc(dev);
 	iounmap(hcd->regs);
 	iounmap(hcd->regs);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
 	usb_put_hcd(hcd);
@@ -235,7 +307,7 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 	if (usb_disabled())
 	if (usb_disabled())
 		return -ENODEV;
 		return -ENODEV;
 
 
-	ret = usb_hcd_au1xxx_probe(&ohci_au1xxx_hc_driver, pdev);
+	ret = usb_ohci_au1xxx_probe(&ohci_au1xxx_hc_driver, pdev);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -243,7 +315,7 @@ static int ohci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
 {
 {
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
 
-	usb_hcd_au1xxx_remove(hcd, pdev);
+	usb_ohci_au1xxx_remove(hcd, pdev);
 	return 0;
 	return 0;
 }
 }
 	/*TBD*/
 	/*TBD*/

+ 32 - 22
drivers/usb/host/ohci-hcd.c

@@ -443,11 +443,16 @@ ohci_reboot (struct notifier_block *block, unsigned long code, void *null)
 static int ohci_init (struct ohci_hcd *ohci)
 static int ohci_init (struct ohci_hcd *ohci)
 {
 {
 	int ret;
 	int ret;
+	struct usb_hcd *hcd = ohci_to_hcd(ohci);
 
 
 	disable (ohci);
 	disable (ohci);
-	ohci->regs = ohci_to_hcd(ohci)->regs;
+	ohci->regs = hcd->regs;
 	ohci->next_statechange = jiffies;
 	ohci->next_statechange = jiffies;
 
 
+	/* REVISIT this BIOS handshake is now moved into PCI "quirks", and
+	 * was never needed for most non-PCI systems ... remove the code?
+	 */
+
 #ifndef IR_DISABLE
 #ifndef IR_DISABLE
 	/* SMM owns the HC?  not for long! */
 	/* SMM owns the HC?  not for long! */
 	if (!no_handshake && ohci_readl (ohci,
 	if (!no_handshake && ohci_readl (ohci,
@@ -478,8 +483,10 @@ static int ohci_init (struct ohci_hcd *ohci)
 
 
 	/* Disable HC interrupts */
 	/* Disable HC interrupts */
 	ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
 	ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
-	// flush the writes
-	(void) ohci_readl (ohci, &ohci->regs->control);
+
+	/* flush the writes, and save key bits like RWC */
+	if (ohci_readl (ohci, &ohci->regs->control) & OHCI_CTRL_RWC)
+		ohci->hc_control |= OHCI_CTRL_RWC;
 
 
 	/* Read the number of ports unless overridden */
 	/* Read the number of ports unless overridden */
 	if (ohci->num_ports == 0)
 	if (ohci->num_ports == 0)
@@ -488,16 +495,19 @@ static int ohci_init (struct ohci_hcd *ohci)
 	if (ohci->hcca)
 	if (ohci->hcca)
 		return 0;
 		return 0;
 
 
-	ohci->hcca = dma_alloc_coherent (ohci_to_hcd(ohci)->self.controller,
+	ohci->hcca = dma_alloc_coherent (hcd->self.controller,
 			sizeof *ohci->hcca, &ohci->hcca_dma, 0);
 			sizeof *ohci->hcca, &ohci->hcca_dma, 0);
 	if (!ohci->hcca)
 	if (!ohci->hcca)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	if ((ret = ohci_mem_init (ohci)) < 0)
 	if ((ret = ohci_mem_init (ohci)) < 0)
-		ohci_stop (ohci_to_hcd(ohci));
+		ohci_stop (hcd);
+	else {
+		register_reboot_notifier (&ohci->reboot_notifier);
+		create_debug_files (ohci);
+	}
 
 
 	return ret;
 	return ret;
-
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -510,6 +520,7 @@ static int ohci_run (struct ohci_hcd *ohci)
 {
 {
   	u32			mask, temp;
   	u32			mask, temp;
 	int			first = ohci->fminterval == 0;
 	int			first = ohci->fminterval == 0;
+	struct usb_hcd		*hcd = ohci_to_hcd(ohci);
 
 
 	disable (ohci);
 	disable (ohci);
 
 
@@ -525,18 +536,17 @@ static int ohci_run (struct ohci_hcd *ohci)
 		/* also: power/overcurrent flags in roothub.a */
 		/* also: power/overcurrent flags in roothub.a */
 	}
 	}
 
 
-  	/* Reset USB nearly "by the book".  RemoteWakeupConnected
-	 * saved if boot firmware (BIOS/SMM/...) told us it's connected
-	 * (for OHCI integrated on mainboard, it normally is)
+  	/* Reset USB nearly "by the book".  RemoteWakeupConnected was
+	 * saved if boot firmware (BIOS/SMM/...) told us it's connected,
+	 * or if bus glue did the same (e.g. for PCI add-in cards with
+	 * PCI PM support).
 	 */
 	 */
-	ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
 	ohci_dbg (ohci, "resetting from state '%s', control = 0x%x\n",
 	ohci_dbg (ohci, "resetting from state '%s', control = 0x%x\n",
 			hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
 			hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
-			ohci->hc_control);
-
-	if (ohci->hc_control & OHCI_CTRL_RWC
-			&& !(ohci->flags & OHCI_QUIRK_AMD756))
-		ohci_to_hcd(ohci)->can_wakeup = 1;
+			ohci_readl (ohci, &ohci->regs->control));
+	if ((ohci->hc_control & OHCI_CTRL_RWC) != 0
+			&& !device_may_wakeup(hcd->self.controller))
+		device_init_wakeup(hcd->self.controller, 1);
 
 
 	switch (ohci->hc_control & OHCI_CTRL_HCFS) {
 	switch (ohci->hc_control & OHCI_CTRL_HCFS) {
 	case OHCI_USB_OPER:
 	case OHCI_USB_OPER:
@@ -632,7 +642,7 @@ retry:
 	ohci->hc_control &= OHCI_CTRL_RWC;
 	ohci->hc_control &= OHCI_CTRL_RWC;
  	ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
  	ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
  	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
  	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
-	ohci_to_hcd(ohci)->state = HC_STATE_RUNNING;
+	hcd->state = HC_STATE_RUNNING;
 
 
 	/* wake on ConnectStatusChange, matching external hubs */
 	/* wake on ConnectStatusChange, matching external hubs */
 	ohci_writel (ohci, RH_HS_DRWE, &ohci->regs->roothub.status);
 	ohci_writel (ohci, RH_HS_DRWE, &ohci->regs->roothub.status);
@@ -667,15 +677,10 @@ retry:
 
 
 	// POTPGT delay is bits 24-31, in 2 ms units.
 	// POTPGT delay is bits 24-31, in 2 ms units.
 	mdelay ((temp >> 23) & 0x1fe);
 	mdelay ((temp >> 23) & 0x1fe);
-	ohci_to_hcd(ohci)->state = HC_STATE_RUNNING;
+	hcd->state = HC_STATE_RUNNING;
 
 
 	ohci_dump (ohci, 1);
 	ohci_dump (ohci, 1);
 
 
-	if (ohci_to_hcd(ohci)->self.root_hub == NULL) {
-		register_reboot_notifier (&ohci->reboot_notifier);
-		create_debug_files (ohci);
-	}
-
 	return 0;
 	return 0;
 }
 }
 
 
@@ -905,6 +910,10 @@ MODULE_LICENSE ("GPL");
 #include "ohci-ppc-soc.c"
 #include "ohci-ppc-soc.c"
 #endif
 #endif
 
 
+#ifdef CONFIG_ARCH_AT91RM9200
+#include "ohci-at91.c"
+#endif
+
 #if !(defined(CONFIG_PCI) \
 #if !(defined(CONFIG_PCI) \
       || defined(CONFIG_SA1111) \
       || defined(CONFIG_SA1111) \
       || defined(CONFIG_ARCH_S3C2410) \
       || defined(CONFIG_ARCH_S3C2410) \
@@ -913,6 +922,7 @@ MODULE_LICENSE ("GPL");
       || defined (CONFIG_PXA27x) \
       || defined (CONFIG_PXA27x) \
       || defined (CONFIG_SOC_AU1X00) \
       || defined (CONFIG_SOC_AU1X00) \
       || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
       || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
+      || defined (CONFIG_ARCH_AT91RM9200) \
 	)
 	)
 #error "missing bus glue for ohci-hcd"
 #error "missing bus glue for ohci-hcd"
 #endif
 #endif

+ 6 - 6
drivers/usb/host/ohci-hub.c

@@ -107,7 +107,7 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
 			&ohci->regs->intrstatus);
 			&ohci->regs->intrstatus);
 
 
 	/* maybe resume can wake root hub */
 	/* maybe resume can wake root hub */
-	if (hcd->remote_wakeup)
+	if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev))
 		ohci->hc_control |= OHCI_CTRL_RWE;
 		ohci->hc_control |= OHCI_CTRL_RWE;
 	else
 	else
 		ohci->hc_control &= ~OHCI_CTRL_RWE;
 		ohci->hc_control &= ~OHCI_CTRL_RWE;
@@ -246,9 +246,9 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
 	(void) ohci_readl (ohci, &ohci->regs->control);
 	(void) ohci_readl (ohci, &ohci->regs->control);
 	msleep (3);
 	msleep (3);
 
 
-	temp = OHCI_CONTROL_INIT | OHCI_USB_OPER;
-	if (hcd->can_wakeup)
-		temp |= OHCI_CTRL_RWC;
+	temp = ohci->hc_control;
+	temp &= OHCI_CTRL_RWC;
+	temp |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
 	ohci->hc_control = temp;
 	ohci->hc_control = temp;
 	ohci_writel (ohci, temp, &ohci->regs->control);
 	ohci_writel (ohci, temp, &ohci->regs->control);
 	(void) ohci_readl (ohci, &ohci->regs->control);
 	(void) ohci_readl (ohci, &ohci->regs->control);
@@ -302,7 +302,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
 {
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 	int		i, changed = 0, length = 1;
 	int		i, changed = 0, length = 1;
-	int		can_suspend = hcd->can_wakeup;
+	int		can_suspend = device_may_wakeup(&hcd->self.root_hub->dev);
 	unsigned long	flags;
 	unsigned long	flags;
 
 
 	spin_lock_irqsave (&ohci->lock, flags);
 	spin_lock_irqsave (&ohci->lock, flags);
@@ -354,7 +354,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
 		 */
 		 */
 		if (!(status & RH_PS_CCS))
 		if (!(status & RH_PS_CCS))
 			continue;
 			continue;
-		if ((status & RH_PS_PSS) && hcd->remote_wakeup)
+		if ((status & RH_PS_PSS) && can_suspend)
 			continue;
 			continue;
 		can_suspend = 0;
 		can_suspend = 0;
 	}
 	}

+ 13 - 2
drivers/usb/host/ohci-pci.c

@@ -35,7 +35,10 @@ ohci_pci_start (struct usb_hcd *hcd)
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 	int		ret;
 	int		ret;
 
 
-	if(hcd->self.controller && hcd->self.controller->bus == &pci_bus_type) {
+	/* REVISIT this whole block should move to reset(), which handles
+	 * all the other one-time init.
+	 */
+	if (hcd->self.controller) {
 		struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
 		struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
 
 
 		/* AMD 756, for most chips (early revs), corrupts register
 		/* AMD 756, for most chips (early revs), corrupts register
@@ -45,7 +48,8 @@ ohci_pci_start (struct usb_hcd *hcd)
 				&& pdev->device == 0x740c) {
 				&& pdev->device == 0x740c) {
 			ohci->flags = OHCI_QUIRK_AMD756;
 			ohci->flags = OHCI_QUIRK_AMD756;
 			ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
 			ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
-			// also somewhat erratum 10 (suspend/resume issues)
+			/* also erratum 10 (suspend/resume issues) */
+			device_init_wakeup(&hcd->self.root_hub->dev, 0);
 		}
 		}
 
 
 		/* FIXME for some of the early AMD 760 southbridges, OHCI
 		/* FIXME for some of the early AMD 760 southbridges, OHCI
@@ -88,6 +92,13 @@ ohci_pci_start (struct usb_hcd *hcd)
 			ohci_dbg (ohci,
 			ohci_dbg (ohci,
 				"enabled Compaq ZFMicro chipset quirk\n");
 				"enabled Compaq ZFMicro chipset quirk\n");
 		}
 		}
+
+		/* RWC may not be set for add-in PCI cards, since boot
+		 * firmware probably ignored them.  This transfers PCI
+		 * PM wakeup capabilities (once the PCI layer is fixed).
+		 */
+		if (device_may_wakeup(&pdev->dev))
+			ohci->hc_control |= OHCI_CTRL_RWC;
 	}
 	}
 
 
 	/* NOTE: there may have already been a first reset, to
 	/* NOTE: there may have already been a first reset, to

+ 1 - 2
drivers/usb/host/sl811-hcd.c

@@ -853,7 +853,7 @@ static int sl811h_urb_enqueue(
 
 
 	} else {
 	} else {
 		INIT_LIST_HEAD(&ep->schedule);
 		INIT_LIST_HEAD(&ep->schedule);
-		ep->udev = usb_get_dev(udev);
+		ep->udev = udev;
 		ep->epnum = epnum;
 		ep->epnum = epnum;
 		ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out);
 		ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out);
 		ep->defctrl = SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENABLE;
 		ep->defctrl = SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENABLE;
@@ -1052,7 +1052,6 @@ sl811h_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
 	if (!list_empty(&hep->urb_list))
 	if (!list_empty(&hep->urb_list))
 		WARN("ep %p not empty?\n", ep);
 		WARN("ep %p not empty?\n", ep);
 
 
-	usb_put_dev(ep->udev);
 	kfree(ep);
 	kfree(ep);
 	hep->hcpriv = NULL;
 	hep->hcpriv = NULL;
 }
 }

+ 123 - 233
drivers/usb/host/uhci-debug.c

@@ -17,10 +17,13 @@
 
 
 #include "uhci-hcd.h"
 #include "uhci-hcd.h"
 
 
-static struct dentry *uhci_debugfs_root = NULL;
+#define uhci_debug_operations (* (struct file_operations *) NULL)
+static struct dentry *uhci_debugfs_root;
+
+#ifdef DEBUG
 
 
 /* Handle REALLY large printks so we don't overflow buffers */
 /* Handle REALLY large printks so we don't overflow buffers */
-static inline void lprintk(char *buf)
+static void lprintk(char *buf)
 {
 {
 	char *p;
 	char *p;
 
 
@@ -90,13 +93,59 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
 	return out - buf;
 	return out - buf;
 }
 }
 
 
-static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
+static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
 {
 {
 	char *out = buf;
 	char *out = buf;
-	struct urb_priv *urbp;
-	struct list_head *head, *tmp;
 	struct uhci_td *td;
 	struct uhci_td *td;
-	int i = 0, checked = 0, prevactive = 0;
+	int i, nactive, ninactive;
+
+	if (len < 200)
+		return 0;
+
+	out += sprintf(out, "urb_priv [%p] ", urbp);
+	out += sprintf(out, "urb [%p] ", urbp->urb);
+	out += sprintf(out, "qh [%p] ", urbp->qh);
+	out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe));
+	out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe),
+			(usb_pipein(urbp->urb->pipe) ? "IN" : "OUT"));
+
+	switch (usb_pipetype(urbp->urb->pipe)) {
+	case PIPE_ISOCHRONOUS: out += sprintf(out, "ISO"); break;
+	case PIPE_INTERRUPT: out += sprintf(out, "INT"); break;
+	case PIPE_BULK: out += sprintf(out, "BLK"); break;
+	case PIPE_CONTROL: out += sprintf(out, "CTL"); break;
+	}
+
+	out += sprintf(out, "%s", (urbp->fsbr ? " FSBR" : ""));
+
+	if (urbp->urb->status != -EINPROGRESS)
+		out += sprintf(out, " Status=%d", urbp->urb->status);
+	out += sprintf(out, "\n");
+
+	i = nactive = ninactive = 0;
+	list_for_each_entry(td, &urbp->td_list, list) {
+		if (++i <= 10 || debug > 2) {
+			out += sprintf(out, "%*s%d: ", space + 2, "", i);
+			out += uhci_show_td(td, out, len - (out - buf), 0);
+		} else {
+			if (td_status(td) & TD_CTRL_ACTIVE)
+				++nactive;
+			else
+				++ninactive;
+		}
+	}
+	if (nactive + ninactive > 0)
+		out += sprintf(out, "%*s[skipped %d inactive and %d active "
+				"TDs]\n",
+				space, "", ninactive, nactive);
+
+	return out - buf;
+}
+
+static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
+{
+	char *out = buf;
+	int i, nurbs;
 	__le32 element = qh_element(qh);
 	__le32 element = qh_element(qh);
 
 
 	/* Try to make sure there's enough memory */
 	/* Try to make sure there's enough memory */
@@ -118,86 +167,40 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
 	if (!(element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH)))
 	if (!(element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH)))
 		out += sprintf(out, "%*s  Element is NULL (bug?)\n", space, "");
 		out += sprintf(out, "%*s  Element is NULL (bug?)\n", space, "");
 
 
-	if (!qh->urbp) {
-		out += sprintf(out, "%*s  urbp == NULL\n", space, "");
-		goto out;
-	}
-
-	urbp = qh->urbp;
-
-	head = &urbp->td_list;
-	tmp = head->next;
-
-	td = list_entry(tmp, struct uhci_td, list);
-
-	if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS))
-		out += sprintf(out, "%*s Element != First TD\n", space, "");
-
-	while (tmp != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		out += sprintf(out, "%*s%d: ", space + 2, "", i++);
-		out += uhci_show_td(td, out, len - (out - buf), 0);
-
-		if (i > 10 && !checked && prevactive && tmp != head &&
-		    debug <= 2) {
-			struct list_head *ntmp = tmp;
-			struct uhci_td *ntd = td;
-			int active = 1, ni = i;
-
-			checked = 1;
-
-			while (ntmp != head && ntmp->next != head && active) {
-				ntd = list_entry(ntmp, struct uhci_td, list);
-
-				ntmp = ntmp->next;
-
-				active = td_status(ntd) & TD_CTRL_ACTIVE;
-
-				ni++;
-			}
-
-			if (active && ni > i) {
-				out += sprintf(out, "%*s[skipped %d active TDs]\n", space, "", ni - i);
-				tmp = ntmp;
-				td = ntd;
-				i = ni;
-			}
+	if (list_empty(&qh->queue)) {
+		out += sprintf(out, "%*s  queue is empty\n", space, "");
+	} else {
+		struct urb_priv *urbp = list_entry(qh->queue.next,
+				struct urb_priv, node);
+		struct uhci_td *td = list_entry(urbp->td_list.next,
+				struct uhci_td, list);
+
+		if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS))
+			out += sprintf(out, "%*s Element != First TD\n",
+					space, "");
+		i = nurbs = 0;
+		list_for_each_entry(urbp, &qh->queue, node) {
+			if (++i <= 10)
+				out += uhci_show_urbp(urbp, out,
+						len - (out - buf), space + 2);
+			else
+				++nurbs;
 		}
 		}
-
-		prevactive = td_status(td) & TD_CTRL_ACTIVE;
+		if (nurbs > 0)
+			out += sprintf(out, "%*s Skipped %d URBs\n",
+					space, "", nurbs);
 	}
 	}
 
 
-	if (list_empty(&urbp->queue_list) || urbp->queued)
-		goto out;
-
-	out += sprintf(out, "%*sQueued QHs:\n", -space, "--");
-
-	head = &urbp->queue_list;
-	tmp = head->next;
-
-	while (tmp != head) {
-		struct urb_priv *nurbp = list_entry(tmp, struct urb_priv,
-						queue_list);
-		tmp = tmp->next;
-
-		out += uhci_show_qh(nurbp->qh, out, len - (out - buf), space);
+	if (qh->udev) {
+		out += sprintf(out, "%*s  Dummy TD\n", space, "");
+		out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0);
 	}
 	}
 
 
-out:
 	return out - buf;
 	return out - buf;
 }
 }
 
 
-#define show_frame_num()	\
-	if (!shown) {		\
-	  shown = 1;		\
-	  out += sprintf(out, "- Frame %d\n", i); \
-	}
-
-#ifdef CONFIG_PROC_FS
 static const char * const qh_names[] = {
 static const char * const qh_names[] = {
+  "skel_unlink_qh", "skel_iso_qh",
   "skel_int128_qh", "skel_int64_qh",
   "skel_int128_qh", "skel_int64_qh",
   "skel_int32_qh", "skel_int16_qh",
   "skel_int32_qh", "skel_int16_qh",
   "skel_int8_qh", "skel_int4_qh",
   "skel_int8_qh", "skel_int4_qh",
@@ -206,12 +209,6 @@ static const char * const qh_names[] = {
   "skel_bulk_qh", "skel_term_qh"
   "skel_bulk_qh", "skel_term_qh"
 };
 };
 
 
-#define show_qh_name()		\
-	if (!shown) {		\
-	  shown = 1;		\
-	  out += sprintf(out, "- %s\n", qh_names[i]); \
-	}
-
 static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
 static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
 {
 {
 	char *out = buf;
 	char *out = buf;
@@ -321,139 +318,29 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
 	return out - buf;
 	return out - buf;
 }
 }
 
 
-static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp, char *buf, int len)
-{
-	struct list_head *tmp;
-	char *out = buf;
-	int count = 0;
-
-	if (len < 200)
-		return 0;
-
-	out += sprintf(out, "urb_priv [%p] ", urbp);
-	out += sprintf(out, "urb [%p] ", urbp->urb);
-	out += sprintf(out, "qh [%p] ", urbp->qh);
-	out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe));
-	out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe), (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT"));
-
-	switch (usb_pipetype(urbp->urb->pipe)) {
-	case PIPE_ISOCHRONOUS: out += sprintf(out, "ISO "); break;
-	case PIPE_INTERRUPT: out += sprintf(out, "INT "); break;
-	case PIPE_BULK: out += sprintf(out, "BLK "); break;
-	case PIPE_CONTROL: out += sprintf(out, "CTL "); break;
-	}
-
-	out += sprintf(out, "%s", (urbp->fsbr ? "FSBR " : ""));
-	out += sprintf(out, "%s", (urbp->fsbr_timeout ? "FSBR_TO " : ""));
-
-	if (urbp->urb->status != -EINPROGRESS)
-		out += sprintf(out, "Status=%d ", urbp->urb->status);
-	//out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime);
-
-	count = 0;
-	list_for_each(tmp, &urbp->td_list)
-		count++;
-	out += sprintf(out, "TDs=%d ",count);
-
-	if (urbp->queued)
-		out += sprintf(out, "queued\n");
-	else {
-		count = 0;
-		list_for_each(tmp, &urbp->queue_list)
-			count++;
-		out += sprintf(out, "queued URBs=%d\n", count);
-	}
-
-	return out - buf;
-}
-
-static int uhci_show_lists(struct uhci_hcd *uhci, char *buf, int len)
-{
-	char *out = buf;
-	struct list_head *head, *tmp;
-	int count;
-
-	out += sprintf(out, "Main list URBs:");
-	if (list_empty(&uhci->urb_list))
-		out += sprintf(out, " Empty\n");
-	else {
-		out += sprintf(out, "\n");
-		count = 0;
-		head = &uhci->urb_list;
-		tmp = head->next;
-		while (tmp != head) {
-			struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
-
-			out += sprintf(out, "  %d: ", ++count);
-			out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
-			tmp = tmp->next;
-		}
-	}
-
-	out += sprintf(out, "Remove list URBs:");
-	if (list_empty(&uhci->urb_remove_list))
-		out += sprintf(out, " Empty\n");
-	else {
-		out += sprintf(out, "\n");
-		count = 0;
-		head = &uhci->urb_remove_list;
-		tmp = head->next;
-		while (tmp != head) {
-			struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
-
-			out += sprintf(out, "  %d: ", ++count);
-			out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
-			tmp = tmp->next;
-		}
-	}
-
-	out += sprintf(out, "Complete list URBs:");
-	if (list_empty(&uhci->complete_list))
-		out += sprintf(out, " Empty\n");
-	else {
-		out += sprintf(out, "\n");
-		count = 0;
-		head = &uhci->complete_list;
-		tmp = head->next;
-		while (tmp != head) {
-			struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list);
-
-			out += sprintf(out, "  %d: ", ++count);
-			out += uhci_show_urbp(uhci, urbp, out, len - (out - buf));
-			tmp = tmp->next;
-		}
-	}
-
-	return out - buf;
-}
-
 static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
 static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
 {
 {
-	unsigned long flags;
 	char *out = buf;
 	char *out = buf;
 	int i, j;
 	int i, j;
 	struct uhci_qh *qh;
 	struct uhci_qh *qh;
 	struct uhci_td *td;
 	struct uhci_td *td;
 	struct list_head *tmp, *head;
 	struct list_head *tmp, *head;
 
 
-	spin_lock_irqsave(&uhci->lock, flags);
-
 	out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
 	out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
 	out += sprintf(out, "HC status\n");
 	out += sprintf(out, "HC status\n");
 	out += uhci_show_status(uhci, out, len - (out - buf));
 	out += uhci_show_status(uhci, out, len - (out - buf));
+	if (debug <= 1)
+		return out - buf;
 
 
 	out += sprintf(out, "Frame List\n");
 	out += sprintf(out, "Frame List\n");
 	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
 	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
-		int shown = 0;
 		td = uhci->frame_cpu[i];
 		td = uhci->frame_cpu[i];
 		if (!td)
 		if (!td)
 			continue;
 			continue;
 
 
-		if (td->dma_handle != (dma_addr_t)uhci->frame[i]) {
-			show_frame_num();
+		out += sprintf(out, "- Frame %d\n", i); \
+		if (td->dma_handle != (dma_addr_t)uhci->frame[i])
 			out += sprintf(out, "    frame list does not match td->dma_handle!\n");
 			out += sprintf(out, "    frame list does not match td->dma_handle!\n");
-		}
-		show_frame_num();
 
 
 		head = &td->fl_list;
 		head = &td->fl_list;
 		tmp = head;
 		tmp = head;
@@ -467,14 +354,11 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
 	out += sprintf(out, "Skeleton QHs\n");
 	out += sprintf(out, "Skeleton QHs\n");
 
 
 	for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
 	for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
-		int shown = 0;
+		int cnt = 0;
 
 
 		qh = uhci->skelqh[i];
 		qh = uhci->skelqh[i];
-
-		if (debug > 1) {
-			show_qh_name();
-			out += uhci_show_qh(qh, out, len - (out - buf), 4);
-		}
+		out += sprintf(out, "- %s\n", qh_names[i]); \
+		out += uhci_show_qh(qh, out, len - (out - buf), 4);
 
 
 		/* Last QH is the Terminating QH, it's different */
 		/* Last QH is the Terminating QH, it's different */
 		if (i == UHCI_NUM_SKELQH - 1) {
 		if (i == UHCI_NUM_SKELQH - 1) {
@@ -487,53 +371,37 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
 			continue;
 			continue;
 		}
 		}
 
 
-		j = (i < 7) ? 7 : i+1;		/* Next skeleton */
-		if (list_empty(&qh->list)) {
-			if (i < UHCI_NUM_SKELQH - 1) {
-				if (qh->link !=
-				    (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH)) {
-					show_qh_name();
-					out += sprintf(out, "    skeleton QH not linked to next skeleton QH!\n");
-				}
-			}
-
-			continue;
-		}
-
-		show_qh_name();
-
-		head = &qh->list;
+		j = (i < 9) ? 9 : i+1;		/* Next skeleton */
+		head = &qh->node;
 		tmp = head->next;
 		tmp = head->next;
 
 
 		while (tmp != head) {
 		while (tmp != head) {
-			qh = list_entry(tmp, struct uhci_qh, list);
-
+			qh = list_entry(tmp, struct uhci_qh, node);
 			tmp = tmp->next;
 			tmp = tmp->next;
-
-			out += uhci_show_qh(qh, out, len - (out - buf), 4);
+			if (++cnt <= 10)
+				out += uhci_show_qh(qh, out,
+						len - (out - buf), 4);
 		}
 		}
+		if ((cnt -= 10) > 0)
+			out += sprintf(out, "    Skipped %d QHs\n", cnt);
 
 
-		if (i < UHCI_NUM_SKELQH - 1) {
+		if (i > 1 && i < UHCI_NUM_SKELQH - 1) {
 			if (qh->link !=
 			if (qh->link !=
 			    (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH))
 			    (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH))
 				out += sprintf(out, "    last QH not linked to next skeleton!\n");
 				out += sprintf(out, "    last QH not linked to next skeleton!\n");
 		}
 		}
 	}
 	}
 
 
-	if (debug > 2)
-		out += uhci_show_lists(uhci, out, len - (out - buf));
-
-	spin_unlock_irqrestore(&uhci->lock, flags);
-
 	return out - buf;
 	return out - buf;
 }
 }
 
 
+#ifdef CONFIG_DEBUG_FS
+
 #define MAX_OUTPUT	(64 * 1024)
 #define MAX_OUTPUT	(64 * 1024)
 
 
 struct uhci_debug {
 struct uhci_debug {
 	int size;
 	int size;
 	char *data;
 	char *data;
-	struct uhci_hcd *uhci;
 };
 };
 
 
 static int uhci_debug_open(struct inode *inode, struct file *file)
 static int uhci_debug_open(struct inode *inode, struct file *file)
@@ -541,6 +409,7 @@ static int uhci_debug_open(struct inode *inode, struct file *file)
 	struct uhci_hcd *uhci = inode->u.generic_ip;
 	struct uhci_hcd *uhci = inode->u.generic_ip;
 	struct uhci_debug *up;
 	struct uhci_debug *up;
 	int ret = -ENOMEM;
 	int ret = -ENOMEM;
+	unsigned long flags;
 
 
 	lock_kernel();
 	lock_kernel();
 	up = kmalloc(sizeof(*up), GFP_KERNEL);
 	up = kmalloc(sizeof(*up), GFP_KERNEL);
@@ -553,7 +422,11 @@ static int uhci_debug_open(struct inode *inode, struct file *file)
 		goto out;
 		goto out;
 	}
 	}
 
 
-	up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
+	up->size = 0;
+	spin_lock_irqsave(&uhci->lock, flags);
+	if (uhci->is_initialized)
+		up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
+	spin_unlock_irqrestore(&uhci->lock, flags);
 
 
 	file->private_data = up;
 	file->private_data = up;
 
 
@@ -604,15 +477,32 @@ static int uhci_debug_release(struct inode *inode, struct file *file)
 	return 0;
 	return 0;
 }
 }
 
 
+#undef uhci_debug_operations
 static struct file_operations uhci_debug_operations = {
 static struct file_operations uhci_debug_operations = {
+	.owner =	THIS_MODULE,
 	.open =		uhci_debug_open,
 	.open =		uhci_debug_open,
 	.llseek =	uhci_debug_lseek,
 	.llseek =	uhci_debug_lseek,
 	.read =		uhci_debug_read,
 	.read =		uhci_debug_read,
 	.release =	uhci_debug_release,
 	.release =	uhci_debug_release,
 };
 };
 
 
-#else	/* CONFIG_DEBUG_FS */
+#endif	/* CONFIG_DEBUG_FS */
 
 
-#define uhci_debug_operations (* (struct file_operations *) NULL)
+#else	/* DEBUG */
+
+static inline void lprintk(char *buf)
+{}
+
+static inline int uhci_show_qh(struct uhci_qh *qh, char *buf,
+		int len, int space)
+{
+	return 0;
+}
+
+static inline int uhci_sprint_schedule(struct uhci_hcd *uhci,
+		char *buf, int len)
+{
+	return 0;
+}
 
 
 #endif
 #endif

+ 80 - 47
drivers/usb/host/uhci-hcd.c

@@ -54,7 +54,7 @@
 /*
 /*
  * Version Information
  * Version Information
  */
  */
-#define DRIVER_VERSION "v2.3"
+#define DRIVER_VERSION "v3.0"
 #define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \
 #define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \
 Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \
 Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \
 Alan Stern"
 Alan Stern"
@@ -68,12 +68,16 @@ Alan Stern"
  * debug = 3, show all TDs in URBs when dumping
  * debug = 3, show all TDs in URBs when dumping
  */
  */
 #ifdef DEBUG
 #ifdef DEBUG
+#define DEBUG_CONFIGURED	1
 static int debug = 1;
 static int debug = 1;
-#else
-static int debug = 0;
-#endif
 module_param(debug, int, S_IRUGO | S_IWUSR);
 module_param(debug, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug level");
 MODULE_PARM_DESC(debug, "Debug level");
+
+#else
+#define DEBUG_CONFIGURED	0
+#define debug			0
+#endif
+
 static char *errbuf;
 static char *errbuf;
 #define ERRBUF_LEN    (32 * 1024)
 #define ERRBUF_LEN    (32 * 1024)
 
 
@@ -338,6 +342,12 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
 				dev_err(uhci_dev(uhci),
 				dev_err(uhci_dev(uhci),
 					"host controller halted, "
 					"host controller halted, "
 					"very bad!\n");
 					"very bad!\n");
+				if (debug > 1 && errbuf) {
+					/* Print the schedule for debugging */
+					uhci_sprint_schedule(uhci,
+							errbuf, ERRBUF_LEN);
+					lprintk(errbuf);
+				}
 				hc_died(uhci);
 				hc_died(uhci);
 
 
 				/* Force a callback in case there are
 				/* Force a callback in case there are
@@ -376,6 +386,14 @@ static void release_uhci(struct uhci_hcd *uhci)
 {
 {
 	int i;
 	int i;
 
 
+	if (DEBUG_CONFIGURED) {
+		spin_lock_irq(&uhci->lock);
+		uhci->is_initialized = 0;
+		spin_unlock_irq(&uhci->lock);
+
+		debugfs_remove(uhci->dentry);
+	}
+
 	for (i = 0; i < UHCI_NUM_SKELQH; i++)
 	for (i = 0; i < UHCI_NUM_SKELQH; i++)
 		uhci_free_qh(uhci, uhci->skelqh[i]);
 		uhci_free_qh(uhci, uhci->skelqh[i]);
 
 
@@ -390,8 +408,6 @@ static void release_uhci(struct uhci_hcd *uhci)
 	dma_free_coherent(uhci_dev(uhci),
 	dma_free_coherent(uhci_dev(uhci),
 			UHCI_NUMFRAMES * sizeof(*uhci->frame),
 			UHCI_NUMFRAMES * sizeof(*uhci->frame),
 			uhci->frame, uhci->frame_dma_handle);
 			uhci->frame, uhci->frame_dma_handle);
-
-	debugfs_remove(uhci->dentry);
 }
 }
 
 
 static int uhci_reset(struct usb_hcd *hcd)
 static int uhci_reset(struct usb_hcd *hcd)
@@ -474,33 +490,29 @@ static int uhci_start(struct usb_hcd *hcd)
 
 
 	hcd->uses_new_polling = 1;
 	hcd->uses_new_polling = 1;
 
 
-	dentry = debugfs_create_file(hcd->self.bus_name,
-			S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci,
-			&uhci_debug_operations);
-	if (!dentry) {
-		dev_err(uhci_dev(uhci),
-				"couldn't create uhci debugfs entry\n");
-		retval = -ENOMEM;
-		goto err_create_debug_entry;
-	}
-	uhci->dentry = dentry;
-
 	uhci->fsbr = 0;
 	uhci->fsbr = 0;
 	uhci->fsbrtimeout = 0;
 	uhci->fsbrtimeout = 0;
 
 
 	spin_lock_init(&uhci->lock);
 	spin_lock_init(&uhci->lock);
-	INIT_LIST_HEAD(&uhci->qh_remove_list);
 
 
 	INIT_LIST_HEAD(&uhci->td_remove_list);
 	INIT_LIST_HEAD(&uhci->td_remove_list);
-
-	INIT_LIST_HEAD(&uhci->urb_remove_list);
-
-	INIT_LIST_HEAD(&uhci->urb_list);
-
-	INIT_LIST_HEAD(&uhci->complete_list);
+	INIT_LIST_HEAD(&uhci->idle_qh_list);
 
 
 	init_waitqueue_head(&uhci->waitqh);
 	init_waitqueue_head(&uhci->waitqh);
 
 
+	if (DEBUG_CONFIGURED) {
+		dentry = debugfs_create_file(hcd->self.bus_name,
+				S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root,
+				uhci, &uhci_debug_operations);
+		if (!dentry) {
+			dev_err(uhci_dev(uhci), "couldn't create uhci "
+					"debugfs entry\n");
+			retval = -ENOMEM;
+			goto err_create_debug_entry;
+		}
+		uhci->dentry = dentry;
+	}
+
 	uhci->frame = dma_alloc_coherent(uhci_dev(uhci),
 	uhci->frame = dma_alloc_coherent(uhci_dev(uhci),
 			UHCI_NUMFRAMES * sizeof(*uhci->frame),
 			UHCI_NUMFRAMES * sizeof(*uhci->frame),
 			&uhci->frame_dma_handle, 0);
 			&uhci->frame_dma_handle, 0);
@@ -540,7 +552,7 @@ static int uhci_start(struct usb_hcd *hcd)
 	}
 	}
 
 
 	for (i = 0; i < UHCI_NUM_SKELQH; i++) {
 	for (i = 0; i < UHCI_NUM_SKELQH; i++) {
-		uhci->skelqh[i] = uhci_alloc_qh(uhci);
+		uhci->skelqh[i] = uhci_alloc_qh(uhci, NULL, NULL);
 		if (!uhci->skelqh[i]) {
 		if (!uhci->skelqh[i]) {
 			dev_err(uhci_dev(uhci), "unable to allocate QH\n");
 			dev_err(uhci_dev(uhci), "unable to allocate QH\n");
 			goto err_alloc_skelqh;
 			goto err_alloc_skelqh;
@@ -557,13 +569,17 @@ static int uhci_start(struct usb_hcd *hcd)
 			uhci->skel_int16_qh->link =
 			uhci->skel_int16_qh->link =
 			uhci->skel_int8_qh->link =
 			uhci->skel_int8_qh->link =
 			uhci->skel_int4_qh->link =
 			uhci->skel_int4_qh->link =
-			uhci->skel_int2_qh->link =
-			cpu_to_le32(uhci->skel_int1_qh->dma_handle) | UHCI_PTR_QH;
-	uhci->skel_int1_qh->link = cpu_to_le32(uhci->skel_ls_control_qh->dma_handle) | UHCI_PTR_QH;
-
-	uhci->skel_ls_control_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;
-	uhci->skel_fs_control_qh->link = cpu_to_le32(uhci->skel_bulk_qh->dma_handle) | UHCI_PTR_QH;
-	uhci->skel_bulk_qh->link = cpu_to_le32(uhci->skel_term_qh->dma_handle) | UHCI_PTR_QH;
+			uhci->skel_int2_qh->link = UHCI_PTR_QH |
+			cpu_to_le32(uhci->skel_int1_qh->dma_handle);
+
+	uhci->skel_int1_qh->link = UHCI_PTR_QH |
+			cpu_to_le32(uhci->skel_ls_control_qh->dma_handle);
+	uhci->skel_ls_control_qh->link = UHCI_PTR_QH |
+			cpu_to_le32(uhci->skel_fs_control_qh->dma_handle);
+	uhci->skel_fs_control_qh->link = UHCI_PTR_QH |
+			cpu_to_le32(uhci->skel_bulk_qh->dma_handle);
+	uhci->skel_bulk_qh->link = UHCI_PTR_QH |
+			cpu_to_le32(uhci->skel_term_qh->dma_handle);
 
 
 	/* This dummy TD is to work around a bug in Intel PIIX controllers */
 	/* This dummy TD is to work around a bug in Intel PIIX controllers */
 	uhci_fill_td(uhci->term_td, 0, uhci_explen(0) |
 	uhci_fill_td(uhci->term_td, 0, uhci_explen(0) |
@@ -589,15 +605,15 @@ static int uhci_start(struct usb_hcd *hcd)
 
 
 		/*
 		/*
 		 * ffs (Find First bit Set) does exactly what we need:
 		 * ffs (Find First bit Set) does exactly what we need:
-		 * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[6],
-		 * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[5], etc.
-		 * ffs > 6 => not on any high-period queue, so use
-		 *	skel_int1_qh = skelqh[7].
+		 * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[8],
+		 * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
+		 * ffs >= 7 => not on any high-period queue, so use
+		 *	skel_int1_qh = skelqh[9].
 		 * Add UHCI_NUMFRAMES to insure at least one bit is set.
 		 * Add UHCI_NUMFRAMES to insure at least one bit is set.
 		 */
 		 */
-		irq = 6 - (int) __ffs(i + UHCI_NUMFRAMES);
-		if (irq < 0)
-			irq = 7;
+		irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES);
+		if (irq <= 1)
+			irq = 9;
 
 
 		/* Only place we don't use the frame list routines */
 		/* Only place we don't use the frame list routines */
 		uhci->frame[i] = UHCI_PTR_QH |
 		uhci->frame[i] = UHCI_PTR_QH |
@@ -611,6 +627,7 @@ static int uhci_start(struct usb_hcd *hcd)
 	mb();
 	mb();
 
 
 	configure_hc(uhci);
 	configure_hc(uhci);
+	uhci->is_initialized = 1;
 	start_rh(uhci);
 	start_rh(uhci);
 	return 0;
 	return 0;
 
 
@@ -767,13 +784,30 @@ static int uhci_resume(struct usb_hcd *hcd)
 }
 }
 #endif
 #endif
 
 
-/* Wait until all the URBs for a particular device/endpoint are gone */
+/* Wait until a particular device/endpoint's QH is idle, and free it */
 static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd,
 static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd,
-		struct usb_host_endpoint *ep)
+		struct usb_host_endpoint *hep)
 {
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+	struct uhci_qh *qh;
+
+	spin_lock_irq(&uhci->lock);
+	qh = (struct uhci_qh *) hep->hcpriv;
+	if (qh == NULL)
+		goto done;
+
+	while (qh->state != QH_STATE_IDLE) {
+		++uhci->num_waiting;
+		spin_unlock_irq(&uhci->lock);
+		wait_event_interruptible(uhci->waitqh,
+				qh->state == QH_STATE_IDLE);
+		spin_lock_irq(&uhci->lock);
+		--uhci->num_waiting;
+	}
 
 
-	wait_event_interruptible(uhci->waitqh, list_empty(&ep->urb_list));
+	uhci_free_qh(uhci, qh);
+done:
+	spin_unlock_irq(&uhci->lock);
 }
 }
 
 
 static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
 static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
@@ -857,16 +891,15 @@ static int __init uhci_hcd_init(void)
 	if (usb_disabled())
 	if (usb_disabled())
 		return -ENODEV;
 		return -ENODEV;
 
 
-	if (debug) {
+	if (DEBUG_CONFIGURED) {
 		errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
 		errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
 		if (!errbuf)
 		if (!errbuf)
 			goto errbuf_failed;
 			goto errbuf_failed;
+		uhci_debugfs_root = debugfs_create_dir("uhci", NULL);
+		if (!uhci_debugfs_root)
+			goto debug_failed;
 	}
 	}
 
 
-	uhci_debugfs_root = debugfs_create_dir("uhci", NULL);
-	if (!uhci_debugfs_root)
-		goto debug_failed;
-
 	uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
 	uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
 		sizeof(struct urb_priv), 0, 0, NULL, NULL);
 		sizeof(struct urb_priv), 0, 0, NULL, NULL);
 	if (!uhci_up_cachep)
 	if (!uhci_up_cachep)

+ 100 - 88
drivers/usb/host/uhci-hcd.h

@@ -28,8 +28,9 @@
 #define   USBSTS_USBINT		0x0001	/* Interrupt due to IOC */
 #define   USBSTS_USBINT		0x0001	/* Interrupt due to IOC */
 #define   USBSTS_ERROR		0x0002	/* Interrupt due to error */
 #define   USBSTS_ERROR		0x0002	/* Interrupt due to error */
 #define   USBSTS_RD		0x0004	/* Resume Detect */
 #define   USBSTS_RD		0x0004	/* Resume Detect */
-#define   USBSTS_HSE		0x0008	/* Host System Error - basically PCI problems */
-#define   USBSTS_HCPE		0x0010	/* Host Controller Process Error - the scripts were buggy */
+#define   USBSTS_HSE		0x0008	/* Host System Error: PCI problems */
+#define   USBSTS_HCPE		0x0010	/* Host Controller Process Error:
+					 * the schedule is buggy */
 #define   USBSTS_HCH		0x0020	/* HC Halted */
 #define   USBSTS_HCH		0x0020	/* HC Halted */
 
 
 /* Interrupt enable register */
 /* Interrupt enable register */
@@ -47,7 +48,8 @@
 /* USB port status and control registers */
 /* USB port status and control registers */
 #define USBPORTSC1	16
 #define USBPORTSC1	16
 #define USBPORTSC2	18
 #define USBPORTSC2	18
-#define   USBPORTSC_CCS		0x0001	/* Current Connect Status ("device present") */
+#define   USBPORTSC_CCS		0x0001	/* Current Connect Status
+					 * ("device present") */
 #define   USBPORTSC_CSC		0x0002	/* Connect Status Change */
 #define   USBPORTSC_CSC		0x0002	/* Connect Status Change */
 #define   USBPORTSC_PE		0x0004	/* Port Enable */
 #define   USBPORTSC_PE		0x0004	/* Port Enable */
 #define   USBPORTSC_PEC		0x0008	/* Port Enable Change */
 #define   USBPORTSC_PEC		0x0008	/* Port Enable Change */
@@ -71,15 +73,16 @@
 #define   USBLEGSUP_RWC		0x8f00	/* the R/WC bits */
 #define   USBLEGSUP_RWC		0x8f00	/* the R/WC bits */
 #define   USBLEGSUP_RO		0x5040	/* R/O and reserved bits */
 #define   USBLEGSUP_RO		0x5040	/* R/O and reserved bits */
 
 
-#define UHCI_PTR_BITS		cpu_to_le32(0x000F)
-#define UHCI_PTR_TERM		cpu_to_le32(0x0001)
-#define UHCI_PTR_QH		cpu_to_le32(0x0002)
-#define UHCI_PTR_DEPTH		cpu_to_le32(0x0004)
-#define UHCI_PTR_BREADTH	cpu_to_le32(0x0000)
+#define UHCI_PTR_BITS		__constant_cpu_to_le32(0x000F)
+#define UHCI_PTR_TERM		__constant_cpu_to_le32(0x0001)
+#define UHCI_PTR_QH		__constant_cpu_to_le32(0x0002)
+#define UHCI_PTR_DEPTH		__constant_cpu_to_le32(0x0004)
+#define UHCI_PTR_BREADTH	__constant_cpu_to_le32(0x0000)
 
 
 #define UHCI_NUMFRAMES		1024	/* in the frame list [array] */
 #define UHCI_NUMFRAMES		1024	/* in the frame list [array] */
 #define UHCI_MAX_SOF_NUMBER	2047	/* in an SOF packet */
 #define UHCI_MAX_SOF_NUMBER	2047	/* in an SOF packet */
-#define CAN_SCHEDULE_FRAMES	1000	/* how far future frames can be scheduled */
+#define CAN_SCHEDULE_FRAMES	1000	/* how far in the future frames
+					 * can be scheduled */
 
 
 
 
 /*
 /*
@@ -87,38 +90,59 @@
  */
  */
 
 
 /*
 /*
- * One role of a QH is to hold a queue of TDs for some endpoint.  Each QH is
- * used with one URB, and qh->element (updated by the HC) is either:
- *   - the next unprocessed TD for the URB, or
- *   - UHCI_PTR_TERM (when there's no more traffic for this endpoint), or
- *   - the QH for the next URB queued to the same endpoint.
+ * One role of a QH is to hold a queue of TDs for some endpoint.  One QH goes
+ * with each endpoint, and qh->element (updated by the HC) is either:
+ *   - the next unprocessed TD in the endpoint's queue, or
+ *   - UHCI_PTR_TERM (when there's no more traffic for this endpoint).
  *
  *
  * The other role of a QH is to serve as a "skeleton" framelist entry, so we
  * The other role of a QH is to serve as a "skeleton" framelist entry, so we
  * can easily splice a QH for some endpoint into the schedule at the right
  * can easily splice a QH for some endpoint into the schedule at the right
  * place.  Then qh->element is UHCI_PTR_TERM.
  * place.  Then qh->element is UHCI_PTR_TERM.
  *
  *
- * In the frame list, qh->link maintains a list of QHs seen by the HC:
+ * In the schedule, qh->link maintains a list of QHs seen by the HC:
  *     skel1 --> ep1-qh --> ep2-qh --> ... --> skel2 --> ...
  *     skel1 --> ep1-qh --> ep2-qh --> ... --> skel2 --> ...
+ *
+ * qh->node is the software equivalent of qh->link.  The differences
+ * are that the software list is doubly-linked and QHs in the UNLINKING
+ * state are on the software list but not the hardware schedule.
+ *
+ * For bookkeeping purposes we maintain QHs even for Isochronous endpoints,
+ * but they never get added to the hardware schedule.
  */
  */
+#define QH_STATE_IDLE		1	/* QH is not being used */
+#define QH_STATE_UNLINKING	2	/* QH has been removed from the
+					 * schedule but the hardware may
+					 * still be using it */
+#define QH_STATE_ACTIVE		3	/* QH is on the schedule */
+
 struct uhci_qh {
 struct uhci_qh {
 	/* Hardware fields */
 	/* Hardware fields */
-	__le32 link;			/* Next queue */
-	__le32 element;			/* Queue element pointer */
+	__le32 link;			/* Next QH in the schedule */
+	__le32 element;			/* Queue element (TD) pointer */
 
 
 	/* Software fields */
 	/* Software fields */
 	dma_addr_t dma_handle;
 	dma_addr_t dma_handle;
 
 
-	struct urb_priv *urbp;
+	struct list_head node;		/* Node in the list of QHs */
+	struct usb_host_endpoint *hep;	/* Endpoint information */
+	struct usb_device *udev;
+	struct list_head queue;		/* Queue of urbps for this QH */
+	struct uhci_qh *skel;		/* Skeleton for this QH */
+	struct uhci_td *dummy_td;	/* Dummy TD to end the queue */
 
 
-	struct list_head list;
-	struct list_head remove_list;
+	unsigned int unlink_frame;	/* When the QH was unlinked */
+	int state;			/* QH_STATE_xxx; see above */
+
+	unsigned int initial_toggle:1;	/* Endpoint's current toggle value */
+	unsigned int needs_fixup:1;	/* Must fix the TD toggle values */
+	unsigned int is_stopped:1;	/* Queue was stopped by an error */
 } __attribute__((aligned(16)));
 } __attribute__((aligned(16)));
 
 
 /*
 /*
  * We need a special accessor for the element pointer because it is
  * We need a special accessor for the element pointer because it is
  * subject to asynchronous updates by the controller.
  * subject to asynchronous updates by the controller.
  */
  */
-static __le32 inline qh_element(struct uhci_qh *qh) {
+static inline __le32 qh_element(struct uhci_qh *qh) {
 	__le32 element = qh->element;
 	__le32 element = qh->element;
 
 
 	barrier();
 	barrier();
@@ -149,11 +173,13 @@ static __le32 inline qh_element(struct uhci_qh *qh) {
 #define TD_CTRL_ACTLEN_MASK	0x7FF	/* actual length, encoded as n - 1 */
 #define TD_CTRL_ACTLEN_MASK	0x7FF	/* actual length, encoded as n - 1 */
 
 
 #define TD_CTRL_ANY_ERROR	(TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
 #define TD_CTRL_ANY_ERROR	(TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
-				 TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
+				 TD_CTRL_BABBLE | TD_CTRL_CRCTIME | \
+				 TD_CTRL_BITSTUFF)
 
 
 #define uhci_maxerr(err)		((err) << TD_CTRL_C_ERR_SHIFT)
 #define uhci_maxerr(err)		((err) << TD_CTRL_C_ERR_SHIFT)
 #define uhci_status_bits(ctrl_sts)	((ctrl_sts) & 0xF60000)
 #define uhci_status_bits(ctrl_sts)	((ctrl_sts) & 0xF60000)
-#define uhci_actual_length(ctrl_sts)	(((ctrl_sts) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
+#define uhci_actual_length(ctrl_sts)	(((ctrl_sts) + 1) & \
+			TD_CTRL_ACTLEN_MASK)	/* 1-based */
 
 
 /*
 /*
  * for TD <info>: (a.k.a. Token)
  * for TD <info>: (a.k.a. Token)
@@ -163,7 +189,7 @@ static __le32 inline qh_element(struct uhci_qh *qh) {
 #define TD_TOKEN_TOGGLE_SHIFT	19
 #define TD_TOKEN_TOGGLE_SHIFT	19
 #define TD_TOKEN_TOGGLE		(1 << 19)
 #define TD_TOKEN_TOGGLE		(1 << 19)
 #define TD_TOKEN_EXPLEN_SHIFT	21
 #define TD_TOKEN_EXPLEN_SHIFT	21
-#define TD_TOKEN_EXPLEN_MASK	0x7FF		/* expected length, encoded as n - 1 */
+#define TD_TOKEN_EXPLEN_MASK	0x7FF	/* expected length, encoded as n-1 */
 #define TD_TOKEN_PID_MASK	0xFF
 #define TD_TOKEN_PID_MASK	0xFF
 
 
 #define uhci_explen(len)	((((len) - 1) & TD_TOKEN_EXPLEN_MASK) << \
 #define uhci_explen(len)	((((len) - 1) & TD_TOKEN_EXPLEN_MASK) << \
@@ -187,7 +213,7 @@ static __le32 inline qh_element(struct uhci_qh *qh) {
  * sw space after the TD entry.
  * sw space after the TD entry.
  *
  *
  * td->link points to either another TD (not necessarily for the same urb or
  * td->link points to either another TD (not necessarily for the same urb or
- * even the same endpoint), or nothing (PTR_TERM), or a QH (for queued urbs).
+ * even the same endpoint), or nothing (PTR_TERM), or a QH.
  */
  */
 struct uhci_td {
 struct uhci_td {
 	/* Hardware fields */
 	/* Hardware fields */
@@ -210,7 +236,7 @@ struct uhci_td {
  * We need a special accessor for the control/status word because it is
  * We need a special accessor for the control/status word because it is
  * subject to asynchronous updates by the controller.
  * subject to asynchronous updates by the controller.
  */
  */
-static u32 inline td_status(struct uhci_td *td) {
+static inline u32 td_status(struct uhci_td *td) {
 	__le32 status = td->status;
 	__le32 status = td->status;
 
 
 	barrier();
 	barrier();
@@ -223,17 +249,14 @@ static u32 inline td_status(struct uhci_td *td) {
  */
  */
 
 
 /*
 /*
- * The UHCI driver places Interrupt, Control and Bulk into QHs both
- * to group together TDs for one transfer, and also to facilitate queuing
- * of URBs. To make it easy to insert entries into the schedule, we have
- * a skeleton of QHs for each predefined Interrupt latency, low-speed
- * control, full-speed control and terminating QH (see explanation for
- * the terminating QH below).
+ * The UHCI driver uses QHs with Interrupt, Control and Bulk URBs for
+ * automatic queuing. To make it easy to insert entries into the schedule,
+ * we have a skeleton of QHs for each predefined Interrupt latency,
+ * low-speed control, full-speed control, bulk, and terminating QH
+ * (see explanation for the terminating QH below).
  *
  *
  * When we want to add a new QH, we add it to the end of the list for the
  * When we want to add a new QH, we add it to the end of the list for the
- * skeleton QH.
- *
- * For instance, the queue can look like this:
+ * skeleton QH.  For instance, the schedule list can look like this:
  *
  *
  * skel int128 QH
  * skel int128 QH
  * dev 1 interrupt QH
  * dev 1 interrupt QH
@@ -256,26 +279,31 @@ static u32 inline td_status(struct uhci_td *td) {
  * - To loop back to the full-speed control queue for full-speed bandwidth
  * - To loop back to the full-speed control queue for full-speed bandwidth
  *   reclamation.
  *   reclamation.
  *
  *
- * Isochronous transfers are stored before the start of the skeleton
- * schedule and don't use QHs. While the UHCI spec doesn't forbid the
- * use of QHs for Isochronous, it doesn't use them either. And the spec
- * says that queues never advance on an error completion status, which
- * makes them totally unsuitable for Isochronous transfers.
+ * There's a special skeleton QH for Isochronous QHs.  It never appears
+ * on the schedule, and Isochronous TDs go on the schedule before the
+ * the skeleton QHs.  The hardware accesses them directly rather than
+ * through their QH, which is used only for bookkeeping purposes.
+ * While the UHCI spec doesn't forbid the use of QHs for Isochronous,
+ * it doesn't use them either.  And the spec says that queues never
+ * advance on an error completion status, which makes them totally
+ * unsuitable for Isochronous transfers.
  */
  */
 
 
-#define UHCI_NUM_SKELQH		12
-#define skel_int128_qh		skelqh[0]
-#define skel_int64_qh		skelqh[1]
-#define skel_int32_qh		skelqh[2]
-#define skel_int16_qh		skelqh[3]
-#define skel_int8_qh		skelqh[4]
-#define skel_int4_qh		skelqh[5]
-#define skel_int2_qh		skelqh[6]
-#define skel_int1_qh		skelqh[7]
-#define skel_ls_control_qh	skelqh[8]
-#define skel_fs_control_qh	skelqh[9]
-#define skel_bulk_qh		skelqh[10]
-#define skel_term_qh		skelqh[11]
+#define UHCI_NUM_SKELQH		14
+#define skel_unlink_qh		skelqh[0]
+#define skel_iso_qh		skelqh[1]
+#define skel_int128_qh		skelqh[2]
+#define skel_int64_qh		skelqh[3]
+#define skel_int32_qh		skelqh[4]
+#define skel_int16_qh		skelqh[5]
+#define skel_int8_qh		skelqh[6]
+#define skel_int4_qh		skelqh[7]
+#define skel_int2_qh		skelqh[8]
+#define skel_int1_qh		skelqh[9]
+#define skel_ls_control_qh	skelqh[10]
+#define skel_fs_control_qh	skelqh[11]
+#define skel_bulk_qh		skelqh[12]
+#define skel_term_qh		skelqh[13]
 
 
 /*
 /*
  * Search tree for determining where <interval> fits in the skelqh[]
  * Search tree for determining where <interval> fits in the skelqh[]
@@ -293,21 +321,21 @@ static inline int __interval_to_skel(int interval)
 	if (interval < 16) {
 	if (interval < 16) {
 		if (interval < 4) {
 		if (interval < 4) {
 			if (interval < 2)
 			if (interval < 2)
-				return 7;	/* int1 for 0-1 ms */
-			return 6;		/* int2 for 2-3 ms */
+				return 9;	/* int1 for 0-1 ms */
+			return 8;		/* int2 for 2-3 ms */
 		}
 		}
 		if (interval < 8)
 		if (interval < 8)
-			return 5;		/* int4 for 4-7 ms */
-		return 4;			/* int8 for 8-15 ms */
+			return 7;		/* int4 for 4-7 ms */
+		return 6;			/* int8 for 8-15 ms */
 	}
 	}
 	if (interval < 64) {
 	if (interval < 64) {
 		if (interval < 32)
 		if (interval < 32)
-			return 3;		/* int16 for 16-31 ms */
-		return 2;			/* int32 for 32-63 ms */
+			return 5;		/* int16 for 16-31 ms */
+		return 4;			/* int32 for 32-63 ms */
 	}
 	}
 	if (interval < 128)
 	if (interval < 128)
-		return 1;			/* int64 for 64-127 ms */
-	return 0;				/* int128 for 128-255 ms (Max.) */
+		return 3;			/* int64 for 64-127 ms */
+	return 2;				/* int128 for 128-255 ms (Max.) */
 }
 }
 
 
 
 
@@ -360,15 +388,16 @@ struct uhci_hcd {
 
 
 	struct uhci_td *term_td;	/* Terminating TD, see UHCI bug */
 	struct uhci_td *term_td;	/* Terminating TD, see UHCI bug */
 	struct uhci_qh *skelqh[UHCI_NUM_SKELQH];	/* Skeleton QHs */
 	struct uhci_qh *skelqh[UHCI_NUM_SKELQH];	/* Skeleton QHs */
+	struct uhci_qh *next_qh;	/* Next QH to scan */
 
 
 	spinlock_t lock;
 	spinlock_t lock;
 
 
-	dma_addr_t frame_dma_handle;		/* Hardware frame list */
+	dma_addr_t frame_dma_handle;	/* Hardware frame list */
 	__le32 *frame;
 	__le32 *frame;
-	void **frame_cpu;			/* CPU's frame list */
+	void **frame_cpu;		/* CPU's frame list */
 
 
-	int fsbr;				/* Full-speed bandwidth reclamation */
-	unsigned long fsbrtimeout;		/* FSBR delay */
+	int fsbr;			/* Full-speed bandwidth reclamation */
+	unsigned long fsbrtimeout;	/* FSBR delay */
 
 
 	enum uhci_rh_state rh_state;
 	enum uhci_rh_state rh_state;
 	unsigned long auto_stop_time;		/* When to AUTO_STOP */
 	unsigned long auto_stop_time;		/* When to AUTO_STOP */
@@ -382,6 +411,7 @@ struct uhci_hcd {
 	unsigned int hc_inaccessible:1;		/* HC is suspended or dead */
 	unsigned int hc_inaccessible:1;		/* HC is suspended or dead */
 	unsigned int working_RD:1;		/* Suspended root hub doesn't
 	unsigned int working_RD:1;		/* Suspended root hub doesn't
 						   need to be polled */
 						   need to be polled */
+	unsigned int is_initialized:1;		/* Data structure is usable */
 
 
 	/* Support for port suspend/resume/reset */
 	/* Support for port suspend/resume/reset */
 	unsigned long port_c_suspend;		/* Bit-arrays of ports */
 	unsigned long port_c_suspend;		/* Bit-arrays of ports */
@@ -389,27 +419,16 @@ struct uhci_hcd {
 	unsigned long resuming_ports;
 	unsigned long resuming_ports;
 	unsigned long ports_timeout;		/* Time to stop signalling */
 	unsigned long ports_timeout;		/* Time to stop signalling */
 
 
-	/* Main list of URBs currently controlled by this HC */
-	struct list_head urb_list;
-
-	/* List of QHs that are done, but waiting to be unlinked (race) */
-	struct list_head qh_remove_list;
-	unsigned int qh_remove_age;		/* Age in frames */
-
 	/* List of TDs that are done, but waiting to be freed (race) */
 	/* List of TDs that are done, but waiting to be freed (race) */
 	struct list_head td_remove_list;
 	struct list_head td_remove_list;
 	unsigned int td_remove_age;		/* Age in frames */
 	unsigned int td_remove_age;		/* Age in frames */
 
 
-	/* List of asynchronously unlinked URBs */
-	struct list_head urb_remove_list;
-	unsigned int urb_remove_age;		/* Age in frames */
-
-	/* List of URBs awaiting completion callback */
-	struct list_head complete_list;
+	struct list_head idle_qh_list;		/* Where the idle QHs live */
 
 
 	int rh_numports;			/* Number of root-hub ports */
 	int rh_numports;			/* Number of root-hub ports */
 
 
 	wait_queue_head_t waitqh;		/* endpoint_disable waiters */
 	wait_queue_head_t waitqh;		/* endpoint_disable waiters */
+	int num_waiting;			/* Number of waiters */
 };
 };
 
 
 /* Convert between a usb_hcd pointer and the corresponding uhci_hcd */
 /* Convert between a usb_hcd pointer and the corresponding uhci_hcd */
@@ -429,7 +448,7 @@ static inline struct usb_hcd *uhci_to_hcd(struct uhci_hcd *uhci)
  *	Private per-URB data
  *	Private per-URB data
  */
  */
 struct urb_priv {
 struct urb_priv {
-	struct list_head urb_list;
+	struct list_head node;		/* Node in the QH's urbp list */
 
 
 	struct urb *urb;
 	struct urb *urb;
 
 
@@ -437,15 +456,8 @@ struct urb_priv {
 	struct list_head td_list;
 	struct list_head td_list;
 
 
 	unsigned fsbr : 1;		/* URB turned on FSBR */
 	unsigned fsbr : 1;		/* URB turned on FSBR */
-	unsigned fsbr_timeout : 1;	/* URB timed out on FSBR */
-	unsigned queued : 1;		/* QH was queued (not linked in) */
-	unsigned short_control_packet : 1;	/* If we get a short packet during */
-						/*  a control transfer, retrigger */
-						/*  the status phase */
-
-	unsigned long fsbrtime;		/* In jiffies */
-
-	struct list_head queue_list;
+	unsigned short_transfer : 1;	/* URB got a short transfer, no
+					 * need to rescan */
 };
 };
 
 
 
 

+ 21 - 0
drivers/usb/host/uhci-hub.c

@@ -99,6 +99,21 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
 	}
 	}
 }
 }
 
 
+/* Wait for the UHCI controller in HP's iLO2 server management chip.
+ * It can take up to 250 us to finish a reset and set the CSC bit.
+ */
+static void wait_for_HP(unsigned long port_addr)
+{
+	int i;
+
+	for (i = 10; i < 250; i += 10) {
+		if (inw(port_addr) & USBPORTSC_CSC)
+			return;
+		udelay(10);
+	}
+	/* Log a warning? */
+}
+
 static void uhci_check_ports(struct uhci_hcd *uhci)
 static void uhci_check_ports(struct uhci_hcd *uhci)
 {
 {
 	unsigned int port;
 	unsigned int port;
@@ -113,6 +128,12 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
 				CLR_RH_PORTSTAT(USBPORTSC_PR);
 				CLR_RH_PORTSTAT(USBPORTSC_PR);
 				udelay(10);
 				udelay(10);
 
 
+				/* HP's server management chip requires
+				 * a longer delay. */
+				if (to_pci_dev(uhci_dev(uhci))->vendor ==
+						PCI_VENDOR_ID_HP)
+					wait_for_HP(port_addr);
+
 				/* If the port was enabled before, turning
 				/* If the port was enabled before, turning
 				 * reset on caused a port enable change.
 				 * reset on caused a port enable change.
 				 * Turning reset off causes a port connect
 				 * Turning reset off causes a port connect

文件差异内容过多而无法显示
+ 316 - 360
drivers/usb/host/uhci-q.c


+ 33 - 34
drivers/usb/image/mdc800.c

@@ -96,6 +96,7 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/smp_lock.h>
 #include <linux/smp_lock.h>
 #include <linux/wait.h>
 #include <linux/wait.h>
+#include <linux/mutex.h>
 
 
 #include <linux/usb.h>
 #include <linux/usb.h>
 #include <linux/fs.h>
 #include <linux/fs.h>
@@ -169,7 +170,7 @@ struct mdc800_data
 	int			out_count;	// Bytes in the buffer
 	int			out_count;	// Bytes in the buffer
 
 
 	int			open;		// Camera device open ?
 	int			open;		// Camera device open ?
-	struct semaphore	io_lock;	// IO -lock
+	struct mutex		io_lock;	// IO -lock
 
 
 	char 			in [8];		// Command Input Buffer
 	char 			in [8];		// Command Input Buffer
 	int  			in_count;
 	int  			in_count;
@@ -497,7 +498,7 @@ static int mdc800_usb_probe (struct usb_interface *intf,
 
 
 	info ("Found Mustek MDC800 on USB.");
 	info ("Found Mustek MDC800 on USB.");
 
 
-	down (&mdc800->io_lock);
+	mutex_lock(&mdc800->io_lock);
 
 
 	retval = usb_register_dev(intf, &mdc800_class);
 	retval = usb_register_dev(intf, &mdc800_class);
 	if (retval) {
 	if (retval) {
@@ -542,7 +543,7 @@ static int mdc800_usb_probe (struct usb_interface *intf,
 
 
 	mdc800->state=READY;
 	mdc800->state=READY;
 
 
-	up (&mdc800->io_lock);
+	mutex_unlock(&mdc800->io_lock);
 	
 	
 	usb_set_intfdata(intf, mdc800);
 	usb_set_intfdata(intf, mdc800);
 	return 0;
 	return 0;
@@ -620,7 +621,7 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
 	int retval=0;
 	int retval=0;
 	int errn=0;
 	int errn=0;
 
 
-	down (&mdc800->io_lock);
+	mutex_lock(&mdc800->io_lock);
 	
 	
 	if (mdc800->state == NOT_CONNECTED)
 	if (mdc800->state == NOT_CONNECTED)
 	{
 	{
@@ -656,7 +657,7 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
 	dbg ("Mustek MDC800 device opened.");
 	dbg ("Mustek MDC800 device opened.");
 
 
 error_out:
 error_out:
-	up (&mdc800->io_lock);
+	mutex_unlock(&mdc800->io_lock);
 	return errn;
 	return errn;
 }
 }
 
 
@@ -669,7 +670,7 @@ static int mdc800_device_release (struct inode* inode, struct file *file)
 	int retval=0;
 	int retval=0;
 	dbg ("Mustek MDC800 device closed.");
 	dbg ("Mustek MDC800 device closed.");
 
 
-	down (&mdc800->io_lock);
+	mutex_lock(&mdc800->io_lock);
 	if (mdc800->open && (mdc800->state != NOT_CONNECTED))
 	if (mdc800->open && (mdc800->state != NOT_CONNECTED))
 	{
 	{
 		usb_kill_urb(mdc800->irq_urb);
 		usb_kill_urb(mdc800->irq_urb);
@@ -682,7 +683,7 @@ static int mdc800_device_release (struct inode* inode, struct file *file)
 		retval=-EIO;
 		retval=-EIO;
 	}
 	}
 
 
-	up(&mdc800->io_lock);
+	mutex_unlock(&mdc800->io_lock);
 	return retval;
 	return retval;
 }
 }
 
 
@@ -695,21 +696,21 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
 	size_t left=len, sts=len; /* single transfer size */
 	size_t left=len, sts=len; /* single transfer size */
 	char __user *ptr = buf;
 	char __user *ptr = buf;
 
 
-	down (&mdc800->io_lock);
+	mutex_lock(&mdc800->io_lock);
 	if (mdc800->state == NOT_CONNECTED)
 	if (mdc800->state == NOT_CONNECTED)
 	{
 	{
-		up (&mdc800->io_lock);
+		mutex_unlock(&mdc800->io_lock);
 		return -EBUSY;
 		return -EBUSY;
 	}
 	}
 	if (mdc800->state == WORKING)
 	if (mdc800->state == WORKING)
 	{
 	{
 		warn ("Illegal State \"working\" reached during read ?!");
 		warn ("Illegal State \"working\" reached during read ?!");
-		up (&mdc800->io_lock);
+		mutex_unlock(&mdc800->io_lock);
 		return -EBUSY;
 		return -EBUSY;
 	}
 	}
 	if (!mdc800->open)
 	if (!mdc800->open)
 	{
 	{
-		up (&mdc800->io_lock);
+		mutex_unlock(&mdc800->io_lock);
 		return -EBUSY;
 		return -EBUSY;
 	}
 	}
 
 
@@ -717,7 +718,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
 	{
 	{
 		if (signal_pending (current)) 
 		if (signal_pending (current)) 
 		{
 		{
-			up (&mdc800->io_lock);
+			mutex_unlock(&mdc800->io_lock);
 			return -EINTR;
 			return -EINTR;
 		}
 		}
 
 
@@ -736,7 +737,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
 				if (usb_submit_urb (mdc800->download_urb, GFP_KERNEL))
 				if (usb_submit_urb (mdc800->download_urb, GFP_KERNEL))
 				{
 				{
 					err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
 					err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
-					up (&mdc800->io_lock);
+					mutex_unlock(&mdc800->io_lock);
 					return len-left;
 					return len-left;
 				}
 				}
 				wait_event_timeout(mdc800->download_wait, mdc800->downloaded,
 				wait_event_timeout(mdc800->download_wait, mdc800->downloaded,
@@ -745,14 +746,14 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
 				if (mdc800->download_urb->status != 0)
 				if (mdc800->download_urb->status != 0)
 				{
 				{
 					err ("request download-bytes fails (status=%i)",mdc800->download_urb->status);
 					err ("request download-bytes fails (status=%i)",mdc800->download_urb->status);
-					up (&mdc800->io_lock);
+					mutex_unlock(&mdc800->io_lock);
 					return len-left;
 					return len-left;
 				}
 				}
 			}
 			}
 			else
 			else
 			{
 			{
 				/* No more bytes -> that's an error*/
 				/* No more bytes -> that's an error*/
-				up (&mdc800->io_lock);
+				mutex_unlock(&mdc800->io_lock);
 				return -EIO;
 				return -EIO;
 			}
 			}
 		}
 		}
@@ -761,7 +762,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
 			/* Copy Bytes */
 			/* Copy Bytes */
 			if (copy_to_user(ptr, &mdc800->out [mdc800->out_ptr],
 			if (copy_to_user(ptr, &mdc800->out [mdc800->out_ptr],
 						sts)) {
 						sts)) {
-				up(&mdc800->io_lock);
+				mutex_unlock(&mdc800->io_lock);
 				return -EFAULT;
 				return -EFAULT;
 			}
 			}
 			ptr+=sts;
 			ptr+=sts;
@@ -770,7 +771,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
 		}
 		}
 	}
 	}
 
 
-	up (&mdc800->io_lock);
+	mutex_unlock(&mdc800->io_lock);
 	return len-left;
 	return len-left;
 }
 }
 
 
@@ -785,15 +786,15 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
 {
 {
 	size_t i=0;
 	size_t i=0;
 
 
-	down (&mdc800->io_lock);
+	mutex_lock(&mdc800->io_lock);
 	if (mdc800->state != READY)
 	if (mdc800->state != READY)
 	{
 	{
-		up (&mdc800->io_lock);
+		mutex_unlock(&mdc800->io_lock);
 		return -EBUSY;
 		return -EBUSY;
 	}
 	}
 	if (!mdc800->open )
 	if (!mdc800->open )
 	{
 	{
-		up (&mdc800->io_lock);
+		mutex_unlock(&mdc800->io_lock);
 		return -EBUSY;
 		return -EBUSY;
 	}
 	}
 
 
@@ -802,13 +803,13 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
 		unsigned char c;
 		unsigned char c;
 		if (signal_pending (current)) 
 		if (signal_pending (current)) 
 		{
 		{
-			up (&mdc800->io_lock);
+			mutex_unlock(&mdc800->io_lock);
 			return -EINTR;
 			return -EINTR;
 		}
 		}
 		
 		
 		if(get_user(c, buf+i))
 		if(get_user(c, buf+i))
 		{
 		{
-			up(&mdc800->io_lock);
+			mutex_unlock(&mdc800->io_lock);
 			return -EFAULT;
 			return -EFAULT;
 		}
 		}
 
 
@@ -829,7 +830,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
 		}
 		}
 		else
 		else
 		{
 		{
-			up (&mdc800->io_lock);
+			mutex_unlock(&mdc800->io_lock);
 			return -EIO;
 			return -EIO;
 		}
 		}
 
 
@@ -841,7 +842,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
 			if (mdc800_usb_waitForIRQ (0,TO_GET_READY))
 			if (mdc800_usb_waitForIRQ (0,TO_GET_READY))
 			{
 			{
 				err ("Camera didn't get ready.\n");
 				err ("Camera didn't get ready.\n");
-				up (&mdc800->io_lock);
+				mutex_unlock(&mdc800->io_lock);
 				return -EIO;
 				return -EIO;
 			}
 			}
 
 
@@ -853,7 +854,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
 			if (usb_submit_urb (mdc800->write_urb, GFP_KERNEL))
 			if (usb_submit_urb (mdc800->write_urb, GFP_KERNEL))
 			{
 			{
 				err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
 				err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
-				up (&mdc800->io_lock);
+				mutex_unlock(&mdc800->io_lock);
 				return -EIO;
 				return -EIO;
 			}
 			}
 			wait_event_timeout(mdc800->write_wait, mdc800->written, TO_WRITE_GET_READY*HZ/1000);
 			wait_event_timeout(mdc800->write_wait, mdc800->written, TO_WRITE_GET_READY*HZ/1000);
@@ -861,7 +862,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
 			if (mdc800->state == WORKING)
 			if (mdc800->state == WORKING)
 			{
 			{
 				usb_kill_urb(mdc800->write_urb);
 				usb_kill_urb(mdc800->write_urb);
-				up (&mdc800->io_lock);
+				mutex_unlock(&mdc800->io_lock);
 				return -EIO;
 				return -EIO;
 			}
 			}
 
 
@@ -873,7 +874,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
 					{
 					{
 						err ("call 0x07 before 0x05,0x3e");
 						err ("call 0x07 before 0x05,0x3e");
 						mdc800->state=READY;
 						mdc800->state=READY;
-						up (&mdc800->io_lock);
+						mutex_unlock(&mdc800->io_lock);
 						return -EIO;
 						return -EIO;
 					}
 					}
 					mdc800->pic_len=-1;
 					mdc800->pic_len=-1;
@@ -892,7 +893,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
 						if (mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ))
 						if (mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ))
 						{
 						{
 							err ("requesting answer from irq fails");
 							err ("requesting answer from irq fails");
-							up (&mdc800->io_lock);
+							mutex_unlock(&mdc800->io_lock);
 							return -EIO;
 							return -EIO;
 						}
 						}
 
 
@@ -920,7 +921,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
 						if (mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND))
 						if (mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND))
 						{
 						{
 							err ("Command Timeout.");
 							err ("Command Timeout.");
-							up (&mdc800->io_lock);
+							mutex_unlock(&mdc800->io_lock);
 							return -EIO;
 							return -EIO;
 						}
 						}
 					}
 					}
@@ -930,7 +931,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
 		}
 		}
 		i++;
 		i++;
 	}
 	}
-	up (&mdc800->io_lock);
+	mutex_unlock(&mdc800->io_lock);
 	return i;
 	return i;
 }
 }
 
 
@@ -978,15 +979,13 @@ static int __init usb_mdc800_init (void)
 {
 {
 	int retval = -ENODEV;
 	int retval = -ENODEV;
 	/* Allocate Memory */
 	/* Allocate Memory */
-	mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL);
+	mdc800=kzalloc (sizeof (struct mdc800_data), GFP_KERNEL);
 	if (!mdc800)
 	if (!mdc800)
 		goto cleanup_on_fail;
 		goto cleanup_on_fail;
 
 
-	memset(mdc800, 0, sizeof(struct mdc800_data));
 	mdc800->dev = NULL;
 	mdc800->dev = NULL;
-	mdc800->open=0;
 	mdc800->state=NOT_CONNECTED;
 	mdc800->state=NOT_CONNECTED;
-	init_MUTEX (&mdc800->io_lock);
+	mutex_init (&mdc800->io_lock);
 
 
 	init_waitqueue_head (&mdc800->irq_wait);
 	init_waitqueue_head (&mdc800->irq_wait);
 	init_waitqueue_head (&mdc800->write_wait);
 	init_waitqueue_head (&mdc800->write_wait);

+ 0 - 2
drivers/usb/input/ati_remote.c

@@ -159,8 +159,6 @@ static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
  */
  */
 #define FILTER_TIME (HZ / 20)
 #define FILTER_TIME (HZ / 20)
 
 
-static DECLARE_MUTEX(disconnect_sem);
-
 struct ati_remote {
 struct ati_remote {
 	struct input_dev *idev;
 	struct input_dev *idev;
 	struct usb_device *udev;
 	struct usb_device *udev;

+ 141 - 34
drivers/usb/input/hid-core.c

@@ -66,9 +66,8 @@ static struct hid_report *hid_register_report(struct hid_device *device, unsigne
 	if (report_enum->report_id_hash[id])
 	if (report_enum->report_id_hash[id])
 		return report_enum->report_id_hash[id];
 		return report_enum->report_id_hash[id];
 
 
-	if (!(report = kmalloc(sizeof(struct hid_report), GFP_KERNEL)))
+	if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL)))
 		return NULL;
 		return NULL;
-	memset(report, 0, sizeof(struct hid_report));
 
 
 	if (id != 0)
 	if (id != 0)
 		report_enum->numbered = 1;
 		report_enum->numbered = 1;
@@ -97,12 +96,9 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
 		return NULL;
 		return NULL;
 	}
 	}
 
 
-	if (!(field = kmalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
+	if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
 		+ values * sizeof(unsigned), GFP_KERNEL))) return NULL;
 		+ values * sizeof(unsigned), GFP_KERNEL))) return NULL;
 
 
-	memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
-		+ values * sizeof(unsigned));
-
 	field->index = report->maxfield++;
 	field->index = report->maxfield++;
 	report->field[field->index] = field;
 	report->field[field->index] = field;
 	field->usage = (struct hid_usage *)(field + 1);
 	field->usage = (struct hid_usage *)(field + 1);
@@ -651,17 +647,14 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
 		hid_parser_reserved
 		hid_parser_reserved
 	};
 	};
 
 
-	if (!(device = kmalloc(sizeof(struct hid_device), GFP_KERNEL)))
+	if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL)))
 		return NULL;
 		return NULL;
-	memset(device, 0, sizeof(struct hid_device));
 
 
-	if (!(device->collection = kmalloc(sizeof(struct hid_collection) *
+	if (!(device->collection = kzalloc(sizeof(struct hid_collection) *
 				   HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {
 				   HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {
 		kfree(device);
 		kfree(device);
 		return NULL;
 		return NULL;
 	}
 	}
-	memset(device->collection, 0, sizeof(struct hid_collection) *
-		HID_DEFAULT_NUM_COLLECTIONS);
 	device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
 	device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
 
 
 	for (i = 0; i < HID_REPORT_TYPES; i++)
 	for (i = 0; i < HID_REPORT_TYPES; i++)
@@ -675,13 +668,12 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
 	memcpy(device->rdesc, start, size);
 	memcpy(device->rdesc, start, size);
 	device->rsize = size;
 	device->rsize = size;
 
 
-	if (!(parser = kmalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
+	if (!(parser = kzalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
 		kfree(device->rdesc);
 		kfree(device->rdesc);
 		kfree(device->collection);
 		kfree(device->collection);
 		kfree(device);
 		kfree(device);
 		return NULL;
 		return NULL;
 	}
 	}
-	memset(parser, 0, sizeof(struct hid_parser));
 	parser->device = device;
 	parser->device = device;
 
 
 	end = start + size;
 	end = start + size;
@@ -910,6 +902,99 @@ static int hid_input_report(int type, struct urb *urb, int interrupt, struct pt_
 	return 0;
 	return 0;
 }
 }
 
 
+/*
+ * Input submission and I/O error handler.
+ */
+
+static void hid_io_error(struct hid_device *hid);
+
+/* Start up the input URB */
+static int hid_start_in(struct hid_device *hid)
+{
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&hid->inlock, flags);
+	if (hid->open > 0 && !test_bit(HID_SUSPENDED, &hid->iofl) &&
+			!test_and_set_bit(HID_IN_RUNNING, &hid->iofl)) {
+		rc = usb_submit_urb(hid->urbin, GFP_ATOMIC);
+		if (rc != 0)
+			clear_bit(HID_IN_RUNNING, &hid->iofl);
+	}
+	spin_unlock_irqrestore(&hid->inlock, flags);
+	return rc;
+}
+
+/* I/O retry timer routine */
+static void hid_retry_timeout(unsigned long _hid)
+{
+	struct hid_device *hid = (struct hid_device *) _hid;
+
+	dev_dbg(&hid->intf->dev, "retrying intr urb\n");
+	if (hid_start_in(hid))
+		hid_io_error(hid);
+}
+
+/* Workqueue routine to reset the device */
+static void hid_reset(void *_hid)
+{
+	struct hid_device *hid = (struct hid_device *) _hid;
+	int rc_lock, rc;
+
+	dev_dbg(&hid->intf->dev, "resetting device\n");
+	rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf);
+	if (rc_lock >= 0) {
+		rc = usb_reset_device(hid->dev);
+		if (rc_lock)
+			usb_unlock_device(hid->dev);
+	}
+	clear_bit(HID_RESET_PENDING, &hid->iofl);
+
+	if (rc == 0) {
+		hid->retry_delay = 0;
+		if (hid_start_in(hid))
+			hid_io_error(hid);
+	} else if (!(rc == -ENODEV || rc == -EHOSTUNREACH || rc == -EINTR))
+		err("can't reset device, %s-%s/input%d, status %d",
+				hid->dev->bus->bus_name,
+				hid->dev->devpath,
+				hid->ifnum, rc);
+}
+
+/* Main I/O error handler */
+static void hid_io_error(struct hid_device *hid)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&hid->inlock, flags);
+
+	/* Stop when disconnected */
+	if (usb_get_intfdata(hid->intf) == NULL)
+		goto done;
+
+	/* When an error occurs, retry at increasing intervals */
+	if (hid->retry_delay == 0) {
+		hid->retry_delay = 13;	/* Then 26, 52, 104, 104, ... */
+		hid->stop_retry = jiffies + msecs_to_jiffies(1000);
+	} else if (hid->retry_delay < 100)
+		hid->retry_delay *= 2;
+
+	if (time_after(jiffies, hid->stop_retry)) {
+
+		/* Retries failed, so do a port reset */
+		if (!test_and_set_bit(HID_RESET_PENDING, &hid->iofl)) {
+			if (schedule_work(&hid->reset_work))
+				goto done;
+			clear_bit(HID_RESET_PENDING, &hid->iofl);
+		}
+	}
+
+	mod_timer(&hid->io_retry,
+			jiffies + msecs_to_jiffies(hid->retry_delay));
+done:
+	spin_unlock_irqrestore(&hid->inlock, flags);
+}
+
 /*
 /*
  * Input interrupt completion handler.
  * Input interrupt completion handler.
  */
  */
@@ -921,25 +1006,35 @@ static void hid_irq_in(struct urb *urb, struct pt_regs *regs)
 
 
 	switch (urb->status) {
 	switch (urb->status) {
 		case 0:			/* success */
 		case 0:			/* success */
+			hid->retry_delay = 0;
 			hid_input_report(HID_INPUT_REPORT, urb, 1, regs);
 			hid_input_report(HID_INPUT_REPORT, urb, 1, regs);
 			break;
 			break;
 		case -ECONNRESET:	/* unlink */
 		case -ECONNRESET:	/* unlink */
 		case -ENOENT:
 		case -ENOENT:
-		case -EPERM:
 		case -ESHUTDOWN:	/* unplug */
 		case -ESHUTDOWN:	/* unplug */
-		case -EILSEQ:		/* unplug timeout on uhci */
+			clear_bit(HID_IN_RUNNING, &hid->iofl);
 			return;
 			return;
+		case -EILSEQ:		/* protocol error or unplug */
+		case -EPROTO:		/* protocol error or unplug */
 		case -ETIMEDOUT:	/* NAK */
 		case -ETIMEDOUT:	/* NAK */
-			break;
+			clear_bit(HID_IN_RUNNING, &hid->iofl);
+			hid_io_error(hid);
+			return;
 		default:		/* error */
 		default:		/* error */
 			warn("input irq status %d received", urb->status);
 			warn("input irq status %d received", urb->status);
 	}
 	}
 
 
 	status = usb_submit_urb(urb, SLAB_ATOMIC);
 	status = usb_submit_urb(urb, SLAB_ATOMIC);
-	if (status)
-		err("can't resubmit intr, %s-%s/input%d, status %d",
-				hid->dev->bus->bus_name, hid->dev->devpath,
-				hid->ifnum, status);
+	if (status) {
+		clear_bit(HID_IN_RUNNING, &hid->iofl);
+		if (status != -EPERM) {
+			err("can't resubmit intr, %s-%s/input%d, status %d",
+					hid->dev->bus->bus_name,
+					hid->dev->devpath,
+					hid->ifnum, status);
+			hid_io_error(hid);
+		}
+	}
 }
 }
 
 
 /*
 /*
@@ -1101,8 +1196,9 @@ static void hid_irq_out(struct urb *urb, struct pt_regs *regs)
 		case 0:			/* success */
 		case 0:			/* success */
 			break;
 			break;
 		case -ESHUTDOWN:	/* unplug */
 		case -ESHUTDOWN:	/* unplug */
-		case -EILSEQ:		/* unplug timeout on uhci */
 			unplug = 1;
 			unplug = 1;
+		case -EILSEQ:		/* protocol error or unplug */
+		case -EPROTO:		/* protocol error or unplug */
 		case -ECONNRESET:	/* unlink */
 		case -ECONNRESET:	/* unlink */
 		case -ENOENT:
 		case -ENOENT:
 			break;
 			break;
@@ -1149,8 +1245,9 @@ static void hid_ctrl(struct urb *urb, struct pt_regs *regs)
 				hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0, regs);
 				hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0, regs);
 			break;
 			break;
 		case -ESHUTDOWN:	/* unplug */
 		case -ESHUTDOWN:	/* unplug */
-		case -EILSEQ:		/* unplug timectrl on uhci */
 			unplug = 1;
 			unplug = 1;
+		case -EILSEQ:		/* protocol error or unplug */
+		case -EPROTO:		/* protocol error or unplug */
 		case -ECONNRESET:	/* unlink */
 		case -ECONNRESET:	/* unlink */
 		case -ENOENT:
 		case -ENOENT:
 		case -EPIPE:		/* report not available */
 		case -EPIPE:		/* report not available */
@@ -1263,14 +1360,9 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
 
 
 int hid_open(struct hid_device *hid)
 int hid_open(struct hid_device *hid)
 {
 {
-	if (hid->open++)
-		return 0;
-
-	hid->urbin->dev = hid->dev;
-
-	if (usb_submit_urb(hid->urbin, GFP_KERNEL))
-		return -EIO;
-
+	++hid->open;
+	if (hid_start_in(hid))
+		hid_io_error(hid);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1460,6 +1552,9 @@ void hid_init_reports(struct hid_device *hid)
 #define USB_VENDOR_ID_HP		0x03f0
 #define USB_VENDOR_ID_HP		0x03f0
 #define USB_DEVICE_ID_HP_USBHUB_KB	0x020c
 #define USB_DEVICE_ID_HP_USBHUB_KB	0x020c
 
 
+#define USB_VENDOR_ID_CREATIVELABS	0x062a
+#define USB_DEVICE_ID_CREATIVELABS_SILVERCREST	0x0201
+
 /*
 /*
  * Alphabetically sorted blacklist by quirk type.
  * Alphabetically sorted blacklist by quirk type.
  */
  */
@@ -1576,6 +1671,7 @@ static const struct hid_blacklist {
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_KEYBOARD, HID_QUIRK_NOGET},
 	{ USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_KEYBOARD, HID_QUIRK_NOGET},
 	{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_USBHUB_KB, HID_QUIRK_NOGET},
 	{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_USBHUB_KB, HID_QUIRK_NOGET},
+	{ USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVELABS_SILVERCREST, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_HP, USB_DEVICE_ID_HP_USBHUB_KB, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_HP, USB_DEVICE_ID_HP_USBHUB_KB, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
 	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
@@ -1795,6 +1891,10 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 
 
 	init_waitqueue_head(&hid->wait);
 	init_waitqueue_head(&hid->wait);
 
 
+	INIT_WORK(&hid->reset_work, hid_reset, hid);
+	setup_timer(&hid->io_retry, hid_retry_timeout, (unsigned long) hid);
+
+	spin_lock_init(&hid->inlock);
 	spin_lock_init(&hid->outlock);
 	spin_lock_init(&hid->outlock);
 	spin_lock_init(&hid->ctrllock);
 	spin_lock_init(&hid->ctrllock);
 
 
@@ -1863,11 +1963,16 @@ static void hid_disconnect(struct usb_interface *intf)
 	if (!hid)
 	if (!hid)
 		return;
 		return;
 
 
+	spin_lock_irq(&hid->inlock);	/* Sync with error handler */
 	usb_set_intfdata(intf, NULL);
 	usb_set_intfdata(intf, NULL);
+	spin_unlock_irq(&hid->inlock);
 	usb_kill_urb(hid->urbin);
 	usb_kill_urb(hid->urbin);
 	usb_kill_urb(hid->urbout);
 	usb_kill_urb(hid->urbout);
 	usb_kill_urb(hid->urbctrl);
 	usb_kill_urb(hid->urbctrl);
 
 
+	del_timer_sync(&hid->io_retry);
+	flush_scheduled_work();
+
 	if (hid->claimed & HID_CLAIMED_INPUT)
 	if (hid->claimed & HID_CLAIMED_INPUT)
 		hidinput_disconnect(hid);
 		hidinput_disconnect(hid);
 	if (hid->claimed & HID_CLAIMED_HIDDEV)
 	if (hid->claimed & HID_CLAIMED_HIDDEV)
@@ -1942,6 +2047,10 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
 {
 {
 	struct hid_device *hid = usb_get_intfdata (intf);
 	struct hid_device *hid = usb_get_intfdata (intf);
 
 
+	spin_lock_irq(&hid->inlock);	/* Sync with error handler */
+	set_bit(HID_SUSPENDED, &hid->iofl);
+	spin_unlock_irq(&hid->inlock);
+	del_timer(&hid->io_retry);
 	usb_kill_urb(hid->urbin);
 	usb_kill_urb(hid->urbin);
 	dev_dbg(&intf->dev, "suspend\n");
 	dev_dbg(&intf->dev, "suspend\n");
 	return 0;
 	return 0;
@@ -1952,10 +2061,8 @@ static int hid_resume(struct usb_interface *intf)
 	struct hid_device *hid = usb_get_intfdata (intf);
 	struct hid_device *hid = usb_get_intfdata (intf);
 	int status;
 	int status;
 
 
-	if (hid->open)
-		status = usb_submit_urb(hid->urbin, GFP_NOIO);
-	else
-		status = 0;
+	clear_bit(HID_SUSPENDED, &hid->iofl);
+	status = hid_start_in(hid);
 	dev_dbg(&intf->dev, "resume status %d\n", status);
 	dev_dbg(&intf->dev, "resume status %d\n", status);
 	return status;
 	return status;
 }
 }

+ 2 - 4
drivers/usb/input/hid-lgff.c

@@ -154,10 +154,9 @@ int hid_lgff_init(struct hid_device* hid)
 		return -1;
 		return -1;
 	}
 	}
 
 
-	private = kmalloc(sizeof(struct lgff_device), GFP_KERNEL);
+	private = kzalloc(sizeof(struct lgff_device), GFP_KERNEL);
 	if (!private)
 	if (!private)
 		return -1;
 		return -1;
-	memset(private, 0, sizeof(struct lgff_device));
 	hid->ff_private = private;
 	hid->ff_private = private;
 
 
 	/* Input init */
 	/* Input init */
@@ -228,13 +227,12 @@ static struct hid_report* hid_lgff_duplicate_report(struct hid_report* report)
 	}
 	}
 	*ret->field[0] = *report->field[0];
 	*ret->field[0] = *report->field[0];
 
 
-	ret->field[0]->value = kmalloc(sizeof(s32[8]), GFP_KERNEL);
+	ret->field[0]->value = kzalloc(sizeof(s32[8]), GFP_KERNEL);
 	if (!ret->field[0]->value) {
 	if (!ret->field[0]->value) {
 		kfree(ret->field[0]);
 		kfree(ret->field[0]);
 		kfree(ret);
 		kfree(ret);
 		return NULL;
 		return NULL;
 	}
 	}
-	memset(ret->field[0]->value, 0, sizeof(s32[8]));
 
 
 	return ret;
 	return ret;
 }
 }

+ 1 - 2
drivers/usb/input/hid-tmff.c

@@ -113,11 +113,10 @@ int hid_tmff_init(struct hid_device *hid)
 	struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
 	struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
 	struct input_dev *input_dev = hidinput->input;
 	struct input_dev *input_dev = hidinput->input;
 
 
-	private = kmalloc(sizeof(struct tmff_device), GFP_KERNEL);
+	private = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
 	if (!private)
 	if (!private)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	memset(private, 0, sizeof(struct tmff_device));
 	hid->ff_private = private;
 	hid->ff_private = private;
 
 
 	/* Find the report to use */
 	/* Find the report to use */

+ 10 - 0
drivers/usb/input/hid.h

@@ -31,6 +31,8 @@
 #include <linux/types.h>
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
 
 
 /*
 /*
  * USB HID (Human Interface Device) interface class code
  * USB HID (Human Interface Device) interface class code
@@ -370,6 +372,9 @@ struct hid_control_fifo {
 
 
 #define HID_CTRL_RUNNING	1
 #define HID_CTRL_RUNNING	1
 #define HID_OUT_RUNNING		2
 #define HID_OUT_RUNNING		2
+#define HID_IN_RUNNING		3
+#define HID_RESET_PENDING	4
+#define HID_SUSPENDED		5
 
 
 struct hid_input {
 struct hid_input {
 	struct list_head list;
 	struct list_head list;
@@ -393,12 +398,17 @@ struct hid_device {							/* device report descriptor */
 	int ifnum;							/* USB interface number */
 	int ifnum;							/* USB interface number */
 
 
 	unsigned long iofl;						/* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
 	unsigned long iofl;						/* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
+	struct timer_list io_retry;					/* Retry timer */
+	unsigned long stop_retry;					/* Time to give up, in jiffies */
+	unsigned int retry_delay;					/* Delay length in ms */
+	struct work_struct reset_work;					/* Task context for resets */
 
 
 	unsigned int bufsize;						/* URB buffer size */
 	unsigned int bufsize;						/* URB buffer size */
 
 
 	struct urb *urbin;						/* Input URB */
 	struct urb *urbin;						/* Input URB */
 	char *inbuf;							/* Input buffer */
 	char *inbuf;							/* Input buffer */
 	dma_addr_t inbuf_dma;						/* Input buffer dma */
 	dma_addr_t inbuf_dma;						/* Input buffer dma */
+	spinlock_t inlock;						/* Input fifo spinlock */
 
 
 	struct urb *urbctrl;						/* Control URB */
 	struct urb *urbctrl;						/* Control URB */
 	struct usb_ctrlrequest *cr;					/* Control request struct */
 	struct usb_ctrlrequest *cr;					/* Control request struct */

+ 2 - 4
drivers/usb/input/hiddev.c

@@ -257,9 +257,8 @@ static int hiddev_open(struct inode * inode, struct file * file) {
 	if (i >= HIDDEV_MINORS || !hiddev_table[i])
 	if (i >= HIDDEV_MINORS || !hiddev_table[i])
 		return -ENODEV;
 		return -ENODEV;
 
 
-	if (!(list = kmalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
+	if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
 		return -ENOMEM;
 		return -ENOMEM;
-	memset(list, 0, sizeof(struct hiddev_list));
 
 
 	list->hiddev = hiddev_table[i];
 	list->hiddev = hiddev_table[i];
 	list->next = hiddev_table[i]->list;
 	list->next = hiddev_table[i]->list;
@@ -754,9 +753,8 @@ int hiddev_connect(struct hid_device *hid)
 	if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
 	if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
 		return -1;
 		return -1;
 
 
-	if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL)))
+	if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL)))
 		return -1;
 		return -1;
-	memset(hiddev, 0, sizeof(struct hiddev));
 
 
 	retval = usb_register_dev(hid->intf, &hiddev_class);
 	retval = usb_register_dev(hid->intf, &hiddev_class);
 	if (retval) {
 	if (retval) {

+ 15 - 0
drivers/usb/media/Kconfig

@@ -191,6 +191,21 @@ config USB_W9968CF
 	  To compile this driver as a module, choose M here: the
 	  To compile this driver as a module, choose M here: the
 	  module will be called w9968cf.
 	  module will be called w9968cf.
 
 
+config USB_ZC0301
+	tristate "USB ZC0301 Image Processor and Control Chip support"
+	depends on USB && VIDEO_DEV
+	---help---
+	  Say Y here if you want support for cameras based on the ZC0301
+	  Image Processor and Control Chip.
+
+	  See <file:Documentation/usb/zc0301.txt> for more informations.
+
+	  This driver uses the Video For Linux API. You must say Y or M to
+	  "Video For Linux" to use this driver.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called zc0301.
+
 config USB_PWC
 config USB_PWC
 	tristate "USB Philips Cameras"
 	tristate "USB Philips Cameras"
 	depends on USB && VIDEO_DEV
 	depends on USB && VIDEO_DEV

+ 6 - 1
drivers/usb/media/Makefile

@@ -2,8 +2,12 @@
 # Makefile for USB Media drivers
 # Makefile for USB Media drivers
 #
 #
 
 
-sn9c102-objs	:= sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bcb.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o
+sn9c102-objs	:= sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \
+		   sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bca.o \
+		   sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \
+		   sn9c102_tas5130d1b.o
 et61x251-objs	:= et61x251_core.o et61x251_tas5130d1b.o
 et61x251-objs	:= et61x251_core.o et61x251_tas5130d1b.o
+zc0301-objs	:= zc0301_core.o zc0301_pas202bcb.o
 
 
 obj-$(CONFIG_USB_DABUSB)	+= dabusb.o
 obj-$(CONFIG_USB_DABUSB)	+= dabusb.o
 obj-$(CONFIG_USB_DSBR)		+= dsbr100.o
 obj-$(CONFIG_USB_DSBR)		+= dsbr100.o
@@ -16,4 +20,5 @@ obj-$(CONFIG_USB_SN9C102)	+= sn9c102.o
 obj-$(CONFIG_USB_STV680)	+= stv680.o
 obj-$(CONFIG_USB_STV680)	+= stv680.o
 obj-$(CONFIG_USB_VICAM)		+= vicam.o usbvideo.o
 obj-$(CONFIG_USB_VICAM)		+= vicam.o usbvideo.o
 obj-$(CONFIG_USB_W9968CF)	+= w9968cf.o
 obj-$(CONFIG_USB_W9968CF)	+= w9968cf.o
+obj-$(CONFIG_USB_ZC0301)	+= zc0301.o
 obj-$(CONFIG_USB_PWC)           += pwc/
 obj-$(CONFIG_USB_PWC)           += pwc/

+ 18 - 18
drivers/usb/media/dabusb.c

@@ -38,6 +38,7 @@
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
 #include <linux/smp_lock.h>
 #include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 
 #include "dabusb.h"
 #include "dabusb.h"
 #include "dabfirmware.h"
 #include "dabfirmware.h"
@@ -217,12 +218,11 @@ static int dabusb_alloc_buffers (pdabusb_t s)
 		 pipesize, packets, transfer_buffer_length);
 		 pipesize, packets, transfer_buffer_length);
 
 
 	while (buffers < (s->total_buffer_size << 10)) {
 	while (buffers < (s->total_buffer_size << 10)) {
-		b = (pbuff_t) kmalloc (sizeof (buff_t), GFP_KERNEL);
+		b = (pbuff_t) kzalloc (sizeof (buff_t), GFP_KERNEL);
 		if (!b) {
 		if (!b) {
-			err("kmalloc(sizeof(buff_t))==NULL");
+			err("kzalloc(sizeof(buff_t))==NULL");
 			goto err;
 			goto err;
 		}
 		}
-		memset (b, 0, sizeof (buff_t));
 		b->s = s;
 		b->s = s;
 		b->purb = usb_alloc_urb(packets, GFP_KERNEL);
 		b->purb = usb_alloc_urb(packets, GFP_KERNEL);
 		if (!b->purb) {
 		if (!b->purb) {
@@ -571,7 +571,7 @@ static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, l
 			s->readptr = 0;
 			s->readptr = 0;
 		}
 		}
 	}
 	}
-      err:			//up(&s->mutex);
+      err:			//mutex_unlock(&s->mutex);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -586,10 +586,10 @@ static int dabusb_open (struct inode *inode, struct file *file)
 	s = &dabusb[devnum - DABUSB_MINOR];
 	s = &dabusb[devnum - DABUSB_MINOR];
 
 
 	dbg("dabusb_open");
 	dbg("dabusb_open");
-	down (&s->mutex);
+	mutex_lock(&s->mutex);
 
 
 	while (!s->usbdev || s->opened) {
 	while (!s->usbdev || s->opened) {
-		up (&s->mutex);
+		mutex_unlock(&s->mutex);
 
 
 		if (file->f_flags & O_NONBLOCK) {
 		if (file->f_flags & O_NONBLOCK) {
 			return -EBUSY;
 			return -EBUSY;
@@ -599,15 +599,15 @@ static int dabusb_open (struct inode *inode, struct file *file)
 		if (signal_pending (current)) {
 		if (signal_pending (current)) {
 			return -EAGAIN;
 			return -EAGAIN;
 		}
 		}
-		down (&s->mutex);
+		mutex_lock(&s->mutex);
 	}
 	}
 	if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
 	if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
-		up(&s->mutex);
+		mutex_unlock(&s->mutex);
 		err("set_interface failed");
 		err("set_interface failed");
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 	s->opened = 1;
 	s->opened = 1;
-	up (&s->mutex);
+	mutex_unlock(&s->mutex);
 
 
 	file->f_pos = 0;
 	file->f_pos = 0;
 	file->private_data = s;
 	file->private_data = s;
@@ -621,10 +621,10 @@ static int dabusb_release (struct inode *inode, struct file *file)
 
 
 	dbg("dabusb_release");
 	dbg("dabusb_release");
 
 
-	down (&s->mutex);
+	mutex_lock(&s->mutex);
 	dabusb_stop (s);
 	dabusb_stop (s);
 	dabusb_free_buffers (s);
 	dabusb_free_buffers (s);
-	up (&s->mutex);
+	mutex_unlock(&s->mutex);
 
 
 	if (!s->remove_pending) {
 	if (!s->remove_pending) {
 		if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0)
 		if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0)
@@ -649,10 +649,10 @@ static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cm
 	if (s->remove_pending)
 	if (s->remove_pending)
 		return -EIO;
 		return -EIO;
 
 
-	down (&s->mutex);
+	mutex_lock(&s->mutex);
 
 
 	if (!s->usbdev) {
 	if (!s->usbdev) {
-		up (&s->mutex);
+		mutex_unlock(&s->mutex);
 		return -EIO;
 		return -EIO;
 	}
 	}
 
 
@@ -692,7 +692,7 @@ static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cm
 		ret = -ENOIOCTLCMD;
 		ret = -ENOIOCTLCMD;
 		break;
 		break;
 	}
 	}
-	up (&s->mutex);
+	mutex_unlock(&s->mutex);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -738,7 +738,7 @@ static int dabusb_probe (struct usb_interface *intf,
 
 
 	s = &dabusb[intf->minor];
 	s = &dabusb[intf->minor];
 
 
-	down (&s->mutex);
+	mutex_lock(&s->mutex);
 	s->remove_pending = 0;
 	s->remove_pending = 0;
 	s->usbdev = usbdev;
 	s->usbdev = usbdev;
 	s->devnum = intf->minor;
 	s->devnum = intf->minor;
@@ -761,7 +761,7 @@ static int dabusb_probe (struct usb_interface *intf,
 	}
 	}
 	dbg("bound to interface: %d", intf->altsetting->desc.bInterfaceNumber);
 	dbg("bound to interface: %d", intf->altsetting->desc.bInterfaceNumber);
 	usb_set_intfdata (intf, s);
 	usb_set_intfdata (intf, s);
-	up (&s->mutex);
+	mutex_unlock(&s->mutex);
 
 
 	retval = usb_register_dev(intf, &dabusb_class);
 	retval = usb_register_dev(intf, &dabusb_class);
 	if (retval) {
 	if (retval) {
@@ -772,7 +772,7 @@ static int dabusb_probe (struct usb_interface *intf,
 	return 0;
 	return 0;
 
 
       reject:
       reject:
-	up (&s->mutex);
+	mutex_unlock(&s->mutex);
 	s->usbdev = NULL;
 	s->usbdev = NULL;
 	return -ENODEV;
 	return -ENODEV;
 }
 }
@@ -829,7 +829,7 @@ static int __init dabusb_init (void)
 	for (u = 0; u < NRDABUSB; u++) {
 	for (u = 0; u < NRDABUSB; u++) {
 		pdabusb_t s = &dabusb[u];
 		pdabusb_t s = &dabusb[u];
 		memset (s, 0, sizeof (dabusb_t));
 		memset (s, 0, sizeof (dabusb_t));
-		init_MUTEX (&s->mutex);
+		mutex_init (&s->mutex);
 		s->usbdev = NULL;
 		s->usbdev = NULL;
 		s->total_buffer_size = buffers;
 		s->total_buffer_size = buffers;
 		init_waitqueue_head (&s->wait);
 		init_waitqueue_head (&s->wait);

+ 1 - 1
drivers/usb/media/dabusb.h

@@ -18,7 +18,7 @@ typedef enum { _stopped=0, _started } driver_state_t;
 
 
 typedef struct
 typedef struct
 {
 {
-	struct semaphore mutex;
+	struct mutex mutex;
 	struct usb_device *usbdev;
 	struct usb_device *usbdev;
 	wait_queue_head_t wait;
 	wait_queue_head_t wait;
 	wait_queue_head_t remove_ok;
 	wait_queue_head_t remove_ok;

+ 21 - 7
drivers/usb/media/et61x251.h

@@ -33,7 +33,9 @@
 #include <linux/types.h>
 #include <linux/types.h>
 #include <linux/param.h>
 #include <linux/param.h>
 #include <linux/rwsem.h>
 #include <linux/rwsem.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
 
 
 #include "et61x251_sensor.h"
 #include "et61x251_sensor.h"
 
 
@@ -51,6 +53,7 @@
 #define ET61X251_ALTERNATE_SETTING   13
 #define ET61X251_ALTERNATE_SETTING   13
 #define ET61X251_URB_TIMEOUT         msecs_to_jiffies(2 * ET61X251_ISO_PACKETS)
 #define ET61X251_URB_TIMEOUT         msecs_to_jiffies(2 * ET61X251_ISO_PACKETS)
 #define ET61X251_CTRL_TIMEOUT        100
 #define ET61X251_CTRL_TIMEOUT        100
+#define ET61X251_FRAME_TIMEOUT       2
 
 
 /*****************************************************************************/
 /*****************************************************************************/
 
 
@@ -127,15 +130,16 @@ struct et61x251_sysfs_attr {
 
 
 struct et61x251_module_param {
 struct et61x251_module_param {
 	u8 force_munmap;
 	u8 force_munmap;
+	u16 frame_timeout;
 };
 };
 
 
-static DECLARE_MUTEX(et61x251_sysfs_lock);
+static DEFINE_MUTEX(et61x251_sysfs_lock);
 static DECLARE_RWSEM(et61x251_disconnect);
 static DECLARE_RWSEM(et61x251_disconnect);
 
 
 struct et61x251_device {
 struct et61x251_device {
 	struct video_device* v4ldev;
 	struct video_device* v4ldev;
 
 
-	struct et61x251_sensor* sensor;
+	struct et61x251_sensor sensor;
 
 
 	struct usb_device* usbdev;
 	struct usb_device* usbdev;
 	struct urb* urb[ET61X251_URBS];
 	struct urb* urb[ET61X251_URBS];
@@ -157,19 +161,28 @@ struct et61x251_device {
 	enum et61x251_dev_state state;
 	enum et61x251_dev_state state;
 	u8 users;
 	u8 users;
 
 
-	struct semaphore dev_sem, fileop_sem;
+	struct mutex dev_mutex, fileop_mutex;
 	spinlock_t queue_lock;
 	spinlock_t queue_lock;
 	wait_queue_head_t open, wait_frame, wait_stream;
 	wait_queue_head_t open, wait_frame, wait_stream;
 };
 };
 
 
 /*****************************************************************************/
 /*****************************************************************************/
 
 
+struct et61x251_device*
+et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id)
+{
+	if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
+		return cam;
+
+	return NULL;
+}
+
+
 void
 void
 et61x251_attach_sensor(struct et61x251_device* cam,
 et61x251_attach_sensor(struct et61x251_device* cam,
                        struct et61x251_sensor* sensor)
                        struct et61x251_sensor* sensor)
 {
 {
-	cam->sensor = sensor;
-	cam->sensor->usbdev = cam->usbdev;
+	memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor));
 }
 }
 
 
 /*****************************************************************************/
 /*****************************************************************************/
@@ -212,7 +225,8 @@ do {                                                                          \
 
 
 #undef PDBG
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
+         __FUNCTION__, __LINE__ , ## args)
 
 
 #undef PDBGG
 #undef PDBGG
 #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
 #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */

文件差异内容过多而无法显示
+ 170 - 146
drivers/usb/media/et61x251_core.c


+ 3 - 2
drivers/usb/media/et61x251_sensor.h

@@ -42,6 +42,9 @@ static int (*et61x251_sensor_table[])(struct et61x251_device*) = {            \
 	NULL,                                                                 \
 	NULL,                                                                 \
 };
 };
 
 
+extern struct et61x251_device*
+et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id);
+
 extern void
 extern void
 et61x251_attach_sensor(struct et61x251_device* cam,
 et61x251_attach_sensor(struct et61x251_device* cam,
                        struct et61x251_sensor* sensor);
                        struct et61x251_sensor* sensor);
@@ -105,8 +108,6 @@ struct et61x251_sensor {
 	int (*set_pix_format)(struct et61x251_device* cam,
 	int (*set_pix_format)(struct et61x251_device* cam,
 	                      const struct v4l2_pix_format* pix);
 	                      const struct v4l2_pix_format* pix);
 
 
-	const struct usb_device* usbdev;
-
 	/* Private */
 	/* Private */
 	struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS];
 	struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS];
 	struct v4l2_rect _rect;
 	struct v4l2_rect _rect;

+ 7 - 3
drivers/usb/media/et61x251_tas5130d1b.c

@@ -126,12 +126,16 @@ static struct et61x251_sensor tas5130d1b = {
 
 
 int et61x251_probe_tas5130d1b(struct et61x251_device* cam)
 int et61x251_probe_tas5130d1b(struct et61x251_device* cam)
 {
 {
-	/* This sensor has no identifiers, so let's attach it anyway */
-	et61x251_attach_sensor(cam, &tas5130d1b);
+	const struct usb_device_id tas5130d1b_id_table[] = {
+		{ USB_DEVICE(0x102c, 0x6251), },
+		{ }
+	};
 
 
 	/* Sensor detection is based on USB pid/vid */
 	/* Sensor detection is based on USB pid/vid */
-	if (le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x6251)
+	if (!et61x251_match_id(cam, tas5130d1b_id_table))
 		return -ENODEV;
 		return -ENODEV;
 
 
+	et61x251_attach_sensor(cam, &tas5130d1b);
+
 	return 0;
 	return 0;
 }
 }

+ 47 - 50
drivers/usb/media/ov511.c

@@ -365,14 +365,14 @@ reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
 
 
 	PDEBUG(5, "0x%02X:0x%02X", reg, value);
 	PDEBUG(5, "0x%02X:0x%02X", reg, value);
 
 
-	down(&ov->cbuf_lock);
+	mutex_lock(&ov->cbuf_lock);
 	ov->cbuf[0] = value;
 	ov->cbuf[0] = value;
 	rc = usb_control_msg(ov->dev,
 	rc = usb_control_msg(ov->dev,
 			     usb_sndctrlpipe(ov->dev, 0),
 			     usb_sndctrlpipe(ov->dev, 0),
 			     (ov->bclass == BCL_OV518)?1:2 /* REG_IO */,
 			     (ov->bclass == BCL_OV518)?1:2 /* REG_IO */,
 			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			     0, (__u16)reg, &ov->cbuf[0], 1, 1000);
 			     0, (__u16)reg, &ov->cbuf[0], 1, 1000);
-	up(&ov->cbuf_lock);
+	mutex_unlock(&ov->cbuf_lock);
 
 
 	if (rc < 0)
 	if (rc < 0)
 		err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc));
 		err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc));
@@ -387,7 +387,7 @@ reg_r(struct usb_ov511 *ov, unsigned char reg)
 {
 {
 	int rc;
 	int rc;
 
 
-	down(&ov->cbuf_lock);
+	mutex_lock(&ov->cbuf_lock);
 	rc = usb_control_msg(ov->dev,
 	rc = usb_control_msg(ov->dev,
 			     usb_rcvctrlpipe(ov->dev, 0),
 			     usb_rcvctrlpipe(ov->dev, 0),
 			     (ov->bclass == BCL_OV518)?1:3 /* REG_IO */,
 			     (ov->bclass == BCL_OV518)?1:3 /* REG_IO */,
@@ -401,7 +401,7 @@ reg_r(struct usb_ov511 *ov, unsigned char reg)
 		PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
 		PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
 	}
 	}
 
 
-	up(&ov->cbuf_lock);
+	mutex_unlock(&ov->cbuf_lock);
 
 
 	return rc;
 	return rc;
 }
 }
@@ -444,7 +444,7 @@ ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
 
 
 	PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n);
 	PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n);
 
 
-	down(&ov->cbuf_lock);
+	mutex_lock(&ov->cbuf_lock);
 
 
 	*((__le32 *)ov->cbuf) = __cpu_to_le32(val);
 	*((__le32 *)ov->cbuf) = __cpu_to_le32(val);
 
 
@@ -453,7 +453,7 @@ ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
 			     1 /* REG_IO */,
 			     1 /* REG_IO */,
 			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			     0, (__u16)reg, ov->cbuf, n, 1000);
 			     0, (__u16)reg, ov->cbuf, n, 1000);
-	up(&ov->cbuf_lock);
+	mutex_unlock(&ov->cbuf_lock);
 
 
 	if (rc < 0)
 	if (rc < 0)
 		err("reg write multiple: error %d: %s", rc,
 		err("reg write multiple: error %d: %s", rc,
@@ -768,14 +768,14 @@ i2c_r(struct usb_ov511 *ov, unsigned char reg)
 {
 {
 	int rc;
 	int rc;
 
 
-	down(&ov->i2c_lock);
+	mutex_lock(&ov->i2c_lock);
 
 
 	if (ov->bclass == BCL_OV518)
 	if (ov->bclass == BCL_OV518)
 		rc = ov518_i2c_read_internal(ov, reg);
 		rc = ov518_i2c_read_internal(ov, reg);
 	else
 	else
 		rc = ov511_i2c_read_internal(ov, reg);
 		rc = ov511_i2c_read_internal(ov, reg);
 
 
-	up(&ov->i2c_lock);
+	mutex_unlock(&ov->i2c_lock);
 
 
 	return rc;
 	return rc;
 }
 }
@@ -785,14 +785,14 @@ i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
 {
 {
 	int rc;
 	int rc;
 
 
-	down(&ov->i2c_lock);
+	mutex_lock(&ov->i2c_lock);
 
 
 	if (ov->bclass == BCL_OV518)
 	if (ov->bclass == BCL_OV518)
 		rc = ov518_i2c_write_internal(ov, reg, value);
 		rc = ov518_i2c_write_internal(ov, reg, value);
 	else
 	else
 		rc = ov511_i2c_write_internal(ov, reg, value);
 		rc = ov511_i2c_write_internal(ov, reg, value);
 
 
-	up(&ov->i2c_lock);
+	mutex_unlock(&ov->i2c_lock);
 
 
 	return rc;
 	return rc;
 }
 }
@@ -842,9 +842,9 @@ i2c_w_mask(struct usb_ov511 *ov,
 {
 {
 	int rc;
 	int rc;
 
 
-	down(&ov->i2c_lock);
+	mutex_lock(&ov->i2c_lock);
 	rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
 	rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
-	up(&ov->i2c_lock);
+	mutex_unlock(&ov->i2c_lock);
 
 
 	return rc;
 	return rc;
 }
 }
@@ -880,7 +880,7 @@ i2c_w_slave(struct usb_ov511 *ov,
 {
 {
 	int rc = 0;
 	int rc = 0;
 
 
-	down(&ov->i2c_lock);
+	mutex_lock(&ov->i2c_lock);
 
 
 	/* Set new slave IDs */
 	/* Set new slave IDs */
 	rc = i2c_set_slave_internal(ov, slave);
 	rc = i2c_set_slave_internal(ov, slave);
@@ -894,7 +894,7 @@ out:
 	if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
 	if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
 		err("Couldn't restore primary I2C slave");
 		err("Couldn't restore primary I2C slave");
 
 
-	up(&ov->i2c_lock);
+	mutex_unlock(&ov->i2c_lock);
 	return rc;
 	return rc;
 }
 }
 
 
@@ -906,7 +906,7 @@ i2c_r_slave(struct usb_ov511 *ov,
 {
 {
 	int rc;
 	int rc;
 
 
-	down(&ov->i2c_lock);
+	mutex_lock(&ov->i2c_lock);
 
 
 	/* Set new slave IDs */
 	/* Set new slave IDs */
 	rc = i2c_set_slave_internal(ov, slave);
 	rc = i2c_set_slave_internal(ov, slave);
@@ -923,7 +923,7 @@ out:
 	if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
 	if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
 		err("Couldn't restore primary I2C slave");
 		err("Couldn't restore primary I2C slave");
 
 
-	up(&ov->i2c_lock);
+	mutex_unlock(&ov->i2c_lock);
 	return rc;
 	return rc;
 }
 }
 
 
@@ -933,7 +933,7 @@ ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
 {
 {
 	int rc;
 	int rc;
 
 
-	down(&ov->i2c_lock);
+	mutex_lock(&ov->i2c_lock);
 
 
 	rc = i2c_set_slave_internal(ov, sid);
 	rc = i2c_set_slave_internal(ov, sid);
 	if (rc < 0)
 	if (rc < 0)
@@ -942,7 +942,7 @@ ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
 	// FIXME: Is this actually necessary?
 	// FIXME: Is this actually necessary?
 	rc = ov51x_reset(ov, OV511_RESET_NOREGS);
 	rc = ov51x_reset(ov, OV511_RESET_NOREGS);
 out:
 out:
-	up(&ov->i2c_lock);
+	mutex_unlock(&ov->i2c_lock);
 	return rc;
 	return rc;
 }
 }
 
 
@@ -3832,7 +3832,7 @@ ov51x_alloc(struct usb_ov511 *ov)
 	const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h);
 	const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h);
 
 
 	PDEBUG(4, "entered");
 	PDEBUG(4, "entered");
-	down(&ov->buf_lock);
+	mutex_lock(&ov->buf_lock);
 
 
 	if (ov->buf_state == BUF_ALLOCATED)
 	if (ov->buf_state == BUF_ALLOCATED)
 		goto out;
 		goto out;
@@ -3879,12 +3879,12 @@ ov51x_alloc(struct usb_ov511 *ov)
 
 
 	ov->buf_state = BUF_ALLOCATED;
 	ov->buf_state = BUF_ALLOCATED;
 out:
 out:
-	up(&ov->buf_lock);
+	mutex_unlock(&ov->buf_lock);
 	PDEBUG(4, "leaving");
 	PDEBUG(4, "leaving");
 	return 0;
 	return 0;
 error:
 error:
 	ov51x_do_dealloc(ov);
 	ov51x_do_dealloc(ov);
-	up(&ov->buf_lock);
+	mutex_unlock(&ov->buf_lock);
 	PDEBUG(4, "errored");
 	PDEBUG(4, "errored");
 	return -ENOMEM;
 	return -ENOMEM;
 }
 }
@@ -3893,9 +3893,9 @@ static void
 ov51x_dealloc(struct usb_ov511 *ov)
 ov51x_dealloc(struct usb_ov511 *ov)
 {
 {
 	PDEBUG(4, "entered");
 	PDEBUG(4, "entered");
-	down(&ov->buf_lock);
+	mutex_lock(&ov->buf_lock);
 	ov51x_do_dealloc(ov);
 	ov51x_do_dealloc(ov);
-	up(&ov->buf_lock);
+	mutex_unlock(&ov->buf_lock);
 	PDEBUG(4, "leaving");
 	PDEBUG(4, "leaving");
 }
 }
 
 
@@ -3914,7 +3914,7 @@ ov51x_v4l1_open(struct inode *inode, struct file *file)
 
 
 	PDEBUG(4, "opening");
 	PDEBUG(4, "opening");
 
 
-	down(&ov->lock);
+	mutex_lock(&ov->lock);
 
 
 	err = -EBUSY;
 	err = -EBUSY;
 	if (ov->user)
 	if (ov->user)
@@ -3958,7 +3958,7 @@ ov51x_v4l1_open(struct inode *inode, struct file *file)
 		ov51x_led_control(ov, 1);
 		ov51x_led_control(ov, 1);
 
 
 out:
 out:
-	up(&ov->lock);
+	mutex_unlock(&ov->lock);
 	return err;
 	return err;
 }
 }
 
 
@@ -3970,7 +3970,7 @@ ov51x_v4l1_close(struct inode *inode, struct file *file)
 
 
 	PDEBUG(4, "ov511_close");
 	PDEBUG(4, "ov511_close");
 
 
-	down(&ov->lock);
+	mutex_lock(&ov->lock);
 
 
 	ov->user--;
 	ov->user--;
 	ov51x_stop_isoc(ov);
 	ov51x_stop_isoc(ov);
@@ -3981,15 +3981,15 @@ ov51x_v4l1_close(struct inode *inode, struct file *file)
 	if (ov->dev)
 	if (ov->dev)
 		ov51x_dealloc(ov);
 		ov51x_dealloc(ov);
 
 
-	up(&ov->lock);
+	mutex_unlock(&ov->lock);
 
 
 	/* Device unplugged while open. Only a minimum of unregistration is done
 	/* Device unplugged while open. Only a minimum of unregistration is done
 	 * here; the disconnect callback already did the rest. */
 	 * here; the disconnect callback already did the rest. */
 	if (!ov->dev) {
 	if (!ov->dev) {
-		down(&ov->cbuf_lock);
+		mutex_lock(&ov->cbuf_lock);
 		kfree(ov->cbuf);
 		kfree(ov->cbuf);
 		ov->cbuf = NULL;
 		ov->cbuf = NULL;
-		up(&ov->cbuf_lock);
+		mutex_unlock(&ov->cbuf_lock);
 
 
 		ov51x_dealloc(ov);
 		ov51x_dealloc(ov);
 		kfree(ov);
 		kfree(ov);
@@ -4449,12 +4449,12 @@ ov51x_v4l1_ioctl(struct inode *inode, struct file *file,
 	struct usb_ov511 *ov = video_get_drvdata(vdev);
 	struct usb_ov511 *ov = video_get_drvdata(vdev);
 	int rc;
 	int rc;
 
 
-	if (down_interruptible(&ov->lock))
+	if (mutex_lock_interruptible(&ov->lock))
 		return -EINTR;
 		return -EINTR;
 
 
 	rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal);
 	rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal);
 
 
-	up(&ov->lock);
+	mutex_unlock(&ov->lock);
 	return rc;
 	return rc;
 }
 }
 
 
@@ -4468,7 +4468,7 @@ ov51x_v4l1_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos)
 	int i, rc = 0, frmx = -1;
 	int i, rc = 0, frmx = -1;
 	struct ov511_frame *frame;
 	struct ov511_frame *frame;
 
 
-	if (down_interruptible(&ov->lock))
+	if (mutex_lock_interruptible(&ov->lock))
 		return -EINTR;
 		return -EINTR;
 
 
 	PDEBUG(4, "%ld bytes, noblock=%d", count, noblock);
 	PDEBUG(4, "%ld bytes, noblock=%d", count, noblock);
@@ -4604,11 +4604,11 @@ restart:
 
 
 	PDEBUG(4, "read finished, returning %ld (sweet)", count);
 	PDEBUG(4, "read finished, returning %ld (sweet)", count);
 
 
-	up(&ov->lock);
+	mutex_unlock(&ov->lock);
 	return count;
 	return count;
 
 
 error:
 error:
-	up(&ov->lock);
+	mutex_unlock(&ov->lock);
 	return rc;
 	return rc;
 }
 }
 
 
@@ -4631,14 +4631,14 @@ ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
 	              + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))))
 	              + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))))
 		return -EINVAL;
 		return -EINVAL;
 
 
-	if (down_interruptible(&ov->lock))
+	if (mutex_lock_interruptible(&ov->lock))
 		return -EINTR;
 		return -EINTR;
 
 
 	pos = (unsigned long)ov->fbuf;
 	pos = (unsigned long)ov->fbuf;
 	while (size > 0) {
 	while (size > 0) {
 		page = vmalloc_to_pfn((void *)pos);
 		page = vmalloc_to_pfn((void *)pos);
 		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
 		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-			up(&ov->lock);
+			mutex_unlock(&ov->lock);
 			return -EAGAIN;
 			return -EAGAIN;
 		}
 		}
 		start += PAGE_SIZE;
 		start += PAGE_SIZE;
@@ -4649,7 +4649,7 @@ ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
 			size = 0;
 			size = 0;
 	}
 	}
 
 
-	up(&ov->lock);
+	mutex_unlock(&ov->lock);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -5639,7 +5639,7 @@ static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
 static ssize_t show_exposure(struct class_device *cd, char *buf)
 static ssize_t show_exposure(struct class_device *cd, char *buf)
 {
 {
 	struct usb_ov511 *ov = cd_to_ov(cd);
 	struct usb_ov511 *ov = cd_to_ov(cd);
-	unsigned char exp;
+	unsigned char exp = 0;
 
 
 	if (!ov->dev)
 	if (!ov->dev)
 		return -ENODEV;
 		return -ENODEV;
@@ -5686,13 +5686,11 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	if (idesc->bInterfaceSubClass != 0x00)
 	if (idesc->bInterfaceSubClass != 0x00)
 		return -ENODEV;
 		return -ENODEV;
 
 
-	if ((ov = kmalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
+	if ((ov = kzalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
 		err("couldn't kmalloc ov struct");
 		err("couldn't kmalloc ov struct");
 		goto error_out;
 		goto error_out;
 	}
 	}
 
 
-	memset(ov, 0, sizeof(*ov));
-
 	ov->dev = dev;
 	ov->dev = dev;
 	ov->iface = idesc->bInterfaceNumber;
 	ov->iface = idesc->bInterfaceNumber;
 	ov->led_policy = led;
 	ov->led_policy = led;
@@ -5738,11 +5736,10 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
 
 
 	init_waitqueue_head(&ov->wq);
 	init_waitqueue_head(&ov->wq);
 
 
-	init_MUTEX(&ov->lock);	/* to 1 == available */
-	init_MUTEX(&ov->buf_lock);
-	init_MUTEX(&ov->param_lock);
-	init_MUTEX(&ov->i2c_lock);
-	init_MUTEX(&ov->cbuf_lock);
+	mutex_init(&ov->lock);	/* to 1 == available */
+	mutex_init(&ov->buf_lock);
+	mutex_init(&ov->i2c_lock);
+	mutex_init(&ov->cbuf_lock);
 
 
 	ov->buf_state = BUF_NOT_ALLOCATED;
 	ov->buf_state = BUF_NOT_ALLOCATED;
 
 
@@ -5833,10 +5830,10 @@ error:
 	}
 	}
 
 
 	if (ov->cbuf) {
 	if (ov->cbuf) {
-		down(&ov->cbuf_lock);
+		mutex_lock(&ov->cbuf_lock);
 		kfree(ov->cbuf);
 		kfree(ov->cbuf);
 		ov->cbuf = NULL;
 		ov->cbuf = NULL;
-		up(&ov->cbuf_lock);
+		mutex_unlock(&ov->cbuf_lock);
 	}
 	}
 
 
 	kfree(ov);
 	kfree(ov);
@@ -5881,10 +5878,10 @@ ov51x_disconnect(struct usb_interface *intf)
 
 
 	/* Free the memory */
 	/* Free the memory */
 	if (ov && !ov->user) {
 	if (ov && !ov->user) {
-		down(&ov->cbuf_lock);
+		mutex_lock(&ov->cbuf_lock);
 		kfree(ov->cbuf);
 		kfree(ov->cbuf);
 		ov->cbuf = NULL;
 		ov->cbuf = NULL;
-		up(&ov->cbuf_lock);
+		mutex_unlock(&ov->cbuf_lock);
 
 
 		ov51x_dealloc(ov);
 		ov51x_dealloc(ov);
 		kfree(ov);
 		kfree(ov);

+ 5 - 6
drivers/usb/media/ov511.h

@@ -5,6 +5,7 @@
 #include <linux/videodev.h>
 #include <linux/videodev.h>
 #include <linux/smp_lock.h>
 #include <linux/smp_lock.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 
 
 #define OV511_DEBUG	/* Turn on debug messages */
 #define OV511_DEBUG	/* Turn on debug messages */
 
 
@@ -435,7 +436,7 @@ struct usb_ov511 {
 
 
 	int led_policy;		/* LED: off|on|auto; OV511+ only */
 	int led_policy;		/* LED: off|on|auto; OV511+ only */
 
 
-	struct semaphore lock;	/* Serializes user-accessible operations */
+	struct mutex lock;	/* Serializes user-accessible operations */
 	int user;		/* user count for exclusive use */
 	int user;		/* user count for exclusive use */
 
 
 	int streaming;		/* Are we streaming Isochronous? */
 	int streaming;		/* Are we streaming Isochronous? */
@@ -473,11 +474,9 @@ struct usb_ov511 {
 	int packet_size;	/* Frame size per isoc desc */
 	int packet_size;	/* Frame size per isoc desc */
 	int packet_numbering;	/* Is ISO frame numbering enabled? */
 	int packet_numbering;	/* Is ISO frame numbering enabled? */
 
 
-	struct semaphore param_lock;	/* params lock for this camera */
-
 	/* Framebuffer/sbuf management */
 	/* Framebuffer/sbuf management */
 	int buf_state;
 	int buf_state;
-	struct semaphore buf_lock;
+	struct mutex buf_lock;
 
 
 	struct ov51x_decomp_ops *decomp_ops;
 	struct ov51x_decomp_ops *decomp_ops;
 
 
@@ -494,12 +493,12 @@ struct usb_ov511 {
 	int pal;		/* Device is designed for PAL resolution */
 	int pal;		/* Device is designed for PAL resolution */
 
 
 	/* I2C interface */
 	/* I2C interface */
-	struct semaphore i2c_lock;	  /* Protect I2C controller regs */
+	struct mutex i2c_lock;	  /* Protect I2C controller regs */
 	unsigned char primary_i2c_slave;  /* I2C write id of sensor */
 	unsigned char primary_i2c_slave;  /* I2C write id of sensor */
 
 
 	/* Control transaction stuff */
 	/* Control transaction stuff */
 	unsigned char *cbuf;		/* Buffer for payload */
 	unsigned char *cbuf;		/* Buffer for payload */
-	struct semaphore cbuf_lock;
+	struct mutex cbuf_lock;
 };
 };
 
 
 /* Used to represent a list of values and their respective symbolic names */
 /* Used to represent a list of values and their respective symbolic names */

+ 0 - 1
drivers/usb/media/pwc/pwc-ctrl.c

@@ -41,7 +41,6 @@
 #include <asm/uaccess.h> 
 #include <asm/uaccess.h> 
 #endif
 #endif
 #include <asm/errno.h>
 #include <asm/errno.h>
-#include <linux/version.h>
  
  
 #include "pwc.h"
 #include "pwc.h"
 #include "pwc-ioctl.h"
 #include "pwc-ioctl.h"

+ 2 - 7
drivers/usb/media/pwc/pwc-if.c

@@ -62,7 +62,6 @@
 #include <linux/poll.h>
 #include <linux/poll.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/vmalloc.h>
-#include <linux/version.h>
 #include <asm/io.h>
 #include <asm/io.h>
 
 
 #include "pwc.h"
 #include "pwc.h"
@@ -827,13 +826,10 @@ static int pwc_isoc_init(struct pwc_device *pdev)
 	/* Get the current alternate interface, adjust packet size */
 	/* Get the current alternate interface, adjust packet size */
 	if (!udev->actconfig)
 	if (!udev->actconfig)
 		return -EFAULT;
 		return -EFAULT;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5)
-	idesc = &udev->actconfig->interface[0]->altsetting[pdev->valternate];
-#else
+
 	intf = usb_ifnum_to_if(udev, 0);
 	intf = usb_ifnum_to_if(udev, 0);
 	if (intf)
 	if (intf)
 		idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
 		idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
-#endif
 		
 		
 	if (!idesc)
 	if (!idesc)
 		return -EFAULT;
 		return -EFAULT;
@@ -1871,12 +1867,11 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
 		Info("Warning: more than 1 configuration available.\n");
 		Info("Warning: more than 1 configuration available.\n");
 
 
 	/* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
 	/* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
-	pdev = kmalloc(sizeof(struct pwc_device), GFP_KERNEL);
+	pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
 	if (pdev == NULL) {
 	if (pdev == NULL) {
 		Err("Oops, could not allocate memory for pwc_device.\n");
 		Err("Oops, could not allocate memory for pwc_device.\n");
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
-	memset(pdev, 0, sizeof(struct pwc_device));
 	pdev->type = type_id;
 	pdev->type = type_id;
 	pdev->vsize = default_size;
 	pdev->vsize = default_size;
 	pdev->vframes = default_fps;
 	pdev->vframes = default_fps;

+ 7 - 9
drivers/usb/media/se401.c

@@ -1157,21 +1157,21 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma)
 	unsigned long size  = vma->vm_end-vma->vm_start;
 	unsigned long size  = vma->vm_end-vma->vm_start;
 	unsigned long page, pos;
 	unsigned long page, pos;
 
 
-	down(&se401->lock);
+	mutex_lock(&se401->lock);
 
 
 	if (se401->dev == NULL) {
 	if (se401->dev == NULL) {
-		up(&se401->lock);
+		mutex_unlock(&se401->lock);
 		return -EIO;
 		return -EIO;
 	}
 	}
 	if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
 	if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
-		up(&se401->lock);
+		mutex_unlock(&se401->lock);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 	pos = (unsigned long)se401->fbuf;
 	pos = (unsigned long)se401->fbuf;
 	while (size > 0) {
 	while (size > 0) {
 		page = vmalloc_to_pfn((void *)pos);
 		page = vmalloc_to_pfn((void *)pos);
 		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
 		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-			up(&se401->lock);
+			mutex_unlock(&se401->lock);
 			return -EAGAIN;
 			return -EAGAIN;
 		}
 		}
 		start += PAGE_SIZE;
 		start += PAGE_SIZE;
@@ -1181,7 +1181,7 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma)
 		else
 		else
 			size = 0;
 			size = 0;
 	}
 	}
-	up(&se401->lock);
+	mutex_unlock(&se401->lock);
 
 
         return 0;
         return 0;
 }
 }
@@ -1345,13 +1345,11 @@ static int se401_probe(struct usb_interface *intf,
         /* We found one */
         /* We found one */
         info("SE401 camera found: %s", camera_name);
         info("SE401 camera found: %s", camera_name);
 
 
-        if ((se401 = kmalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
+        if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
                 err("couldn't kmalloc se401 struct");
                 err("couldn't kmalloc se401 struct");
 		return -ENOMEM;
 		return -ENOMEM;
         }
         }
 
 
-        memset(se401, 0, sizeof(*se401));
-
         se401->dev = dev;
         se401->dev = dev;
         se401->iface = interface->bInterfaceNumber;
         se401->iface = interface->bInterfaceNumber;
         se401->camera_name = camera_name;
         se401->camera_name = camera_name;
@@ -1366,7 +1364,7 @@ static int se401_probe(struct usb_interface *intf,
 	memcpy(&se401->vdev, &se401_template, sizeof(se401_template));
 	memcpy(&se401->vdev, &se401_template, sizeof(se401_template));
 	memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name));
 	memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name));
 	init_waitqueue_head(&se401->wq);
 	init_waitqueue_head(&se401->wq);
-	init_MUTEX(&se401->lock);
+	mutex_init(&se401->lock);
 	wmb();
 	wmb();
 
 
 	if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
 	if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {

+ 2 - 1
drivers/usb/media/se401.h

@@ -5,6 +5,7 @@
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 #include <linux/videodev.h>
 #include <linux/videodev.h>
 #include <linux/smp_lock.h>
 #include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 
 #define se401_DEBUG	/* Turn on debug messages */
 #define se401_DEBUG	/* Turn on debug messages */
 
 
@@ -189,7 +190,7 @@ struct usb_se401 {
 	int maxframesize;
 	int maxframesize;
 	int cframesize;		/* current framesize */
 	int cframesize;		/* current framesize */
 
 
-	struct semaphore lock;
+	struct mutex lock;
 	int user;		/* user count for exclusive use */
 	int user;		/* user count for exclusive use */
 	int removed;		/* device disconnected */
 	int removed;		/* device disconnected */
 
 

+ 21 - 7
drivers/usb/media/sn9c102.h

@@ -33,7 +33,9 @@
 #include <linux/types.h>
 #include <linux/types.h>
 #include <linux/param.h>
 #include <linux/param.h>
 #include <linux/rwsem.h>
 #include <linux/rwsem.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/stddef.h>
 
 
 #include "sn9c102_sensor.h"
 #include "sn9c102_sensor.h"
 
 
@@ -50,6 +52,7 @@
 #define SN9C102_ALTERNATE_SETTING 8
 #define SN9C102_ALTERNATE_SETTING 8
 #define SN9C102_URB_TIMEOUT       msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
 #define SN9C102_URB_TIMEOUT       msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
 #define SN9C102_CTRL_TIMEOUT      300
 #define SN9C102_CTRL_TIMEOUT      300
+#define SN9C102_FRAME_TIMEOUT     2
 
 
 /*****************************************************************************/
 /*****************************************************************************/
 
 
@@ -107,16 +110,17 @@ struct sn9c102_sysfs_attr {
 
 
 struct sn9c102_module_param {
 struct sn9c102_module_param {
 	u8 force_munmap;
 	u8 force_munmap;
+	u16 frame_timeout;
 };
 };
 
 
-static DECLARE_MUTEX(sn9c102_sysfs_lock);
+static DEFINE_MUTEX(sn9c102_sysfs_lock);
 static DECLARE_RWSEM(sn9c102_disconnect);
 static DECLARE_RWSEM(sn9c102_disconnect);
 
 
 struct sn9c102_device {
 struct sn9c102_device {
 	struct video_device* v4ldev;
 	struct video_device* v4ldev;
 
 
 	enum sn9c102_bridge bridge;
 	enum sn9c102_bridge bridge;
-	struct sn9c102_sensor* sensor;
+	struct sn9c102_sensor sensor;
 
 
 	struct usb_device* usbdev;
 	struct usb_device* usbdev;
 	struct urb* urb[SN9C102_URBS];
 	struct urb* urb[SN9C102_URBS];
@@ -141,19 +145,28 @@ struct sn9c102_device {
 	enum sn9c102_dev_state state;
 	enum sn9c102_dev_state state;
 	u8 users;
 	u8 users;
 
 
-	struct semaphore dev_sem, fileop_sem;
+	struct mutex dev_mutex, fileop_mutex;
 	spinlock_t queue_lock;
 	spinlock_t queue_lock;
 	wait_queue_head_t open, wait_frame, wait_stream;
 	wait_queue_head_t open, wait_frame, wait_stream;
 };
 };
 
 
 /*****************************************************************************/
 /*****************************************************************************/
 
 
+struct sn9c102_device*
+sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id)
+{
+	if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
+		return cam;
+
+	return NULL;
+}
+
+
 void
 void
 sn9c102_attach_sensor(struct sn9c102_device* cam,
 sn9c102_attach_sensor(struct sn9c102_device* cam,
                       struct sn9c102_sensor* sensor)
                       struct sn9c102_sensor* sensor)
 {
 {
-	cam->sensor = sensor;
-	cam->sensor->usbdev = cam->usbdev;
+	memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor));
 }
 }
 
 
 /*****************************************************************************/
 /*****************************************************************************/
@@ -196,7 +209,8 @@ do {                                                                          \
 
 
 #undef PDBG
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
+         __FUNCTION__, __LINE__ , ## args)
 
 
 #undef PDBGG
 #undef PDBGG
 #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
 #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */

文件差异内容过多而无法显示
+ 175 - 146
drivers/usb/media/sn9c102_core.c


+ 19 - 14
drivers/usb/media/sn9c102_ov7630.c

@@ -34,8 +34,8 @@ static int ov7630_init(struct sn9c102_device* cam)
 	err += sn9c102_write_reg(cam, 0x0f, 0x18);
 	err += sn9c102_write_reg(cam, 0x0f, 0x18);
 	err += sn9c102_write_reg(cam, 0x50, 0x19);
 	err += sn9c102_write_reg(cam, 0x50, 0x19);
 
 
-	err += sn9c102_i2c_write(cam, 0x12, 0x8d);
-	err += sn9c102_i2c_write(cam, 0x11, 0x00);
+	err += sn9c102_i2c_write(cam, 0x12, 0x80);
+	err += sn9c102_i2c_write(cam, 0x11, 0x01);
 	err += sn9c102_i2c_write(cam, 0x15, 0x34);
 	err += sn9c102_i2c_write(cam, 0x15, 0x34);
 	err += sn9c102_i2c_write(cam, 0x16, 0x03);
 	err += sn9c102_i2c_write(cam, 0x16, 0x03);
 	err += sn9c102_i2c_write(cam, 0x17, 0x1c);
 	err += sn9c102_i2c_write(cam, 0x17, 0x1c);
@@ -43,12 +43,14 @@ static int ov7630_init(struct sn9c102_device* cam)
 	err += sn9c102_i2c_write(cam, 0x19, 0x06);
 	err += sn9c102_i2c_write(cam, 0x19, 0x06);
 	err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
 	err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
 	err += sn9c102_i2c_write(cam, 0x1b, 0x04);
 	err += sn9c102_i2c_write(cam, 0x1b, 0x04);
-	err += sn9c102_i2c_write(cam, 0x20, 0x44);
+	err += sn9c102_i2c_write(cam, 0x20, 0xf6);
 	err += sn9c102_i2c_write(cam, 0x23, 0xee);
 	err += sn9c102_i2c_write(cam, 0x23, 0xee);
 	err += sn9c102_i2c_write(cam, 0x26, 0xa0);
 	err += sn9c102_i2c_write(cam, 0x26, 0xa0);
 	err += sn9c102_i2c_write(cam, 0x27, 0x9a);
 	err += sn9c102_i2c_write(cam, 0x27, 0x9a);
-	err += sn9c102_i2c_write(cam, 0x28, 0x20);
+	err += sn9c102_i2c_write(cam, 0x28, 0xa0);
 	err += sn9c102_i2c_write(cam, 0x29, 0x30);
 	err += sn9c102_i2c_write(cam, 0x29, 0x30);
+	err += sn9c102_i2c_write(cam, 0x2a, 0xa0);
+	err += sn9c102_i2c_write(cam, 0x2b, 0x1f);
 	err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
 	err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
 	err += sn9c102_i2c_write(cam, 0x30, 0x24);
 	err += sn9c102_i2c_write(cam, 0x30, 0x24);
 	err += sn9c102_i2c_write(cam, 0x32, 0x86);
 	err += sn9c102_i2c_write(cam, 0x32, 0x86);
@@ -80,7 +82,7 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
 		err += sn9c102_i2c_write(cam, 0x02, ctrl->value);
 		err += sn9c102_i2c_write(cam, 0x02, ctrl->value);
 		break;
 		break;
 	case V4L2_CID_BLUE_BALANCE:
 	case V4L2_CID_BLUE_BALANCE:
-		err += sn9c102_i2c_write(cam, 0x03, ctrl->value);
+		err += sn9c102_i2c_write(cam, 0x01, ctrl->value);
 		break;
 		break;
 	case V4L2_CID_GAIN:
 	case V4L2_CID_GAIN:
 		err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
 		err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
@@ -108,7 +110,7 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
 		err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
 		err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
 		break;
 		break;
 	case V4L2_CID_AUTO_WHITE_BALANCE:
 	case V4L2_CID_AUTO_WHITE_BALANCE:
-		err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x09);
+		err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x78);
 		break;
 		break;
 	case V4L2_CID_AUTOGAIN:
 	case V4L2_CID_AUTOGAIN:
 		err += sn9c102_i2c_write(cam, 0x13, ctrl->value);
 		err += sn9c102_i2c_write(cam, 0x13, ctrl->value);
@@ -371,26 +373,29 @@ static struct sn9c102_sensor ov7630 = {
 
 
 int sn9c102_probe_ov7630(struct sn9c102_device* cam)
 int sn9c102_probe_ov7630(struct sn9c102_device* cam)
 {
 {
+	const struct usb_device_id ov7630_id_table[] = {
+		{ USB_DEVICE(0x0c45, 0x602c), },
+		{ USB_DEVICE(0x0c45, 0x602d), },
+		{ USB_DEVICE(0x0c45, 0x608f), },
+		{ USB_DEVICE(0x0c45, 0x60b0), },
+		{ }
+	};
 	int err = 0;
 	int err = 0;
 
 
-	sn9c102_attach_sensor(cam, &ov7630);
-
-	if (le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602c &&
-	    le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602d &&
-	    le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x608f &&
-	    le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x60b0)
+	if (!sn9c102_match_id(cam, ov7630_id_table))
 		return -ENODEV;
 		return -ENODEV;
 
 
 	err += sn9c102_write_reg(cam, 0x01, 0x01);
 	err += sn9c102_write_reg(cam, 0x01, 0x01);
 	err += sn9c102_write_reg(cam, 0x00, 0x01);
 	err += sn9c102_write_reg(cam, 0x00, 0x01);
 	err += sn9c102_write_reg(cam, 0x28, 0x17);
 	err += sn9c102_write_reg(cam, 0x28, 0x17);
-
 	if (err)
 	if (err)
 		return -EIO;
 		return -EIO;
 
 
-	err += sn9c102_i2c_write(cam, 0x0b, 0);
+	err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0);
 	if (err)
 	if (err)
 		return -ENODEV;
 		return -ENODEV;
 
 
+	sn9c102_attach_sensor(cam, &ov7630);
+
 	return 0;
 	return 0;
 }
 }

+ 238 - 0
drivers/usb/media/sn9c102_pas202bca.c

@@ -0,0 +1,238 @@
+/***************************************************************************
+ * Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera   *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * 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 <linux/delay.h>
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor pas202bca;
+
+
+static int pas202bca_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, 0x30, 0x19);
+	err += sn9c102_write_reg(cam, 0x09, 0x18);
+
+	err += sn9c102_i2c_write(cam, 0x02, 0x14);
+	err += sn9c102_i2c_write(cam, 0x03, 0x40);
+	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, 0x10, 0x08);
+	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 pas202bca_set_pix_format(struct sn9c102_device* cam,
+                                    const struct v4l2_pix_format* pix)
+{
+	int err = 0;
+
+	if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+		err += sn9c102_write_reg(cam, 0x24, 0x17);
+	else
+		err += sn9c102_write_reg(cam, 0x20, 0x17);
+
+	return err;
+}
+
+
+static int pas202bca_set_ctrl(struct sn9c102_device* cam,
+                              const struct v4l2_control* ctrl)
+{
+	int err = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_EXPOSURE:
+		err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
+		err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
+		break;
+	case V4L2_CID_RED_BALANCE:
+		err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
+		break;
+	case V4L2_CID_BLUE_BALANCE:
+		err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
+		break;
+	case V4L2_CID_GAIN:
+		err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
+		break;
+	case SN9C102_V4L2_CID_GREEN_BALANCE:
+		err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
+		break;
+	case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+		err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
+		break;
+	default:
+		return -EINVAL;
+	}
+	err += sn9c102_i2c_write(cam, 0x11, 0x01);
+
+	return err ? -EIO : 0;
+}
+
+
+static int pas202bca_set_crop(struct sn9c102_device* cam,
+                              const struct v4l2_rect* rect)
+{
+	struct sn9c102_sensor* s = &pas202bca;
+	int err = 0;
+	u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3,
+	   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 pas202bca = {
+	.name = "PAS202BCA",
+	.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+	.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
+	.frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
+	.interface = SN9C102_I2C_2WIRES,
+	.i2c_slave_id = 0x40,
+	.init = &pas202bca_init,
+	.qctrl = {
+		{
+			.id = V4L2_CID_EXPOSURE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "exposure",
+			.minimum = 0x01e5,
+			.maximum = 0x3fff,
+			.step = 0x0001,
+			.default_value = 0x01e5,
+			.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_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 = SN9C102_V4L2_CID_GREEN_BALANCE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "green balance",
+			.minimum = 0x00,
+			.maximum = 0x0f,
+			.step = 0x01,
+			.default_value = 0x00,
+			.flags = 0,
+		},
+		{
+			.id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "DAC magnitude",
+			.minimum = 0x00,
+			.maximum = 0xff,
+			.step = 0x01,
+			.default_value = 0x04,
+			.flags = 0,
+		},
+	},
+	.set_ctrl = &pas202bca_set_ctrl,
+	.cropcap = {
+		.bounds = {
+			.left = 0,
+			.top = 0,
+			.width = 640,
+			.height = 480,
+		},
+		.defrect = {
+			.left = 0,
+			.top = 0,
+			.width = 640,
+			.height = 480,
+		},
+	},
+	.set_crop = &pas202bca_set_crop,
+	.pix_format = {
+		.width = 640,
+		.height = 480,
+		.pixelformat = V4L2_PIX_FMT_SBGGR8,
+		.priv = 8,
+	},
+	.set_pix_format = &pas202bca_set_pix_format
+};
+
+
+int sn9c102_probe_pas202bca(struct sn9c102_device* cam)
+{
+	const struct usb_device_id pas202bca_id_table[] = {
+		{ USB_DEVICE(0x0c45, 0x60af), },
+		{ }
+	};
+	int err = 0;
+
+	if (!sn9c102_match_id(cam,pas202bca_id_table))
+		return -ENODEV;
+
+	err += sn9c102_write_reg(cam, 0x01, 0x01);
+	err += sn9c102_write_reg(cam, 0x40, 0x01);
+	err += sn9c102_write_reg(cam, 0x28, 0x17);
+	if (err)
+		return -EIO;
+
+	if (sn9c102_i2c_try_write(cam, &pas202bca, 0x10, 0)) /* try to write */
+		return -ENODEV;
+
+	sn9c102_attach_sensor(cam, &pas202bca);
+
+	return 0;
+}

+ 1 - 1
drivers/usb/media/sn9c102_pas202bcb.c

@@ -263,7 +263,7 @@ static struct sn9c102_sensor pas202bcb = {
 
 
 
 
 int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
 int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
-{       
+{
 	int r0 = 0, r1 = 0, err = 0;
 	int r0 = 0, r1 = 0, err = 0;
 	unsigned int pid = 0;
 	unsigned int pid = 0;
 
 

+ 8 - 7
drivers/usb/media/sn9c102_sensor.h

@@ -66,6 +66,7 @@ extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
 extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
 extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
 extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
 extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
 extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
 extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
+extern int sn9c102_probe_pas202bca(struct sn9c102_device* cam);
 extern int sn9c102_probe_pas202bcb(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_tas5110c1b(struct sn9c102_device* cam);
 extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
 extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
@@ -81,12 +82,17 @@ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {              \
 	&sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */    \
 	&sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */    \
 	&sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */  \
 	&sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */  \
 	&sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */    \
 	&sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */    \
+	&sn9c102_probe_pas202bca, /* detection mostly based on USB pid/vid */ \
 	&sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */    \
 	&sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */    \
 	&sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */       \
 	&sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */       \
 	&sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */       \
 	&sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */       \
 	NULL,                                                                 \
 	NULL,                                                                 \
 };
 };
 
 
+/* Device identification */
+extern struct sn9c102_device*
+sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id);
+
 /* Attach a probed sensor to the camera. */
 /* Attach a probed sensor to the camera. */
 extern void 
 extern void 
 sn9c102_attach_sensor(struct sn9c102_device* cam,
 sn9c102_attach_sensor(struct sn9c102_device* cam,
@@ -108,6 +114,7 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
 static const struct usb_device_id sn9c102_id_table[] = {                      \
 static const struct usb_device_id sn9c102_id_table[] = {                      \
 	{ USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */                     \
 	{ USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */                     \
 	{ USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */                     \
 	{ USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */                     \
+	{ USB_DEVICE(0x0c45, 0x6007), },                                      \
 	{ USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */                        \
 	{ USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */                        \
 	{ USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */                        \
 	{ USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */                        \
 	{ USB_DEVICE(0x0c45, 0x6024), },                                      \
 	{ USB_DEVICE(0x0c45, 0x6024), },                                      \
@@ -126,7 +133,7 @@ static const struct usb_device_id sn9c102_id_table[] = {                      \
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), },                        \
 	{ SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), },                        \
 	{ SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), },                        \
 	{ SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), },                        \
 	{ SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), },                        \
 	{ SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), },                        \
-	{ SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131x */          \
+	{ SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131/R */         \
 	{ SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */         \
 	{ SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */         \
 	{ SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */           \
 	{ SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */           \
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), },                        \
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), },                        \
@@ -359,12 +366,6 @@ struct sn9c102_sensor {
 	   error code without rolling back.
 	   error code without rolling back.
 	*/
 	*/
 
 
-	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.
-	*/
-
 	/*
 	/*
 	   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
 	   core module to store successfully updated values of the above

+ 9 - 5
drivers/usb/media/sn9c102_tas5110c1b.c

@@ -142,14 +142,18 @@ static struct sn9c102_sensor tas5110c1b = {
 
 
 int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
 int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
 {
 {
-	/* This sensor has no identifiers, so let's attach it anyway */
-	sn9c102_attach_sensor(cam, &tas5110c1b);
+	const struct usb_device_id tas5110c1b_id_table[] = {
+		{ USB_DEVICE(0x0c45, 0x6001), },
+		{ USB_DEVICE(0x0c45, 0x6005), },
+		{ USB_DEVICE(0x0c45, 0x60ab), },
+		{ }
+	};
 
 
 	/* Sensor detection is based on USB pid/vid */
 	/* Sensor detection is based on USB pid/vid */
-	if (le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x6001 &&
-	    le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x6005 &&
-	    le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x60ab)
+	if (!sn9c102_match_id(cam, tas5110c1b_id_table))
 		return -ENODEV;
 		return -ENODEV;
 
 
+	sn9c102_attach_sensor(cam, &tas5110c1b);
+
 	return 0;
 	return 0;
 }
 }

+ 8 - 4
drivers/usb/media/sn9c102_tas5130d1b.c

@@ -153,13 +153,17 @@ static struct sn9c102_sensor tas5130d1b = {
 
 
 int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
 int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
 {
 {
-	/* This sensor has no identifiers, so let's attach it anyway */
-	sn9c102_attach_sensor(cam, &tas5130d1b);
+	const struct usb_device_id tas5130d1b_id_table[] = {
+		{ USB_DEVICE(0x0c45, 0x6025), },
+		{ USB_DEVICE(0x0c45, 0x60aa), },
+		{ }
+	};
 
 
 	/* Sensor detection is based on USB pid/vid */
 	/* Sensor detection is based on USB pid/vid */
-	if (le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x6025 &&
-	    le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x60aa)
+	if (!sn9c102_match_id(cam, tas5130d1b_id_table))
 		return -ENODEV;
 		return -ENODEV;
 
 
+	sn9c102_attach_sensor(cam, &tas5130d1b);
+
 	return 0;
 	return 0;
 }
 }

+ 9 - 11
drivers/usb/media/stv680.c

@@ -67,6 +67,7 @@
 #include <linux/errno.h>
 #include <linux/errno.h>
 #include <linux/videodev.h>
 #include <linux/videodev.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 
 
 #include "stv680.h"
 #include "stv680.h"
 
 
@@ -317,12 +318,11 @@ static int stv_init (struct usb_stv *stv680)
 	unsigned char *buffer;
 	unsigned char *buffer;
 	unsigned long int bufsize;
 	unsigned long int bufsize;
 
 
-	buffer = kmalloc (40, GFP_KERNEL);
+	buffer = kzalloc (40, GFP_KERNEL);
 	if (buffer == NULL) {
 	if (buffer == NULL) {
 		PDEBUG (0, "STV(e): Out of (small buf) memory");
 		PDEBUG (0, "STV(e): Out of (small buf) memory");
 		return -1;
 		return -1;
 	}
 	}
-	memset (buffer, 0, 40);
 	udelay (100);
 	udelay (100);
 
 
 	/* set config 1, interface 0, alternate 0 */
 	/* set config 1, interface 0, alternate 0 */
@@ -1258,22 +1258,22 @@ static int stv680_mmap (struct file *file, struct vm_area_struct *vma)
 	unsigned long size  = vma->vm_end-vma->vm_start;
 	unsigned long size  = vma->vm_end-vma->vm_start;
 	unsigned long page, pos;
 	unsigned long page, pos;
 
 
-	down (&stv680->lock);
+	mutex_lock(&stv680->lock);
 
 
 	if (stv680->udev == NULL) {
 	if (stv680->udev == NULL) {
-		up (&stv680->lock);
+		mutex_unlock(&stv680->lock);
 		return -EIO;
 		return -EIO;
 	}
 	}
 	if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1)
 	if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1)
 		    & ~(PAGE_SIZE - 1))) {
 		    & ~(PAGE_SIZE - 1))) {
-		up (&stv680->lock);
+		mutex_unlock(&stv680->lock);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 	pos = (unsigned long) stv680->fbuf;
 	pos = (unsigned long) stv680->fbuf;
 	while (size > 0) {
 	while (size > 0) {
 		page = vmalloc_to_pfn((void *)pos);
 		page = vmalloc_to_pfn((void *)pos);
 		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
 		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-			up (&stv680->lock);
+			mutex_unlock(&stv680->lock);
 			return -EAGAIN;
 			return -EAGAIN;
 		}
 		}
 		start += PAGE_SIZE;
 		start += PAGE_SIZE;
@@ -1283,7 +1283,7 @@ static int stv680_mmap (struct file *file, struct vm_area_struct *vma)
 		else
 		else
 			size = 0;
 			size = 0;
 	}
 	}
-	up (&stv680->lock);
+	mutex_unlock(&stv680->lock);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1387,14 +1387,12 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id
 		goto error;
 		goto error;
 	}
 	}
 	/* We found one */
 	/* We found one */
-	if ((stv680 = kmalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) {
+	if ((stv680 = kzalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) {
 		PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct.");
 		PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct.");
 		retval = -ENOMEM;
 		retval = -ENOMEM;
 		goto error;
 		goto error;
 	}
 	}
 
 
-	memset (stv680, 0, sizeof (*stv680));
-
 	stv680->udev = dev;
 	stv680->udev = dev;
 	stv680->camera_name = camera_name;
 	stv680->camera_name = camera_name;
 
 
@@ -1409,7 +1407,7 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id
 
 
 	memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name));
 	memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name));
 	init_waitqueue_head (&stv680->wq);
 	init_waitqueue_head (&stv680->wq);
-	init_MUTEX (&stv680->lock);
+	mutex_init (&stv680->lock);
 	wmb ();
 	wmb ();
 
 
 	if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
 	if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {

+ 1 - 1
drivers/usb/media/stv680.h

@@ -118,7 +118,7 @@ struct usb_stv {
 	int origGain;
 	int origGain;
 	int origMode;		/* original camera mode */
 	int origMode;		/* original camera mode */
 
 
-	struct semaphore lock;	/* to lock the structure */
+	struct mutex lock;	/* to lock the structure */
 	int user;		/* user count for exclusive use */
 	int user;		/* user count for exclusive use */
 	int removed;		/* device disconnected */
 	int removed;		/* device disconnected */
 	int streaming;		/* Are we streaming video? */
 	int streaming;		/* Are we streaming video? */

+ 15 - 16
drivers/usb/media/usbvideo.c

@@ -690,14 +690,13 @@ int usbvideo_register(
 	}
 	}
 
 
 	base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo);
 	base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo);
-	cams = (struct usbvideo *) kmalloc(base_size, GFP_KERNEL);
+	cams = (struct usbvideo *) kzalloc(base_size, GFP_KERNEL);
 	if (cams == NULL) {
 	if (cams == NULL) {
 		err("Failed to allocate %d. bytes for usbvideo struct", base_size);
 		err("Failed to allocate %d. bytes for usbvideo struct", base_size);
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 	dbg("%s: Allocated $%p (%d. bytes) for %d. cameras",
 	dbg("%s: Allocated $%p (%d. bytes) for %d. cameras",
 	    __FUNCTION__, cams, base_size, num_cams);
 	    __FUNCTION__, cams, base_size, num_cams);
-	memset(cams, 0, base_size);
 
 
 	/* Copy callbacks, apply defaults for those that are not set */
 	/* Copy callbacks, apply defaults for those that are not set */
 	memmove(&cams->cb, cbTbl, sizeof(cams->cb));
 	memmove(&cams->cb, cbTbl, sizeof(cams->cb));
@@ -715,7 +714,7 @@ int usbvideo_register(
 	cams->md_module = md;
 	cams->md_module = md;
 	if (cams->md_module == NULL)
 	if (cams->md_module == NULL)
 		warn("%s: module == NULL!", __FUNCTION__);
 		warn("%s: module == NULL!", __FUNCTION__);
-	init_MUTEX(&cams->lock);	/* to 1 == available */
+	mutex_init(&cams->lock);	/* to 1 == available */
 
 
 	for (i = 0; i < num_cams; i++) {
 	for (i = 0; i < num_cams; i++) {
 		struct uvd *up = &cams->cam[i];
 		struct uvd *up = &cams->cam[i];
@@ -863,7 +862,7 @@ static void usbvideo_Disconnect(struct usb_interface *intf)
 	if (uvd->debug > 0)
 	if (uvd->debug > 0)
 		info("%s(%p.)", __FUNCTION__, intf);
 		info("%s(%p.)", __FUNCTION__, intf);
 
 
-	down(&uvd->lock);
+	mutex_lock(&uvd->lock);
 	uvd->remove_pending = 1; /* Now all ISO data will be ignored */
 	uvd->remove_pending = 1; /* Now all ISO data will be ignored */
 
 
 	/* At this time we ask to cancel outstanding URBs */
 	/* At this time we ask to cancel outstanding URBs */
@@ -883,7 +882,7 @@ static void usbvideo_Disconnect(struct usb_interface *intf)
 		info("%s: In use, disconnect pending.", __FUNCTION__);
 		info("%s: In use, disconnect pending.", __FUNCTION__);
 	else
 	else
 		usbvideo_CameraRelease(uvd);
 		usbvideo_CameraRelease(uvd);
-	up(&uvd->lock);
+	mutex_unlock(&uvd->lock);
 	info("USB camera disconnected.");
 	info("USB camera disconnected.");
 
 
 	usbvideo_ClientDecModCount(uvd);
 	usbvideo_ClientDecModCount(uvd);
@@ -930,19 +929,19 @@ static int usbvideo_find_struct(struct usbvideo *cams)
 		err("No usbvideo handle?");
 		err("No usbvideo handle?");
 		return -1;
 		return -1;
 	}
 	}
-	down(&cams->lock);
+	mutex_lock(&cams->lock);
 	for (u = 0; u < cams->num_cameras; u++) {
 	for (u = 0; u < cams->num_cameras; u++) {
 		struct uvd *uvd = &cams->cam[u];
 		struct uvd *uvd = &cams->cam[u];
 		if (!uvd->uvd_used) /* This one is free */
 		if (!uvd->uvd_used) /* This one is free */
 		{
 		{
 			uvd->uvd_used = 1;	/* In use now */
 			uvd->uvd_used = 1;	/* In use now */
-			init_MUTEX(&uvd->lock);	/* to 1 == available */
+			mutex_init(&uvd->lock);	/* to 1 == available */
 			uvd->dev = NULL;
 			uvd->dev = NULL;
 			rv = u;
 			rv = u;
 			break;
 			break;
 		}
 		}
 	}
 	}
-	up(&cams->lock);
+	mutex_unlock(&cams->lock);
 	return rv;
 	return rv;
 }
 }
 
 
@@ -984,7 +983,7 @@ struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams)
 	/* Not relying upon caller we increase module counter ourselves */
 	/* Not relying upon caller we increase module counter ourselves */
 	usbvideo_ClientIncModCount(uvd);
 	usbvideo_ClientIncModCount(uvd);
 
 
-	down(&uvd->lock);
+	mutex_lock(&uvd->lock);
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
 		uvd->sbuf[i].urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
 		uvd->sbuf[i].urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
 		if (uvd->sbuf[i].urb == NULL) {
 		if (uvd->sbuf[i].urb == NULL) {
@@ -1007,7 +1006,7 @@ struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams)
 	 * return control to the client's probe function right now.
 	 * return control to the client's probe function right now.
 	 */
 	 */
 allocate_done:
 allocate_done:
-	up (&uvd->lock);
+	mutex_unlock(&uvd->lock);
 	usbvideo_ClientDecModCount(uvd);
 	usbvideo_ClientDecModCount(uvd);
 	return uvd;
 	return uvd;
 }
 }
@@ -1121,7 +1120,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
 		info("%s($%p)", __FUNCTION__, dev);
 		info("%s($%p)", __FUNCTION__, dev);
 
 
 	usbvideo_ClientIncModCount(uvd);
 	usbvideo_ClientIncModCount(uvd);
-	down(&uvd->lock);
+	mutex_lock(&uvd->lock);
 
 
 	if (uvd->user) {
 	if (uvd->user) {
 		err("%s: Someone tried to open an already opened device!", __FUNCTION__);
 		err("%s: Someone tried to open an already opened device!", __FUNCTION__);
@@ -1202,7 +1201,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
 			}
 			}
 		}
 		}
 	}
 	}
-	up(&uvd->lock);
+	mutex_unlock(&uvd->lock);
 	if (errCode != 0)
 	if (errCode != 0)
 		usbvideo_ClientDecModCount(uvd);
 		usbvideo_ClientDecModCount(uvd);
 	if (uvd->debug > 0)
 	if (uvd->debug > 0)
@@ -1231,7 +1230,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file)
 	if (uvd->debug > 1)
 	if (uvd->debug > 1)
 		info("%s($%p)", __FUNCTION__, dev);
 		info("%s($%p)", __FUNCTION__, dev);
 
 
-	down(&uvd->lock);
+	mutex_lock(&uvd->lock);
 	GET_CALLBACK(uvd, stopDataPump)(uvd);
 	GET_CALLBACK(uvd, stopDataPump)(uvd);
 	usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
 	usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
 	uvd->fbuf = NULL;
 	uvd->fbuf = NULL;
@@ -1252,7 +1251,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file)
 			info("usbvideo_v4l_close: Final disconnect.");
 			info("usbvideo_v4l_close: Final disconnect.");
 		usbvideo_CameraRelease(uvd);
 		usbvideo_CameraRelease(uvd);
 	}
 	}
-	up(&uvd->lock);
+	mutex_unlock(&uvd->lock);
 	usbvideo_ClientDecModCount(uvd);
 	usbvideo_ClientDecModCount(uvd);
 
 
 	if (uvd->debug > 1)
 	if (uvd->debug > 1)
@@ -1512,7 +1511,7 @@ static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
 	if (uvd->debug >= 1)
 	if (uvd->debug >= 1)
 		info("%s: %Zd. bytes, noblock=%d.", __FUNCTION__, count, noblock);
 		info("%s: %Zd. bytes, noblock=%d.", __FUNCTION__, count, noblock);
 
 
-	down(&uvd->lock);	
+	mutex_lock(&uvd->lock);
 
 
 	/* See if a frame is completed, then use it. */
 	/* See if a frame is completed, then use it. */
 	for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
 	for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
@@ -1644,7 +1643,7 @@ static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
 		}
 		}
 	}
 	}
 read_done:
 read_done:
-	up(&uvd->lock);	
+	mutex_unlock(&uvd->lock);
 	return count;
 	return count;
 }
 }
 
 

部分文件因为文件数量过多而无法显示