Просмотр исходного кода

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 лет назад
Родитель
Сommit
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
 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 ET61X151 and ET61X251 PC Camera Controllers
+D: V4L2 driver for ZC0301 Image Processor and Control Chip
 S: Via Liberta' 41/A
 S: Osio Sotto, 24046, Bergamo
 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)
 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>
@@ -266,7 +274,7 @@ the V4L2 interface.
 
 
 10. Notes for V4L2 application developers
-========================================
+=========================================
 This driver follows the V4L2 API specifications. In particular, it enforces two
 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)
 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> 
@@ -321,6 +329,7 @@ Vendor ID  Product ID
 ---------  ----------
 0x0c45     0x6001
 0x0c45     0x6005
+0x0c45     0x6007
 0x0c45     0x6009
 0x0c45     0x600d
 0x0c45     0x6024
@@ -370,6 +379,7 @@ HV7131D     Hynix Semiconductor, Inc.
 MI-0343     Micron Technology, Inc.
 OV7630      OmniVision Technologies, Inc.
 PAS106B     PixArt Imaging, Inc.
+PAS202BCA   PixArt Imaging, Inc.
 PAS202BCB   PixArt Imaging, Inc.
 TAS5110C1B  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):
 
 - 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
   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
 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
 P:	Jeroen Vreeken
 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, 0x03030200, "Au1550 AA", 0, 1 },
     { 0xffffffff, 0x04030200, "Au1200 AB", 0, 0 },
-    { 0xffffffff, 0x04030201, "Au1200 AC", 0, 1 },
+    { 0xffffffff, 0x04030201, "Au1200 AC", 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[] = {
 	[0] = {
 		.start		= USB_OHCI_BASE,
-		.end		= USB_OHCI_BASE + USB_OHCI_LEN,
+		.end		= USB_OHCI_BASE + USB_OHCI_LEN - 1,
 		.flags		= IORESOURCE_MEM,
 	},
 	[1] = {
@@ -278,9 +278,7 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = {
 	&au1100_lcd_device,
 #endif
 #ifdef CONFIG_SOC_AU1200
-#if 0	/* fixme */
 	&au1xxx_usb_ehci_device,
-#endif
 	&au1xxx_usb_gdt_device,
 	&au1xxx_usb_otg_device,
 	&au1200_lcd_device,

+ 9 - 236
drivers/block/ub.c

@@ -8,7 +8,6 @@
  * and is not licensed separately. See file COPYING for details.
  *
  * 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
  *  -- 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
@@ -181,6 +180,7 @@ struct ub_dev;
 #define UB_DIR_ILLEGAL2	2
 #define UB_DIR_WRITE	3
 
+/* P3 */
 #define UB_DIR_CHAR(c)  (((c)==UB_DIR_WRITE)? 'w': \
 			 (((c)==UB_DIR_READ)? 'r': 'n'))
 
@@ -196,24 +196,11 @@ enum ub_scsi_cmd_state {
 	UB_CMDST_DONE			/* Final state */
 };
 
-static char *ub_scsi_cmd_stname[] = {
-	".  ",
-	"Cmd",
-	"dat",
-	"c2s",
-	"sts",
-	"clr",
-	"crs",
-	"Sen",
-	"fin"
-};
-
 struct ub_scsi_cmd {
 	unsigned char cdb[UB_MAX_CDB_SIZE];
 	unsigned char cdb_len;
 
 	unsigned char dir;		/* 0 - none, 1 - read, 3 - write. */
-	unsigned char trace_index;
 	enum ub_scsi_cmd_state state;
 	unsigned int tag;
 	struct ub_scsi_cmd *next;
@@ -249,28 +236,6 @@ struct ub_capacity {
 	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
  * 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 removable;
 	int readonly;
-	int first_open;			/* Kludge. See ub_bd_open. */
 
 	struct ub_request urq;
 
@@ -390,7 +354,6 @@ struct ub_dev {
 	wait_queue_head_t reset_wait;
 
 	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 */
 
-/*
- * 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.
  *
@@ -1092,7 +924,6 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 	add_timer(&sc->work_timer);
 
 	cmd->state = UB_CMDST_CMD;
-	ub_cmdtr_state(sc, cmd);
 	return 0;
 }
 
@@ -1145,12 +976,10 @@ static void ub_scsi_dispatch(struct ub_dev *sc)
 			ub_cmdq_pop(sc);
 			(*cmd->done)(sc, cmd);
 		} else if (cmd->state == UB_CMDST_INIT) {
-			ub_cmdtr_new(sc, cmd);
 			if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0)
 				break;
 			cmd->error = rc;
 			cmd->state = UB_CMDST_DONE;
-			ub_cmdtr_state(sc, cmd);
 		} else {
 			if (!ub_is_completed(&sc->work_done))
 				break;
@@ -1247,7 +1076,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 				return;
 			}
 			cmd->state = UB_CMDST_CLEAR;
-			ub_cmdtr_state(sc, cmd);
 			return;
 		case -ESHUTDOWN:	/* unplug */
 		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;
 			}
 			cmd->state = UB_CMDST_CLR2STS;
-			ub_cmdtr_state(sc, cmd);
 			return;
 		}
 		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 ||
 			    len != cmd->sgv[cmd->current_sg].length) {
 				cmd->act_len += len;
-				ub_cmdtr_act_len(sc, cmd);
 
 				cmd->error = -EIO;
 				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;
-		ub_cmdtr_act_len(sc, cmd);
 
 		if (++cmd->current_sg < cmd->nsg) {
 			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->state = UB_CMDST_CLRRS;
-			ub_cmdtr_state(sc, cmd);
 			return;
 		}
 
@@ -1441,7 +1265,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 			return;
 		}
 		cmd->state = UB_CMDST_DONE;
-		ub_cmdtr_state(sc, cmd);
 		ub_cmdq_pop(sc);
 		(*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);
 
 	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->state = UB_CMDST_DONE;
-	ub_cmdtr_state(sc, cmd);
 	ub_cmdq_pop(sc);
 	(*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->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;
 
 	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++;
 
 	cmd->state = UB_CMDST_SENSE;
-	ub_cmdtr_state(sc, cmd);
 
 	ub_cmdq_insert(sc, scmd);
 	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;
 	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,
 	 * 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;
 	}
 
+	/*
+	 * Ignoring scmd->act_len, because the buffer was pre-zeroed.
+	 */
 	cmd->key = sense[2] & 0x0F;
 	cmd->asc = sense[12];
 	cmd->ascq = sense[13];
@@ -1849,26 +1665,6 @@ static int ub_bd_open(struct inode *inode, struct file *filp)
 	sc->openc++;
 	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)
 		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);
 
 	rc = -ENOMEM;
-	if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
+	if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
 		goto err_alloc;
-	memset(cmd, 0, ALLOC_SIZE);
 
 	cmd->cdb[0] = TEST_UNIT_READY;
 	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);
 
 	rc = -ENOMEM;
-	if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
+	if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
 		goto err_alloc;
-	memset(cmd, 0, ALLOC_SIZE);
 	p = (char *)cmd + sizeof(struct ub_scsi_cmd);
 
 	cmd->cdb[0] = 0x25;
@@ -2405,9 +2199,8 @@ static int ub_probe(struct usb_interface *intf,
 		return -ENXIO;
 
 	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;
-	memset(sc, 0, sizeof(struct ub_dev));
 	sc->lock = ub_next_lock();
 	INIT_LIST_HEAD(&sc->luns);
 	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)
 		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.
 	 * We really hate halfway initialized structures, so from the
@@ -2480,19 +2270,8 @@ static int ub_probe(struct usb_interface *intf,
 
 	nluns = 1;
 	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;
-		}
 		if (rc != 0) {
 			nluns = rc;
 			break;
@@ -2505,8 +2284,6 @@ static int ub_probe(struct usb_interface *intf,
 	}
 	return 0;
 
-	/* device_remove_file(&sc->intf->dev, &dev_attr_diag); */
-err_diag:
 err_dev_desc:
 	usb_set_intfdata(intf, NULL);
 	// usb_put_intf(sc->intf);
@@ -2524,9 +2301,8 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
 	int rc;
 
 	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;
-	memset(lun, 0, sizeof(struct ub_lun));
 	lun->num = lnum;
 
 	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->changed = 1;		/* ub_revalidate clears only */
-	lun->first_open = 1;
 	ub_revalidate(sc, lun);
 
 	rc = -ENOMEM;
@@ -2636,7 +2411,6 @@ static void ub_disconnect(struct usb_interface *intf)
 		while ((cmd = ub_cmdq_peek(sc)) != NULL) {
 			cmd->error = -ENOTCONN;
 			cmd->state = UB_CMDST_DONE;
-			ub_cmdtr_state(sc, cmd);
 			ub_cmdq_pop(sc);
 			(*cmd->done)(sc, cmd);
 			cnt++;
@@ -2687,7 +2461,6 @@ static void ub_disconnect(struct usb_interface *intf)
 	 * and no URBs left in transit.
 	 */
 
-	device_remove_file(&sc->intf->dev, &dev_attr_diag);
 	usb_set_intfdata(intf, NULL);
 	// usb_put_intf(sc->intf);
 	sc->intf = NULL;

+ 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 *dataskb;
 	struct urb *next_urb;
-	int		docopy;
+	unsigned int len, docopy;
 
 	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->mac.raw  = dataskb->data;
 	dataskb->protocol = htons(ETH_P_IRDA);
+	len = dataskb->len;
 	netif_rx(dataskb);
 
 	/* Keep stats up to date */
-	self->stats.rx_bytes += dataskb->len;
+	self->stats.rx_bytes += len;
 	self->stats.rx_packets++;
 	self->netdev->last_rx = jiffies;
 

+ 9 - 0
drivers/usb/Kconfig

@@ -10,6 +10,7 @@ menu "USB support"
 config USB_ARCH_HAS_HCD
 	boolean
 	default y if USB_ARCH_HAS_OHCI
+	default y if USB_ARCH_HAS_EHCI
 	default y if ARM				# SL-811
 	default PCI
 
@@ -22,6 +23,7 @@ config USB_ARCH_HAS_OHCI
 	default y if ARCH_LH7A404
 	default y if ARCH_S3C2410
 	default y if PXA27x
+	default y if ARCH_AT91RM9200
 	# PPC:
 	default y if STB03xxx
 	default y if PPC_MPC52xx
@@ -30,6 +32,13 @@ config USB_ARCH_HAS_OHCI
 	# more:
 	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.
 config 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_SL811_HCD)	+= host/
 obj-$(CONFIG_ETRAX_USB_HOST)	+= host/
+obj-$(CONFIG_USB_OHCI_AT91)	+= host/
 
 obj-$(CONFIG_USB_ACM)		+= class/
-obj-$(CONFIG_USB_AUDIO)		+= class/
-obj-$(CONFIG_USB_MIDI)		+= class/
 obj-$(CONFIG_USB_PRINTER)	+= class/
 
 obj-$(CONFIG_USB_STORAGE)	+= storage/
@@ -48,6 +47,7 @@ obj-$(CONFIG_USB_SN9C102)	+= media/
 obj-$(CONFIG_USB_STV680)	+= media/
 obj-$(CONFIG_USB_VICAM)		+= media/
 obj-$(CONFIG_USB_W9968CF)	+= media/
+obj-$(CONFIG_USB_ZC0301)	+= media/
 
 obj-$(CONFIG_USB_CATC)		+= net/
 obj-$(CONFIG_USB_KAWETH)	+= net/

+ 0 - 47
drivers/usb/class/Kconfig

@@ -4,53 +4,6 @@
 comment "USB Device Class drivers"
 	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
 	tristate "USB Modem (CDC ACM) support"
 	depends on USB

+ 0 - 2
drivers/usb/class/Makefile

@@ -4,6 +4,4 @@
 #
 
 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

+ 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/module.h>
 #include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <linux/usb.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 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)
 
@@ -431,8 +432,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
 	int rv = -EINVAL;
 	int i;
 	dbg("Entering acm_tty_open.\n");
-	
-	down(&open_sem);
+
+	mutex_lock(&open_mutex);
 
 	acm = acm_table[tty->index];
 	if (!acm || !acm->dev)
@@ -474,14 +475,14 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
 
 done:
 err_out:
-	up(&open_sem);
+	mutex_unlock(&open_mutex);
 	return rv;
 
 full_bailout:
 	usb_kill_urb(acm->ctrlurb);
 bail_out:
 	acm->used--;
-	up(&open_sem);
+	mutex_unlock(&open_mutex);
 	return -EIO;
 }
 
@@ -507,7 +508,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
 	if (!acm || !acm->used)
 		return;
 
-	down(&open_sem);
+	mutex_lock(&open_mutex);
 	if (!--acm->used) {
 		if (acm->dev) {
 			acm_set_control(acm, acm->ctrlout = 0);
@@ -518,7 +519,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
 		} else
 			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)
@@ -1013,9 +1014,9 @@ static void acm_disconnect(struct usb_interface *intf)
 		return;
 	}
 
-	down(&open_sem);
+	mutex_lock(&open_mutex);
 	if (!usb_get_intfdata(intf)) {
-		up(&open_sem);
+		mutex_unlock(&open_mutex);
 		return;
 	}
 	acm->dev = NULL;
@@ -1045,11 +1046,11 @@ static void acm_disconnect(struct usb_interface *intf)
 
 	if (!acm->used) {
 		acm_tty_unregister(acm);
-		up(&open_sem);
+		mutex_unlock(&open_mutex);
 		return;
 	}
 
-	up(&open_sem);
+	mutex_unlock(&open_mutex);
 
 	if (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/slab.h>
 #include <linux/lp.h>
+#include <linux/mutex.h>
 #undef DEBUG
 #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 */
 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.
@@ -351,7 +352,7 @@ static int usblp_open(struct inode *inode, struct file *file)
 	if (minor < 0)
 		return -ENODEV;
 
-	down (&usblp_sem);
+	mutex_lock (&usblp_mutex);
 
 	retval = -ENODEV;
 	intf = usb_find_interface(&usblp_driver, minor);
@@ -399,7 +400,7 @@ static int usblp_open(struct inode *inode, struct file *file)
 		}
 	}
 out:
-	up (&usblp_sem);
+	mutex_unlock (&usblp_mutex);
 	return retval;
 }
 
@@ -425,13 +426,13 @@ static int usblp_release(struct inode *inode, struct file *file)
 {
 	struct usblp *usblp = file->private_data;
 
-	down (&usblp_sem);
+	mutex_lock (&usblp_mutex);
 	usblp->used = 0;
 	if (usblp->present) {
 		usblp_unlink_urbs(usblp);
 	} else 		/* finish cleanup from disconnect */
 		usblp_cleanup (usblp);
-	up (&usblp_sem);
+	mutex_unlock (&usblp_mutex);
 	return 0;
 }
 
@@ -1152,7 +1153,7 @@ static void usblp_disconnect(struct usb_interface *intf)
 
 	device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
 
-	down (&usblp_sem);
+	mutex_lock (&usblp_mutex);
 	down (&usblp->sem);
 	usblp->present = 0;
 	usb_set_intfdata (intf, NULL);
@@ -1166,7 +1167,7 @@ static void usblp_disconnect(struct usb_interface *intf)
 
 	if (!usblp->used)
 		usblp_cleanup (usblp);
-	up (&usblp_sem);
+	mutex_unlock (&usblp_mutex);
 }
 
 static struct usb_device_id usblp_ids [] = {

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

@@ -57,6 +57,7 @@
 #include <linux/usb.h>
 #include <linux/smp_lock.h>
 #include <linux/usbdevice_fs.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.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))
 		return -EFAULT;
 
-	down (&usb_bus_list_lock);
+	mutex_lock(&usb_bus_list_lock);
 	/* print devices for all busses */
 	list_for_each_entry(bus, &usb_bus_list, bus_list) {
 		/* 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);
 		usb_unlock_device(bus->root_hub);
 		if (ret < 0) {
-			up(&usb_bus_list_lock);
+			mutex_unlock(&usb_bus_list_lock);
 			return ret;
 		}
 		total_written += ret;
 	}
-	up (&usb_bus_list_lock);
+	mutex_unlock(&usb_bus_list_lock);
 	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)) {
-		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;
 		if (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;
 			goto err;
 		}
-		kfree(desc);
 
 		*ppos += len;
 		buf += len;
@@ -498,7 +493,8 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
 {
 	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;
 	if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
 		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);
 		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
 			 * reject requests the hardware can't implement, rather
 			 * 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 {
 			dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n",
 					retval);

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

@@ -34,6 +34,7 @@
 #include <asm/scatterlist.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
+#include <linux/mutex.h>
 #include <asm/irq.h>
 #include <asm/byteorder.h>
 
@@ -93,7 +94,7 @@ struct usb_busmap {
 static struct usb_busmap busmap;
 
 /* 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);
 
 /* 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 */
 
+	/* 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:
-		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);
 		tbuf [1] = 0;
 		len = 2;
 		break;
 	case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
 		if (wValue == USB_DEVICE_REMOTE_WAKEUP)
-			hcd->remote_wakeup = 0;
+			device_set_wakeup_enable(&hcd->self.root_hub->dev, 0);
 		else
 			goto error;
 		break;
 	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
 			goto error;
 		break;
@@ -409,7 +428,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
 				bufp = 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;
 			break;
 		case USB_DT_STRING << 8:
@@ -761,14 +780,14 @@ static int usb_register_bus(struct usb_bus *bus)
 {
 	int busnum;
 
-	down (&usb_bus_list_lock);
+	mutex_lock(&usb_bus_list_lock);
 	busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
 	if (busnum < USB_MAXBUS) {
 		set_bit (busnum, busmap.busmap);
 		bus->busnum = busnum;
 	} else {
 		printk (KERN_ERR "%s: too many buses\n", usbcore_name);
-		up(&usb_bus_list_lock);
+		mutex_unlock(&usb_bus_list_lock);
 		return -E2BIG;
 	}
 
@@ -776,7 +795,7 @@ static int usb_register_bus(struct usb_bus *bus)
 					     bus->controller, "usb_host%d", busnum);
 	if (IS_ERR(bus->class_dev)) {
 		clear_bit(busnum, busmap.busmap);
-		up(&usb_bus_list_lock);
+		mutex_unlock(&usb_bus_list_lock);
 		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 */
 	list_add (&bus->bus_list, &usb_bus_list);
-	up (&usb_bus_list_lock);
+	mutex_unlock(&usb_bus_list_lock);
 
 	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
 	 * itself up
 	 */
-	down (&usb_bus_list_lock);
+	mutex_lock(&usb_bus_list_lock);
 	list_del (&bus->bus_list);
-	up (&usb_bus_list_lock);
+	mutex_unlock(&usb_bus_list_lock);
 
 	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
- * @usb_dev: the usb root hub device to be registered.
  * @hcd: host controller for this root hub
  *
  * 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 usb_device *usb_dev = hcd->self.root_hub;
 	const int devnum = 1;
 	int retval;
 
@@ -844,14 +862,12 @@ static int register_root_hub (struct usb_device *usb_dev,
 	set_bit (devnum, usb_dev->bus->devmap.devicemap);
 	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);
 	retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
 	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",
 				usb_dev->dev.bus_id, retval);
 		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);
 	if (retval) {
-		usb_dev->bus->root_hub = NULL;
 		dev_err (parent_dev, "can't register root hub for %s, %d\n",
 				usb_dev->dev.bus_id, retval);
 	}
-	up (&usb_bus_list_lock);
+	mutex_unlock(&usb_bus_list_lock);
 
 	if (retval == 0) {
 		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);
 	list_del_init (&urb->urb_list);
 	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_RESUMING:
 doit:
-		usb_get_dev (urb->dev);
 		list_add_tail (&urb->urb_list, &ep->urb_list);
 		status = 0;
 		break;
@@ -1771,12 +1784,10 @@ int usb_add_hcd(struct usb_hcd *hcd,
 
 	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) {
 		dev_dbg(hcd->self.controller, "pool alloc failed\n");
 		return retval;
@@ -1785,6 +1796,36 @@ int usb_add_hcd(struct usb_hcd *hcd,
 	if ((retval = usb_register_bus(&hcd->self)) < 0)
 		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) {
 		char	buf[8], *bufp = buf;
 
@@ -1816,56 +1857,32 @@ int usb_add_hcd(struct usb_hcd *hcd,
 					(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) {
 		dev_err(hcd->self.controller, "startup error %d\n", retval);
 		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);
-	if ((retval = register_root_hub(rhdev, hcd)) != 0)
+	if ((retval = register_root_hub(hcd)) != 0)
 		goto err_register_root_hub;
 
 	if (hcd->uses_new_polling && hcd->poll_rh)
 		usb_hcd_poll_rh_status(hcd);
 	return retval;
 
- err_register_root_hub:
+err_register_root_hub:
 	hcd->driver->stop(hcd);
-
- err_hcd_driver_start:
-	usb_put_dev(rhdev);
-
- err_allocate_root_hub:
+err_hcd_driver_start:
 	if (hcd->irq >= 0)
 		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);
-
- err_register_bus:
+err_register_bus:
 	hcd_buffer_destroy(hcd);
 	return retval;
 } 
@@ -1891,9 +1908,9 @@ void usb_remove_hcd(struct usb_hcd *hcd)
 	hcd->rh_registered = 0;
 	spin_unlock_irq (&hcd_root_hub_lock);
 
-	down(&usb_bus_list_lock);
+	mutex_lock(&usb_bus_list_lock);
 	usb_disconnect(&hcd->self.root_hub);
-	up(&usb_bus_list_lock);
+	mutex_unlock(&usb_bus_list_lock);
 
 	hcd->poll_rh = 0;
 	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_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? */
 
 	/* 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 */
 
 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 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/usbdevice_fs.h>
 #include <linux/kthread.h>
+#include <linux/mutex.h>
 
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
@@ -1005,12 +1006,18 @@ void usb_set_device_state(struct usb_device *udev,
 		;	/* do nothing */
 	else if (new_state != USB_STATE_NOTATTACHED) {
 		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
 		recursively_mark_NOTATTACHED(udev);
 	spin_unlock_irqrestore(&device_state_lock, flags);
@@ -1172,8 +1179,11 @@ static int choose_configuration(struct usb_device *udev)
 	c = udev->config;
 	num_configs = udev->descriptor.bNumConfigurations;
 	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
@@ -1208,7 +1218,8 @@ static int choose_configuration(struct usb_device *udev)
 		/* If the first config's first interface is COMM/2/0xff
 		 * (MSFT RNDIS), rule it out unless Linux has host-side
 		 * RNDIS support. */
-		if (i == 0 && desc->bInterfaceClass == USB_CLASS_COMM
+		if (i == 0 && desc
+				&& desc->bInterfaceClass == USB_CLASS_COMM
 				&& desc->bInterfaceSubClass == 2
 				&& desc->bInterfaceProtocol == 0xff) {
 #ifndef CONFIG_USB_NET_RNDIS
@@ -1224,8 +1235,8 @@ static int choose_configuration(struct usb_device *udev)
 		 * than a vendor-specific driver. */
 		else if (udev->descriptor.bDeviceClass !=
 						USB_CLASS_VENDOR_SPEC &&
-				desc->bInterfaceClass !=
-						USB_CLASS_VENDOR_SPEC) {
+				(!desc || desc->bInterfaceClass !=
+						USB_CLASS_VENDOR_SPEC)) {
 			best = c;
 			break;
 		}
@@ -1876,18 +1887,18 @@ int usb_resume_device(struct usb_device *udev)
 	if (udev->state == USB_STATE_NOTATTACHED)
 		return -ENODEV;
 
-#ifdef	CONFIG_USB_SUSPEND
 	/* selective resume of one downstream hub-to-device port */
 	if (udev->parent) {
+#ifdef	CONFIG_USB_SUSPEND
 		if (udev->state == USB_STATE_SUSPENDED) {
 			// NOTE swsusp may bork us, device state being wrong...
 			// NOTE this fails if parent is also suspended...
 			status = hub_port_resume(hdev_to_hub(udev->parent),
 					udev->portnum, udev);
 		} else
+#endif
 			status = 0;
 	} else
-#endif
 		status = finish_device_resume(udev);
 	if (status < 0)
 		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,
 		int retry_counter)
 {
-	static DECLARE_MUTEX(usb_address0_sem);
+	static DEFINE_MUTEX(usb_address0_mutex);
 
 	struct usb_device	*hdev = hub->hdev;
 	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)
 		delay = HUB_LONG_RESET_TIME;
 
-	down(&usb_address0_sem);
+	mutex_lock(&usb_address0_mutex);
 
 	/* Reset the device; full speed may morph to high speed */
 	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:
 	if (retval)
 		hub_port_disable(hub, port1, 0);
-	up(&usb_address0_sem);
+	mutex_unlock(&usb_address0_mutex);
 	return retval;
 }
 
@@ -3017,7 +3028,7 @@ int usb_reset_device(struct usb_device *udev)
 	parent_hub = hdev_to_hub(parent_hdev);
 
 	/* 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 ==
 				&hub_driver.driver &&
 			(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
  * 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 result;
@@ -1388,11 +1388,13 @@ free_interfaces:
 	if (dev->state != USB_STATE_ADDRESS)
 		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),
 			USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
@@ -1488,7 +1490,6 @@ EXPORT_SYMBOL(usb_sg_wait);
 // synchronous control message convenience routines
 EXPORT_SYMBOL(usb_get_descriptor);
 EXPORT_SYMBOL(usb_get_status);
-EXPORT_SYMBOL(usb_get_string);
 EXPORT_SYMBOL(usb_string);
 
 // synchronous calls that also maintain usbcore state

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

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

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

@@ -33,6 +33,7 @@
 #include <linux/errno.h>
 #include <linux/smp_lock.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 
 #include <asm/io.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_device *dev = NULL;
 	
-	down(&usb_bus_list_lock);
+	mutex_lock(&usb_bus_list_lock);
 	for (buslist = usb_bus_list.next;
 	     buslist != &usb_bus_list; 
 	     buslist = buslist->next) {
@@ -653,7 +654,7 @@ struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
 			goto exit;
 	}
 exit:
-	up(&usb_bus_list_lock);
+	mutex_unlock(&usb_bus_list_lock);
 	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.
 
+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
 	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_OMAP)		+= omap_udc.o
 obj-$(CONFIG_USB_LH7A40X)	+= lh7a40x_udc.o
+obj-$(CONFIG_USB_AT91)		+= at91_udc.o
 
 #
 # 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;
 	ep = usb_ep_to_dummy_ep (_ep);
 
-	req = kmalloc (sizeof *req, mem_flags);
+	req = kzalloc(sizeof(*req), mem_flags);
 	if (!req)
 		return NULL;
-	memset (req, 0, sizeof *req);
 	INIT_LIST_HEAD (&req->queue);
 	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).
  */
 
-static ushort __initdata idVendor;
+static ushort idVendor;
 module_param(idVendor, ushort, S_IRUGO);
 MODULE_PARM_DESC(idVendor, "USB Vendor ID");
 
-static ushort __initdata idProduct;
+static ushort idProduct;
 module_param(idProduct, ushort, S_IRUGO);
 MODULE_PARM_DESC(idProduct, "USB Product ID");
 
-static ushort __initdata bcdDevice;
+static ushort bcdDevice;
 module_param(bcdDevice, ushort, S_IRUGO);
 MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
 
-static char *__initdata iManufacturer;
+static char *iManufacturer;
 module_param(iManufacturer, charp, S_IRUGO);
 MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
 
-static char *__initdata iProduct;
+static char *iProduct;
 module_param(iProduct, charp, S_IRUGO);
 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" */
-static char *__initdata dev_addr;
+static char *dev_addr;
 module_param(dev_addr, charp, S_IRUGO);
 MODULE_PARM_DESC(dev_addr, "Device Ethernet Address");
 
 /* this address is invisible to ifconfig */
-static char *__initdata host_addr;
+static char *host_addr;
 module_param(host_addr, charp, S_IRUGO);
 MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 
@@ -253,6 +257,14 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 #define DEV_CONFIG_CDC
 #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.
  * 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_SUBSET			8
 #define STRING_RNDIS			9
+#define STRING_SERIALNUMBER		10
 
 /* holds our biggest descriptor (or RNDIS response) */
 #define USB_BUFSIZ	256
@@ -862,6 +875,7 @@ static inline void __init hs_subset_descriptors(void)
 
 static char				manufacturer [50];
 static char				product_desc [40] = DRIVER_DESC;
+static char				serial_number [20];
 
 #ifdef	DEV_CONFIG_CDC
 /* 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 [] = {
 	{ STRING_MANUFACTURER,	manufacturer, },
 	{ STRING_PRODUCT,	product_desc, },
+	{ STRING_SERIALNUMBER,	serial_number, },
 	{ STRING_DATA,		"Ethernet Data", },
 #ifdef	DEV_CONFIG_CDC
 	{ 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);
 
-	// 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)
 		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)
 {
 	struct eth_dev		*dev = get_gadget_data (gadget);
@@ -2153,7 +2169,7 @@ static u8 __init nibble (unsigned char c)
 	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) {
 		unsigned	i;
@@ -2168,9 +2184,10 @@ static void __init get_ether_addr (const char *str, u8 *dev_addr)
 			dev_addr [i] = num;
 		}
 		if (is_valid_ether_addr (dev_addr))
-			return;
+			return 0;
 	}
 	random_ether_addr(dev_addr);
+	return 1;
 }
 
 static int __init
@@ -2268,6 +2285,10 @@ eth_bind (struct usb_gadget *gadget)
 		strlcpy (manufacturer, iManufacturer, sizeof manufacturer);
 	if (iProduct)
 		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 */
 	usb_ep_autoconfig_reset (gadget);
@@ -2377,9 +2398,13 @@ autoconf_fail:
 	 * The host side address is used with CDC and RNDIS, and commonly
 	 * 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) {
-		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
 		snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
 			dev->host_mac [0], dev->host_mac [1],
@@ -2523,7 +2548,7 @@ static struct usb_gadget_driver eth_driver = {
 
 	.function	= (char *) driver_desc,
 	.bind		= eth_bind,
-	.unbind		= eth_unbind,
+	.unbind		= __exit_p(eth_unbind),
 
 	.setup		= eth_setup,
 	.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);
 }
 
-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);
 	int			i;
@@ -4064,7 +4064,7 @@ static struct usb_gadget_driver		fsg_driver = {
 #endif
 	.function	= (char *) longname,
 	.bind		= fsg_bind,
-	.unbind		= fsg_unbind,
+	.unbind		= __exit_p(fsg_unbind),
 	.disconnect	= fsg_disconnect,
 	.setup		= fsg_setup,
 	.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
  * 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.
- * (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.
  */
@@ -93,6 +93,26 @@
 #define gadget_is_imx(g)	0
 #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_AU1X00
 // ...
@@ -143,5 +163,11 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x13;
 	else if (gadget_is_imx(gadget))
 		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;
 }

+ 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)
 		return NULL;
-	req = kmalloc(sizeof *req, gfp_flags);
+	req = kzalloc(sizeof *req, gfp_flags);
 	if (!req)
 		return NULL;
 
-	memset(req, 0, sizeof *req);
 	req->req.dma = DMA_ADDR_INVALID;
 	INIT_LIST_HEAD(&req->queue);
 	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;
 
-	dev = kmalloc (sizeof *dev, GFP_KERNEL);
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev)
 		return NULL;
-	memset (dev, 0, sizeof *dev);
 	dev->state = STATE_DEV_DISABLED;
 	atomic_set (&dev->count, 1);
 	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) {
 		struct ep_data	*data;
 
-		data = kmalloc (sizeof *data, GFP_KERNEL);
+		data = kzalloc(sizeof(*data), GFP_KERNEL);
 		if (!data)
 			goto enomem;
-		memset (data, 0, sizeof data);
 		data->state = STATE_EP_DISABLED;
 		init_MUTEX (&data->lock);
 		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);
 
-	req = kmalloc(sizeof *req, gfp_flags);
+	req = kzalloc(sizeof(*req), gfp_flags);
 	if (!req)
 		return 0;
 
-	memset(req, 0, sizeof *req);
 	INIT_LIST_HEAD(&req->queue);
 
 	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;
 	ep = container_of (_ep, struct net2280_ep, ep);
 
-	req = kmalloc (sizeof *req, gfp_flags);
+	req = kzalloc(sizeof(*req), gfp_flags);
 	if (!req)
 		return NULL;
 
-	memset (req, 0, sizeof *req);
 	req->req.dma = DMA_ADDR_INVALID;
 	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;
 
-	req = kmalloc(sizeof *req, gfp_flags);
+	req = kzalloc(sizeof(*req), gfp_flags);
 	if (req) {
-		memset (req, 0, sizeof *req);
 		req->req.dma = DMA_ADDR_INVALID;
 		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 */
 	// OTG_SYSCON_1_REG |= DEV_IDLE_EN;
 
-	udc = kmalloc (sizeof *udc, SLAB_KERNEL);
+	udc = kzalloc(sizeof(*udc), SLAB_KERNEL);
 	if (!udc)
 		return -ENOMEM;
 
-	memset(udc, 0, sizeof *udc);
 	spin_lock_init (&udc->lock);
 
 	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;
 
-	req = kmalloc (sizeof *req, gfp_flags);
+	req = kzalloc(sizeof(*req), gfp_flags);
 	if (!req)
 		return NULL;
 
-	memset (req, 0, sizeof *req);
 	INIT_LIST_HEAD (&req->queue);
 	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 */
 	.function =		GS_LONG_NAME,
 	.bind =			gs_bind,
-	.unbind =		gs_unbind,
+	.unbind =		__exit_p(gs_unbind),
 	.setup =		gs_setup,
 	.disconnect =		gs_disconnect,
 	.driver = {
@@ -1413,7 +1413,7 @@ requeue:
  * Called on module load.  Allocates and initializes the device
  * structure and a control request.
  */
-static int gs_bind(struct usb_gadget *gadget)
+static int __init gs_bind(struct usb_gadget *gadget)
 {
 	int ret;
 	struct usb_ep *ep;
@@ -1538,7 +1538,7 @@ autoconf_fail:
  * Called on module unload.  Frees the control request and device
  * 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);
 
@@ -2178,10 +2178,9 @@ static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags)
 		return -EIO;
 
 	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;
 
-		memset(port, 0, sizeof(struct gs_port));
 		port->port_dev = dev;
 		port->port_num = i;
 		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)
 {
 	struct zero_dev		*dev = get_gadget_data (gadget);
@@ -1136,7 +1136,7 @@ zero_unbind (struct usb_gadget *gadget)
 	set_gadget_data (gadget, NULL);
 }
 
-static int
+static int __init
 zero_bind (struct usb_gadget *gadget)
 {
 	struct zero_dev		*dev;
@@ -1188,10 +1188,9 @@ autoconf_fail:
 
 
 	/* ok, we made sense of the hardware ... */
-	dev = kmalloc (sizeof *dev, SLAB_KERNEL);
+	dev = kzalloc(sizeof(*dev), SLAB_KERNEL);
 	if (!dev)
 		return -ENOMEM;
-	memset (dev, 0, sizeof *dev);
 	spin_lock_init (&dev->lock);
 	dev->gadget = gadget;
 	set_gadget_data (gadget, dev);
@@ -1224,12 +1223,6 @@ autoconf_fail:
 		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);
 
 	init_timer (&dev->resume);
@@ -1294,7 +1287,7 @@ static struct usb_gadget_driver zero_driver = {
 #endif
 	.function	= (char *) longname,
 	.bind		= zero_bind,
-	.unbind		= zero_unbind,
+	.unbind		= __exit_p(zero_unbind),
 
 	.setup		= zero_setup,
 	.disconnect	= zero_disconnect,

+ 1 - 1
drivers/usb/host/Kconfig

@@ -6,7 +6,7 @@ comment "USB Host Controller Drivers"
 
 config USB_EHCI_HCD
 	tristate "EHCI HCD (USB 2.0) support"
-	depends on USB && PCI
+	depends on USB && USB_ARCH_HAS_EHCI
 	---help---
 	  The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
 	  "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
 #include "ehci-pci.c"
+#define	EHCI_BUS_GLUED
 #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"
 #endif

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

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

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

@@ -75,7 +75,6 @@ static void qh_destroy (struct kref *kref)
 	}
 	if (qh->dummy)
 		ehci_qtd_free (ehci, qh->dummy);
-	usb_put_dev (qh->dev);
 	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;
 
 	/* 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:
 	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;
 	case PCI_VENDOR_ID_NVIDIA:
+		switch (pdev->device) {
 		/* NVidia reports that certain chips don't handle
 		 * QH, ITD, or SITD addresses above 2GB.  (But TD,
 		 * data buffer, and periodic schedule are normal.)
 		 */
-		switch (pdev->device) {
 		case 0x003c:	/* MCP04 */
 		case 0x005b:	/* CK804 */
 		case 0x00d8:	/* CK8 */
@@ -120,6 +120,14 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 				ehci_warn(ehci, "can't enable NVidia "
 					"workaround for >2GB RAM\n");
 			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;
 	}
@@ -163,6 +171,21 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 			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);
 done:
 	return retval;

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

@@ -702,7 +702,7 @@ qh_make (
 	}
 
 	/* support for tt scheduling, and access to toggles */
-	qh->dev = usb_get_dev (urb->dev);
+	qh->dev = urb->dev;
 
 	/* using TT? */
 	switch (urb->dev->speed) {
@@ -721,7 +721,14 @@ qh_make (
 		info1 |= maxp << 16;
 
 		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
 		 * 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? */
 	if (unlikely (qh == ehci->async)) {
 		/* 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);
 			wmb ();
 			// handshake later, if we need to
+			timer_action_done (ehci, TIMER_ASYNC_OFF);
 		}
-		timer_action_done (ehci, TIMER_ASYNC_OFF);
 		return;
 	} 
 

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

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

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

@@ -88,7 +88,12 @@ struct ehci_hcd {			/* one per controller */
 	unsigned long		next_statechange;
 	u32			command;
 
+	/* SILICON QUIRKS */
 	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 */
 #ifdef EHCI_STATS
@@ -97,7 +102,6 @@ struct ehci_hcd {			/* one per controller */
 #else
 #	define COUNT(x) do {} while (0)
 #endif
-	u8			sbrn;		/* packed release number */
 };
 
 /* 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)
 #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

+ 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;
 
 	/* 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);
 	/* This sets rx_offset to 0. */
-	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
 	urb_priv->urb_state = NOT_STARTED;
 	urb->hcpriv = urb_priv;
 
@@ -2475,10 +2474,9 @@ static int etrax_usb_submit_ctrl_urb(struct urb *urb)
 	urb->status = -EINPROGRESS;
 
 	/* 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);
 	/* This sets rx_offset to 0. */
-	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
 	urb_priv->urb_state = NOT_STARTED;
 	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));
 	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);
-	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
 	urb->hcpriv = urb_priv;
 
 	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;
 
-	urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC);
+	urb_priv = kzalloc(sizeof(etrax_urb_priv_t), GFP_ATOMIC);
 	assert(urb_priv != NULL);
-	memset(urb_priv, 0, sizeof(etrax_urb_priv_t));
 
 	urb->hcpriv = urb_priv;
 	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;
 	else {
 		INIT_LIST_HEAD(&ep->schedule);
-		ep->udev = usb_get_dev(udev);
+		ep->udev = udev;
 		ep->epnum = epnum;
 		ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out);
 		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))
 		WARN("ep %p not empty?\n", ep);
 
-	usb_put_dev(ep->udev);
 	kfree(ep);
 	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 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>
 
+#ifndef	CONFIG_SOC_AU1200
+
 #define USBH_ENABLE_BE (1<<0)
 #define USBH_ENABLE_C  (1<<1)
 #define USBH_ENABLE_E  (1<<2)
@@ -37,21 +39,68 @@
 #error not byte order defined
 #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);
 
 /*-------------------------------------------------------------------------*/
 
-static void au1xxx_start_hc(struct platform_device *dev)
+static void au1xxx_start_ohc(struct platform_device *dev)
 {
 	printk(KERN_DEBUG __FILE__
 		": starting Au1xxx OHCI USB Controller\n");
 
 	/* enable host controller */
+
+#ifndef CONFIG_SOC_AU1200
+
 	au_writel(USBH_ENABLE_CE, USB_HOST_CONFIG);
 	udelay(1000);
 	au_writel(USBH_ENABLE_INIT, USB_HOST_CONFIG);
 	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) */
 	while (au_readl(USB_HOST_CONFIG),
 		!(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");
 }
 
-static void au1xxx_stop_hc(struct platform_device *dev)
+static void au1xxx_stop_ohc(struct platform_device *dev)
 {
 	printk(KERN_DEBUG __FILE__
 	       ": stopping Au1xxx OHCI USB Controller\n");
 
+#ifndef CONFIG_SOC_AU1200
+
 	/* Disable clock */
 	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()
  *
  * 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.
  *
  */
-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)
 {
 	int retval;
 	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;
 	}
 
@@ -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;
 
 	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;
 		goto err1;
 	}
 
 	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 	if (!hcd->regs) {
-		pr_debug("ioremap failed");
+		pr_debug("ioremap failed\n");
 		retval = -ENOMEM;
 		goto err2;
 	}
 
-	au1xxx_start_hc(dev);
+	au1xxx_start_ohc(dev);
 	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)
 		return retval;
 
-	au1xxx_stop_hc(dev);
+	au1xxx_stop_ohc(dev);
 	iounmap(hcd->regs);
  err2:
 	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.
  *
  */
-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);
-	au1xxx_stop_hc(dev);
+	au1xxx_stop_ohc(dev);
 	iounmap(hcd->regs);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
@@ -235,7 +307,7 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 	if (usb_disabled())
 		return -ENODEV;
 
-	ret = usb_hcd_au1xxx_probe(&ohci_au1xxx_hc_driver, pdev);
+	ret = usb_ohci_au1xxx_probe(&ohci_au1xxx_hc_driver, pdev);
 	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);
 
-	usb_hcd_au1xxx_remove(hcd, pdev);
+	usb_ohci_au1xxx_remove(hcd, pdev);
 	return 0;
 }
 	/*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)
 {
 	int ret;
+	struct usb_hcd *hcd = ohci_to_hcd(ohci);
 
 	disable (ohci);
-	ohci->regs = ohci_to_hcd(ohci)->regs;
+	ohci->regs = hcd->regs;
 	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
 	/* SMM owns the HC?  not for long! */
 	if (!no_handshake && ohci_readl (ohci,
@@ -478,8 +483,10 @@ static int ohci_init (struct ohci_hcd *ohci)
 
 	/* Disable HC interrupts */
 	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 */
 	if (ohci->num_ports == 0)
@@ -488,16 +495,19 @@ static int ohci_init (struct ohci_hcd *ohci)
 	if (ohci->hcca)
 		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);
 	if (!ohci->hcca)
 		return -ENOMEM;
 
 	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;
-
 }
 
 /*-------------------------------------------------------------------------*/
@@ -510,6 +520,7 @@ static int ohci_run (struct ohci_hcd *ohci)
 {
   	u32			mask, temp;
 	int			first = ohci->fminterval == 0;
+	struct usb_hcd		*hcd = ohci_to_hcd(ohci);
 
 	disable (ohci);
 
@@ -525,18 +536,17 @@ static int ohci_run (struct ohci_hcd *ohci)
 		/* 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",
 			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) {
 	case OHCI_USB_OPER:
@@ -632,7 +642,7 @@ retry:
 	ohci->hc_control &= OHCI_CTRL_RWC;
  	ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
  	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 */
 	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.
 	mdelay ((temp >> 23) & 0x1fe);
-	ohci_to_hcd(ohci)->state = HC_STATE_RUNNING;
+	hcd->state = HC_STATE_RUNNING;
 
 	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;
 }
 
@@ -905,6 +910,10 @@ MODULE_LICENSE ("GPL");
 #include "ohci-ppc-soc.c"
 #endif
 
+#ifdef CONFIG_ARCH_AT91RM9200
+#include "ohci-at91.c"
+#endif
+
 #if !(defined(CONFIG_PCI) \
       || defined(CONFIG_SA1111) \
       || defined(CONFIG_ARCH_S3C2410) \
@@ -913,6 +922,7 @@ MODULE_LICENSE ("GPL");
       || defined (CONFIG_PXA27x) \
       || defined (CONFIG_SOC_AU1X00) \
       || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
+      || defined (CONFIG_ARCH_AT91RM9200) \
 	)
 #error "missing bus glue for ohci-hcd"
 #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);
 
 	/* 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;
 	else
 		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);
 	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_writel (ohci, temp, &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);
 	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;
 
 	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))
 			continue;
-		if ((status & RH_PS_PSS) && hcd->remote_wakeup)
+		if ((status & RH_PS_PSS) && can_suspend)
 			continue;
 		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);
 	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);
 
 		/* AMD 756, for most chips (early revs), corrupts register
@@ -45,7 +48,8 @@ ohci_pci_start (struct usb_hcd *hcd)
 				&& pdev->device == 0x740c) {
 			ohci->flags = OHCI_QUIRK_AMD756;
 			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
@@ -88,6 +92,13 @@ ohci_pci_start (struct usb_hcd *hcd)
 			ohci_dbg (ohci,
 				"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

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

@@ -853,7 +853,7 @@ static int sl811h_urb_enqueue(
 
 	} else {
 		INIT_LIST_HEAD(&ep->schedule);
-		ep->udev = usb_get_dev(udev);
+		ep->udev = udev;
 		ep->epnum = epnum;
 		ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out);
 		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))
 		WARN("ep %p not empty?\n", ep);
 
-	usb_put_dev(ep->udev);
 	kfree(ep);
 	hep->hcpriv = NULL;
 }

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

@@ -17,10 +17,13 @@
 
 #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 */
-static inline void lprintk(char *buf)
+static void lprintk(char *buf)
 {
 	char *p;
 
@@ -90,13 +93,59 @@ static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
 	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;
-	struct urb_priv *urbp;
-	struct list_head *head, *tmp;
 	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);
 
 	/* 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)))
 		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;
 }
 
-#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[] = {
+  "skel_unlink_qh", "skel_iso_qh",
   "skel_int128_qh", "skel_int64_qh",
   "skel_int32_qh", "skel_int16_qh",
   "skel_int8_qh", "skel_int4_qh",
@@ -206,12 +209,6 @@ static const char * const qh_names[] = {
   "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)
 {
 	char *out = buf;
@@ -321,139 +318,29 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
 	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)
 {
-	unsigned long flags;
 	char *out = buf;
 	int i, j;
 	struct uhci_qh *qh;
 	struct uhci_td *td;
 	struct list_head *tmp, *head;
 
-	spin_lock_irqsave(&uhci->lock, flags);
-
 	out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
 	out += sprintf(out, "HC status\n");
 	out += uhci_show_status(uhci, out, len - (out - buf));
+	if (debug <= 1)
+		return out - buf;
 
 	out += sprintf(out, "Frame List\n");
 	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
-		int shown = 0;
 		td = uhci->frame_cpu[i];
 		if (!td)
 			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");
-		}
-		show_frame_num();
 
 		head = &td->fl_list;
 		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");
 
 	for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
-		int shown = 0;
+		int cnt = 0;
 
 		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 */
 		if (i == UHCI_NUM_SKELQH - 1) {
@@ -487,53 +371,37 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
 			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;
 
 		while (tmp != head) {
-			qh = list_entry(tmp, struct uhci_qh, list);
-
+			qh = list_entry(tmp, struct uhci_qh, node);
 			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 !=
 			    (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH))
 				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;
 }
 
+#ifdef CONFIG_DEBUG_FS
+
 #define MAX_OUTPUT	(64 * 1024)
 
 struct uhci_debug {
 	int size;
 	char *data;
-	struct uhci_hcd *uhci;
 };
 
 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_debug *up;
 	int ret = -ENOMEM;
+	unsigned long flags;
 
 	lock_kernel();
 	up = kmalloc(sizeof(*up), GFP_KERNEL);
@@ -553,7 +422,11 @@ static int uhci_debug_open(struct inode *inode, struct file *file)
 		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;
 
@@ -604,15 +477,32 @@ static int uhci_debug_release(struct inode *inode, struct file *file)
 	return 0;
 }
 
+#undef uhci_debug_operations
 static struct file_operations uhci_debug_operations = {
+	.owner =	THIS_MODULE,
 	.open =		uhci_debug_open,
 	.llseek =	uhci_debug_lseek,
 	.read =		uhci_debug_read,
 	.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

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

@@ -54,7 +54,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v2.3"
+#define DRIVER_VERSION "v3.0"
 #define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \
 Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \
 Alan Stern"
@@ -68,12 +68,16 @@ Alan Stern"
  * debug = 3, show all TDs in URBs when dumping
  */
 #ifdef DEBUG
+#define DEBUG_CONFIGURED	1
 static int debug = 1;
-#else
-static int debug = 0;
-#endif
 module_param(debug, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug level");
+
+#else
+#define DEBUG_CONFIGURED	0
+#define debug			0
+#endif
+
 static char *errbuf;
 #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),
 					"host controller halted, "
 					"very bad!\n");
+				if (debug > 1 && errbuf) {
+					/* Print the schedule for debugging */
+					uhci_sprint_schedule(uhci,
+							errbuf, ERRBUF_LEN);
+					lprintk(errbuf);
+				}
 				hc_died(uhci);
 
 				/* Force a callback in case there are
@@ -376,6 +386,14 @@ static void release_uhci(struct uhci_hcd *uhci)
 {
 	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++)
 		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),
 			UHCI_NUMFRAMES * sizeof(*uhci->frame),
 			uhci->frame, uhci->frame_dma_handle);
-
-	debugfs_remove(uhci->dentry);
 }
 
 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;
 
-	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->fsbrtimeout = 0;
 
 	spin_lock_init(&uhci->lock);
-	INIT_LIST_HEAD(&uhci->qh_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);
 
+	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_NUMFRAMES * sizeof(*uhci->frame),
 			&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++) {
-		uhci->skelqh[i] = uhci_alloc_qh(uhci);
+		uhci->skelqh[i] = uhci_alloc_qh(uhci, NULL, NULL);
 		if (!uhci->skelqh[i]) {
 			dev_err(uhci_dev(uhci), "unable to allocate QH\n");
 			goto err_alloc_skelqh;
@@ -557,13 +569,17 @@ static int uhci_start(struct usb_hcd *hcd)
 			uhci->skel_int16_qh->link =
 			uhci->skel_int8_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 */
 	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:
-		 * 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.
 		 */
-		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 */
 		uhci->frame[i] = UHCI_PTR_QH |
@@ -611,6 +627,7 @@ static int uhci_start(struct usb_hcd *hcd)
 	mb();
 
 	configure_hc(uhci);
+	uhci->is_initialized = 1;
 	start_rh(uhci);
 	return 0;
 
@@ -767,13 +784,30 @@ static int uhci_resume(struct usb_hcd *hcd)
 }
 #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,
-		struct usb_host_endpoint *ep)
+		struct usb_host_endpoint *hep)
 {
 	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)
@@ -857,16 +891,15 @@ static int __init uhci_hcd_init(void)
 	if (usb_disabled())
 		return -ENODEV;
 
-	if (debug) {
+	if (DEBUG_CONFIGURED) {
 		errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
 		if (!errbuf)
 			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",
 		sizeof(struct urb_priv), 0, 0, NULL, NULL);
 	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_ERROR		0x0002	/* Interrupt due to error */
 #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 */
 
 /* Interrupt enable register */
@@ -47,7 +48,8 @@
 /* USB port status and control registers */
 #define USBPORTSC1	16
 #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_PE		0x0004	/* Port Enable */
 #define   USBPORTSC_PEC		0x0008	/* Port Enable Change */
@@ -71,15 +73,16 @@
 #define   USBLEGSUP_RWC		0x8f00	/* the R/WC 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_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
  * can easily splice a QH for some endpoint into the schedule at the right
  * 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 --> ...
+ *
+ * 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 {
 	/* 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 */
 	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)));
 
 /*
  * We need a special accessor for the element pointer because it is
  * 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;
 
 	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_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_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)
@@ -163,7 +189,7 @@ static __le32 inline qh_element(struct uhci_qh *qh) {
 #define TD_TOKEN_TOGGLE_SHIFT	19
 #define TD_TOKEN_TOGGLE		(1 << 19)
 #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 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.
  *
  * 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 {
 	/* Hardware fields */
@@ -210,7 +236,7 @@ struct uhci_td {
  * We need a special accessor for the control/status word because it is
  * 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;
 
 	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
- * skeleton QH.
- *
- * For instance, the queue can look like this:
+ * skeleton QH.  For instance, the schedule list can look like this:
  *
  * skel int128 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
  *   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[]
@@ -293,21 +321,21 @@ static inline int __interval_to_skel(int interval)
 	if (interval < 16) {
 		if (interval < 4) {
 			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)
-			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 < 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)
-		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_qh *skelqh[UHCI_NUM_SKELQH];	/* Skeleton QHs */
+	struct uhci_qh *next_qh;	/* Next QH to scan */
 
 	spinlock_t lock;
 
-	dma_addr_t frame_dma_handle;		/* Hardware frame list */
+	dma_addr_t frame_dma_handle;	/* Hardware frame list */
 	__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;
 	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 working_RD:1;		/* Suspended root hub doesn't
 						   need to be polled */
+	unsigned int is_initialized:1;		/* Data structure is usable */
 
 	/* Support for port suspend/resume/reset */
 	unsigned long port_c_suspend;		/* Bit-arrays of ports */
@@ -389,27 +419,16 @@ struct uhci_hcd {
 	unsigned long resuming_ports;
 	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) */
 	struct list_head td_remove_list;
 	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 */
 
 	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 */
@@ -429,7 +448,7 @@ static inline struct usb_hcd *uhci_to_hcd(struct uhci_hcd *uhci)
  *	Private per-URB data
  */
 struct urb_priv {
-	struct list_head urb_list;
+	struct list_head node;		/* Node in the QH's urbp list */
 
 	struct urb *urb;
 
@@ -437,15 +456,8 @@ struct urb_priv {
 	struct list_head td_list;
 
 	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)
 {
 	unsigned int port;
@@ -113,6 +128,12 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
 				CLR_RH_PORTSTAT(USBPORTSC_PR);
 				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
 				 * reset on caused a port enable change.
 				 * 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/smp_lock.h>
 #include <linux/wait.h>
+#include <linux/mutex.h>
 
 #include <linux/usb.h>
 #include <linux/fs.h>
@@ -169,7 +170,7 @@ struct mdc800_data
 	int			out_count;	// Bytes in the buffer
 
 	int			open;		// Camera device open ?
-	struct semaphore	io_lock;	// IO -lock
+	struct mutex		io_lock;	// IO -lock
 
 	char 			in [8];		// Command Input Buffer
 	int  			in_count;
@@ -497,7 +498,7 @@ static int mdc800_usb_probe (struct usb_interface *intf,
 
 	info ("Found Mustek MDC800 on USB.");
 
-	down (&mdc800->io_lock);
+	mutex_lock(&mdc800->io_lock);
 
 	retval = usb_register_dev(intf, &mdc800_class);
 	if (retval) {
@@ -542,7 +543,7 @@ static int mdc800_usb_probe (struct usb_interface *intf,
 
 	mdc800->state=READY;
 
-	up (&mdc800->io_lock);
+	mutex_unlock(&mdc800->io_lock);
 	
 	usb_set_intfdata(intf, mdc800);
 	return 0;
@@ -620,7 +621,7 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
 	int retval=0;
 	int errn=0;
 
-	down (&mdc800->io_lock);
+	mutex_lock(&mdc800->io_lock);
 	
 	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.");
 
 error_out:
-	up (&mdc800->io_lock);
+	mutex_unlock(&mdc800->io_lock);
 	return errn;
 }
 
@@ -669,7 +670,7 @@ static int mdc800_device_release (struct inode* inode, struct file *file)
 	int retval=0;
 	dbg ("Mustek MDC800 device closed.");
 
-	down (&mdc800->io_lock);
+	mutex_lock(&mdc800->io_lock);
 	if (mdc800->open && (mdc800->state != NOT_CONNECTED))
 	{
 		usb_kill_urb(mdc800->irq_urb);
@@ -682,7 +683,7 @@ static int mdc800_device_release (struct inode* inode, struct file *file)
 		retval=-EIO;
 	}
 
-	up(&mdc800->io_lock);
+	mutex_unlock(&mdc800->io_lock);
 	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 */
 	char __user *ptr = buf;
 
-	down (&mdc800->io_lock);
+	mutex_lock(&mdc800->io_lock);
 	if (mdc800->state == NOT_CONNECTED)
 	{
-		up (&mdc800->io_lock);
+		mutex_unlock(&mdc800->io_lock);
 		return -EBUSY;
 	}
 	if (mdc800->state == WORKING)
 	{
 		warn ("Illegal State \"working\" reached during read ?!");
-		up (&mdc800->io_lock);
+		mutex_unlock(&mdc800->io_lock);
 		return -EBUSY;
 	}
 	if (!mdc800->open)
 	{
-		up (&mdc800->io_lock);
+		mutex_unlock(&mdc800->io_lock);
 		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)) 
 		{
-			up (&mdc800->io_lock);
+			mutex_unlock(&mdc800->io_lock);
 			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))
 				{
 					err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
-					up (&mdc800->io_lock);
+					mutex_unlock(&mdc800->io_lock);
 					return len-left;
 				}
 				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)
 				{
 					err ("request download-bytes fails (status=%i)",mdc800->download_urb->status);
-					up (&mdc800->io_lock);
+					mutex_unlock(&mdc800->io_lock);
 					return len-left;
 				}
 			}
 			else
 			{
 				/* No more bytes -> that's an error*/
-				up (&mdc800->io_lock);
+				mutex_unlock(&mdc800->io_lock);
 				return -EIO;
 			}
 		}
@@ -761,7 +762,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
 			/* Copy Bytes */
 			if (copy_to_user(ptr, &mdc800->out [mdc800->out_ptr],
 						sts)) {
-				up(&mdc800->io_lock);
+				mutex_unlock(&mdc800->io_lock);
 				return -EFAULT;
 			}
 			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;
 }
 
@@ -785,15 +786,15 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
 {
 	size_t i=0;
 
-	down (&mdc800->io_lock);
+	mutex_lock(&mdc800->io_lock);
 	if (mdc800->state != READY)
 	{
-		up (&mdc800->io_lock);
+		mutex_unlock(&mdc800->io_lock);
 		return -EBUSY;
 	}
 	if (!mdc800->open )
 	{
-		up (&mdc800->io_lock);
+		mutex_unlock(&mdc800->io_lock);
 		return -EBUSY;
 	}
 
@@ -802,13 +803,13 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
 		unsigned char c;
 		if (signal_pending (current)) 
 		{
-			up (&mdc800->io_lock);
+			mutex_unlock(&mdc800->io_lock);
 			return -EINTR;
 		}
 		
 		if(get_user(c, buf+i))
 		{
-			up(&mdc800->io_lock);
+			mutex_unlock(&mdc800->io_lock);
 			return -EFAULT;
 		}
 
@@ -829,7 +830,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
 		}
 		else
 		{
-			up (&mdc800->io_lock);
+			mutex_unlock(&mdc800->io_lock);
 			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))
 			{
 				err ("Camera didn't get ready.\n");
-				up (&mdc800->io_lock);
+				mutex_unlock(&mdc800->io_lock);
 				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))
 			{
 				err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
-				up (&mdc800->io_lock);
+				mutex_unlock(&mdc800->io_lock);
 				return -EIO;
 			}
 			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)
 			{
 				usb_kill_urb(mdc800->write_urb);
-				up (&mdc800->io_lock);
+				mutex_unlock(&mdc800->io_lock);
 				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");
 						mdc800->state=READY;
-						up (&mdc800->io_lock);
+						mutex_unlock(&mdc800->io_lock);
 						return -EIO;
 					}
 					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))
 						{
 							err ("requesting answer from irq fails");
-							up (&mdc800->io_lock);
+							mutex_unlock(&mdc800->io_lock);
 							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))
 						{
 							err ("Command Timeout.");
-							up (&mdc800->io_lock);
+							mutex_unlock(&mdc800->io_lock);
 							return -EIO;
 						}
 					}
@@ -930,7 +931,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
 		}
 		i++;
 	}
-	up (&mdc800->io_lock);
+	mutex_unlock(&mdc800->io_lock);
 	return i;
 }
 
@@ -978,15 +979,13 @@ static int __init usb_mdc800_init (void)
 {
 	int retval = -ENODEV;
 	/* Allocate Memory */
-	mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL);
+	mdc800=kzalloc (sizeof (struct mdc800_data), GFP_KERNEL);
 	if (!mdc800)
 		goto cleanup_on_fail;
 
-	memset(mdc800, 0, sizeof(struct mdc800_data));
 	mdc800->dev = NULL;
-	mdc800->open=0;
 	mdc800->state=NOT_CONNECTED;
-	init_MUTEX (&mdc800->io_lock);
+	mutex_init (&mdc800->io_lock);
 
 	init_waitqueue_head (&mdc800->irq_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)
 
-static DECLARE_MUTEX(disconnect_sem);
-
 struct ati_remote {
 	struct input_dev *idev;
 	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])
 		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;
-	memset(report, 0, sizeof(struct hid_report));
 
 	if (id != 0)
 		report_enum->numbered = 1;
@@ -97,12 +96,9 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
 		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;
 
-	memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
-		+ values * sizeof(unsigned));
-
 	field->index = report->maxfield++;
 	report->field[field->index] = field;
 	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
 	};
 
-	if (!(device = kmalloc(sizeof(struct hid_device), GFP_KERNEL)))
+	if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL)))
 		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))) {
 		kfree(device);
 		return NULL;
 	}
-	memset(device->collection, 0, sizeof(struct hid_collection) *
-		HID_DEFAULT_NUM_COLLECTIONS);
 	device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
 
 	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);
 	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->collection);
 		kfree(device);
 		return NULL;
 	}
-	memset(parser, 0, sizeof(struct hid_parser));
 	parser->device = device;
 
 	end = start + size;
@@ -910,6 +902,99 @@ static int hid_input_report(int type, struct urb *urb, int interrupt, struct pt_
 	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.
  */
@@ -921,25 +1006,35 @@ static void hid_irq_in(struct urb *urb, struct pt_regs *regs)
 
 	switch (urb->status) {
 		case 0:			/* success */
+			hid->retry_delay = 0;
 			hid_input_report(HID_INPUT_REPORT, urb, 1, regs);
 			break;
 		case -ECONNRESET:	/* unlink */
 		case -ENOENT:
-		case -EPERM:
 		case -ESHUTDOWN:	/* unplug */
-		case -EILSEQ:		/* unplug timeout on uhci */
+			clear_bit(HID_IN_RUNNING, &hid->iofl);
 			return;
+		case -EILSEQ:		/* protocol error or unplug */
+		case -EPROTO:		/* protocol error or unplug */
 		case -ETIMEDOUT:	/* NAK */
-			break;
+			clear_bit(HID_IN_RUNNING, &hid->iofl);
+			hid_io_error(hid);
+			return;
 		default:		/* error */
 			warn("input irq status %d received", urb->status);
 	}
 
 	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 */
 			break;
 		case -ESHUTDOWN:	/* unplug */
-		case -EILSEQ:		/* unplug timeout on uhci */
 			unplug = 1;
+		case -EILSEQ:		/* protocol error or unplug */
+		case -EPROTO:		/* protocol error or unplug */
 		case -ECONNRESET:	/* unlink */
 		case -ENOENT:
 			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);
 			break;
 		case -ESHUTDOWN:	/* unplug */
-		case -EILSEQ:		/* unplug timectrl on uhci */
 			unplug = 1;
+		case -EILSEQ:		/* protocol error or unplug */
+		case -EPROTO:		/* protocol error or unplug */
 		case -ECONNRESET:	/* unlink */
 		case -ENOENT:
 		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)
 {
-	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;
 }
 
@@ -1460,6 +1552,9 @@ void hid_init_reports(struct hid_device *hid)
 #define USB_VENDOR_ID_HP		0x03f0
 #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.
  */
@@ -1576,6 +1671,7 @@ static const struct hid_blacklist {
 	{ 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_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_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 },
@@ -1795,6 +1891,10 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 
 	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->ctrllock);
 
@@ -1863,11 +1963,16 @@ static void hid_disconnect(struct usb_interface *intf)
 	if (!hid)
 		return;
 
+	spin_lock_irq(&hid->inlock);	/* Sync with error handler */
 	usb_set_intfdata(intf, NULL);
+	spin_unlock_irq(&hid->inlock);
 	usb_kill_urb(hid->urbin);
 	usb_kill_urb(hid->urbout);
 	usb_kill_urb(hid->urbctrl);
 
+	del_timer_sync(&hid->io_retry);
+	flush_scheduled_work();
+
 	if (hid->claimed & HID_CLAIMED_INPUT)
 		hidinput_disconnect(hid);
 	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);
 
+	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);
 	dev_dbg(&intf->dev, "suspend\n");
 	return 0;
@@ -1952,10 +2061,8 @@ static int hid_resume(struct usb_interface *intf)
 	struct hid_device *hid = usb_get_intfdata (intf);
 	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);
 	return status;
 }

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

@@ -154,10 +154,9 @@ int hid_lgff_init(struct hid_device* hid)
 		return -1;
 	}
 
-	private = kmalloc(sizeof(struct lgff_device), GFP_KERNEL);
+	private = kzalloc(sizeof(struct lgff_device), GFP_KERNEL);
 	if (!private)
 		return -1;
-	memset(private, 0, sizeof(struct lgff_device));
 	hid->ff_private = private;
 
 	/* 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]->value = kmalloc(sizeof(s32[8]), GFP_KERNEL);
+	ret->field[0]->value = kzalloc(sizeof(s32[8]), GFP_KERNEL);
 	if (!ret->field[0]->value) {
 		kfree(ret->field[0]);
 		kfree(ret);
 		return NULL;
 	}
-	memset(ret->field[0]->value, 0, sizeof(s32[8]));
 
 	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 input_dev *input_dev = hidinput->input;
 
-	private = kmalloc(sizeof(struct tmff_device), GFP_KERNEL);
+	private = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
 	if (!private)
 		return -ENOMEM;
 
-	memset(private, 0, sizeof(struct tmff_device));
 	hid->ff_private = private;
 
 	/* Find the report to use */

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

@@ -31,6 +31,8 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
 
 /*
  * USB HID (Human Interface Device) interface class code
@@ -370,6 +372,9 @@ struct hid_control_fifo {
 
 #define HID_CTRL_RUNNING	1
 #define HID_OUT_RUNNING		2
+#define HID_IN_RUNNING		3
+#define HID_RESET_PENDING	4
+#define HID_SUSPENDED		5
 
 struct hid_input {
 	struct list_head list;
@@ -393,12 +398,17 @@ struct hid_device {							/* device report descriptor */
 	int ifnum;							/* USB interface number */
 
 	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 */
 
 	struct urb *urbin;						/* Input URB */
 	char *inbuf;							/* Input buffer */
 	dma_addr_t inbuf_dma;						/* Input buffer dma */
+	spinlock_t inlock;						/* Input fifo spinlock */
 
 	struct urb *urbctrl;						/* Control URB */
 	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])
 		return -ENODEV;
 
-	if (!(list = kmalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
+	if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
 		return -ENOMEM;
-	memset(list, 0, sizeof(struct hiddev_list));
 
 	list->hiddev = hiddev_table[i];
 	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)
 		return -1;
 
-	if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL)))
+	if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL)))
 		return -1;
-	memset(hiddev, 0, sizeof(struct hiddev));
 
 	retval = usb_register_dev(hid->intf, &hiddev_class);
 	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
 	  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
 	tristate "USB Philips Cameras"
 	depends on USB && VIDEO_DEV

+ 6 - 1
drivers/usb/media/Makefile

@@ -2,8 +2,12 @@
 # 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
+zc0301-objs	:= zc0301_core.o zc0301_pas202bcb.o
 
 obj-$(CONFIG_USB_DABUSB)	+= dabusb.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_VICAM)		+= vicam.o usbvideo.o
 obj-$(CONFIG_USB_W9968CF)	+= w9968cf.o
+obj-$(CONFIG_USB_ZC0301)	+= zc0301.o
 obj-$(CONFIG_USB_PWC)           += pwc/

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

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

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

@@ -33,7 +33,9 @@
 #include <linux/types.h>
 #include <linux/param.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"
 
@@ -51,6 +53,7 @@
 #define ET61X251_ALTERNATE_SETTING   13
 #define ET61X251_URB_TIMEOUT         msecs_to_jiffies(2 * ET61X251_ISO_PACKETS)
 #define ET61X251_CTRL_TIMEOUT        100
+#define ET61X251_FRAME_TIMEOUT       2
 
 /*****************************************************************************/
 
@@ -127,15 +130,16 @@ struct et61x251_sysfs_attr {
 
 struct et61x251_module_param {
 	u8 force_munmap;
+	u16 frame_timeout;
 };
 
-static DECLARE_MUTEX(et61x251_sysfs_lock);
+static DEFINE_MUTEX(et61x251_sysfs_lock);
 static DECLARE_RWSEM(et61x251_disconnect);
 
 struct et61x251_device {
 	struct video_device* v4ldev;
 
-	struct et61x251_sensor* sensor;
+	struct et61x251_sensor sensor;
 
 	struct usb_device* usbdev;
 	struct urb* urb[ET61X251_URBS];
@@ -157,19 +161,28 @@ struct et61x251_device {
 	enum et61x251_dev_state state;
 	u8 users;
 
-	struct semaphore dev_sem, fileop_sem;
+	struct mutex dev_mutex, fileop_mutex;
 	spinlock_t queue_lock;
 	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
 et61x251_attach_sensor(struct et61x251_device* cam,
                        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
 #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
 #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,                                                                 \
 };
 
+extern struct et61x251_device*
+et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id);
+
 extern void
 et61x251_attach_sensor(struct et61x251_device* cam,
                        struct et61x251_sensor* sensor);
@@ -105,8 +108,6 @@ struct et61x251_sensor {
 	int (*set_pix_format)(struct et61x251_device* cam,
 	                      const struct v4l2_pix_format* pix);
 
-	const struct usb_device* usbdev;
-
 	/* Private */
 	struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS];
 	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)
 {
-	/* 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 */
-	if (le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x6251)
+	if (!et61x251_match_id(cam, tas5130d1b_id_table))
 		return -ENODEV;
 
+	et61x251_attach_sensor(cam, &tas5130d1b);
+
 	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);
 
-	down(&ov->cbuf_lock);
+	mutex_lock(&ov->cbuf_lock);
 	ov->cbuf[0] = value;
 	rc = usb_control_msg(ov->dev,
 			     usb_sndctrlpipe(ov->dev, 0),
 			     (ov->bclass == BCL_OV518)?1:2 /* REG_IO */,
 			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			     0, (__u16)reg, &ov->cbuf[0], 1, 1000);
-	up(&ov->cbuf_lock);
+	mutex_unlock(&ov->cbuf_lock);
 
 	if (rc < 0)
 		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;
 
-	down(&ov->cbuf_lock);
+	mutex_lock(&ov->cbuf_lock);
 	rc = usb_control_msg(ov->dev,
 			     usb_rcvctrlpipe(ov->dev, 0),
 			     (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]);
 	}
 
-	up(&ov->cbuf_lock);
+	mutex_unlock(&ov->cbuf_lock);
 
 	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);
 
-	down(&ov->cbuf_lock);
+	mutex_lock(&ov->cbuf_lock);
 
 	*((__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 */,
 			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 			     0, (__u16)reg, ov->cbuf, n, 1000);
-	up(&ov->cbuf_lock);
+	mutex_unlock(&ov->cbuf_lock);
 
 	if (rc < 0)
 		err("reg write multiple: error %d: %s", rc,
@@ -768,14 +768,14 @@ i2c_r(struct usb_ov511 *ov, unsigned char reg)
 {
 	int rc;
 
-	down(&ov->i2c_lock);
+	mutex_lock(&ov->i2c_lock);
 
 	if (ov->bclass == BCL_OV518)
 		rc = ov518_i2c_read_internal(ov, reg);
 	else
 		rc = ov511_i2c_read_internal(ov, reg);
 
-	up(&ov->i2c_lock);
+	mutex_unlock(&ov->i2c_lock);
 
 	return rc;
 }
@@ -785,14 +785,14 @@ i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
 {
 	int rc;
 
-	down(&ov->i2c_lock);
+	mutex_lock(&ov->i2c_lock);
 
 	if (ov->bclass == BCL_OV518)
 		rc = ov518_i2c_write_internal(ov, reg, value);
 	else
 		rc = ov511_i2c_write_internal(ov, reg, value);
 
-	up(&ov->i2c_lock);
+	mutex_unlock(&ov->i2c_lock);
 
 	return rc;
 }
@@ -842,9 +842,9 @@ i2c_w_mask(struct usb_ov511 *ov,
 {
 	int rc;
 
-	down(&ov->i2c_lock);
+	mutex_lock(&ov->i2c_lock);
 	rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
-	up(&ov->i2c_lock);
+	mutex_unlock(&ov->i2c_lock);
 
 	return rc;
 }
@@ -880,7 +880,7 @@ i2c_w_slave(struct usb_ov511 *ov,
 {
 	int rc = 0;
 
-	down(&ov->i2c_lock);
+	mutex_lock(&ov->i2c_lock);
 
 	/* Set new slave IDs */
 	rc = i2c_set_slave_internal(ov, slave);
@@ -894,7 +894,7 @@ out:
 	if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
 		err("Couldn't restore primary I2C slave");
 
-	up(&ov->i2c_lock);
+	mutex_unlock(&ov->i2c_lock);
 	return rc;
 }
 
@@ -906,7 +906,7 @@ i2c_r_slave(struct usb_ov511 *ov,
 {
 	int rc;
 
-	down(&ov->i2c_lock);
+	mutex_lock(&ov->i2c_lock);
 
 	/* Set new slave IDs */
 	rc = i2c_set_slave_internal(ov, slave);
@@ -923,7 +923,7 @@ out:
 	if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
 		err("Couldn't restore primary I2C slave");
 
-	up(&ov->i2c_lock);
+	mutex_unlock(&ov->i2c_lock);
 	return rc;
 }
 
@@ -933,7 +933,7 @@ ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
 {
 	int rc;
 
-	down(&ov->i2c_lock);
+	mutex_lock(&ov->i2c_lock);
 
 	rc = i2c_set_slave_internal(ov, sid);
 	if (rc < 0)
@@ -942,7 +942,7 @@ ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
 	// FIXME: Is this actually necessary?
 	rc = ov51x_reset(ov, OV511_RESET_NOREGS);
 out:
-	up(&ov->i2c_lock);
+	mutex_unlock(&ov->i2c_lock);
 	return rc;
 }
 
@@ -3832,7 +3832,7 @@ ov51x_alloc(struct usb_ov511 *ov)
 	const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h);
 
 	PDEBUG(4, "entered");
-	down(&ov->buf_lock);
+	mutex_lock(&ov->buf_lock);
 
 	if (ov->buf_state == BUF_ALLOCATED)
 		goto out;
@@ -3879,12 +3879,12 @@ ov51x_alloc(struct usb_ov511 *ov)
 
 	ov->buf_state = BUF_ALLOCATED;
 out:
-	up(&ov->buf_lock);
+	mutex_unlock(&ov->buf_lock);
 	PDEBUG(4, "leaving");
 	return 0;
 error:
 	ov51x_do_dealloc(ov);
-	up(&ov->buf_lock);
+	mutex_unlock(&ov->buf_lock);
 	PDEBUG(4, "errored");
 	return -ENOMEM;
 }
@@ -3893,9 +3893,9 @@ static void
 ov51x_dealloc(struct usb_ov511 *ov)
 {
 	PDEBUG(4, "entered");
-	down(&ov->buf_lock);
+	mutex_lock(&ov->buf_lock);
 	ov51x_do_dealloc(ov);
-	up(&ov->buf_lock);
+	mutex_unlock(&ov->buf_lock);
 	PDEBUG(4, "leaving");
 }
 
@@ -3914,7 +3914,7 @@ ov51x_v4l1_open(struct inode *inode, struct file *file)
 
 	PDEBUG(4, "opening");
 
-	down(&ov->lock);
+	mutex_lock(&ov->lock);
 
 	err = -EBUSY;
 	if (ov->user)
@@ -3958,7 +3958,7 @@ ov51x_v4l1_open(struct inode *inode, struct file *file)
 		ov51x_led_control(ov, 1);
 
 out:
-	up(&ov->lock);
+	mutex_unlock(&ov->lock);
 	return err;
 }
 
@@ -3970,7 +3970,7 @@ ov51x_v4l1_close(struct inode *inode, struct file *file)
 
 	PDEBUG(4, "ov511_close");
 
-	down(&ov->lock);
+	mutex_lock(&ov->lock);
 
 	ov->user--;
 	ov51x_stop_isoc(ov);
@@ -3981,15 +3981,15 @@ ov51x_v4l1_close(struct inode *inode, struct file *file)
 	if (ov->dev)
 		ov51x_dealloc(ov);
 
-	up(&ov->lock);
+	mutex_unlock(&ov->lock);
 
 	/* Device unplugged while open. Only a minimum of unregistration is done
 	 * here; the disconnect callback already did the rest. */
 	if (!ov->dev) {
-		down(&ov->cbuf_lock);
+		mutex_lock(&ov->cbuf_lock);
 		kfree(ov->cbuf);
 		ov->cbuf = NULL;
-		up(&ov->cbuf_lock);
+		mutex_unlock(&ov->cbuf_lock);
 
 		ov51x_dealloc(ov);
 		kfree(ov);
@@ -4449,12 +4449,12 @@ ov51x_v4l1_ioctl(struct inode *inode, struct file *file,
 	struct usb_ov511 *ov = video_get_drvdata(vdev);
 	int rc;
 
-	if (down_interruptible(&ov->lock))
+	if (mutex_lock_interruptible(&ov->lock))
 		return -EINTR;
 
 	rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal);
 
-	up(&ov->lock);
+	mutex_unlock(&ov->lock);
 	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;
 	struct ov511_frame *frame;
 
-	if (down_interruptible(&ov->lock))
+	if (mutex_lock_interruptible(&ov->lock))
 		return -EINTR;
 
 	PDEBUG(4, "%ld bytes, noblock=%d", count, noblock);
@@ -4604,11 +4604,11 @@ restart:
 
 	PDEBUG(4, "read finished, returning %ld (sweet)", count);
 
-	up(&ov->lock);
+	mutex_unlock(&ov->lock);
 	return count;
 
 error:
-	up(&ov->lock);
+	mutex_unlock(&ov->lock);
 	return rc;
 }
 
@@ -4631,14 +4631,14 @@ ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
 	              + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))))
 		return -EINVAL;
 
-	if (down_interruptible(&ov->lock))
+	if (mutex_lock_interruptible(&ov->lock))
 		return -EINTR;
 
 	pos = (unsigned long)ov->fbuf;
 	while (size > 0) {
 		page = vmalloc_to_pfn((void *)pos);
 		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-			up(&ov->lock);
+			mutex_unlock(&ov->lock);
 			return -EAGAIN;
 		}
 		start += PAGE_SIZE;
@@ -4649,7 +4649,7 @@ ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
 			size = 0;
 	}
 
-	up(&ov->lock);
+	mutex_unlock(&ov->lock);
 	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)
 {
 	struct usb_ov511 *ov = cd_to_ov(cd);
-	unsigned char exp;
+	unsigned char exp = 0;
 
 	if (!ov->dev)
 		return -ENODEV;
@@ -5686,13 +5686,11 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	if (idesc->bInterfaceSubClass != 0x00)
 		return -ENODEV;
 
-	if ((ov = kmalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
+	if ((ov = kzalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
 		err("couldn't kmalloc ov struct");
 		goto error_out;
 	}
 
-	memset(ov, 0, sizeof(*ov));
-
 	ov->dev = dev;
 	ov->iface = idesc->bInterfaceNumber;
 	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_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;
 
@@ -5833,10 +5830,10 @@ error:
 	}
 
 	if (ov->cbuf) {
-		down(&ov->cbuf_lock);
+		mutex_lock(&ov->cbuf_lock);
 		kfree(ov->cbuf);
 		ov->cbuf = NULL;
-		up(&ov->cbuf_lock);
+		mutex_unlock(&ov->cbuf_lock);
 	}
 
 	kfree(ov);
@@ -5881,10 +5878,10 @@ ov51x_disconnect(struct usb_interface *intf)
 
 	/* Free the memory */
 	if (ov && !ov->user) {
-		down(&ov->cbuf_lock);
+		mutex_lock(&ov->cbuf_lock);
 		kfree(ov->cbuf);
 		ov->cbuf = NULL;
-		up(&ov->cbuf_lock);
+		mutex_unlock(&ov->cbuf_lock);
 
 		ov51x_dealloc(ov);
 		kfree(ov);

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

@@ -5,6 +5,7 @@
 #include <linux/videodev.h>
 #include <linux/smp_lock.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 
 #define OV511_DEBUG	/* Turn on debug messages */
 
@@ -435,7 +436,7 @@ struct usb_ov511 {
 
 	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 streaming;		/* Are we streaming Isochronous? */
@@ -473,11 +474,9 @@ struct usb_ov511 {
 	int packet_size;	/* Frame size per isoc desc */
 	int packet_numbering;	/* Is ISO frame numbering enabled? */
 
-	struct semaphore param_lock;	/* params lock for this camera */
-
 	/* Framebuffer/sbuf management */
 	int buf_state;
-	struct semaphore buf_lock;
+	struct mutex buf_lock;
 
 	struct ov51x_decomp_ops *decomp_ops;
 
@@ -494,12 +493,12 @@ struct usb_ov511 {
 	int pal;		/* Device is designed for PAL resolution */
 
 	/* 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 */
 
 	/* Control transaction stuff */
 	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 */

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

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

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

@@ -62,7 +62,6 @@
 #include <linux/poll.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-#include <linux/version.h>
 #include <asm/io.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 */
 	if (!udev->actconfig)
 		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);
 	if (intf)
 		idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
-#endif
 		
 	if (!idesc)
 		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");
 
 	/* 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) {
 		Err("Oops, could not allocate memory for pwc_device.\n");
 		return -ENOMEM;
 	}
-	memset(pdev, 0, sizeof(struct pwc_device));
 	pdev->type = type_id;
 	pdev->vsize = default_size;
 	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 page, pos;
 
-	down(&se401->lock);
+	mutex_lock(&se401->lock);
 
 	if (se401->dev == NULL) {
-		up(&se401->lock);
+		mutex_unlock(&se401->lock);
 		return -EIO;
 	}
 	if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
-		up(&se401->lock);
+		mutex_unlock(&se401->lock);
 		return -EINVAL;
 	}
 	pos = (unsigned long)se401->fbuf;
 	while (size > 0) {
 		page = vmalloc_to_pfn((void *)pos);
 		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-			up(&se401->lock);
+			mutex_unlock(&se401->lock);
 			return -EAGAIN;
 		}
 		start += PAGE_SIZE;
@@ -1181,7 +1181,7 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma)
 		else
 			size = 0;
 	}
-	up(&se401->lock);
+	mutex_unlock(&se401->lock);
 
         return 0;
 }
@@ -1345,13 +1345,11 @@ static int se401_probe(struct usb_interface *intf,
         /* We found one */
         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");
 		return -ENOMEM;
         }
 
-        memset(se401, 0, sizeof(*se401));
-
         se401->dev = dev;
         se401->iface = interface->bInterfaceNumber;
         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.name, se401->camera_name, strlen(se401->camera_name));
 	init_waitqueue_head(&se401->wq);
-	init_MUTEX(&se401->lock);
+	mutex_init(&se401->lock);
 	wmb();
 
 	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 <linux/videodev.h>
 #include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #define se401_DEBUG	/* Turn on debug messages */
 
@@ -189,7 +190,7 @@ struct usb_se401 {
 	int maxframesize;
 	int cframesize;		/* current framesize */
 
-	struct semaphore lock;
+	struct mutex lock;
 	int user;		/* user count for exclusive use */
 	int removed;		/* device disconnected */
 

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

@@ -33,7 +33,9 @@
 #include <linux/types.h>
 #include <linux/param.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"
 
@@ -50,6 +52,7 @@
 #define SN9C102_ALTERNATE_SETTING 8
 #define SN9C102_URB_TIMEOUT       msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
 #define SN9C102_CTRL_TIMEOUT      300
+#define SN9C102_FRAME_TIMEOUT     2
 
 /*****************************************************************************/
 
@@ -107,16 +110,17 @@ struct sn9c102_sysfs_attr {
 
 struct sn9c102_module_param {
 	u8 force_munmap;
+	u16 frame_timeout;
 };
 
-static DECLARE_MUTEX(sn9c102_sysfs_lock);
+static DEFINE_MUTEX(sn9c102_sysfs_lock);
 static DECLARE_RWSEM(sn9c102_disconnect);
 
 struct sn9c102_device {
 	struct video_device* v4ldev;
 
 	enum sn9c102_bridge bridge;
-	struct sn9c102_sensor* sensor;
+	struct sn9c102_sensor sensor;
 
 	struct usb_device* usbdev;
 	struct urb* urb[SN9C102_URBS];
@@ -141,19 +145,28 @@ struct sn9c102_device {
 	enum sn9c102_dev_state state;
 	u8 users;
 
-	struct semaphore dev_sem, fileop_sem;
+	struct mutex dev_mutex, fileop_mutex;
 	spinlock_t queue_lock;
 	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
 sn9c102_attach_sensor(struct sn9c102_device* cam,
                       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
 #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
 #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, 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, 0x16, 0x03);
 	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, 0x1a, 0xf6);
 	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, 0x26, 0xa0);
 	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, 0x2a, 0xa0);
+	err += sn9c102_i2c_write(cam, 0x2b, 0x1f);
 	err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
 	err += sn9c102_i2c_write(cam, 0x30, 0x24);
 	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);
 		break;
 	case V4L2_CID_BLUE_BALANCE:
-		err += sn9c102_i2c_write(cam, 0x03, ctrl->value);
+		err += sn9c102_i2c_write(cam, 0x01, ctrl->value);
 		break;
 	case V4L2_CID_GAIN:
 		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);
 		break;
 	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;
 	case V4L2_CID_AUTOGAIN:
 		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)
 {
+	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;
 
-	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;
 
 	err += sn9c102_write_reg(cam, 0x01, 0x01);
 	err += sn9c102_write_reg(cam, 0x00, 0x01);
 	err += sn9c102_write_reg(cam, 0x28, 0x17);
-
 	if (err)
 		return -EIO;
 
-	err += sn9c102_i2c_write(cam, 0x0b, 0);
+	err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0);
 	if (err)
 		return -ENODEV;
 
+	sn9c102_attach_sensor(cam, &ov7630);
+
 	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 r0 = 0, r1 = 0, err = 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_ov7630(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_tas5110c1b(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_pas202bcb, /* 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_tas5110c1b, /* detection based on USB pid/vid */       \
 	&sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */       \
 	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. */
 extern void 
 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[] = {                      \
 	{ USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */                     \
 	{ USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */                     \
+	{ USB_DEVICE(0x0c45, 0x6007), },                                      \
 	{ USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */                        \
 	{ USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */                        \
 	{ 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, 0x608a, 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, 0x608f, 0xff), }, /* OV7630 */           \
 	{ SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), },                        \
@@ -359,12 +366,6 @@ struct sn9c102_sensor {
 	   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
 	   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)
 {
-	/* 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 */
-	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;
 
+	sn9c102_attach_sensor(cam, &tas5110c1b);
+
 	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)
 {
-	/* 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 */
-	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;
 
+	sn9c102_attach_sensor(cam, &tas5130d1b);
+
 	return 0;
 }

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

@@ -67,6 +67,7 @@
 #include <linux/errno.h>
 #include <linux/videodev.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 
 #include "stv680.h"
 
@@ -317,12 +318,11 @@ static int stv_init (struct usb_stv *stv680)
 	unsigned char *buffer;
 	unsigned long int bufsize;
 
-	buffer = kmalloc (40, GFP_KERNEL);
+	buffer = kzalloc (40, GFP_KERNEL);
 	if (buffer == NULL) {
 		PDEBUG (0, "STV(e): Out of (small buf) memory");
 		return -1;
 	}
-	memset (buffer, 0, 40);
 	udelay (100);
 
 	/* 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 page, pos;
 
-	down (&stv680->lock);
+	mutex_lock(&stv680->lock);
 
 	if (stv680->udev == NULL) {
-		up (&stv680->lock);
+		mutex_unlock(&stv680->lock);
 		return -EIO;
 	}
 	if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1)
 		    & ~(PAGE_SIZE - 1))) {
-		up (&stv680->lock);
+		mutex_unlock(&stv680->lock);
 		return -EINVAL;
 	}
 	pos = (unsigned long) stv680->fbuf;
 	while (size > 0) {
 		page = vmalloc_to_pfn((void *)pos);
 		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-			up (&stv680->lock);
+			mutex_unlock(&stv680->lock);
 			return -EAGAIN;
 		}
 		start += PAGE_SIZE;
@@ -1283,7 +1283,7 @@ static int stv680_mmap (struct file *file, struct vm_area_struct *vma)
 		else
 			size = 0;
 	}
-	up (&stv680->lock);
+	mutex_unlock(&stv680->lock);
 
 	return 0;
 }
@@ -1387,14 +1387,12 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id
 		goto error;
 	}
 	/* 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.");
 		retval = -ENOMEM;
 		goto error;
 	}
 
-	memset (stv680, 0, sizeof (*stv680));
-
 	stv680->udev = dev;
 	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));
 	init_waitqueue_head (&stv680->wq);
-	init_MUTEX (&stv680->lock);
+	mutex_init (&stv680->lock);
 	wmb ();
 
 	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 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 removed;		/* device disconnected */
 	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);
-	cams = (struct usbvideo *) kmalloc(base_size, GFP_KERNEL);
+	cams = (struct usbvideo *) kzalloc(base_size, GFP_KERNEL);
 	if (cams == NULL) {
 		err("Failed to allocate %d. bytes for usbvideo struct", base_size);
 		return -ENOMEM;
 	}
 	dbg("%s: Allocated $%p (%d. bytes) for %d. cameras",
 	    __FUNCTION__, cams, base_size, num_cams);
-	memset(cams, 0, base_size);
 
 	/* Copy callbacks, apply defaults for those that are not set */
 	memmove(&cams->cb, cbTbl, sizeof(cams->cb));
@@ -715,7 +714,7 @@ int usbvideo_register(
 	cams->md_module = md;
 	if (cams->md_module == NULL)
 		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++) {
 		struct uvd *up = &cams->cam[i];
@@ -863,7 +862,7 @@ static void usbvideo_Disconnect(struct usb_interface *intf)
 	if (uvd->debug > 0)
 		info("%s(%p.)", __FUNCTION__, intf);
 
-	down(&uvd->lock);
+	mutex_lock(&uvd->lock);
 	uvd->remove_pending = 1; /* Now all ISO data will be ignored */
 
 	/* 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__);
 	else
 		usbvideo_CameraRelease(uvd);
-	up(&uvd->lock);
+	mutex_unlock(&uvd->lock);
 	info("USB camera disconnected.");
 
 	usbvideo_ClientDecModCount(uvd);
@@ -930,19 +929,19 @@ static int usbvideo_find_struct(struct usbvideo *cams)
 		err("No usbvideo handle?");
 		return -1;
 	}
-	down(&cams->lock);
+	mutex_lock(&cams->lock);
 	for (u = 0; u < cams->num_cameras; u++) {
 		struct uvd *uvd = &cams->cam[u];
 		if (!uvd->uvd_used) /* This one is free */
 		{
 			uvd->uvd_used = 1;	/* In use now */
-			init_MUTEX(&uvd->lock);	/* to 1 == available */
+			mutex_init(&uvd->lock);	/* to 1 == available */
 			uvd->dev = NULL;
 			rv = u;
 			break;
 		}
 	}
-	up(&cams->lock);
+	mutex_unlock(&cams->lock);
 	return rv;
 }
 
@@ -984,7 +983,7 @@ struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams)
 	/* Not relying upon caller we increase module counter ourselves */
 	usbvideo_ClientIncModCount(uvd);
 
-	down(&uvd->lock);
+	mutex_lock(&uvd->lock);
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
 		uvd->sbuf[i].urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
 		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.
 	 */
 allocate_done:
-	up (&uvd->lock);
+	mutex_unlock(&uvd->lock);
 	usbvideo_ClientDecModCount(uvd);
 	return uvd;
 }
@@ -1121,7 +1120,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
 		info("%s($%p)", __FUNCTION__, dev);
 
 	usbvideo_ClientIncModCount(uvd);
-	down(&uvd->lock);
+	mutex_lock(&uvd->lock);
 
 	if (uvd->user) {
 		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)
 		usbvideo_ClientDecModCount(uvd);
 	if (uvd->debug > 0)
@@ -1231,7 +1230,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file)
 	if (uvd->debug > 1)
 		info("%s($%p)", __FUNCTION__, dev);
 
-	down(&uvd->lock);
+	mutex_lock(&uvd->lock);
 	GET_CALLBACK(uvd, stopDataPump)(uvd);
 	usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
 	uvd->fbuf = NULL;
@@ -1252,7 +1251,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file)
 			info("usbvideo_v4l_close: Final disconnect.");
 		usbvideo_CameraRelease(uvd);
 	}
-	up(&uvd->lock);
+	mutex_unlock(&uvd->lock);
 	usbvideo_ClientDecModCount(uvd);
 
 	if (uvd->debug > 1)
@@ -1512,7 +1511,7 @@ static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
 	if (uvd->debug >= 1)
 		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. */
 	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:
-	up(&uvd->lock);	
+	mutex_unlock(&uvd->lock);
 	return count;
 }
 

Некоторые файлы не были показаны из-за большого количества измененных файлов