bk://kernel.bkbits.net/gregkh/linux/usb-2.6 greg@kroah.com|ChangeSet|20050113234558|56335 greg # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2005/01/13 15:45:58-08:00 greg@kroah.com # USB: give the idmouse the 132 minor number # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/misc/idmouse.c # 2005/01/13 15:45:18-08:00 greg@kroah.com +1 -1 # USB: give the idmouse the 132 minor number # # Signed-off-by: Greg Kroah-Hartman # # Documentation/devices.txt # 2005/01/13 15:45:18-08:00 greg@kroah.com +1 -0 # USB: give the idmouse the 132 minor number # # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2005/01/13 13:32:01-08:00 arekm@pld-linux.org # [PATCH] USB: add Ever UPS vendor/product id to ftdi_sio driver # # This patch allows to use ftdi_sio driver with Ever ECO Pro CDS UPS. # Patch was tested on pre-2.6.10 kernel. # # Signed-Off: Arkadiusz Miskiewicz # # drivers/usb/serial/ftdi_sio.h # 2005/01/13 07:37:33-08:00 arekm@pld-linux.org +6 -0 # USB: add Ever UPS vendor/product id to ftdi_sio driver # # drivers/usb/serial/ftdi_sio.c # 2005/01/13 08:04:12-08:00 arekm@pld-linux.org +3 -0 # USB: add Ever UPS vendor/product id to ftdi_sio driver # # ChangeSet # 2005/01/13 12:46:54-08:00 greg@kroah.com # [PATCH] USB: fix sparse warnings in the idmouse.c driver # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/misc/idmouse.c # 2005/01/13 12:40:10-08:00 greg@kroah.com +3 -3 # USB: fix sparse warnings in the idmouse.c driver # # ChangeSet # 2005/01/13 12:46:08-08:00 echtler@fs.tum.de # [PATCH] USB: add driver for the Siemens ID Mouse fingerprint sensor # # This patch adds a new usb-misc driver for the fingerprint sensor that # can be found in the Siemens ID Mouse USB. "cat /dev/usb/idmouseX" # yields a 225x288 greyscale PNM with the fingerprint information. # # It's now in version 0.5, which uses memcpy() instead of snprintf() # and allows interruption of the image acquisition process, in case # it should get stuck. # # It may be considered controversial that it outputs a PNM instead # of raw data, but I hold the opinion that the 15 bytes of header, # "P5 225 288 256 ", do not do any harm and allow the device to be # used in shell scripts or similar, too. # # The setup packets are not described further, simply because I don"t # know anything about them myself. We captured them under Windows # using SnoopyPro. # # Please include this into the main USB kernel tree - I think it has # by now been scrutinized and tested quite thoroughly. # # Signed-off-by: Florian Echtler # Signed-off-by: Andreas Deresch # # drivers/usb/misc/idmouse.c # 2005/01/13 01:00:45-08:00 echtler@fs.tum.de +442 -0 # USB: add driver for the Siemens ID Mouse fingerprint sensor # # drivers/usb/misc/Makefile # 2005/01/13 01:00:25-08:00 echtler@fs.tum.de +1 -0 # USB: add driver for the Siemens ID Mouse fingerprint sensor # # drivers/usb/misc/Kconfig # 2005/01/13 01:00:25-08:00 echtler@fs.tum.de +14 -0 # USB: add driver for the Siemens ID Mouse fingerprint sensor # # drivers/usb/Makefile # 2005/01/13 01:00:25-08:00 echtler@fs.tum.de +1 -0 # USB: add driver for the Siemens ID Mouse fingerprint sensor # # drivers/usb/misc/idmouse.c # 2005/01/13 01:00:45-08:00 echtler@fs.tum.de +0 -0 # BitKeeper file /home/greg/linux/BK/usb-2.6/drivers/usb/misc/idmouse.c # # ChangeSet # 2005/01/13 12:44:59-08:00 stern@rowland.harvard.edu # [PATCH] USB: correct and clarify error-code documentation # # This patch corrects some misconceptions that have persisted in the USB # error-code documentation for quite some time. # # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # Documentation/usb/error-codes.txt # 2005/01/12 14:10:28-08:00 stern@rowland.harvard.edu +13 -4 # USB: correct and clarify error-code documentation # # ChangeSet # 2005/01/13 12:43:52-08:00 petkan@nucleusys.com # [PATCH] pegasus 2.6.10 cset # # Various fixes to the 'pegasus' driver, notably fixing OSDL bugid #3978 # so this can be used with bridges again (or for that matter, other # normal usage). # # * Bugfixes in the status urb completion handler: # # - Never use garbage that happens to be sitting in the URB # data buffer to change the carrier status. # # # - There are two bits which claim to report parts of carrier # detect bit. This switches to the one that works sometimes; # monitoring through MII might be the best solution. # # - Stop log spamming ... at least some of these chips seem # to get confused about data toggle, no point in warning # about each packet error as it's detected. # # * Report the normal Ethernet MTU. # # * Better ethtool support: # # - Save the message level set by userspace # - Basic WOL support # # * Add USB suspend() and resume() methods, to go with WOL. # Modeled on what stir4200 does. # # Also, some of the messages are converted to the more conventional # style: "ethN: message text", or driver model style before the # device is registered. # # * removed redundant MII code since CONFIG_MII is always set by Kconfig; # * updated the version string; # # Signed-off-by: David Brownell # Signed-off-by: Petko Manolov # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/net/pegasus.h # 2005/01/13 03:04:59-08:00 petkan@nucleusys.com +3 -0 # pegasus 2.6.10 cset # # drivers/usb/net/pegasus.c # 2005/01/13 03:04:59-08:00 petkan@nucleusys.com +114 -90 # pegasus 2.6.10 cset # # ChangeSet # 2005/01/13 12:42:36-08:00 luca.risolia@studio.unibo.it # [PATCH] USB: SN9C10x driver updates # # SN9C10x driver updates. # # Changes: # # @ Fix the sysfs interface # @ Fix allocated minor number after device detection # + Add "force_munmap" module parameter # + Documentation updates # + Add support for old VIDIOC_S_PARM_OLD and VIDIOC_S_CTRL_OLD ioctl's # # Signed-off-by: Luca Risolia # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/media/sn9c102_tas5130d1b.c # 2005/01/12 18:05:21-08:00 luca.risolia@studio.unibo.it +1 -1 # USB: SN9C10x driver updates # # drivers/usb/media/sn9c102_tas5110c1b.c # 2005/01/12 18:05:21-08:00 luca.risolia@studio.unibo.it +1 -1 # USB: SN9C10x driver updates # # drivers/usb/media/sn9c102_sensor.h # 2005/01/12 18:05:21-08:00 luca.risolia@studio.unibo.it +1 -1 # USB: SN9C10x driver updates # # drivers/usb/media/sn9c102_pas106b.c # 2005/01/12 18:05:20-08:00 luca.risolia@studio.unibo.it +1 -1 # USB: SN9C10x driver updates # # drivers/usb/media/sn9c102_mi0343.c # 2005/01/12 18:05:20-08:00 luca.risolia@studio.unibo.it +1 -1 # USB: SN9C10x driver updates # # drivers/usb/media/sn9c102_hv7131d.c # 2005/01/12 18:05:20-08:00 luca.risolia@studio.unibo.it +1 -1 # USB: SN9C10x driver updates # # drivers/usb/media/sn9c102_core.c # 2005/01/12 18:05:20-08:00 luca.risolia@studio.unibo.it +67 -29 # USB: SN9C10x driver updates # # drivers/usb/media/sn9c102.h # 2005/01/12 18:05:20-08:00 luca.risolia@studio.unibo.it +10 -3 # USB: SN9C10x driver updates # # Documentation/usb/sn9c102.txt # 2005/01/12 18:15:19-08:00 luca.risolia@studio.unibo.it +17 -6 # USB: SN9C10x driver updates # # ChangeSet # 2005/01/13 12:41:41-08:00 tglx@linutronix.de # [PATCH] USB: Lock initializer cleanup - batch 4 # # Use the new lock initializers DEFINE_SPIN_LOCK and DEFINE_RW_LOCK # # Signed-off-by: Thomas Gleixner # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/core/hub.c # 2005/01/12 14:01:19-08:00 tglx@linutronix.de +2 -2 # USB: Lock initializer cleanup - batch 4 # # drivers/usb/core/hcd.c # 2005/01/12 14:01:20-08:00 tglx@linutronix.de +1 -1 # USB: Lock initializer cleanup - batch 4 # # drivers/usb/core/file.c # 2005/01/12 14:01:20-08:00 tglx@linutronix.de +1 -1 # USB: Lock initializer cleanup - batch 4 # # ChangeSet # 2005/01/12 10:23:24-08:00 david-b@pacbell.net # [PATCH] USB: usbnet: Olympus R1000 PDA, and blacklisting if CDC && !ZAURUS # # Add support for the Zaurus-compatible configuration of the # Olympus R1000 PDA. (IDs from Todd Blumer, todd@sdgsystems.com) # # Resolve a FIXME: all the Zaurus support morphs into blacklist # entries when CDC Ethernet is enabled and Zaurus isn't (since the # Zaurus firmware falsely advertises itself as CDC conformant). # # Signed-off-by: David Brownell # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/net/usbnet.c # 2005/01/11 19:44:33-08:00 david-b@pacbell.net +56 -36 # USB: usbnet: Olympus R1000 PDA, and blacklisting if CDC && !ZAURUS # # ChangeSet # 2005/01/12 10:22:41-08:00 adobriyan@mail.ru # [PATCH] USB: drivers/usb/*: s/0/NULL/ in pointer context # # Signed-off-by: Alexey Dobriyan # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/serial/keyspan.c # 2005/01/11 16:00:00-08:00 adobriyan@mail.ru +3 -3 # USB: drivers/usb/*: s/0/NULL/ in pointer context # # drivers/usb/serial/garmin_gps.c # 2005/01/11 16:00:00-08:00 adobriyan@mail.ru +4 -4 # USB: drivers/usb/*: s/0/NULL/ in pointer context # # drivers/usb/net/usbnet.c # 2005/01/11 16:00:00-08:00 adobriyan@mail.ru +5 -4 # USB: drivers/usb/*: s/0/NULL/ in pointer context # # drivers/usb/misc/usbtest.c # 2005/01/11 16:00:00-08:00 adobriyan@mail.ru +2 -2 # USB: drivers/usb/*: s/0/NULL/ in pointer context # # drivers/usb/input/hid-core.c # 2005/01/11 16:00:00-08:00 adobriyan@mail.ru +1 -1 # USB: drivers/usb/*: s/0/NULL/ in pointer context # # drivers/usb/image/mdc800.c # 2005/01/11 16:00:00-08:00 adobriyan@mail.ru +2 -2 # USB: drivers/usb/*: s/0/NULL/ in pointer context # # drivers/usb/host/sl811-hcd.c # 2005/01/11 16:00:00-08:00 adobriyan@mail.ru +1 -1 # USB: drivers/usb/*: s/0/NULL/ in pointer context # # drivers/usb/host/ehci-sched.c # 2005/01/11 16:00:00-08:00 adobriyan@mail.ru +13 -13 # USB: drivers/usb/*: s/0/NULL/ in pointer context # # drivers/usb/host/ehci-q.c # 2005/01/11 16:00:00-08:00 adobriyan@mail.ru +7 -7 # USB: drivers/usb/*: s/0/NULL/ in pointer context # # drivers/usb/host/ehci-mem.c # 2005/01/11 16:00:00-08:00 adobriyan@mail.ru +4 -4 # USB: drivers/usb/*: s/0/NULL/ in pointer context # # drivers/usb/host/ehci-hcd.c # 2005/01/11 16:00:00-08:00 adobriyan@mail.ru +1 -1 # USB: drivers/usb/*: s/0/NULL/ in pointer context # # drivers/usb/core/message.c # 2005/01/11 16:00:00-08:00 adobriyan@mail.ru +2 -2 # USB: drivers/usb/*: s/0/NULL/ in pointer context # # drivers/usb/core/hub.c # 2005/01/11 16:00:00-08:00 adobriyan@mail.ru +3 -3 # USB: drivers/usb/*: s/0/NULL/ in pointer context # # drivers/usb/core/hcd.c # 2005/01/11 16:00:00-08:00 adobriyan@mail.ru +1 -1 # USB: drivers/usb/*: s/0/NULL/ in pointer context # # drivers/usb/core/devio.c # 2005/01/11 16:00:00-08:00 adobriyan@mail.ru +3 -3 # USB: drivers/usb/*: s/0/NULL/ in pointer context # # drivers/usb/class/usblp.c # 2005/01/11 16:00:00-08:00 adobriyan@mail.ru +1 -1 # USB: drivers/usb/*: s/0/NULL/ in pointer context # # ChangeSet # 2005/01/11 17:06:37-08:00 stern@rowland.harvard.edu # [PATCH] USB UHCI: protect DMA-able fields with barriers # # This is a revised patch to fix a problem in the UHCI driver, in which the # compiler incorrectly optimizes certain accesses to DMA-able memory # addresses. The patch reorganizes the code to use special accessor # routines including a compiler optimization barrier, and stores the results # in local variables to help prevent repeated accesses. No use is made of # the "volatile" keyword. :-) # # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/host/uhci-hcd.h # 2005/01/11 17:06:12-08:00 stern@rowland.harvard.edu +23 -1 # [PATCH] USB UHCI: protect DMA-able fields with barriers # # This is a revised patch to fix a problem in the UHCI driver, in which the # compiler incorrectly optimizes certain accesses to DMA-able memory # addresses. The patch reorganizes the code to use special accessor # routines including a compiler optimization barrier, and stores the results # in local variables to help prevent repeated accesses. No use is made of # the "volatile" keyword. :-) # # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/host/uhci-hcd.c # 2005/01/11 17:06:12-08:00 stern@rowland.harvard.edu +27 -17 # [PATCH] USB UHCI: protect DMA-able fields with barriers # # This is a revised patch to fix a problem in the UHCI driver, in which the # compiler incorrectly optimizes certain accesses to DMA-able memory # addresses. The patch reorganizes the code to use special accessor # routines including a compiler optimization barrier, and stores the results # in local variables to help prevent repeated accesses. No use is made of # the "volatile" keyword. :-) # # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/host/uhci-debug.c # 2005/01/11 17:06:12-08:00 stern@rowland.harvard.edu +8 -7 # [PATCH] USB UHCI: protect DMA-able fields with barriers # # This is a revised patch to fix a problem in the UHCI driver, in which the # compiler incorrectly optimizes certain accesses to DMA-able memory # addresses. The patch reorganizes the code to use special accessor # routines including a compiler optimization barrier, and stores the results # in local variables to help prevent repeated accesses. No use is made of # the "volatile" keyword. :-) # # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2005/01/11 17:06:02-08:00 zaitcev@redhat.com # [PATCH] USB: Patch to fix ub looping with a tag mismatch # # If a command times out, we resubmit a retry. Some devices, however, buffer # everything we send and then eventually reply to a command we have timed out # already. We receive a bad tag, send a new command, device replies to the # one sent before, and so on without end. # # The fix is to flush pending replies if tags mismatch (by reading them). # # Signed-off-by: Pete Zaitcev # Signed-off-by: Greg Kroah-Hartman # # drivers/block/ub.c # 2005/01/11 17:05:37-08:00 zaitcev@redhat.com +44 -42 # [PATCH] USB: Patch to fix ub looping with a tag mismatch # # If a command times out, we resubmit a retry. Some devices, however, buffer # everything we send and then eventually reply to a command we have timed out # already. We receive a bad tag, send a new command, device replies to the # one sent before, and so on without end. # # The fix is to flush pending replies if tags mismatch (by reading them). # # Signed-off-by: Pete Zaitcev # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2005/01/11 17:04:56-08:00 phil@ipom.com # [PATCH] USB unusual_devs addition: Ignore residue for ours-tech disk # # This "Ours Technology" device incorrectly reports 100% residue on transferred data. # Patch originally sent by Daniel Drake , with slight modification by me. # # Signed-off-by: Daniel Drake # Signed-off-by: Phil Dibowitz # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/storage/unusual_devs.h # 2005/01/11 17:04:25-08:00 phil@ipom.com +8 -0 # [PATCH] USB unusual_devs addition: Ignore residue for ours-tech disk # # This "Ours Technology" device incorrectly reports 100% residue on transferred data. # Patch originally sent by Daniel Drake , with slight modification by me. # # Signed-off-by: Daniel Drake # Signed-off-by: Phil Dibowitz # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2005/01/11 17:04:01-08:00 lmendez19@austin.rr.com # [PATCH] USB cypress_m8: line setting bugfix, circular write buffer added, misc. fixes # # This patch brings up to date the driver with the current stable development # source. A bug with RTS not raising upon first open was fixed, Al Borcher's # circular write buffer from the pl2303 driver was implemented, and various # fixes/cleanups were made. # # Signed-off-by: Lonnie Mendez # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/serial/cypress_m8.c # 2005/01/11 17:03:39-08:00 lmendez19@austin.rr.com +465 -149 # [PATCH] USB cypress_m8: line setting bugfix, circular write buffer added, misc. fixes # # This patch brings up to date the driver with the current stable development # source. A bug with RTS not raising upon first open was fixed, Al Borcher's # circular write buffer from the pl2303 driver was implemented, and various # fixes/cleanups were made. # # Signed-off-by: Lonnie Mendez # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2005/01/11 17:02:56-08:00 oliver@neukum.org # [PATCH] USB: CDC ACM module and Zoom 2985 modem # # there's a bug in the acm driver's work arounds. This fixes it. # # Signed-Off-By: Oliver Neukum # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/class/cdc-acm.c # 2005/01/11 17:02:27-08:00 oliver@neukum.org +13 -10 # [PATCH] USB: CDC ACM module and Zoom 2985 modem # # there's a bug in the acm driver's work arounds. This fixes it. # # Signed-Off-By: Oliver Neukum # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2005/01/11 15:19:24-08:00 greg@kroah.com # USB: remove some unneeded exported symbols. # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/core/usb.c # 2005/01/11 15:18:34-08:00 greg@kroah.com +1 -2 # USB: remove some unneeded exported symbols. # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/core/hub.c # 2005/01/11 15:18:34-08:00 greg@kroah.com +0 -1 # USB: remove some unneeded exported symbols. # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/core/hcd.c # 2005/01/11 15:18:34-08:00 greg@kroah.com +0 -3 # USB: remove some unneeded exported symbols. # # Signed-off-by: Greg Kroah-Hartman # diff -Nru a/Documentation/devices.txt b/Documentation/devices.txt --- a/Documentation/devices.txt 2005-01-13 17:08:38 -08:00 +++ b/Documentation/devices.txt 2005-01-13 17:08:38 -08:00 @@ -2563,6 +2563,7 @@ 128 = /dev/usb/brlvgr0 First Braille Voyager device ... 131 = /dev/usb/brlvgr3 Fourth Braille Voyager device + 132 = /dev/usb/idmouse ID Mouse (fingerprint scanner) device 144 = /dev/usb/lcd USB LCD device 160 = /dev/usb/legousbtower0 1st USB Legotower device ... diff -Nru a/Documentation/usb/error-codes.txt b/Documentation/usb/error-codes.txt --- a/Documentation/usb/error-codes.txt 2005-01-13 17:08:38 -08:00 +++ b/Documentation/usb/error-codes.txt 2005-01-13 17:08:38 -08:00 @@ -83,7 +83,18 @@ prescribed bus turn-around time c) unknown USB error --EILSEQ (*, **) CRC mismatch +-EILSEQ (*, **) a) CRC mismatch + b) no response packet received within the + prescribed bus turn-around time + c) unknown USB error + + In cases b) and c) either -EPROTO or -EILSEQ + may be returned. Note that often the controller + hardware does not distinguish among cases a), + b), and c), so a driver cannot tell whether + there was a protocol error, a failure to respond + (often caused by device disconnect), or some + other fault. -EPIPE (**) Endpoint stalled. For non-control endpoints, reset this status with usb_clear_halt(). @@ -104,8 +115,6 @@ specified buffer, and URB_SHORT_NOT_OK was set in urb->transfer_flags. --ETIMEDOUT (**) transfer timed out, NAK - -ENODEV Device was removed. Often preceded by a burst of other errors, since the hub driver does't detect device removal events immediately. @@ -143,4 +152,4 @@ usb_get_*/usb_set_*(): usb_control_msg(): usb_bulk_msg(): - All USB errors (submit/status) can occur +-ETIMEDOUT timeout expired before the transfer completed diff -Nru a/Documentation/usb/sn9c102.txt b/Documentation/usb/sn9c102.txt --- a/Documentation/usb/sn9c102.txt 2005-01-13 17:08:38 -08:00 +++ b/Documentation/usb/sn9c102.txt 2005-01-13 17:08:38 -08:00 @@ -26,7 +26,7 @@ 1. Copyright ============ -Copyright (C) 2004 by Luca Risolia +Copyright (C) 2004-2005 by Luca Risolia 2. Disclaimer @@ -165,6 +165,17 @@ other camera. Default: -1 ------------------------------------------------------------------------------- +Name: force_munmap; +Type: bool array (min = 0, max = 64) +Syntax: <0|1[,...]> +Description: Force the application to unmap previously mapped buffer memory + before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not + all the applications support this feature. This parameter is + specific for each detected camera. + 0 = do not force memory unmapping" + 1 = force memory unmapping (save memory)" +Default: 0 +------------------------------------------------------------------------------- Name: debug Type: int Syntax: @@ -362,11 +373,11 @@ file descriptor. Once it is selected, the application must close and reopen the 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 the buffers again before any I/O attempts -on them. +- although it is not mandatory, previously mapped buffer memory should always +be unmapped before calling any "VIDIOC_S_CROP" or "VIDIOC_S_FMT" ioctl's. +The same number of buffers as before will be allocated again to match the size +of the new video frames, so you have to map the buffers again before any I/O +attempts on them. Consistently with the hardware limits, this driver also supports image downscaling with arbitrary scaling factors from 1, 2 and 4 in both directions. diff -Nru a/drivers/block/ub.c b/drivers/block/ub.c --- a/drivers/block/ub.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/block/ub.c 2005-01-13 17:08:38 -08:00 @@ -108,7 +108,8 @@ */ #define UB_URB_TIMEOUT (HZ*2) #define UB_DATA_TIMEOUT (HZ*5) /* ZIP does spin-ups in the data phase */ -#define UB_CTRL_TIMEOUT (HZ/2) /* 500ms ought to be enough to clear a stall */ +#define UB_STAT_TIMEOUT (HZ*5) /* Same spinups and eject for a dataless cmd. */ +#define UB_CTRL_TIMEOUT (HZ/2) /* 500ms ought to be enough to clear a stall */ /* * An instance of a SCSI command in transit. @@ -307,6 +308,7 @@ static void ub_scsi_dispatch(struct ub_dev *sc); static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd); static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc); +static void __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd); static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd); static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd); static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, @@ -894,7 +896,7 @@ if (urb->status == -EPIPE) { /* * STALL while clearning STALL. - * A STALL is illegal on a control pipe! + * The control pipe clears itself - nothing to do. * XXX Might try to reset the device here and retry. */ printk(KERN_NOTICE "%s: " @@ -917,7 +919,7 @@ if (urb->status == -EPIPE) { /* * STALL while clearning STALL. - * A STALL is illegal on a control pipe! + * The control pipe clears itself - nothing to do. * XXX Might try to reset the device here and retry. */ printk(KERN_NOTICE "%s: " @@ -941,7 +943,8 @@ rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); if (rc != 0) { printk(KERN_NOTICE "%s: " - "unable to submit clear for device %u (%d)\n", + "unable to submit clear for device %u" + " (code %d)\n", sc->name, sc->dev->devnum, rc); /* * This is typically ENOMEM or some other such shit. @@ -1001,7 +1004,8 @@ rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); if (rc != 0) { printk(KERN_NOTICE "%s: " - "unable to submit clear for device %u (%d)\n", + "unable to submit clear for device %u" + " (code %d)\n", sc->name, sc->dev->devnum, rc); /* * This is typically ENOMEM or some other such shit. @@ -1033,7 +1037,8 @@ rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); if (rc != 0) { printk(KERN_NOTICE "%s: " - "unable to submit clear for device %u (%d)\n", + "unable to submit clear for device %u" + " (code %d)\n", sc->name, sc->dev->devnum, rc); /* * This is typically ENOMEM or some other such shit. @@ -1061,33 +1066,7 @@ sc->name, sc->dev->devnum); goto Bad_End; } - - /* - * ub_state_stat only not dropping the count... - */ - UB_INIT_COMPLETION(sc->work_done); - - sc->last_pipe = sc->recv_bulk_pipe; - usb_fill_bulk_urb(&sc->work_urb, sc->dev, - sc->recv_bulk_pipe, &sc->work_bcs, - US_BULK_CS_WRAP_LEN, ub_urb_complete, sc); - sc->work_urb.transfer_flags = URB_ASYNC_UNLINK; - sc->work_urb.actual_length = 0; - sc->work_urb.error_count = 0; - sc->work_urb.status = 0; - - rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC); - if (rc != 0) { - /* XXX Clear stalls */ - printk("%s: CSW #%d submit failed (%d)\n", - sc->name, cmd->tag, rc); /* P3 */ - ub_complete(&sc->work_done); - ub_state_done(sc, cmd, rc); - return; - } - - sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; - add_timer(&sc->work_timer); + __ub_state_stat(sc, cmd); return; } @@ -1108,17 +1087,31 @@ goto Bad_End; } +#if 0 if (bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN) && bcs->Signature != cpu_to_le32(US_BULK_CS_OLYMPUS_SIGN)) { - /* XXX Rate-limit, even for P3 tagged */ - /* P3 */ printk("ub: signature 0x%x\n", bcs->Signature); /* Windows ignores signatures, so do we. */ } +#endif if (bcs->Tag != cmd->tag) { - /* P3 */ printk("%s: tag orig 0x%x reply 0x%x\n", - sc->name, cmd->tag, bcs->Tag); - goto Bad_End; + /* + * This usually happens when we disagree with the + * device's microcode about something. For instance, + * a few of them throw this after timeouts. They buffer + * commands and reply at commands we timed out before. + * Without flushing these replies we loop forever. + */ + if (++cmd->stat_count >= 4) { + printk(KERN_NOTICE "%s: " + "tag mismatch orig 0x%x reply 0x%x " + "on device %u\n", + sc->name, cmd->tag, bcs->Tag, + sc->dev->devnum); + goto Bad_End; + } + __ub_state_stat(sc, cmd); + return; } switch (bcs->Status) { @@ -1174,9 +1167,9 @@ /* * Factorization helper for the command state machine: - * Submit a CSW read and go to STAT state. + * Submit a CSW read. */ -static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +static void __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) { int rc; @@ -1192,14 +1185,23 @@ 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 */ + printk("%s: CSW #%d submit failed (%d)\n", sc->name, cmd->tag, rc); /* P3 */ ub_complete(&sc->work_done); ub_state_done(sc, cmd, rc); return; } - sc->work_timer.expires = jiffies + UB_URB_TIMEOUT; + sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT; add_timer(&sc->work_timer); +} + +/* + * Factorization helper for the command state machine: + * Submit a CSW read and go to STAT state. + */ +static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + __ub_state_stat(sc, cmd); cmd->stat_count = 0; cmd->state = UB_CMDST_STAT; diff -Nru a/drivers/usb/Makefile b/drivers/usb/Makefile --- a/drivers/usb/Makefile 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/Makefile 2005-01-13 17:08:38 -08:00 @@ -59,6 +59,7 @@ obj-$(CONFIG_USB_CYTHERM) += misc/ obj-$(CONFIG_USB_EMI26) += misc/ obj-$(CONFIG_USB_EMI62) += misc/ +obj-$(CONFIG_USB_IDMOUSE) += misc/ obj-$(CONFIG_USB_LCD) += misc/ obj-$(CONFIG_USB_LED) += misc/ obj-$(CONFIG_USB_LEGOTOWER) += misc/ diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c --- a/drivers/usb/class/cdc-acm.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/class/cdc-acm.c 2005-01-13 17:08:38 -08:00 @@ -544,24 +544,24 @@ /* normal probing*/ if (!buffer) { - err("Wierd descriptor references"); + err("Wierd descriptor references\n"); return -EINVAL; } if (!buflen) { if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) { - dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint"); + dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint\n"); buflen = intf->cur_altsetting->endpoint->extralen; buffer = intf->cur_altsetting->endpoint->extra; } else { - err("Zero length descriptor references"); + err("Zero length descriptor references\n"); return -EINVAL; } } while (buflen > 0) { if (buffer [1] != USB_DT_CS_INTERFACE) { - err("skipping garbage"); + err("skipping garbage\n"); goto next_desc; } @@ -614,14 +614,10 @@ } } - if (data_interface_num != call_interface_num) - dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported."); + if (data_interface_num != call_interface_num) + dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.\n"); skip_normal_probe: - if (usb_interface_claimed(data_interface)) { /* valid in this context */ - dev_dbg(&intf->dev,"The data interface isn't available\n"); - return -EBUSY; - } /*workaround for switched interfaces */ if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) { @@ -636,6 +632,13 @@ return -EINVAL; } } + + if (usb_interface_claimed(data_interface)) { /* valid in this context */ + dev_dbg(&intf->dev,"The data interface isn't available\n"); + return -EBUSY; + } + + if (data_interface->cur_altsetting->desc.bNumEndpoints < 2) return -EINVAL; diff -Nru a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c --- a/drivers/usb/class/usblp.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/class/usblp.c 2005-01-13 17:08:38 -08:00 @@ -1096,7 +1096,7 @@ usblp->writebuf, 0, usblp_bulk_write, usblp); - usblp->bidir = (usblp->protocol[protocol].epread != 0); + usblp->bidir = (usblp->protocol[protocol].epread != NULL); if (usblp->bidir) usb_fill_bulk_urb(usblp->readurb, usblp->dev, usb_rcvbulkpipe(usblp->dev, diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c --- a/drivers/usb/core/devio.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/core/devio.c 2005-01-13 17:08:38 -08:00 @@ -1127,7 +1127,7 @@ if (copy_from_user(&ctrl, arg, sizeof (ctrl))) return -EFAULT; if ((size = _IOC_SIZE (ctrl.ioctl_code)) > 0) { - if ((buf = kmalloc (size, GFP_KERNEL)) == 0) + if ((buf = kmalloc (size, GFP_KERNEL)) == NULL) return -ENOMEM; if ((_IOC_DIR(ctrl.ioctl_code) & _IOC_WRITE)) { if (copy_from_user (buf, ctrl.data, size)) { @@ -1187,7 +1187,7 @@ down_read(&usb_bus_type.subsys.rwsem); if (intf->dev.driver) driver = to_usb_driver(intf->dev.driver); - if (driver == 0 || driver->ioctl == 0) { + if (driver == NULL || driver->ioctl == NULL) { retval = -ENOTTY; } else { retval = driver->ioctl (intf, ctrl.ioctl_code, buf); @@ -1203,7 +1203,7 @@ && size > 0 && copy_to_user (ctrl.data, buf, size) != 0) retval = -EFAULT; - if (buf != 0) + if (buf != NULL) kfree (buf); return retval; } diff -Nru a/drivers/usb/core/file.c b/drivers/usb/core/file.c --- a/drivers/usb/core/file.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/core/file.c 2005-01-13 17:08:38 -08:00 @@ -30,7 +30,7 @@ #define MAX_USB_MINORS 256 static struct file_operations *usb_minors[MAX_USB_MINORS]; -static spinlock_t minor_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(minor_lock); static int usb_open(struct inode * inode, struct file * file) { diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/core/hcd.c 2005-01-13 17:08:38 -08:00 @@ -86,7 +86,6 @@ /* host controllers we manage */ LIST_HEAD (usb_bus_list); -EXPORT_SYMBOL_GPL (usb_bus_list); /* used when allocating bus numbers */ #define USB_MAXBUS 64 @@ -97,10 +96,9 @@ /* used when updating list of hcds */ DECLARE_MUTEX (usb_bus_list_lock); /* exported only for usbfs */ -EXPORT_SYMBOL_GPL (usb_bus_list_lock); /* used when updating hcd data */ -static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(hcd_data_lock); /* wait queue for synchronous unlinks */ DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue); @@ -526,7 +524,7 @@ /* do nothing if the urb's been unlinked */ if (!urb->dev || urb->status != -EINPROGRESS - || (hcd = urb->dev->bus->hcpriv) == 0) { + || (hcd = urb->dev->bus->hcpriv) == NULL) { spin_unlock (&urb->lock); local_irq_restore (flags); return; @@ -1542,7 +1540,6 @@ usb_set_device_state(hcd->self.root_hub, USB_STATE_NOTATTACHED); mod_timer(&hcd->rh_timer, jiffies); } -EXPORT_SYMBOL (usb_hc_died); /*-------------------------------------------------------------------------*/ diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/core/hub.c 2005-01-13 17:08:38 -08:00 @@ -39,10 +39,10 @@ /* 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; +static DEFINE_SPINLOCK(device_state_lock); /* khubd's worklist and its lock */ -static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(hub_event_lock); static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */ /* Wakes up khubd */ @@ -405,7 +405,7 @@ * since each TT has "at least two" buffers that can need it (and * there can be many TTs per hub). even if they're uncommon. */ - if ((clear = kmalloc (sizeof *clear, SLAB_ATOMIC)) == 0) { + if ((clear = kmalloc (sizeof *clear, SLAB_ATOMIC)) == NULL) { dev_err (&udev->dev, "can't save CLEAR_TT_BUFFER state\n"); /* FIXME recover somehow ... RESET_TT? */ return; @@ -1618,7 +1618,6 @@ udev->dev.power.power_state = state; return status; } -EXPORT_SYMBOL(__usb_suspend_device); /** * usb_suspend_device - suspend a usb device @@ -2300,7 +2299,7 @@ int status; qual = kmalloc (sizeof *qual, SLAB_KERNEL); - if (qual == 0) + if (qual == NULL) return; status = usb_get_descriptor (udev, USB_DT_DEVICE_QUALIFIER, 0, @@ -2832,7 +2831,7 @@ len = le16_to_cpu(udev->config[index].desc.wTotalLength); } buf = kmalloc (len, SLAB_KERNEL); - if (buf == 0) { + if (buf == NULL) { dev_err(&udev->dev, "no mem to re-read configs after reset\n"); /* assume the worst */ return 1; diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c --- a/drivers/usb/core/message.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/core/message.c 2005-01-13 17:08:38 -08:00 @@ -209,7 +209,7 @@ kfree (io->urbs); io->urbs = NULL; } - if (io->dev->dev.dma_mask != 0) + if (io->dev->dev.dma_mask != NULL) usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents); io->dev = NULL; } @@ -334,7 +334,7 @@ /* not all host controllers use DMA (like the mainstream pci ones); * they can use PIO (sl811) or be software over another transport. */ - dma = (dev->dev.dma_mask != 0); + dma = (dev->dev.dma_mask != NULL); if (dma) io->entries = usb_buffer_map_sg (dev, pipe, sg, nents); else diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/core/usb.c 2005-01-13 17:08:38 -08:00 @@ -63,8 +63,7 @@ int nousb; /* Disable USB when built into kernel image */ /* Not honored on modular build */ -DECLARE_RWSEM(usb_all_devices_rwsem); -EXPORT_SYMBOL(usb_all_devices_rwsem); +static DECLARE_RWSEM(usb_all_devices_rwsem); static int generic_probe (struct device *dev) diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c --- a/drivers/usb/host/ehci-hcd.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/host/ehci-hcd.c 2005-01-13 17:08:38 -08:00 @@ -796,7 +796,7 @@ * such lossage has been observed on both VT6202 and VT8235. */ if (HCD_IS_RUNNING (ehci_to_hcd(ehci)->state) && - (ehci->async->qh_next.ptr != 0 || + (ehci->async->qh_next.ptr != NULL || ehci->periodic_sched != 0)) timer_action (ehci, TIMER_IO_WATCHDOG); } diff -Nru a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c --- a/drivers/usb/host/ehci-mem.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/host/ehci-mem.c 2005-01-13 17:08:38 -08:00 @@ -51,7 +51,7 @@ dma_addr_t dma; qtd = dma_pool_alloc (ehci->qtd_pool, flags, &dma); - if (qtd != 0) { + if (qtd != NULL) { ehci_qtd_init (qtd, dma); } return qtd; @@ -98,7 +98,7 @@ /* dummy td enables safe urb queuing */ qh->dummy = ehci_qtd_alloc (ehci, flags); - if (qh->dummy == 0) { + if (qh->dummy == NULL) { ehci_dbg (ehci, "no dummy td\n"); dma_pool_free (ehci->qh_pool, qh, qh->qh_dma); qh = NULL; @@ -215,7 +215,7 @@ dma_alloc_coherent (ehci_to_hcd(ehci)->self.controller, ehci->periodic_size * sizeof(__le32), &ehci->periodic_dma, 0); - if (ehci->periodic == 0) { + if (ehci->periodic == NULL) { goto fail; } for (i = 0; i < ehci->periodic_size; i++) @@ -223,7 +223,7 @@ /* software shadow of hardware table */ ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *), flags); - if (ehci->pshadow == 0) { + if (ehci->pshadow == NULL) { goto fail; } memset (ehci->pshadow, 0, ehci->periodic_size * sizeof (void *)); diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c --- a/drivers/usb/host/ehci-q.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/host/ehci-q.c 2005-01-13 17:08:38 -08:00 @@ -218,7 +218,7 @@ __releases(ehci->lock) __acquires(ehci->lock) { - if (likely (urb->hcpriv != 0)) { + if (likely (urb->hcpriv != NULL)) { struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv; /* S-mask in a QH means it's an interrupt urb */ @@ -404,7 +404,7 @@ } /* last urb's completion might still need calling */ - if (likely (last != 0)) { + if (likely (last != NULL)) { ehci_urb_done (ehci, last->urb, regs); count++; ehci_qtd_free (ehci, last); @@ -846,7 +846,7 @@ /* just one way to queue requests: swap with the dummy qtd. * only hc or qh_refresh() ever modify the overlay. */ - if (likely (qtd != 0)) { + if (likely (qtd != NULL)) { struct ehci_qtd *dummy; dma_addr_t dma; __le32 token; @@ -921,12 +921,12 @@ /* Control/bulk operations through TTs don't need scheduling, * the HC and TT handle it when the TT has a buffer ready. */ - if (likely (qh != 0)) { + if (likely (qh != NULL)) { if (likely (qh->qh_state == QH_STATE_IDLE)) qh_link_async (ehci, qh_get (qh)); } spin_unlock_irqrestore (&ehci->lock, flags); - if (unlikely (qh == 0)) { + if (unlikely (qh == NULL)) { qtd_list_free (ehci, urb, qtd_list); return -ENOMEM; } @@ -967,7 +967,7 @@ * active but idle for a while once it empties. */ if (HCD_IS_RUNNING (ehci_to_hcd(ehci)->state) - && ehci->async->qh_next.qh == 0) + && ehci->async->qh_next.qh == NULL) timer_action (ehci, TIMER_ASYNC_OFF); } @@ -1048,7 +1048,7 @@ timer_action_done (ehci, TIMER_ASYNC_SHRINK); rescan: qh = ehci->async->qh_next.qh; - if (likely (qh != 0)) { + if (likely (qh != NULL)) { do { /* clean any finished work for this qh */ if (!list_empty (&qh->qtd_list) diff -Nru a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c --- a/drivers/usb/host/ehci-sched.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/host/ehci-sched.c 2005-01-13 17:08:38 -08:00 @@ -604,7 +604,7 @@ /* get qh and force any scheduling errors */ INIT_LIST_HEAD (&empty); qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv); - if (qh == 0) { + if (qh == NULL) { status = -ENOMEM; goto done; } @@ -615,7 +615,7 @@ /* then queue the urb's tds to the qh */ qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv); - BUG_ON (qh == 0); + BUG_ON (qh == NULL); /* ... update usbfs periodic stats */ ehci_to_hcd(ehci)->self.bandwidth_int_reqs++; @@ -638,7 +638,7 @@ struct ehci_iso_stream *stream; stream = kmalloc(sizeof *stream, mem_flags); - if (likely (stream != 0)) { + if (likely (stream != NULL)) { memset (stream, 0, sizeof(*stream)); INIT_LIST_HEAD(&stream->td_list); INIT_LIST_HEAD(&stream->free_list); @@ -791,7 +791,7 @@ static inline struct ehci_iso_stream * iso_stream_get (struct ehci_iso_stream *stream) { - if (likely (stream != 0)) + if (likely (stream != NULL)) stream->refcount++; return stream; } @@ -813,9 +813,9 @@ spin_lock_irqsave (&ehci->lock, flags); stream = ep->hcpriv; - if (unlikely (stream == 0)) { + if (unlikely (stream == NULL)) { stream = iso_stream_alloc(GFP_ATOMIC); - if (likely (stream != 0)) { + if (likely (stream != NULL)) { /* dev->ep owns the initial refcount */ ep->hcpriv = stream; stream->ep = ep; @@ -850,7 +850,7 @@ size += packets * sizeof (struct ehci_iso_packet); iso_sched = kmalloc (size, mem_flags); - if (likely (iso_sched != 0)) { + if (likely (iso_sched != NULL)) { memset(iso_sched, 0, size); INIT_LIST_HEAD (&iso_sched->td_list); } @@ -927,7 +927,7 @@ unsigned long flags; sched = iso_sched_alloc (urb->number_of_packets, mem_flags); - if (unlikely (sched == 0)) + if (unlikely (sched == NULL)) return -ENOMEM; itd_sched_init (sched, stream, urb); @@ -961,7 +961,7 @@ spin_lock_irqsave (&ehci->lock, flags); } - if (unlikely (0 == itd)) { + if (unlikely (NULL == itd)) { iso_sched_free (stream, sched); spin_unlock_irqrestore (&ehci->lock, flags); return -ENOMEM; @@ -1416,7 +1416,7 @@ /* Get iso_stream head */ stream = iso_stream_find (ehci, urb); - if (unlikely (stream == 0)) { + if (unlikely (stream == NULL)) { ehci_dbg (ehci, "can't get iso stream\n"); return -ENOMEM; } @@ -1530,7 +1530,7 @@ unsigned long flags; iso_sched = iso_sched_alloc (urb->number_of_packets, mem_flags); - if (iso_sched == 0) + if (iso_sched == NULL) return -ENOMEM; sitd_sched_init (iso_sched, stream, urb); @@ -1784,7 +1784,7 @@ /* Get iso_stream head */ stream = iso_stream_find (ehci, urb); - if (stream == 0) { + if (stream == NULL) { ehci_dbg (ehci, "can't get iso stream\n"); return -ENOMEM; } @@ -1889,7 +1889,7 @@ type = Q_NEXT_TYPE (*hw_p); modified = 0; - while (q.ptr != 0) { + while (q.ptr != NULL) { unsigned uf; union ehci_shadow temp; int live; diff -Nru a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c --- a/drivers/usb/host/sl811-hcd.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/host/sl811-hcd.c 2005-01-13 17:08:38 -08:00 @@ -1042,7 +1042,7 @@ usb_put_dev(ep->udev); kfree(ep); - hep->hcpriv = 0; + hep->hcpriv = NULL; } static int diff -Nru a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c --- a/drivers/usb/host/uhci-debug.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/host/uhci-debug.c 2005-01-13 17:08:38 -08:00 @@ -95,24 +95,25 @@ struct list_head *head, *tmp; struct uhci_td *td; int i = 0, checked = 0, prevactive = 0; + __le32 element = qh_element(qh); /* Try to make sure there's enough memory */ if (len < 80 * 6) return 0; out += sprintf(out, "%*s[%p] link (%08x) element (%08x)\n", space, "", - qh, le32_to_cpu(qh->link), le32_to_cpu(qh->element)); + qh, le32_to_cpu(qh->link), le32_to_cpu(element)); - if (qh->element & UHCI_PTR_QH) + if (element & UHCI_PTR_QH) out += sprintf(out, "%*s Element points to QH (bug?)\n", space, ""); - if (qh->element & UHCI_PTR_DEPTH) + if (element & UHCI_PTR_DEPTH) out += sprintf(out, "%*s Depth traverse\n", space, ""); - if (qh->element & cpu_to_le32(8)) + if (element & cpu_to_le32(8)) out += sprintf(out, "%*s Bit 3 set (bug?)\n", space, ""); - if (!(qh->element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH))) + if (!(element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH))) out += sprintf(out, "%*s Element is NULL (bug?)\n", space, ""); if (!qh->urbp) { @@ -127,7 +128,7 @@ td = list_entry(tmp, struct uhci_td, list); - if (cpu_to_le32(td->dma_handle) != (qh->element & ~UHCI_PTR_BITS)) + if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS)) out += sprintf(out, "%*s Element != First TD\n", space, ""); while (tmp != head) { @@ -447,7 +448,7 @@ if (qh->link != UHCI_PTR_TERM) out += sprintf(out, " bandwidth reclamation on!\n"); - if (qh->element != cpu_to_le32(uhci->term_td->dma_handle)) + if (qh_element(qh) != cpu_to_le32(uhci->term_td->dma_handle)) out += sprintf(out, " skel_term_qh element is not set to term_td!\n"); continue; diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c --- a/drivers/usb/host/uhci-hcd.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/host/uhci-hcd.c 2005-01-13 17:08:38 -08:00 @@ -236,7 +236,7 @@ { struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; struct uhci_td *td; - u32 *plink; + __le32 *plink; /* Ordering isn't important here yet since the QH hasn't been */ /* inserted into the schedule yet */ @@ -637,8 +637,9 @@ /* * Map status to standard result codes * - * is (td->status & 0xF60000) [a.k.a. uhci_status_bits(td->status)] - * Note: status does not include the TD_CTRL_NAK bit. + * is (td_status(td) & 0xF60000), a.k.a. + * uhci_status_bits(td_status(td)). + * Note: does not include the TD_CTRL_NAK bit. * is True for output TDs and False for input TDs. */ static int uhci_map_status(int status, int dir_out) @@ -843,21 +844,24 @@ /* The rest of the TD's (but the last) are data */ tmp = tmp->next; while (tmp != head && tmp->next != head) { - td = list_entry(tmp, struct uhci_td, list); + unsigned int ctrlstat; + td = list_entry(tmp, struct uhci_td, list); tmp = tmp->next; - status = uhci_status_bits(td_status(td)); + ctrlstat = td_status(td); + status = uhci_status_bits(ctrlstat); if (status & TD_CTRL_ACTIVE) return -EINPROGRESS; - urb->actual_length += uhci_actual_length(td_status(td)); + urb->actual_length += uhci_actual_length(ctrlstat); if (status) goto td_error; /* Check to see if we received a short packet */ - if (uhci_actual_length(td_status(td)) < uhci_expected_length(td_token(td))) { + if (uhci_actual_length(ctrlstat) < + uhci_expected_length(td_token(td))) { if (urb->transfer_flags & URB_SHORT_NOT_OK) { ret = -EREMOTEIO; goto err; @@ -1031,16 +1035,19 @@ urb->actual_length = 0; list_for_each_entry(td, &urbp->td_list, list) { - status = uhci_status_bits(td_status(td)); + unsigned int ctrlstat = td_status(td); + + status = uhci_status_bits(ctrlstat); if (status & TD_CTRL_ACTIVE) return -EINPROGRESS; - urb->actual_length += uhci_actual_length(td_status(td)); + urb->actual_length += uhci_actual_length(ctrlstat); if (status) goto td_error; - if (uhci_actual_length(td_status(td)) < uhci_expected_length(td_token(td))) { + if (uhci_actual_length(ctrlstat) < + uhci_expected_length(td_token(td))) { if (urb->transfer_flags & URB_SHORT_NOT_OK) { ret = -EREMOTEIO; goto err; @@ -1209,15 +1216,16 @@ i = 0; list_for_each_entry(td, &urbp->td_list, list) { int actlength; + unsigned int ctrlstat = td_status(td); - if (td_status(td) & TD_CTRL_ACTIVE) + if (ctrlstat & TD_CTRL_ACTIVE) return -EINPROGRESS; - actlength = uhci_actual_length(td_status(td)); + actlength = uhci_actual_length(ctrlstat); urb->iso_frame_desc[i].actual_length = actlength; urb->actual_length += actlength; - status = uhci_map_status(uhci_status_bits(td_status(td)), + status = uhci_map_status(uhci_status_bits(ctrlstat), usb_pipeout(urb->pipe)); urb->iso_frame_desc[i].status = status; if (status) { @@ -1423,19 +1431,21 @@ */ head = &urbp->td_list; list_for_each_entry(td, head, list) { - if (!(td_status(td) & TD_CTRL_ACTIVE) && - (uhci_actual_length(td_status(td)) < + unsigned int ctrlstat = td_status(td); + + if (!(ctrlstat & TD_CTRL_ACTIVE) && + (uhci_actual_length(ctrlstat) < 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); - else if ((td_status(td) & TD_CTRL_ACTIVE) && !prevactive) + else if ((ctrlstat & TD_CTRL_ACTIVE) && !prevactive) usb_settoggle(urb->dev, uhci_endpoint(td_token(td)), uhci_packetout(td_token(td)), uhci_toggle(td_token(td))); - prevactive = td_status(td) & TD_CTRL_ACTIVE; + prevactive = ctrlstat & TD_CTRL_ACTIVE; } uhci_delete_queued_urb(uhci, urb); diff -Nru a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h --- a/drivers/usb/host/uhci-hcd.h 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/host/uhci-hcd.h 2005-01-13 17:08:38 -08:00 @@ -119,9 +119,19 @@ } __attribute__((aligned(16))); /* + * We need a special accessor for the element pointer because it is + * subject to asynchronous updates by the controller + */ +static __le32 inline qh_element(struct uhci_qh *qh) { + __le32 element = qh->element; + + barrier(); + return element; +} + +/* * for TD : */ -#define td_status(td) le32_to_cpu((td)->status) #define TD_CTRL_SPD (1 << 29) /* Short Packet Detect */ #define TD_CTRL_C_ERR_MASK (3 << 27) /* Error Counter bits */ #define TD_CTRL_C_ERR_SHIFT 27 @@ -202,6 +212,18 @@ int frame; /* for iso: what frame? */ struct list_head fl_list; /* P: uhci->frame_list_lock */ } __attribute__((aligned(16))); + +/* + * We need a special accessor for the control/status word because it is + * subject to asynchronous updates by the controller + */ +static u32 inline td_status(struct uhci_td *td) { + __le32 status = td->status; + + barrier(); + return le32_to_cpu(status); +} + /* * The UHCI driver places Interrupt, Control and Bulk into QH's both diff -Nru a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c --- a/drivers/usb/image/mdc800.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/image/mdc800.c 2005-01-13 17:08:38 -08:00 @@ -456,7 +456,7 @@ dbg ("(mdc800_usb_probe) called."); - if (mdc800->dev != 0) + if (mdc800->dev != NULL) { warn ("only one Mustek MDC800 is supported."); return -ENODEV; @@ -1045,7 +1045,7 @@ cleanup_on_fail: - if (mdc800 != 0) + if (mdc800 != NULL) { err ("can't alloc memory!"); diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c --- a/drivers/usb/input/hid-core.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/input/hid-core.c 2005-01-13 17:08:38 -08:00 @@ -676,7 +676,7 @@ parser->device = device; end = start + size; - while ((start = fetch_item(start, end, &item)) != 0) { + while ((start = fetch_item(start, end, &item)) != NULL) { if (item.format != HID_ITEM_FORMAT_SHORT) { dbg("unexpected long global item"); diff -Nru a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h --- a/drivers/usb/media/sn9c102.h 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/media/sn9c102.h 2005-01-13 17:08:38 -08:00 @@ -1,7 +1,7 @@ /*************************************************************************** * V4L2 driver for SN9C10x PC Camera Controllers * * * - * Copyright (C) 2004 by Luca Risolia * + * Copyright (C) 2004-2005 by Luca Risolia * * * * 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 * @@ -42,6 +42,7 @@ #define SN9C102_DEBUG_LEVEL 2 #define SN9C102_MAX_DEVICES 64 #define SN9C102_PRESERVE_IMGSCALE 0 +#define SN9C102_FORCE_MUNMAP 0 #define SN9C102_MAX_FRAMES 32 #define SN9C102_URBS 2 #define SN9C102_ISO_PACKETS 7 @@ -55,8 +56,8 @@ #define SN9C102_MODULE_AUTHOR "(C) 2004 Luca Risolia" #define SN9C102_AUTHOR_EMAIL "" #define SN9C102_MODULE_LICENSE "GPL" -#define SN9C102_MODULE_VERSION "1:1.20" -#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 20) +#define SN9C102_MODULE_VERSION "1:1.22" +#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 22) enum sn9c102_bridge { BRIDGE_SN9C101 = 0x01, @@ -109,6 +110,10 @@ sn9c102_sof_header_t frame_header; }; +struct sn9c102_module_param { + u8 force_munmap; +}; + static DECLARE_MUTEX(sn9c102_sysfs_lock); static DECLARE_RWSEM(sn9c102_disconnect); @@ -137,6 +142,8 @@ struct sn9c102_sysfs_attr sysfs; sn9c102_sof_header_t sof_header; u16 reg[32]; + + struct sn9c102_module_param module_param; enum sn9c102_dev_state state; u8 users; diff -Nru a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c --- a/drivers/usb/media/sn9c102_core.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/media/sn9c102_core.c 2005-01-13 17:08:38 -08:00 @@ -1,7 +1,7 @@ /*************************************************************************** * V4L2 driver for SN9C10x PC Camera Controllers * * * - * Copyright (C) 2004 by Luca Risolia * + * Copyright (C) 2004-2005 by Luca Risolia * * * * 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 * @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -65,6 +66,20 @@ "\none and for every other camera." "\n"); +static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] = + SN9C102_FORCE_MUNMAP}; +module_param_array(force_munmap, bool, NULL, 0444); +MODULE_PARM_DESC(force_munmap, + "\n<0|1[,...]> Force the application to unmap previously " + "\nmapped buffer memory before calling any VIDIOC_S_CROP or " + "\nVIDIOC_S_FMT ioctl's. Not all the applications support " + "\nthis feature. This parameter is specific for each " + "\ndetected camera." + "\n 0 = do not force memory unmapping" + "\n 1 = force memory unmapping (save memory)" + "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"." + "\n"); + #ifdef SN9C102_DEBUG static unsigned short debug = SN9C102_DEBUG_LEVEL; module_param(debug, ushort, 0644); @@ -141,10 +156,16 @@ } -static u32 sn9c102_request_buffers(struct sn9c102_device* cam, u32 count) +static u32 +sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, + enum sn9c102_io_method io) { struct v4l2_pix_format* p = &(cam->sensor->pix_format); - const size_t imagesize = (p->width * p->height * p->priv)/8; + struct v4l2_rect* r = &(cam->sensor->cropcap.bounds); + const size_t imagesize = cam->module_param.force_munmap || + io == IO_READ ? + (p->width * p->height * p->priv)/8 : + (r->width * r->height * p->priv)/8; void* buff = NULL; u32 i; @@ -911,11 +932,6 @@ return -ENODEV; } - if (!(cam->sensor->sysfs_ops & SN9C102_I2C_WRITE)) { - up(&sn9c102_sysfs_lock); - return -ENOSYS; - } - value = sn9c102_strtou8(buf, len, &count); if (!count) { up(&sn9c102_sysfs_lock); @@ -1047,6 +1063,11 @@ return -ENODEV; } + if (!(cam->sensor->sysfs_ops & SN9C102_I2C_WRITE)) { + up(&sn9c102_sysfs_lock); + return -ENOSYS; + } + value = sn9c102_strtou8(buf, len, &count); if (!count) { up(&sn9c102_sysfs_lock); @@ -1514,7 +1535,7 @@ } if (cam->io == IO_NONE) { - if (!sn9c102_request_buffers(cam, cam->nreadbuffers)) { + if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) { DBG(1, "read() failed, not enough memory") up(&cam->fileop_sem); return -ENOMEM; @@ -1594,7 +1615,7 @@ } if (cam->io == IO_NONE) { - if (!sn9c102_request_buffers(cam, 2)) { + if (!sn9c102_request_buffers(cam, 2, IO_READ)) { DBG(1, "poll() failed, not enough memory") goto error; } @@ -1811,6 +1832,7 @@ return err; } + case VIDIOC_S_CTRL_OLD: case VIDIOC_S_CTRL: { struct sn9c102_sensor* s = cam->sensor; @@ -1895,12 +1917,13 @@ if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_S_CROP failed. " - "Unmap the buffers first.") - return -EINVAL; - } + if (cam->module_param.force_munmap) + for (i = 0; i < cam->nbuffers; i++) + if (cam->frame[i].vma_use_count) { + DBG(3, "VIDIOC_S_CROP failed. " + "Unmap the buffers first.") + return -EINVAL; + } /* Preserve R,G or B origin */ rect->left = (s->_rect.left & 1L) ? @@ -1947,7 +1970,8 @@ return -EFAULT; } - sn9c102_release_buffers(cam); + if (cam->module_param.force_munmap) + sn9c102_release_buffers(cam); err = sn9c102_set_crop(cam, rect); if (s->set_crop) @@ -1966,7 +1990,9 @@ s->pix_format.height = rect->height/scale; memcpy(&(s->_rect), rect, sizeof(*rect)); - if (nbuffers != sn9c102_request_buffers(cam, nbuffers)) { + if (cam->module_param.force_munmap && + nbuffers != sn9c102_request_buffers(cam, nbuffers, + cam->io)) { cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_CROP failed because of not enough " "memory. To use the camera, close and open " @@ -2103,12 +2129,13 @@ return 0; } - for (i = 0; i < cam->nbuffers; i++) - if (cam->frame[i].vma_use_count) { - DBG(3, "VIDIOC_S_FMT failed. " - "Unmap the buffers first.") - return -EINVAL; - } + if (cam->module_param.force_munmap) + for (i = 0; i < cam->nbuffers; i++) + if (cam->frame[i].vma_use_count) { + DBG(3, "VIDIOC_S_FMT failed. " + "Unmap the buffers first.") + return -EINVAL; + } if (cam->stream == STREAM_ON) if ((err = sn9c102_stream_interrupt(cam))) @@ -2119,7 +2146,8 @@ return -EFAULT; } - sn9c102_release_buffers(cam); + if (cam->module_param.force_munmap) + sn9c102_release_buffers(cam); err += sn9c102_set_pix_format(cam, pix); err += sn9c102_set_crop(cam, &rect); @@ -2140,7 +2168,9 @@ memcpy(pfmt, pix, sizeof(*pix)); memcpy(&(s->_rect), &rect, sizeof(rect)); - if (nbuffers != sn9c102_request_buffers(cam, nbuffers)) { + if (cam->module_param.force_munmap && + nbuffers != sn9c102_request_buffers(cam, nbuffers, + cam->io)) { cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_FMT failed because of not enough " "memory. To use the camera, close and open " @@ -2228,7 +2258,8 @@ sn9c102_release_buffers(cam); if (rb.count) - rb.count = sn9c102_request_buffers(cam, rb.count); + rb.count = sn9c102_request_buffers(cam, rb.count, + IO_MMAP); if (copy_to_user(arg, &rb, sizeof(rb))) { sn9c102_release_buffers(cam); @@ -2402,6 +2433,7 @@ return 0; } + case VIDIOC_S_PARM_OLD: case VIDIOC_S_PARM: { struct v4l2_streamparm sp; @@ -2496,8 +2528,10 @@ n = sizeof(sn9c102_id_table)/sizeof(sn9c102_id_table[0]); for (i = 0; i < n-1; i++) - if (le16_to_cpu(udev->descriptor.idVendor) == sn9c102_id_table[i].idVendor && - le16_to_cpu(udev->descriptor.idProduct) == sn9c102_id_table[i].idProduct) + if (le16_to_cpu(udev->descriptor.idVendor) == + sn9c102_id_table[i].idVendor && + le16_to_cpu(udev->descriptor.idProduct) == + sn9c102_id_table[i].idProduct) break; if (i == n-1) return -ENODEV; @@ -2595,6 +2629,10 @@ } DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor) + + cam->module_param.force_munmap = force_munmap[dev_nr]; + + dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; sn9c102_create_sysfs(cam); DBG(2, "Optional device control through 'sysfs' interface ready") diff -Nru a/drivers/usb/media/sn9c102_hv7131d.c b/drivers/usb/media/sn9c102_hv7131d.c --- a/drivers/usb/media/sn9c102_hv7131d.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/media/sn9c102_hv7131d.c 2005-01-13 17:08:38 -08:00 @@ -2,7 +2,7 @@ * Plug-in for HV7131D image sensor connected to the SN9C10x PC Camera * * Controllers * * * - * Copyright (C) 2004 by Luca Risolia * + * Copyright (C) 2004-2005 by Luca Risolia * * * * 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 * diff -Nru a/drivers/usb/media/sn9c102_mi0343.c b/drivers/usb/media/sn9c102_mi0343.c --- a/drivers/usb/media/sn9c102_mi0343.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/media/sn9c102_mi0343.c 2005-01-13 17:08:38 -08:00 @@ -2,7 +2,7 @@ * Plug-in for MI-0343 image sensor connected to the SN9C10x PC Camera * * Controllers * * * - * Copyright (C) 2004 by Luca Risolia * + * Copyright (C) 2004-2005 by Luca Risolia * * * * 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 * diff -Nru a/drivers/usb/media/sn9c102_pas106b.c b/drivers/usb/media/sn9c102_pas106b.c --- a/drivers/usb/media/sn9c102_pas106b.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/media/sn9c102_pas106b.c 2005-01-13 17:08:38 -08:00 @@ -2,7 +2,7 @@ * Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera * * Controllers * * * - * Copyright (C) 2004 by Luca Risolia * + * Copyright (C) 2004-2005 by Luca Risolia * * * * 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 * diff -Nru a/drivers/usb/media/sn9c102_sensor.h b/drivers/usb/media/sn9c102_sensor.h --- a/drivers/usb/media/sn9c102_sensor.h 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/media/sn9c102_sensor.h 2005-01-13 17:08:38 -08:00 @@ -1,7 +1,7 @@ /*************************************************************************** * API for image sensors connected to the SN9C10x PC Camera Controllers * * * - * Copyright (C) 2004 by Luca Risolia * + * Copyright (C) 2004-2005 by Luca Risolia * * * * 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 * diff -Nru a/drivers/usb/media/sn9c102_tas5110c1b.c b/drivers/usb/media/sn9c102_tas5110c1b.c --- a/drivers/usb/media/sn9c102_tas5110c1b.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/media/sn9c102_tas5110c1b.c 2005-01-13 17:08:38 -08:00 @@ -2,7 +2,7 @@ * Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera * * Controllers * * * - * Copyright (C) 2004 by Luca Risolia * + * Copyright (C) 2004-2005 by Luca Risolia * * * * 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 * diff -Nru a/drivers/usb/media/sn9c102_tas5130d1b.c b/drivers/usb/media/sn9c102_tas5130d1b.c --- a/drivers/usb/media/sn9c102_tas5130d1b.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/media/sn9c102_tas5130d1b.c 2005-01-13 17:08:38 -08:00 @@ -2,7 +2,7 @@ * Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera * * Controllers * * * - * Copyright (C) 2004 by Luca Risolia * + * Copyright (C) 2004-2005 by Luca Risolia * * * * 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 * diff -Nru a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig --- a/drivers/usb/misc/Kconfig 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/misc/Kconfig 2005-01-13 17:08:38 -08:00 @@ -123,6 +123,20 @@ To compile this driver as a module, choose M here: the module will be called phidgetservo. +config USB_IDMOUSE + tristate "Siemens ID USB Mouse Fingerprint sensor support" + depends on USB + help + Say Y here if you want to use the fingerprint sensor on + the Siemens ID Mouse. There is also a Siemens ID Mouse + _Professional_, which has not been tested with this driver, + but uses the same sensor and may therefore work. + + This driver creates an entry "/dev/idmouseX" or "/dev/usb/idmouseX", + which can be used by, e.g.,"cat /dev/idmouse0 > fingerprint.pnm". + + See also . + config USB_TEST tristate "USB testing driver (DEVELOPMENT)" depends on USB && USB_DEVICEFS && EXPERIMENTAL diff -Nru a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile --- a/drivers/usb/misc/Makefile 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/misc/Makefile 2005-01-13 17:08:38 -08:00 @@ -7,6 +7,7 @@ obj-$(CONFIG_USB_CYTHERM) += cytherm.o obj-$(CONFIG_USB_EMI26) += emi26.o obj-$(CONFIG_USB_EMI62) += emi62.o +obj-$(CONFIG_USB_IDMOUSE) += idmouse.o obj-$(CONFIG_USB_LCD) += usblcd.o obj-$(CONFIG_USB_LED) += usbled.o obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o diff -Nru a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/usb/misc/idmouse.c 2005-01-13 17:08:38 -08:00 @@ -0,0 +1,442 @@ +/* Siemens ID Mouse driver v0.5 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + Copyright (C) 2004-5 by Florian 'Floe' Echtler + and Andreas 'ad' Deresch + + Derived from the USB Skeleton driver 1.1, + Copyright (C) 2003 Greg Kroah-Hartman (greg@kroah.com) + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WIDTH 225 +#define HEIGHT 288 +#define HEADER "P5 225 288 255 " +#define IMGSIZE ((WIDTH * HEIGHT) + sizeof(HEADER)-1) + +/* Version Information */ +#define DRIVER_VERSION "0.5" +#define DRIVER_SHORT "idmouse" +#define DRIVER_AUTHOR "Florian 'Floe' Echtler " +#define DRIVER_DESC "Siemens ID Mouse FingerTIP Sensor Driver" + +/* Siemens ID Mouse */ +#define USB_IDMOUSE_VENDOR_ID 0x0681 +#define USB_IDMOUSE_PRODUCT_ID 0x0005 + +/* we still need a minor number */ +#define USB_IDMOUSE_MINOR_BASE 132 + +static struct usb_device_id idmouse_table[] = { + {USB_DEVICE(USB_IDMOUSE_VENDOR_ID, USB_IDMOUSE_PRODUCT_ID)}, + {} /* null entry at the end */ +}; + +MODULE_DEVICE_TABLE(usb, idmouse_table); + +/* structure to hold all of our device specific stuff */ +struct usb_idmouse { + + struct usb_device *udev; /* save off the usb device pointer */ + struct usb_interface *interface; /* the interface for this device */ + + unsigned char *bulk_in_buffer; /* the buffer to receive data */ + size_t bulk_in_size; /* the size of the receive buffer */ + __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ + + int open; /* if the port is open or not */ + int present; /* if the device is not disconnected */ + struct semaphore sem; /* locks this structure */ + +}; + +/* local function prototypes */ +static ssize_t idmouse_read(struct file *file, char __user *buffer, + size_t count, loff_t * ppos); + +static int idmouse_open(struct inode *inode, struct file *file); +static int idmouse_release(struct inode *inode, struct file *file); + +static int idmouse_probe(struct usb_interface *interface, + const struct usb_device_id *id); + +static void idmouse_disconnect(struct usb_interface *interface); + +/* file operation pointers */ +static struct file_operations idmouse_fops = { + .owner = THIS_MODULE, + .read = idmouse_read, + .open = idmouse_open, + .release = idmouse_release, +}; + +/* class driver information for devfs */ +static struct usb_class_driver idmouse_class = { + .name = "usb/idmouse%d", + .fops = &idmouse_fops, + .mode = S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, /* filemode (char, 444) */ + .minor_base = USB_IDMOUSE_MINOR_BASE, +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver idmouse_driver = { + .owner = THIS_MODULE, + .name = DRIVER_SHORT, + .probe = idmouse_probe, + .disconnect = idmouse_disconnect, + .id_table = idmouse_table, +}; + +// prevent races between open() and disconnect() +static DECLARE_MUTEX(disconnect_sem); + +static int idmouse_create_image(struct usb_idmouse *dev) +{ + int bytes_read = 0; + int bulk_read = 0; + int result = 0; + + if (dev->bulk_in_size < sizeof(HEADER)) + return -ENOMEM; + + memcpy(dev->bulk_in_buffer,HEADER,sizeof(HEADER)-1); + bytes_read += sizeof(HEADER)-1; + + /* Dump the setup packets. Yes, they are uncommented, simply + because they were sniffed under Windows using SnoopyPro. + I _guess_ that 0x22 is a kind of reset command and 0x21 + means init.. + */ + result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), + 0x21, 0x42, 0x0001, 0x0002, NULL, 0, HZ); + if (result < 0) + return result; + result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), + 0x20, 0x42, 0x0001, 0x0002, NULL, 0, HZ); + if (result < 0) + return result; + result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), + 0x22, 0x42, 0x0000, 0x0002, NULL, 0, HZ); + if (result < 0) + return result; + + result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), + 0x21, 0x42, 0x0001, 0x0002, NULL, 0, HZ); + if (result < 0) + return result; + result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), + 0x20, 0x42, 0x0001, 0x0002, NULL, 0, HZ); + if (result < 0) + return result; + result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), + 0x20, 0x42, 0x0000, 0x0002, NULL, 0, HZ); + if (result < 0) + return result; + + /* loop over a blocking bulk read to get data from the device */ + while (bytes_read < IMGSIZE) { + result = usb_bulk_msg (dev->udev, + usb_rcvbulkpipe (dev->udev, dev->bulk_in_endpointAddr), + dev->bulk_in_buffer + bytes_read, + dev->bulk_in_size, &bulk_read, HZ * 5); + if (result < 0) + return result; + if (signal_pending(current)) + return -EINTR; + bytes_read += bulk_read; + } + + /* reset the device */ + result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), + 0x22, 0x42, 0x0000, 0x0002, NULL, 0, HZ); + if (result < 0) + return result; + + /* should be IMGSIZE == 64815 */ + dbg("read %d bytes fingerprint data", bytes_read); + return 0; +} + +static inline void idmouse_delete(struct usb_idmouse *dev) +{ + kfree(dev->bulk_in_buffer); + kfree(dev); +} + +static int idmouse_open(struct inode *inode, struct file *file) +{ + struct usb_idmouse *dev = NULL; + struct usb_interface *interface; + int result = 0; + + /* prevent disconnects */ + down(&disconnect_sem); + + /* get the interface from minor number and driver information */ + interface = usb_find_interface (&idmouse_driver, iminor (inode)); + if (!interface) { + up(&disconnect_sem); + return -ENODEV; + } + /* get the device information block from the interface */ + dev = usb_get_intfdata(interface); + if (!dev) { + up(&disconnect_sem); + return -ENODEV; + } + + /* lock this device */ + down(&dev->sem); + + /* check if already open */ + if (dev->open) { + + /* already open, so fail */ + result = -EBUSY; + + } else { + + /* create a new image and check for success */ + result = idmouse_create_image (dev); + if (result) + goto error; + + /* increment our usage count for the driver */ + ++dev->open; + + /* save our object in the file's private structure */ + file->private_data = dev; + + } + +error: + + /* unlock this device */ + up(&dev->sem); + + /* unlock the disconnect semaphore */ + up(&disconnect_sem); + return result; +} + +static int idmouse_release(struct inode *inode, struct file *file) +{ + struct usb_idmouse *dev; + + /* prevent a race condition with open() */ + down(&disconnect_sem); + + dev = (struct usb_idmouse *) file->private_data; + + if (dev == NULL) { + up(&disconnect_sem); + return -ENODEV; + } + + /* lock our device */ + down(&dev->sem); + + /* are we really open? */ + if (dev->open <= 0) { + up(&dev->sem); + up(&disconnect_sem); + return -ENODEV; + } + + --dev->open; + + if (!dev->present) { + /* the device was unplugged before the file was released */ + up(&dev->sem); + idmouse_delete(dev); + up(&disconnect_sem); + return 0; + } + + up(&dev->sem); + up(&disconnect_sem); + return 0; +} + +static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count, + loff_t * ppos) +{ + struct usb_idmouse *dev; + int result = 0; + + dev = (struct usb_idmouse *) file->private_data; + + // lock this object + down (&dev->sem); + + // verify that the device wasn't unplugged + if (!dev->present) { + up (&dev->sem); + return -ENODEV; + } + + if (*ppos >= IMGSIZE) { + up (&dev->sem); + return 0; + } + + count = min ((loff_t)count, IMGSIZE - (*ppos)); + + if (copy_to_user (buffer, dev->bulk_in_buffer + *ppos, count)) { + result = -EFAULT; + } else { + result = count; + *ppos += count; + } + + // unlock the device + up(&dev->sem); + return result; +} + +static int idmouse_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(interface); + struct usb_idmouse *dev = NULL; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + size_t buffer_size; + int result; + + /* check if we have gotten the data or the hid interface */ + iface_desc = &interface->altsetting[0]; + if (iface_desc->desc.bInterfaceClass != 0x0A) + return -ENODEV; + + /* allocate memory for our device state and initialize it */ + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) + return -ENOMEM; + memset(dev, 0x00, sizeof(*dev)); + + init_MUTEX(&dev->sem); + dev->udev = udev; + dev->interface = interface; + + /* set up the endpoint information - use only the first bulk-in endpoint */ + endpoint = &iface_desc->endpoint[0].desc; + if (!dev->bulk_in_endpointAddr + && (endpoint->bEndpointAddress & USB_DIR_IN) + && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_BULK)) { + + /* we found a bulk in endpoint */ + buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + dev->bulk_in_size = buffer_size; + dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; + dev->bulk_in_buffer = + kmalloc(IMGSIZE + buffer_size, GFP_KERNEL); + + if (!dev->bulk_in_buffer) { + err("Unable to allocate input buffer."); + idmouse_delete(dev); + return -ENOMEM; + } + } + + if (!(dev->bulk_in_endpointAddr)) { + err("Unable to find bulk-in endpoint."); + idmouse_delete(dev); + return -ENODEV; + } + /* allow device read, write and ioctl */ + dev->present = 1; + + /* we can register the device now, as it is ready */ + usb_set_intfdata(interface, dev); + result = usb_register_dev(interface, &idmouse_class); + if (result) { + /* something prevented us from registering this device */ + err("Unble to allocate minor number."); + usb_set_intfdata(interface, NULL); + idmouse_delete(dev); + return result; + } + + /* be noisy */ + dev_info(&interface->dev,"%s now attached\n",DRIVER_DESC); + + return 0; +} + +static void idmouse_disconnect(struct usb_interface *interface) +{ + struct usb_idmouse *dev; + + /* prevent races with open() */ + down(&disconnect_sem); + + /* get device structure */ + dev = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + + /* lock it */ + down(&dev->sem); + + /* give back our minor */ + usb_deregister_dev(interface, &idmouse_class); + + /* prevent device read, write and ioctl */ + dev->present = 0; + + /* unlock */ + up(&dev->sem); + + /* if the device is opened, idmouse_release will clean this up */ + if (!dev->open) + idmouse_delete(dev); + + up(&disconnect_sem); + + info("%s disconnected", DRIVER_DESC); +} + +static int __init usb_idmouse_init(void) +{ + int result; + + info(DRIVER_DESC " " DRIVER_VERSION); + + /* register this driver with the USB subsystem */ + result = usb_register(&idmouse_driver); + if (result) + err("Unable to register device (error %d).", result); + + return result; +} + +static void __exit usb_idmouse_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&idmouse_driver); +} + +module_init(usb_idmouse_init); +module_exit(usb_idmouse_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + diff -Nru a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c --- a/drivers/usb/misc/usbtest.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/misc/usbtest.c 2005-01-13 17:08:38 -08:00 @@ -1204,7 +1204,7 @@ struct urb *urb; urb = simple_alloc_urb (testdev_to_usbdev (dev), 0, 512); - if (urb == 0) + if (urb == NULL) return -ENOMEM; if (dev->in_pipe) { @@ -1862,7 +1862,7 @@ dev->intf = intf; /* cacheline-aligned scratch for i/o */ - if ((dev->buf = kmalloc (TBUF_SIZE, SLAB_KERNEL)) == 0) { + if ((dev->buf = kmalloc (TBUF_SIZE, SLAB_KERNEL)) == NULL) { kfree (dev); return -ENOMEM; } diff -Nru a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c --- a/drivers/usb/net/pegasus.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/net/pegasus.c 2005-01-13 17:08:38 -08:00 @@ -28,6 +28,8 @@ * is out of the interrupt routine. */ +#undef DEBUG + #include #include #include @@ -45,7 +47,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.5.12 (2003/06/06)" +#define DRIVER_VERSION "v0.5.12 (2005/01/13)" #define DRIVER_AUTHOR "Petko Manolov " #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver" @@ -712,11 +714,11 @@ { pegasus_t *pegasus = urb->context; struct net_device *net; - __u8 *d; int status; if (!pegasus) return; + net = pegasus->net; switch (urb->status) { case 0: @@ -726,36 +728,50 @@ case -ESHUTDOWN: return; default: - info("intr status %d", urb->status); + /* some Pegasus-I products report LOTS of data + * toggle errors... avoid log spamming + */ + pr_debug("%s: intr status %d\n", net->name, urb->status); } - d = urb->transfer_buffer; - net = pegasus->net; - if (d[0] & 0xfc) { - pegasus->stats.tx_errors++; - if (d[0] & TX_UNDERRUN) - pegasus->stats.tx_fifo_errors++; - if (d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT)) - pegasus->stats.tx_aborted_errors++; - if (d[0] & LATE_COL) - pegasus->stats.tx_window_errors++; - if (d[5] & LINK_STATUS) { - netif_carrier_on(net); - } else { - pegasus->stats.tx_carrier_errors++; - netif_carrier_off(net); + if (urb->actual_length >= 6) { + u8 * d = urb->transfer_buffer; + + /* byte 0 == tx_status1, reg 2B */ + if (d[0] & (TX_UNDERRUN|EXCESSIVE_COL + |LATE_COL|JABBER_TIMEOUT)) { + pegasus->stats.tx_errors++; + if (d[0] & TX_UNDERRUN) + pegasus->stats.tx_fifo_errors++; + if (d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT)) + pegasus->stats.tx_aborted_errors++; + if (d[0] & LATE_COL) + pegasus->stats.tx_window_errors++; } + + /* d[5].LINK_STATUS lies on some adapters. + * d[0].NO_CARRIER kicks in only with failed TX. + * ... so monitoring with MII may be safest. + */ + if (d[0] & NO_CARRIER) + netif_carrier_off(net); + else + netif_carrier_on(net); + + /* bytes 3-4 == rx_lostpkt, reg 2E/2F */ + pegasus->stats.rx_missed_errors += ((d[3] & 0x7f) << 8) | d[4]; } status = usb_submit_urb(urb, SLAB_ATOMIC); if (status) - err("%s: can't resubmit interrupt urb, %d", net->name, status); + printk(KERN_ERR "%s: can't resubmit interrupt urb, %d\n", + net->name, status); } static void pegasus_tx_timeout(struct net_device *net) { pegasus_t *pegasus = netdev_priv(net); - warn("%s: Tx timed out.", net->name); + printk(KERN_WARNING "%s: tx timeout\n", net->name); pegasus->tx_urb->transfer_flags |= URB_ASYNC_UNLINK; usb_unlink_urb(pegasus->tx_urb); pegasus->stats.tx_errors++; @@ -948,14 +964,57 @@ usb_make_path(pegasus->usb, info->bus_info, sizeof (info->bus_info)); } -#ifdef CONFIG_MII -static int pegasus_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) +/* also handles three patterns of some kind in hardware */ +#define WOL_SUPPORTED (WAKE_MAGIC|WAKE_PHY) + +static void +pegasus_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + pegasus_t *pegasus = netdev_priv(dev); + + wol->supported = WAKE_MAGIC | WAKE_PHY; + wol->wolopts = pegasus->wolopts; +} + +static int +pegasus_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + pegasus_t *pegasus = netdev_priv(dev); + u8 reg78 = 0x04; + + if (wol->wolopts & ~WOL_SUPPORTED) + return -EINVAL; + + if (wol->wolopts & WAKE_MAGIC) + reg78 |= 0x80; + if (wol->wolopts & WAKE_PHY) + reg78 |= 0x40; + if (wol->wolopts) + pegasus->eth_regs[0] |= 0x10; + else + pegasus->eth_regs[0] &= ~0x10; + pegasus->wolopts = wol->wolopts; + return set_register(pegasus, WakeupControl, reg78); +} + +static inline void +pegasus_reset_wol(struct net_device *dev) +{ + struct ethtool_wolinfo wol; + + memset(&wol, 0, sizeof wol); + (void) pegasus_set_wol(dev, &wol); +} + +static int +pegasus_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { pegasus_t *pegasus = netdev_priv(dev); mii_ethtool_gset(&pegasus->mii, ecmd); return 0; } -static int pegasus_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) +static int +pegasus_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { pegasus_t *pegasus = netdev_priv(dev); return mii_ethtool_sset(&pegasus->mii, ecmd); @@ -975,19 +1034,14 @@ static u32 pegasus_get_msglevel(struct net_device *dev) { - /* - * pegasus_t *pegasus = netdev_priv(dev); - * return pegasus->msg_enable; FIXME - */ - return 0; + pegasus_t *pegasus = netdev_priv(dev); + return pegasus->msg_level; } static void pegasus_set_msglevel(struct net_device *dev, u32 v) { - /* - * pegasus_t *pegasus = netdev_priv(dev); - * pegasus->msg_enable = edata.data; FIXME - */ + pegasus_t *pegasus = netdev_priv(dev); + pegasus->msg_level = v; } static struct ethtool_ops ops = { @@ -998,58 +1052,10 @@ .get_link = pegasus_get_link, .get_msglevel = pegasus_get_msglevel, .set_msglevel = pegasus_set_msglevel, + .get_wol = pegasus_get_wol, + .set_wol = pegasus_set_wol, }; -#else - -static int pegasus_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) -{ - pegasus_t *pegasus = netdev_priv(dev); - short lpa, bmcr; - u8 port; - - ecmd->supported = (SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_Autoneg | - SUPPORTED_TP | SUPPORTED_MII); - get_registers(pegasus, Reg7b, 1, &port); - if (port == 0) - ecmd->port = PORT_MII; - else - ecmd->port = PORT_TP; - ecmd->transceiver = XCVR_INTERNAL; - ecmd->phy_address = pegasus->phy; - read_mii_word(pegasus, pegasus->phy, MII_BMCR, &bmcr); - read_mii_word(pegasus, pegasus->phy, MII_LPA, &lpa); - if (bmcr & BMCR_ANENABLE) { - ecmd->autoneg = AUTONEG_ENABLE; - ecmd->speed = lpa & (LPA_100HALF | LPA_100FULL) ? - SPEED_100 : SPEED_10; - if (ecmd->speed == SPEED_100) - ecmd->duplex = lpa & LPA_100FULL ? - DUPLEX_FULL : DUPLEX_HALF; - else - ecmd->duplex = lpa & LPA_10FULL ? - DUPLEX_FULL : DUPLEX_HALF; - } else { - ecmd->autoneg = AUTONEG_DISABLE; - ecmd->speed = bmcr & BMCR_SPEED100 ? - SPEED_100 : SPEED_10; - ecmd->duplex = bmcr & BMCR_FULLDPLX ? - DUPLEX_FULL : DUPLEX_HALF; - } - return 0; -} - -static struct ethtool_ops ops = { - .get_drvinfo = pegasus_get_drvinfo, - .get_settings = pegasus_get_settings, - .get_link = ethtool_op_get_link, -}; -#endif - static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd) { __u16 *data = (__u16 *) & rq->ifr_ifru; @@ -1081,12 +1087,12 @@ if (net->flags & IFF_PROMISC) { pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS; - info("%s: Promiscuous mode enabled", net->name); + pr_info("%s: Promiscuous mode enabled.\n", net->name); } else if ((net->mc_count > multicast_filter_limit) || (net->flags & IFF_ALLMULTI)) { pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST; pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; - info("%s set allmulti", net->name); + pr_info("%s: set allmulti\n", net->name); } else { pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST; pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; @@ -1180,7 +1186,6 @@ net->hard_start_xmit = pegasus_start_xmit; net->set_multicast_list = pegasus_set_multicast; net->get_stats = pegasus_netdev_stats; - net->mtu = PEGASUS_MTU; SET_ETHTOOL_OPS(net, &ops); pegasus->mii.dev = net; pegasus->mii.mdio_read = mdio_read; @@ -1192,27 +1197,28 @@ pegasus->features = usb_dev_id[dev_index].private; get_interrupt_interval(pegasus); if (reset_mac(pegasus)) { - err("can't reset MAC"); + dev_err(&intf->dev, "can't reset MAC\n"); res = -EIO; goto out2; } set_ethernet_addr(pegasus); fill_skb_pool(pegasus); if (pegasus->features & PEGASUS_II) { - info("setup Pegasus II specific registers"); + dev_info(&intf->dev, "setup Pegasus II specific registers\n"); setup_pegasus_II(pegasus); } pegasus->phy = mii_phy_probe(pegasus); if (pegasus->phy == 0xff) { - warn("can't locate MII phy, using default"); + dev_warn(&intf->dev, "can't locate MII phy, using default\n"); pegasus->phy = 1; } usb_set_intfdata(intf, pegasus); SET_NETDEV_DEV(net, &intf->dev); + pegasus_reset_wol(net); res = register_netdev(net); if (res) goto out3; - printk("%s: %s\n", net->name, usb_dev_id[dev_index].name); + pr_info("%s: %s\n", net->name, usb_dev_id[dev_index].name); return 0; out3: @@ -1247,16 +1253,34 @@ free_netdev(pegasus->net); } +static int pegasus_suspend (struct usb_interface *intf, u32 state) +{ + struct pegasus *pegasus = usb_get_intfdata(intf); + + netif_device_detach (pegasus->net); + return 0; +} + +static int pegasus_resume (struct usb_interface *intf) +{ + struct pegasus *pegasus = usb_get_intfdata(intf); + + netif_device_attach (pegasus->net); + return 0; +} + static struct usb_driver pegasus_driver = { .name = driver_name, .probe = pegasus_probe, .disconnect = pegasus_disconnect, .id_table = pegasus_ids, + .suspend = pegasus_suspend, + .resume = pegasus_resume, }; static int __init pegasus_init(void) { - info(DRIVER_VERSION ":" DRIVER_DESC); + pr_info("%s: %s, " DRIVER_DESC "\n", driver_name, DRIVER_VERSION); return usb_register(&pegasus_driver); } diff -Nru a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h --- a/drivers/usb/net/pegasus.h 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/net/pegasus.h 2005-01-13 17:08:38 -08:00 @@ -76,6 +76,7 @@ EthTxStat0 = 0x2b, EthTxStat1 = 0x2c, EthRxStat = 0x2d, + WakeupControl = 0x78, Reg7b = 0x7b, Gpio0 = 0x7e, Gpio1 = 0x7f, @@ -90,6 +91,8 @@ struct mii_if_info mii; unsigned flags; unsigned features; + u32 msg_level; + u32 wolopts; int dev_index; int intr_interval; struct tasklet_struct rx_tl; diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c --- a/drivers/usb/net/usbnet.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/net/usbnet.c 2005-01-13 17:08:38 -08:00 @@ -745,7 +745,7 @@ dev->out = usb_sndbulkpipe(dev->udev, 2); // allocate irq urb - if ((data->int_urb = usb_alloc_urb (0, GFP_KERNEL)) == 0) { + if ((data->int_urb = usb_alloc_urb (0, GFP_KERNEL)) == NULL) { dbg ("%s: cannot allocate interrupt URB", dev->net->name); return -ENOMEM; @@ -2265,14 +2265,34 @@ .unbind = cdc_unbind, .tx_fixup = zaurus_tx_fixup, }; +#define ZAURUS_STRONGARM_INFO ((unsigned long)&zaurus_sl5x00_info) + static const struct driver_info zaurus_pxa_info = { .description = "Sharp Zaurus, PXA-2xx based", .flags = FLAG_FRAMING_Z, .check_connect = always_connected, + .bind = generic_cdc_bind, + .unbind = cdc_unbind, .tx_fixup = zaurus_tx_fixup, +}; +#define ZAURUS_PXA_INFO ((unsigned long)&zaurus_pxa_info) - .in = 1, .out = 2, +static const struct driver_info olympus_mxl_info = { + .description = "Olympus R1000", + .flags = FLAG_FRAMING_Z, + .check_connect = always_connected, + .bind = generic_cdc_bind, + .unbind = cdc_unbind, + .tx_fixup = zaurus_tx_fixup, }; +#define OLYMPUS_MXL_INFO ((unsigned long)&olympus_mxl_info) + +#else + +/* blacklist all those devices */ +#define ZAURUS_STRONGARM_INFO 0 +#define ZAURUS_PXA_INFO 0 +#define OLYMPUS_MXL_INFO 0 #endif @@ -2384,7 +2404,7 @@ #endif size = (sizeof (struct ethhdr) + dev->net->mtu); - if ((skb = alloc_skb (size, flags)) == 0) { + if ((skb = alloc_skb (size, flags)) == NULL) { devdbg (dev, "no rx skb"); defer_kevent (dev, EVENT_RX_MEMORY); usb_free_urb (urb); @@ -2741,7 +2761,7 @@ if (test_bit (EVENT_TX_HALT, &dev->flags)) { unlink_urbs (dev, &dev->txq); status = usb_clear_halt (dev->udev, dev->out); - if (status < 0) + if (status < 0 && status != -EPIPE) deverr (dev, "can't clear tx halt, status %d", status); else { @@ -2752,7 +2772,7 @@ if (test_bit (EVENT_RX_HALT, &dev->flags)) { unlink_urbs (dev, &dev->rxq); status = usb_clear_halt (dev->udev, dev->in); - if (status < 0) + if (status < 0 && status != -EPIPE) deverr (dev, "can't clear rx halt, status %d", status); else { @@ -2769,7 +2789,7 @@ urb = usb_alloc_urb (0, GFP_KERNEL); else clear_bit (EVENT_RX_MEMORY, &dev->flags); - if (urb != 0) { + if (urb != NULL) { clear_bit (EVENT_RX_MEMORY, &dev->flags); rx_submit (dev, urb, GFP_KERNEL); tasklet_schedule (&dev->bh); @@ -2996,7 +3016,8 @@ // don't refill the queue all at once for (i = 0; i < 10 && dev->rxq.qlen < qlen; i++) { - if ((urb = usb_alloc_urb (0, GFP_ATOMIC)) != 0) + urb = usb_alloc_urb (0, GFP_ATOMIC); + if (urb != NULL) rx_submit (dev, urb, GFP_ATOMIC); } if (temp != dev->rxq.qlen) @@ -3354,12 +3375,15 @@ }, #endif -#ifdef CONFIG_USB_ZAURUS +#if defined(CONFIG_USB_ZAURUS) || defined(CONFIG_USB_CDCETHER) /* * SA-1100 based Sharp Zaurus ("collie"), or compatible. * Same idea as above, but different framing. * * PXA-2xx based models are also lying-about-cdc. + * + * NOTE: These entries do double-duty, serving as blacklist entries + * whenever Zaurus support isn't enabled, but CDC Ethernet is. */ { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO @@ -3370,82 +3394,79 @@ .bInterfaceClass = USB_CLASS_COMM, .bInterfaceSubClass = 6 /* Ethernet model */, .bInterfaceProtocol = 0, - .driver_info = (unsigned long) &zaurus_sl5x00_info, + .driver_info = ZAURUS_STRONGARM_INFO, }, { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x04DD, .idProduct = 0x8005, /* A-300 */ - .bInterfaceClass = 0x02, - .bInterfaceSubClass = 0x0a, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = 6 /* Ethernet model */, .bInterfaceProtocol = 0x00, - .driver_info = (unsigned long) &zaurus_pxa_info, + .driver_info = ZAURUS_PXA_INFO, }, { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x04DD, .idProduct = 0x8006, /* B-500/SL-5600 */ - .bInterfaceClass = 0x02, - .bInterfaceSubClass = 0x0a, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = 6 /* Ethernet model */, .bInterfaceProtocol = 0x00, - .driver_info = (unsigned long) &zaurus_pxa_info, + .driver_info = ZAURUS_PXA_INFO, }, { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x04DD, .idProduct = 0x8007, /* C-700 */ - .bInterfaceClass = 0x02, - .bInterfaceSubClass = 0x0a, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = 6 /* Ethernet model */, .bInterfaceProtocol = 0x00, - .driver_info = (unsigned long) &zaurus_pxa_info, + .driver_info = ZAURUS_PXA_INFO, }, { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x04DD, .idProduct = 0x9031, /* C-750 C-760 */ - .bInterfaceClass = 0x02, - .bInterfaceSubClass = 0x0a, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = 6 /* Ethernet model */, .bInterfaceProtocol = 0x00, - .driver_info = (unsigned long) &zaurus_pxa_info, + .driver_info = ZAURUS_PXA_INFO, }, { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x04DD, .idProduct = 0x9032, /* SL-6000 */ - .bInterfaceClass = 0x02, - .bInterfaceSubClass = 0x0a, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = 6 /* Ethernet model */, .bInterfaceProtocol = 0x00, - .driver_info = (unsigned long) &zaurus_pxa_info, + .driver_info = ZAURUS_PXA_INFO, }, { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x04DD, .idProduct = 0x9050, /* C-860 */ - .bInterfaceClass = 0x02, - .bInterfaceSubClass = 0x0a, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = 6 /* Ethernet model */, .bInterfaceProtocol = 0x00, - .driver_info = (unsigned long) &zaurus_pxa_info, + .driver_info = ZAURUS_PXA_INFO, }, -#endif -#ifdef CONFIG_USB_CDCETHER - -#ifndef CONFIG_USB_ZAURUS - /* if we couldn't whitelist Zaurus, we must blacklist it */ +/* Olympus has some models with a Zaurus-compatible option. + * R-1000 uses a FreeScale i.MXL cpu (ARMv4T) + */ { - .match_flags = USB_DEVICE_ID_MATCH_INT_INFO - | USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = 0x04DD, - .idProduct = 0x8004, - /* match the master interface */ + .match_flags = USB_DEVICE_ID_MATCH_INT_INFO + | USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x07B4, + .idProduct = 0x0F02, /* R-1000 */ .bInterfaceClass = USB_CLASS_COMM, .bInterfaceSubClass = 6 /* Ethernet model */, - .bInterfaceProtocol = 0, - .driver_info = 0, /* BLACKLIST */ + .bInterfaceProtocol = 0x00, + .driver_info = OLYMPUS_MXL_INFO, }, - // FIXME blacklist the other Zaurus models too, sigh #endif +#ifdef CONFIG_USB_CDCETHER { /* CDC Ether uses two interfaces, not necessarily consecutive. * We match the main interface, ignoring the optional device diff -Nru a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c --- a/drivers/usb/serial/cypress_m8.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/serial/cypress_m8.c 2005-01-13 17:08:38 -08:00 @@ -18,6 +18,12 @@ * * * Lonnie Mendez + * 12-15-2004 + * Incorporated write buffering from pl2303 driver. Fixed bug with line + * handling so both lines are raised in cypress_open. (was dropping rts) + * Various code cleanups made as well along with other misc bug fixes. + * + * Lonnie Mendez * 04-10-2004 * Driver modified to support dynamic line settings. Various improvments * and features. @@ -30,9 +36,11 @@ * Long Term TODO: * Improve transfer speeds - both read/write are somewhat slow * at this point. + * Improve debugging. Show modem line status with debug output and + * implement filtering for certain data as a module parameter. */ -/* Neil Whelchel wrote the cypress m8 implementation */ +/* Thanks to Neil Whelchel for writing the first cypress m8 implementation for linux. */ /* Thanks to cypress for providing references for the hid reports. */ /* Thanks to Jiang Zhang for providing links and for general help. */ /* Code originates and was built up from ftdi_sio, belkin, pl2303 and others. */ @@ -53,24 +61,28 @@ #include #include +#include "usb-serial.h" +#include "cypress_m8.h" + + #ifdef CONFIG_USB_SERIAL_DEBUG static int debug = 1; #else static int debug; #endif - static int stats; -#include "usb-serial.h" -#include "cypress_m8.h" - /* * Version Information */ -#define DRIVER_VERSION "v1.06" +#define DRIVER_VERSION "v1.08" #define DRIVER_AUTHOR "Lonnie Mendez , Neil Whelchel " #define DRIVER_DESC "Cypress USB to Serial Driver" +/* write buffer size defines */ +#define CYPRESS_BUF_SIZE 1024 +#define CYPRESS_CLOSING_WAIT (30*HZ) + static struct usb_device_id id_table_earthmate [] = { { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) }, { } /* Terminating entry */ @@ -103,6 +115,8 @@ int bytes_out; /* used for statistics */ int cmd_count; /* used for statistics */ int cmd_ctrl; /* always set this to 1 before issuing a command */ + struct cypress_buf *buf; /* write buffer */ + int write_urb_in_use; /* write urb in use indicator */ int termios_initialized; __u8 line_control; /* holds dtr / rts value */ __u8 current_status; /* received from last read - info on dsr,cts,cd,ri,etc */ @@ -115,8 +129,15 @@ char prev_status, diff_status; /* used for TIOCMIWAIT */ /* we pass a pointer to this as the arguement sent to cypress_set_termios old_termios */ struct termios tmp_termios; /* stores the old termios settings */ - int write_interval; /* interrupt out write interval, as obtained from interrupt_out_urb */ - int writepipe; /* used for clear halt, if necessary */ + char calledfromopen; /* used when issuing lines on open - fixes rts drop bug */ +}; + +/* write buffer structure */ +struct cypress_buf { + unsigned int buf_size; + char *buf_buf; + char *buf_get; + char *buf_put; }; /* function prototypes for the Cypress USB to serial device */ @@ -126,6 +147,7 @@ static int cypress_open (struct usb_serial_port *port, struct file *filp); static void cypress_close (struct usb_serial_port *port, struct file *filp); static int cypress_write (struct usb_serial_port *port, const unsigned char *buf, int count); +static void cypress_send (struct usb_serial_port *port); static int cypress_write_room (struct usb_serial_port *port); static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); static void cypress_set_termios (struct usb_serial_port *port, struct termios * old); @@ -136,8 +158,20 @@ static void cypress_unthrottle (struct usb_serial_port *port); static void cypress_read_int_callback (struct urb *urb, struct pt_regs *regs); static void cypress_write_int_callback (struct urb *urb, struct pt_regs *regs); -static int mask_to_rate (unsigned mask); -static unsigned rate_to_mask (int rate); +/* baud helper functions */ +static int mask_to_rate (unsigned mask); +static unsigned rate_to_mask (int rate); +/* write buffer functions */ +static struct cypress_buf *cypress_buf_alloc(unsigned int size); +static void cypress_buf_free(struct cypress_buf *cb); +static void cypress_buf_clear(struct cypress_buf *cb); +static unsigned int cypress_buf_data_avail(struct cypress_buf *cb); +static unsigned int cypress_buf_space_avail(struct cypress_buf *cb); +static unsigned int cypress_buf_put(struct cypress_buf *cb, const char *buf, + unsigned int count); +static unsigned int cypress_buf_get(struct cypress_buf *cb, char *buf, + unsigned int count); + static struct usb_serial_device_type cypress_earthmate_device = { .owner = THIS_MODULE, @@ -394,25 +428,19 @@ memset(priv, 0x00, sizeof (struct cypress_private)); spin_lock_init(&priv->lock); + priv->buf = cypress_buf_alloc(CYPRESS_BUF_SIZE); + if (priv->buf == NULL) { + kfree(priv); + return -ENOMEM; + } init_waitqueue_head(&priv->delta_msr_wait); - priv->writepipe = serial->port[0]->interrupt_out_urb->pipe; - /* free up interrupt_out buffer / urb allocated by usbserial - * for this port as we use our own urbs for writing */ - if (serial->port[0]->interrupt_out_buffer) { - kfree(serial->port[0]->interrupt_out_buffer); - serial->port[0]->interrupt_out_buffer = NULL; - } - if (serial->port[0]->interrupt_out_urb) { - priv->write_interval = serial->port[0]->interrupt_out_urb->interval; - usb_free_urb(serial->port[0]->interrupt_out_urb); - serial->port[0]->interrupt_out_urb = NULL; - } else /* still need a write interval */ - priv->write_interval = 10; - + usb_reset_configuration (serial->dev); + priv->cmd_ctrl = 0; priv->line_control = 0; priv->termios_initialized = 0; + priv->calledfromopen = 0; priv->rx_flags = 0; usb_set_serial_port_data(serial->port[0], priv); @@ -467,6 +495,7 @@ priv = usb_get_serial_port_data(serial->port[0]); if (priv) { + cypress_buf_free(priv->buf); kfree(priv); usb_set_serial_port_data(serial->port[0], NULL); } @@ -482,37 +511,39 @@ dbg("%s - port %d", __FUNCTION__, port->number); + /* clear halts before open */ + usb_clear_halt(serial->dev, 0x00); + usb_clear_halt(serial->dev, 0x81); + usb_clear_halt(serial->dev, 0x02); + spin_lock_irqsave(&priv->lock, flags); /* reset read/write statistics */ priv->bytes_in = 0; priv->bytes_out = 0; priv->cmd_count = 0; - - /* turn on dtr / rts since we are not flow controlling by default */ - priv->line_control = CONTROL_DTR | CONTROL_RTS; /* sent in status byte */ + priv->rx_flags = 0; spin_unlock_irqrestore(&priv->lock, flags); - priv->cmd_ctrl = 1; - result = cypress_write(port, NULL, 0); - + + /* setting to zero could cause data loss */ port->tty->low_latency = 1; - /* termios defaults are set by usb_serial_init */ - - cypress_set_termios(port, &priv->tmp_termios); + /* raise both lines and set termios */ + spin_lock_irqsave(&priv->lock, flags); + priv->line_control = CONTROL_DTR | CONTROL_RTS; + priv->calledfromopen = 1; + priv->cmd_ctrl = 1; + spin_unlock_irqrestore(&priv->lock, flags); + result = cypress_write(port, NULL, 0); if (result) { dev_err(&port->dev, "%s - failed setting the control lines - error %d\n", __FUNCTION__, result); return result; } else - dbg("%s - success setting the control lines", __FUNCTION__); + dbg("%s - success setting the control lines", __FUNCTION__); - /* throttling off */ - spin_lock_irqsave(&priv->lock, flags); - priv->rx_flags = 0; - spin_unlock_irqrestore(&priv->lock, flags); + cypress_set_termios(port, &priv->tmp_termios); - /* setup the port and - * start reading from the device */ + /* setup the port and start reading from the device */ if(!port->interrupt_in_urb){ err("%s - interrupt_in_urb is empty!", __FUNCTION__); return(-1); @@ -537,9 +568,46 @@ struct cypress_private *priv = usb_get_serial_port_data(port); unsigned int c_cflag; unsigned long flags; + int bps; + long timeout; + wait_queue_t wait; dbg("%s - port %d", __FUNCTION__, port->number); + /* wait for data to drain from buffer */ + spin_lock_irqsave(&priv->lock, flags); + timeout = CYPRESS_CLOSING_WAIT; + init_waitqueue_entry(&wait, current); + add_wait_queue(&port->tty->write_wait, &wait); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + if (cypress_buf_data_avail(priv->buf) == 0 + || timeout == 0 || signal_pending(current) + || !usb_get_intfdata(port->serial->interface)) + 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 */ + cypress_buf_clear(priv->buf); + spin_unlock_irqrestore(&priv->lock, flags); + + /* wait for characters to drain from device */ + 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); + + dbg("%s - stopping urbs", __FUNCTION__); + usb_kill_urb (port->interrupt_in_urb); + usb_kill_urb (port->interrupt_out_urb); + if (port->tty) { c_cflag = port->tty->termios->c_cflag; if (c_cflag & HUPCL) { @@ -553,11 +621,6 @@ } } - if (port->interrupt_in_urb) { - dbg("%s - stopping read urb", __FUNCTION__); - usb_kill_urb (port->interrupt_in_urb); - } - if (stats) dev_info (&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n", priv->bytes_in, priv->bytes_out, priv->cmd_count); @@ -568,116 +631,145 @@ { struct cypress_private *priv = usb_get_serial_port_data(port); unsigned long flags; - struct urb *urb; - int status, s_pos = 0; - __u8 transfer_size = 0; - __u8 *buffer; - - dbg("%s - port %d", __FUNCTION__, port->number); + + dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count); - spin_lock_irqsave(&priv->lock, flags); - if (count == 0 && !priv->cmd_ctrl) { - spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - write request of 0 bytes", __FUNCTION__); - return 0; + /* line control commands, which need to be executed immediately, + are not put into the buffer for obvious reasons. + */ + if (priv->cmd_ctrl) { + count = 0; + goto finish; } - - if (priv->cmd_ctrl) - ++priv->cmd_count; - priv->cmd_ctrl = 0; + + if (!count) + return count; + + spin_lock_irqsave(&priv->lock, flags); + count = cypress_buf_put(priv->buf, buf, count); spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - interrupt out size is %d", __FUNCTION__, port->interrupt_out_size); - dbg("%s - count is %d", __FUNCTION__, count); +finish: + cypress_send(port); - /* Allocate buffer and urb */ - buffer = kmalloc (port->interrupt_out_size, GFP_ATOMIC); - if (!buffer) { - dev_err(&port->dev, "ran out of memory for buffer\n"); - return -ENOMEM; - } + return count; +} /* cypress_write */ - urb = usb_alloc_urb (0, GFP_ATOMIC); - if (!urb) { - dev_err(&port->dev, "failed allocating write urb\n"); - kfree (buffer); - return -ENOMEM; + +static void cypress_send(struct usb_serial_port *port) +{ + int count = 0, result, offset, actual_size; + struct cypress_private *priv = usb_get_serial_port_data(port); + unsigned long flags; + + dbg("%s - port %d", __FUNCTION__, port->number); + dbg("%s - interrupt out size is %d", __FUNCTION__, port->interrupt_out_size); + + spin_lock_irqsave(&priv->lock, flags); + if (priv->write_urb_in_use) { + dbg("%s - can't write, urb in use", __FUNCTION__); + spin_unlock_irqrestore(&priv->lock, flags); + return; } + spin_unlock_irqrestore(&priv->lock, flags); - memset(buffer, 0, port->interrupt_out_size); // test if this is needed... probably not since loop removed + /* clear buffer */ + memset(port->interrupt_out_urb->transfer_buffer, 0, port->interrupt_out_size); spin_lock_irqsave(&priv->lock, flags); switch (port->interrupt_out_size) { case 32: // this is for the CY7C64013... - transfer_size = min (count, 30); - buffer[0] = priv->line_control; - buffer[1] = transfer_size; - s_pos = 2; + offset = 2; + port->interrupt_out_buffer[0] = priv->line_control; break; case 8: // this is for the CY7C63743... - transfer_size = min (count, 7); - buffer[0] = priv->line_control | transfer_size; - s_pos = 1; + offset = 1; + port->interrupt_out_buffer[0] = priv->line_control; break; default: dbg("%s - wrong packet size", __FUNCTION__); spin_unlock_irqrestore(&priv->lock, flags); - kfree (buffer); - usb_free_urb (urb); - return -1; + return; } if (priv->line_control & CONTROL_RESET) priv->line_control &= ~CONTROL_RESET; - spin_unlock_irqrestore(&priv->lock, flags); - - /* copy data to offset position in urb transfer buffer */ - memcpy (&buffer[s_pos], buf, transfer_size); - usb_serial_debug_data (debug, &port->dev, __FUNCTION__, port->interrupt_out_size, buffer); + if (priv->cmd_ctrl) { + priv->cmd_count++; + dbg("%s - line control command being issued", __FUNCTION__); + spin_unlock_irqrestore(&priv->lock, flags); + goto send; + } else + spin_unlock_irqrestore(&priv->lock, flags); - /* build up the urb */ - usb_fill_int_urb (urb, port->serial->dev, - usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress), - buffer, port->interrupt_out_size, - cypress_write_int_callback, port, priv->write_interval); + count = cypress_buf_get(priv->buf, &port->interrupt_out_buffer[offset], + port->interrupt_out_size-offset); - status = usb_submit_urb(urb, GFP_ATOMIC); + if (count == 0) { + return; + } - if (status) { - dev_err(&port->dev, "%s - usb_submit_urb (write interrupt) failed with status %d\n", - __FUNCTION__, status); - transfer_size = status; - kfree (buffer); - goto exit; + switch (port->interrupt_out_size) { + case 32: + port->interrupt_out_buffer[1] = count; + break; + case 8: + port->interrupt_out_buffer[0] |= count; } + dbg("%s - count is %d", __FUNCTION__, count); + +send: spin_lock_irqsave(&priv->lock, flags); - priv->bytes_out += transfer_size; + priv->write_urb_in_use = 1; spin_unlock_irqrestore(&priv->lock, flags); -exit: - /* buffer free'd in callback */ - usb_free_urb (urb); + if (priv->cmd_ctrl) + actual_size = 1; + else + actual_size = count + (port->interrupt_out_size == 32 ? 2 : 1); + + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, port->interrupt_out_size, + port->interrupt_out_urb->transfer_buffer); - return transfer_size; + port->interrupt_out_urb->transfer_buffer_length = actual_size; + port->interrupt_out_urb->dev = port->serial->dev; + result = usb_submit_urb (port->interrupt_out_urb, GFP_ATOMIC); + if (result) { + dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, + result); + priv->write_urb_in_use = 0; + } -} /* cypress_write */ + spin_lock_irqsave(&priv->lock, flags); + if (priv->cmd_ctrl) { + priv->cmd_ctrl = 0; + } + priv->bytes_out += count; /* do not count the line control and size bytes */ + spin_unlock_irqrestore(&priv->lock, flags); + schedule_work(&port->work); +} /* cypress_send */ + +/* returns how much space is available in the soft buffer */ static int cypress_write_room(struct usb_serial_port *port) { + struct cypress_private *priv = usb_get_serial_port_data(port); + int room = 0; + unsigned long flags; + dbg("%s - port %d", __FUNCTION__, port->number); - /* - * We really can take anything the user throw at us - * but let's pick a nice big number to tell the tty - * layer that we have lots of free space - */ + spin_lock_irqsave(&priv->lock, flags); + room = cypress_buf_space_avail(priv->buf); + spin_unlock_irqrestore(&priv->lock, flags); - return 2048; + dbg("%s - returns %d", __FUNCTION__, room); + return room; } @@ -816,6 +908,8 @@ int data_bits, stop_bits, parity_type, parity_enable; unsigned cflag, iflag, baud_mask; unsigned long flags; + __u8 oldlines; + int linechange; dbg("%s - port %d", __FUNCTION__, port->number); @@ -880,6 +974,7 @@ data_bits = 3; spin_lock_irqsave(&priv->lock, flags); + oldlines = priv->line_control; if ((cflag & CBAUD) == B0) { /* drop dtr and rts */ dbg("%s - dropping the lines, baud rate 0bps", __FUNCTION__); @@ -902,11 +997,13 @@ } priv->line_control |= CONTROL_DTR; - /* this is probably not what I think it is... check into it */ - if (cflag & CRTSCTS) - priv->line_control |= CONTROL_RTS; - else - priv->line_control &= ~CONTROL_RTS; + /* toggle CRTSCTS? - don't do this if being called from cypress_open */ + if (!priv->calledfromopen) { + if (cflag & CRTSCTS) + priv->line_control |= CONTROL_RTS; + else + priv->line_control &= ~CONTROL_RTS; + } } spin_unlock_irqrestore(&priv->lock, flags); @@ -925,7 +1022,7 @@ /* Here we can define custom tty settings for devices * - * the main tty base comes from empeg.c + * the main tty termios flag base comes from empeg.c */ spin_lock_irqsave(&priv->lock, flags); @@ -959,33 +1056,37 @@ // Software app handling it for device... - } else { - - /* do something here */ - } + linechange = (priv->line_control != oldlines); spin_unlock_irqrestore(&priv->lock, flags); - /* set lines */ - priv->cmd_ctrl = 1; - cypress_write(port, NULL, 0); + /* if necessary, set lines */ + if (!priv->calledfromopen && linechange) { + priv->cmd_ctrl = 1; + cypress_write(port, NULL, 0); + } + + if (priv->calledfromopen) + priv->calledfromopen = 0; - return; } /* cypress_set_termios */ - + +/* returns amount of data still left in soft buffer */ static int cypress_chars_in_buffer(struct usb_serial_port *port) { - dbg("%s - port %d", __FUNCTION__, port->number); + struct cypress_private *priv = usb_get_serial_port_data(port); + int chars = 0; + unsigned long flags; - /* - * We can't really account for how much data we - * have sent out, but hasn't made it through to the - * device, so just tell the tty layer that everything - * is flushed. - */ + dbg("%s - port %d", __FUNCTION__, port->number); + + spin_lock_irqsave(&priv->lock, flags); + chars = cypress_buf_data_avail(priv->buf); + spin_unlock_irqrestore(&priv->lock, flags); - return 0; + dbg("%s - returns %d", __FUNCTION__, chars); + return chars; } @@ -1032,10 +1133,11 @@ struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; unsigned long flags; - char tty_flag = TTY_NORMAL; - int bytes=0; + char tty_flag = TTY_NORMAL; + int havedata = 0; + int bytes = 0; int result; - int i=0; + int i = 0; dbg("%s - port %d", __FUNCTION__, port->number); @@ -1046,6 +1148,7 @@ spin_lock_irqsave(&priv->lock, flags); if (priv->rx_flags & THROTTLED) { + dbg("%s - now throttling", __FUNCTION__); priv->rx_flags |= ACTUALLY_THROTTLED; spin_unlock_irqrestore(&priv->lock, flags); return; @@ -1058,8 +1161,6 @@ return; } - usb_serial_debug_data (debug, &port->dev, __FUNCTION__, urb->actual_length, data); - spin_lock_irqsave(&priv->lock, flags); switch(urb->actual_length) { case 32: @@ -1067,12 +1168,16 @@ priv->current_status = data[0] & 0xF8; bytes = data[1]+2; i=2; + if (bytes > 2) + havedata = 1; break; case 8: // This is for the CY7C63743... priv->current_status = data[0] & 0xF8; bytes = (data[0] & 0x07)+1; i=1; + if (bytes > 1) + havedata = 1; break; default: dbg("%s - wrong packet size - received %d bytes", __FUNCTION__, urb->actual_length); @@ -1081,6 +1186,8 @@ } spin_unlock_irqrestore(&priv->lock, flags); + usb_serial_debug_data (debug, &port->dev, __FUNCTION__, urb->actual_length, data); + spin_lock_irqsave(&priv->lock, flags); /* check to see if status has changed */ if (priv != NULL) { @@ -1115,7 +1222,7 @@ /* process read if there is data other than line status */ if (tty && (bytes > i)) { for (; i < bytes ; ++i) { - dbg("pushing byte number %d - %d",i,data[i]); + dbg("pushing byte number %d - %d - %c",i,data[i],data[i]); if(tty->flip.count >= TTY_FLIPBUF_SIZE) { tty_flip_buffer_push(tty); } @@ -1151,21 +1258,229 @@ static void cypress_write_int_callback(struct urb *urb, struct pt_regs *regs) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - - /* free up the transfer buffer, as usb_free_urb() does not do this */ - kfree (urb->transfer_buffer); + struct cypress_private *priv = usb_get_serial_port_data(port); + int result; dbg("%s - port %d", __FUNCTION__, port->number); - if (urb->status) { - dbg("%s - nonzero write status received: %d", __FUNCTION__, urb->status); - return; + 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); + port->interrupt_out_urb->transfer_buffer_length = 1; + port->interrupt_out_urb->dev = port->serial->dev; + result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC); + if (result) + dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n", + __FUNCTION__, result); + else + return; } + + priv->write_urb_in_use = 0; + + /* send any buffered data */ + cypress_send(port); +} + + +/***************************************************************************** + * Write buffer functions - buffering code from pl2303 used + *****************************************************************************/ + +/* + * cypress_buf_alloc + * + * Allocate a circular buffer and all associated memory. + */ + +static struct cypress_buf *cypress_buf_alloc(unsigned int size) +{ + + struct cypress_buf *cb; + + + if (size == 0) + return NULL; + + cb = (struct cypress_buf *)kmalloc(sizeof(struct cypress_buf), GFP_KERNEL); + if (cb == NULL) + return NULL; + + cb->buf_buf = kmalloc(size, GFP_KERNEL); + if (cb->buf_buf == NULL) { + kfree(cb); + return NULL; + } + + cb->buf_size = size; + cb->buf_get = cb->buf_put = cb->buf_buf; + + return cb; - schedule_work(&port->work); } +/* + * cypress_buf_free + * + * Free the buffer and all associated memory. + */ + +static void cypress_buf_free(struct cypress_buf *cb) +{ + if (cb != NULL) { + if (cb->buf_buf != NULL) + kfree(cb->buf_buf); + kfree(cb); + } +} + + +/* + * cypress_buf_clear + * + * Clear out all data in the circular buffer. + */ + +static void cypress_buf_clear(struct cypress_buf *cb) +{ + if (cb != NULL) + cb->buf_get = cb->buf_put; + /* equivalent to a get of all data available */ +} + + +/* + * cypress_buf_data_avail + * + * Return the number of bytes of data available in the circular + * buffer. + */ + +static unsigned int cypress_buf_data_avail(struct cypress_buf *cb) +{ + if (cb != NULL) + return ((cb->buf_size + cb->buf_put - cb->buf_get) % cb->buf_size); + else + return 0; +} + + +/* + * cypress_buf_space_avail + * + * Return the number of bytes of space available in the circular + * buffer. + */ + +static unsigned int cypress_buf_space_avail(struct cypress_buf *cb) +{ + if (cb != NULL) + return ((cb->buf_size + cb->buf_get - cb->buf_put - 1) % cb->buf_size); + else + return 0; +} + + +/* + * cypress_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 cypress_buf_put(struct cypress_buf *cb, const char *buf, + unsigned int count) +{ + + unsigned int len; + + + if (cb == NULL) + return 0; + + len = cypress_buf_space_avail(cb); + if (count > len) + count = len; + + if (count == 0) + return 0; + + len = cb->buf_buf + cb->buf_size - cb->buf_put; + if (count > len) { + memcpy(cb->buf_put, buf, len); + memcpy(cb->buf_buf, buf+len, count - len); + cb->buf_put = cb->buf_buf + count - len; + } else { + memcpy(cb->buf_put, buf, count); + if (count < len) + cb->buf_put += count; + else /* count == len */ + cb->buf_put = cb->buf_buf; + } + + return count; + +} + + +/* + * cypress_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 cypress_buf_get(struct cypress_buf *cb, char *buf, + unsigned int count) +{ + + unsigned int len; + + + if (cb == NULL) + return 0; + + len = cypress_buf_data_avail(cb); + if (count > len) + count = len; + + if (count == 0) + return 0; + + len = cb->buf_buf + cb->buf_size - cb->buf_get; + if (count > len) { + memcpy(buf, cb->buf_get, len); + memcpy(buf+len, cb->buf_buf, count - len); + cb->buf_get = cb->buf_buf + count - len; + } else { + memcpy(buf, cb->buf_get, count); + if (count < len) + cb->buf_get += count; + else /* count == len */ + cb->buf_get = cb->buf_buf; + } + + return count; + +} + /***************************************************************************** * Module functions *****************************************************************************/ @@ -1214,6 +1529,7 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_VERSION( DRIVER_VERSION ); MODULE_LICENSE("GPL"); module_param(debug, bool, S_IRUGO | S_IWUSR); diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c --- a/drivers/usb/serial/ftdi_sio.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/serial/ftdi_sio.c 2005-01-13 17:08:38 -08:00 @@ -372,6 +372,7 @@ { 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) }, + { USB_DEVICE_VER(FTDI_VID, EVER_ECO_PRO_CDS, 0, 0x3ff) }, { } /* Terminating entry */ }; @@ -486,6 +487,7 @@ { 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) }, + { USB_DEVICE_VER(FTDI_VID, EVER_ECO_PRO_CDS, 0x400, 0xffff) }, { } /* Terminating entry */ }; @@ -608,6 +610,7 @@ { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) }, { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) }, { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) }, + { USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) }, { } /* Terminating entry */ }; diff -Nru a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h --- a/drivers/usb/serial/ftdi_sio.h 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/serial/ftdi_sio.h 2005-01-13 17:08:38 -08:00 @@ -240,6 +240,12 @@ #define FTDI_RM_VID 0x0403 /* Vendor Id */ #define FTDI_RMCANVIEW_PID 0xfd60 /* Product Id */ +/* + * EVER Eco Pro UPS (http://www.ever.com.pl/) + */ + +#define EVER_ECO_PRO_CDS 0xe520 /* RS-232 converter */ + /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ diff -Nru a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c --- a/drivers/usb/serial/garmin_gps.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/serial/garmin_gps.c 2005-01-13 17:08:38 -08:00 @@ -316,7 +316,7 @@ garmin_data_p->flags |= FLAGS_QUEUING; pkt = kmalloc(sizeof(struct garmin_packet)+data_length, GFP_ATOMIC); - if (pkt == 0) { + if (pkt == NULL) { dev_err(&garmin_data_p->port->dev, "out of memory\n"); return 0; } @@ -739,7 +739,7 @@ { struct garmin_packet *pkt = NULL; - while ((pkt = pkt_pop(garmin_data_p)) != 0) { + while ((pkt = pkt_pop(garmin_data_p)) != NULL) { dbg("%s - next pkt: %d", __FUNCTION__, pkt->seq); if (gsp_send(garmin_data_p, pkt->data, pkt->size) > 0) { kfree(pkt); @@ -877,7 +877,7 @@ struct usb_serial_port *port = garmin_data_p->port; - if (port != 0 && garmin_data_p->flags & FLAGS_APP_RESP_SEEN) { + if (port != NULL && garmin_data_p->flags & FLAGS_APP_RESP_SEEN) { /* send a terminate command */ status = garmin_write_bulk(port, GARMIN_STOP_TRANSFER_REQ, sizeof(GARMIN_STOP_TRANSFER_REQ)); @@ -1366,7 +1366,7 @@ if ((garmin_data_p->flags & FLAGS_THROTTLED) == 0) { pkt = pkt_pop(garmin_data_p); - if (pkt != 0) { + if (pkt != NULL) { send_to_tty(garmin_data_p->port, pkt->data, pkt->size); kfree(pkt); diff -Nru a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c --- a/drivers/usb/serial/keyspan.c 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/serial/keyspan.c 2005-01-13 17:08:38 -08:00 @@ -374,7 +374,7 @@ flip = p_priv->out_flip; /* Check we have a valid urb/endpoint before we use it... */ - if ((this_urb = p_priv->out_urbs[flip]) == 0) { + if ((this_urb = p_priv->out_urbs[flip]) == NULL) { /* no bulk out, so return 0 bytes written */ dbg("%s - no output urb :(", __FUNCTION__); return count; @@ -1020,11 +1020,11 @@ flip = p_priv->out_flip; /* Check both endpoints to see if any are available. */ - if ((this_urb = p_priv->out_urbs[flip]) != 0) { + if ((this_urb = p_priv->out_urbs[flip]) != NULL) { if (this_urb->status != -EINPROGRESS) return (data_len); flip = (flip + 1) & d_details->outdat_endp_flip; - if ((this_urb = p_priv->out_urbs[flip]) != 0) + if ((this_urb = p_priv->out_urbs[flip]) != NULL) if (this_urb->status != -EINPROGRESS) return (data_len); } diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h --- a/drivers/usb/storage/unusual_devs.h 2005-01-13 17:08:38 -08:00 +++ b/drivers/usb/storage/unusual_devs.h 2005-01-13 17:08:38 -08:00 @@ -865,6 +865,14 @@ US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY ), +/* Submitted by Daniel Drake + * Reported by dayul on the Gentoo Forums */ +UNUSUAL_DEV( 0x0ea0, 0x2168, 0x0110, 0x0110, + "Ours Technology", + "Flash Disk", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE ), + /* Reported by Rastislav Stanik */ UNUSUAL_DEV( 0x0ea0, 0x6828, 0x0110, 0x0110, "USB",