Signed-off-by: Andrew Morton --- 25-akpm/CREDITS | 2 25-akpm/Documentation/kernel-parameters.txt | 2 25-akpm/Documentation/usb/sn9c102.txt | 109 +++-- 25-akpm/MAINTAINERS | 12 25-akpm/drivers/block/ub.c | 102 ++-- 25-akpm/drivers/net/irda/stir4200.c | 10 25-akpm/drivers/pci/quirks.c | 230 ++++++++++ 25-akpm/drivers/usb/class/Kconfig | 3 25-akpm/drivers/usb/class/audio.c | 37 - 25-akpm/drivers/usb/class/bluetty.c | 12 25-akpm/drivers/usb/class/cdc-acm.c | 29 - 25-akpm/drivers/usb/class/usb-midi.c | 19 25-akpm/drivers/usb/class/usblp.c | 12 25-akpm/drivers/usb/core/devices.c | 18 25-akpm/drivers/usb/core/devio.c | 57 +- 25-akpm/drivers/usb/core/hcd-pci.c | 6 25-akpm/drivers/usb/core/hcd.c | 33 - 25-akpm/drivers/usb/core/hcd.h | 4 25-akpm/drivers/usb/core/hub.c | 397 +++++++++--------- 25-akpm/drivers/usb/core/inode.c | 121 ----- 25-akpm/drivers/usb/core/message.c | 16 25-akpm/drivers/usb/core/sysfs.c | 4 25-akpm/drivers/usb/core/urb.c | 5 25-akpm/drivers/usb/core/usb.c | 195 ++++++++- 25-akpm/drivers/usb/core/usb.h | 10 25-akpm/drivers/usb/gadget/dummy_hcd.c | 39 + 25-akpm/drivers/usb/gadget/ether.c | 6 25-akpm/drivers/usb/gadget/file_storage.c | 39 + 25-akpm/drivers/usb/gadget/gadget_chips.h | 6 25-akpm/drivers/usb/gadget/net2280.c | 19 25-akpm/drivers/usb/gadget/omap_udc.c | 144 +++--- 25-akpm/drivers/usb/gadget/omap_udc.h | 11 25-akpm/drivers/usb/gadget/zero.c | 2 25-akpm/drivers/usb/host/ehci-hcd.c | 14 25-akpm/drivers/usb/host/ehci-hub.c | 2 25-akpm/drivers/usb/host/ehci.h | 1 25-akpm/drivers/usb/host/hc_sl811.c | 8 25-akpm/drivers/usb/host/ohci-dbg.c | 4 25-akpm/drivers/usb/host/ohci-hcd.c | 241 +++++++---- 25-akpm/drivers/usb/host/ohci-hub.c | 63 +- 25-akpm/drivers/usb/host/ohci-lh7a404.c | 30 - 25-akpm/drivers/usb/host/ohci-omap.c | 30 - 25-akpm/drivers/usb/host/ohci-pci.c | 44 -- 25-akpm/drivers/usb/host/ohci-sa1111.c | 25 - 25-akpm/drivers/usb/host/ohci.h | 34 + 25-akpm/drivers/usb/host/uhci-hcd.c | 253 +++-------- 25-akpm/drivers/usb/host/uhci-hcd.h | 18 25-akpm/drivers/usb/host/uhci-hub.c | 140 ++++-- 25-akpm/drivers/usb/image/Kconfig | 7 25-akpm/drivers/usb/image/hpusbscsi.c | 12 25-akpm/drivers/usb/image/mdc800.c | 14 25-akpm/drivers/usb/image/microtek.c | 17 25-akpm/drivers/usb/image/microtek.h | 1 25-akpm/drivers/usb/input/aiptek.c | 4 25-akpm/drivers/usb/input/ati_remote.c | 6 25-akpm/drivers/usb/input/hid-core.c | 9 25-akpm/drivers/usb/input/kbtab.c | 4 25-akpm/drivers/usb/input/mtouchusb.c | 4 25-akpm/drivers/usb/input/pid.c | 2 25-akpm/drivers/usb/input/powermate.c | 2 25-akpm/drivers/usb/input/touchkitusb.c | 4 25-akpm/drivers/usb/input/usbkbd.c | 4 25-akpm/drivers/usb/input/usbmouse.c | 4 25-akpm/drivers/usb/input/wacom.c | 4 25-akpm/drivers/usb/input/xpad.c | 4 25-akpm/drivers/usb/media/Kconfig | 6 25-akpm/drivers/usb/media/dabusb.c | 6 25-akpm/drivers/usb/media/konicawc.c | 11 25-akpm/drivers/usb/media/ov511.c | 2 25-akpm/drivers/usb/media/se401.c | 6 25-akpm/drivers/usb/media/sn9c102.h | 19 25-akpm/drivers/usb/media/sn9c102_core.c | 148 +++++- 25-akpm/drivers/usb/media/sn9c102_pas106b.c | 14 25-akpm/drivers/usb/media/sn9c102_pas202bcb.c | 21 25-akpm/drivers/usb/media/sn9c102_sensor.h | 61 ++ 25-akpm/drivers/usb/media/sn9c102_tas5110c1b.c | 45 +- 25-akpm/drivers/usb/media/sn9c102_tas5130d1b.c | 60 ++ 25-akpm/drivers/usb/media/stv680.c | 4 25-akpm/drivers/usb/media/usbvideo.c | 4 25-akpm/drivers/usb/misc/speedtch.c | 49 -- 25-akpm/drivers/usb/misc/tiglusb.c | 1 25-akpm/drivers/usb/net/kaweth.c | 2 25-akpm/drivers/usb/net/rtl8150.c | 10 25-akpm/drivers/usb/net/usbnet.c | 17 25-akpm/drivers/usb/serial/belkin_sa.c | 8 25-akpm/drivers/usb/serial/cyberjack.c | 6 25-akpm/drivers/usb/serial/digi_acceleport.c | 13 25-akpm/drivers/usb/serial/empeg.c | 8 25-akpm/drivers/usb/serial/ftdi_sio.c | 21 25-akpm/drivers/usb/serial/ftdi_sio.h | 8 25-akpm/drivers/usb/serial/generic.c | 4 25-akpm/drivers/usb/serial/io_edgeport.c | 6 25-akpm/drivers/usb/serial/io_ti.c | 6 25-akpm/drivers/usb/serial/ipaq.c | 23 - 25-akpm/drivers/usb/serial/ir-usb.c | 2 25-akpm/drivers/usb/serial/keyspan_pda.c | 6 25-akpm/drivers/usb/serial/kl5kusb105.c | 12 25-akpm/drivers/usb/serial/kobil_sct.c | 14 25-akpm/drivers/usb/serial/mct_u232.c | 6 25-akpm/drivers/usb/serial/omninet.c | 4 25-akpm/drivers/usb/serial/pl2303.c | 430 +++++++++++++++++--- 25-akpm/drivers/usb/serial/usb-serial.c | 53 +- 25-akpm/drivers/usb/serial/visor.c | 6 25-akpm/drivers/usb/serial/whiteheat.c | 8 25-akpm/drivers/usb/storage/isd200.c | 6 25-akpm/drivers/usb/storage/protocol.c | 49 -- 25-akpm/drivers/usb/storage/scsiglue.c | 31 + 25-akpm/drivers/usb/storage/unusual_devs.h | 33 - 25-akpm/include/asm-i386/mach-summit/mach_mpparse.h | 3 25-akpm/include/linux/usb.h | 29 + 25-akpm/include/linux/usbdevice_fs.h | 10 111 files changed, 2461 insertions(+), 1550 deletions(-) diff -puN CREDITS~bk-usb CREDITS --- 25/CREDITS~bk-usb 2004-09-23 21:23:38.237495256 -0700 +++ 25-akpm/CREDITS 2004-09-23 21:23:38.601439928 -0700 @@ -2764,7 +2764,7 @@ N: Luca Risolia 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 SN9C10[12] PC Camera Controllers +D: V4L2 driver for SN9C10x PC Camera Controllers S: Via Liberta' 41/A S: Osio Sotto, 24046, Bergamo S: Italy diff -puN Documentation/kernel-parameters.txt~bk-usb Documentation/kernel-parameters.txt --- 25/Documentation/kernel-parameters.txt~bk-usb 2004-09-23 21:23:38.238495104 -0700 +++ 25-akpm/Documentation/kernel-parameters.txt 2004-09-23 21:23:38.603439624 -0700 @@ -1304,6 +1304,8 @@ running once the system is up. uart6850= [HW,OSS] Format: , + + usb-handoff [HW] Enable early USB BIOS -> OS handoff video= [FB] Frame buffer configuration See Documentation/fb/modedb.txt. diff -puN Documentation/usb/sn9c102.txt~bk-usb Documentation/usb/sn9c102.txt --- 25/Documentation/usb/sn9c102.txt~bk-usb 2004-09-23 21:23:38.240494800 -0700 +++ 25-akpm/Documentation/usb/sn9c102.txt 2004-09-23 21:23:38.605439320 -0700 @@ -1,7 +1,7 @@ - SN9C10[12] PC Camera Controllers + SN9C10x PC Camera Controllers Driver for Linux - ================================ + ============================= - Documentation - @@ -49,22 +49,23 @@ Foundation, Inc., 675 Mass Ave, Cambridg 3. Overview =========== -This driver attempts to support the video streaming capabilities of the devices -mounting the SONiX SN9C101 or SONiX SN9C102 PC Camera Controllers. +This driver attempts to support the video and audio streaming capabilities of +the devices mounting the SONiX SN9C101, SN9C102 and SN9C103 (or SUI-102) PC +Camera Controllers. - It's worth to note that SONiX has never collaborated with me during the -development of this project, despite of several requests for enough detailed +development of this project, despite several requests for enough detailed specifications of the register tables, compression engine and video data format of the above chips - 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 -your system supports the hotplug facility. +your system supports hotplugging. 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 SN9C10[12] driver can be found at the following URL: +The latest version of the SN9C10x driver can be found at the following URL: http://go.lamarinapunto.com/ @@ -122,12 +123,12 @@ analyze kernel messages and verify that Module parameters are listed below: ------------------------------------------------------------------------------- Name: video_nr -Type: int array (min = 0, max = 32) +Type: int 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 32 cameras this way. + You can specify up to 64 cameras this way. For example: video_nr=-1,2,-1 would assign minor number 2 to the second recognized camera and use auto for the first one and for every @@ -150,17 +151,20 @@ Default: 2 7. Optional device control through "sysfs" ========================================== -It is possible to read and write both the SN9C10[12] and the image sensor +It is possible to read and write both the SN9C10x and the image sensor registers by using the "sysfs" filesystem interface. -Every time a supported device is recognized, a read-only file named "green" is +Every time a supported device is recognized, a write-only file named "green" is created in the /sys/class/video4linux/videoX directory. You can set the green channel's gain by writing the desired value to it. The value may range from 0 -to 15. +to 15 for SN9C101 or SN9C102 bridges, from 0 to 127 for SN9C103 bridges. +Similarly, only for SN9C103 controllers, blue and red gain control files are +available in the same directory, for which accepted values may range from 0 to +127. There are other four entries in the directory above for each registered camera: "reg", "val", "i2c_reg" and "i2c_val". The first two files control the -SN9C10[12] bridge, while the other two control the sensor chip. "reg" and +SN9C10x bridge, while the other two control the sensor chip. "reg" and "i2c_reg" hold the values of the current register index where the following reading/writing operations are addressed at through "val" and "i2c_val". Their use is not intended for end-users, unless you know what you are doing. Note @@ -169,19 +173,21 @@ support the standard I2C protocol. Also, root before writing to them. As an example, suppose we were to want to read the value contained in the -register number 1 of the sensor register table - which usually is the product +register number 1 of the sensor register table - which is usually the product identifier - of the camera registered as "/dev/video0": [root@localhost #] cd /sys/class/video4linux/video0 [root@localhost #] echo 1 > i2c_reg [root@localhost #] cat i2c_val -Now let's set the green gain's register of the SN9C10[12] chip to 2: +Note that "cat" will fail if sensor registers cannot be read. + +Now let's set the green gain's register of the SN9C101 or SN9C102 chips to 2: [root@localhost #] echo 0x11 > reg [root@localhost #] echo 2 > val -Note that the SN9C10[12] always returns 0 when some of its registers are read. +Note that the SN9C10x always returns 0 when some of its registers are read. To avoid race conditions, all the I/O accesses to the files are serialized. @@ -192,25 +198,52 @@ here. They have never collaborated with 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 SN9C10[12] PC camera controllers: +devices mounting the SN9C10x PC camera controllers: Vendor ID Product ID --------- ---------- -0xc45 0x6001 -0xc45 0x6005 -0xc45 0x6009 -0xc45 0x600d -0xc45 0x6024 -0xc45 0x6025 -0xc45 0x6028 -0xc45 0x6029 -0xc45 0x602a -0xc45 0x602c -0xc45 0x6030 +0x0c45 0x6001 +0x0c45 0x6005 +0x0c45 0x6009 +0x0c45 0x600d +0x0c45 0x6024 +0x0c45 0x6025 +0x0c45 0x6028 +0x0c45 0x6029 +0x0c45 0x602a +0x0c45 0x602b +0x0c45 0x602c +0x0c45 0x6030 +0x0c45 0x6080 +0x0c45 0x6082 +0x0c45 0x6083 +0x0c45 0x6088 +0x0c45 0x608a +0x0c45 0x608b +0x0c45 0x608c +0x0c45 0x608e +0x0c45 0x608f +0x0c45 0x60a0 +0x0c45 0x60a2 +0x0c45 0x60a3 +0x0c45 0x60a8 +0x0c45 0x60aa +0x0c45 0x60ab +0x0c45 0x60ac +0x0c45 0x60ae +0x0c45 0x60af +0x0c45 0x60b0 +0x0c45 0x60b2 +0x0c45 0x60b3 +0x0c45 0x60b8 +0x0c45 0x60ba +0x0c45 0x60bb +0x0c45 0x60bc +0x0c45 0x60be 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: +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 ----- ------------ @@ -219,12 +252,15 @@ PAS202BCB PixArt Imaging Inc. TAS5110C1B Taiwan Advanced Sensor Corporation TAS5130D1B Taiwan Advanced Sensor Corporation +All the available control settings of each image sensor are supported through +the V4L2 interface. + If you think your camera is based on the above hardware and is not actually listed in the above table, you may try to add the specific USB VendorID and ProductID identifiers to the sn9c102_id_table[] in the file "sn9c102_sensor.h"; then compile, load the module again and look at the kernel output. If this works, please send an email to me reporting the kernel messages, so -that I will add a new entry in the list of supported devices. +that I can add a new entry in the list of supported devices. Donations of new models for further testing and support would be much appreciated. I won't add official support for hardware that I don't actually @@ -238,8 +274,8 @@ have created for this purpose, which is (documentation is included there). As an example, have a look at the code in "sn9c102_pas106b.c", which uses the mentioned interface. -At the moment, not yet supported image sensors are: HV7131[D|E1] (VGA), -MI03 (VGA), OV7620 (VGA). +At the moment, possible unsupported image sensors are: HV7131x series (VGA), +MI03x series (VGA), OV7620 (VGA), OV7630 (VGA), CIS-VF10 (VGA). 10. Notes for V4L2 application developers @@ -254,12 +290,13 @@ device to switch to the other I/O method - previously mapped buffer memory must always be unmapped before calling any of the "VIDIOC_S_CROP", "VIDIOC_TRY_FMT" and "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 them again before any I/O attempts. +new video frames, so you have to map the buffers again before any I/O attempts +on them. Consistently with the hardware limits, this driver also supports image downscaling with arbitrary scaling factors from 1, 2 and 4 in both directions. -However the V4L2 API specifications don't correctly define how the scaling -factor can be choosen arbitrarily by the "negotiation" of the "source" and +However, the V4L2 API specifications don't correctly define how the scaling +factor can be chosen arbitrarily by the "negotiation" of the "source" and "target" rectangles. To work around this flaw, we have added the convention that, during the negotiation, whenever the "VIDIOC_S_CROP" ioctl is issued, the scaling factor is restored to 1. diff -puN drivers/block/ub.c~bk-usb drivers/block/ub.c --- 25/drivers/block/ub.c~bk-usb 2004-09-23 21:23:38.242494496 -0700 +++ 25-akpm/drivers/block/ub.c 2004-09-23 21:23:38.609438712 -0700 @@ -490,6 +490,18 @@ static void ub_id_put(int id) */ static void ub_cleanup(struct ub_dev *sc) { + + /* + * If we zero disk->private_data BEFORE put_disk, we have to check + * for NULL all over the place in open, release, check_media and + * revalidate, because the block level semaphore is well inside the + * put_disk. But we cannot zero after the call, because *disk is gone. + * The sd.c is blatantly racy in this area. + */ + /* disk->private_data = NULL; */ + put_disk(sc->disk); + sc->disk = NULL; + ub_id_put(sc->id); kfree(sc); } @@ -786,17 +798,16 @@ static int ub_scsi_cmd_start(struct ub_d sc->work_urb.error_count = 0; sc->work_urb.status = 0; - sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; - add_timer(&sc->work_timer); - if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { /* XXX Clear stalls */ printk("ub: cmd #%d start failed (%d)\n", cmd->tag, rc); /* P3 */ - del_timer(&sc->work_timer); ub_complete(&sc->work_done); return rc; } + sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; + add_timer(&sc->work_timer); + cmd->state = UB_CMDST_CMD; ub_cmdtr_state(sc, cmd); return 0; @@ -968,18 +979,17 @@ static void ub_scsi_urb_compl(struct ub_ sc->work_urb.error_count = 0; sc->work_urb.status = 0; - sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; - add_timer(&sc->work_timer); - if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { /* XXX Clear stalls */ printk("ub: data #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */ - del_timer(&sc->work_timer); ub_complete(&sc->work_done); ub_state_done(sc, cmd, rc); return; } + sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; + add_timer(&sc->work_timer); + cmd->state = UB_CMDST_DATA; ub_cmdtr_state(sc, cmd); @@ -1063,19 +1073,18 @@ static void ub_scsi_urb_compl(struct ub_ sc->work_urb.error_count = 0; sc->work_urb.status = 0; - sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; - add_timer(&sc->work_timer); - rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC); if (rc != 0) { /* XXX Clear stalls */ printk("%s: CSW #%d submit failed (%d)\n", sc->name, cmd->tag, rc); /* P3 */ - del_timer(&sc->work_timer); ub_complete(&sc->work_done); ub_state_done(sc, cmd, rc); return; } + + sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; + add_timer(&sc->work_timer); return; } @@ -1186,18 +1195,17 @@ static void ub_state_stat(struct ub_dev sc->work_urb.error_count = 0; sc->work_urb.status = 0; - sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; - add_timer(&sc->work_timer); - if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { /* XXX Clear stalls */ printk("ub: CSW #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */ - del_timer(&sc->work_timer); ub_complete(&sc->work_done); ub_state_done(sc, cmd, rc); return; } + sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; + add_timer(&sc->work_timer); + cmd->stat_count = 0; cmd->state = UB_CMDST_STAT; ub_cmdtr_state(sc, cmd); @@ -1217,9 +1225,17 @@ static void ub_state_sense(struct ub_dev goto error; } + /* + * ``If the allocation length is eighteen or greater, and a device + * server returns less than eithteen bytes of data, the application + * client should assume that the bytes not transferred would have been + * zeroes had the device server returned those bytes.'' + */ memset(&sc->top_sense, 0, UB_SENSE_SIZE); + scmd = &sc->top_rqs_cmd; scmd->cdb[0] = REQUEST_SENSE; + scmd->cdb[4] = UB_SENSE_SIZE; scmd->cdb_len = 6; scmd->dir = UB_DIR_READ; scmd->state = UB_CMDST_INIT; @@ -1271,14 +1287,13 @@ static int ub_submit_clear_stall(struct sc->work_urb.error_count = 0; sc->work_urb.status = 0; - sc->work_timer.expires = jiffies + UB_CTRL_TIMEOUT; - add_timer(&sc->work_timer); - if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { - del_timer(&sc->work_timer); ub_complete(&sc->work_done); return rc; } + + sc->work_timer.expires = jiffies + UB_CTRL_TIMEOUT; + add_timer(&sc->work_timer); return 0; } @@ -1289,6 +1304,9 @@ static void ub_top_sense_done(struct ub_ unsigned char *sense = scmd->data; struct ub_scsi_cmd *cmd; + /* + * Ignoring scmd->act_len, because the buffer was pre-zeroed. + */ ub_cmdtr_sense(sc, scmd, sense); if ((cmd = ub_cmdq_peek(sc)) == NULL) { @@ -1407,7 +1425,15 @@ static int ub_bd_open(struct inode *inod if (sc->removable || sc->readonly) check_disk_change(inode->i_bdev); - /* XXX sd.c and floppy.c bail on open if media is not present. */ + /* + * The sd.c considers ->media_present and ->changed not equivalent, + * under some pretty murky conditions (a failure of READ CAPACITY). + * We may need it one day. + */ + if (sc->removable && sc->changed && !(filp->f_flags & O_NDELAY)) { + rc = -ENOMEDIUM; + goto err_open; + } if (sc->readonly && (filp->f_mode & FMODE_WRITE)) { rc = -EROFS; @@ -1492,8 +1518,11 @@ static int ub_bd_revalidate(struct gendi printk(KERN_INFO "%s: device %u capacity nsec %ld bsize %u\n", sc->name, sc->dev->devnum, sc->capacity.nsec, sc->capacity.bsize); + /* XXX Support sector size switching like in sr.c */ + // blk_queue_hardsect_size(q, sc->capacity.bsize); set_capacity(disk, sc->capacity.nsec); // set_disk_ro(sdkp->disk, sc->readonly); + return 0; } @@ -1725,28 +1754,22 @@ static int ub_probe_clear_stall(struct u sc->work_urb.error_count = 0; sc->work_urb.status = 0; - init_timer(&timer); - timer.function = ub_probe_timeout; - timer.data = (unsigned long) &compl; - timer.expires = jiffies + UB_CTRL_TIMEOUT; - add_timer(&timer); - if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) { printk(KERN_WARNING "%s: Unable to submit a probe clear (%d)\n", sc->name, rc); - del_timer_sync(&timer); return rc; } + init_timer(&timer); + timer.function = ub_probe_timeout; + timer.data = (unsigned long) &compl; + timer.expires = jiffies + UB_CTRL_TIMEOUT; + add_timer(&timer); + wait_for_completion(&compl); del_timer_sync(&timer); - /* - * Most of the time, URB was done and dev set to NULL, and so - * the unlink bounces out with ENODEV. We do not call usb_kill_urb - * because we still think about a backport to 2.4. - */ - usb_unlink_urb(&sc->work_urb); + usb_kill_urb(&sc->work_urb); /* reset the endpoint toggle */ usb_settoggle(sc->dev, endp, usb_pipeout(sc->last_pipe), 0); @@ -2006,17 +2029,6 @@ static void ub_disconnect(struct usb_int blk_cleanup_queue(q); /* - * If we zero disk->private_data BEFORE put_disk, we have to check - * for NULL all over the place in open, release, check_media and - * revalidate, because the block level semaphore is well inside the - * put_disk. But we cannot zero after the call, because *disk is gone. - * The sd.c is blatantly racy in this area. - */ - /* disk->private_data = NULL; */ - put_disk(disk); - sc->disk = NULL; - - /* * We really expect blk_cleanup_queue() to wait, so no amount * of paranoya is too much. * diff -puN drivers/net/irda/stir4200.c~bk-usb drivers/net/irda/stir4200.c --- 25/drivers/net/irda/stir4200.c~bk-usb 2004-09-23 21:23:38.244494192 -0700 +++ 25-akpm/drivers/net/irda/stir4200.c 2004-09-23 21:23:38.610438560 -0700 @@ -168,6 +168,7 @@ enum StirTestMask { struct stir_cb { struct usb_device *usbdev; /* init: probe_irda */ + struct usb_interface *usbintf; struct net_device *netdev; /* network layer */ struct irlap_cb *irlap; /* The link layer we are binded to */ struct net_device_stats stats; /* network statistics */ @@ -508,6 +509,7 @@ static int change_speed(struct stir_cb * { int i, err; __u8 mode; + int rc; for (i = 0; i < ARRAY_SIZE(stir_modes); ++i) { if (speed == stir_modes[i].speed) @@ -521,7 +523,14 @@ static int change_speed(struct stir_cb * pr_debug("speed change from %d to %d\n", stir->speed, speed); /* sometimes needed to get chip out of stuck state */ + rc = usb_lock_device_for_reset(stir->usbdev, stir->usbintf); + if (rc < 0) { + err = rc; + goto out; + } err = usb_reset_device(stir->usbdev); + if (rc) + usb_unlock_device(stir->usbdev); if (err) goto out; @@ -1066,6 +1075,7 @@ static int stir_probe(struct usb_interfa stir = net->priv; stir->netdev = net; stir->usbdev = dev; + stir->usbintf = intf; ret = usb_reset_configuration(dev); if (ret != 0) { diff -puN drivers/pci/quirks.c~bk-usb drivers/pci/quirks.c --- 25/drivers/pci/quirks.c~bk-usb 2004-09-23 21:23:38.245494040 -0700 +++ 25-akpm/drivers/pci/quirks.c 2004-09-23 21:23:38.613438104 -0700 @@ -829,6 +829,236 @@ static void __init quirk_sis_96x_smbus(s pci_read_config_byte(dev, 0x77, &val); } + +#define UHCI_USBLEGSUP 0xc0 /* legacy support */ +#define UHCI_USBCMD 0 /* command register */ +#define UHCI_USBSTS 2 /* status register */ +#define UHCI_USBINTR 4 /* interrupt register */ +#define UHCI_USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */ +#define UHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */ +#define UHCI_USBCMD_GRESET (1 << 2) /* Global reset */ +#define UHCI_USBCMD_CONFIGURE (1 << 6) /* config semaphore */ +#define UHCI_USBSTS_HALTED (1 << 5) /* HCHalted bit */ + +#define OHCI_CONTROL 0x04 +#define OHCI_CMDSTATUS 0x08 +#define OHCI_INTRSTATUS 0x0c +#define OHCI_INTRENABLE 0x10 +#define OHCI_INTRDISABLE 0x14 +#define OHCI_OCR (1 << 3) /* ownership change request */ +#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ +#define OHCI_INTR_OC (1 << 30) /* ownership change */ + +#define EHCI_HCC_PARAMS 0x08 /* extended capabilities */ +#define EHCI_USBCMD 0 /* command register */ +#define EHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */ +#define EHCI_USBSTS 4 /* status register */ +#define EHCI_USBSTS_HALTED (1 << 12) /* HCHalted bit */ +#define EHCI_USBINTR 8 /* interrupt register */ +#define EHCI_USBLEGSUP 0 /* legacy support register */ +#define EHCI_USBLEGSUP_BIOS (1 << 16) /* BIOS semaphore */ +#define EHCI_USBLEGSUP_OS (1 << 24) /* OS semaphore */ +#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */ +#define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */ + +int usb_early_handoff __initdata = 0; +static int __init usb_handoff_early(char *str) +{ + usb_early_handoff = 1; + return 0; +} +__setup("usb-handoff", usb_handoff_early); + +static void __init quirk_usb_handoff_uhci(struct pci_dev *pdev) +{ + unsigned long base = 0; + int wait_time, delta; + u16 val, sts; + int i; + + for (i = 0; i < PCI_ROM_RESOURCE; i++) + if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) { + base = pci_resource_start(pdev, i); + break; + } + + if (!base) + return; + + /* + * stop controller + */ + sts = inw(base + UHCI_USBSTS); + val = inw(base + UHCI_USBCMD); + val &= ~(u16)(UHCI_USBCMD_RUN | UHCI_USBCMD_CONFIGURE); + outw(val, base + UHCI_USBCMD); + + /* + * wait while it stops if it was running + */ + if ((sts & UHCI_USBSTS_HALTED) == 0) + { + wait_time = 1000; + delta = 100; + + do { + outw(0x1f, base + UHCI_USBSTS); + udelay(delta); + wait_time -= delta; + val = inw(base + UHCI_USBSTS); + if (val & UHCI_USBSTS_HALTED) + break; + } while (wait_time > 0); + } + + /* + * disable interrupts & legacy support + */ + outw(0, base + UHCI_USBINTR); + outw(0x1f, base + UHCI_USBSTS); + pci_read_config_word(pdev, UHCI_USBLEGSUP, &val); + if (val & 0xbf) + pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT); + +} + +static void __init quirk_usb_handoff_ohci(struct pci_dev *pdev) +{ + void __iomem *base; + int wait_time; + + base = ioremap_nocache(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (base == NULL) return; + + if (readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) { + wait_time = 500; /* 0.5 seconds */ + writel(OHCI_INTR_OC, base + OHCI_INTRENABLE); + writel(OHCI_OCR, base + OHCI_CMDSTATUS); + while (wait_time > 0 && + readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) { + wait_time -= 10; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((HZ*10 + 999) / 1000); + } + } + + /* + * disable interrupts + */ + writel(~(u32)0, base + OHCI_INTRDISABLE); + writel(~(u32)0, base + OHCI_INTRSTATUS); + + iounmap(base); +} + +static void __init quirk_usb_disable_ehci(struct pci_dev *pdev) +{ + int wait_time, delta; + void __iomem *base, *op_reg_base; + u32 hcc_params, val, temp; + u8 cap_length; + + base = ioremap_nocache(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (base == NULL) return; + + cap_length = readb(base); + op_reg_base = base + cap_length; + hcc_params = readl(base + EHCI_HCC_PARAMS); + hcc_params = (hcc_params >> 8) & 0xff; + if (hcc_params) { + pci_read_config_dword(pdev, + hcc_params + EHCI_USBLEGSUP, + &val); + if (((val & 0xff) == 1) && (val & EHCI_USBLEGSUP_BIOS)) { + /* + * Ok, BIOS is in smm mode, try to hand off... + */ + pci_read_config_dword(pdev, + hcc_params + EHCI_USBLEGCTLSTS, + &temp); + pci_write_config_dword(pdev, + hcc_params + EHCI_USBLEGCTLSTS, + temp | EHCI_USBLEGCTLSTS_SOOE); + val |= EHCI_USBLEGSUP_OS; + pci_write_config_dword(pdev, + hcc_params + EHCI_USBLEGSUP, + val); + + wait_time = 500; + do { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((HZ*10+999)/1000); + wait_time -= 10; + pci_read_config_dword(pdev, + hcc_params + EHCI_USBLEGSUP, + &val); + } while (wait_time && (val & EHCI_USBLEGSUP_BIOS)); + if (!wait_time) { + /* + * well, possibly buggy BIOS... + */ + printk(KERN_WARNING "EHCI early BIOS handoff " + "failed (BIOS bug ?)\n"); + pci_write_config_dword(pdev, + hcc_params + EHCI_USBLEGSUP, + EHCI_USBLEGSUP_OS); + pci_write_config_dword(pdev, + hcc_params + EHCI_USBLEGCTLSTS, + 0); + } + } + } + + /* + * halt EHCI & disable its interrupts in any case + */ + val = readl(op_reg_base + EHCI_USBSTS); + if ((val & EHCI_USBSTS_HALTED) == 0) { + val = readl(op_reg_base + EHCI_USBCMD); + val &= ~EHCI_USBCMD_RUN; + writel(val, op_reg_base + EHCI_USBCMD); + + wait_time = 2000; + delta = 100; + do { + writel(0x3f, op_reg_base + EHCI_USBSTS); + udelay(delta); + wait_time -= delta; + val = readl(op_reg_base + EHCI_USBSTS); + if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) { + break; + } + } while (wait_time > 0); + } + writel(0, op_reg_base + EHCI_USBINTR); + writel(0x3f, op_reg_base + EHCI_USBSTS); + + iounmap(base); + + return; +} + + + +static void __init quirk_usb_early_handoff(struct pci_dev *pdev) +{ + if (!usb_early_handoff) + return; + + if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x00)) { /* UHCI */ + quirk_usb_handoff_uhci(pdev); + } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) { /* OHCI */ + quirk_usb_handoff_ohci(pdev); + } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x20)) { /* EHCI */ + quirk_usb_disable_ehci(pdev); + } + + return; +} +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff); + /* * ... This is further complicated by the fact that some SiS96x south * bridges pretend to be 85C503/5513 instead. In that case see if we diff -puN drivers/usb/class/audio.c~bk-usb drivers/usb/class/audio.c --- 25/drivers/usb/class/audio.c~bk-usb 2004-09-23 21:23:38.247493736 -0700 +++ 25-akpm/drivers/usb/class/audio.c 2004-09-23 21:23:38.617437496 -0700 @@ -635,13 +635,13 @@ static void usbin_stop(struct usb_audiod spin_unlock_irqrestore(&as->lock, flags); if (notkilled && signal_pending(current)) { if (i & FLG_URB0RUNNING) - usb_unlink_urb(u->durb[0].urb); + usb_kill_urb(u->durb[0].urb); if (i & FLG_URB1RUNNING) - usb_unlink_urb(u->durb[1].urb); + usb_kill_urb(u->durb[1].urb); if (i & FLG_SYNC0RUNNING) - usb_unlink_urb(u->surb[0].urb); + usb_kill_urb(u->surb[0].urb); if (i & FLG_SYNC1RUNNING) - usb_unlink_urb(u->surb[1].urb); + usb_kill_urb(u->surb[1].urb); notkilled = 0; } } @@ -1114,13 +1114,13 @@ static void usbout_stop(struct usb_audio spin_unlock_irqrestore(&as->lock, flags); if (notkilled && signal_pending(current)) { if (i & FLG_URB0RUNNING) - usb_unlink_urb(u->durb[0].urb); + usb_kill_urb(u->durb[0].urb); if (i & FLG_URB1RUNNING) - usb_unlink_urb(u->durb[1].urb); + usb_kill_urb(u->durb[1].urb); if (i & FLG_SYNC0RUNNING) - usb_unlink_urb(u->surb[0].urb); + usb_kill_urb(u->surb[0].urb); if (i & FLG_SYNC1RUNNING) - usb_unlink_urb(u->surb[1].urb); + usb_kill_urb(u->surb[1].urb); notkilled = 0; } } @@ -1949,15 +1949,12 @@ static inline int prog_dmabuf_out(struct static int usb_audio_open_mixdev(struct inode *inode, struct file *file) { unsigned int minor = iminor(inode); - struct list_head *devs, *mdevs; struct usb_mixerdev *ms; struct usb_audio_state *s; down(&open_sem); - list_for_each(devs, &audiodevs) { - s = list_entry(devs, struct usb_audio_state, audiodev); - list_for_each(mdevs, &s->mixerlist) { - ms = list_entry(mdevs, struct usb_mixerdev, list); + list_for_each_entry(s, &audiodevs, audiodev) { + list_for_each_entry(ms, &s->mixerlist, list) { if (ms->dev_mixer == minor) goto mixer_found; } @@ -2634,16 +2631,13 @@ static int usb_audio_open(struct inode * { unsigned int minor = iminor(inode); DECLARE_WAITQUEUE(wait, current); - struct list_head *devs, *adevs; struct usb_audiodev *as; struct usb_audio_state *s; for (;;) { down(&open_sem); - list_for_each(devs, &audiodevs) { - s = list_entry(devs, struct usb_audio_state, audiodev); - list_for_each(adevs, &s->audiolist) { - as = list_entry(adevs, struct usb_audiodev, list); + list_for_each_entry(s, &audiodevs, audiodev) { + list_for_each_entry(as, &s->audiolist, list) { if (!((as->dev_audio ^ minor) & ~0xf)) goto device_found; } @@ -3809,7 +3803,6 @@ static int usb_audio_probe(struct usb_in static void usb_audio_disconnect(struct usb_interface *intf) { struct usb_audio_state *s = usb_get_intfdata (intf); - struct list_head *list; struct usb_audiodev *as; struct usb_mixerdev *ms; @@ -3831,8 +3824,7 @@ static void usb_audio_disconnect(struct usb_set_intfdata (intf, NULL); /* deregister all audio and mixer devices, so no new processes can open this device */ - list_for_each(list, &s->audiolist) { - as = list_entry(list, struct usb_audiodev, list); + list_for_each_entry(as, &s->audiolist, list) { usbin_disc(as); usbout_disc(as); wake_up(&as->usbin.dma.wait); @@ -3843,8 +3835,7 @@ static void usb_audio_disconnect(struct } as->dev_audio = -1; } - list_for_each(list, &s->mixerlist) { - ms = list_entry(list, struct usb_mixerdev, list); + 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); diff -puN drivers/usb/class/bluetty.c~bk-usb drivers/usb/class/bluetty.c --- 25/drivers/usb/class/bluetty.c~bk-usb 2004-09-23 21:23:38.249493432 -0700 +++ 25-akpm/drivers/usb/class/bluetty.c 2004-09-23 21:23:38.618437344 -0700 @@ -426,8 +426,8 @@ static void bluetooth_close (struct tty_ bluetooth->open_count = 0; /* shutdown any in-flight urbs that we know about */ - usb_unlink_urb (bluetooth->read_urb); - usb_unlink_urb (bluetooth->interrupt_in_urb); + usb_kill_urb (bluetooth->read_urb); + usb_kill_urb (bluetooth->interrupt_in_urb); } up(&bluetooth->lock); } @@ -705,7 +705,7 @@ void btusb_disable_bulk_read(struct tty_ } if ((bluetooth->read_urb) && (bluetooth->read_urb->actual_length)) - usb_unlink_urb(bluetooth->read_urb); + usb_kill_urb(bluetooth->read_urb); } #endif @@ -1187,14 +1187,14 @@ static void usb_bluetooth_disconnect(str bluetooth->open_count = 0; if (bluetooth->read_urb) { - usb_unlink_urb (bluetooth->read_urb); + usb_kill_urb (bluetooth->read_urb); usb_free_urb (bluetooth->read_urb); } if (bluetooth->bulk_in_buffer) kfree (bluetooth->bulk_in_buffer); if (bluetooth->interrupt_in_urb) { - usb_unlink_urb (bluetooth->interrupt_in_urb); + usb_kill_urb (bluetooth->interrupt_in_urb); usb_free_urb (bluetooth->interrupt_in_urb); } if (bluetooth->interrupt_in_buffer) @@ -1204,7 +1204,7 @@ static void usb_bluetooth_disconnect(str for (i = 0; i < NUM_CONTROL_URBS; ++i) { if (bluetooth->control_urb_pool[i]) { - usb_unlink_urb (bluetooth->control_urb_pool[i]); + usb_kill_urb (bluetooth->control_urb_pool[i]); if (bluetooth->control_urb_pool[i]->transfer_buffer) kfree (bluetooth->control_urb_pool[i]->transfer_buffer); usb_free_urb (bluetooth->control_urb_pool[i]); diff -puN drivers/usb/class/cdc-acm.c~bk-usb drivers/usb/class/cdc-acm.c --- 25/drivers/usb/class/cdc-acm.c~bk-usb 2004-09-23 21:23:38.250493280 -0700 +++ 25-akpm/drivers/usb/class/cdc-acm.c 2004-09-23 21:23:38.619437192 -0700 @@ -306,9 +306,9 @@ done: return 0; full_bailout: - usb_unlink_urb(acm->readurb); + usb_kill_urb(acm->readurb); bail_out_and_unlink: - usb_unlink_urb(acm->ctrlurb); + usb_kill_urb(acm->ctrlurb); bail_out: up(&open_sem); return -EIO; @@ -325,9 +325,9 @@ static void acm_tty_close(struct tty_str if (!--acm->used) { if (acm->dev) { acm_set_control(acm, acm->ctrlout = 0); - usb_unlink_urb(acm->ctrlurb); - usb_unlink_urb(acm->writeurb); - usb_unlink_urb(acm->readurb); + usb_kill_urb(acm->ctrlurb); + usb_kill_urb(acm->writeurb); + usb_kill_urb(acm->readurb); } else { tty_unregister_device(acm_tty_driver, acm->minor); acm_table[acm->minor] = NULL; @@ -547,6 +547,17 @@ static int acm_probe (struct usb_interfa return -EINVAL; } + if (!buflen) { + if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) { + dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint"); + buflen = intf->cur_altsetting->endpoint->extralen; + buffer = intf->cur_altsetting->endpoint->extra; + } else { + err("Zero length descriptor references"); + return -EINVAL; + } + } + while (buflen > 0) { if (buffer [1] != USB_DT_CS_INTERFACE) { err("skipping garbage"); @@ -642,7 +653,7 @@ next_desc: dbg("interfaces are valid"); for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++); - if (acm_table[minor]) { + if (minor == ACM_TTY_MINORS) { err("no more free acm devices"); return -ENODEV; } @@ -767,9 +778,9 @@ static void acm_disconnect(struct usb_in acm->dev = NULL; usb_set_intfdata (intf, NULL); - usb_unlink_urb(acm->ctrlurb); - usb_unlink_urb(acm->readurb); - usb_unlink_urb(acm->writeurb); + usb_kill_urb(acm->ctrlurb); + usb_kill_urb(acm->readurb); + usb_kill_urb(acm->writeurb); flush_scheduled_work(); /* wait for acm_softint */ diff -puN drivers/usb/class/Kconfig~bk-usb drivers/usb/class/Kconfig --- 25/drivers/usb/class/Kconfig~bk-usb 2004-09-23 21:23:38.252492976 -0700 +++ 25-akpm/drivers/usb/class/Kconfig 2004-09-23 21:23:38.613438104 -0700 @@ -9,7 +9,8 @@ config USB_AUDIO depends on USB && SOUND help Say Y here if you want to connect USB audio equipment such as - speakers to your computer's USB port. + 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. diff -puN drivers/usb/class/usblp.c~bk-usb drivers/usb/class/usblp.c --- 25/drivers/usb/class/usblp.c~bk-usb 2004-09-23 21:23:38.253492824 -0700 +++ 25-akpm/drivers/usb/class/usblp.c 2004-09-23 21:23:38.623436584 -0700 @@ -397,10 +397,6 @@ static void usblp_cleanup (struct usblp { info("usblp%d: removed", usblp->minor); - usb_buffer_free (usblp->dev, USBLP_BUF_SIZE, - usblp->writebuf, usblp->writeurb->transfer_dma); - usb_buffer_free (usblp->dev, USBLP_BUF_SIZE, - usblp->readbuf, usblp->readurb->transfer_dma); kfree (usblp->device_id_string); kfree (usblp->statusbuf); usb_free_urb(usblp->writeurb); @@ -410,9 +406,9 @@ static void usblp_cleanup (struct usblp static void usblp_unlink_urbs(struct usblp *usblp) { - usb_unlink_urb(usblp->writeurb); + usb_kill_urb(usblp->writeurb); if (usblp->bidir) - usb_unlink_urb(usblp->readurb); + usb_kill_urb(usblp->readurb); } static int usblp_release(struct inode *inode, struct file *file) @@ -1159,6 +1155,10 @@ static void usblp_disconnect(struct usb_ usb_set_intfdata (intf, NULL); usblp_unlink_urbs(usblp); + usb_buffer_free (usblp->dev, USBLP_BUF_SIZE, + usblp->writebuf, usblp->writeurb->transfer_dma); + usb_buffer_free (usblp->dev, USBLP_BUF_SIZE, + usblp->readbuf, usblp->readurb->transfer_dma); if (!usblp->used) usblp_cleanup (usblp); diff -puN drivers/usb/class/usb-midi.c~bk-usb drivers/usb/class/usb-midi.c --- 25/drivers/usb/class/usb-midi.c~bk-usb 2004-09-23 21:23:38.255492520 -0700 +++ 25-akpm/drivers/usb/class/usb-midi.c 2004-09-23 21:23:38.621436888 -0700 @@ -805,7 +805,6 @@ static int usb_midi_open(struct inode *i { int minor = iminor(inode); DECLARE_WAITQUEUE(wait, current); - struct list_head *devs, *mdevs; struct usb_midi_state *s; struct usb_mididev *m; unsigned long flags; @@ -817,10 +816,8 @@ static int usb_midi_open(struct inode *i for(;;) { down(&open_sem); - list_for_each(devs, &mididevs) { - s = list_entry(devs, struct usb_midi_state, mididev); - list_for_each(mdevs, &s->midiDevList) { - m = list_entry(mdevs, struct usb_mididev, list); + list_for_each_entry(s, &mididevs, mididev) { + list_for_each_entry(m, &s->midiDevList, list) { if ( !((m->dev_midi ^ minor) & ~0xf) ) goto device_found; } @@ -939,7 +936,7 @@ static int usb_midi_release(struct inode if ( m->open_mode & FMODE_WRITE ) { m->open_mode &= ~FMODE_WRITE; - usb_unlink_urb( m->mout.ep->urb ); + usb_kill_urb( m->mout.ep->urb ); } if ( m->open_mode & FMODE_READ ) { @@ -951,7 +948,7 @@ static int usb_midi_release(struct inode if ( m->min.ep->readers == 0 && m->min.ep->urbSubmitted ) { m->min.ep->urbSubmitted = 0; - usb_unlink_urb(m->min.ep->urb); + usb_kill_urb(m->min.ep->urb); } spin_unlock_irqrestore( &m->min.ep->lock, flagsep ); } @@ -1042,7 +1039,7 @@ static struct midi_in_endpoint *alloc_mi static int remove_midi_in_endpoint( struct midi_in_endpoint *min ) { - usb_unlink_urb( min->urb ); + usb_kill_urb( min->urb ); usb_free_urb( min->urb ); kfree( min->recvBuf ); kfree( min ); @@ -1102,7 +1099,7 @@ static struct midi_out_endpoint *alloc_m static int remove_midi_out_endpoint( struct midi_out_endpoint *mout ) { - usb_unlink_urb( mout->urb ); + usb_kill_urb( mout->urb ); usb_free_urb( mout->urb ); kfree( mout->buf ); kfree( mout ); @@ -1994,7 +1991,6 @@ static int usb_midi_probe(struct usb_int static void usb_midi_disconnect(struct usb_interface *intf) { struct usb_midi_state *s = usb_get_intfdata (intf); - struct list_head *list; struct usb_mididev *m; if ( !s ) @@ -2012,8 +2008,7 @@ static void usb_midi_disconnect(struct u s->usbdev = NULL; usb_set_intfdata (intf, NULL); - list_for_each(list, &s->midiDevList) { - m = list_entry(list, struct usb_mididev, list); + 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 ) { diff -puN drivers/usb/core/devices.c~bk-usb drivers/usb/core/devices.c --- 25/drivers/usb/core/devices.c~bk-usb 2004-09-23 21:23:38.256492368 -0700 +++ 25-akpm/drivers/usb/core/devices.c 2004-09-23 21:23:38.624436432 -0700 @@ -149,7 +149,7 @@ static const struct class_info clas_info /*****************************************************************/ -void usbdevfs_conn_disc_event(void) +void usbfs_conn_disc_event(void) { conndiscevcnt++; wake_up(&deviceconndiscwq); @@ -451,7 +451,7 @@ static char *usb_dump_string(char *start * nbytes - the maximum number of bytes to write * skip_bytes - the number of bytes to skip before writing anything * file_offset - the offset into the devices file on completion - * The caller must own the usbdev->serialize semaphore. + * The caller must own the device lock. */ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *skip_bytes, loff_t *file_offset, struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count) @@ -569,7 +569,6 @@ static ssize_t usb_device_dump(char __us static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { - struct list_head *buslist; struct usb_bus *bus; ssize_t ret, total_written = 0; loff_t skip_bytes = *ppos; @@ -581,18 +580,15 @@ static ssize_t usb_device_read(struct fi if (!access_ok(VERIFY_WRITE, buf, nbytes)) return -EFAULT; - /* enumerate busses */ down (&usb_bus_list_lock); - list_for_each(buslist, &usb_bus_list) { - /* print devices for this bus */ - bus = list_entry(buslist, struct usb_bus, bus_list); - + /* print devices for all busses */ + list_for_each_entry(bus, &usb_bus_list, bus_list) { /* recurse through all children of the root hub */ if (!bus->root_hub) continue; - down(&bus->root_hub->serialize); + usb_lock_device(bus->root_hub); ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0); - up(&bus->root_hub->serialize); + usb_unlock_device(bus->root_hub); if (ret < 0) { up(&usb_bus_list_lock); return ret; @@ -682,7 +678,7 @@ static loff_t usb_device_lseek(struct fi return ret; } -struct file_operations usbdevfs_devices_fops = { +struct file_operations usbfs_devices_fops = { .llseek = usb_device_lseek, .read = usb_device_read, .poll = usb_device_poll, diff -puN drivers/usb/core/devio.c~bk-usb drivers/usb/core/devio.c --- 25/drivers/usb/core/devio.c~bk-usb 2004-09-23 21:23:38.258492064 -0700 +++ 25-akpm/drivers/usb/core/devio.c 2004-09-23 21:23:38.626436128 -0700 @@ -21,7 +21,7 @@ * * $Id: devio.c,v 1.7 2000/02/01 17:28:48 fliegl Exp $ * - * This file implements the usbdevfs/x/y files, where + * This file implements the usbfs/x/y files, where * x is the bus number and y the device number. * * It allows user space programs/"drivers" to communicate directly @@ -113,7 +113,7 @@ static ssize_t usbdev_read(struct file * int i; pos = *ppos; - down(&dev->serialize); + usb_lock_device(dev); if (!connected(dev)) { ret = -ENODEV; goto err; @@ -175,7 +175,7 @@ static ssize_t usbdev_read(struct file * } err: - up(&dev->serialize); + usb_unlock_device(dev); return ret; } @@ -286,9 +286,10 @@ static void destroy_async (struct dev_st while (!list_empty(list)) { as = list_entry(list->next, struct async, asynclist); list_del_init(&as->asynclist); + + /* drop the spinlock so the completion handler can run */ spin_unlock_irqrestore(&ps->lock, flags); - /* usb_unlink_urb calls the completion handler with status == -ENOENT */ - usb_unlink_urb(as->urb); + usb_kill_urb(as->urb); spin_lock_irqsave(&ps->lock, flags); } spin_unlock_irqrestore(&ps->lock, flags); @@ -353,7 +354,7 @@ static void driver_disconnect(struct usb destroy_async_on_interface(ps, ifnum); } -struct usb_driver usbdevfs_driver = { +struct usb_driver usbfs_driver = { .owner = THIS_MODULE, .name = "usbfs", .probe = driver_probe, @@ -378,7 +379,7 @@ static int claimintf(struct dev_state *p if (!intf) err = -ENOENT; else - err = usb_driver_claim_interface(&usbdevfs_driver, intf, ps); + err = usb_driver_claim_interface(&usbfs_driver, intf, ps); up_write(&usb_bus_type.subsys.rwsem); if (err == 0) set_bit(ifnum, &ps->ifclaimed); @@ -401,7 +402,7 @@ static int releaseintf(struct dev_state if (!intf) err = -ENOENT; else if (test_and_clear_bit(ifnum, &ps->ifclaimed)) { - usb_driver_release_interface(&usbdevfs_driver, intf); + usb_driver_release_interface(&usbfs_driver, intf); err = 0; } up_write(&usb_bus_type.subsys.rwsem); @@ -516,7 +517,7 @@ static int usbdev_release(struct inode * struct usb_device *dev = ps->dev; unsigned int ifnum; - down(&dev->serialize); + usb_lock_device(dev); list_del_init(&ps->list); if (connected(dev)) { @@ -525,7 +526,7 @@ static int usbdev_release(struct inode * releaseintf(ps, ifnum); destroy_all_async(ps); } - up(&dev->serialize); + usb_unlock_device(dev); usb_put_dev(dev); ps->dev = NULL; kfree(ps); @@ -557,10 +558,10 @@ static int proc_control(struct dev_state snoop(&dev->dev, "control read: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n", ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex); - up(&dev->serialize); + usb_unlock_device(dev); i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo); - down(&dev->serialize); + usb_lock_device(dev); if ((i > 0) && ctrl.wLength) { if (usbfs_snoop) { dev_info(&dev->dev, "control read: data "); @@ -588,10 +589,10 @@ static int proc_control(struct dev_state printk ("%02x ", (unsigned char)(tbuf)[j]); printk("\n"); } - up(&dev->serialize); + usb_unlock_device(dev); i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo); - down(&dev->serialize); + usb_lock_device(dev); } free_page((unsigned long)tbuf); if (i<0) { @@ -635,9 +636,9 @@ static int proc_bulk(struct dev_state *p kfree(tbuf); return -EINVAL; } - up(&dev->serialize); + usb_unlock_device(dev); i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); - down(&dev->serialize); + usb_lock_device(dev); if (!i && len2) { if (copy_to_user(bulk.data, tbuf, len2)) { kfree(tbuf); @@ -651,9 +652,9 @@ static int proc_bulk(struct dev_state *p return -EFAULT; } } - up(&dev->serialize); + usb_unlock_device(dev); i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); - down(&dev->serialize); + usb_lock_device(dev); } kfree(tbuf); if (i < 0) { @@ -734,7 +735,7 @@ static int proc_connectinfo(struct dev_s static int proc_resetdevice(struct dev_state *ps) { - return __usb_reset_device(ps->dev); + return usb_reset_device(ps->dev); } @@ -976,7 +977,7 @@ static int proc_unlinkurb(struct dev_sta as = async_getpending(ps, arg); if (!as) return -EINVAL; - usb_unlink_urb(as->urb); + usb_kill_urb(as->urb); return 0; } @@ -1024,9 +1025,9 @@ static int proc_reapurb(struct dev_state break; if (signal_pending(current)) break; - up(&dev->serialize); + usb_unlock_device(dev); schedule(); - down(&dev->serialize); + usb_lock_device(dev); } remove_wait_queue(&ps->wait, &wait); set_current_state(TASK_RUNNING); @@ -1149,7 +1150,11 @@ static int proc_ioctl (struct dev_state /* let kernel drivers try to (re)bind to the interface */ case USBDEVFS_CONNECT: + usb_unlock_device(ps->dev); + usb_lock_all_devices(); bus_rescan_devices(intf->dev.bus); + usb_unlock_all_devices(); + usb_lock_device(ps->dev); break; /* talk directly to the interface's driver */ @@ -1192,9 +1197,9 @@ static int usbdev_ioctl(struct inode *in if (!(file->f_mode & FMODE_WRITE)) return -EPERM; - down(&dev->serialize); + usb_lock_device(dev); if (!connected(dev)) { - up(&dev->serialize); + usb_unlock_device(dev); return -ENODEV; } @@ -1294,7 +1299,7 @@ static int usbdev_ioctl(struct inode *in ret = proc_ioctl(ps, p); break; } - up(&dev->serialize); + usb_unlock_device(dev); if (ret >= 0) inode->i_atime = CURRENT_TIME; return ret; @@ -1314,7 +1319,7 @@ static unsigned int usbdev_poll(struct f return mask; } -struct file_operations usbdevfs_device_file_operations = { +struct file_operations usbfs_device_file_operations = { .llseek = usbdev_lseek, .read = usbdev_read, .poll = usbdev_poll, diff -puN drivers/usb/core/hcd.c~bk-usb drivers/usb/core/hcd.c --- 25/drivers/usb/core/hcd.c~bk-usb 2004-09-23 21:23:38.259491912 -0700 +++ 25-akpm/drivers/usb/core/hcd.c 2004-09-23 21:23:38.628435824 -0700 @@ -797,9 +797,9 @@ int usb_register_root_hub (struct usb_de return (retval < 0) ? retval : -EMSGSIZE; } - down (&usb_dev->serialize); + usb_lock_device (usb_dev); retval = usb_new_device (usb_dev); - up (&usb_dev->serialize); + usb_unlock_device (usb_dev); if (retval) { usb_dev->bus->root_hub = NULL; dev_err (parent_dev, "can't register root hub for %s, %d\n", @@ -1263,7 +1263,7 @@ static int hcd_unlink_urb (struct urb *u * never get completion IRQs ... maybe even the ones we need to * finish unlinking the initial failed usb_set_address(). */ - if (!hcd->saw_irq) { + if (!hcd->saw_irq && hcd->rh_timer.data != (unsigned long) urb) { dev_warn (hcd->self.controller, "Unlink after no-IRQ? " "Different ACPI or APIC settings may help." "\n"); @@ -1572,13 +1572,12 @@ irqreturn_t usb_hcd_irq (int irq, void * struct usb_hcd *hcd = __hcd; int start = hcd->state; - if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */ + if (start == USB_STATE_HALT) return IRQ_NONE; - - hcd->saw_irq = 1; if (hcd->driver->irq (hcd, r) == IRQ_NONE) return IRQ_NONE; + hcd->saw_irq = 1; if (hcd->state != start && hcd->state == USB_STATE_HALT) usb_hc_died (hcd); return IRQ_HANDLED; @@ -1587,22 +1586,6 @@ EXPORT_SYMBOL (usb_hcd_irq); /*-------------------------------------------------------------------------*/ -static void hcd_panic (void *_hcd) -{ - struct usb_hcd *hcd = _hcd; - struct usb_device *hub = hcd->self.root_hub; - unsigned i; - - /* hc's root hub is removed later removed in hcd->stop() */ - down (&hub->serialize); - usb_set_device_state(hub, USB_STATE_NOTATTACHED); - for (i = 0; i < hub->maxchild; i++) { - if (hub->children [i]) - usb_disconnect (&hub->children [i]); - } - up (&hub->serialize); -} - /** * usb_hc_died - report abnormal shutdown of a host controller (bus glue) * @hcd: pointer to the HCD representing the controller @@ -1615,9 +1598,9 @@ void usb_hc_died (struct usb_hcd *hcd) { dev_err (hcd->self.controller, "HC died; cleaning up\n"); - /* clean up old urbs and devices; needs a task context */ - INIT_WORK (&hcd->work, hcd_panic, hcd); - (void) schedule_work (&hcd->work); + /* make khubd clean up old urbs and devices */ + usb_set_device_state(hcd->self.root_hub, USB_STATE_NOTATTACHED); + mod_timer(&hcd->rh_timer, jiffies); } EXPORT_SYMBOL (usb_hc_died); diff -puN drivers/usb/core/hcd.h~bk-usb drivers/usb/core/hcd.h --- 25/drivers/usb/core/hcd.h~bk-usb 2004-09-23 21:23:38.261491608 -0700 +++ 25-akpm/drivers/usb/core/hcd.h 2004-09-23 21:23:38.629435672 -0700 @@ -67,7 +67,6 @@ struct usb_hcd { /* usb_bus.hcpriv point struct timer_list rh_timer; /* drives root hub */ struct list_head dev_list; /* devices on this bus */ - struct work_struct work; /* * hardware info/state @@ -363,6 +362,9 @@ static inline int hcd_register_root (str return usb_register_root_hub (usb_dev, hcd->self.controller); } +extern void usb_set_device_state(struct usb_device *udev, + enum usb_device_state new_state); + /*-------------------------------------------------------------------------*/ /* exported only within usbcore */ diff -puN drivers/usb/core/hcd-pci.c~bk-usb drivers/usb/core/hcd-pci.c --- 25/drivers/usb/core/hcd-pci.c~bk-usb 2004-09-23 21:23:38.262491456 -0700 +++ 25-akpm/drivers/usb/core/hcd-pci.c 2004-09-23 21:23:38.626436128 -0700 @@ -188,9 +188,9 @@ clean_3: } hcd->irq = dev->irq; - dev_info (hcd->self.controller, "irq %s, %s %p\n", bufp, + dev_info (hcd->self.controller, "irq %s, %s 0x%lx\n", bufp, (driver->flags & HCD_MEMORY) ? "pci mem" : "io base", - base); + resource); usb_bus_init (&hcd->self); hcd->self.op = &usb_hcd_operations; @@ -260,6 +260,8 @@ void usb_hcd_pci_remove (struct pci_dev } usb_deregister_bus (&hcd->self); + + pci_disable_device(dev); } EXPORT_SYMBOL (usb_hcd_pci_remove); diff -puN drivers/usb/core/hub.c~bk-usb drivers/usb/core/hub.c --- 25/drivers/usb/core/hub.c~bk-usb 2004-09-23 21:23:38.264491152 -0700 +++ 25-akpm/drivers/usb/core/hub.c 2004-09-23 21:23:38.634434912 -0700 @@ -36,15 +36,18 @@ #include "hcd.h" #include "hub.h" -/* Protect struct usb_device state and children members */ +/* Protect struct usb_device->state and ->children members + * Note: Both are also protected by ->serialize, except that ->state can + * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */ static spinlock_t device_state_lock = SPIN_LOCK_UNLOCKED; -/* Wakes up khubd */ +/* khubd's worklist and its lock */ static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED; - static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */ +/* Wakes up khubd */ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); + static pid_t khubd_pid = 0; /* PID of khubd */ static DECLARE_COMPLETION(khubd_exited); @@ -226,6 +229,19 @@ static int get_port_status(struct usb_de data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT); } +static void kick_khubd(struct usb_hub *hub) +{ + unsigned long flags; + + spin_lock_irqsave(&hub_event_lock, flags); + if (list_empty(&hub->event_list)) { + list_add_tail(&hub->event_list, &hub_event_list); + wake_up(&khubd_wait); + } + spin_unlock_irqrestore(&hub_event_lock, flags); +} + + /* completion function, fires on port status changes and various faults */ static void hub_irq(struct urb *urb, struct pt_regs *regs) { @@ -261,12 +277,7 @@ static void hub_irq(struct urb *urb, str hub->nerrors = 0; /* Something happened, let khubd figure it out */ - spin_lock(&hub_event_lock); - if (list_empty(&hub->event_list)) { - list_add_tail(&hub->event_list, &hub_event_list); - wake_up(&khubd_wait); - } - spin_unlock(&hub_event_lock); + kick_khubd(hub); resubmit: if (hub->quiescing) @@ -384,6 +395,33 @@ static void hub_power_on(struct usb_hub msleep(hub->descriptor->bPwrOn2PwrGood * 2); } +static void hub_quiesce(struct usb_hub *hub) +{ + /* stop khubd and related activity */ + hub->quiescing = 1; + usb_kill_urb(hub->urb); + if (hub->has_indicators) + cancel_delayed_work(&hub->leds); + if (hub->has_indicators || hub->tt.hub) + flush_scheduled_work(); +} + +static void hub_activate(struct usb_hub *hub) +{ + int status; + + hub->quiescing = 0; + status = usb_submit_urb(hub->urb, GFP_NOIO); + if (status < 0) + dev_err(&hub->intf->dev, "activate --> %d\n", status); + if (hub->has_indicators && blinkenlights) + schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD); + + /* scan all ports ASAP */ + hub->event_bits[0] = ~0; + kick_khubd(hub); +} + static int hub_hub_status(struct usb_hub *hub, u16 *status, u16 *change) { @@ -579,7 +617,7 @@ static int hub_configure(struct usb_hub dev_dbg(hub_dev, "%sover-current condition exists\n", (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no "); - /* Start the interrupt endpoint */ + /* set up the interrupt endpoint */ pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress); maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe)); @@ -597,24 +635,13 @@ static int hub_configure(struct usb_hub hub, endpoint->bInterval); hub->urb->transfer_dma = hub->buffer_dma; hub->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - ret = usb_submit_urb(hub->urb, GFP_KERNEL); - if (ret) { - message = "couldn't submit status urb"; - goto fail; - } - - /* Wake up khubd */ - wake_up(&khubd_wait); - /* maybe start cycling the hub leds */ - if (hub->has_indicators && blinkenlights) { - set_port_led(hdev, 1, HUB_LED_GREEN); + /* maybe cycle the hub leds */ + if (hub->has_indicators && blinkenlights) hub->indicator [0] = INDICATOR_CYCLE; - schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD); - } hub_power_on(hub); - + hub_activate(hub); return 0; fail: @@ -626,33 +653,6 @@ fail: static unsigned highspeed_hubs; -static void hub_quiesce(struct usb_hub *hub) -{ - /* stop khubd and related activity */ - hub->quiescing = 1; - usb_kill_urb(hub->urb); - if (hub->has_indicators) - cancel_delayed_work(&hub->leds); - if (hub->has_indicators || hub->tt.hub) - flush_scheduled_work(); -} - -#ifdef CONFIG_USB_SUSPEND - -static void hub_reactivate(struct usb_hub *hub) -{ - int status; - - hub->quiescing = 0; - status = usb_submit_urb(hub->urb, GFP_NOIO); - if (status < 0) - dev_err(&hub->intf->dev, "reactivate --> %d\n", status); - if (hub->has_indicators && blinkenlights) - schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD); -} - -#endif - static void hub_disconnect(struct usb_interface *intf) { struct usb_hub *hub = usb_get_intfdata (intf); @@ -794,68 +794,29 @@ hub_ioctl(struct usb_interface *intf, un } } -/* caller has locked the hub and must own the device lock */ -static int hub_reset(struct usb_hub *hub) +/* caller has locked the hub device */ +static void hub_pre_reset(struct usb_device *hdev) { - struct usb_device *hdev = hub->hdev; + struct usb_hub *hub = usb_get_intfdata(hdev->actconfig->interface[0]); int i; - /* Disconnect any attached devices */ - for (i = 0; i < hub->descriptor->bNbrPorts; i++) { + for (i = 0; i < hdev->maxchild; ++i) { if (hdev->children[i]) usb_disconnect(&hdev->children[i]); } - - /* Attempt to reset the hub */ - if (hub->urb) - usb_kill_urb(hub->urb); - else - return -1; - - if (__usb_reset_device(hdev)) - return -1; - - hub->urb->dev = hdev; - if (usb_submit_urb(hub->urb, GFP_KERNEL)) - return -1; - - hub_power_on(hub); - - return 0; + hub_quiesce(hub); } -/* caller has locked the hub */ -/* FIXME! This routine should be subsumed into hub_reset */ -static void hub_start_disconnect(struct usb_device *hdev) +/* caller has locked the hub device */ +static void hub_post_reset(struct usb_device *hdev) { - struct usb_device *parent = hdev->parent; - int i; - - /* Find the device pointer to disconnect */ - if (parent) { - for (i = 0; i < parent->maxchild; i++) { - if (parent->children[i] == hdev) { - usb_disconnect(&parent->children[i]); - return; - } - } - } + struct usb_hub *hub = usb_get_intfdata(hdev->actconfig->interface[0]); - dev_err(&hdev->dev, "cannot disconnect hub!\n"); + hub_activate(hub); + hub_power_on(hub); } -static void recursively_mark_NOTATTACHED(struct usb_device *udev) -{ - int i; - - for (i = 0; i < udev->maxchild; ++i) { - if (udev->children[i]) - recursively_mark_NOTATTACHED(udev->children[i]); - } - udev->state = USB_STATE_NOTATTACHED; -} - /* grab device/port lock, returning index of that port (zero based). * protects the upstream link used by this device from concurrent * tree operations like suspend, resume, reset, and disconnect, which @@ -872,21 +833,16 @@ static int locktree(struct usb_device *u /* root hub is always the first lock in the series */ hdev = udev->parent; if (!hdev) { - down(&udev->serialize); + usb_lock_device(udev); return 0; } /* on the path from root to us, lock everything from * top down, dropping parent locks when not needed - * - * NOTE: if disconnect were to ignore the locking, we'd need - * to get extra refcounts to everything since hdev->children - * and udev->parent could be invalidated while we work... */ t = locktree(hdev); if (t < 0) return t; - spin_lock_irq(&device_state_lock); for (t = 0; t < hdev->maxchild; t++) { if (hdev->children[t] == udev) { /* everything is fail-fast once disconnect @@ -898,33 +854,45 @@ static int locktree(struct usb_device *u /* when everyone grabs locks top->bottom, * non-overlapping work may be concurrent */ - spin_unlock_irq(&device_state_lock); down(&udev->serialize); up(&hdev->serialize); return t; } } - spin_unlock_irq(&device_state_lock); - up(&hdev->serialize); + usb_unlock_device(hdev); return -ENODEV; } +static void recursively_mark_NOTATTACHED(struct usb_device *udev) +{ + int i; + + for (i = 0; i < udev->maxchild; ++i) { + if (udev->children[i]) + recursively_mark_NOTATTACHED(udev->children[i]); + } + udev->state = USB_STATE_NOTATTACHED; +} + /** - * usb_set_device_state - change a device's current state (usbcore-internal) + * usb_set_device_state - change a device's current state (usbcore, hcds) * @udev: pointer to device whose state should be changed * @new_state: new state value to be stored * - * udev->state is _not_ protected by the device lock. This + * udev->state is _not_ fully protected by the device lock. Although + * most transitions are made only while holding the lock, the state can + * can change to USB_STATE_NOTATTACHED at almost any time. This * is so that devices can be marked as disconnected as soon as possible, - * without having to wait for the semaphore to be released. Instead, - * changes to the state must be protected by the device_state_lock spinlock. + * without having to wait for any semaphores to be released. As a result, + * all changes to any device's state must be protected by the + * device_state_lock spinlock. * * Once a device has been added to the device tree, all changes to its state * should be made using this routine. The state should _not_ be set directly. * * If udev->state is already USB_STATE_NOTATTACHED then no change is made. * Otherwise udev->state is set to new_state, and if new_state is - * USB_STATE_NOTATTACHED then all of udev's descendant's states are also set + * USB_STATE_NOTATTACHED then all of udev's descendants' states are also set * to USB_STATE_NOTATTACHED. */ void usb_set_device_state(struct usb_device *udev, @@ -941,6 +909,7 @@ void usb_set_device_state(struct usb_dev recursively_mark_NOTATTACHED(udev); spin_unlock_irqrestore(&device_state_lock, flags); } +EXPORT_SYMBOL(usb_set_device_state); static void choose_address(struct usb_device *udev) @@ -974,11 +943,12 @@ static void release_address(struct usb_d /** * usb_disconnect - disconnect a device (usbcore-internal) - * @pdev: pointer to device being disconnected, into a locked hub + * @pdev: pointer to device being disconnected * Context: !in_interrupt () * - * Something got disconnected. Get rid of it, and all of its children. - * If *pdev is a normal device then the parent hub should be locked. + * Something got disconnected. Get rid of it and all of its children. + * + * If *pdev is a normal device then the parent hub must already be locked. * If *pdev is a root hub then this routine will acquire the * usb_bus_list_lock on behalf of the caller. * @@ -1004,9 +974,11 @@ void usb_disconnect(struct usb_device ** usb_set_device_state(udev, USB_STATE_NOTATTACHED); /* lock the bus list on behalf of HCDs unregistering their root hubs */ - if (!udev->parent) + if (!udev->parent) { down(&usb_bus_list_lock); - down(&udev->serialize); + usb_lock_device(udev); + } else + down(&udev->serialize); dev_info (&udev->dev, "USB disconnect, address %d\n", udev->devnum); @@ -1031,14 +1003,16 @@ void usb_disconnect(struct usb_device ** usbfs_remove_device(udev); usb_remove_sysfs_dev_files(udev); - /* Avoid races with recursively_mark_NOTATTACHED() and locktree() */ + /* Avoid races with recursively_mark_NOTATTACHED() */ spin_lock_irq(&device_state_lock); *pdev = NULL; spin_unlock_irq(&device_state_lock); - up(&udev->serialize); - if (!udev->parent) + if (!udev->parent) { + usb_unlock_device(udev); up(&usb_bus_list_lock); + } else + up(&udev->serialize); device_unregister(&udev->dev); } @@ -1061,11 +1035,19 @@ static int choose_configuration(struct u ->altsetting->desc; if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC) continue; - /* COMM/2/all is CDC ACM, except 0xff is MSFT RNDIS */ + /* COMM/2/all is CDC ACM, except 0xff is MSFT RNDIS. + * MSFT needs this to be the first config; never use + * it as the default unless Linux has host-side RNDIS. + * A second config would ideally be CDC-Ethernet, but + * may instead be the "vendor specific" CDC subset + * long used by ARM Linux for sa1100 or pxa255. + */ if (desc->bInterfaceClass == USB_CLASS_COMM && desc->bInterfaceSubClass == 2 - && desc->bInterfaceProtocol == 0xff) + && desc->bInterfaceProtocol == 0xff) { + c = udev->config[1].desc.bConfigurationValue; continue; + } c = udev->config[i].desc.bConfigurationValue; break; } @@ -1384,7 +1366,6 @@ static int hub_port_disable(struct usb_d int ret; if (hdev->children[port]) { - /* FIXME need disconnect() for NOTATTACHED device */ usb_set_device_state(hdev->children[port], USB_STATE_NOTATTACHED); } @@ -1396,6 +1377,33 @@ static int hub_port_disable(struct usb_d return ret; } +/* + * Disable a port and mark a logical connnect-change event, so that some + * time later khubd will disconnect() any existing usb_device on the port + * and will re-enumerate if there actually is a device attached. + */ +static void hub_port_logical_disconnect(struct usb_device *hdev, int port) +{ + struct usb_hub *hub; + + dev_dbg(hubdev(hdev), "logical disconnect on port %d\n", port + 1); + hub_port_disable(hdev, port); + + /* FIXME let caller ask to power down the port: + * - some devices won't enumerate without a VBUS power cycle + * - SRP saves power that way + * - usb_suspend_device(dev,PM_SUSPEND_DISK) + * That's easy if this hub can switch power per-port, and + * khubd reactivates the port later (timer, SRP, etc). + * Powerdown must be optional, because of reset/DFU. + */ + + hub = usb_get_intfdata(hdev->actconfig->interface[0]); + set_bit(port, hub->change_bits); + kick_khubd(hub); +} + + #ifdef CONFIG_USB_SUSPEND /* @@ -1413,8 +1421,8 @@ static int hub_port_suspend(struct usb_d int status; struct usb_device *udev; - udev = hdev->children[port - 1]; - // dev_dbg(hubdev(hdev), "suspend port %d\n", port); + udev = hdev->children[port]; + // dev_dbg(hubdev(hdev), "suspend port %d\n", port + 1); /* enable remote wakeup when appropriate; this lets the device * wake up the upstream hub (including maybe the root hub). @@ -1439,11 +1447,11 @@ static int hub_port_suspend(struct usb_d } /* see 7.1.7.6 */ - status = set_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND); + status = set_port_feature(hdev, port + 1, USB_PORT_FEAT_SUSPEND); if (status) { dev_dbg(hubdev(hdev), "can't suspend port %d, status %d\n", - port, status); + port + 1, status); /* paranoia: "should not happen" */ (void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0), USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, @@ -1477,16 +1485,14 @@ static int __usb_suspend_device (struct { int status; + /* caller owns the udev device lock */ if (port < 0) return port; - /* NOTE: udev->serialize released on all real returns! */ - if (state <= udev->dev.power.power_state || state < PM_SUSPEND_MEM || udev->state == USB_STATE_SUSPENDED || udev->state == USB_STATE_NOTATTACHED) { - up(&udev->serialize); return 0; } @@ -1562,11 +1568,10 @@ static int __usb_suspend_device (struct else status = -EOPNOTSUPP; } else - status = hub_port_suspend(udev->parent, port + 1); + status = hub_port_suspend(udev->parent, port); if (status == 0) udev->dev.power.power_state = state; - up(&udev->serialize); return status; } @@ -1590,7 +1595,15 @@ static int __usb_suspend_device (struct */ int usb_suspend_device(struct usb_device *udev, u32 state) { - return __usb_suspend_device(udev, locktree(udev), state); + int port, status; + + port = locktree(udev); + if (port < 0) + return port; + + status = __usb_suspend_device(udev, port, state); + usb_unlock_device(udev); + return status; } /* @@ -1603,7 +1616,7 @@ static int finish_port_resume(struct usb int status; u16 devstatus; - /* caller owns udev->serialize */ + /* caller owns the udev device lock */ dev_dbg(&udev->dev, "usb resume\n"); udev->dev.power.power_state = PM_SUSPEND_ON; @@ -1687,15 +1700,15 @@ hub_port_resume(struct usb_device *hdev, int status; struct usb_device *udev; - udev = hdev->children[port - 1]; - // dev_dbg(hubdev(hdev), "resume port %d\n", port); + udev = hdev->children[port]; + // dev_dbg(hubdev(hdev), "resume port %d\n", port + 1); /* see 7.1.7.7; affects power usage, but not budgeting */ - status = clear_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND); + status = clear_port_feature(hdev, port + 1, USB_PORT_FEAT_SUSPEND); if (status) { dev_dbg(&hdev->actconfig->interface[0]->dev, "can't resume port %d, status %d\n", - port, status); + port + 1, status); } else { u16 devstatus; u16 portchange; @@ -1713,7 +1726,7 @@ hub_port_resume(struct usb_device *hdev, * sequence. */ devstatus = portchange = 0; - status = hub_port_status(hdev, port - 1, + status = hub_port_status(hdev, port, &devstatus, &portchange); if (status < 0 || (devstatus & LIVE_FLAGS) != LIVE_FLAGS @@ -1721,7 +1734,7 @@ hub_port_resume(struct usb_device *hdev, ) { dev_dbg(&hdev->actconfig->interface[0]->dev, "port %d status %04x.%04x after resume, %d\n", - port, portchange, devstatus, status); + port + 1, portchange, devstatus, status); } else { /* TRSMRCY = 10 msec */ msleep(10); @@ -1729,7 +1742,7 @@ hub_port_resume(struct usb_device *hdev, } } if (status < 0) - status = hub_port_disable(hdev, port); + hub_port_logical_disconnect(hdev, port); return status; } @@ -1773,7 +1786,7 @@ int usb_resume_device(struct usb_device ->actconfig->interface[0]); } } else if (udev->state == USB_STATE_SUSPENDED) { - status = hub_port_resume(udev->parent, port + 1); + status = hub_port_resume(udev->parent, port); } else { status = 0; udev->dev.power.power_state = PM_SUSPEND_ON; @@ -1783,10 +1796,12 @@ int usb_resume_device(struct usb_device status); } - up(&udev->serialize); + usb_unlock_device(udev); /* rebind drivers that had no suspend() */ + usb_lock_all_devices(); bus_rescan_devices(&usb_bus_type); + usb_unlock_all_devices(); return status; } @@ -1828,6 +1843,7 @@ static int hub_suspend(struct usb_interf continue; down(&udev->serialize); status = __usb_suspend_device(udev, port, state); + up(&udev->serialize); if (status < 0) dev_dbg(&intf->dev, "suspend port %d --> %d\n", port, status); @@ -1866,20 +1882,20 @@ static int hub_resume(struct usb_interfa continue; down (&udev->serialize); if (portstat & USB_PORT_STAT_SUSPEND) - status = hub_port_resume(hdev, port + 1); + status = hub_port_resume(hdev, port); else { status = finish_port_resume(udev); - if (status < 0) - status = hub_port_disable(hdev, port); - if (status < 0) + if (status < 0) { dev_dbg(&intf->dev, "resume port %d --> %d\n", - port, status); + port + 1, status); + hub_port_logical_disconnect(hdev, port); + } } up(&udev->serialize); } intf->dev.power.power_state = PM_SUSPEND_ON; - hub_reactivate(hub); + hub_activate(hub); return 0; } @@ -2011,7 +2027,7 @@ hub_port_init (struct usb_device *hdev, hdev->bus->b_hnp_enable = 0; } - retval = clear_port_feature(hdev, port, USB_PORT_FEAT_SUSPEND); + retval = clear_port_feature(hdev, port + 1, USB_PORT_FEAT_SUSPEND); if (retval < 0 && retval != -EPIPE) dev_dbg(&udev->dev, "can't clear suspend; %d\n", retval); @@ -2443,10 +2459,10 @@ static void hub_events(void) dev_dbg (hub_dev, "resetting for error %d\n", hub->error); - if (hub_reset(hub)) { + ret = usb_reset_device(hdev); + if (ret) { dev_dbg (hub_dev, - "can't reset; disconnecting\n"); - hub_start_disconnect(hdev); + "error resetting hub: %d\n", ret); goto loop; } @@ -2502,15 +2518,17 @@ static void hub_events(void) if (portchange & USB_PORT_STAT_C_SUSPEND) { clear_port_feature(hdev, i + 1, USB_PORT_FEAT_C_SUSPEND); - if (hdev->children[i]) + if (hdev->children[i]) { ret = remote_wakeup(hdev->children[i]); - else + if (ret < 0) + connect_change = 1; + } else { ret = -ENODEV; + hub_port_disable(hdev, i); + } dev_dbg (hub_dev, "resume on port %d, status %d\n", i + 1, ret); - if (ret < 0) - ret = hub_port_disable(hdev, i); } if (portchange & USB_PORT_STAT_C_OVERCURRENT) { @@ -2554,7 +2572,7 @@ static void hub_events(void) } loop: - up(&hdev->serialize); + usb_unlock_device(hdev); usb_put_dev(hdev); } /* end while (1) */ @@ -2707,13 +2725,15 @@ static int config_descriptors_changed(st * * The caller must own the device lock. For example, it's safe to use * this from a driver probe() routine after downloading new firmware. + * For calls that might not occur during probe(), drivers should lock + * the device using usb_lock_device_for_reset(). */ -int __usb_reset_device(struct usb_device *udev) +int usb_reset_device(struct usb_device *udev) { struct usb_device *parent = udev->parent; struct usb_device_descriptor descriptor = udev->descriptor; int i, ret, port = -1; - struct usb_hub *hub; + int udev_is_a_hub = 0; if (udev->state == USB_STATE_NOTATTACHED || udev->state == USB_STATE_SUSPENDED) { @@ -2722,13 +2742,9 @@ int __usb_reset_device(struct usb_device return -EINVAL; } - /* FIXME: This should be legal for regular hubs. Root hubs may - * have special requirements. */ - if (udev->maxchild) { - /* this requires hub- or hcd-specific logic; - * see hub_reset() and OHCI hc_restart() - */ - dev_dbg(&udev->dev, "%s for hub!\n", __FUNCTION__); + if (!parent) { + /* this requires hcd-specific logic; see OHCI hc_restart() */ + dev_dbg(&udev->dev, "%s for root hub!\n", __FUNCTION__); return -EISDIR; } @@ -2744,6 +2760,19 @@ int __usb_reset_device(struct usb_device return -ENOENT; } + /* If we're resetting an active hub, take some special actions */ + if (udev->actconfig && + udev->actconfig->interface[0]->dev.driver == + &hub_driver.driver) { + udev_is_a_hub = 1; + hub_pre_reset(udev); + } + + /* ep0 maxpacket size may change; let the HCD know about it. + * Other endpoints will be handled by re-enumeration. */ + usb_disable_endpoint(udev, 0); + usb_disable_endpoint(udev, 0 + USB_DIR_IN); + ret = hub_port_init(parent, udev, port); if (ret < 0) goto re_enumerate; @@ -2757,7 +2786,7 @@ int __usb_reset_device(struct usb_device } if (!udev->actconfig) - return 0; + goto done; ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), USB_REQ_SET_CONFIGURATION, 0, @@ -2791,32 +2820,12 @@ int __usb_reset_device(struct usb_device } } +done: + if (udev_is_a_hub) + hub_post_reset(udev); return 0; re_enumerate: - hub_port_disable(parent, port); - - hub = usb_get_intfdata(parent->actconfig->interface[0]); - set_bit(port, hub->change_bits); - - spin_lock_irq(&hub_event_lock); - if (list_empty(&hub->event_list)) { - list_add_tail(&hub->event_list, &hub_event_list); - wake_up(&khubd_wait); - } - spin_unlock_irq(&hub_event_lock); - + hub_port_logical_disconnect(parent, port); return -ENODEV; } -EXPORT_SYMBOL(__usb_reset_device); - -int usb_reset_device(struct usb_device *udev) -{ - int r; - - down(&udev->serialize); - r = __usb_reset_device(udev); - up(&udev->serialize); - - return r; -} diff -puN drivers/usb/core/inode.c~bk-usb drivers/usb/core/inode.c --- 25/drivers/usb/core/inode.c~bk-usb 2004-09-23 21:23:38.265491000 -0700 +++ 25-akpm/drivers/usb/core/inode.c 2004-09-23 21:23:38.636434608 -0700 @@ -4,7 +4,7 @@ * inode.c -- Inode/Dentry functions for the USB device file system. * * Copyright (C) 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) - * Copyright (C) 2001,2002 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2001,2002,2004 Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,17 +40,15 @@ #include #include #include +#include "usb.h" static struct super_operations usbfs_ops; static struct file_operations default_file_operations; static struct inode_operations usbfs_dir_inode_operations; -static struct vfsmount *usbdevfs_mount; static struct vfsmount *usbfs_mount; -static int usbdevfs_mount_count; /* = 0 */ static int usbfs_mount_count; /* = 0 */ static int ignore_mount = 0; -static struct dentry *devices_usbdevfs_dentry; static struct dentry *devices_usbfs_dentry; static int num_buses; /* = 0 */ @@ -240,9 +238,6 @@ static int remount(struct super_block *s if (usbfs_mount && usbfs_mount->mnt_sb) update_sb(usbfs_mount->mnt_sb); - if (usbdevfs_mount && usbdevfs_mount->mnt_sb) - update_sb(usbdevfs_mount->mnt_sb); - return 0; } @@ -561,28 +556,12 @@ static void fs_remove_file (struct dentr /* --------------------------------------------------------------------- */ - - -/* - * The usbdevfs name is now deprecated (as of 2.5.1). - * It will be removed when the 2.7.x development cycle is started. - * You have been warned :) - */ -static struct file_system_type usbdevice_fs_type; - static struct super_block *usb_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { return get_sb_single(fs_type, flags, data, usbfs_fill_super); } -static struct file_system_type usbdevice_fs_type = { - .owner = THIS_MODULE, - .name = "usbdevfs", - .get_sb = usb_get_sb, - .kill_sb = kill_litter_super, -}; - static struct file_system_type usb_fs_type = { .owner = THIS_MODULE, .name = "usbfs", @@ -603,16 +582,10 @@ static int create_special_files (void) ignore_mount = 1; /* create the devices special file */ - retval = simple_pin_fs("usbdevfs", &usbdevfs_mount, &usbdevfs_mount_count); - if (retval) { - err ("Unable to get usbdevfs mount"); - goto exit; - } - retval = simple_pin_fs("usbfs", &usbfs_mount, &usbfs_mount_count); if (retval) { err ("Unable to get usbfs mount"); - goto error_clean_usbdevfs_mount; + goto exit; } ignore_mount = 0; @@ -620,7 +593,7 @@ static int create_special_files (void) parent = usbfs_mount->mnt_sb->s_root; devices_usbfs_dentry = fs_create_file ("devices", listmode | S_IFREG, parent, - NULL, &usbdevfs_devices_fops, + NULL, &usbfs_devices_fops, listuid, listgid); if (devices_usbfs_dentry == NULL) { err ("Unable to create devices usbfs file"); @@ -628,42 +601,19 @@ static int create_special_files (void) goto error_clean_mounts; } - parent = usbdevfs_mount->mnt_sb->s_root; - devices_usbdevfs_dentry = fs_create_file ("devices", - listmode | S_IFREG, parent, - NULL, &usbdevfs_devices_fops, - listuid, listgid); - if (devices_usbdevfs_dentry == NULL) { - err ("Unable to create devices usbfs file"); - retval = -ENODEV; - goto error_remove_file; - } - goto exit; -error_remove_file: - fs_remove_file (devices_usbfs_dentry); - devices_usbfs_dentry = NULL; - error_clean_mounts: simple_release_fs(&usbfs_mount, &usbfs_mount_count); - -error_clean_usbdevfs_mount: - simple_release_fs(&usbdevfs_mount, &usbdevfs_mount_count); - exit: return retval; } static void remove_special_files (void) { - if (devices_usbdevfs_dentry) - fs_remove_file (devices_usbdevfs_dentry); if (devices_usbfs_dentry) fs_remove_file (devices_usbfs_dentry); - devices_usbdevfs_dentry = NULL; devices_usbfs_dentry = NULL; - simple_release_fs(&usbdevfs_mount, &usbdevfs_mount_count); simple_release_fs(&usbfs_mount, &usbfs_mount_count); } @@ -671,11 +621,6 @@ void usbfs_update_special (void) { struct inode *inode; - if (devices_usbdevfs_dentry) { - inode = devices_usbdevfs_dentry->d_inode; - if (inode) - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - } if (devices_usbfs_dentry) { inode = devices_usbfs_dentry->d_inode; if (inode) @@ -707,29 +652,16 @@ void usbfs_add_bus(struct usb_bus *bus) return; } - parent = usbdevfs_mount->mnt_sb->s_root; - bus->usbdevfs_dentry = fs_create_file (name, busmode | S_IFDIR, parent, - bus, NULL, busuid, busgid); - if (bus->usbdevfs_dentry == NULL) { - err ("error creating usbdevfs bus entry"); - return; - } - usbfs_update_special(); - usbdevfs_conn_disc_event(); + usbfs_conn_disc_event(); } - void usbfs_remove_bus(struct usb_bus *bus) { if (bus->usbfs_dentry) { fs_remove_file (bus->usbfs_dentry); bus->usbfs_dentry = NULL; } - if (bus->usbdevfs_dentry) { - fs_remove_file (bus->usbdevfs_dentry); - bus->usbdevfs_dentry = NULL; - } --num_buses; if (num_buses <= 0) { @@ -738,7 +670,7 @@ void usbfs_remove_bus(struct usb_bus *bu } usbfs_update_special(); - usbdevfs_conn_disc_event(); + usbfs_conn_disc_event(); } void usbfs_add_device(struct usb_device *dev) @@ -750,20 +682,12 @@ void usbfs_add_device(struct usb_device sprintf (name, "%03d", dev->devnum); dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG, dev->bus->usbfs_dentry, dev, - &usbdevfs_device_file_operations, + &usbfs_device_file_operations, devuid, devgid); if (dev->usbfs_dentry == NULL) { err ("error creating usbfs device entry"); return; } - dev->usbdevfs_dentry = fs_create_file (name, devmode | S_IFREG, - dev->bus->usbdevfs_dentry, dev, - &usbdevfs_device_file_operations, - devuid, devgid); - if (dev->usbdevfs_dentry == NULL) { - err ("error creating usbdevfs device entry"); - return; - } /* Set the size of the device's file to be * equal to the size of the device descriptors. */ @@ -775,11 +699,9 @@ void usbfs_add_device(struct usb_device } if (dev->usbfs_dentry->d_inode) dev->usbfs_dentry->d_inode->i_size = i_size; - if (dev->usbdevfs_dentry->d_inode) - dev->usbdevfs_dentry->d_inode->i_size = i_size; usbfs_update_special(); - usbdevfs_conn_disc_event(); + usbfs_conn_disc_event(); } void usbfs_remove_device(struct usb_device *dev) @@ -791,10 +713,6 @@ void usbfs_remove_device(struct usb_devi fs_remove_file (dev->usbfs_dentry); dev->usbfs_dentry = NULL; } - if (dev->usbdevfs_dentry) { - fs_remove_file (dev->usbdevfs_dentry); - dev->usbdevfs_dentry = NULL; - } while (!list_empty(&dev->filelist)) { ds = list_entry(dev->filelist.next, struct dev_state, list); list_del_init(&ds->list); @@ -807,51 +725,38 @@ void usbfs_remove_device(struct usb_devi } } usbfs_update_special(); - usbdevfs_conn_disc_event(); + usbfs_conn_disc_event(); } /* --------------------------------------------------------------------- */ -#ifdef CONFIG_PROC_FS static struct proc_dir_entry *usbdir = NULL; -#endif int __init usbfs_init(void) { int retval; - retval = usb_register(&usbdevfs_driver); + retval = usb_register(&usbfs_driver); if (retval) return retval; retval = register_filesystem(&usb_fs_type); if (retval) { - usb_deregister(&usbdevfs_driver); - return retval; - } - retval = register_filesystem(&usbdevice_fs_type); - if (retval) { - unregister_filesystem(&usb_fs_type); - usb_deregister(&usbdevfs_driver); + usb_deregister(&usbfs_driver); return retval; } -#ifdef CONFIG_PROC_FS - /* create mount point for usbdevfs */ + /* create mount point for usbfs */ usbdir = proc_mkdir("usb", proc_bus); -#endif return 0; } void usbfs_cleanup(void) { - usb_deregister(&usbdevfs_driver); + usb_deregister(&usbfs_driver); unregister_filesystem(&usb_fs_type); - unregister_filesystem(&usbdevice_fs_type); -#ifdef CONFIG_PROC_FS if (usbdir) remove_proc_entry("usb", proc_bus); -#endif } diff -puN drivers/usb/core/message.c~bk-usb drivers/usb/core/message.c --- 25/drivers/usb/core/message.c~bk-usb 2004-09-23 21:23:38.267490696 -0700 +++ 25-akpm/drivers/usb/core/message.c 2004-09-23 21:23:38.638434304 -0700 @@ -1132,6 +1132,8 @@ int usb_set_interface(struct usb_device * use usb_set_interface() on the interfaces it claims. Resetting the whole * configuration would affect other drivers' interfaces. * + * The caller must own the device lock. + * * Returns zero on success, else a negative error code. */ int usb_reset_configuration(struct usb_device *dev) @@ -1142,9 +1144,9 @@ int usb_reset_configuration(struct usb_d if (dev->state == USB_STATE_SUSPENDED) return -EHOSTUNREACH; - /* caller must own dev->serialize (config won't change) - * and the usb bus readlock (so driver bindings are stable); - * so calls during probe() are fine + /* caller must have locked the device and must own + * the usb bus readlock (so driver bindings are stable); + * calls during probe() are fine */ for (i = 1; i < 16; ++i) { @@ -1199,7 +1201,7 @@ static void release_interface(struct dev * usb_set_configuration - Makes a particular device setting be current * @dev: the device whose configuration is being updated * @configuration: the configuration being chosen. - * Context: !in_interrupt(), caller holds dev->serialize + * Context: !in_interrupt(), caller owns the device lock * * This is used to enable non-default device modes. Not all devices * use this kind of configurability; many devices only have one @@ -1220,8 +1222,8 @@ static void release_interface(struct dev * usb_set_interface(). * * This call is synchronous. The calling context must be able to sleep, - * and must not hold the driver model lock for USB; usb device driver - * probe() methods may not use this routine. + * must own the device lock, and must not hold the driver model's USB + * bus rwsem; usb device driver probe() methods cannot use this routine. * * Returns zero on success, or else the status code returned by the * underlying call that failed. On succesful completion, each interface @@ -1236,8 +1238,6 @@ int usb_set_configuration(struct usb_dev struct usb_interface **new_interfaces = NULL; int n, nintf; - /* dev->serialize guards all config changes */ - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { if (dev->config[i].desc.bConfigurationValue == configuration) { cp = &dev->config[i]; diff -puN drivers/usb/core/sysfs.c~bk-usb drivers/usb/core/sysfs.c --- 25/drivers/usb/core/sysfs.c~bk-usb 2004-09-23 21:23:38.268490544 -0700 +++ 25-akpm/drivers/usb/core/sysfs.c 2004-09-23 21:23:38.638434304 -0700 @@ -55,9 +55,9 @@ set_bConfigurationValue (struct device * if (sscanf (buf, "%u", &config) != 1 || config > 255) return -EINVAL; - down(&udev->serialize); + usb_lock_device(udev); value = usb_set_configuration (udev, config); - up(&udev->serialize); + usb_unlock_device(udev); return (value < 0) ? value : count; } diff -puN drivers/usb/core/urb.c~bk-usb drivers/usb/core/urb.c --- 25/drivers/usb/core/urb.c~bk-usb 2004-09-23 21:23:38.269490392 -0700 +++ 25-akpm/drivers/usb/core/urb.c 2004-09-23 21:23:38.639434152 -0700 @@ -451,6 +451,11 @@ int usb_unlink_urb(struct urb *urb) if (!urb) return -EINVAL; if (!(urb->transfer_flags & URB_ASYNC_UNLINK)) { +#ifdef CONFIG_DEBUG_KERNEL + printk(KERN_NOTICE "usb_unlink_urb() is deprecated for " + "synchronous unlinks. Use usb_kill_urb() instead.\n"); + WARN_ON(1); +#endif usb_kill_urb(urb); return 0; } diff -puN drivers/usb/core/usb.c~bk-usb drivers/usb/core/usb.c --- 25/drivers/usb/core/usb.c~bk-usb 2004-09-23 21:23:38.271490088 -0700 +++ 25-akpm/drivers/usb/core/usb.c 2004-09-23 21:23:38.642433696 -0700 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -62,6 +63,8 @@ const char *usbcore_name = "usbcore"; int nousb; /* Disable USB when built into kernel image */ /* Not honored on modular build */ +static DECLARE_RWSEM(usb_all_devices_rwsem); + static int generic_probe (struct device *dev) { @@ -100,7 +103,10 @@ int usb_probe_interface(struct device *d id = usb_match_id (intf, driver->id_table); if (id) { dev_dbg (dev, "%s - got id\n", __FUNCTION__); + intf->condition = USB_INTERFACE_BINDING; error = driver->probe (intf, id); + intf->condition = error ? USB_INTERFACE_UNBOUND : + USB_INTERFACE_BOUND; } return error; @@ -112,6 +118,8 @@ int usb_unbind_interface(struct device * struct usb_interface *intf = to_usb_interface(dev); struct usb_driver *driver = to_usb_driver(intf->dev.driver); + intf->condition = USB_INTERFACE_UNBINDING; + /* release all urbs for this interface */ usb_disable_interface(interface_to_usbdev(intf), intf); @@ -123,6 +131,7 @@ int usb_unbind_interface(struct device * intf->altsetting[0].desc.bInterfaceNumber, 0); usb_set_intfdata(intf, NULL); + intf->condition = USB_INTERFACE_UNBOUND; return 0; } @@ -153,7 +162,9 @@ int usb_register(struct usb_driver *new_ new_driver->driver.remove = usb_unbind_interface; new_driver->driver.owner = new_driver->owner; + usb_lock_all_devices(); retval = driver_register(&new_driver->driver); + usb_unlock_all_devices(); if (!retval) { pr_info("%s: registered new driver %s\n", @@ -182,7 +193,9 @@ void usb_deregister(struct usb_driver *d { pr_info("%s: deregistering driver %s\n", usbcore_name, driver->name); + usb_lock_all_devices(); driver_unregister (&driver->driver); + usb_unlock_all_devices(); usbfs_update_special(); } @@ -204,7 +217,7 @@ void usb_deregister(struct usb_driver *d * alternate settings available for this interfaces. * * Don't call this function unless you are bound to one of the interfaces - * on this device or you own the dev->serialize semaphore! + * on this device or you have locked the device! */ struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum) { @@ -237,7 +250,7 @@ struct usb_interface *usb_ifnum_to_if(st * drivers avoid such mistakes. * * Don't call this function unless you are bound to the intf interface - * or you own the device's ->serialize semaphore! + * or you have locked the device! */ struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf, unsigned int altnum) @@ -305,11 +318,12 @@ usb_epnum_to_ep_desc(struct usb_device * * way to bind to an interface is to return the private data from * the driver's probe() method. * - * Callers must own the driver model's usb bus writelock. So driver - * probe() entries don't need extra locking, but other call contexts - * may need to explicitly claim that lock. + * Callers must own the device lock and the driver model's usb_bus_type.subsys + * writelock. So driver probe() entries don't need extra locking, + * but other call contexts may need to explicitly claim those locks. */ -int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv) +int usb_driver_claim_interface(struct usb_driver *driver, + struct usb_interface *iface, void* priv) { struct device *dev = &iface->dev; @@ -318,6 +332,7 @@ int usb_driver_claim_interface(struct us dev->driver = &driver->driver; usb_set_intfdata(iface, priv); + iface->condition = USB_INTERFACE_BOUND; /* if interface was already added, bind now; else let * the future device_add() bind it, bypassing probe() @@ -338,8 +353,8 @@ int usb_driver_claim_interface(struct us * also causes the driver disconnect() method to be called. * * This call is synchronous, and may not be used in an interrupt context. - * Callers must own the usb_device serialize semaphore and the driver model's - * usb bus writelock. So driver disconnect() entries don't need extra locking, + * Callers must own the device lock and the driver model's usb_bus_type.subsys + * writelock. So driver disconnect() entries don't need extra locking, * but other call contexts may need to explicitly claim those locks. */ void usb_driver_release_interface(struct usb_driver *driver, @@ -357,6 +372,7 @@ void usb_driver_release_interface(struct dev->driver = NULL; usb_set_intfdata(iface, NULL); + iface->condition = USB_INTERFACE_UNBOUND; } /** @@ -832,6 +848,160 @@ void usb_put_intf(struct usb_interface * put_device(&intf->dev); } + +/* USB device locking + * + * Although locking USB devices should be straightforward, it is + * complicated by the way the driver-model core works. When a new USB + * driver is registered or unregistered, the core will automatically + * probe or disconnect all matching interfaces on all USB devices while + * holding the USB subsystem writelock. There's no good way for us to + * tell which devices will be used or to lock them beforehand; our only + * option is to effectively lock all the USB devices. + * + * We do that by using a private rw-semaphore, usb_all_devices_rwsem. + * When locking an individual device you must first acquire the rwsem's + * readlock. When a driver is registered or unregistered the writelock + * must be held. These actions are encapsulated in the subroutines + * below, so all a driver needs to do is call usb_lock_device() and + * usb_unlock_device(). + * + * Complications arise when several devices are to be locked at the same + * time. Only hub-aware drivers that are part of usbcore ever have to + * do this; nobody else needs to worry about it. The problem is that + * usb_lock_device() must not be called to lock a second device since it + * would acquire the rwsem's readlock reentrantly, leading to deadlock if + * another thread was waiting for the writelock. The solution is simple: + * + * When locking more than one device, call usb_lock_device() + * to lock the first one. Lock the others by calling + * down(&udev->serialize) directly. + * + * When unlocking multiple devices, use up(&udev->serialize) + * to unlock all but the last one. Unlock the last one by + * calling usb_unlock_device(). + * + * When locking both a device and its parent, always lock the + * the parent first. + */ + +/** + * usb_lock_device - acquire the lock for a usb device structure + * @udev: device that's being locked + * + * Use this routine when you don't hold any other device locks; + * to acquire nested inner locks call down(&udev->serialize) directly. + * This is necessary for proper interaction with usb_lock_all_devices(). + */ +void usb_lock_device(struct usb_device *udev) +{ + down_read(&usb_all_devices_rwsem); + down(&udev->serialize); +} + +/** + * usb_trylock_device - attempt to acquire the lock for a usb device structure + * @udev: device that's being locked + * + * Don't use this routine if you already hold a device lock; + * use down_trylock(&udev->serialize) instead. + * This is necessary for proper interaction with usb_lock_all_devices(). + * + * Returns 1 if successful, 0 if contention. + */ +int usb_trylock_device(struct usb_device *udev) +{ + if (!down_read_trylock(&usb_all_devices_rwsem)) + return 0; + if (down_trylock(&udev->serialize)) { + up_read(&usb_all_devices_rwsem); + return 0; + } + return 1; +} + +/** + * usb_lock_device_for_reset - cautiously acquire the lock for a + * usb device structure + * @udev: device that's being locked + * @iface: interface bound to the driver making the request (optional) + * + * Attempts to acquire the device lock, but fails if the device is + * NOTATTACHED or SUSPENDED, or if iface is specified and the interface + * is neither BINDING nor BOUND. Rather than sleeping to wait for the + * lock, the routine polls repeatedly. This is to prevent deadlock with + * disconnect; in some drivers (such as usb-storage) the disconnect() + * callback will block waiting for a device reset to complete. + * + * Returns a negative error code for failure, otherwise 1 or 0 to indicate + * that the device will or will not have to be unlocked. (0 can be + * returned when an interface is given and is BINDING, because in that + * case the driver already owns the device lock.) + */ +int usb_lock_device_for_reset(struct usb_device *udev, + struct usb_interface *iface) +{ + if (udev->state == USB_STATE_NOTATTACHED) + return -ENODEV; + if (udev->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; + if (iface) { + switch (iface->condition) { + case USB_INTERFACE_BINDING: + return 0; + case USB_INTERFACE_BOUND: + break; + default: + return -EINTR; + } + } + + while (!usb_trylock_device(udev)) { + msleep(15); + if (udev->state == USB_STATE_NOTATTACHED) + return -ENODEV; + if (udev->state == USB_STATE_SUSPENDED) + return -EHOSTUNREACH; + if (iface && iface->condition != USB_INTERFACE_BOUND) + return -EINTR; + } + return 1; +} + +/** + * usb_unlock_device - release the lock for a usb device structure + * @udev: device that's being unlocked + * + * Use this routine when releasing the only device lock you hold; + * to release inner nested locks call up(&udev->serialize) directly. + * This is necessary for proper interaction with usb_lock_all_devices(). + */ +void usb_unlock_device(struct usb_device *udev) +{ + up(&udev->serialize); + up_read(&usb_all_devices_rwsem); +} + +/** + * usb_lock_all_devices - acquire the lock for all usb device structures + * + * This is necessary when registering a new driver or probing a bus, + * since the driver-model core may try to use any usb_device. + */ +void usb_lock_all_devices(void) +{ + down_write(&usb_all_devices_rwsem); +} + +/** + * usb_unlock_all_devices - release the lock for all usb device structures + */ +void usb_unlock_all_devices(void) +{ + up_write(&usb_all_devices_rwsem); +} + + static struct usb_device *match_device(struct usb_device *dev, u16 vendor_id, u16 product_id) { @@ -853,8 +1023,10 @@ static struct usb_device *match_device(s /* look through all of the children of this device */ for (child = 0; child < dev->maxchild; ++child) { if (dev->children[child]) { + down(&dev->children[child]->serialize); ret_dev = match_device(dev->children[child], vendor_id, product_id); + up(&dev->children[child]->serialize); if (ret_dev) goto exit; } @@ -889,7 +1061,9 @@ struct usb_device *usb_find_device(u16 v bus = container_of(buslist, struct usb_bus, bus_list); if (!bus->root_hub) continue; + usb_lock_device(bus->root_hub); dev = match_device(bus->root_hub, vendor_id, product_id); + usb_unlock_device(bus->root_hub); if (dev) goto exit; } @@ -1375,6 +1549,11 @@ EXPORT_SYMBOL(usb_put_dev); EXPORT_SYMBOL(usb_get_dev); EXPORT_SYMBOL(usb_hub_tt_clear_buffer); +EXPORT_SYMBOL(usb_lock_device); +EXPORT_SYMBOL(usb_trylock_device); +EXPORT_SYMBOL(usb_lock_device_for_reset); +EXPORT_SYMBOL(usb_unlock_device); + EXPORT_SYMBOL(usb_driver_claim_interface); EXPORT_SYMBOL(usb_driver_release_interface); EXPORT_SYMBOL(usb_match_id); diff -puN drivers/usb/core/usb.h~bk-usb drivers/usb/core/usb.h --- 25/drivers/usb/core/usb.h~bk-usb 2004-09-23 21:23:38.272489936 -0700 +++ 25-akpm/drivers/usb/core/usb.h 2004-09-23 21:23:38.643433544 -0700 @@ -22,8 +22,14 @@ extern int usb_get_device_descriptor(str unsigned int size); extern int usb_set_configuration(struct usb_device *dev, int configuration); -extern void usb_set_device_state(struct usb_device *udev, - enum usb_device_state new_state); +extern void usb_lock_all_devices(void); +extern void usb_unlock_all_devices(void); /* for labeling diagnostics */ extern const char *usbcore_name; + +/* usbfs stuff */ +extern struct usb_driver usbfs_driver; +extern struct file_operations usbfs_devices_fops; +extern struct file_operations usbfs_device_file_operations; +extern void usbfs_conn_disc_event(void); diff -puN drivers/usb/gadget/dummy_hcd.c~bk-usb drivers/usb/gadget/dummy_hcd.c --- 25/drivers/usb/gadget/dummy_hcd.c~bk-usb 2004-09-23 21:23:38.274489632 -0700 +++ 25-akpm/drivers/usb/gadget/dummy_hcd.c 2004-09-23 21:23:38.644433392 -0700 @@ -770,7 +770,8 @@ usb_gadget_unregister_driver (struct usb spin_lock_irqsave (&dum->lock, flags); stop_activity (dum, driver); - dum->port_status &= ~USB_PORT_STAT_CONNECTION; + dum->port_status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | + USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); dum->port_status |= (1 << USB_PORT_FEAT_C_CONNECTION); spin_unlock_irqrestore (&dum->lock, flags); @@ -815,8 +816,8 @@ static int dummy_urb_enqueue ( struct dummy *dum; unsigned long flags; - /* patch to usb_sg_init() is in 2.5.60 */ - BUG_ON (!urb->transfer_buffer && urb->transfer_buffer_length); + if (!urb->transfer_buffer && urb->transfer_buffer_length) + return -EINVAL; dum = container_of (hcd, struct dummy, hcd); spin_lock_irqsave (&dum->lock, flags); @@ -1102,10 +1103,10 @@ restart: ep = find_endpoint(dum, address); if (!ep) { /* set_configuration() disagreement */ - dev_err (hardware, + dev_dbg (hardware, "no ep configured for urb %p\n", urb); - maybe_set_status (urb, -ETIMEDOUT); + maybe_set_status (urb, -EPROTO); goto return_urb; } @@ -1409,9 +1410,12 @@ static int dummy_hub_control ( case ClearPortFeature: switch (wValue) { case USB_PORT_FEAT_SUSPEND: - /* 20msec resume signaling */ - dum->resuming = 1; - dum->re_timeout = jiffies + ((HZ * 20)/1000); + if (dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) { + /* 20msec resume signaling */ + dum->resuming = 1; + dum->re_timeout = jiffies + + msecs_to_jiffies(20); + } break; case USB_PORT_FEAT_POWER: dum->port_status = 0; @@ -1440,7 +1444,7 @@ static int dummy_hub_control ( dum->port_status &= ~(1 << USB_PORT_FEAT_SUSPEND); dum->resuming = 0; dum->re_timeout = 0; - if (dum->driver->resume) { + if (dum->driver && dum->driver->resume) { spin_unlock (&dum->lock); dum->driver->resume (&dum->gadget); spin_lock (&dum->lock); @@ -1481,11 +1485,15 @@ static int dummy_hub_control ( case SetPortFeature: switch (wValue) { case USB_PORT_FEAT_SUSPEND: - dum->port_status |= (1 << USB_PORT_FEAT_SUSPEND); - if (dum->driver->suspend) { - spin_unlock (&dum->lock); - dum->driver->suspend (&dum->gadget); - spin_lock (&dum->lock); + if ((dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) + == 0) { + dum->port_status |= + (1 << USB_PORT_FEAT_SUSPEND); + if (dum->driver && dum->driver->suspend) { + spin_unlock (&dum->lock); + dum->driver->suspend (&dum->gadget); + spin_lock (&dum->lock); + } } break; case USB_PORT_FEAT_RESET: @@ -1502,7 +1510,7 @@ static int dummy_hub_control ( /* FIXME test that code path! */ } /* 50msec reset signaling */ - dum->re_timeout = jiffies + ((HZ * 50)/1000); + dum->re_timeout = jiffies + msecs_to_jiffies(50); /* FALLTHROUGH */ default: dum->port_status |= (1 << wValue); @@ -1790,4 +1798,3 @@ static void __exit cleanup (void) the_controller = 0; } module_exit (cleanup); - diff -puN drivers/usb/gadget/ether.c~bk-usb drivers/usb/gadget/ether.c --- 25/drivers/usb/gadget/ether.c~bk-usb 2004-09-23 21:23:38.275489480 -0700 +++ 25-akpm/drivers/usb/gadget/ether.c 2004-09-23 21:23:38.800409680 -0700 @@ -231,6 +231,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethern #define DEV_CONFIG_CDC #endif +#ifdef CONFIG_USB_GADGET_N9604 +#define DEV_CONFIG_CDC +#endif + /* For CDC-incapable hardware, choose the simple cdc subset. * Anything that talks bulk (without notable bugs) can do this. @@ -2305,6 +2309,8 @@ eth_bind (struct usb_gadget *gadget) device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208); } else if (gadget_is_lh7a40x(gadget)) { device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209); + } else if (gadget_is_n9604(gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x020a); } else { /* can't assume CDC works. don't want to default to * anything less functional on CDC-capable hardware, diff -puN drivers/usb/gadget/file_storage.c~bk-usb drivers/usb/gadget/file_storage.c --- 25/drivers/usb/gadget/file_storage.c~bk-usb 2004-09-23 21:23:38.277489176 -0700 +++ 25-akpm/drivers/usb/gadget/file_storage.c 2004-09-23 21:23:38.804409072 -0700 @@ -234,6 +234,7 @@ #include #include #include +#include #include #include #include @@ -248,7 +249,7 @@ #define DRIVER_DESC "File-backed Storage Gadget" #define DRIVER_NAME "g_file_storage" -#define DRIVER_VERSION "28 July 2004" +#define DRIVER_VERSION "31 August 2004" static const char longname[] = DRIVER_DESC; static const char shortname[] = DRIVER_NAME; @@ -866,6 +867,14 @@ config_desc = { .bMaxPower = 1, // self-powered }; +static struct usb_otg_descriptor +otg_desc = { + .bLength = sizeof(otg_desc), + .bDescriptorType = USB_DT_OTG, + + .bmAttributes = USB_OTG_SRP, +}; + /* There is only one interface. */ static struct usb_interface_descriptor @@ -914,12 +923,14 @@ fs_intr_in_desc = { }; static const struct usb_descriptor_header *fs_function[] = { + (struct usb_descriptor_header *) &otg_desc, (struct usb_descriptor_header *) &intf_desc, (struct usb_descriptor_header *) &fs_bulk_in_desc, (struct usb_descriptor_header *) &fs_bulk_out_desc, (struct usb_descriptor_header *) &fs_intr_in_desc, NULL, }; +#define FS_FUNCTION_PRE_EP_ENTRIES 2 #ifdef CONFIG_USB_GADGET_DUALSPEED @@ -976,12 +987,14 @@ hs_intr_in_desc = { }; static const struct usb_descriptor_header *hs_function[] = { + (struct usb_descriptor_header *) &otg_desc, (struct usb_descriptor_header *) &intf_desc, (struct usb_descriptor_header *) &hs_bulk_in_desc, (struct usb_descriptor_header *) &hs_bulk_out_desc, (struct usb_descriptor_header *) &hs_intr_in_desc, NULL, }; +#define HS_FUNCTION_PRE_EP_ENTRIES 2 /* Maxpacket and other transfer characteristics vary by speed. */ #define ep_desc(g,fs,hs) (((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs)) @@ -1018,9 +1031,10 @@ static struct usb_gadget_strings stringt * and with code managing interfaces and their altsettings. They must * also handle different speeds and other-speed requests. */ -static int populate_config_buf(enum usb_device_speed speed, +static int populate_config_buf(struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index) { + enum usb_device_speed speed = gadget->speed; int len; const struct usb_descriptor_header **function; @@ -1036,6 +1050,10 @@ static int populate_config_buf(enum usb_ #endif function = fs_function; + /* for now, don't advertise srp-only devices */ + if (!gadget->is_otg) + function++; + len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); ((struct usb_config_descriptor *) buf)->bDescriptorType = type; return len; @@ -1366,7 +1384,7 @@ static int standard_setup_req(struct fsg #ifdef CONFIG_USB_GADGET_DUALSPEED get_config: #endif - value = populate_config_buf(fsg->gadget->speed, + value = populate_config_buf(fsg->gadget, req->buf, ctrl->wValue >> 8, ctrl->wValue & 0xff); @@ -1523,6 +1541,8 @@ static int sleep_thread(struct fsg_dev * rc = wait_event_interruptible(fsg->thread_wqh, fsg->thread_wakeup_needed); fsg->thread_wakeup_needed = 0; + if (current->flags & PF_FREEZE) + refrigerator(PF_FREEZE); return (rc ? -EINTR : 0); } @@ -3713,8 +3733,10 @@ static int __init check_parameters(struc mod_data.release = __constant_cpu_to_le16(0x0307); else if (gadget_is_omap(fsg->gadget)) mod_data.release = __constant_cpu_to_le16(0x0308); - else if (gadget_is_lh7a40x(gadget)) + else if (gadget_is_lh7a40x(fsg->gadget)) mod_data.release = __constant_cpu_to_le16 (0x0309); + else if (gadget_is_n9604(fsg->gadget)) + mod_data.release = __constant_cpu_to_le16 (0x030a); else { WARN(fsg, "controller '%s' not recognized\n", fsg->gadget->name); @@ -3882,10 +3904,10 @@ static int __init fsg_bind(struct usb_ga intf_desc.bNumEndpoints = i; intf_desc.bInterfaceSubClass = mod_data.protocol_type; intf_desc.bInterfaceProtocol = mod_data.transport_type; - fs_function[i+1] = NULL; + fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL; #ifdef CONFIG_USB_GADGET_DUALSPEED - hs_function[i+1] = NULL; + hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL; /* Assume ep0 uses the same maxpacket value for both speeds */ dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; @@ -3896,6 +3918,11 @@ static int __init fsg_bind(struct usb_ga hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress; #endif + if (gadget->is_otg) { + otg_desc.bmAttributes |= USB_OTG_HNP, + config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + } + rc = -ENOMEM; /* Allocate the request and buffer for endpoint 0 */ diff -puN drivers/usb/gadget/gadget_chips.h~bk-usb drivers/usb/gadget/gadget_chips.h --- 25/drivers/usb/gadget/gadget_chips.h~bk-usb 2004-09-23 21:23:38.279488872 -0700 +++ 25-akpm/drivers/usb/gadget/gadget_chips.h 2004-09-23 21:23:38.804409072 -0700 @@ -62,6 +62,12 @@ #define gadget_is_omap(g) 0 #endif +#ifdef CONFIG_USB_GADGET_N9604 +#define gadget_is_n9604(g) !strcmp("n9604_udc", (g)->name) +#else +#define gadget_is_n9604(g) 0 +#endif + // CONFIG_USB_GADGET_AT91RM9200 // CONFIG_USB_GADGET_SX2 // CONFIG_USB_GADGET_AU1X00 diff -puN drivers/usb/gadget/net2280.c~bk-usb drivers/usb/gadget/net2280.c --- 25/drivers/usb/gadget/net2280.c~bk-usb 2004-09-23 21:23:38.280488720 -0700 +++ 25-akpm/drivers/usb/gadget/net2280.c 2004-09-23 21:23:38.807408616 -0700 @@ -303,13 +303,16 @@ static void ep_reset (struct net2280_reg /* init to our chosen defaults, notably so that we NAK OUT * packets until the driver queues a read (+note erratum 0112) */ - writel ( (1 << SET_NAK_OUT_PACKETS_MODE) + tmp = (1 << SET_NAK_OUT_PACKETS_MODE) | (1 << SET_NAK_OUT_PACKETS) | (1 << CLEAR_EP_HIDE_STATUS_PHASE) - | (1 << CLEAR_INTERRUPT_MODE) - | (1 << CLEAR_ENDPOINT_TOGGLE) - | (1 << CLEAR_ENDPOINT_HALT) - , &ep->regs->ep_rsp); + | (1 << CLEAR_INTERRUPT_MODE); + + if (ep->num != 0) { + tmp |= (1 << CLEAR_ENDPOINT_TOGGLE) + | (1 << CLEAR_ENDPOINT_HALT); + } + writel (tmp, &ep->regs->ep_rsp); /* scrub most status bits, and flush any fifo state */ writel ( (1 << TIMEOUT) @@ -1920,8 +1923,6 @@ static void ep0_start (struct net2280 *d , &dev->usb->stdrsp); writel ( (1 << USB_ROOT_PORT_WAKEUP_ENABLE) | (1 << SELF_POWERED_USB_DEVICE) - /* erratum 0102 workaround */ - | ((dev->chiprev == 0100) ? 0 : 1) << SUSPEND_IMMEDIATELY | (1 << REMOTE_WAKEUP_SUPPORT) | (dev->softconnect << USB_DETECT_ENABLE) | (1 << SELF_POWERED_STATUS) @@ -2047,6 +2048,8 @@ int usb_gadget_unregister_driver (struct stop_activity (dev, driver); spin_unlock_irqrestore (&dev->lock, flags); + net2280_pullup (&dev->gadget, 0); + driver->unbind (&dev->gadget); dev->gadget.dev.driver = NULL; dev->driver = NULL; @@ -2552,8 +2555,6 @@ static void handle_stat1_irqs (struct ne if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) { if (dev->driver->suspend) dev->driver->suspend (&dev->gadget); - /* we use SUSPEND_IMMEDIATELY */ - stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT); } else { if (dev->driver->resume) dev->driver->resume (&dev->gadget); diff -puN drivers/usb/gadget/omap_udc.c~bk-usb drivers/usb/gadget/omap_udc.c --- 25/drivers/usb/gadget/omap_udc.c~bk-usb 2004-09-23 21:23:38.282488416 -0700 +++ 25-akpm/drivers/usb/gadget/omap_udc.c 2004-09-23 21:23:38.810408160 -0700 @@ -1200,7 +1200,8 @@ static void pullup_enable(struct omap_ud { UDC_SYSCON1_REG |= UDC_PULLUP_EN; #ifndef CONFIG_USB_OTG - OTG_CTRL_REG |= OTG_BSESSVLD; + if (!cpu_is_omap15xx()) + OTG_CTRL_REG |= OTG_BSESSVLD; #endif UDC_IRQ_EN_REG = UDC_DS_CHG_IE; } @@ -1208,7 +1209,8 @@ static void pullup_enable(struct omap_ud static void pullup_disable(struct omap_udc *udc) { #ifndef CONFIG_USB_OTG - OTG_CTRL_REG &= ~OTG_BSESSVLD; + if (!cpu_is_omap15xx()) + OTG_CTRL_REG &= ~OTG_BSESSVLD; #endif UDC_IRQ_EN_REG = UDC_DS_CHG_IE; UDC_SYSCON1_REG &= ~UDC_PULLUP_EN; @@ -1688,7 +1690,7 @@ static void devstate_irq(struct omap_udc } change &= ~UDC_SUS; } - if (change & OTG_FLAGS) { + if (!cpu_is_omap15xx() && (change & OTG_FLAGS)) { update_otg(udc); change &= ~OTG_FLAGS; } @@ -2036,34 +2038,14 @@ static char *trx_mode(unsigned m) } } -static int proc_udc_show(struct seq_file *s, void *_) +static int proc_otg_show(struct seq_file *s) { u32 tmp; - struct omap_ep *ep; - unsigned long flags; - - spin_lock_irqsave(&udc->lock, flags); - seq_printf(s, "%s, version: " DRIVER_VERSION -#ifdef USE_ISO - " (iso)" -#endif - "%s\n", - driver_desc, - use_dma ? " (dma)" : ""); - - tmp = UDC_REV_REG & 0xff; - seq_printf(s, - "UDC rev %d.%d, OTG rev %d.%d, fifo mode %d, gadget %s\n" - "hmc %d, transceiver %08x %s\n", + tmp = OTG_REV_REG; + seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %08x\n", tmp >> 4, tmp & 0xf, - OTG_REV_REG >> 4, OTG_REV_REG & 0xf, - fifo_mode, - udc->driver ? udc->driver->driver.name : "(none)", - HMC, USB_TRANSCEIVER_CTRL_REG, - udc->transceiver ? udc->transceiver->label : ""); - - /* OTG controller registers */ + USB_TRANSCEIVER_CTRL_REG); tmp = OTG_SYSCON_1_REG; seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s," FOURBITS "\n", tmp, @@ -2117,6 +2099,37 @@ static int proc_udc_show(struct seq_file seq_printf(s, "otg_outctrl %04x" "\n", tmp); tmp = OTG_TEST_REG; seq_printf(s, "otg_test %04x" "\n", tmp); +} + +static int proc_udc_show(struct seq_file *s, void *_) +{ + u32 tmp; + struct omap_ep *ep; + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + + seq_printf(s, "%s, version: " DRIVER_VERSION +#ifdef USE_ISO + " (iso)" +#endif + "%s\n", + driver_desc, + use_dma ? " (dma)" : ""); + + tmp = UDC_REV_REG & 0xff; + seq_printf(s, + "UDC rev %d.%d, fifo mode %d, gadget %s\n" + "hmc %d, transceiver %s\n", + tmp >> 4, tmp & 0xf, + fifo_mode, + udc->driver ? udc->driver->driver.name : "(none)", + HMC, + udc->transceiver ? udc->transceiver->label : ""); + + /* OTG controller registers */ + if (!cpu_is_omap15xx()) + proc_otg_show(s); tmp = UDC_SYSCON1_REG; seq_printf(s, "\nsyscon1 %04x" EIGHTBITS "\n", tmp, @@ -2496,41 +2509,51 @@ static int __init omap_udc_probe(struct return -EBUSY; } - INFO("OMAP UDC rev %d.%d, OTG rev %d.%d, %s receptacle\n", + INFO("OMAP UDC rev %d.%d, %s receptacle\n", UDC_REV_REG >> 4, UDC_REV_REG & 0xf, - OTG_REV_REG >> 4, OTG_REV_REG & 0xf, config->otg ? "Mini-AB" : "B/Mini-B"); /* use the mode given to us by board init code */ - hmc = HMC; - switch (hmc) { - case 3: - case 11: - case 19: - case 25: - xceiv = otg_get_transceiver(); - if (!xceiv) { - DBG("external transceiver not registered!\n"); - goto cleanup0; - } - type = xceiv->label; - break; - case 0: /* POWERUP DEFAULT == 0 */ - case 4: - case 12: - case 20: - type = "INTEGRATED"; - break; - case 21: /* internal loopback */ - type = "(loopback)"; - break; - case 14: /* transceiverless */ - type = "(none)"; - break; + if (cpu_is_omap15xx()) { + hmc = HMC_1510; + type = "(unknown)"; - default: - ERR("unrecognized UDC HMC mode %d\n", hmc); - return -ENODEV; + /* FIXME may need a GPIO-0 handler to call + * usb_gadget_vbus_{dis,}connect() on us... + */ + } else { + hmc = HMC_1610; + switch (hmc) { + case 3: + case 11: + case 19: + case 25: + xceiv = otg_get_transceiver(); + if (!xceiv) { + DBG("external transceiver not registered!\n"); + if (config->otg) + goto cleanup0; + type = "(unknown external)"; + } else + type = xceiv->label; + break; + case 0: /* POWERUP DEFAULT == 0 */ + case 4: + case 12: + case 20: + type = "INTEGRATED"; + break; + case 21: /* internal loopback */ + type = "(loopback)"; + break; + case 14: /* transceiverless */ + type = "(none)"; + break; + + default: + ERR("unrecognized UDC HMC mode %d\n", hmc); + return -ENODEV; + } } INFO("hmc mode %d, transceiver %s\n", hmc, type); @@ -2671,13 +2694,6 @@ static struct device_driver udc_driver = static int __init udc_init(void) { - /* should work on many OMAP systems with at most minor changes, - * but the 1510 doesn't have an OTG controller. - */ - if (cpu_is_omap1510()) { - DBG("no OMAP1510 support yet\n"); - return -ENODEV; - } INFO("%s, version: " DRIVER_VERSION "%s\n", driver_desc, use_dma ? " (dma)" : ""); return driver_register(&udc_driver); diff -puN drivers/usb/gadget/omap_udc.h~bk-usb drivers/usb/gadget/omap_udc.h --- 25/drivers/usb/gadget/omap_udc.h~bk-usb 2004-09-23 21:23:38.283488264 -0700 +++ 25-akpm/drivers/usb/gadget/omap_udc.h 2004-09-23 21:23:38.811408008 -0700 @@ -193,7 +193,14 @@ struct omap_udc { /*-------------------------------------------------------------------------*/ -// #define HMC_1510 ((MOD_CONF_CTRL_0_REG >> 1) & 0x3f) +#define MOD_CONF_CTRL_0_REG __REG32(MOD_CONF_CTRL_0) +#define VBUS_W2FC_1510 (1 << 17) /* 0 gpio0, 1 dvdd2 pin */ + +#define FUNC_MUX_CTRL_0_REG __REG32(FUNC_MUX_CTRL_0) +#define VBUS_CTRL_1510 (1 << 19) /* 1 connected (software) */ +#define VBUS_MODE_1510 (1 << 18) /* 0 hardware, 1 software */ + +#define HMC_1510 ((MOD_CONF_CTRL_0_REG >> 1) & 0x3f) #define HMC_1610 (OTG_SYSCON_2_REG & 0x3f) -#define HMC HMC_1610 +#define HMC (cpu_is_omap15xx() ? HMC_1510 : HMC_1610) diff -puN drivers/usb/gadget/zero.c~bk-usb drivers/usb/gadget/zero.c --- 25/drivers/usb/gadget/zero.c~bk-usb 2004-09-23 21:23:38.285487960 -0700 +++ 25-akpm/drivers/usb/gadget/zero.c 2004-09-23 21:23:38.812407856 -0700 @@ -1188,6 +1188,8 @@ autoconf_fail: device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208); } else if (gadget_is_lh7a40x(gadget)) { device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209); + } else if (gadget_is_n9604(gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x020a); } else { /* gadget zero is so simple (for now, no altsettings) that * it SHOULD NOT have problems with bulk-capable hardware. diff -puN drivers/usb/host/ehci.h~bk-usb drivers/usb/host/ehci.h --- 25/drivers/usb/host/ehci.h~bk-usb 2004-09-23 21:23:38.286487808 -0700 +++ 25-akpm/drivers/usb/host/ehci.h 2004-09-23 21:23:38.815407400 -0700 @@ -53,6 +53,7 @@ struct ehci_hcd { /* one per controlle struct ehci_qh *async; struct ehci_qh *reclaim; unsigned reclaim_ready : 1; + unsigned scanning : 1; /* periodic schedule support */ #define DEFAULT_I_TDPS 1024 /* some HCs can do less */ diff -puN drivers/usb/host/ehci-hcd.c~bk-usb drivers/usb/host/ehci-hcd.c --- 25/drivers/usb/host/ehci-hcd.c~bk-usb 2004-09-23 21:23:38.288487504 -0700 +++ 25-akpm/drivers/usb/host/ehci-hcd.c 2004-09-23 21:23:38.813407704 -0700 @@ -155,7 +155,7 @@ MODULE_PARM_DESC (log2_irq_thresh, "log2 * before driver shutdown. But it also seems to be caused by bugs in cardbus * bridge shutdown: shutting down the bridge before the devices using it. */ -static int handshake (u32 __iomem *ptr, u32 mask, u32 done, int usec) +static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec) { u32 result; @@ -341,8 +341,7 @@ static int ehci_hc_reset (struct usb_hcd spin_lock_init (&ehci->lock); ehci->caps = hcd->regs; - ehci->regs = (hcd->regs + - HC_LENGTH (readl (&ehci->caps->hc_capbase))); + ehci->regs = hcd->regs + HC_LENGTH (readl (&ehci->caps->hc_capbase)); dbg_hcs_params (ehci, "reset"); dbg_hcc_params (ehci, "reset"); @@ -695,9 +694,18 @@ static void ehci_work (struct ehci_hcd * timer_action_done (ehci, TIMER_IO_WATCHDOG); if (ehci->reclaim_ready) end_unlink_async (ehci, regs); + + /* another CPU may drop ehci->lock during a schedule scan while + * it reports urb completions. this flag guards against bogus + * attempts at re-entrant schedule scanning. + */ + if (ehci->scanning) + return; + ehci->scanning = 1; scan_async (ehci, regs); if (ehci->next_uframe != -1) scan_periodic (ehci, regs); + ehci->scanning = 0; /* the IO watchdog guards against hardware or driver bugs that * misplace IRQs, and should let us run completely without IRQs. diff -puN drivers/usb/host/ehci-hub.c~bk-usb drivers/usb/host/ehci-hub.c --- 25/drivers/usb/host/ehci-hub.c~bk-usb 2004-09-23 21:23:38.289487352 -0700 +++ 25-akpm/drivers/usb/host/ehci-hub.c 2004-09-23 21:23:38.814407552 -0700 @@ -81,7 +81,7 @@ static int ehci_hub_suspend (struct usb_ } -/* caller owns root->serialize, and should reset/reinit on error */ +/* caller has locked the root hub, and should reset/reinit on error */ static int ehci_hub_resume (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); diff -puN drivers/usb/host/hc_sl811.c~bk-usb drivers/usb/host/hc_sl811.c --- 25/drivers/usb/host/hc_sl811.c~bk-usb 2004-09-23 21:23:38.291487048 -0700 +++ 25-akpm/drivers/usb/host/hc_sl811.c 2004-09-23 21:23:38.816407248 -0700 @@ -1343,15 +1343,11 @@ static int __init hci_hcd_init (void) *****************************************************************/ static void __exit hci_hcd_cleanup (void) { - struct list_head *hci_l; - hci_t *hci; + hci_t *hci, *tmp; DBGFUNC ("Enter hci_hcd_cleanup\n"); - for (hci_l = hci_hcd_list.next; hci_l != &hci_hcd_list;) { - hci = list_entry (hci_l, hci_t, hci_hcd_list); - hci_l = hci_l->next; + list_for_each_entry_safe(hci, tmp, &hci_hcd_list, hci_hcd_list) hc_release_hci (hci); - } } module_init (hci_hcd_init); diff -puN drivers/usb/host/ohci-dbg.c~bk-usb drivers/usb/host/ohci-dbg.c --- 25/drivers/usb/host/ohci-dbg.c~bk-usb 2004-09-23 21:23:38.292486896 -0700 +++ 25-akpm/drivers/usb/host/ohci-dbg.c 2004-09-23 21:23:38.817407096 -0700 @@ -640,14 +640,14 @@ show_registers (struct class_device *cla rdata = ohci_readl (®s->fminterval); temp = scnprintf (next, size, "fmintvl 0x%08x %sFSMPS=0x%04x FI=0x%04x\n", - rdata, (rdata >> 31) ? " FIT" : "", + rdata, (rdata >> 31) ? "FIT " : "", (rdata >> 16) & 0xefff, rdata & 0xffff); size -= temp; next += temp; rdata = ohci_readl (®s->fmremaining); temp = scnprintf (next, size, "fmremaining 0x%08x %sFR=0x%04x\n", - rdata, (rdata >> 31) ? " FRT" : "", + rdata, (rdata >> 31) ? "FRT " : "", rdata & 0x3fff); size -= temp; next += temp; diff -puN drivers/usb/host/ohci.h~bk-usb drivers/usb/host/ohci.h --- 25/drivers/usb/host/ohci.h~bk-usb 2004-09-23 21:23:38.293486744 -0700 +++ 25-akpm/drivers/usb/host/ohci.h 2004-09-23 21:23:38.825405880 -0700 @@ -42,7 +42,6 @@ struct ed { /* create --> IDLE --> OPER --> ... --> IDLE --> destroy * usually: OPER --> UNLINK --> (IDLE | OPER) --> ... - * some special cases : OPER --> IDLE ... */ u8 state; /* ED_{IDLE,UNLINK,OPER} */ #define ED_IDLE 0x00 /* NOT linked to HC */ @@ -387,6 +386,7 @@ struct ohci_hcd { unsigned long flags; /* for HC bugs */ #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ #define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */ +#define OHCI_QUIRK_INITRESET 0x04 /* SiS, OPTi, ... */ // there are also chip quirks/bugs in init logic /* @@ -405,14 +405,14 @@ static inline void disable (struct ohci_ } #define FI 0x2edf /* 12000 bits per frame (-1) */ -#define DEFAULT_FMINTERVAL ((((6 * (FI - 210)) / 7) << 16) | FI) +#define FSMP(fi) (0x7fff & ((6 * ((fi) - 210)) / 7)) #define LSTHRESH 0x628 /* lowspeed bit threshold */ static inline void periodic_reinit (struct ohci_hcd *ohci) { - writel (ohci->fminterval, &ohci->regs->fminterval); - writel (((9 * FI) / 10) & 0x3fff, &ohci->regs->periodicstart); - writel (LSTHRESH, &ohci->regs->lsthresh); + u32 fi = ohci->fminterval & 0x0ffff; + + writel (((9 * fi) / 10) & 0x3fff, &ohci->regs->periodicstart); } /*-------------------------------------------------------------------------*/ @@ -436,6 +436,8 @@ static inline void periodic_reinit (stru # define ohci_vdbg(ohci, fmt, args...) do { } while (0) #endif +/*-------------------------------------------------------------------------*/ + #ifdef CONFIG_ARCH_LH7A404 /* Marc Singer: at the time this code was written, the LH7A404 * had a problem reading the USB host registers. This @@ -455,3 +457,25 @@ static inline unsigned int ohci_readl (v return readl (regs); } #endif + +/* AMD-756 (D2 rev) reports corrupt register contents in some cases. + * The erratum (#4) description is incorrect. AMD's workaround waits + * till some bits (mostly reserved) are clear; ok for all revs. + */ +#define read_roothub(hc, register, mask) ({ \ + u32 temp = ohci_readl (&hc->regs->roothub.register); \ + if (temp == -1) \ + disable (hc); \ + else if (hc->flags & OHCI_QUIRK_AMD756) \ + while (temp & mask) \ + temp = ohci_readl (&hc->regs->roothub.register); \ + temp; }) + +static u32 roothub_a (struct ohci_hcd *hc) + { return read_roothub (hc, a, 0xfc0fe000); } +static inline u32 roothub_b (struct ohci_hcd *hc) + { return ohci_readl (&hc->regs->roothub.b); } +static inline u32 roothub_status (struct ohci_hcd *hc) + { return ohci_readl (&hc->regs->roothub.status); } +static u32 roothub_portstatus (struct ohci_hcd *hc, int i) + { return read_roothub (hc, portstatus [i], 0xffe0fce0); } diff -puN drivers/usb/host/ohci-hcd.c~bk-usb drivers/usb/host/ohci-hcd.c --- 25/drivers/usb/host/ohci-hcd.c~bk-usb 2004-09-23 21:23:38.295486440 -0700 +++ 25-akpm/drivers/usb/host/ohci-hcd.c 2004-09-23 21:23:38.819406792 -0700 @@ -2,7 +2,7 @@ * OHCI HCD (Host Controller Driver) for USB. * * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell + * (C) Copyright 2000-2004 David Brownell * * [ Initialisation is based on Linus' ] * [ uhci code and gregs ohci fragments ] @@ -122,12 +122,27 @@ #define OHCI_INTR_INIT \ (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_WDH) +#ifdef __hppa__ +/* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */ +#define IR_DISABLE +#endif + +#ifdef CONFIG_ARCH_OMAP +/* OMAP doesn't support IR (no SMM; not needed) */ +#define IR_DISABLE +#endif + /*-------------------------------------------------------------------------*/ static const char hcd_name [] = "ohci_hcd"; #include "ohci.h" +static void ohci_dump (struct ohci_hcd *ohci, int verbose); +static int ohci_init (struct ohci_hcd *ohci); +static int ohci_restart (struct ohci_hcd *ohci); +static void ohci_stop (struct usb_hcd *hcd); + #include "ohci-hub.c" #include "ohci-dbg.c" #include "ohci-mem.c" @@ -387,30 +402,30 @@ static int ohci_get_frame (struct usb_hc return OHCI_FRAME_NO(ohci->hcca); } +static void ohci_usb_reset (struct ohci_hcd *ohci) +{ + ohci->hc_control = ohci_readl (&ohci->regs->control); + ohci->hc_control &= OHCI_CTRL_RWC; + writel (ohci->hc_control, &ohci->regs->control); +} + /*-------------------------------------------------------------------------* * HC functions *-------------------------------------------------------------------------*/ -/* reset the HC and BUS */ +/* init memory, and kick BIOS/SMM off */ -static int hc_reset (struct ohci_hcd *ohci) +static int ohci_init (struct ohci_hcd *ohci) { u32 temp; + int ret; - /* boot firmware should have set this up (5.1.1.3.1) */ - if (!ohci->fminterval) { - temp = ohci_readl (&ohci->regs->fminterval); - if (temp & 0x3fff0000) - ohci->fminterval = temp; - else - ohci->fminterval = DEFAULT_FMINTERVAL; - /* also: power/overcurrent flags in roothub.a */ - } + disable (ohci); + ohci->regs = ohci->hcd.regs; + ohci->next_statechange = jiffies; - /* SMM owns the HC? not for long! - * On PA-RISC, PDC can leave IR set incorrectly; ignore it there. - */ -#ifndef __hppa__ +#ifndef IR_DISABLE + /* SMM owns the HC? not for long! */ if (ohci_readl (&ohci->regs->control) & OHCI_CTRL_IR) { ohci_dbg (ohci, "USB HC TakeOver from BIOS/SMM\n"); @@ -426,27 +441,95 @@ static int hc_reset (struct ohci_hcd *oh msleep (10); if (--temp == 0) { ohci_err (ohci, "USB HC TakeOver failed!\n"); - return -1; + return -EBUSY; } } + ohci_usb_reset (ohci); } #endif /* Disable HC interrupts */ writel (OHCI_INTR_MIE, &ohci->regs->intrdisable); + // flush the writes + (void) ohci_readl (&ohci->regs->control); + + if (ohci->hcca) + return 0; + + ohci->hcca = dma_alloc_coherent (ohci->hcd.self.controller, + sizeof *ohci->hcca, &ohci->hcca_dma, 0); + if (!ohci->hcca) + return -ENOMEM; - ohci_dbg (ohci, "reset, control = 0x%x\n", - ohci_readl (&ohci->regs->control)); + if ((ret = ohci_mem_init (ohci)) < 0) + ohci_stop (&ohci->hcd); - /* Reset USB (needed by some controllers); RemoteWakeupConnected + return ret; + +} + +/*-------------------------------------------------------------------------*/ + +/* Start an OHCI controller, set the BUS operational + * resets USB and controller + * enable interrupts + * connect the virtual root hub + */ +static int ohci_run (struct ohci_hcd *ohci) +{ + u32 mask, temp; + struct usb_device *udev; + struct usb_bus *bus; + int first = ohci->fminterval == 0; + + disable (ohci); + + /* boot firmware should have set this up (5.1.1.3.1) */ + if (first) { + + temp = ohci_readl (&ohci->regs->fminterval); + ohci->fminterval = temp & 0x3fff; + if (ohci->fminterval != FI) + ohci_dbg (ohci, "fminterval delta %d\n", + ohci->fminterval - FI); + ohci->fminterval |= FSMP (ohci->fminterval) << 16; + /* 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) */ ohci->hc_control = ohci_readl (&ohci->regs->control); - ohci->hc_control &= OHCI_CTRL_RWC; /* hcfs 0 = RESET */ - if (ohci->hc_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->hcd.can_wakeup = 1; + + switch (ohci->hc_control & OHCI_CTRL_HCFS) { + case OHCI_USB_OPER: + temp = 0; + break; + case OHCI_USB_SUSPEND: + case OHCI_USB_RESUME: + ohci->hc_control &= OHCI_CTRL_RWC; + ohci->hc_control |= OHCI_USB_RESUME; + temp = 10 /* msec wait */; + break; + // case OHCI_USB_RESET: + default: + ohci->hc_control &= OHCI_CTRL_RWC; + ohci->hc_control |= OHCI_USB_RESET; + temp = 50 /* msec wait */; + break; + } writel (ohci->hc_control, &ohci->regs->control); + // flush the writes + (void) ohci_readl (&ohci->regs->control); + msleep(temp); if (power_switching) { unsigned ports = roothub_a (ohci) & RH_A_NDP; @@ -455,15 +538,19 @@ static int hc_reset (struct ohci_hcd *oh writel (RH_PS_LSDA, &ohci->regs->roothub.portstatus [temp]); } - // flush those pci writes + // flush those writes (void) ohci_readl (&ohci->regs->control); - msleep (50); + memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); + + /* 2msec timelimit here means no irqs/preempt */ + spin_lock_irq (&ohci->lock); /* HC Reset requires max 10 us delay */ writel (OHCI_HCR, &ohci->regs->cmdstatus); temp = 30; /* ... allow extra time */ while ((ohci_readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) { if (--temp == 0) { + spin_unlock_irq (&ohci->lock); ohci_err (ohci, "USB HC reset timed out!\n"); return -1; } @@ -477,26 +564,12 @@ static int hc_reset (struct ohci_hcd *oh * (SiS, OPTi ...), so reset again instead. SiS doesn't need * this if we write fmInterval after we're OPERATIONAL. */ - writel (ohci->hc_control, &ohci->regs->control); - // flush those pci writes - (void) ohci_readl (&ohci->regs->control); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* Start an OHCI controller, set the BUS operational - * enable interrupts - * connect the virtual root hub - */ -static int hc_start (struct ohci_hcd *ohci) -{ - u32 mask, tmp; - struct usb_device *udev; - struct usb_bus *bus; - - disable (ohci); + if (ohci->flags & OHCI_QUIRK_INITRESET) { + writel (ohci->hc_control, &ohci->regs->control); + // flush those writes + (void) ohci_readl (&ohci->regs->control); + } + writel (ohci->fminterval, &ohci->regs->fminterval); /* Tell the controller where the control and bulk lists are * The lists are empty now. */ @@ -513,7 +586,10 @@ static int hc_start (struct ohci_hcd *oh */ if ((ohci_readl (&ohci->regs->fminterval) & 0x3fff0000) == 0 || !ohci_readl (&ohci->regs->periodicstart)) { - ohci_err (ohci, "init err\n"); + spin_unlock_irq (&ohci->lock); + ohci_err (ohci, "init err (%08x %04x)\n", + ohci_readl (&ohci->regs->fminterval), + ohci_readl (&ohci->regs->periodicstart)); return -EOVERFLOW; } @@ -532,42 +608,48 @@ static int hc_start (struct ohci_hcd *oh writel (mask, &ohci->regs->intrenable); /* handle root hub init quirks ... */ - tmp = roothub_a (ohci); - tmp &= ~(RH_A_PSM | RH_A_OCPM); + temp = roothub_a (ohci); + temp &= ~(RH_A_PSM | RH_A_OCPM); if (ohci->flags & OHCI_QUIRK_SUPERIO) { /* NSC 87560 and maybe others */ - tmp |= RH_A_NOCP; - tmp &= ~(RH_A_POTPGT | RH_A_NPS); + temp |= RH_A_NOCP; + temp &= ~(RH_A_POTPGT | RH_A_NPS); } else if (power_switching) { /* act like most external hubs: use per-port power * switching and overcurrent reporting. */ - tmp &= ~(RH_A_NPS | RH_A_NOCP); - tmp |= RH_A_PSM | RH_A_OCPM; + temp &= ~(RH_A_NPS | RH_A_NOCP); + temp |= RH_A_PSM | RH_A_OCPM; } else { /* hub power always on; required for AMD-756 and some * Mac platforms. ganged overcurrent reporting, if any. */ - tmp |= RH_A_NPS; + temp |= RH_A_NPS; } - writel (tmp, &ohci->regs->roothub.a); + writel (temp, &ohci->regs->roothub.a); writel (RH_HS_LPSC, &ohci->regs->roothub.status); writel (power_switching ? RH_B_PPCM : 0, &ohci->regs->roothub.b); - // flush those pci writes + // flush those writes (void) ohci_readl (&ohci->regs->control); + spin_unlock_irq (&ohci->lock); + // POTPGT delay is bits 24-31, in 2 ms units. mdelay ((roothub_a (ohci) >> 23) & 0x1fe); bus = hcd_to_bus (&ohci->hcd); + ohci->hcd.state = USB_STATE_RUNNING; - if (bus->root_hub) { - ohci->hcd.state = USB_STATE_RUNNING; + ohci_dump (ohci, 1); + + udev = hcd_to_bus (&ohci->hcd)->root_hub; + if (udev) { + udev->dev.power.power_state = 0; + usb_set_device_state (udev, USB_STATE_CONFIGURED); return 0; } /* connect the virtual root hub */ udev = usb_alloc_dev (NULL, bus, 0); - ohci->hcd.state = USB_STATE_RUNNING; if (!udev) { disable (ohci); ohci->hc_control &= ~OHCI_CTRL_HCFS; @@ -583,7 +665,10 @@ static int hc_start (struct ohci_hcd *oh writel (ohci->hc_control, &ohci->regs->control); return -ENODEV; } + if (ohci->power_budget) + hub_set_power_budget(udev, ohci->power_budget); + create_debug_files (ohci); return 0; } @@ -620,7 +705,7 @@ static irqreturn_t ohci_irq (struct usb_ // e.g. due to PCI Master/Target Abort ohci_dump (ohci, 1); - hc_reset (ohci); + ohci_usb_reset (ohci); } if (ints & OHCI_INTR_RD) { @@ -655,7 +740,7 @@ static irqreturn_t ohci_irq (struct usb_ if (HCD_IS_RUNNING(ohci->hcd.state)) { writel (ints, ®s->intrstatus); writel (OHCI_INTR_MIE, ®s->intrenable); - // flush those pci writes + // flush those writes (void) ohci_readl (&ohci->regs->control); } @@ -674,10 +759,9 @@ static void ohci_stop (struct usb_hcd *h ohci_dump (ohci, 1); flush_scheduled_work(); - if (HCD_IS_RUNNING(ohci->hcd.state)) - hc_reset (ohci); - else - writel (OHCI_INTR_MIE, &ohci->regs->intrdisable); + + ohci_usb_reset (ohci); + writel (OHCI_INTR_MIE, &ohci->regs->intrdisable); remove_debug_files (ohci); ohci_mem_cleanup (ohci); @@ -696,19 +780,7 @@ static void ohci_stop (struct usb_hcd *h #if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM) -static void mark_children_gone (struct usb_device *dev) -{ - unsigned i; - - for (i = 0; i < dev->maxchild; i++) { - if (dev->children [i] == 0) - continue; - dev->children [i]->state = USB_STATE_NOTATTACHED; - mark_children_gone (dev->children [i]); - } -} - -static int hc_restart (struct ohci_hcd *ohci) +static int ohci_restart (struct ohci_hcd *ohci) { int temp; int i; @@ -721,7 +793,7 @@ static int hc_restart (struct ohci_hcd * */ spin_lock_irq(&ohci->lock); disable (ohci); - mark_children_gone (ohci->hcd.self.root_hub); + usb_set_device_state (ohci->hcd.self.root_hub, USB_STATE_NOTATTACHED); if (!list_empty (&ohci->pending)) ohci_dbg(ohci, "abort schedule...\n"); list_for_each_entry (priv, &ohci->pending, pending) { @@ -765,7 +837,7 @@ static int hc_restart (struct ohci_hcd * ohci->ed_controltail = NULL; ohci->ed_bulktail = NULL; - if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) { + if ((temp = ohci_run (ohci)) < 0) { ohci_err (ohci, "can't restart, %d\n", temp); return temp; } else { @@ -777,10 +849,7 @@ static int hc_restart (struct ohci_hcd * while (i--) writel (RH_PS_PSS, &ohci->regs->roothub.portstatus [temp]); - ohci->hcd.self.root_hub->dev.power.power_state = 0; - ohci->hcd.state = USB_STATE_RUNNING; ohci_dbg (ohci, "restart complete\n"); - ohci_dump (ohci, 1); } return 0; } @@ -817,3 +886,13 @@ MODULE_LICENSE ("GPL"); ) #error "missing bus glue for ohci-hcd" #endif + +#if !defined(HAVE_HNP) && defined(CONFIG_USB_OTG) + +#warning non-OTG configuration, too many HCDs + +static void start_hnp(struct ohci_hcd *ohci) +{ + /* "can't happen" */ +} +#endif diff -puN drivers/usb/host/ohci-hub.c~bk-usb drivers/usb/host/ohci-hub.c --- 25/drivers/usb/host/ohci-hub.c~bk-usb 2004-09-23 21:23:38.296486288 -0700 +++ 25-akpm/drivers/usb/host/ohci-hub.c 2004-09-23 21:23:38.821406488 -0700 @@ -2,7 +2,7 @@ * OHCI HCD (Host Controller Driver) for USB. * * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell + * (C) Copyright 2000-2004 David Brownell * * This file is licenced under GPL */ @@ -11,34 +11,8 @@ /* * OHCI Root Hub ... the nonsharable stuff - * - * Registers don't need cpu_to_le32, that happens transparently */ -/* AMD-756 (D2 rev) reports corrupt register contents in some cases. - * The erratum (#4) description is incorrect. AMD's workaround waits - * till some bits (mostly reserved) are clear; ok for all revs. - */ -#define read_roothub(hc, register, mask) ({ \ - u32 temp = ohci_readl (&hc->regs->roothub.register); \ - if (temp == -1) \ - disable (hc); \ - else if (hc->flags & OHCI_QUIRK_AMD756) \ - while (temp & mask) \ - temp = ohci_readl (&hc->regs->roothub.register); \ - temp; }) - -static u32 roothub_a (struct ohci_hcd *hc) - { return read_roothub (hc, a, 0xfc0fe000); } -static inline u32 roothub_b (struct ohci_hcd *hc) - { return ohci_readl (&hc->regs->roothub.b); } -static inline u32 roothub_status (struct ohci_hcd *hc) - { return ohci_readl (&hc->regs->roothub.status); } -static u32 roothub_portstatus (struct ohci_hcd *hc, int i) - { return read_roothub (hc, portstatus [i], 0xffe0fce0); } - -/*-------------------------------------------------------------------------*/ - #define dbg_port(hc,label,num,value) \ ohci_dbg (hc, \ "%s roothub.portstatus [%d] " \ @@ -146,10 +120,11 @@ static int ohci_hub_suspend (struct usb_ ohci->next_statechange = jiffies + msecs_to_jiffies (5); succeed: - /* it's not USB_STATE_SUSPENDED unless access to this + /* it's not HCD_STATE_SUSPENDED unless access to this * hub from the non-usb side (PCI, SOC, etc) stopped */ root->dev.power.power_state = 3; + usb_set_device_state (root, USB_STATE_SUSPENDED); done: spin_unlock_irq (&ohci->lock); return status; @@ -163,9 +138,7 @@ static inline struct ed *find_head (stru return ed; } -static int hc_restart (struct ohci_hcd *ohci); - -/* caller owns root->serialize */ +/* caller has locked the root hub */ static int ohci_hub_resume (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); @@ -180,7 +153,12 @@ static int ohci_hub_resume (struct usb_h spin_lock_irq (&ohci->lock); ohci->hc_control = ohci_readl (&ohci->regs->control); - switch (ohci->hc_control & OHCI_CTRL_HCFS) { + if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { + /* this can happen after suspend-to-disk */ + ohci_dbg (ohci, "BIOS/SMM active, control %03x\n", + ohci->hc_control); + status = -EBUSY; + } else switch (ohci->hc_control & OHCI_CTRL_HCFS) { case OHCI_USB_SUSPEND: ohci->hc_control &= ~(OHCI_CTRL_HCFS|OHCI_SCHED_ENABLES); ohci->hc_control |= OHCI_USB_RESUME; @@ -202,8 +180,10 @@ static int ohci_hub_resume (struct usb_h status = -EBUSY; } spin_unlock_irq (&ohci->lock); - if (status == -EBUSY) - return hc_restart (ohci); + if (status == -EBUSY) { + (void) ohci_init (ohci); + return ohci_restart (ohci); + } if (status != -EINPROGRESS) return status; @@ -260,6 +240,7 @@ static int ohci_hub_resume (struct usb_h /* TRSMRCY */ msleep (10); root->dev.power.power_state = 0; + usb_set_device_state (root, USB_STATE_CONFIGURED); /* keep it alive for ~5x suspend + resume costs */ ohci->next_statechange = jiffies + msecs_to_jiffies (250); @@ -289,7 +270,7 @@ static int ohci_hub_resume (struct usb_h ohci->hc_control |= enables; writel (ohci->hc_control, &ohci->regs->control); if (temp) - writel (status, &ohci->regs->cmdstatus); + writel (temp, &ohci->regs->cmdstatus); (void) ohci_readl (&ohci->regs->control); } @@ -301,9 +282,9 @@ static void ohci_rh_resume (void *_hcd) { struct usb_hcd *hcd = _hcd; - down (&hcd->self.root_hub->serialize); + usb_lock_device (hcd->self.root_hub); (void) ohci_hub_resume (hcd); - up (&hcd->self.root_hub->serialize); + usb_unlock_device (hcd->self.root_hub); } #else @@ -381,12 +362,12 @@ ohci_hub_status_data (struct usb_hcd *hc && ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES) & ohci->hc_control) == OHCI_USB_OPER - && down_trylock (&hcd->self.root_hub->serialize) == 0 + && usb_trylock_device (hcd->self.root_hub) ) { ohci_vdbg (ohci, "autosuspend\n"); (void) ohci_hub_suspend (&ohci->hcd); ohci->hcd.state = USB_STATE_RUNNING; - up (&hcd->self.root_hub->serialize); + usb_unlock_device (hcd->self.root_hub); } #endif @@ -481,8 +462,8 @@ static void start_hnp(struct ohci_hcd *o /* this timer value might be vendor-specific ... */ #define PORT_RESET_HW_MSEC 10 -/* wrap-aware logic stolen from */ -#define tick_before(t1,t2) ((((s16)(t1))-((s16)(t2))) < 0) +/* wrap-aware logic morphed from */ +#define tick_before(t1,t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0) /* called from some task, normally khubd */ static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port) diff -puN drivers/usb/host/ohci-lh7a404.c~bk-usb drivers/usb/host/ohci-lh7a404.c --- 25/drivers/usb/host/ohci-lh7a404.c~bk-usb 2004-09-23 21:23:38.298485984 -0700 +++ 25-akpm/drivers/usb/host/ohci-lh7a404.c 2004-09-23 21:23:38.822406336 -0700 @@ -229,38 +229,14 @@ ohci_lh7a404_start (struct usb_hcd *hcd) int ret; ohci_dbg (ohci, "ohci_lh7a404_start, ohci:%p", ohci); - - ohci->hcca = dma_alloc_coherent (hcd->self.controller, - sizeof *ohci->hcca, &ohci->hcca_dma, 0); - if (!ohci->hcca) - return -ENOMEM; - - ohci_dbg (ohci, "ohci_lh7a404_start, ohci->hcca:%p", - ohci->hcca); - - memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); - - if ((ret = ohci_mem_init (ohci)) < 0) { - ohci_stop (hcd); + if ((ret = ohci_init(ohci)) < 0) return ret; - } - ohci->regs = hcd->regs; - if (hc_reset (ohci) < 0) { - ohci_stop (hcd); - return -ENODEV; - } - - if (hc_start (ohci) < 0) { + if ((ret = ohci_run (ohci)) < 0) { err ("can't start %s", ohci->hcd.self.bus_name); ohci_stop (hcd); - return -EBUSY; + return ret; } - create_debug_files (ohci); - -#ifdef DEBUG - ohci_dump (ohci, 1); -#endif /*DEBUG*/ return 0; } diff -puN drivers/usb/host/ohci-omap.c~bk-usb drivers/usb/host/ohci-omap.c --- 25/drivers/usb/host/ohci-omap.c~bk-usb 2004-09-23 21:23:38.299485832 -0700 +++ 25-akpm/drivers/usb/host/ohci-omap.c 2004-09-23 21:23:38.822406336 -0700 @@ -428,40 +428,18 @@ ohci_omap_start (struct usb_hcd *hcd) struct ohci_hcd *ohci = hcd_to_ohci (hcd); int ret; - config = hcd->self.controller->platform_data; - ohci->hcca = dma_alloc_coherent (hcd->self.controller, - sizeof *ohci->hcca, &ohci->hcca_dma, 0); - if (!ohci->hcca) - return -ENOMEM; - - memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); - if ((ret = ohci_mem_init (ohci)) < 0) { - ohci_stop (hcd); + if ((ret = ohci_init(ohci)) < 0) return ret; - } - ohci->regs = hcd->regs; + config = hcd->self.controller->platform_data; if (config->otg || config->rwc) writel(OHCI_CTRL_RWC, &ohci->regs->control); - if (hc_reset (ohci) < 0) { - ohci_stop (hcd); - return -ENODEV; - } - - if (hc_start (ohci) < 0) { + if ((ret = ohci_run (ohci)) < 0) { err ("can't start %s", ohci->hcd.self.bus_name); ohci_stop (hcd); - return -EBUSY; + return ret; } - if (ohci->power_budget) - hub_set_power_budget(ohci->hcd.self.root_hub, - ohci->power_budget); - create_debug_files (ohci); - -#ifdef DEBUG - ohci_dump (ohci, 1); -#endif return 0; } diff -puN drivers/usb/host/ohci-pci.c~bk-usb drivers/usb/host/ohci-pci.c --- 25/drivers/usb/host/ohci-pci.c~bk-usb 2004-09-23 21:23:38.300485680 -0700 +++ 25-akpm/drivers/usb/host/ohci-pci.c 2004-09-23 21:23:38.823406184 -0700 @@ -35,9 +35,7 @@ ohci_pci_reset (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); - ohci->regs = hcd->regs; - ohci->next_statechange = jiffies; - return hc_reset (ohci); + return ohci_init (ohci); } static int __devinit @@ -46,11 +44,6 @@ ohci_pci_start (struct usb_hcd *hcd) struct ohci_hcd *ohci = hcd_to_ohci (hcd); int ret; - ohci->hcca = dma_alloc_coherent (hcd->self.controller, - sizeof *ohci->hcca, &ohci->hcca_dma, 0); - if (!ohci->hcca) - return -ENOMEM; - if(hcd->self.controller && hcd->self.controller->bus == &pci_bus_type) { struct pci_dev *pdev = to_pci_dev(hcd->self.controller); @@ -61,6 +54,7 @@ ohci_pci_start (struct usb_hcd *hcd) && pdev->device == 0x740c) { ohci->flags = OHCI_QUIRK_AMD756; ohci_info (ohci, "AMD756 erratum 4 workaround\n"); + // also somewhat erratum 10 (suspend/resume issues) } /* FIXME for some of the early AMD 760 southbridges, OHCI @@ -75,6 +69,8 @@ ohci_pci_start (struct usb_hcd *hcd) && pdev->device == 0xc861) { ohci_info (ohci, "WARNING: OPTi workarounds unavailable\n"); + /* OPTi sometimes acts wierd during init */ + ohci->flags = OHCI_QUIRK_INITRESET; } /* Check for NSC87560. We have to look at the bridge (fn1) to @@ -92,25 +88,23 @@ ohci_pci_start (struct usb_hcd *hcd) ohci_info (ohci, "Using NSC SuperIO setup\n"); } } - - } - memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); - if ((ret = ohci_mem_init (ohci)) < 0) { - ohci_stop (hcd); - return ret; + /* SiS sometimes acts wierd during init */ + else if (pdev->vendor == PCI_VENDOR_ID_SI) { + ohci->flags = OHCI_QUIRK_INITRESET; + ohci_info(ohci, "SiS init quirk\n"); + } + } - if (hc_start (ohci) < 0) { + /* NOTE: there may have already been a first reset, to + * keep bios/smm irqs from making trouble + */ + if ((ret = ohci_run (ohci)) < 0) { ohci_err (ohci, "can't start\n"); ohci_stop (hcd); - return -EBUSY; + return ret; } - create_debug_files (ohci); - -#ifdef DEBUG - ohci_dump (ohci, 1); -#endif return 0; } @@ -127,9 +121,9 @@ static int ohci_pci_suspend (struct usb_ #ifdef CONFIG_USB_SUSPEND (void) usb_suspend_device (hcd->self.root_hub, state); #else - down (&hcd->self.root_hub->serialize); + usb_lock_device (hcd->self.root_hub); (void) ohci_hub_suspend (hcd); - up (&hcd->self.root_hub->serialize); + usb_unlock_device (hcd->self.root_hub); #endif /* let things settle down a bit */ @@ -175,9 +169,9 @@ static int ohci_pci_resume (struct usb_h /* get extra cleanup even if remote wakeup isn't in use */ retval = usb_resume_device (hcd->self.root_hub); #else - down (&hcd->self.root_hub->serialize); + usb_lock_device (hcd->self.root_hub); retval = ohci_hub_resume (hcd); - up (&hcd->self.root_hub->serialize); + usb_unlock_device (hcd->self.root_hub); #endif if (retval == 0) { diff -puN drivers/usb/host/ohci-sa1111.c~bk-usb drivers/usb/host/ohci-sa1111.c --- 25/drivers/usb/host/ohci-sa1111.c~bk-usb 2004-09-23 21:23:38.302485376 -0700 +++ 25-akpm/drivers/usb/host/ohci-sa1111.c 2004-09-23 21:23:38.824406032 -0700 @@ -272,33 +272,14 @@ ohci_sa1111_start (struct usb_hcd *hcd) struct ohci_hcd *ohci = hcd_to_ohci (hcd); int ret; - ohci->hcca = dma_alloc_coherent (hcd->self.controller, - sizeof *ohci->hcca, &ohci->hcca_dma, 0); - if (!ohci->hcca) - return -ENOMEM; - - memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); - if ((ret = ohci_mem_init (ohci)) < 0) { - ohci_stop (hcd); + if ((ret = ohci_init(ohci)) < 0) return ret; - } - ohci->regs = hcd->regs; - if (hc_reset (ohci) < 0) { - ohci_stop (hcd); - return -ENODEV; - } - - if (hc_start (ohci) < 0) { + if ((ret = ohci_run (ohci)) < 0) { err ("can't start %s", ohci->hcd.self.bus_name); ohci_stop (hcd); - return -EBUSY; + return ret; } - create_debug_files (ohci); - -#ifdef DEBUG - ohci_dump (ohci, 1); -#endif return 0; } diff -puN drivers/usb/host/uhci-hcd.c~bk-usb drivers/usb/host/uhci-hcd.c --- 25/drivers/usb/host/uhci-hcd.c~bk-usb 2004-09-23 21:23:38.303485224 -0700 +++ 25-akpm/drivers/usb/host/uhci-hcd.c 2004-09-23 21:23:38.829405272 -0700 @@ -230,42 +230,22 @@ static void uhci_remove_td(struct uhci_h } /* - * Inserts a td into qh list at the top. + * Inserts a td list into qh. */ static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, u32 breadth) { - struct list_head *tmp, *head; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct uhci_td *td, *ptd; - - if (list_empty(&urbp->td_list)) - return; - - head = &urbp->td_list; - tmp = head->next; + struct uhci_td *td; + u32 *plink; /* Ordering isn't important here yet since the QH hasn't been */ - /* inserted into the schedule yet */ - td = list_entry(tmp, struct uhci_td, list); - - /* Add the first TD to the QH element pointer */ - qh->element = cpu_to_le32(td->dma_handle) | breadth; - - ptd = td; - - /* Then link the rest of the TD's */ - tmp = tmp->next; - while (tmp != head) { - td = list_entry(tmp, struct uhci_td, list); - - tmp = tmp->next; - - ptd->link = cpu_to_le32(td->dma_handle) | breadth; - - ptd = td; + /* inserted into the schedule yet */ + plink = &qh->element; + list_for_each_entry(td, &urbp->td_list, list) { + *plink = cpu_to_le32(td->dma_handle) | breadth; + plink = &td->link; } - - ptd->link = UHCI_PTR_TERM; + *plink = UHCI_PTR_TERM; } static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td) @@ -330,7 +310,7 @@ static void uhci_free_qh(struct uhci_hcd static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct list_head *tmp; + struct urb_priv *turbp; struct uhci_qh *lqh; /* Grab the last QH */ @@ -358,12 +338,8 @@ static void uhci_insert_qh(struct uhci_h */ lqh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH; if (lqh->urbp) { - list_for_each (tmp, &lqh->urbp->queue_list) { - struct urb_priv *turbp = - list_entry(tmp, struct urb_priv, queue_list); - + list_for_each_entry(turbp, &lqh->urbp->queue_list, queue_list) turbp->qh->link = lqh->link; - } } list_add_tail(&urbp->qh->list, &skelqh->list); @@ -405,18 +381,11 @@ static void uhci_remove_qh(struct uhci_h pqh = list_entry(qh->list.prev, struct uhci_qh, list); pqh->link = newlink; if (pqh->urbp) { - struct list_head *head, *tmp; - - head = &pqh->urbp->queue_list; - tmp = head->next; - while (head != tmp) { - struct urb_priv *turbp = - list_entry(tmp, struct urb_priv, queue_list); - - tmp = tmp->next; + struct urb_priv *turbp; + list_for_each_entry(turbp, &pqh->urbp->queue_list, + queue_list) turbp->qh->link = newlink; - } } wmb(); @@ -447,21 +416,14 @@ static void uhci_remove_qh(struct uhci_h static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct list_head *head, *tmp; - - head = &urbp->td_list; - tmp = head->next; - while (head != tmp) { - struct uhci_td *td = list_entry(tmp, struct uhci_td, list); - - tmp = tmp->next; + struct uhci_td *td; + list_for_each_entry(td, &urbp->td_list, list) { if (toggle) td->token |= cpu_to_le32(TD_TOKEN_TOGGLE); else td->token &= ~cpu_to_le32(TD_TOKEN_TOGGLE); - toggle ^= 1; } @@ -473,30 +435,19 @@ static int uhci_fixup_toggle(struct urb static void uhci_append_queued_urb(struct uhci_hcd *uhci, struct urb *eurb, struct urb *urb) { struct urb_priv *eurbp, *urbp, *furbp, *lurbp; - struct list_head *tmp; struct uhci_td *lltd; eurbp = eurb->hcpriv; urbp = urb->hcpriv; /* Find the first URB in the queue */ + furbp = eurbp; if (eurbp->queued) { - struct list_head *head = &eurbp->queue_list; - - tmp = head->next; - while (tmp != head) { - struct urb_priv *turbp = - list_entry(tmp, struct urb_priv, queue_list); - - if (!turbp->queued) + list_for_each_entry(furbp, &eurbp->queue_list, queue_list) + if (!furbp->queued) break; + } - tmp = tmp->next; - } - } else - tmp = &eurbp->queue_list; - - furbp = list_entry(tmp, struct urb_priv, queue_list); lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list); lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list); @@ -522,9 +473,7 @@ static void uhci_append_queued_urb(struc static void uhci_delete_queued_urb(struct uhci_hcd *uhci, struct urb *urb) { - struct urb_priv *urbp, *nurbp; - struct list_head *head, *tmp; - struct urb_priv *purbp; + struct urb_priv *urbp, *nurbp, *purbp, *turbp; struct uhci_td *pltd; unsigned int toggle; @@ -556,14 +505,7 @@ static void uhci_delete_queued_urb(struc toggle = uhci_toggle(td_token(pltd)) ^ 1; } - head = &urbp->queue_list; - tmp = head->next; - while (head != tmp) { - struct urb_priv *turbp; - - turbp = list_entry(tmp, struct urb_priv, queue_list); - tmp = tmp->next; - + list_for_each_entry(turbp, &urbp->queue_list, queue_list) { if (!turbp->queued) break; toggle = uhci_fixup_toggle(turbp->urb, toggle); @@ -637,7 +579,7 @@ static void uhci_remove_td_from_urb(stru static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) { - struct list_head *head, *tmp; + struct uhci_td *td, *tmp; struct urb_priv *urbp; unsigned int age; @@ -660,13 +602,7 @@ static void uhci_destroy_urb_priv(struct if (list_empty(&uhci->td_remove_list)) uhci_set_next_interrupt(uhci); - head = &urbp->td_list; - tmp = head->next; - while (tmp != head) { - struct uhci_td *td = list_entry(tmp, struct uhci_td, list); - - tmp = tmp->next; - + list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { uhci_remove_td_from_urb(td); uhci_remove_td(uhci, td); list_add(&td->remove_list, &uhci->td_remove_list); @@ -1083,7 +1019,6 @@ static int uhci_submit_common(struct uhc */ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) { - struct list_head *tmp, *head; struct urb_priv *urbp = urb->hcpriv; struct uhci_td *td; unsigned int status = 0; @@ -1091,13 +1026,7 @@ static int uhci_result_common(struct uhc urb->actual_length = 0; - head = &urbp->td_list; - tmp = head->next; - while (tmp != head) { - td = list_entry(tmp, struct uhci_td, list); - - tmp = tmp->next; - + list_for_each_entry(td, &urbp->td_list, list) { status = uhci_status_bits(td_status(td)); if (status & TD_CTRL_ACTIVE) return -EINPROGRESS; @@ -1176,17 +1105,12 @@ static inline int uhci_submit_interrupt( static int isochronous_find_limits(struct uhci_hcd *uhci, struct urb *urb, unsigned int *start, unsigned int *end) { struct urb *last_urb = NULL; - struct list_head *tmp, *head; + struct urb_priv *up; int ret = 0; - head = &uhci->urb_list; - tmp = head->next; - while (tmp != head) { - struct urb_priv *up = list_entry(tmp, struct urb_priv, urb_list); + list_for_each_entry(up, &uhci->urb_list, urb_list) { struct urb *u = up->urb; - tmp = tmp->next; - /* look for pending URB's with identical pipe handle */ if ((urb->pipe == u->pipe) && (urb->dev == u->dev) && (u->status == -EINPROGRESS) && (u != urb)) { @@ -1272,7 +1196,7 @@ static int uhci_submit_isochronous(struc static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) { - struct list_head *tmp, *head; + struct uhci_td *td; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; int status; int i, ret = 0; @@ -1280,14 +1204,9 @@ static int uhci_result_isochronous(struc urb->actual_length = 0; i = 0; - head = &urbp->td_list; - tmp = head->next; - while (tmp != head) { - struct uhci_td *td = list_entry(tmp, struct uhci_td, list); + list_for_each_entry(td, &urbp->td_list, list) { int actlength; - tmp = tmp->next; - if (td_status(td) & TD_CTRL_ACTIVE) return -EINPROGRESS; @@ -1311,20 +1230,15 @@ static int uhci_result_isochronous(struc static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb) { - struct list_head *tmp, *head; + struct urb_priv *up; /* We don't match Isoc transfers since they are special */ if (usb_pipeisoc(urb->pipe)) return NULL; - head = &uhci->urb_list; - tmp = head->next; - while (tmp != head) { - struct urb_priv *up = list_entry(tmp, struct urb_priv, urb_list); + list_for_each_entry(up, &uhci->urb_list, urb_list) { struct urb *u = up->urb; - tmp = tmp->next; - if (u->dev == urb->dev && u->status == -EINPROGRESS) { /* For control, ignore the direction */ if (usb_pipecontrol(urb->pipe) && @@ -1475,9 +1389,10 @@ out: static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb) { - struct list_head *head, *tmp; + struct list_head *head; + struct uhci_td *td; struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - int prevactive = 1; + int prevactive = 0; uhci_dec_fsbr(uhci, urb); /* Safe since it checks */ @@ -1485,25 +1400,28 @@ static void uhci_unlink_generic(struct u * Now we need to find out what the last successful toggle was * so we can update the local data toggle for the next transfer * - * There's 3 way's the last successful completed TD is found: + * There are 2 ways the last successful completed TD is found: * * 1) The TD is NOT active and the actual length < expected length * 2) The TD is NOT active and it's the last TD in the chain + * + * and a third way the first uncompleted TD is found: + * * 3) The TD is active and the previous TD is NOT active * * Control and Isochronous ignore the toggle, so this is safe * for all types + * + * FIXME: The toggle fixups won't be 100% reliable until we + * change over to using a single queue for each endpoint and + * stop the queue before unlinking. */ head = &urbp->td_list; - tmp = head->next; - while (tmp != head) { - struct uhci_td *td = list_entry(tmp, struct uhci_td, list); - - tmp = tmp->next; - + list_for_each_entry(td, head, list) { if (!(td_status(td) & TD_CTRL_ACTIVE) && - (uhci_actual_length(td_status(td)) < uhci_expected_length(td_token(td)) || - tmp == head)) + (uhci_actual_length(td_status(td)) < + uhci_expected_length(td_token(td)) || + td->list.next == head)) usb_settoggle(urb->dev, uhci_endpoint(td_token(td)), uhci_packetout(td_token(td)), uhci_toggle(td_token(td)) ^ 1); @@ -1556,7 +1474,8 @@ done: static int uhci_fsbr_timeout(struct uhci_hcd *uhci, struct urb *urb) { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; - struct list_head *head, *tmp; + struct list_head *head; + struct uhci_td *td; int count = 0; uhci_dec_fsbr(uhci, urb); @@ -1570,18 +1489,14 @@ static int uhci_fsbr_timeout(struct uhci */ head = &urbp->td_list; - tmp = head->next; - while (tmp != head) { - struct uhci_td *td = list_entry(tmp, struct uhci_td, list); - - tmp = tmp->next; - + list_for_each_entry(td, head, list) { /* * Make sure we don't do the last one (since it'll have the * TERM bit set) as well as we skip every so many TD's to * make sure it doesn't hog the bandwidth */ - if (tmp != head && (count % DEPTH_INTERVAL) == (DEPTH_INTERVAL - 1)) + if (td->list.next != head && (count % DEPTH_INTERVAL) == + (DEPTH_INTERVAL - 1)) td->link |= UHCI_PTR_DEPTH; count++; @@ -1606,12 +1521,10 @@ static void stall_callback(unsigned long { struct usb_hcd *hcd = (struct usb_hcd *)ptr; struct uhci_hcd *uhci = hcd_to_uhci(hcd); - struct list_head list, *tmp, *head; + struct urb_priv *up; unsigned long flags; int called_uhci_finish_completion = 0; - INIT_LIST_HEAD(&list); - spin_lock_irqsave(&uhci->schedule_lock, flags); if (!list_empty(&uhci->urb_remove_list) && uhci_get_current_frame_number(uhci) != uhci->urb_remove_age) { @@ -1620,14 +1533,9 @@ static void stall_callback(unsigned long called_uhci_finish_completion = 1; } - head = &uhci->urb_list; - tmp = head->next; - while (tmp != head) { - struct urb_priv *up = list_entry(tmp, struct urb_priv, urb_list); + list_for_each_entry(up, &uhci->urb_list, urb_list) { struct urb *u = up->urb; - tmp = tmp->next; - spin_lock(&u->lock); /* Check if the FSBR timed out */ @@ -1642,17 +1550,6 @@ static void stall_callback(unsigned long if (called_uhci_finish_completion) wake_up_all(&uhci->waitqh); - head = &list; - tmp = head->next; - while (tmp != head) { - struct urb_priv *up = list_entry(tmp, struct urb_priv, urb_list); - struct urb *u = up->urb; - - tmp = tmp->next; - - uhci_urb_dequeue(hcd, u); - } - /* Really disable FSBR */ if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) { uhci->fsbrtimeout = 0; @@ -1661,6 +1558,8 @@ static void stall_callback(unsigned long /* Poll for and perform state transitions */ hc_state_transitions(uhci); + if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED)) + uhci_check_resume(uhci); init_stall_timer(hcd); } @@ -1680,15 +1579,9 @@ static int init_stall_timer(struct usb_h static void uhci_free_pending_qhs(struct uhci_hcd *uhci) { - struct list_head *tmp, *head; - - head = &uhci->qh_remove_list; - tmp = head->next; - while (tmp != head) { - struct uhci_qh *qh = list_entry(tmp, struct uhci_qh, remove_list); - - tmp = tmp->next; + struct uhci_qh *qh, *tmp; + list_for_each_entry_safe(qh, tmp, &uhci->qh_remove_list, remove_list) { list_del_init(&qh->remove_list); uhci_free_qh(uhci, qh); @@ -1697,15 +1590,9 @@ static void uhci_free_pending_qhs(struct static void uhci_free_pending_tds(struct uhci_hcd *uhci) { - struct list_head *tmp, *head; - - head = &uhci->td_remove_list; - tmp = head->next; - while (tmp != head) { - struct uhci_td *td = list_entry(tmp, struct uhci_td, remove_list); - - tmp = tmp->next; + struct uhci_td *td, *tmp; + list_for_each_entry_safe(td, tmp, &uhci->td_remove_list, remove_list) { list_del_init(&td->remove_list); uhci_free_td(uhci, td); @@ -1726,19 +1613,13 @@ static void uhci_finish_urb(struct usb_h static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - struct list_head *tmp, *head; + struct urb_priv *urbp, *tmp; - head = &uhci->complete_list; - tmp = head->next; - while (tmp != head) { - struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list); + list_for_each_entry_safe(urbp, tmp, &uhci->complete_list, urb_list) { struct urb *urb = urbp->urb; list_del_init(&urbp->urb_list); uhci_finish_urb(hcd, urb, regs); - - head = &uhci->complete_list; - tmp = head->next; } } @@ -1754,7 +1635,7 @@ static irqreturn_t uhci_irq(struct usb_h struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long io_addr = uhci->io_addr; unsigned short status; - struct list_head *tmp, *head; + struct urb_priv *urbp, *tmp; unsigned int age; /* @@ -1801,15 +1682,11 @@ static irqreturn_t uhci_irq(struct usb_h else uhci_set_next_interrupt(uhci); - /* Walk the list of pending URB's to see which ones completed */ - head = &uhci->urb_list; - tmp = head->next; - while (tmp != head) { - struct urb_priv *urbp = list_entry(tmp, struct urb_priv, urb_list); + /* Walk the list of pending URBs to see which ones completed + * (must be _safe because uhci_transfer_result() dequeues URBs) */ + list_for_each_entry_safe(urbp, tmp, &uhci->urb_list, urb_list) { struct urb *urb = urbp->urb; - tmp = tmp->next; - /* Checks the status and does all of the magic necessary */ uhci_transfer_result(uhci, urb); } diff -puN drivers/usb/host/uhci-hcd.h~bk-usb drivers/usb/host/uhci-hcd.h --- 25/drivers/usb/host/uhci-hcd.h~bk-usb 2004-09-23 21:23:38.305484920 -0700 +++ 25-akpm/drivers/usb/host/uhci-hcd.h 2004-09-23 21:23:38.830405120 -0700 @@ -352,6 +352,12 @@ struct uhci_hcd { int resume_detect; /* Need a Global Resume */ unsigned int saved_framenumber; /* Save during PM suspend */ + /* Support for port suspend/resume */ + unsigned long port_c_suspend; /* Bit-arrays of ports */ + unsigned long suspended_ports; + unsigned long resuming_ports; + unsigned long resume_timeout; /* Time to stop signalling */ + /* Main list of URB's currently controlled by this HC */ struct list_head urb_list; /* P: uhci->schedule_lock */ @@ -385,12 +391,12 @@ struct urb_priv { struct uhci_qh *qh; /* QH for this URB */ struct list_head td_list; /* P: urb->lock */ - int fsbr : 1; /* URB turned on FSBR */ - int fsbr_timeout : 1; /* URB timed out on FSBR */ - int queued : 1; /* QH was queued (not linked in) */ - int short_control_packet : 1; /* If we get a short packet during */ - /* a control transfer, retrigger */ - /* the status phase */ + 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 inserttime; /* In jiffies */ unsigned long fsbrtime; /* In jiffies */ diff -puN drivers/usb/host/uhci-hub.c~bk-usb drivers/usb/host/uhci-hub.c --- 25/drivers/usb/host/uhci-hub.c~bk-usb 2004-09-23 21:23:38.306484768 -0700 +++ 25-akpm/drivers/usb/host/uhci-hub.c 2004-09-23 21:23:38.832404816 -0700 @@ -36,13 +36,13 @@ static __u8 root_hub_hub_des[] = static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - unsigned long io_addr = uhci->io_addr; - int i; + int port; *buf = 0; - for (i = 0; i < uhci->rh_numports; i++) { - if (inw(io_addr + USBPORTSC1 + i * 2) & RWC_BITS) - *buf |= (1 << (i + 1)); + for (port = 0; port < uhci->rh_numports; ++port) { + if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & RWC_BITS) || + test_bit(port, &uhci->port_c_suspend)) + *buf |= (1 << (port + 1)); } return !!*buf; } @@ -62,31 +62,67 @@ static int uhci_hub_status_data(struct u status &= ~(RWC_BITS|WZ_BITS); \ outw(status, port_addr) +/* UHCI controllers don't automatically stop resume signalling after 20 msec, + * so we have to poll and check timeouts in order to take care of it. + * FIXME: Synchronize access to these fields by a spinlock. + */ +static void uhci_finish_suspend(struct uhci_hcd *uhci, int port, + unsigned int port_addr) +{ + int status; + + if (test_bit(port, &uhci->suspended_ports)) { + CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD); + clear_bit(port, &uhci->suspended_ports); + clear_bit(port, &uhci->resuming_ports); + set_bit(port, &uhci->port_c_suspend); + } +} + +static void uhci_check_resume(struct uhci_hcd *uhci) +{ + unsigned int port; + unsigned int port_addr; + + for (port = 0; port < uhci->rh_numports; ++port) { + port_addr = uhci->io_addr + USBPORTSC1 + 2 * port; + if (unlikely(inw(port_addr) & USBPORTSC_RD)) { + if (!test_bit(port, &uhci->resuming_ports)) { + + /* Port received a wakeup request */ + set_bit(port, &uhci->resuming_ports); + uhci->resume_timeout = jiffies + + msecs_to_jiffies(20); + } else if (time_after_eq(jiffies, + uhci->resume_timeout)) { + uhci_finish_suspend(uhci, port, port_addr); + } + } + } +} /* size of returned buffer is part of USB spec */ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - int status, retval = 0, len = 0; - unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * (wIndex-1); - __u16 wPortChange, wPortStatus; + int status, lstatus, retval = 0, len = 0; + unsigned int port = wIndex - 1; + unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * port; + u16 wPortChange, wPortStatus; switch (typeReq) { - /* Request Destination: - without flags: Device, - RH_INTERFACE: interface, - RH_ENDPOINT: endpoint, - RH_CLASS means HUB here, - RH_OTHER | RH_CLASS almost ever means HUB_PORT here - */ case GetHubStatus: - *(__u32 *)buf = cpu_to_le32(0); + *(u32 *) buf = cpu_to_le32(0); OK(4); /* hub power */ case GetPortStatus: - if (!wIndex || wIndex > uhci->rh_numports) + if (port >= uhci->rh_numports) goto err; + + if (uhci->resuming_ports) + uhci_check_resume(uhci); + status = inw(port_addr); /* Intel controllers report the OverCurrent bit active on. @@ -97,37 +133,46 @@ static int uhci_hub_control(struct usb_h PCI_VENDOR_ID_VIA) status ^= USBPORTSC_OC; - /* UHCI doesn't support C_SUSPEND and C_RESET (always false) */ - wPortChange = 0; + /* UHCI doesn't support C_RESET (always false) */ + wPortChange = lstatus = 0; if (status & USBPORTSC_CSC) - wPortChange |= 1 << (USB_PORT_FEAT_C_CONNECTION - 16); + wPortChange |= USB_PORT_STAT_C_CONNECTION; if (status & USBPORTSC_PEC) - wPortChange |= 1 << (USB_PORT_FEAT_C_ENABLE - 16); + wPortChange |= USB_PORT_STAT_C_ENABLE; if (status & USBPORTSC_OCC) - wPortChange |= 1 << (USB_PORT_FEAT_C_OVER_CURRENT - 16); + wPortChange |= USB_PORT_STAT_C_OVERCURRENT; + + if (test_bit(port, &uhci->port_c_suspend)) { + wPortChange |= USB_PORT_STAT_C_SUSPEND; + lstatus |= 1; + } + if (test_bit(port, &uhci->suspended_ports)) + lstatus |= 2; + if (test_bit(port, &uhci->resuming_ports)) + lstatus |= 4; /* UHCI has no power switching (always on) */ - wPortStatus = 1 << USB_PORT_FEAT_POWER; + wPortStatus = USB_PORT_STAT_POWER; if (status & USBPORTSC_CCS) - wPortStatus |= 1 << USB_PORT_FEAT_CONNECTION; + wPortStatus |= USB_PORT_STAT_CONNECTION; if (status & USBPORTSC_PE) { - wPortStatus |= 1 << USB_PORT_FEAT_ENABLE; + wPortStatus |= USB_PORT_STAT_ENABLE; if (status & (USBPORTSC_SUSP | USBPORTSC_RD)) - wPortStatus |= 1 << USB_PORT_FEAT_SUSPEND; + wPortStatus |= USB_PORT_STAT_SUSPEND; } if (status & USBPORTSC_OC) - wPortStatus |= 1 << USB_PORT_FEAT_OVER_CURRENT; + wPortStatus |= USB_PORT_STAT_OVERCURRENT; if (status & USBPORTSC_PR) - wPortStatus |= 1 << USB_PORT_FEAT_RESET; + wPortStatus |= USB_PORT_STAT_RESET; if (status & USBPORTSC_LSDA) - wPortStatus |= 1 << USB_PORT_FEAT_LOWSPEED; + wPortStatus |= USB_PORT_STAT_LOW_SPEED; if (wPortChange) - dev_dbg(uhci_dev(uhci), "port %d portsc %04x\n", - wIndex, status); + dev_dbg(uhci_dev(uhci), "port %d portsc %04x,%02x\n", + wIndex, status, lstatus); - *(__u16 *)buf = cpu_to_le16(wPortStatus); - *(__u16 *)(buf + 2) = cpu_to_le16(wPortChange); + *(u16 *) buf = cpu_to_le16(wPortStatus); + *(u16 *) (buf + 2) = cpu_to_le16(wPortChange); OK(4); case SetHubFeature: /* We don't implement these */ case ClearHubFeature: @@ -140,11 +185,12 @@ static int uhci_hub_control(struct usb_h } break; case SetPortFeature: - if (!wIndex || wIndex > uhci->rh_numports) + if (port >= uhci->rh_numports) goto err; switch (wValue) { case USB_PORT_FEAT_SUSPEND: + set_bit(port, &uhci->suspended_ports); SET_RH_PORTSTAT(USBPORTSC_SUSP); OK(0); case USB_PORT_FEAT_RESET: @@ -152,6 +198,9 @@ static int uhci_hub_control(struct usb_h mdelay(50); /* USB v1.1 7.1.7.3 */ CLR_RH_PORTSTAT(USBPORTSC_PR); udelay(10); + + /* Reset terminates Resume signalling */ + uhci_finish_suspend(uhci, port, port_addr); SET_RH_PORTSTAT(USBPORTSC_PE); mdelay(10); CLR_RH_PORTSTAT(USBPORTSC_PEC|USBPORTSC_CSC); @@ -164,21 +213,38 @@ static int uhci_hub_control(struct usb_h } break; case ClearPortFeature: - if (!wIndex || wIndex > uhci->rh_numports) + if (port >= uhci->rh_numports) goto err; switch (wValue) { case USB_PORT_FEAT_ENABLE: CLR_RH_PORTSTAT(USBPORTSC_PE); + + /* Disable terminates Resume signalling */ + uhci_finish_suspend(uhci, port, port_addr); OK(0); case USB_PORT_FEAT_C_ENABLE: CLR_RH_PORTSTAT(USBPORTSC_PEC); OK(0); case USB_PORT_FEAT_SUSPEND: - CLR_RH_PORTSTAT(USBPORTSC_SUSP); + if (test_bit(port, &uhci->suspended_ports) && + !test_and_set_bit(port, + &uhci->resuming_ports)) { + uhci->resume_timeout = jiffies + + msecs_to_jiffies(20); + SET_RH_PORTSTAT(USBPORTSC_RD); + + /* The controller won't allow RD to be set + * if the port is disabled. When this happens + * just skip the Resume signalling. + */ + if (!(inw(port_addr) & USBPORTSC_RD)) + uhci_finish_suspend(uhci, port, + port_addr); + } OK(0); case USB_PORT_FEAT_C_SUSPEND: - /* this driver won't report these */ + clear_bit(port, &uhci->port_c_suspend); OK(0); case USB_PORT_FEAT_POWER: /* UHCI has no power switching */ diff -puN drivers/usb/image/hpusbscsi.c~bk-usb drivers/usb/image/hpusbscsi.c --- 25/drivers/usb/image/hpusbscsi.c~bk-usb 2004-09-23 21:23:38.307484616 -0700 +++ 25-akpm/drivers/usb/image/hpusbscsi.c 2004-09-23 21:23:38.833404664 -0700 @@ -106,7 +106,7 @@ hpusbscsi_usb_probe(struct usb_interface /* In host->hostdata we store a pointer to desc */ new->host = scsi_host_alloc(&hpusbscsi_scsi_host_template, sizeof(new)); if (!new->host) - goto out_unlink_controlurb; + goto out_kill_controlurb; new->host->hostdata[0] = (unsigned long)new; scsi_add_host(new->host, &intf->dev); /* XXX handle failure */ @@ -118,8 +118,8 @@ hpusbscsi_usb_probe(struct usb_interface usb_set_intfdata(intf, new); return 0; - out_unlink_controlurb: - usb_unlink_urb(new->controlurb); + out_kill_controlurb: + usb_kill_urb(new->controlurb); out_free_controlurb: usb_free_urb(new->controlurb); out_free_dataurb: @@ -137,7 +137,7 @@ hpusbscsi_usb_disconnect(struct usb_inte usb_set_intfdata(intf, NULL); scsi_remove_host(desc->host); - usb_unlink_urb(desc->controlurb); + usb_kill_urb(desc->controlurb); scsi_host_put(desc->host); usb_free_urb(desc->controlurb); @@ -280,8 +280,8 @@ static int hpusbscsi_scsi_abort (Scsi_Cm struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->device->host->hostdata[0]); printk(KERN_DEBUG"Requested is canceled.\n"); - usb_unlink_urb(hpusbscsi->dataurb); - usb_unlink_urb(hpusbscsi->controlurb); + usb_kill_urb(hpusbscsi->dataurb); + usb_kill_urb(hpusbscsi->controlurb); hpusbscsi->state = HP_STATE_FREE; return SCSI_ABORT_PENDING; diff -puN drivers/usb/image/Kconfig~bk-usb drivers/usb/image/Kconfig --- 25/drivers/usb/image/Kconfig~bk-usb 2004-09-23 21:23:38.308484464 -0700 +++ 25-akpm/drivers/usb/image/Kconfig 2004-09-23 21:23:38.832404816 -0700 @@ -30,11 +30,12 @@ config USB_MICROTEK This driver can be compiled as a module, called microtek. config USB_HPUSBSCSI - tristate "HP53xx USB scanner support (EXPERIMENTAL)" - depends on USB && SCSI && EXPERIMENTAL + tristate "HP53xx USB scanner support" + depends on USB && SCSI help Say Y here if you want support for the HP 53xx series of scanners - and the Minolta Scan Dual. This driver is experimental. + and the Minolta Scan Dual. The scanner will be accessible as a SCSI device. + Please note that recent versions of SANE use usbfs, not this driver. This can be compiled as a module, called hpusbscsi. diff -puN drivers/usb/image/mdc800.c~bk-usb drivers/usb/image/mdc800.c --- 25/drivers/usb/image/mdc800.c~bk-usb 2004-09-23 21:23:38.310484160 -0700 +++ 25-akpm/drivers/usb/image/mdc800.c 2004-09-23 21:23:38.834404512 -0700 @@ -543,9 +543,9 @@ static void mdc800_usb_disconnect (struc mdc800->state=NOT_CONNECTED; - usb_unlink_urb (mdc800->irq_urb); - usb_unlink_urb (mdc800->write_urb); - usb_unlink_urb (mdc800->download_urb); + usb_kill_urb(mdc800->irq_urb); + usb_kill_urb(mdc800->write_urb); + usb_kill_urb(mdc800->download_urb); mdc800->dev = NULL; usb_set_intfdata(intf, NULL); @@ -649,9 +649,9 @@ static int mdc800_device_release (struct down (&mdc800->io_lock); if (mdc800->open && (mdc800->state != NOT_CONNECTED)) { - usb_unlink_urb (mdc800->irq_urb); - usb_unlink_urb (mdc800->write_urb); - usb_unlink_urb (mdc800->download_urb); + usb_kill_urb(mdc800->irq_urb); + usb_kill_urb(mdc800->write_urb); + usb_kill_urb(mdc800->download_urb); mdc800->open=0; } else @@ -856,7 +856,7 @@ static ssize_t mdc800_device_write (stru mdc800->written = 0; if (mdc800->state == WORKING) { - usb_unlink_urb (mdc800->write_urb); + usb_kill_urb(mdc800->write_urb); up (&mdc800->io_lock); return -EIO; } diff -puN drivers/usb/image/microtek.c~bk-usb drivers/usb/image/microtek.c --- 25/drivers/usb/image/microtek.c~bk-usb 2004-09-23 21:23:38.311484008 -0700 +++ 25-akpm/drivers/usb/image/microtek.c 2004-09-23 21:23:38.835404360 -0700 @@ -324,7 +324,7 @@ static inline void mts_urb_abort(struct MTS_DEBUG_GOT_HERE(); mts_debug_dump(desc); - usb_unlink_urb( desc->urb ); + usb_kill_urb( desc->urb ); } static int mts_scsi_abort (Scsi_Cmnd *srb) @@ -341,12 +341,18 @@ static int mts_scsi_abort (Scsi_Cmnd *sr static int mts_scsi_host_reset (Scsi_Cmnd *srb) { struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]); + int result, rc; MTS_DEBUG_GOT_HERE(); mts_debug_dump(desc); - usb_reset_device(desc->usb_dev); /*FIXME: untested on new reset code */ - return 0; /* RANT why here 0 and not SUCCESS */ + rc = usb_lock_device_for_reset(desc->usb_dev, desc->usb_intf); + if (rc < 0) + return FAILED; + result = usb_reset_device(desc->usb_dev);; + if (rc) + usb_unlock_device(desc->usb_dev); + return result ? FAILED : SUCCESS; } static @@ -777,6 +783,7 @@ static int mts_usb_probe(struct usb_inte goto out_kfree; new_desc->usb_dev = dev; + new_desc->usb_intf = intf; init_MUTEX(&new_desc->lock); /* endpoints */ @@ -822,10 +829,10 @@ static void mts_usb_disconnect (struct u usb_set_intfdata(intf, NULL); + usb_kill_urb(desc->urb); scsi_remove_host(desc->host); - usb_unlink_urb(desc->urb); - scsi_host_put(desc->host); + scsi_host_put(desc->host); usb_free_urb(desc->urb); kfree(desc); } diff -puN drivers/usb/image/microtek.h~bk-usb drivers/usb/image/microtek.h --- 25/drivers/usb/image/microtek.h~bk-usb 2004-09-23 21:23:38.312483856 -0700 +++ 25-akpm/drivers/usb/image/microtek.h 2004-09-23 21:23:38.835404360 -0700 @@ -31,6 +31,7 @@ struct mts_desc { struct mts_desc *prev; struct usb_device *usb_dev; + struct usb_interface *usb_intf; /* Endpoint addresses */ u8 ep_out; diff -puN drivers/usb/input/aiptek.c~bk-usb drivers/usb/input/aiptek.c --- 25/drivers/usb/input/aiptek.c~bk-usb 2004-09-23 21:23:38.314483552 -0700 +++ 25-akpm/drivers/usb/input/aiptek.c 2004-09-23 21:23:38.837404056 -0700 @@ -837,7 +837,7 @@ static void aiptek_close(struct input_de struct aiptek *aiptek = inputdev->private; if (--aiptek->openCount == 0) { - usb_unlink_urb(aiptek->urb); + usb_kill_urb(aiptek->urb); } } @@ -2258,7 +2258,7 @@ static void aiptek_disconnect(struct usb if (aiptek != NULL) { /* Free & unhook everything from the system. */ - usb_unlink_urb(aiptek->urb); + usb_kill_urb(aiptek->urb); input_unregister_device(&aiptek->inputdev); aiptek_delete_files(&intf->dev); usb_free_urb(aiptek->urb); diff -puN drivers/usb/input/ati_remote.c~bk-usb drivers/usb/input/ati_remote.c --- 25/drivers/usb/input/ati_remote.c~bk-usb 2004-09-23 21:23:38.316483248 -0700 +++ 25-akpm/drivers/usb/input/ati_remote.c 2004-09-23 21:23:38.839403752 -0700 @@ -424,7 +424,7 @@ static int ati_remote_sendpacket(struct set_current_state(TASK_RUNNING); remove_wait_queue(&ati_remote->wait, &wait); - usb_unlink_urb(ati_remote->out_urb); + usb_kill_urb(ati_remote->out_urb); return retval; } @@ -624,10 +624,10 @@ static void ati_remote_delete(struct ati if (!ati_remote) return; if (ati_remote->irq_urb) - usb_unlink_urb(ati_remote->irq_urb); + usb_kill_urb(ati_remote->irq_urb); if (ati_remote->out_urb) - usb_unlink_urb(ati_remote->out_urb); + usb_kill_urb(ati_remote->out_urb); input_unregister_device(&ati_remote->idev); diff -puN drivers/usb/input/hid-core.c~bk-usb drivers/usb/input/hid-core.c --- 25/drivers/usb/input/hid-core.c~bk-usb 2004-09-23 21:23:38.317483096 -0700 +++ 25-akpm/drivers/usb/input/hid-core.c 2004-09-23 21:23:39.011377608 -0700 @@ -1353,9 +1353,9 @@ void hid_init_reports(struct hid_device while (ret) { err |= ret; if (test_bit(HID_CTRL_RUNNING, &hid->iofl)) - usb_unlink_urb(hid->urbctrl); + usb_kill_urb(hid->urbctrl); if (test_bit(HID_OUT_RUNNING, &hid->iofl)) - usb_unlink_urb(hid->urbout); + usb_kill_urb(hid->urbout); ret = hid_wait_io(hid); } @@ -1547,6 +1547,11 @@ static struct hid_blacklist { { USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW48, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28, HID_QUIRK_IGNORE }, + { 0, 0 } }; diff -puN drivers/usb/input/kbtab.c~bk-usb drivers/usb/input/kbtab.c --- 25/drivers/usb/input/kbtab.c~bk-usb 2004-09-23 21:23:38.318482944 -0700 +++ 25-akpm/drivers/usb/input/kbtab.c 2004-09-23 21:23:39.011377608 -0700 @@ -122,7 +122,7 @@ static void kbtab_close(struct input_dev struct kbtab *kbtab = dev->private; if (!--kbtab->open) - usb_unlink_urb(kbtab->irq); + usb_kill_urb(kbtab->irq); } static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -205,7 +205,7 @@ static void kbtab_disconnect(struct usb_ usb_set_intfdata(intf, NULL); if (kbtab) { - usb_unlink_urb(kbtab->irq); + usb_kill_urb(kbtab->irq); input_unregister_device(&kbtab->dev); usb_free_urb(kbtab->irq); usb_buffer_free(interface_to_usbdev(intf), 10, kbtab->data, kbtab->data_dma); diff -puN drivers/usb/input/mtouchusb.c~bk-usb drivers/usb/input/mtouchusb.c --- 25/drivers/usb/input/mtouchusb.c~bk-usb 2004-09-23 21:23:38.320482640 -0700 +++ 25-akpm/drivers/usb/input/mtouchusb.c 2004-09-23 21:23:39.012377456 -0700 @@ -155,7 +155,7 @@ static void mtouchusb_close (struct inpu struct mtouch_usb *mtouch = input->private; if (!--mtouch->open) - usb_unlink_urb (mtouch->irq); + usb_kill_urb (mtouch->irq); } static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *mtouch) @@ -320,7 +320,7 @@ static void mtouchusb_disconnect(struct usb_set_intfdata(intf, NULL); if (mtouch) { dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__); - usb_unlink_urb(mtouch->irq); + usb_kill_urb(mtouch->irq); input_unregister_device(&mtouch->input); usb_free_urb(mtouch->irq); mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch); diff -puN drivers/usb/input/pid.c~bk-usb drivers/usb/input/pid.c --- 25/drivers/usb/input/pid.c~bk-usb 2004-09-23 21:23:38.321482488 -0700 +++ 25-akpm/drivers/usb/input/pid.c 2004-09-23 21:23:39.013377304 -0700 @@ -56,7 +56,7 @@ static void hid_pid_exit(struct hid_devi struct hid_ff_pid *private = hid->ff_private; if (private->urbffout) { - usb_unlink_urb(private->urbffout); + usb_kill_urb(private->urbffout); usb_free_urb(private->urbffout); } } diff -puN drivers/usb/input/powermate.c~bk-usb drivers/usb/input/powermate.c --- 25/drivers/usb/input/powermate.c~bk-usb 2004-09-23 21:23:38.322482336 -0700 +++ 25-akpm/drivers/usb/input/powermate.c 2004-09-23 21:23:39.014377152 -0700 @@ -417,7 +417,7 @@ static void powermate_disconnect(struct usb_set_intfdata(intf, NULL); if (pm) { pm->requires_update = 0; - usb_unlink_urb(pm->irq); + usb_kill_urb(pm->irq); input_unregister_device(&pm->input); usb_free_urb(pm->irq); usb_free_urb(pm->config); diff -puN drivers/usb/input/touchkitusb.c~bk-usb drivers/usb/input/touchkitusb.c --- 25/drivers/usb/input/touchkitusb.c~bk-usb 2004-09-23 21:23:38.324482032 -0700 +++ 25-akpm/drivers/usb/input/touchkitusb.c 2004-09-23 21:23:39.014377152 -0700 @@ -141,7 +141,7 @@ static void touchkit_close(struct input_ struct touchkit_usb *touchkit = input->private; if (!--touchkit->open) - usb_unlink_urb(touchkit->irq); + usb_kill_urb(touchkit->irq); } static int touchkit_alloc_buffers(struct usb_device *udev, @@ -276,7 +276,7 @@ static void touchkit_disconnect(struct u dbg("%s - touchkit is initialized, cleaning up", __FUNCTION__); usb_set_intfdata(intf, NULL); input_unregister_device(&touchkit->input); - usb_unlink_urb(touchkit->irq); + usb_kill_urb(touchkit->irq); usb_free_urb(touchkit->irq); touchkit_free_buffers(interface_to_usbdev(intf), touchkit); kfree(touchkit); diff -puN drivers/usb/input/usbkbd.c~bk-usb drivers/usb/input/usbkbd.c --- 25/drivers/usb/input/usbkbd.c~bk-usb 2004-09-23 21:23:38.325481880 -0700 +++ 25-akpm/drivers/usb/input/usbkbd.c 2004-09-23 21:23:39.015377000 -0700 @@ -196,7 +196,7 @@ static void usb_kbd_close(struct input_d struct usb_kbd *kbd = dev->private; if (!--kbd->open) - usb_unlink_urb(kbd->irq); + usb_kill_urb(kbd->irq); } static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd) @@ -343,7 +343,7 @@ static void usb_kbd_disconnect(struct us usb_set_intfdata(intf, NULL); if (kbd) { - usb_unlink_urb(kbd->irq); + usb_kill_urb(kbd->irq); input_unregister_device(&kbd->dev); usb_kbd_free_mem(interface_to_usbdev(intf), kbd); kfree(kbd); diff -puN drivers/usb/input/usbmouse.c~bk-usb drivers/usb/input/usbmouse.c --- 25/drivers/usb/input/usbmouse.c~bk-usb 2004-09-23 21:23:38.326481728 -0700 +++ 25-akpm/drivers/usb/input/usbmouse.c 2004-09-23 21:23:39.016376848 -0700 @@ -118,7 +118,7 @@ static void usb_mouse_close(struct input struct usb_mouse *mouse = dev->private; if (!--mouse->open) - usb_unlink_urb(mouse->irq); + usb_kill_urb(mouse->irq); } static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_id * id) @@ -223,7 +223,7 @@ static void usb_mouse_disconnect(struct usb_set_intfdata(intf, NULL); if (mouse) { - usb_unlink_urb(mouse->irq); + usb_kill_urb(mouse->irq); input_unregister_device(&mouse->dev); usb_free_urb(mouse->irq); usb_buffer_free(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma); diff -puN drivers/usb/input/wacom.c~bk-usb drivers/usb/input/wacom.c --- 25/drivers/usb/input/wacom.c~bk-usb 2004-09-23 21:23:38.328481424 -0700 +++ 25-akpm/drivers/usb/input/wacom.c 2004-09-23 21:23:39.017376696 -0700 @@ -608,7 +608,7 @@ static void wacom_close(struct input_dev struct wacom *wacom = dev->private; if (!--wacom->open) - usb_unlink_urb(wacom->irq); + usb_kill_urb(wacom->irq); } static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -729,7 +729,7 @@ static void wacom_disconnect(struct usb_ usb_set_intfdata(intf, NULL); if (wacom) { - usb_unlink_urb(wacom->irq); + usb_kill_urb(wacom->irq); input_unregister_device(&wacom->dev); usb_free_urb(wacom->irq); usb_buffer_free(interface_to_usbdev(intf), 10, wacom->data, wacom->data_dma); diff -puN drivers/usb/input/xpad.c~bk-usb drivers/usb/input/xpad.c --- 25/drivers/usb/input/xpad.c~bk-usb 2004-09-23 21:23:38.329481272 -0700 +++ 25-akpm/drivers/usb/input/xpad.c 2004-09-23 21:23:39.017376696 -0700 @@ -214,7 +214,7 @@ static void xpad_close (struct input_dev struct usb_xpad *xpad = dev->private; if (!--xpad->open_count) - usb_unlink_urb(xpad->irq_in); + usb_kill_urb(xpad->irq_in); } static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -325,7 +325,7 @@ static void xpad_disconnect(struct usb_i usb_set_intfdata(intf, NULL); if (xpad) { - usb_unlink_urb(xpad->irq_in); + usb_kill_urb(xpad->irq_in); input_unregister_device(&xpad->dev); usb_free_urb(xpad->irq_in); usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); diff -puN drivers/usb/media/dabusb.c~bk-usb drivers/usb/media/dabusb.c --- 25/drivers/usb/media/dabusb.c~bk-usb 2004-09-23 21:23:38.512453456 -0700 +++ 25-akpm/drivers/usb/media/dabusb.c 2004-09-23 21:23:39.019376392 -0700 @@ -109,16 +109,13 @@ static void dump_urb (struct urb *urb) static int dabusb_cancel_queue (pdabusb_t s, struct list_head *q) { unsigned long flags; - struct list_head *p; pbuff_t b; dbg("dabusb_cancel_queue"); spin_lock_irqsave (&s->lock, flags); - for (p = q->next; p != q; p = p->next) { - b = list_entry (p, buff_t, buff_list); - + list_for_each_entry(b, q, buff_list) { #ifdef DEBUG dump_urb(b->purb); #endif @@ -598,6 +595,7 @@ static int dabusb_open (struct inode *in if (file->f_flags & O_NONBLOCK) { return -EBUSY; } + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout (HZ / 2); if (signal_pending (current)) { diff -puN drivers/usb/media/Kconfig~bk-usb drivers/usb/media/Kconfig --- 25/drivers/usb/media/Kconfig~bk-usb 2004-09-23 21:23:38.513453304 -0700 +++ 25-akpm/drivers/usb/media/Kconfig 2004-09-23 21:23:39.018376544 -0700 @@ -123,11 +123,11 @@ config USB_SE401 module will be called se401. config USB_SN9C102 - tristate "USB SN9C10[12] PC Camera Controller support" + tristate "USB SN9C10x PC Camera Controller support" depends on USB && VIDEO_DEV ---help--- - Say Y here if you want support for cameras based on SONiX SN9C101 - or SN9C102 PC Camera Controllers. + Say Y here if you want support for cameras based on SONiX SN9C101, + SN9C102 or SN9C103 PC Camera Controllers. See for more informations. diff -puN drivers/usb/media/konicawc.c~bk-usb drivers/usb/media/konicawc.c --- 25/drivers/usb/media/konicawc.c~bk-usb 2004-09-23 21:23:38.515453000 -0700 +++ 25-akpm/drivers/usb/media/konicawc.c 2004-09-23 21:23:39.021376088 -0700 @@ -362,8 +362,8 @@ static void konicawc_isoc_irq(struct urb else if (!urb->status && !cam->last_data_urb->status) len = konicawc_compress_iso(uvd, cam->last_data_urb, urb); - resubmit_urb(uvd, urb); resubmit_urb(uvd, cam->last_data_urb); + resubmit_urb(uvd, urb); cam->last_data_urb = NULL; uvd->stats.urb_length = len; uvd->stats.data_count += len; @@ -474,13 +474,8 @@ static void konicawc_stop_data(struct uv /* Unschedule all of the iso td's */ for (i=0; i < USBVIDEO_NUMSBUF; i++) { - j = usb_unlink_urb(uvd->sbuf[i].urb); - if (j < 0) - err("usb_unlink_urb() error %d.", j); - - j = usb_unlink_urb(cam->sts_urb[i]); - if (j < 0) - err("usb_unlink_urb() error %d.", j); + usb_kill_urb(uvd->sbuf[i].urb); + usb_kill_urb(cam->sts_urb[i]); } if (!uvd->remove_pending) { diff -puN drivers/usb/media/ov511.c~bk-usb drivers/usb/media/ov511.c --- 25/drivers/usb/media/ov511.c~bk-usb 2004-09-23 21:23:38.517452696 -0700 +++ 25-akpm/drivers/usb/media/ov511.c 2004-09-23 21:23:39.025375480 -0700 @@ -3830,7 +3830,7 @@ ov51x_unlink_isoc(struct usb_ov511 *ov) /* Unschedule all of the iso td's */ for (n = OV511_NUMSBUF - 1; n >= 0; n--) { if (ov->sbuf[n].urb) { - usb_unlink_urb(ov->sbuf[n].urb); + usb_kill_urb(ov->sbuf[n].urb); usb_free_urb(ov->sbuf[n].urb); ov->sbuf[n].urb = NULL; } diff -puN drivers/usb/media/se401.c~bk-usb drivers/usb/media/se401.c --- 25/drivers/usb/media/se401.c~bk-usb 2004-09-23 21:23:38.518452544 -0700 +++ 25-akpm/drivers/usb/media/se401.c 2004-09-23 21:23:39.027375176 -0700 @@ -514,7 +514,7 @@ static int se401_stop_stream(struct usb_ se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0); for (i=0; iurb[i]) { - usb_unlink_urb(se401->urb[i]); + usb_kill_urb(se401->urb[i]); usb_free_urb(se401->urb[i]); se401->urb[i]=NULL; kfree(se401->sbuf[i].data); @@ -883,7 +883,7 @@ static void usb_se401_remove_disconnecte se401->dev = NULL; for (i=0; iurb[i]) { - usb_unlink_urb(se401->urb[i]); + usb_kill_urb(se401->urb[i]); usb_free_urb(se401->urb[i]); se401->urb[i] = NULL; kfree(se401->sbuf[i].data); @@ -892,7 +892,7 @@ static void usb_se401_remove_disconnecte kfree(se401->scratch[i].data); } if (se401->inturb) { - usb_unlink_urb(se401->inturb); + usb_kill_urb(se401->inturb); usb_free_urb(se401->inturb); } info("%s disconnected", se401->camera_name); diff -puN drivers/usb/media/sn9c102_core.c~bk-usb drivers/usb/media/sn9c102_core.c --- 25/drivers/usb/media/sn9c102_core.c~bk-usb 2004-09-23 21:23:38.520452240 -0700 +++ 25-akpm/drivers/usb/media/sn9c102_core.c 2004-09-23 21:23:39.030374720 -0700 @@ -1,5 +1,5 @@ /*************************************************************************** - * V4L2 driver for SN9C10[12] PC Camera Controllers * + * V4L2 driver for SN9C10x PC Camera Controllers * * * * Copyright (C) 2004 by Luca Risolia * * * @@ -169,15 +169,15 @@ static u32 sn9c102_request_buffers(struc cam->nbuffers = count; while (cam->nbuffers > 0) { - if ((buff = rvmalloc(cam->nbuffers * imagesize))) + if ((buff = rvmalloc(cam->nbuffers * PAGE_ALIGN(imagesize)))) break; cam->nbuffers--; } for (i = 0; i < cam->nbuffers; i++) { - cam->frame[i].bufmem = buff + i*imagesize; + cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize); cam->frame[i].buf.index = i; - cam->frame[i].buf.m.offset = i*imagesize; + cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize); cam->frame[i].buf.length = imagesize; cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; cam->frame[i].buf.sequence = 0; @@ -388,7 +388,7 @@ sn9c102_i2c_try_raw_write(struct sn9c102 data[4] = data3; data[5] = data4; data[6] = data5; - data[7] = 0x10; + data[7] = 0x14; res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, 0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT); if (res < 0) @@ -400,7 +400,7 @@ sn9c102_i2c_try_raw_write(struct sn9c102 if (err) DBG(3, "I2C write failed for %s image sensor", sensor->name) - PDBGG("I2C write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, " + PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, " "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X", n, data0, data1, data2, data3, data4, data5) @@ -634,7 +634,7 @@ static int sn9c102_start_transfer(struct struct usb_device *udev = cam->usbdev; struct urb* urb; const unsigned int wMaxPacketSize[] = {0, 128, 256, 384, 512, - 680, 800, 900, 1023}; + 680, 800, 900, 1023}; const unsigned int psz = wMaxPacketSize[SN9C102_ALTERNATE_SETTING]; s8 i, j; int err = 0; @@ -965,6 +965,11 @@ static ssize_t sn9c102_show_i2c_val(stru return -ENODEV; } + if (cam->sensor->slave_read_id == SN9C102_I2C_SLAVEID_UNAVAILABLE) { + up(&sn9c102_sysfs_lock); + return -ENOSYS; + } + if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) { up(&sn9c102_sysfs_lock); return -EIO; @@ -1022,15 +1027,79 @@ sn9c102_store_i2c_val(struct class_devic static ssize_t sn9c102_store_green(struct class_device* cd, const char* buf, size_t len) { + struct sn9c102_device* cam; + enum sn9c102_bridge bridge; + ssize_t res = 0; + u8 value; + ssize_t count; + + if (down_interruptible(&sn9c102_sysfs_lock)) + return -ERESTARTSYS; + + cam = video_get_drvdata(to_video_device(cd)); + if (!cam) { + up(&sn9c102_sysfs_lock); + return -ENODEV; + } + + bridge = cam->bridge; + + up(&sn9c102_sysfs_lock); + + value = sn9c102_strtou8(buf, len, &count); + if (!count) + return -EINVAL; + + switch (bridge) { + case BRIDGE_SN9C101: + case BRIDGE_SN9C102: + if (value > 0x0f) + return -EINVAL; + if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0) + res = sn9c102_store_val(cd, buf, len); + break; + case BRIDGE_SN9C103: + if (value > 0x7f) + return -EINVAL; + if ((res = sn9c102_store_reg(cd, "0x04", 4)) >= 0) + res = sn9c102_store_val(cd, buf, len); + break; + } + + return res; +} + + +static ssize_t +sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len) +{ ssize_t res = 0; u8 value; ssize_t count; value = sn9c102_strtou8(buf, len, &count); - if (!count || value > 0x0f) + if (!count || value > 0x7f) return -EINVAL; - if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0) + if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0) + res = sn9c102_store_val(cd, buf, len); + + return res; +} + + +static ssize_t +sn9c102_store_red(struct class_device* cd, const char* buf, size_t len) +{ + ssize_t res = 0; + u8 value; + ssize_t count; + + value = sn9c102_strtou8(buf, len, &count); + if (!count || value > 0x7f) + return -EINVAL; + + if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0) res = sn9c102_store_val(cd, buf, len); return res; @@ -1046,6 +1115,8 @@ static CLASS_DEVICE_ATTR(i2c_reg, S_IRUG static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, sn9c102_show_i2c_val, sn9c102_store_i2c_val); static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green); +static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue); +static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red); static void sn9c102_create_sysfs(struct sn9c102_device* cam) @@ -1054,8 +1125,14 @@ static void sn9c102_create_sysfs(struct video_device_create_file(v4ldev, &class_device_attr_reg); video_device_create_file(v4ldev, &class_device_attr_val); - video_device_create_file(v4ldev, &class_device_attr_green); - if (cam->sensor->slave_write_id && cam->sensor->slave_read_id) { + if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) + video_device_create_file(v4ldev, &class_device_attr_green); + else if (cam->bridge == BRIDGE_SN9C103) { + video_device_create_file(v4ldev, &class_device_attr_blue); + video_device_create_file(v4ldev, &class_device_attr_red); + } + if (cam->sensor->slave_write_id != SN9C102_I2C_SLAVEID_UNAVAILABLE || + cam->sensor->slave_read_id != SN9C102_I2C_SLAVEID_UNAVAILABLE) { video_device_create_file(v4ldev, &class_device_attr_i2c_reg); video_device_create_file(v4ldev, &class_device_attr_i2c_val); } @@ -1092,21 +1169,13 @@ static int sn9c102_set_crop(struct sn9c1 u8 h_start = (u8)(rect->left - s->cropcap.bounds.left), v_start = (u8)(rect->top - s->cropcap.bounds.top), h_size = (u8)(rect->width / 16), - v_size = (u8)(rect->height / 16), - ae_strx = 0x00, - ae_stry = 0x00, - ae_endx = h_size / 2, - ae_endy = v_size / 2; + v_size = (u8)(rect->height / 16); int err = 0; err += sn9c102_write_reg(cam, h_start, 0x12); err += sn9c102_write_reg(cam, v_start, 0x13); err += sn9c102_write_reg(cam, h_size, 0x15); err += sn9c102_write_reg(cam, v_size, 0x16); - err += sn9c102_write_reg(cam, ae_strx, 0x1c); - err += sn9c102_write_reg(cam, ae_stry, 0x1d); - err += sn9c102_write_reg(cam, ae_endx, 0x1e); - err += sn9c102_write_reg(cam, ae_endy, 0x1f); if (err) return -EIO; @@ -1636,16 +1705,21 @@ static int sn9c102_v4l2_ioctl(struct ino if (copy_from_user(&ctrl, arg, sizeof(ctrl))) return -EFAULT; - if ((err = s->set_ctrl(cam, &ctrl))) - return err; - n = sizeof(s->qctrl) / sizeof(s->qctrl[0]); for (i = 0; i < n; i++) if (ctrl.id == s->qctrl[i].id) { - s->_qctrl[i].default_value = ctrl.value; + if (ctrl.value < s->qctrl[i].minimum || + ctrl.value > s->qctrl[i].maximum) + return -ERANGE; + ctrl.value -= ctrl.value % s->qctrl[i].step; break; } + if ((err = s->set_ctrl(cam, &ctrl))) + return err; + + s->_qctrl[i].default_value = ctrl.value; + return 0; } @@ -1776,7 +1850,7 @@ static int sn9c102_v4l2_ioctl(struct ino DBG(1, "VIDIOC_S_CROP failed because of hardware " "problems. To use the camera, close and open " "/dev/video%d again.", cam->v4ldev->minor) - return err; + return -EIO; } s->pix_format.width = rect->width/scale; @@ -1951,7 +2025,7 @@ static int sn9c102_v4l2_ioctl(struct ino DBG(1, "VIDIOC_S_FMT failed because of hardware " "problems. To use the camera, close and open " "/dev/video%d again.", cam->v4ldev->minor) - return err; + return -EIO; } memcpy(pfmt, pix, sizeof(*pix)); @@ -2286,16 +2360,28 @@ sn9c102_usb_probe(struct usb_interface* r = sn9c102_read_reg(cam, 0x00); if (r < 0 || r != 0x10) { - DBG(1, "Sorry, this is not a SN9C10[12] based camera " + DBG(1, "Sorry, this is not a SN9C10x based camera " "(vid/pid 0x%04X/0x%04X)", sn9c102_id_table[i].idVendor,sn9c102_id_table[i].idProduct) err = -ENODEV; goto fail; } - DBG(2, "SN9C10[12] PC Camera Controller detected " - "(vid/pid 0x%04X/0x%04X)", - sn9c102_id_table[i].idVendor, sn9c102_id_table[i].idProduct) + cam->bridge = (sn9c102_id_table[i].idProduct & 0xffc0) == 0x6080 ? + BRIDGE_SN9C103 : BRIDGE_SN9C102; + switch (cam->bridge) { + case BRIDGE_SN9C101: + case BRIDGE_SN9C102: + DBG(2, "SN9C10[12] PC Camera Controller detected " + "(vid/pid 0x%04X/0x%04X)", sn9c102_id_table[i].idVendor, + sn9c102_id_table[i].idProduct) + break; + case BRIDGE_SN9C103: + DBG(2, "SN9C103 PC Camera Controller detected " + "(vid/pid 0x%04X/0x%04X)", sn9c102_id_table[i].idVendor, + sn9c102_id_table[i].idProduct) + break; + } for (i = 0; sn9c102_sensor_table[i]; i++) { err = sn9c102_sensor_table[i](cam); @@ -2318,7 +2404,7 @@ sn9c102_usb_probe(struct usb_interface* cam->state |= DEV_MISCONFIGURED; } - strcpy(cam->v4ldev->name, "SN9C10[12] PC Camera"); + strcpy(cam->v4ldev->name, "SN9C10x PC Camera"); cam->v4ldev->owner = THIS_MODULE; cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; cam->v4ldev->hardware = VID_HARDWARE_SN9C102; diff -puN drivers/usb/media/sn9c102.h~bk-usb drivers/usb/media/sn9c102.h --- 25/drivers/usb/media/sn9c102.h~bk-usb 2004-09-23 21:23:38.521452088 -0700 +++ 25-akpm/drivers/usb/media/sn9c102.h 2004-09-23 21:23:39.027375176 -0700 @@ -1,5 +1,5 @@ /*************************************************************************** - * V4L2 driver for SN9C10[12] PC Camera Controllers * + * V4L2 driver for SN9C10x PC Camera Controllers * * * * Copyright (C) 2004 by Luca Risolia * * * @@ -49,15 +49,21 @@ /*****************************************************************************/ -#define SN9C102_MODULE_NAME "V4L2 driver for SN9C10[12] PC Camera Controllers" +#define SN9C102_MODULE_NAME "V4L2 driver for SN9C10x PC Camera Controllers" #define SN9C102_MODULE_AUTHOR "(C) 2004 Luca Risolia" #define SN9C102_AUTHOR_EMAIL "" #define SN9C102_MODULE_LICENSE "GPL" -#define SN9C102_MODULE_VERSION "1:1.08" -#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 8) +#define SN9C102_MODULE_VERSION "1:1.12" +#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 12) -SN9C102_ID_TABLE; -SN9C102_SENSOR_TABLE; +enum sn9c102_bridge { + BRIDGE_SN9C101 = 0x01, + BRIDGE_SN9C102 = 0x02, + BRIDGE_SN9C103 = 0x04, +}; + +SN9C102_ID_TABLE +SN9C102_SENSOR_TABLE enum sn9c102_frame_state { F_UNUSED, @@ -105,6 +111,7 @@ struct sn9c102_device { struct video_device* v4ldev; + enum sn9c102_bridge bridge; struct sn9c102_sensor* sensor; struct usb_device* usbdev; diff -puN drivers/usb/media/sn9c102_pas106b.c~bk-usb drivers/usb/media/sn9c102_pas106b.c --- 25/drivers/usb/media/sn9c102_pas106b.c~bk-usb 2004-09-23 21:23:38.523451784 -0700 +++ 25-akpm/drivers/usb/media/sn9c102_pas106b.c 2004-09-23 21:23:39.031374568 -0700 @@ -1,5 +1,5 @@ /*************************************************************************** - * Driver for PAS106B image sensor connected to the SN9C10[12] PC Camera * + * Driver for PAS106B image sensor connected to the SN9C10x PC Camera * * Controllers * * * * Copyright (C) 2004 by Luca Risolia * @@ -100,26 +100,26 @@ static int pas106b_set_ctrl(struct sn9c1 switch (ctrl->id) { case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_write(cam, 0x0c, ctrl->value & 0x1f); + err += sn9c102_i2c_write(cam, 0x0c, ctrl->value); break; case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_write(cam, 0x09, ctrl->value & 0x1f); + err += sn9c102_i2c_write(cam, 0x09, ctrl->value); break; case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x0e, ctrl->value & 0x1f); + err += sn9c102_i2c_write(cam, 0x0e, ctrl->value); break; case V4L2_CID_BRIGHTNESS: - err += sn9c102_i2c_write(cam, 0x0d, 0x1f-(ctrl->value & 0x1f)); + err += sn9c102_i2c_write(cam, 0x0d, 0x1f - ctrl->value); break; case V4L2_CID_CONTRAST: - err += sn9c102_i2c_write(cam, 0x0f, ctrl->value & 0x03); + err += sn9c102_i2c_write(cam, 0x0f, ctrl->value); break; default: return -EINVAL; } err += sn9c102_i2c_write(cam, 0x13, 0x01); - return err; + return err ? -EIO : 0; } diff -puN drivers/usb/media/sn9c102_pas202bcb.c~bk-usb drivers/usb/media/sn9c102_pas202bcb.c --- 25/drivers/usb/media/sn9c102_pas202bcb.c~bk-usb 2004-09-23 21:23:38.524451632 -0700 +++ 25-akpm/drivers/usb/media/sn9c102_pas202bcb.c 2004-09-23 21:23:39.032374416 -0700 @@ -1,5 +1,5 @@ /*************************************************************************** - * Driver for PAS202BCB image sensor connected to the SN9C10[12] PC Camera * + * Driver for PAS202BCB image sensor connected to the SN9C10x PC Camera * * Controllers * * * * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio * @@ -36,18 +36,19 @@ static int pas202bcb_init(struct sn9c102 err += sn9c102_write_reg(cam, 0x00, 0x11); err += sn9c102_write_reg(cam, 0x00, 0x14); err += sn9c102_write_reg(cam, 0x20, 0x17); - err += sn9c102_write_reg(cam, 0x20, 0x19); + err += sn9c102_write_reg(cam, 0x30, 0x19); err += sn9c102_write_reg(cam, 0x09, 0x18); - err += sn9c102_i2c_write(cam, 0x02, 0x0c); + err += sn9c102_i2c_write(cam, 0x02, 0x14); err += sn9c102_i2c_write(cam, 0x03, 0x40); err += sn9c102_i2c_write(cam, 0x04, 0x07); err += sn9c102_i2c_write(cam, 0x05, 0x25); err += sn9c102_i2c_write(cam, 0x0d, 0x2c); err += sn9c102_i2c_write(cam, 0x0e, 0x01); err += sn9c102_i2c_write(cam, 0x0f, 0xa9); - err += sn9c102_i2c_write(cam, 0x08, 0x01); + err += sn9c102_i2c_write(cam, 0x10, 0x08); err += sn9c102_i2c_write(cam, 0x0b, 0x01); + err += sn9c102_i2c_write(cam, 0x0c, 0x04); err += sn9c102_i2c_write(cam, 0x13, 0x63); err += sn9c102_i2c_write(cam, 0x15, 0x70); err += sn9c102_i2c_write(cam, 0x11, 0x01); @@ -95,23 +96,23 @@ static int pas202bcb_set_ctrl(struct sn9 switch (ctrl->id) { case V4L2_CID_RED_BALANCE: - err += sn9c102_i2c_write(cam, 0x09, ctrl->value & 0x0f); + err += sn9c102_i2c_write(cam, 0x09, ctrl->value); break; case V4L2_CID_BLUE_BALANCE: - err += sn9c102_i2c_write(cam, 0x07, ctrl->value & 0x0f); + err += sn9c102_i2c_write(cam, 0x07, ctrl->value); break; case V4L2_CID_GAIN: - err += sn9c102_i2c_write(cam, 0x10, ctrl->value & 0x1f); + err += sn9c102_i2c_write(cam, 0x10, ctrl->value); break; case V4L2_CID_BRIGHTNESS: - err += sn9c102_i2c_write(cam, 0x06, 0x0f-(ctrl->value & 0x0f)); + err += sn9c102_i2c_write(cam, 0x06, 0x0f - ctrl->value); break; default: return -EINVAL; } err += sn9c102_i2c_write(cam, 0x11, 0x01); - return err; + return err ? -EIO : 0; } @@ -217,7 +218,7 @@ int sn9c102_probe_pas202bcb(struct sn9c1 * NOTE: do NOT change the values! */ err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */ - err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */ + err += sn9c102_write_reg(cam, 0x40, 0x01); /* sensor power on */ err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */ if (err) return -EIO; diff -puN drivers/usb/media/sn9c102_sensor.h~bk-usb drivers/usb/media/sn9c102_sensor.h --- 25/drivers/usb/media/sn9c102_sensor.h~bk-usb 2004-09-23 21:23:38.526451328 -0700 +++ 25-akpm/drivers/usb/media/sn9c102_sensor.h 2004-09-23 21:23:39.033374264 -0700 @@ -1,5 +1,5 @@ /*************************************************************************** - * API for image sensors connected to the SN9C10[12] PC Camera Controllers * + * API for image sensors connected to the SN9C10x PC Camera Controllers * * * * Copyright (C) 2004 by Luca Risolia * * * @@ -89,17 +89,44 @@ sn9c102_attach_sensor(struct sn9c102_dev /* Each SN9C10X camera has proper PID/VID identifiers. Add them here in case.*/ #define SN9C102_ID_TABLE \ static const struct usb_device_id sn9c102_id_table[] = { \ - { USB_DEVICE(0xc45, 0x6001), }, /* TAS5110C1B */ \ - { USB_DEVICE(0xc45, 0x6005), }, /* TAS5110C1B */ \ - { USB_DEVICE(0xc45, 0x6009), }, /* PAS106B */ \ - { USB_DEVICE(0xc45, 0x600d), }, /* PAS106B */ \ - { USB_DEVICE(0xc45, 0x6024), }, \ - { USB_DEVICE(0xc45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */ \ - { USB_DEVICE(0xc45, 0x6028), }, /* PAS202BCB */ \ - { USB_DEVICE(0xc45, 0x6029), }, /* PAS106B */ \ - { USB_DEVICE(0xc45, 0x602a), }, /* HV7131[D|E1] */ \ - { USB_DEVICE(0xc45, 0x602c), }, /* OV7620 */ \ - { USB_DEVICE(0xc45, 0x6030), }, /* MI03 */ \ + { USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */ \ + { USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */ \ + { USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */ \ + { USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */ \ + { USB_DEVICE(0x0c45, 0x6024), }, \ + { USB_DEVICE(0x0c45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */ \ + { USB_DEVICE(0x0c45, 0x6028), }, /* PAS202BCB */ \ + { USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */ \ + { USB_DEVICE(0x0c45, 0x602a), }, /* HV7131[D|E1] */ \ + { USB_DEVICE(0x0c45, 0x602b), }, \ + { USB_DEVICE(0x0c45, 0x602c), }, /* OV7620 */ \ + { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */ \ + { USB_DEVICE(0x0c45, 0x6080), }, \ + { USB_DEVICE(0x0c45, 0x6082), }, /* MI0343 and MI0360 */ \ + { USB_DEVICE(0x0c45, 0x6083), }, /* HV7131[D|E1] */ \ + { USB_DEVICE(0x0c45, 0x6088), }, \ + { USB_DEVICE(0x0c45, 0x608a), }, \ + { USB_DEVICE(0x0c45, 0x608b), }, \ + { USB_DEVICE(0x0c45, 0x608c), }, /* HV7131x */ \ + { USB_DEVICE(0x0c45, 0x608e), }, /* CIS-VF10 */ \ + { USB_DEVICE(0x0c45, 0x608f), }, /* OV7630 */ \ + { USB_DEVICE(0x0c45, 0x60a0), }, \ + { USB_DEVICE(0x0c45, 0x60a2), }, \ + { USB_DEVICE(0x0c45, 0x60a3), }, \ + { USB_DEVICE(0x0c45, 0x60a8), }, /* PAS106B */ \ + { USB_DEVICE(0x0c45, 0x60aa), }, /* TAS5130D1B */ \ + { USB_DEVICE(0x0c45, 0x60ab), }, /* TAS5110C1B */ \ + { USB_DEVICE(0x0c45, 0x60ac), }, \ + { USB_DEVICE(0x0c45, 0x60ae), }, \ + { USB_DEVICE(0x0c45, 0x60af), }, /* PAS202BCB */ \ + { USB_DEVICE(0x0c45, 0x60b0), }, \ + { USB_DEVICE(0x0c45, 0x60b2), }, \ + { USB_DEVICE(0x0c45, 0x60b3), }, \ + { USB_DEVICE(0x0c45, 0x60b8), }, \ + { USB_DEVICE(0x0c45, 0x60ba), }, \ + { USB_DEVICE(0x0c45, 0x60bb), }, \ + { USB_DEVICE(0x0c45, 0x60bc), }, \ + { USB_DEVICE(0x0c45, 0x60be), }, \ { } \ }; @@ -159,6 +186,9 @@ enum sn9c102_i2c_interface { SN9C102_I2C_3WIRES, }; +#define SN9C102_I2C_SLAVEID_FICTITIOUS 0xff +#define SN9C102_I2C_SLAVEID_UNAVAILABLE 0x00 + struct sn9c102_sensor { char name[32], /* sensor name */ maintainer[64]; /* name of the mantainer */ @@ -173,9 +203,7 @@ struct sn9c102_sensor { /* These identifiers must be provided if the image sensor implements - the standard I2C protocol. TASC sensors don't, although they have a - serial interface: so this is a case where the "raw" I2C version - could be helpful. + the standard I2C protocol. */ u8 slave_read_id, slave_write_id; /* reg. 0x09 */ @@ -214,7 +242,8 @@ struct sn9c102_sensor { the list above. The returned value must follow the V4L2 specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER are not supported by this driver, so do not implement them. Also, - passed values are NOT checked to see if they are out of bounds. + you don't have to check whether the passed values are out of bounds, + given that this is done by the core module. */ struct v4l2_cropcap cropcap; diff -puN drivers/usb/media/sn9c102_tas5110c1b.c~bk-usb drivers/usb/media/sn9c102_tas5110c1b.c --- 25/drivers/usb/media/sn9c102_tas5110c1b.c~bk-usb 2004-09-23 21:23:38.527451176 -0700 +++ 25-akpm/drivers/usb/media/sn9c102_tas5110c1b.c 2004-09-23 21:23:39.034374112 -0700 @@ -1,6 +1,6 @@ /*************************************************************************** - * Driver for TAS5110C1B image sensor connected to the SN9C10[12] PC * - * Camera Controllers * + * Driver for TAS5110C1B image sensor connected to the SN9C10x PC Camera * + * Controllers * * * * Copyright (C) 2004 by Luca Risolia * * * @@ -24,6 +24,8 @@ static struct sn9c102_sensor tas5110c1b; +static struct v4l2_control tas5110c1b_gain; + static int tas5110c1b_init(struct sn9c102_device* cam) { @@ -38,25 +40,42 @@ static int tas5110c1b_init(struct sn9c10 err += sn9c102_write_reg(cam, 0x06, 0x18); err += sn9c102_write_reg(cam, 0xfb, 0x19); - err += sn9c102_i2c_try_raw_write(cam, &tas5110c1b, 4, 0x11, 0x00, 0xc0, - 0x80, 0, 0); + err += sn9c102_i2c_write(cam, 0xc0, 0x80); return err; } +static int tas5110c1b_get_ctrl(struct sn9c102_device* cam, + struct v4l2_control* ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_GAIN: + ctrl->value = tas5110c1b_gain.value; + break; + default: + return -EINVAL; + } + + return 0; +} + + static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, const struct v4l2_control* ctrl) { + int err = 0; + switch (ctrl->id) { case V4L2_CID_GAIN: - return sn9c102_i2c_try_raw_write(cam, &tas5110c1b, 4, 0x11, - 0x02, 0x20, - 0xff - (ctrl->value & 0xff), - 0, 0); + if (!(err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value))) + tas5110c1b_gain.value = ctrl->value; + break; default: return -EINVAL; } + + return err ? -EIO : 0; } @@ -85,6 +104,8 @@ static struct sn9c102_sensor tas5110c1b .maintainer = "Luca Risolia ", .frequency = SN9C102_I2C_100KHZ, .interface = SN9C102_I2C_3WIRES, + .slave_read_id = SN9C102_I2C_SLAVEID_UNAVAILABLE, + .slave_write_id = SN9C102_I2C_SLAVEID_FICTITIOUS, .init = &tas5110c1b_init, .qctrl = { { @@ -92,9 +113,9 @@ static struct sn9c102_sensor tas5110c1b .type = V4L2_CTRL_TYPE_INTEGER, .name = "global gain", .minimum = 0x00, - .maximum = 0xff, + .maximum = 0xf6, .step = 0x01, - .default_value = 0x48, + .default_value = 0x40, .flags = 0, }, }, @@ -113,6 +134,7 @@ static struct sn9c102_sensor tas5110c1b .height = 288, }, }, + .get_ctrl = &tas5110c1b_get_ctrl, .set_crop = &tas5110c1b_set_crop, .pix_format = { .width = 352, @@ -130,7 +152,8 @@ int sn9c102_probe_tas5110c1b(struct sn9c /* At the moment, sensor detection is based on USB pid/vid */ if (tas5110c1b.usbdev->descriptor.idProduct != 0x6001 && - tas5110c1b.usbdev->descriptor.idProduct != 0x6005) + tas5110c1b.usbdev->descriptor.idProduct != 0x6005 && + tas5110c1b.usbdev->descriptor.idProduct != 0x60ab) return -ENODEV; return 0; diff -puN drivers/usb/media/sn9c102_tas5130d1b.c~bk-usb drivers/usb/media/sn9c102_tas5130d1b.c --- 25/drivers/usb/media/sn9c102_tas5130d1b.c~bk-usb 2004-09-23 21:23:38.529450872 -0700 +++ 25-akpm/drivers/usb/media/sn9c102_tas5130d1b.c 2004-09-23 21:23:39.035373960 -0700 @@ -1,6 +1,6 @@ /*************************************************************************** - * Driver for TAS5130D1B image sensor connected to the SN9C10[12] PC * - * Camera Controllers * + * Driver for TAS5130D1B image sensor connected to the SN9C10x PC Camera * + * Controllers * * * * Copyright (C) 2004 by Luca Risolia * * * @@ -24,6 +24,8 @@ static struct sn9c102_sensor tas5130d1b; +static struct v4l2_control tas5130d1b_gain, tas5130d1b_exposure; + static int tas5130d1b_init(struct sn9c102_device* cam) { @@ -38,25 +40,47 @@ static int tas5130d1b_init(struct sn9c10 err += sn9c102_write_reg(cam, 0x60, 0x17); err += sn9c102_write_reg(cam, 0x07, 0x18); - err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x40, - 0x47, 0, 0); - return err; } +static int tas5130d1b_get_ctrl(struct sn9c102_device* cam, + struct v4l2_control* ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_GAIN: + ctrl->value = tas5130d1b_gain.value; + break; + case V4L2_CID_EXPOSURE: + ctrl->value = tas5130d1b_exposure.value; + break; + default: + return -EINVAL; + } + + return 0; +} + + static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, const struct v4l2_control* ctrl) { + int err = 0; + switch (ctrl->id) { case V4L2_CID_GAIN: - return sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, - 0x02, 0x20, - 0xff - (ctrl->value & 0xff), - 0, 0); + if (!(err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value))) + tas5130d1b_gain.value = ctrl->value; + break; + case V4L2_CID_EXPOSURE: + if (!(err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value))) + tas5130d1b_exposure.value = ctrl->value; + break; default: return -EINVAL; } + + return err ? -EIO : 0; } @@ -85,6 +109,8 @@ static struct sn9c102_sensor tas5130d1b .maintainer = "Luca Risolia ", .frequency = SN9C102_I2C_100KHZ, .interface = SN9C102_I2C_3WIRES, + .slave_read_id = SN9C102_I2C_SLAVEID_UNAVAILABLE, + .slave_write_id = SN9C102_I2C_SLAVEID_FICTITIOUS, .init = &tas5130d1b_init, .qctrl = { { @@ -92,12 +118,23 @@ static struct sn9c102_sensor tas5130d1b .type = V4L2_CTRL_TYPE_INTEGER, .name = "global gain", .minimum = 0x00, - .maximum = 0xff, + .maximum = 0xf6, + .step = 0x02, + .default_value = 0x00, + .flags = 0, + }, + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .minimum = 0x00, + .maximum = 0x47, .step = 0x01, .default_value = 0x00, .flags = 0, }, }, + .get_ctrl = &tas5130d1b_get_ctrl, .set_ctrl = &tas5130d1b_set_ctrl, .cropcap = { .bounds = { @@ -129,7 +166,8 @@ int sn9c102_probe_tas5130d1b(struct sn9c sn9c102_attach_sensor(cam, &tas5130d1b); /* At the moment, sensor detection is based on USB pid/vid */ - if (tas5130d1b.usbdev->descriptor.idProduct != 0x6025) + if (tas5130d1b.usbdev->descriptor.idProduct != 0x6025 && + tas5130d1b.usbdev->descriptor.idProduct != 0x60aa) return -ENODEV; return 0; diff -puN drivers/usb/media/stv680.c~bk-usb drivers/usb/media/stv680.c --- 25/drivers/usb/media/stv680.c~bk-usb 2004-09-23 21:23:38.530450720 -0700 +++ 25-akpm/drivers/usb/media/stv680.c 2004-09-23 21:23:39.037373656 -0700 @@ -725,7 +725,7 @@ static int stv680_stop_stream (struct us for (i = 0; i < STV680_NUMSBUF; i++) if (stv680->urb[i]) { - usb_unlink_urb (stv680->urb[i]); + usb_kill_urb (stv680->urb[i]); usb_free_urb (stv680->urb[i]); stv680->urb[i] = NULL; kfree (stv680->sbuf[i].data); @@ -1457,7 +1457,7 @@ static inline void usb_stv680_remove_dis for (i = 0; i < STV680_NUMSBUF; i++) if (stv680->urb[i]) { - usb_unlink_urb (stv680->urb[i]); + usb_kill_urb (stv680->urb[i]); usb_free_urb (stv680->urb[i]); stv680->urb[i] = NULL; kfree (stv680->sbuf[i].data); diff -puN drivers/usb/media/usbvideo.c~bk-usb drivers/usb/media/usbvideo.c --- 25/drivers/usb/media/usbvideo.c~bk-usb 2004-09-23 21:23:38.532450416 -0700 +++ 25-akpm/drivers/usb/media/usbvideo.c 2004-09-23 21:23:39.038373504 -0700 @@ -1910,9 +1910,7 @@ static void usbvideo_StopDataPump(struct /* Unschedule all of the iso td's */ for (i=0; i < USBVIDEO_NUMSBUF; i++) { - j = usb_unlink_urb(uvd->sbuf[i].urb); - if (j < 0) - err("%s: usb_unlink_urb() error %d.", __FUNCTION__, j); + usb_kill_urb(uvd->sbuf[i].urb); } if (uvd->debug > 1) info("%s: streaming=0", __FUNCTION__); diff -puN drivers/usb/misc/speedtch.c~bk-usb drivers/usb/misc/speedtch.c --- 25/drivers/usb/misc/speedtch.c~bk-usb 2004-09-23 21:23:38.534450112 -0700 +++ 25-akpm/drivers/usb/misc/speedtch.c 2004-09-23 21:23:39.040373200 -0700 @@ -93,7 +93,7 @@ #ifdef DEBUG #define DEBUG_ON(x) BUG_ON(x) #else -#define DEBUG_ON(x) do { if (x); } while (0) +#define DEBUG_ON(x) #endif #ifdef VERBOSE_DEBUG @@ -518,7 +518,8 @@ static unsigned int udsl_write_cells (un memset (target, 0, ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER); target += ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER; - DEBUG_ON (--ctrl->num_cells); + --ctrl->num_cells; + DEBUG_ON (ctrl->num_cells); } memcpy (target, ctrl->aal5_trailer, ATM_AAL5_TRAILER); @@ -1219,9 +1220,7 @@ fail: static void udsl_usb_disconnect (struct usb_interface *intf) { struct udsl_instance_data *instance = usb_get_intfdata (intf); - struct list_head *pos; - unsigned int count; - int result, i; + int i; dbg ("udsl_usb_disconnect entered"); @@ -1236,25 +1235,7 @@ static void udsl_usb_disconnect (struct tasklet_disable (&instance->receive_tasklet); for (i = 0; i < num_rcv_urbs; i++) - if ((result = usb_unlink_urb (instance->receivers [i].urb)) < 0) - dbg ("udsl_usb_disconnect: usb_unlink_urb on receive urb %d returned %d!", i, result); - - /* wait for completion handlers to finish */ - do { - count = 0; - spin_lock_irq (&instance->receive_lock); - list_for_each (pos, &instance->spare_receivers) - DEBUG_ON (++count > num_rcv_urbs); - spin_unlock_irq (&instance->receive_lock); - - dbg ("udsl_usb_disconnect: found %u spare receivers", count); - - if (count == num_rcv_urbs) - break; - - set_current_state (TASK_RUNNING); - schedule (); - } while (1); + usb_kill_urb (instance->receivers [i].urb); /* no need to take the spinlock */ INIT_LIST_HEAD (&instance->filled_receive_buffers); @@ -1272,25 +1253,7 @@ static void udsl_usb_disconnect (struct tasklet_disable (&instance->send_tasklet); for (i = 0; i < num_snd_urbs; i++) - if ((result = usb_unlink_urb (instance->senders [i].urb)) < 0) - dbg ("udsl_usb_disconnect: usb_unlink_urb on send urb %d returned %d!", i, result); - - /* wait for completion handlers to finish */ - do { - count = 0; - spin_lock_irq (&instance->send_lock); - list_for_each (pos, &instance->spare_senders) - DEBUG_ON (++count > num_snd_urbs); - spin_unlock_irq (&instance->send_lock); - - dbg ("udsl_usb_disconnect: found %u spare senders", count); - - if (count == num_snd_urbs) - break; - - set_current_state (TASK_RUNNING); - schedule (); - } while (1); + usb_kill_urb (instance->senders [i].urb); /* no need to take the spinlock */ INIT_LIST_HEAD (&instance->spare_senders); diff -puN drivers/usb/misc/tiglusb.c~bk-usb drivers/usb/misc/tiglusb.c --- 25/drivers/usb/misc/tiglusb.c~bk-usb 2004-09-23 21:23:38.535449960 -0700 +++ 25-akpm/drivers/usb/misc/tiglusb.c 2004-09-23 21:23:39.041373048 -0700 @@ -115,6 +115,7 @@ tiglusb_open (struct inode *inode, struc return -EBUSY; } + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout (HZ / 2); if (signal_pending (current)) { diff -puN drivers/usb/net/kaweth.c~bk-usb drivers/usb/net/kaweth.c --- 25/drivers/usb/net/kaweth.c~bk-usb 2004-09-23 21:23:38.537449656 -0700 +++ 25-akpm/drivers/usb/net/kaweth.c 2004-09-23 21:23:39.042372896 -0700 @@ -668,7 +668,7 @@ static int kaweth_open(struct net_device INTBUFFERSIZE, int_callback, kaweth, - 8); + 250); /* overriding the descriptor */ kaweth->irq_urb->transfer_dma = kaweth->intbufferhandle; kaweth->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; diff -puN drivers/usb/net/rtl8150.c~bk-usb drivers/usb/net/rtl8150.c --- 25/drivers/usb/net/rtl8150.c~bk-usb 2004-09-23 21:23:38.538449504 -0700 +++ 25-akpm/drivers/usb/net/rtl8150.c 2004-09-23 21:23:39.043372744 -0700 @@ -20,7 +20,7 @@ #include /* Version Information */ -#define DRIVER_VERSION "v0.6.1 (2004/03/13)" +#define DRIVER_VERSION "v0.6.2 (2004/08/27)" #define DRIVER_AUTHOR "Petko Manolov " #define DRIVER_DESC "rtl8150 based usb-ethernet driver" @@ -389,10 +389,10 @@ static void free_all_urbs(rtl8150_t * de static void unlink_all_urbs(rtl8150_t * dev) { - usb_unlink_urb(dev->rx_urb); - usb_unlink_urb(dev->tx_urb); - usb_unlink_urb(dev->intr_urb); - usb_unlink_urb(dev->ctrl_urb); + usb_kill_urb(dev->rx_urb); + usb_kill_urb(dev->tx_urb); + usb_kill_urb(dev->intr_urb); + usb_kill_urb(dev->ctrl_urb); } static inline struct sk_buff *pull_skb(rtl8150_t *dev) diff -puN drivers/usb/net/usbnet.c~bk-usb drivers/usb/net/usbnet.c --- 25/drivers/usb/net/usbnet.c~bk-usb 2004-09-23 21:23:38.540449200 -0700 +++ 25-akpm/drivers/usb/net/usbnet.c 2004-09-23 21:23:39.046372288 -0700 @@ -3252,6 +3252,10 @@ static const struct usb_device_id produc // Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter" USB_DEVICE (0x6189, 0x182d), .driver_info = (unsigned long) &ax8817x_info, +}, { + // Surecom EP-1427X-2 + USB_DEVICE (0x1189, 0x0893), + .driver_info = (unsigned long) &ax8817x_info, }, #endif @@ -3308,11 +3312,18 @@ static const struct usb_device_id produc * * PXA25x or PXA210 ... these use a "usb-eth" driver much like * the sa1100 one, but hardware uses different endpoint numbers. + * + * Or the Linux "Ethernet" gadget on hardware that can't talk + * CDC Ethernet (e.g., no altsettings), in either of two modes: + * - acting just like the old "usb-eth" firmware, though + * the implementation is different + * - supporting RNDIS as the first/default configuration for + * MS-Windows interop; Linux needs to use the other config */ { // 1183 = 0x049F, both used as hex values? // Compaq "Itsy" vendor/product id - USB_DEVICE (0x049F, 0x505A), + USB_DEVICE (0x049F, 0x505A), // usb-eth, or compatible .driver_info = (unsigned long) &linuxdev_info, }, { USB_DEVICE (0x0E7E, 0x1001), // G.Mate "Yopy" @@ -3320,6 +3331,10 @@ static const struct usb_device_id produc }, { USB_DEVICE (0x8086, 0x07d3), // "blob" bootloader .driver_info = (unsigned long) &blob_info, +}, { + // Linux Ethernet/RNDIS gadget on pxa210/25x/26x + USB_DEVICE_VER (0x0525, 0xa4a2, 0x0203, 0x0203), + .driver_info = (unsigned long) &linuxdev_info, }, #endif diff -puN drivers/usb/serial/belkin_sa.c~bk-usb drivers/usb/serial/belkin_sa.c --- 25/drivers/usb/serial/belkin_sa.c~bk-usb 2004-09-23 21:23:38.542448896 -0700 +++ 25-akpm/drivers/usb/serial/belkin_sa.c 2004-09-23 21:23:39.047372136 -0700 @@ -228,7 +228,7 @@ static int belkin_sa_open (struct usb_s port->interrupt_in_urb->dev = port->serial->dev; retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (retval) { - usb_unlink_urb(port->read_urb); + usb_kill_urb(port->read_urb); err(" usb_submit_urb(read int) failed"); } @@ -242,9 +242,9 @@ static void belkin_sa_close (struct usb_ dbg("%s port %d", __FUNCTION__, port->number); /* shutdown our bulk reads and writes */ - usb_unlink_urb (port->write_urb); - usb_unlink_urb (port->read_urb); - usb_unlink_urb (port->interrupt_in_urb); + usb_kill_urb(port->write_urb); + usb_kill_urb(port->read_urb); + usb_kill_urb(port->interrupt_in_urb); } /* belkin_sa_close */ diff -puN drivers/usb/serial/cyberjack.c~bk-usb drivers/usb/serial/cyberjack.c --- 25/drivers/usb/serial/cyberjack.c~bk-usb 2004-09-23 21:23:38.543448744 -0700 +++ 25-akpm/drivers/usb/serial/cyberjack.c 2004-09-23 21:23:39.048371984 -0700 @@ -149,7 +149,7 @@ static void cyberjack_shutdown (struct u dbg("%s", __FUNCTION__); for (i=0; i < serial->num_ports; ++i) { - usb_unlink_urb (serial->port[i]->interrupt_in_urb); + usb_kill_urb(serial->port[i]->interrupt_in_urb); /* My special items, the standard routines free my urbs */ kfree(usb_get_serial_port_data(serial->port[i])); usb_set_serial_port_data(serial->port[i], NULL); @@ -189,8 +189,8 @@ static void cyberjack_close (struct usb_ if (port->serial->dev) { /* shutdown any bulk reads that might be going on */ - usb_unlink_urb (port->write_urb); - usb_unlink_urb (port->read_urb); + usb_kill_urb(port->write_urb); + usb_kill_urb(port->read_urb); } } diff -puN drivers/usb/serial/digi_acceleport.c~bk-usb drivers/usb/serial/digi_acceleport.c --- 25/drivers/usb/serial/digi_acceleport.c~bk-usb 2004-09-23 21:23:38.544448592 -0700 +++ 25-akpm/drivers/usb/serial/digi_acceleport.c 2004-09-23 21:23:39.049371832 -0700 @@ -1553,13 +1553,17 @@ static void digi_close( struct usb_seria dbg( "digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_count ); + /* if disconnected, just clear flags */ + if (!usb_get_intfdata(port->serial->interface)) + goto exit; + /* do cleanup only after final close on this port */ spin_lock_irqsave( &priv->dp_port_lock, flags ); priv->dp_in_close = 1; spin_unlock_irqrestore( &priv->dp_port_lock, flags ); /* tell line discipline to process only XON/XOFF */ - tty->closing = 1; + tty->closing = 1; /* wait for output to drain */ if( (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) { @@ -1619,11 +1623,12 @@ dbg( "digi_close: TOP: port=%d, open_cou DIGI_CLOSE_TIMEOUT ); /* shutdown any outstanding bulk writes */ - usb_unlink_urb (port->write_urb); + usb_kill_urb(port->write_urb); } tty->closing = 0; +exit: spin_lock_irqsave( &priv->dp_port_lock, flags ); priv->dp_write_urb_in_use = 0; priv->dp_in_close = 0; @@ -1757,8 +1762,8 @@ dbg( "digi_shutdown: TOP, in_interrupt() /* stop reads and writes on all ports */ for( i=0; itype->num_ports+1; i++ ) { - usb_unlink_urb( serial->port[i]->read_urb ); - usb_unlink_urb( serial->port[i]->write_urb ); + usb_kill_urb(serial->port[i]->read_urb); + usb_kill_urb(serial->port[i]->write_urb); } /* free the private data structures for all ports */ diff -puN drivers/usb/serial/empeg.c~bk-usb drivers/usb/serial/empeg.c --- 25/drivers/usb/serial/empeg.c~bk-usb 2004-09-23 21:23:38.546448288 -0700 +++ 25-akpm/drivers/usb/serial/empeg.c 2004-09-23 21:23:39.050371680 -0700 @@ -185,7 +185,7 @@ static void empeg_close (struct usb_seri dbg("%s - port %d", __FUNCTION__, port->number); /* shutdown our bulk read */ - usb_unlink_urb (port->read_urb); + usb_kill_urb(port->read_urb); /* Uncomment the following line if you want to see some statistics in your syslog */ /* dev_info (&port->dev, "Bytes In = %d Bytes Out = %d\n", bytes_in, bytes_out); */ } @@ -406,7 +406,7 @@ static void empeg_read_bulk_callback (st static void empeg_throttle (struct usb_serial_port *port) { dbg("%s - port %d", __FUNCTION__, port->number); - usb_unlink_urb (port->read_urb); + usb_kill_urb(port->read_urb); } @@ -583,10 +583,10 @@ static void __exit empeg_exit (void) for (i = 0; i < NUM_URBS; ++i) { if (write_urb_pool[i]) { - /* FIXME - uncomment the following usb_unlink_urb call when + /* FIXME - uncomment the following usb_kill_urb call when * the host controllers get fixed to set urb->dev = NULL after * the urb is finished. Otherwise this call oopses. */ - /* usb_unlink_urb(write_urb_pool[i]); */ + /* usb_kill_urb(write_urb_pool[i]); */ if (write_urb_pool[i]->transfer_buffer) kfree(write_urb_pool[i]->transfer_buffer); usb_free_urb (write_urb_pool[i]); diff -puN drivers/usb/serial/ftdi_sio.c~bk-usb drivers/usb/serial/ftdi_sio.c --- 25/drivers/usb/serial/ftdi_sio.c~bk-usb 2004-09-23 21:23:38.548447984 -0700 +++ 25-akpm/drivers/usb/serial/ftdi_sio.c 2004-09-23 21:23:39.053371224 -0700 @@ -368,6 +368,9 @@ static struct usb_device_id id_table_8U2 { USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FALCOM_VID, FALCOM_TWIST_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_SUUNTO_SPORTS_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(BANDB_VID, BANDB_USOTL4_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(BANDB_VID, BANDB_USTL4_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(BANDB_VID, BANDB_USO9ML2_PID, 0, 0x3ff) }, { } /* Terminating entry */ }; @@ -478,6 +481,9 @@ static struct usb_device_id id_table_FT2 { USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FALCOM_VID, FALCOM_TWIST_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_SUUNTO_SPORTS_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(BANDB_VID, BANDB_USOTL4_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(BANDB_VID, BANDB_USTL4_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(BANDB_VID, BANDB_USO9ML2_PID, 0x400, 0xffff) }, { } /* Terminating entry */ }; @@ -595,6 +601,9 @@ static struct usb_device_id id_table_com { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) }, { USB_DEVICE(FALCOM_VID, FALCOM_TWIST_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SUUNTO_SPORTS_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) }, + { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) }, { } /* Terminating entry */ }; @@ -1479,16 +1488,8 @@ static void ftdi_close (struct usb_seria } /* Note change no line if hupcl is off */ /* shutdown our bulk read */ - if (port->read_urb) { - if (usb_unlink_urb (port->read_urb) < 0) { - /* Generally, this isn't an error. If the previous - read bulk callback occurred (or is about to occur) - while the port was being closed or was throtted - (and is still throttled), the read urb will not - have been submitted. */ - dbg("%s - failed to unlink read urb (generally not an error)", __FUNCTION__); - } - } + if (port->read_urb) + usb_kill_urb(port->read_urb); } /* ftdi_close */ diff -puN drivers/usb/serial/ftdi_sio.h~bk-usb drivers/usb/serial/ftdi_sio.h --- 25/drivers/usb/serial/ftdi_sio.h~bk-usb 2004-09-23 21:23:38.549447832 -0700 +++ 25-akpm/drivers/usb/serial/ftdi_sio.h 2004-09-23 21:23:39.054371072 -0700 @@ -225,6 +225,14 @@ */ #define FTDI_SUUNTO_SPORTS_PID 0xF680 /* Suunto Sports instrument */ +/* + * Definitions for B&B Electronics products. + */ +#define BANDB_VID 0x0856 /* B&B Electronics Vendor ID */ +#define BANDB_USOTL4_PID 0xAC01 /* USOTL4 Isolated RS-485 Converter */ +#define BANDB_USTL4_PID 0xAC02 /* USTL4 RS-485 Converter */ +#define BANDB_USO9ML2_PID 0xAC03 /* USO9ML2 Isolated RS-232 Converter */ + /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ diff -puN drivers/usb/serial/generic.c~bk-usb drivers/usb/serial/generic.c --- 25/drivers/usb/serial/generic.c~bk-usb 2004-09-23 21:23:38.550447680 -0700 +++ 25-akpm/drivers/usb/serial/generic.c 2004-09-23 21:23:39.054371072 -0700 @@ -147,9 +147,9 @@ static void generic_cleanup (struct usb_ if (serial->dev) { /* shutdown any bulk reads that might be going on */ if (serial->num_bulk_out) - usb_unlink_urb (port->write_urb); + usb_kill_urb(port->write_urb); if (serial->num_bulk_in) - usb_unlink_urb (port->read_urb); + usb_kill_urb(port->read_urb); } } diff -puN drivers/usb/serial/io_edgeport.c~bk-usb drivers/usb/serial/io_edgeport.c --- 25/drivers/usb/serial/io_edgeport.c~bk-usb 2004-09-23 21:23:38.552447376 -0700 +++ 25-akpm/drivers/usb/serial/io_edgeport.c 2004-09-23 21:23:39.057370616 -0700 @@ -1243,7 +1243,7 @@ static void edge_close (struct usb_seria edge_port->openPending = FALSE; if (edge_port->write_urb) { - usb_unlink_urb (edge_port->write_urb); + usb_kill_urb(edge_port->write_urb); } if (edge_port->write_urb) { @@ -2448,8 +2448,8 @@ static int write_cmd_usb (struct edgepor if (status) { /* something went wrong */ dbg("%s - usb_submit_urb(write bulk) failed", __FUNCTION__); - usb_unlink_urb (urb); - usb_free_urb (urb); + usb_kill_urb(urb); + usb_free_urb(urb); return status; } diff -puN drivers/usb/serial/io_ti.c~bk-usb drivers/usb/serial/io_ti.c --- 25/drivers/usb/serial/io_ti.c~bk-usb 2004-09-23 21:23:38.554447072 -0700 +++ 25-akpm/drivers/usb/serial/io_ti.c 2004-09-23 21:23:39.059370312 -0700 @@ -1977,7 +1977,7 @@ static void edge_close (struct usb_seria /* chase the port close */ TIChasePort (edge_port); - usb_unlink_urb (port->read_urb); + usb_kill_urb(port->read_urb); /* assuming we can still talk to the device, * send a close port command to it */ @@ -1992,7 +1992,7 @@ static void edge_close (struct usb_seria --edge_port->edge_serial->num_ports_open; if (edge_port->edge_serial->num_ports_open <= 0) { /* last port is now closed, let's shut down our interrupt urb */ - usb_unlink_urb (port->serial->port[0]->interrupt_in_urb); + usb_kill_urb(port->serial->port[0]->interrupt_in_urb); edge_port->edge_serial->num_ports_open = 0; } edge_port->close_pending = 0; @@ -2126,7 +2126,7 @@ static void edge_throttle (struct usb_se status = TIClearRts (edge_port); } - usb_unlink_urb (port->read_urb); + usb_kill_urb(port->read_urb); } static void edge_unthrottle (struct usb_serial_port *port) diff -puN drivers/usb/serial/ipaq.c~bk-usb drivers/usb/serial/ipaq.c --- 25/drivers/usb/serial/ipaq.c~bk-usb 2004-09-23 21:23:38.556446768 -0700 +++ 25-akpm/drivers/usb/serial/ipaq.c 2004-09-23 21:23:39.060370160 -0700 @@ -288,8 +288,8 @@ static void ipaq_close(struct usb_serial /* * shut down bulk read and write */ - usb_unlink_urb(port->write_urb); - usb_unlink_urb(port->read_urb); + usb_kill_urb(port->write_urb); + usb_kill_urb(port->read_urb); ipaq_destroy_lists(port); kfree(priv); usb_set_serial_port_data(port, NULL); @@ -419,9 +419,8 @@ static void ipaq_write_gather(struct usb struct ipaq_private *priv = usb_get_serial_port_data(port); struct usb_serial *serial = port->serial; int count, room; - struct ipaq_packet *pkt; + struct ipaq_packet *pkt, *tmp; struct urb *urb = port->write_urb; - struct list_head *tmp; if (urb->status == -EINPROGRESS) { /* Should never happen */ @@ -429,9 +428,7 @@ static void ipaq_write_gather(struct usb return; } room = URBDATA_SIZE; - for (tmp = priv->queue.next; tmp != &priv->queue;) { - pkt = list_entry(tmp, struct ipaq_packet, list); - tmp = tmp->next; + list_for_each_entry_safe(pkt, tmp, &priv->queue, list) { count = min(room, (int)(pkt->len - pkt->written)); memcpy(urb->transfer_buffer + (URBDATA_SIZE - room), pkt->data + pkt->written, count); @@ -503,22 +500,16 @@ static int ipaq_chars_in_buffer(struct u static void ipaq_destroy_lists(struct usb_serial_port *port) { struct ipaq_private *priv = usb_get_serial_port_data(port); - struct list_head *tmp; - struct ipaq_packet *pkt; + struct ipaq_packet *pkt, *tmp; - for (tmp = priv->queue.next; tmp != &priv->queue;) { - pkt = list_entry(tmp, struct ipaq_packet, list); - tmp = tmp->next; + list_for_each_entry_safe(pkt, tmp, &priv->queue, list) { kfree(pkt->data); kfree(pkt); } - for (tmp = priv->freelist.next; tmp != &priv->freelist;) { - pkt = list_entry(tmp, struct ipaq_packet, list); - tmp = tmp->next; + list_for_each_entry_safe(pkt, tmp, &priv->freelist, list) { kfree(pkt->data); kfree(pkt); } - return; } diff -puN drivers/usb/serial/ir-usb.c~bk-usb drivers/usb/serial/ir-usb.c --- 25/drivers/usb/serial/ir-usb.c~bk-usb 2004-09-23 21:23:38.557446616 -0700 +++ 25-akpm/drivers/usb/serial/ir-usb.c 2004-09-23 21:23:39.061370008 -0700 @@ -322,7 +322,7 @@ static void ir_close (struct usb_serial_ dbg("%s - port %d", __FUNCTION__, port->number); /* shutdown our bulk read */ - usb_unlink_urb (port->read_urb); + usb_kill_urb(port->read_urb); } static int ir_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) diff -puN drivers/usb/serial/keyspan_pda.c~bk-usb drivers/usb/serial/keyspan_pda.c --- 25/drivers/usb/serial/keyspan_pda.c~bk-usb 2004-09-23 21:23:38.559446312 -0700 +++ 25-akpm/drivers/usb/serial/keyspan_pda.c 2004-09-23 21:23:39.062369856 -0700 @@ -291,7 +291,7 @@ static void keyspan_pda_rx_throttle (str upon the device too. */ dbg("keyspan_pda_rx_throttle port %d", port->number); - usb_unlink_urb(port->interrupt_in_urb); + usb_kill_urb(port->interrupt_in_urb); } @@ -712,8 +712,8 @@ static void keyspan_pda_close(struct usb keyspan_pda_set_modem_info(serial, 0); /* shutdown our bulk reads and writes */ - usb_unlink_urb (port->write_urb); - usb_unlink_urb (port->interrupt_in_urb); + usb_kill_urb(port->write_urb); + usb_kill_urb(port->interrupt_in_urb); } } diff -puN drivers/usb/serial/kl5kusb105.c~bk-usb drivers/usb/serial/kl5kusb105.c --- 25/drivers/usb/serial/kl5kusb105.c~bk-usb 2004-09-23 21:23:38.560446160 -0700 +++ 25-akpm/drivers/usb/serial/kl5kusb105.c 2004-09-23 21:23:39.063369704 -0700 @@ -336,12 +336,12 @@ static void klsi_105_shutdown (struct us for (j = 0; j < NUM_URBS; j++) { if (write_urbs[j]) { /* FIXME - uncomment the following - * usb_unlink_urb call when the host + * usb_kill_urb call when the host * controllers get fixed to set * urb->dev = NULL after the urb is * finished. Otherwise this call * oopses. */ - /* usb_unlink_urb(write_urbs[j]); */ + /* usb_kill_urb(write_urbs[j]); */ if (write_urbs[j]->transfer_buffer) kfree(write_urbs[j]->transfer_buffer); usb_free_urb (write_urbs[j]); @@ -467,12 +467,12 @@ static void klsi_105_close (struct usb_s err("Disabling read failed (error = %d)", rc); /* shutdown our bulk reads and writes */ - usb_unlink_urb (port->write_urb); - usb_unlink_urb (port->read_urb); + usb_kill_urb(port->write_urb); + usb_kill_urb(port->read_urb); /* unlink our write pool */ /* FIXME */ /* wgg - do I need this? I think so. */ - usb_unlink_urb (port->interrupt_in_urb); + usb_kill_urb(port->interrupt_in_urb); info("kl5kusb105 port stats: %ld bytes in, %ld bytes out", priv->bytes_in, priv->bytes_out); } /* klsi_105_close */ @@ -994,7 +994,7 @@ static int klsi_105_ioctl (struct usb_se static void klsi_105_throttle (struct usb_serial_port *port) { dbg("%s - port %d", __FUNCTION__, port->number); - usb_unlink_urb (port->read_urb); + usb_kill_urb(port->read_urb); } static void klsi_105_unthrottle (struct usb_serial_port *port) diff -puN drivers/usb/serial/kobil_sct.c~bk-usb drivers/usb/serial/kobil_sct.c --- 25/drivers/usb/serial/kobil_sct.c~bk-usb 2004-09-23 21:23:38.561446008 -0700 +++ 25-akpm/drivers/usb/serial/kobil_sct.c 2004-09-23 21:23:39.064369552 -0700 @@ -350,14 +350,13 @@ static void kobil_close (struct usb_seri { dbg("%s - port %d", __FUNCTION__, port->number); - if (port->write_urb){ - usb_unlink_urb( port->write_urb ); + if (port->write_urb) { + usb_kill_urb(port->write_urb); usb_free_urb( port->write_urb ); port->write_urb = NULL; } - if (port->interrupt_in_urb){ - usb_unlink_urb (port->interrupt_in_urb); - } + if (port->interrupt_in_urb) + usb_kill_urb(port->interrupt_in_urb); } @@ -458,9 +457,8 @@ static int kobil_write (struct usb_seria ((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 3) && (priv->filled >= (priv->buf[2] + 4))) ) { // stop reading (except TWIN and KAAN SIM) - if ( (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) || (priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) ) { - usb_unlink_urb( port->interrupt_in_urb ); - } + if ( (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) || (priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) ) + usb_kill_urb(port->interrupt_in_urb); todo = priv->filled - priv->cur_pos; diff -puN drivers/usb/serial/mct_u232.c~bk-usb drivers/usb/serial/mct_u232.c --- 25/drivers/usb/serial/mct_u232.c~bk-usb 2004-09-23 21:23:38.563445704 -0700 +++ 25-akpm/drivers/usb/serial/mct_u232.c 2004-09-23 21:23:39.065369400 -0700 @@ -480,9 +480,9 @@ static void mct_u232_close (struct usb_s if (port->serial->dev) { /* shutdown our urbs */ - usb_unlink_urb (port->write_urb); - usb_unlink_urb (port->read_urb); - usb_unlink_urb (port->interrupt_in_urb); + usb_kill_urb(port->write_urb); + usb_kill_urb(port->read_urb); + usb_kill_urb(port->interrupt_in_urb); } } /* mct_u232_close */ diff -puN drivers/usb/serial/omninet.c~bk-usb drivers/usb/serial/omninet.c --- 25/drivers/usb/serial/omninet.c~bk-usb 2004-09-23 21:23:38.564445552 -0700 +++ 25-akpm/drivers/usb/serial/omninet.c 2004-09-23 21:23:39.066369248 -0700 @@ -183,8 +183,8 @@ static void omninet_close (struct usb_se dbg("%s - port %d", __FUNCTION__, port->number); wport = serial->port[1]; - usb_unlink_urb(wport->write_urb); - usb_unlink_urb(port->read_urb); + usb_kill_urb(wport->write_urb); + usb_kill_urb(port->read_urb); od = usb_get_serial_port_data(port); if (od) diff -puN drivers/usb/serial/pl2303.c~bk-usb drivers/usb/serial/pl2303.c --- 25/drivers/usb/serial/pl2303.c~bk-usb 2004-09-23 21:23:38.566445248 -0700 +++ 25-akpm/drivers/usb/serial/pl2303.c 2004-09-23 21:23:39.069368792 -0700 @@ -55,11 +55,26 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.11" +#define DRIVER_VERSION "v0.12" #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver" static int debug; +#define PL2303_CLOSING_WAIT (30*HZ) + +#define PL2303_BUF_SIZE 1024 +#define PL2303_TMP_BUF_SIZE 1024 + +static char pl2303_tmp_buf[PL2303_TMP_BUF_SIZE]; +static DECLARE_MUTEX(pl2303_tmp_buf_sem); + +struct pl2303_buf { + unsigned int buf_size; + char *buf_buf; + char *buf_get; + char *buf_put; +}; + static struct usb_device_id id_table [] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, @@ -134,12 +149,24 @@ static void pl2303_read_bulk_callback (s static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs); static int pl2303_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); +static void pl2303_send (struct usb_serial_port *port); +static int pl2303_write_room(struct usb_serial_port *port); +static int pl2303_chars_in_buffer(struct usb_serial_port *port); static void pl2303_break_ctl(struct usb_serial_port *port,int break_state); static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file); static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); static int pl2303_startup (struct usb_serial *serial); static void pl2303_shutdown (struct usb_serial *serial); +static struct pl2303_buf *pl2303_buf_alloc(unsigned int size); +static void pl2303_buf_free(struct pl2303_buf *pb); +static void pl2303_buf_clear(struct pl2303_buf *pb); +static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb); +static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb); +static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf, + unsigned int count); +static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, + unsigned int count); /* All of the device info needed for the PL2303 SIO serial converter */ @@ -162,6 +189,8 @@ static struct usb_serial_device_type pl2 .read_bulk_callback = pl2303_read_bulk_callback, .read_int_callback = pl2303_read_int_callback, .write_bulk_callback = pl2303_write_bulk_callback, + .write_room = pl2303_write_room, + .chars_in_buffer = pl2303_chars_in_buffer, .attach = pl2303_startup, .shutdown = pl2303_shutdown, }; @@ -174,6 +203,8 @@ enum pl2303_type { struct pl2303_private { spinlock_t lock; + struct pl2303_buf *buf; + int write_urb_in_use; wait_queue_head_t delta_msr_wait; u8 line_control; u8 line_status; @@ -201,14 +232,28 @@ static int pl2303_startup (struct usb_se for (i = 0; i < serial->num_ports; ++i) { priv = kmalloc (sizeof (struct pl2303_private), GFP_KERNEL); if (!priv) - return -ENOMEM; + goto cleanup; memset (priv, 0x00, sizeof (struct pl2303_private)); spin_lock_init(&priv->lock); + priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE); + if (priv->buf == NULL) { + kfree(priv); + goto cleanup; + } init_waitqueue_head(&priv->delta_msr_wait); priv->type = type; usb_set_serial_port_data(serial->port[i], priv); } return 0; + +cleanup: + for (--i; i>=0; --i) { + priv = usb_get_serial_port_data(serial->port[i]); + pl2303_buf_free(priv->buf); + kfree(priv); + usb_set_serial_port_data(serial->port[i], NULL); + } + return -ENOMEM; } static int set_control_lines (struct usb_device *dev, u8 value) @@ -224,40 +269,109 @@ static int set_control_lines (struct usb static int pl2303_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) { - int result; + struct pl2303_private *priv = usb_get_serial_port_data(port); + unsigned long flags; dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count); if (!count) return count; - if (port->write_urb->status == -EINPROGRESS) { - dbg("%s - already writing", __FUNCTION__); - return 0; - } - - count = (count > port->bulk_out_size) ? port->bulk_out_size : count; if (from_user) { - if (copy_from_user (port->write_urb->transfer_buffer, buf, count)) + if (count > PL2303_TMP_BUF_SIZE) + count = PL2303_TMP_BUF_SIZE; + down(&pl2303_tmp_buf_sem); + if (copy_from_user(pl2303_tmp_buf, buf, count)) { + up(&pl2303_tmp_buf_sem); return -EFAULT; - } else { - memcpy (port->write_urb->transfer_buffer, buf, count); + } + buf = pl2303_tmp_buf; } - + + spin_lock_irqsave(&priv->lock, flags); + count = pl2303_buf_put(priv->buf, buf, count); + spin_unlock_irqrestore(&priv->lock, flags); + + if (from_user) + up(&pl2303_tmp_buf_sem); + + pl2303_send(port); + + return count; +} + +static void pl2303_send(struct usb_serial_port *port) +{ + int count, result; + struct pl2303_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + + dbg("%s - port %d", __FUNCTION__, port->number); + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->write_urb_in_use) { + spin_unlock_irqrestore(&priv->lock, flags); + return; + } + + count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer, + port->bulk_out_size); + + if (count == 0) { + spin_unlock_irqrestore(&priv->lock, flags); + return; + } + + priv->write_urb_in_use = 1; + + spin_unlock_irqrestore(&priv->lock, flags); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer); port->write_urb->transfer_buffer_length = count; port->write_urb->dev = port->serial->dev; result = usb_submit_urb (port->write_urb, GFP_ATOMIC); - if (result) + if (result) { dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result); - else - result = count; + priv->write_urb_in_use = 0; + // TODO: reschedule pl2303_send + } - return result; + schedule_work(&port->work); } +static int pl2303_write_room(struct usb_serial_port *port) +{ + struct pl2303_private *priv = usb_get_serial_port_data(port); + int room = 0; + unsigned long flags; + dbg("%s - port %d", __FUNCTION__, port->number); + + spin_lock_irqsave(&priv->lock, flags); + room = pl2303_buf_space_avail(priv->buf); + spin_unlock_irqrestore(&priv->lock, flags); + + dbg("%s - returns %d", __FUNCTION__, room); + return room; +} + +static int pl2303_chars_in_buffer(struct usb_serial_port *port) +{ + struct pl2303_private *priv = usb_get_serial_port_data(port); + int chars = 0; + unsigned long flags; + + dbg("%s - port %d", __FUNCTION__, port->number); + + spin_lock_irqsave(&priv->lock, flags); + chars = pl2303_buf_data_avail(priv->buf); + spin_unlock_irqrestore(&priv->lock, flags); + + dbg("%s - returns %d", __FUNCTION__, chars); + return chars; +} static void pl2303_set_termios (struct usb_serial_port *port, struct termios *old_termios) { @@ -422,7 +536,7 @@ static void pl2303_set_termios (struct u } kfree (buf); -} +} static int pl2303_open (struct usb_serial_port *port, struct file *filp) { @@ -461,7 +575,7 @@ static int pl2303_open (struct usb_seria FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0); SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1); SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0); - + if (priv->type == HX) { /* HX chip */ SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x44); @@ -504,45 +618,67 @@ static int pl2303_open (struct usb_seria static void pl2303_close (struct usb_serial_port *port, struct file *filp) { - struct pl2303_private *priv; + struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; unsigned int c_cflag; - int result; + int bps; + long timeout; + wait_queue_t wait; \ dbg("%s - port %d", __FUNCTION__, port->number); - /* shutdown our urbs */ - dbg("%s - shutting down urbs", __FUNCTION__); - result = usb_unlink_urb (port->write_urb); - if (result) - dbg("%s - usb_unlink_urb (write_urb)" - " failed with reason: %d", __FUNCTION__, - result); + /* wait for data to drain from the buffer */ + spin_lock_irqsave(&priv->lock, flags); + timeout = PL2303_CLOSING_WAIT; + init_waitqueue_entry(&wait, current); + add_wait_queue(&port->tty->write_wait, &wait); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + if (pl2303_buf_data_avail(priv->buf) == 0 + || timeout == 0 || signal_pending(current) + || !usb_get_intfdata(port->serial->interface)) /* disconnect */ + break; + spin_unlock_irqrestore(&priv->lock, flags); + timeout = schedule_timeout(timeout); + spin_lock_irqsave(&priv->lock, flags); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&port->tty->write_wait, &wait); + /* clear out any remaining data in the buffer */ + pl2303_buf_clear(priv->buf); + spin_unlock_irqrestore(&priv->lock, flags); - result = usb_unlink_urb (port->read_urb); - if (result) - dbg("%s - usb_unlink_urb (read_urb) " - "failed with reason: %d", __FUNCTION__, - result); + /* wait for characters to drain from the device */ + /* (this is long enough for the entire 256 byte */ + /* pl2303 hardware buffer to drain with no flow */ + /* control for data rates of 1200 bps or more, */ + /* for lower rates we should really know how much */ + /* data is in the buffer to compute a delay */ + /* that is not unnecessarily long) */ + bps = tty_get_baud_rate(port->tty); + if (bps > 1200) + timeout = max((HZ*2560)/bps,HZ/10); + else + timeout = 2*HZ; + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(timeout); - result = usb_unlink_urb (port->interrupt_in_urb); - if (result) - dbg("%s - usb_unlink_urb (interrupt_in_urb)" - " failed with reason: %d", __FUNCTION__, - result); + /* shutdown our urbs */ + dbg("%s - shutting down urbs", __FUNCTION__); + usb_kill_urb(port->write_urb); + usb_kill_urb(port->read_urb); + usb_kill_urb(port->interrupt_in_urb); if (port->tty) { c_cflag = port->tty->termios->c_cflag; if (c_cflag & HUPCL) { /* drop DTR and RTS */ - priv = usb_get_serial_port_data(port); spin_lock_irqsave(&priv->lock, flags); priv->line_control = 0; spin_unlock_irqrestore (&priv->lock, flags); set_control_lines (port->serial->dev, 0); } } - } static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file, @@ -672,12 +808,17 @@ static void pl2303_break_ctl (struct usb static void pl2303_shutdown (struct usb_serial *serial) { int i; + struct pl2303_private *priv; dbg("%s", __FUNCTION__); for (i = 0; i < serial->num_ports; ++i) { - kfree (usb_get_serial_port_data(serial->port[i])); - usb_set_serial_port_data(serial->port[i], NULL); + priv = usb_get_serial_port_data(serial->port[i]); + if (priv) { + pl2303_buf_free(priv->buf); + kfree(priv); + usb_set_serial_port_data(serial->port[i], NULL); + } } } @@ -815,11 +956,23 @@ static void pl2303_read_bulk_callback (s static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs) { struct usb_serial_port *port = (struct usb_serial_port *) urb->context; + struct pl2303_private *priv = usb_get_serial_port_data(port); int result; dbg("%s - port %d", __FUNCTION__, port->number); - - if (urb->status) { + + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); + priv->write_urb_in_use = 0; + return; + default: /* error in the urb, so we have to resubmit it */ dbg("%s - Overflow in write", __FUNCTION__); dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); @@ -828,14 +981,199 @@ static void pl2303_write_bulk_callback ( result = usb_submit_urb (port->write_urb, GFP_ATOMIC); if (result) dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n", __FUNCTION__, result); + else + return; + } - return; + priv->write_urb_in_use = 0; + + /* send any buffered data */ + pl2303_send(port); +} + + +/* + * pl2303_buf_alloc + * + * Allocate a circular buffer and all associated memory. + */ + +static struct pl2303_buf *pl2303_buf_alloc(unsigned int size) +{ + + struct pl2303_buf *pb; + + + if (size == 0) + return NULL; + + pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL); + if (pb == NULL) + return NULL; + + pb->buf_buf = kmalloc(size, GFP_KERNEL); + if (pb->buf_buf == NULL) { + kfree(pb); + return NULL; } - schedule_work(&port->work); + pb->buf_size = size; + pb->buf_get = pb->buf_put = pb->buf_buf; + + return pb; + } +/* + * pl2303_buf_free + * + * Free the buffer and all associated memory. + */ + +static void pl2303_buf_free(struct pl2303_buf *pb) +{ + if (pb != NULL) { + if (pb->buf_buf != NULL) + kfree(pb->buf_buf); + kfree(pb); + } +} + + +/* + * pl2303_buf_clear + * + * Clear out all data in the circular buffer. + */ + +static void pl2303_buf_clear(struct pl2303_buf *pb) +{ + if (pb != NULL) + pb->buf_get = pb->buf_put; + /* equivalent to a get of all data available */ +} + + +/* + * pl2303_buf_data_avail + * + * Return the number of bytes of data available in the circular + * buffer. + */ + +static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb) +{ + if (pb != NULL) + return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size); + else + return 0; +} + + +/* + * pl2303_buf_space_avail + * + * Return the number of bytes of space available in the circular + * buffer. + */ + +static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb) +{ + if (pb != NULL) + return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size); + else + return 0; +} + + +/* + * pl2303_buf_put + * + * Copy data data from a user buffer and put it into the circular buffer. + * Restrict to the amount of space available. + * + * Return the number of bytes copied. + */ + +static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf, + unsigned int count) +{ + + unsigned int len; + + + if (pb == NULL) + return 0; + + len = pl2303_buf_space_avail(pb); + if (count > len) + count = len; + + if (count == 0) + return 0; + + len = pb->buf_buf + pb->buf_size - pb->buf_put; + if (count > len) { + memcpy(pb->buf_put, buf, len); + memcpy(pb->buf_buf, buf+len, count - len); + pb->buf_put = pb->buf_buf + count - len; + } else { + memcpy(pb->buf_put, buf, count); + if (count < len) + pb->buf_put += count; + else /* count == len */ + pb->buf_put = pb->buf_buf; + } + + return count; + +} + + +/* + * pl2303_buf_get + * + * Get data from the circular buffer and copy to the given buffer. + * Restrict to the amount of data available. + * + * Return the number of bytes copied. + */ + +static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf, + unsigned int count) +{ + + unsigned int len; + + + if (pb == NULL) + return 0; + + len = pl2303_buf_data_avail(pb); + if (count > len) + count = len; + + if (count == 0) + return 0; + + len = pb->buf_buf + pb->buf_size - pb->buf_get; + if (count > len) { + memcpy(buf, pb->buf_get, len); + memcpy(buf+len, pb->buf_buf, count - len); + pb->buf_get = pb->buf_buf + count - len; + } else { + memcpy(buf, pb->buf_get, count); + if (count < len) + pb->buf_get += count; + else /* count == len */ + pb->buf_get = pb->buf_buf; + } + + return count; + +} + static int __init pl2303_init (void) { int retval; diff -puN drivers/usb/serial/usb-serial.c~bk-usb drivers/usb/serial/usb-serial.c --- 25/drivers/usb/serial/usb-serial.c~bk-usb 2004-09-23 21:23:38.567445096 -0700 +++ 25-akpm/drivers/usb/serial/usb-serial.c 2004-09-23 21:23:39.071368488 -0700 @@ -388,7 +388,7 @@ static struct usb_serial *get_free_seria good_spot = 1; for (j = 1; j <= num_ports-1; ++j) - if ((serial_table[i+j]) || (i+j >= SERIAL_TTY_MINORS)) { + if ((i+j >= SERIAL_TTY_MINORS) || (serial_table[i+j])) { good_spot = 0; i += j; break; @@ -455,15 +455,15 @@ static void destroy_serial(struct kref * if (!port) continue; if (port->read_urb) { - usb_unlink_urb(port->read_urb); + usb_kill_urb(port->read_urb); usb_free_urb(port->read_urb); } if (port->write_urb) { - usb_unlink_urb(port->write_urb); + usb_kill_urb(port->write_urb); usb_free_urb(port->write_urb); } if (port->interrupt_in_urb) { - usb_unlink_urb(port->interrupt_in_urb); + usb_kill_urb(port->interrupt_in_urb); usb_free_urb(port->interrupt_in_urb); } kfree(port->bulk_in_buffer); @@ -621,15 +621,12 @@ static void serial_throttle (struct tty_ if (!port->open_count) { dbg ("%s - port not open", __FUNCTION__); - goto exit; + return; } /* pass on to the driver specific version of this function */ if (port->serial->type->throttle) port->serial->type->throttle(port); - -exit: - ; } static void serial_unthrottle (struct tty_struct * tty) @@ -640,15 +637,12 @@ static void serial_unthrottle (struct tt if (!port->open_count) { dbg("%s - port not open", __FUNCTION__); - goto exit; + return; } /* pass on to the driver specific version of this function */ if (port->serial->type->unthrottle) port->serial->type->unthrottle(port); - -exit: - ; } static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) @@ -681,15 +675,12 @@ static void serial_set_termios (struct t if (!port->open_count) { dbg("%s - port not open", __FUNCTION__); - goto exit; + return; } /* pass on to the driver specific version of this function if it is available */ if (port->serial->type->set_termios) port->serial->type->set_termios(port, old); - -exit: - ; } static void serial_break (struct tty_struct *tty, int break_state) @@ -700,15 +691,12 @@ static void serial_break (struct tty_str if (!port->open_count) { dbg("%s - port not open", __FUNCTION__); - goto exit; + return; } /* pass on to the driver specific version of this function if it is available */ if (port->serial->type->break_ctl) port->serial->type->break_ctl(port, break_state); - -exit: - ; } static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) @@ -819,15 +807,15 @@ static void port_release(struct device * dbg ("%s - %s", __FUNCTION__, dev->bus_id); if (port->read_urb) { - usb_unlink_urb(port->read_urb); + usb_kill_urb(port->read_urb); usb_free_urb(port->read_urb); } if (port->write_urb) { - usb_unlink_urb(port->write_urb); + usb_kill_urb(port->write_urb); usb_free_urb(port->write_urb); } if (port->interrupt_in_urb) { - usb_unlink_urb(port->interrupt_in_urb); + usb_kill_urb(port->interrupt_in_urb); usb_free_urb(port->interrupt_in_urb); } kfree(port->bulk_in_buffer); @@ -1229,7 +1217,7 @@ struct tty_driver *usb_serial_tty_driver static int __init usb_serial_init(void) { int i; - int result = 0; + int result; usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS); if (!usb_serial_tty_driver) @@ -1240,13 +1228,17 @@ static int __init usb_serial_init(void) serial_table[i] = NULL; } - bus_register(&usb_serial_bus_type); + result = bus_register(&usb_serial_bus_type); + if (result) { + err("%s - registering bus driver failed", __FUNCTION__); + goto exit_bus; + } /* register the generic driver, if we should */ result = usb_serial_generic_register(debug); if (result < 0) { err("%s - registering generic driver failed", __FUNCTION__); - goto exit; + goto exit_generic; } usb_serial_tty_driver->owner = THIS_MODULE; @@ -1264,7 +1256,7 @@ static int __init usb_serial_init(void) result = tty_register_driver(usb_serial_tty_driver); if (result) { err("%s - tty_register_driver failed", __FUNCTION__); - goto exit_generic; + goto exit_reg_driver; } /* register the USB driver */ @@ -1281,10 +1273,13 @@ static int __init usb_serial_init(void) exit_tty: tty_unregister_driver(usb_serial_tty_driver); -exit_generic: +exit_reg_driver: usb_serial_generic_deregister(); -exit: +exit_generic: + bus_unregister(&usb_serial_bus_type); + +exit_bus: err ("%s - returning with error %d", __FUNCTION__, result); put_tty_driver(usb_serial_tty_driver); return result; diff -puN drivers/usb/serial/visor.c~bk-usb drivers/usb/serial/visor.c --- 25/drivers/usb/serial/visor.c~bk-usb 2004-09-23 21:23:38.569444792 -0700 +++ 25-akpm/drivers/usb/serial/visor.c 2004-09-23 21:23:39.072368336 -0700 @@ -446,9 +446,9 @@ static void visor_close (struct usb_seri dbg("%s - port %d", __FUNCTION__, port->number); /* shutdown our urbs */ - usb_unlink_urb (port->read_urb); + usb_kill_urb(port->read_urb); if (port->interrupt_in_urb) - usb_unlink_urb (port->interrupt_in_urb); + usb_kill_urb(port->interrupt_in_urb); /* Try to send shutdown message, if the device is gone, this will just fail. */ transfer_buffer = kmalloc (0x12, GFP_KERNEL); @@ -655,7 +655,7 @@ exit: static void visor_throttle (struct usb_serial_port *port) { dbg("%s - port %d", __FUNCTION__, port->number); - usb_unlink_urb (port->read_urb); + usb_kill_urb(port->read_urb); } diff -puN drivers/usb/serial/whiteheat.c~bk-usb drivers/usb/serial/whiteheat.c --- 25/drivers/usb/serial/whiteheat.c~bk-usb 2004-09-23 21:23:38.570444640 -0700 +++ 25-akpm/drivers/usb/serial/whiteheat.c 2004-09-23 21:23:39.073368184 -0700 @@ -680,7 +680,7 @@ static void whiteheat_close(struct usb_s list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) { wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); urb = wrap->urb; - usb_unlink_urb(urb); + usb_kill_urb(urb); list_del(tmp); list_add(tmp, &info->rx_urbs_free); } @@ -691,7 +691,7 @@ static void whiteheat_close(struct usb_s list_for_each_safe(tmp, tmp2, &info->tx_urbs_submitted) { wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); urb = wrap->urb; - usb_unlink_urb(urb); + usb_kill_urb(urb); list_del(tmp); list_add(tmp, &info->tx_urbs_free); } @@ -1344,7 +1344,7 @@ static void stop_command_port(struct usb spin_lock_irqsave(&command_info->lock, flags); command_info->port_running--; if (!command_info->port_running) - usb_unlink_urb(command_port->read_urb); + usb_kill_urb(command_port->read_urb); spin_unlock_irqrestore(&command_info->lock, flags); } @@ -1372,7 +1372,7 @@ static int start_port_read(struct usb_se list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) { wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); urb = wrap->urb; - usb_unlink_urb(urb); + usb_kill_urb(urb); list_del(tmp); list_add(tmp, &info->rx_urbs_free); } diff -puN drivers/usb/storage/isd200.c~bk-usb drivers/usb/storage/isd200.c --- 25/drivers/usb/storage/isd200.c~bk-usb 2004-09-23 21:23:38.572444336 -0700 +++ 25-akpm/drivers/usb/storage/isd200.c 2004-09-23 21:23:39.075367880 -0700 @@ -1052,12 +1052,6 @@ static int isd200_get_inquiry_data( stru /* Standard IDE interface only supports disks */ info->InquiryData.DeviceType = DIRECT_ACCESS_DEVICE; - /* Fix-up the return data from an INQUIRY command to show - * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us - * in Linux. - */ - info->InquiryData.Versions = 0x2; - /* The length must be at least 36 (5 + 31) */ info->InquiryData.AdditionalLength = 0x1F; diff -puN drivers/usb/storage/protocol.c~bk-usb drivers/usb/storage/protocol.c --- 25/drivers/usb/storage/protocol.c~bk-usb 2004-09-23 21:23:38.573444184 -0700 +++ 25-akpm/drivers/usb/storage/protocol.c 2004-09-23 21:23:39.075367880 -0700 @@ -58,38 +58,6 @@ ***********************************************************************/ /* - * Fix-up the return data from an INQUIRY command to show - * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us - */ -static void fix_inquiry_data(struct scsi_cmnd *srb) -{ - unsigned char databuf[3]; - unsigned int index, offset; - - /* verify that it's an INQUIRY command */ - if (srb->cmnd[0] != INQUIRY) - return; - - index = offset = 0; - if (usb_stor_access_xfer_buf(databuf, sizeof(databuf), srb, - &index, &offset, FROM_XFER_BUF) != sizeof(databuf)) - return; - - if ((databuf[2] & 7) == 2) - return; - - US_DEBUGP("Fixing INQUIRY data to show SCSI rev 2 - was %d\n", - databuf[2] & 7); - - /* Change the SCSI revision number */ - databuf[2] = (databuf[2] & ~7) | 2; - - index = offset = 0; - usb_stor_access_xfer_buf(databuf, sizeof(databuf), srb, - &index, &offset, TO_XFER_BUF); -} - -/* * Fix-up the return data from a READ CAPACITY command. My Feiya reader * returns a value that is 1 too large. */ @@ -137,10 +105,6 @@ void usb_stor_qic157_command(struct scsi /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); - if (srb->result == SAM_STAT_GOOD) { - /* fix the INQUIRY data if necessary */ - fix_inquiry_data(srb); - } } void usb_stor_ATAPI_command(struct scsi_cmnd *srb, struct us_data *us) @@ -160,11 +124,6 @@ void usb_stor_ATAPI_command(struct scsi_ /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); - - if (srb->result == SAM_STAT_GOOD) { - /* fix the INQUIRY data if necessary */ - fix_inquiry_data(srb); - } } @@ -208,11 +167,6 @@ void usb_stor_ufi_command(struct scsi_cm /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); - - if (srb->result == SAM_STAT_GOOD) { - /* Fix the data for an INQUIRY, if necessary */ - fix_inquiry_data(srb); - } } void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb, @@ -222,9 +176,6 @@ void usb_stor_transparent_scsi_command(s usb_stor_invoke_transport(srb, us); if (srb->result == SAM_STAT_GOOD) { - /* Fix the INQUIRY data if necessary */ - fix_inquiry_data(srb); - /* Fix the READ CAPACITY result if necessary */ if (us->flags & US_FL_FIX_CAPACITY) fix_read_capacity(srb); diff -puN drivers/usb/storage/scsiglue.c~bk-usb drivers/usb/storage/scsiglue.c --- 25/drivers/usb/storage/scsiglue.c~bk-usb 2004-09-23 21:23:38.575443880 -0700 +++ 25-akpm/drivers/usb/storage/scsiglue.c 2004-09-23 21:23:39.076367728 -0700 @@ -98,6 +98,23 @@ static int slave_configure(struct scsi_d * the end, scatter-gather buffers follow page boundaries. */ blk_queue_dma_alignment(sdev->request_queue, (512 - 1)); + /* Set the SCSI level to at least 2. We'll leave it at 3 if that's + * what is originally reported. We need this to avoid confusing + * the SCSI layer with devices that report 0 or 1, but need 10-byte + * commands (ala ATAPI devices behind certain bridges, or devices + * which simply have broken INQUIRY data). + * + * NOTE: This means /dev/sg programs (ala cdrecord) will get the + * actual information. This seems to be the preference for + * programs like that. + * + * NOTE: This also means that /proc/scsi/scsi and sysfs may report + * the actual value or the modified one, depending on where the + * data comes from. + */ + if (sdev->scsi_level < SCSI_2) + sdev->scsi_level = SCSI_2; + /* According to the technical support people at Genesys Logic, * devices using their chips have problems transferring more than * 32 KB at a time. In practice people have found that 64 KB @@ -266,7 +283,7 @@ static int device_reset(struct scsi_cmnd static int bus_reset(struct scsi_cmnd *srb) { struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; - int result; + int result, rc; US_DEBUGP("%s called\n", __FUNCTION__); if (us->sm_state != US_STATE_IDLE) { @@ -291,8 +308,16 @@ static int bus_reset(struct scsi_cmnd *s result = -EBUSY; US_DEBUGP("Refusing to reset a multi-interface device\n"); } else { - result = usb_reset_device(us->pusb_dev); - US_DEBUGP("usb_reset_device returns %d\n", result); + rc = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf); + if (rc < 0) { + US_DEBUGP("unable to lock device for reset: %d\n", rc); + result = rc; + } else { + result = usb_reset_device(us->pusb_dev); + if (rc) + usb_unlock_device(us->pusb_dev); + US_DEBUGP("usb_reset_device returns %d\n", result); + } } up(&(us->dev_semaphore)); diff -puN drivers/usb/storage/unusual_devs.h~bk-usb drivers/usb/storage/unusual_devs.h --- 25/drivers/usb/storage/unusual_devs.h~bk-usb 2004-09-23 21:23:38.576443728 -0700 +++ 25-akpm/drivers/usb/storage/unusual_devs.h 2004-09-23 21:23:39.077367576 -0700 @@ -36,13 +36,16 @@ /* If you edit this file, please try to keep it sorted first by VendorID, * then by ProductID. * - * If you want to add an entry for this file, please send the following - * to greg@kroah.com: - * - patch that adds the entry for your device which includes your - * email address right above the entry. + * If you want to add an entry for this file, be sure to include the + * following information: + * - a patch that adds the entry for your device, including your + * email address right above the entry (plus maybe a brief + * explanation of the reason for the entry), * - a copy of /proc/bus/usb/devices with your device plugged in * running with this patch. - * + * Send your submission to either Phil Dibowitz or + * Alan Stern , and don't forget to CC: the + * USB development list . */ UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0100, @@ -68,16 +71,6 @@ UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0), #endif -/* : I don't know the name of the bridge - * manufacturer, but I've got an external USB drive by the Revoltec company - * that needs this. otherwise the drive is recognized as /dev/sda, but any - * access to it blocks indefinitely. - */ -UNUSUAL_DEV( 0x0402, 0x5621, 0x0103, 0x0103, - "Revoltec", - "USB/IDE Bridge (ATA/ATAPI)", - US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY), - /* Deduced by Jonathan Woithe * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message * always fails and confuses drive. @@ -180,6 +173,16 @@ UNUSUAL_DEV( 0x04da, 0x0d05, 0x0000, 0x "CD-R/RW Drive", US_SC_8070, US_PR_CB, NULL, 0), +/* Reported by Adriaan Penning + * Note that these cameras report "Medium not present" after + * ALLOW_MEDIUM_REMOVAL, so they also need to be marked + * NOT_LOCKABLE in the SCSI blacklist (and the vendor is MATSHITA). */ +UNUSUAL_DEV( 0x04da, 0x2372, 0x0000, 0x9999, + "Panasonic", + "DMC-LCx Camera", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + /* Most of the following entries were developed with the help of * Shuttle/SCM directly. */ diff -puN include/asm-i386/mach-summit/mach_mpparse.h~bk-usb include/asm-i386/mach-summit/mach_mpparse.h --- 25/include/asm-i386/mach-summit/mach_mpparse.h~bk-usb 2004-09-23 21:23:38.578443424 -0700 +++ 25-akpm/include/asm-i386/mach-summit/mach_mpparse.h 2004-09-23 21:23:39.078367424 -0700 @@ -22,6 +22,7 @@ static inline void mpc_oem_pci_bus(struc { } +extern int usb_early_handoff; static inline int mps_oem_check(struct mp_config_table *mpc, char *oem, char *productid) { @@ -31,6 +32,7 @@ static inline int mps_oem_check(struct m || !strncmp(productid, "RUTHLESS SMP", 12))){ use_cyclone = 1; /*enable cyclone-timer*/ setup_summit(); + usb_early_handoff = 1; return 1; } return 0; @@ -44,6 +46,7 @@ static inline int acpi_madt_oem_check(ch || !strncmp(oem_table_id, "EXA", 3))){ use_cyclone = 1; /*enable cyclone-timer*/ setup_summit(); + usb_early_handoff = 1; return 1; } return 0; diff -puN include/linux/usbdevice_fs.h~bk-usb include/linux/usbdevice_fs.h --- 25/include/linux/usbdevice_fs.h~bk-usb 2004-09-23 21:23:38.579443272 -0700 +++ 25-akpm/include/linux/usbdevice_fs.h 2004-09-23 21:23:39.080367120 -0700 @@ -166,16 +166,6 @@ struct dev_state { unsigned long ifclaimed; }; -/* internal methods & data */ -extern struct usb_driver usbdevfs_driver; -extern struct file_operations usbdevfs_drivers_fops; -extern struct file_operations usbdevfs_devices_fops; -extern struct file_operations usbdevfs_device_file_operations; -extern struct inode_operations usbdevfs_device_inode_operations; -extern struct inode_operations usbdevfs_bus_inode_operations; -extern struct file_operations usbdevfs_bus_file_operations; -extern void usbdevfs_conn_disc_event(void); - #endif /* __KERNEL__ */ /* --------------------------------------------------------------------- */ diff -puN include/linux/usb.h~bk-usb include/linux/usb.h --- 25/include/linux/usb.h~bk-usb 2004-09-23 21:23:38.580443120 -0700 +++ 25-akpm/include/linux/usb.h 2004-09-23 21:23:39.080367120 -0700 @@ -61,6 +61,13 @@ struct usb_host_interface { int extralen; }; +enum usb_interface_condition { + USB_INTERFACE_UNBOUND = 0, + USB_INTERFACE_BINDING, + USB_INTERFACE_BOUND, + USB_INTERFACE_UNBINDING, +}; + /** * struct usb_interface - what usb device drivers talk to * @altsetting: array of interface structures, one for each alternate @@ -75,6 +82,8 @@ struct usb_host_interface { * be unused. The driver should set this value in the probe() * function of the driver, after it has been assigned a minor * number from the USB core by calling usb_register_dev(). + * @condition: binding state of the interface: not bound, binding + * (in probe()), bound to a driver, or unbinding (in disconnect()) * @dev: driver model's view of this device * @class_dev: driver model's class view of this device. * @@ -113,6 +122,7 @@ struct usb_interface { unsigned num_altsetting; /* number of alternate settings */ int minor; /* minor number this interface is bound to */ + enum usb_interface_condition condition; /* state of binding */ struct device dev; /* interface specific device info */ struct class_device *class_dev; }; @@ -264,7 +274,6 @@ struct usb_bus { int bandwidth_isoc_reqs; /* number of Isoc. requests */ struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */ - struct dentry *usbdevfs_dentry; /* usbdevfs dentry entry for the bus */ struct class_device class_dev; /* class device for this bus */ void (*release)(struct usb_bus *bus); /* function to destroy this bus's memory */ @@ -282,6 +291,14 @@ struct usb_bus { struct usb_tt; +/* + * struct usb_device - kernel's representation of a USB device + * + * FIXME: Write the kerneldoc! + * + * Usbcore drivers should not set usbdev->state directly. Instead use + * usb_set_device_state(). + */ struct usb_device { int devnum; /* Address on USB bus */ char devpath [16]; /* Use in messages: /port/port/... */ @@ -315,7 +332,6 @@ struct usb_device { struct list_head filelist; struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */ - struct dentry *usbdevfs_dentry; /* usbdevfs dentry entry for the device */ /* * Child devices - these can be either new devices @@ -333,9 +349,14 @@ struct usb_device { extern struct usb_device *usb_get_dev(struct usb_device *dev); extern void usb_put_dev(struct usb_device *dev); -/* mostly for devices emulating SCSI over USB */ +extern void usb_lock_device(struct usb_device *udev); +extern int usb_trylock_device(struct usb_device *udev); +extern int usb_lock_device_for_reset(struct usb_device *udev, + struct usb_interface *iface); +extern void usb_unlock_device(struct usb_device *udev); + +/* USB port reset for device reinitialization */ extern int usb_reset_device(struct usb_device *dev); -extern int __usb_reset_device(struct usb_device *dev); extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id); diff -puN MAINTAINERS~bk-usb MAINTAINERS --- 25/MAINTAINERS~bk-usb 2004-09-23 21:23:38.582442816 -0700 +++ 25-akpm/MAINTAINERS 2004-09-23 21:23:38.607439016 -0700 @@ -947,7 +947,7 @@ S: Maintained HPUSBSCSI P: Oliver Neukum -M: drivers@neukum.org +M: oliver@neukum.name S: Maintained I2C AND SENSORS DRIVERS @@ -1428,7 +1428,7 @@ S: Maintained MICROTEK X6 SCANNER P: Oliver Neukum -M: drivers@neukum.org +M: oliver@neukum.name S: Maintained MIPS @@ -2197,8 +2197,8 @@ W: http://www.kernel.dk S: Maintained USB ACM DRIVER -P: Vojtech Pavlik -M: vojtech@suse.cz +P: Oliver Neukum +M: oliver@neukum.name L: linux-usb-users@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net S: Maintained @@ -2241,7 +2241,7 @@ S: Maintained USB KAWASAKI LSI DRIVER P: Oliver Neukum -M: drivers@neukum.org +M: oliver@neukum.name L: linux-usb-users@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net S: Maintained @@ -2358,7 +2358,7 @@ L: linux-usb-devel@lists.sourceforge.net W: http://www.connecttech.com S: Supported -USB SN9C10[12] DRIVER +USB SN9C10x DRIVER P: Luca Risolia M: luca.risolia@studio.unibo.it L: linux-usb-devel@lists.sourceforge.net _