bk://kernel.bkbits.net/gregkh/linux/usb-2.6
tejohnson@yahoo.com|ChangeSet|20040503211833|11011 tejohnson
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
# 2004/05/04 14:13:11-07:00 akpm@bix.(none)
# Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
# into bix.(none):/usr/src/bk-usb
#
# include/linux/usb.h
# 2004/05/04 14:13:08-07:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/05/03 14:18:33-07:00 tejohnson@yahoo.com
# [PATCH] USB: update for mtouchusb
#
# The attached patch for the 3M Touch Systems Capacitive controller. (again)
#
# Quick list of changes:
#
# * decrease mtouch->open counter in the event of a urb submission
# failure
#
# The changes are due to comments Oliver Neukum's comments on the
# touchkit.c driver. Good catch! Sorry I missed it.
#
# http://marc.theaimsgroup.com/?l=linux-usb-devel&m=108343028201159&w=2
#
# drivers/usb/input/mtouchusb.c
# 2004/05/02 09:37:18-07:00 tejohnson@yahoo.com +3 -1
# USB: update for mtouchusb
#
# ChangeSet
# 2004/05/03 14:17:38-07:00 stern@rowland.harvard.edu
# [PATCH] USB: Altsetting update for USB IrDA driver
#
# This patch updates the USB IrDA driver to take into account that the
# kernel may no longer store altsetting entries in numerical order.
# The driver only needed one change; this was a simple matter of using the
# entry corresponding to the altsetting that was just installed.
#
# drivers/net/irda/irda-usb.c
# 2004/05/03 03:37:59-07:00 stern@rowland.harvard.edu +1 -1
# USB: Altsetting update for USB IrDA driver
#
# ChangeSet
# 2004/05/03 14:16:51-07:00 c.lucas@ifrance.com
# [PATCH] USB: esthetic and trivial patch.
#
# include/linux/usb.h
# 2004/05/02 23:42:51-07:00 c.lucas@ifrance.com +1 -1
# USB: esthetic and trivial patch.
#
# ChangeSet
# 2004/05/01 16:24:00-07:00 msdemlei@cl.uni-heidelberg.de
# [PATCH] USB: DSBR-100 tiny patch
#
# On Fri, Feb 06, 2004 at 10:17:32AM -0800, Greg KH wrote:
# > On Fri, Feb 06, 2004 at 05:06:01PM +0100, Markus Demleitner wrote:
# > > Since I finally switched over to 2.6 I noticed that my dsbr100 driver
# > > produces a warning to the effect that I should provide a release
# > > callback. After a quick google on the issue I came to the conclusion
# >
# > No, you will have to fix up your driver to work properly, sorry. It's
# > due to the changes to the v4l layer to handle removable devices much
# > better (and to tie it into the driver model.)
#
# I didn't get around to doing real work on this until now, but finally
# in the attachment there's my stab at bringing dsbr100 up to kernel 2.6.
# I'm not really comfortable with the release callback issues (I've yet
# to find some HOWTO-like documentation on this...) on the v4l side,
# so I'd be grateful if you could have a look at it. I've basically
# tried to copy what stv680 does, which may or may not have been a
# good idea (in particular see the comment above the disconnect
# function).
#
# I've used the opportunity for some code beautyfing, which of course
# makes the patch a bit of a mess. I hope you won't mind too much
# -- as you can see, it would have been pretty messy anyway.
#
# drivers/usb/media/dsbr100.c
# 2004/04/21 12:32:35-07:00 msdemlei@cl.uni-heidelberg.de +133 -94
# USB: DSBR-100 tiny patch
#
# ChangeSet
# 2004/05/01 16:18:03-07:00 david-b@pacbell.net
# [PATCH] USB: dummy_hcd, root port wakeup/suspend
#
# Here's what's in my tree to make dummy_hcd do suspend and
# wakeup correctly ... that is, making its emulated root hub
# and gadget work more like real ones.
#
# It's easier to do this for fake hardware than the real stuff.
# But real drivers tend to need very similar changes ... :)
#
# - Dave
#
# p.s. This does not depend on the suspend/resume patch.
# And it doesn't do "global" suspend (of root hub).
#
# drivers/usb/gadget/dummy_hcd.c
# 2004/04/29 11:16:12-07:00 david-b@pacbell.net +133 -33
# USB: dummy_hcd, root port wakeup/suspend
#
# ChangeSet
# 2004/05/01 16:02:37-07:00 baldrick@free.fr
# [PATCH] USB: fix WARN_ON in usbfs
#
# On Tuesday 27 April 2004 10:58, Oliver Neukum wrote:
# > Am Dienstag, 27. April 2004 00:14 schrieb Greg KH:
# > > On Mon, Apr 26, 2004 at 04:05:17PM +0200, Duncan Sands wrote:
# > > > diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
# > > > --- a/drivers/usb/core/devio.c Mon Apr 26 13:48:28 2004
# > > > +++ b/drivers/usb/core/devio.c Mon Apr 26 13:48:28 2004
# > > > @@ -350,8 +350,8 @@
# > > > * all pending I/O requests; 2.6 does that.
# > > > */
# > > >
# > > > - if (ifnum < 8*sizeof(ps->ifclaimed))
# > > > - clear_bit(ifnum, &ps->ifclaimed);
# > > > + BUG_ON(ifnum >= 8*sizeof(ps->ifclaimed));
# > >
# > > I've changed that to a WARN_ON(). Yeah, writing over memory is bad, but
# > > oopsing is worse. Let's be a bit nicer than that.
# >
# > You aren't nice that way. An oops has localised consequences. Scribbling
# > over memory can cause anything.
#
# Hi Greg, if won't accept a BUG_ON, how about the following?
#
# drivers/usb/core/devio.c
# 2004/04/30 03:01:37-07:00 baldrick@free.fr +5 -2
# USB: fix WARN_ON in usbfs
#
# ChangeSet
# 2004/05/01 16:02:00-07:00 baldrick@free.fr
# [PATCH] USB: usbfs: change extern inline to static inline
#
# And change __inline__ to inline and get rid of an unused function
# while at it.
#
# drivers/usb/core/devio.c
# 2004/04/30 16:36:25-07:00 baldrick@free.fr +5 -30
# USB: usbfs: change extern inline to static inline
#
# ChangeSet
# 2004/05/01 15:23:25-07:00 akpm@bix.(none)
# Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
# into bix.(none):/usr/src/bk-usb
#
# MAINTAINERS
# 2004/05/01 15:23:22-07:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/04/30 22:19:36-07:00 stuber@loria.fr
# [PATCH] USB: LEGO USB Tower driver v0.95
#
# here is the latest version 0.95 of the LEGO USB Tower driver against 2.6.6-rc3
# which corrects a lot of problems in the version currently in the kernel,
# most notably sleeping in interrupt context and improper locking.
# Please apply.
#
# It has been thoroughly tested with UHCI, OHCI and EHCI host controllers
# using Lejos and NQC. Firmware and program download, and with proper
# modifications all communication protocols supported by Lejos work,
# as well as firmware and program download and datalog upload in NQC.
#
# Notes to application maintainers/protocol designers:
#
# - Small modifications are needed in communication protocols because
# the tower tends to discard the first byte of transmissions.
# So for example LNP needs to send an extra byte like 0xff before
# the packet, and F7 handlers needs to cope with a lost 0x55.
#
# - I suggest /dev/usb/legousbtower0 etc. as the standard device names.
# This puts it in the same place as the other USB devices and makes
# clear which driver is responsible for these devices.
#
# drivers/usb/misc/legousbtower.c
# 2004/04/30 12:44:31-07:00 stuber@loria.fr +489 -276
# USB: LEGO USB Tower driver v0.95
#
# MAINTAINERS
# 2004/04/30 08:30:25-07:00 stuber@loria.fr +7 -0
# USB: LEGO USB Tower driver v0.95
#
# ChangeSet
# 2004/04/30 22:19:00-07:00 david-b@pacbell.net
# [PATCH] USB: reject urb submissions to suspended devices
#
# This patch rejects URB submissions to suspended devices, so
# that they don't get hardware-specific fault reports. Instead,
# they get the same code (-EHOSTUNREACH) for all HCDs.
#
# It also fixes a minor problem with colliding declarations of
# the symbol USB_STATE_SUSPENDED.
#
# drivers/usb/core/urb.c
# 2004/04/28 07:00:02-07:00 david-b@pacbell.net +2 -0
# USB: reject urb submissions to suspended devices
#
# drivers/usb/core/hcd.h
# 2004/04/28 07:01:03-07:00 david-b@pacbell.net +1 -1
# USB: reject urb submissions to suspended devices
#
# drivers/usb/core/hcd-pci.c
# 2004/04/28 06:57:24-07:00 david-b@pacbell.net +3 -3
# USB: reject urb submissions to suspended devices
#
# ChangeSet
# 2004/04/30 22:17:59-07:00 david-b@pacbell.net
# [PATCH] USB Gadget: gadget zero and USB suspend/resume
#
# This patch lets gadget zero be more useful in testing usb suspend
# and resume. It prints messages on suspend() and resume(), and
# supports an "autoresume=N" mode to wake the host after N seconds.
#
# drivers/usb/gadget/zero.c
# 2004/04/27 13:26:18-07:00 david-b@pacbell.net +63 -2
# USB Gadget: gadget zero and USB suspend/resume
#
# ChangeSet
# 2004/04/30 22:16:57-07:00 linux-usb@nerds-incorporated.org
# [PATCH] USB: Alcatel TD10 Serial to USB converter cable support
#
# The Alcatel TD10 USB to Serial converter cable (for use with a Alcatel
# OT 535 or 735(i) mobile phone) seems to be a repackaged Alcatel
# version of the Prolific 2303 adapter.
#
# And as such, simply adding its product/vendor id (0x11f7/0x02df) to
# drivers/usb/serial/pl2303.c seems to be enough to make it work.
#
# drivers/usb/serial/pl2303.h
# 2004/04/29 09:35:06-07:00 linux-usb@nerds-incorporated.org +3 -0
# USB: Alcatel TD10 Serial to USB converter cable support
#
# drivers/usb/serial/pl2303.c
# 2004/04/29 09:35:28-07:00 linux-usb@nerds-incorporated.org +1 -0
# USB: Alcatel TD10 Serial to USB converter cable support
#
# ChangeSet
# 2004/04/30 22:15:51-07:00 stern@rowland.harvard.edu
# [PATCH] USB: USB altsetting updates for IDSN Hisax driver
#
# The USB core is changing the way interfaces and altsettings are stored.
# They are no longer required to be in numerical order, and as a result,
# simply indexing the interface and altsetting arrays won't work as
# expected.
#
# This patch for the st5481 takes these changes into account. A simpler
# approach would be to store a pointer to the struct usb_host_interface
# rather than look it up repeatedly, but I'm not very familiar with this
# driver and didn't want to attempt such an alteration.
#
# drivers/isdn/hisax/st5481_usb.c
# 2004/04/26 07:43:53-07:00 stern@rowland.harvard.edu +7 -3
# USB: USB altsetting updates for IDSN Hisax driver
#
# drivers/isdn/hisax/st5481_d.c
# 2004/04/26 07:43:53-07:00 stern@rowland.harvard.edu +7 -2
# USB: USB altsetting updates for IDSN Hisax driver
#
# drivers/isdn/hisax/st5481_b.c
# 2004/04/26 07:43:53-07:00 stern@rowland.harvard.edu +7 -2
# USB: USB altsetting updates for IDSN Hisax driver
#
# ChangeSet
# 2004/04/30 22:06:45-07:00 akpm@bix.(none)
# Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
#
# drivers/usb/core/inode.c
# 2004/04/30 22:06:42-07:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/04/29 16:00:47-07:00 akpm@bix.(none)
# Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
#
# include/linux/pci_ids.h
# 2004/04/29 16:00:44-07:00 akpm@bix.(none) +0 -0
# Auto merged
#
# MAINTAINERS
# 2004/04/29 16:00:44-07:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/04/29 10:47:50-07:00 greg@kroah.com
# USB: fix build error in hci_usb driver due to urb reference count change.
#
# This really needs to get fixed the proper way, by making the urb allocation
# dynamic in the driver, instead of the hack it is currently doing...
#
# drivers/bluetooth/hci_usb.c
# 2004/04/29 03:47:26-07:00 greg@kroah.com +1 -1
# USB: fix build error in hci_usb driver due to urb reference count change.
#
# This really needs to get fixed the proper way, by making the urb allocation
# dynamic in the driver, instead of the hack it is currently doing...
#
# ChangeSet
# 2004/04/29 10:40:57-07:00 greg@kroah.com
# USB: remove the wait_for_urb function from bfusb driver as it's no longer needed.
#
# drivers/bluetooth/bfusb.c
# 2004/04/29 03:40:30-07:00 greg@kroah.com +0 -9
# USB: remove the wait_for_urb function from bfusb driver as it's no longer needed.
#
# ChangeSet
# 2004/04/28 21:43:38-07:00 sean@mess.org
# [PATCH] USB: fix PhidgetServo driver
#
# Somehow I managed to send the wrong version. Here is a patch which fixes
# that. (Remove a dev_info() which wasn't supposed to be there, and make sure
# that everything is still consistent in the unlikely event that kmalloc()
# fails). Just minor cleanups.
#
# drivers/usb/misc/phidgetservo.c
# 2004/04/28 17:35:09-07:00 sean@mess.org +14 -17
# USB: fix PhidgetServo driver
#
# ChangeSet
# 2004/04/28 13:38:52-07:00 akpm@bix.(none)
# Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
# into bix.(none):/usr/src/bk-usb
#
# drivers/usb/input/hid-core.c
# 2004/04/28 13:38:49-07:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/04/28 13:25:14-07:00 david-b@pacbell.net
# [PATCH] USB: fix sparc64 2.6.6-rc2-mm2 build busted: usb/core/hub.c hubstatus
#
# > 2) An undefined 'hubstatus' variable in drivers/usb/core/hub.c:
# >
# > CC drivers/usb/core/hub.o
# > drivers/usb/core/hub.c: In function `hub_port_connect_change':
# > drivers/usb/core/hub.c:1343: error: `hubstatus' undeclared (first use in this function)
# > drivers/usb/core/hub.c:1343: error: (Each undeclared identifier is reported only once
# > drivers/usb/core/hub.c:1343: error: for each function it appears in.)
# > make[3]: *** [drivers/usb/core/hub.o] Error 1
# >
# > As a total shot in the dark, the following fixes the build (I've no clue
# > if it is the right fix):
#
# Yes, it's the right fix. Greg, please merge the attached patch,
# which will be needed on any big-endian system.
#
# drivers/usb/core/hub.c
# 2004/04/27 01:19:29-07:00 david-b@pacbell.net +1 -1
# USB: fix sparc64 2.6.6-rc2-mm2 build busted: usb/core/hub.c hubstatus
#
# ChangeSet
# 2004/04/28 11:52:21-07:00 stern@rowland.harvard.edu
# [PATCH] USB: Lock devices during tree traversal
#
# On Tue, 27 Apr 2004, Greg KH wrote:
#
# > So, what's next in this patch series? :)
#
# Funny you should ask...
#
# While writing those patches I noted a problem, that the USB device tree
# can change while a process reading /proc/bus/usb/devices is traversing it,
# leading to an oops when a pointer to a no-longer-existing child device is
# dereferenced. The ensuing discussion led to the conclusion that the
# devices' ->serialize locks should be acquired, top-down, while going
# through the tree.
#
# That means changing the code that populates the devices file and changing
# the code that adds and removes USB device structures. This patch takes
# care of the first part. I'm delaying the second part because that section
# of usbcore is still under change -- David Brownell's revisions have not
# yet been fully integrated.
#
# A similar change should be made to usb_find_device() and match_device() in
# usb.c. You may want to add that yourself.
#
# drivers/usb/core/devices.c
# 2004/04/28 06:48:48-07:00 stern@rowland.harvard.edu +10 -2
# USB: Lock devices during tree traversal
#
# ChangeSet
# 2004/04/28 11:51:52-07:00 sean@mess.org
# [PATCH] USB: add new USB PhidgetServo driver
#
# Here is a driver for the usb servo controllers from Phidgets
# , using sysfs.
#
# Note that the devices claim to be hid devices, so I've added them to the
# hid_blacklist (HID_QUIRK_IGNORE). A servo controller isn't really an hid
# device (or is it?).
#
# drivers/usb/misc/Makefile
# 2004/04/21 09:02:00-07:00 sean@mess.org +1 -0
# USB: add new USB PhidgetServo driver
#
# drivers/usb/misc/Kconfig
# 2004/04/21 09:02:00-07:00 sean@mess.org +12 -0
# USB: add new USB PhidgetServo driver
#
# drivers/usb/input/hid-core.c
# 2004/04/22 02:54:25-07:00 sean@mess.org +12 -0
# USB: add new USB PhidgetServo driver
#
# drivers/usb/Makefile
# 2004/04/21 09:02:00-07:00 sean@mess.org +1 -0
# USB: add new USB PhidgetServo driver
#
# drivers/usb/misc/phidgetservo.c
# 2004/04/27 04:03:07-07:00 sean@mess.org +330 -0
# USB: add new USB PhidgetServo driver
#
# drivers/usb/misc/phidgetservo.c
# 2004/04/27 04:03:07-07:00 sean@mess.org +0 -0
# BitKeeper file /home/greg/linux/BK/usb-2.6/drivers/usb/misc/phidgetservo.c
#
# ChangeSet
# 2004/04/27 19:39:13-07:00 akpm@bix.(none)
# Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
# into bix.(none):/usr/src/bk-usb
#
# include/linux/usb.h
# 2004/04/27 19:39:10-07:00 akpm@bix.(none) +0 -0
# Auto merged
#
# drivers/usb/core/usb.c
# 2004/04/27 19:39:10-07:00 akpm@bix.(none) +0 -0
# Auto merged
#
# drivers/usb/core/message.c
# 2004/04/27 19:39:10-07:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/04/27 17:33:52-07:00 greg@kroah.com
# USB: fix compiler warnings in devices.c file.
#
# drivers/usb/core/devices.c
# 2004/04/27 10:33:12-07:00 greg@kroah.com +2 -2
# USB: fix compiler warnings in devices.c file.
#
# ChangeSet
# 2004/04/27 16:02:32-07:00 stern@rowland.harvard.edu
# [PATCH] USB: Allocate interface structures dynamically
#
# This is a revised version of an earlier patch; I feel a lot better about
# this one. Basically it does the same thing as before: allocate
# interfaces dynamically to avoid the problems with reusing them.
#
# The difference is that this patch adds a struct kref to the array of
# usb_interface_cache's, so the array can persist if needed after the
# device has been disconnected. Each interface takes a reference to it
# (along with the configuration itself), so as long as the interfaces
# remain pinned in memory the altsettings will also remain.
#
# Here is a slight revision of patch as246b. This one allocates all the new
# interfaces before changing any other state; otherwise it's the same.
#
# include/linux/usb.h
# 2004/04/15 07:43:58-07:00 stern@rowland.harvard.edu +38 -3
# USB: Allocate interface structures dynamically
#
# drivers/usb/core/usb.c
# 2004/04/15 05:19:20-07:00 stern@rowland.harvard.edu +1 -1
# USB: Allocate interface structures dynamically
#
# drivers/usb/core/message.c
# 2004/04/15 05:28:25-07:00 stern@rowland.harvard.edu +46 -13
# USB: Allocate interface structures dynamically
#
# drivers/usb/core/devices.c
# 2004/04/15 05:21:07-07:00 stern@rowland.harvard.edu +19 -12
# USB: Allocate interface structures dynamically
#
# drivers/usb/core/config.c
# 2004/04/15 07:45:41-07:00 stern@rowland.harvard.edu +31 -44
# USB: Allocate interface structures dynamically
#
# ChangeSet
# 2004/04/27 15:22:05-07:00 greg@kroah.com
# USB: fix incorrect usb-serial conversion for cur_altsetting from previous patch.
#
# drivers/usb/serial/usb-serial.c
# 2004/04/27 08:21:23-07:00 greg@kroah.com +1 -1
# USB: fix incorrect usb-serial conversion for cur_altsetting from previous patch.
#
# ChangeSet
# 2004/04/27 14:45:49-07:00 greg@kroah.com
# USB: make ehci driver use a kref instead of an atomic_t
#
# drivers/usb/host/ehci.h
# 2004/04/27 14:45:32-07:00 greg@kroah.com +2 -1
# USB: make ehci driver use a kref instead of an atomic_t
#
# drivers/usb/host/ehci-sched.c
# 2004/04/27 14:45:32-07:00 greg@kroah.com +3 -3
# USB: make ehci driver use a kref instead of an atomic_t
#
# drivers/usb/host/ehci-q.c
# 2004/04/27 14:45:32-07:00 greg@kroah.com +5 -5
# USB: make ehci driver use a kref instead of an atomic_t
#
# drivers/usb/host/ehci-mem.c
# 2004/04/27 14:45:32-07:00 greg@kroah.com +23 -16
# USB: make ehci driver use a kref instead of an atomic_t
#
# drivers/usb/host/ehci-hcd.c
# 2004/04/27 14:45:32-07:00 greg@kroah.com +1 -1
# USB: make ehci driver use a kref instead of an atomic_t
#
# ChangeSet
# 2004/04/27 14:21:13-07:00 greg@kroah.com
# USB: removed unused atomic_t in keyspan driver structure.
#
# drivers/usb/serial/keyspan.c
# 2004/04/27 07:20:12-07:00 greg@kroah.com +0 -3
# USB: removed unused atomic_t in keyspan driver structure.
#
# ChangeSet
# 2004/04/26 18:31:48-07:00 akpm@bix.(none)
# Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
# into bix.(none):/usr/src/bk-usb
#
# include/linux/usb.h
# 2004/04/26 18:31:45-07:00 akpm@bix.(none) +0 -0
# Auto merged
#
# drivers/usb/core/usb.c
# 2004/04/26 18:31:45-07:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/04/26 17:07:28-07:00 greg@kroah.com
# USB: switch struct urb to use a kref instead of it's own atomic_t
#
# include/linux/usb.h
# 2004/04/26 10:06:52-07:00 greg@kroah.com +2 -1
# USB: switch struct urb to use a kref instead of it's own atomic_t
#
# drivers/usb/core/urb.c
# 2004/04/26 10:06:52-07:00 greg@kroah.com +13 -8
# USB: switch struct urb to use a kref instead of it's own atomic_t
#
# ChangeSet
# 2004/04/26 16:11:11-07:00 mdharm-usb@one-eyed-alien.net
# [PATCH] USB: usb-storage driver changes for 2.6.x [4/4]
#
# This is a trivial patch to remove some duplicate includes. sched.h and
# errno.h are already included in this file about a dozen lines or so above
# this point.
#
# drivers/usb/storage/usb.c
# 2004/04/24 19:25:23-07:00 mdharm-usb@one-eyed-alien.net +0 -2
# USB: usb-storage driver changes for 2.6.x [4/4]
#
# ChangeSet
# 2004/04/26 16:10:49-07:00 mdharm-usb@one-eyed-alien.net
# [PATCH] USB: usb-storage driver changes for 2.6.x [3/4]
#
# This patch adds some clear-halt calls if a GetMaxLUN fails. Apparently,
# some devices (like certain early-rev Zip100s) stall their bulk pipes if
# they receive a GetMaxLUN.
#
# drivers/usb/storage/transport.c
# 2004/04/24 19:25:32-07:00 mdharm-usb@one-eyed-alien.net +11 -0
# USB: usb-storage driver changes for 2.6.x [3/4]
#
# ChangeSet
# 2004/04/26 16:10:25-07:00 mdharm-usb@one-eyed-alien.net
# [PATCH] USB: usb-storage driver changes for 2.6.x [2/4]
#
# This is patch as248b from Alan Stern, modified by myself: This adds a flag
# which allows us to supress the "unneeded unusual_devs.h entry" message.
# This is useful for times when idiotic device manufacturers break the rules
# and release two different devices with the same VID, PID, and revision
# number.
#
# drivers/usb/storage/usb.h
# 2004/04/24 19:25:41-07:00 mdharm-usb@one-eyed-alien.net +1 -0
# USB: usb-storage driver changes for 2.6.x [2/4]
#
# drivers/usb/storage/usb.c
# 2004/04/24 19:25:41-07:00 mdharm-usb@one-eyed-alien.net +1 -1
# USB: usb-storage driver changes for 2.6.x [2/4]
#
# drivers/usb/storage/unusual_devs.h
# 2004/04/24 19:25:41-07:00 mdharm-usb@one-eyed-alien.net +1 -1
# USB: usb-storage driver changes for 2.6.x [2/4]
#
# ChangeSet
# 2004/04/26 16:10:02-07:00 mdharm-usb@one-eyed-alien.net
# [PATCH] USB: usb-storage driver changes for 2.6.x [1/4]
#
# Patch as239b from Alan Stern: This patch improves the interaction between
# a SCSI reset, an internally generated reset, and an abort. This improves
# our error-recovery in cases where the device is hung (or almost hung) while
# we're trying to auto-reset.
#
# drivers/usb/storage/usb.h
# 2004/04/24 19:25:50-07:00 mdharm-usb@one-eyed-alien.net +3 -2
# USB: usb-storage driver changes for 2.6.x [1/4]
#
# drivers/usb/storage/transport.c
# 2004/04/24 19:25:50-07:00 mdharm-usb@one-eyed-alien.net +26 -21
# USB: usb-storage driver changes for 2.6.x [1/4]
#
# drivers/usb/storage/scsiglue.c
# 2004/04/24 19:25:50-07:00 mdharm-usb@one-eyed-alien.net +11 -8
# USB: usb-storage driver changes for 2.6.x [1/4]
#
# ChangeSet
# 2004/04/26 16:09:34-07:00 stern@rowland.harvard.edu
# [PATCH] USB: Altsetting updates for usb/serial
#
# The updates needed for proper altsetting handling among the USB serial
# drivers turned out to be a lot easier than I expected, thanks to the
# organization of the drivers. Only a handful of changes were needed.
#
# drivers/usb/serial/usb-serial.c
# 2004/04/26 07:38:00-07:00 stern@rowland.harvard.edu +1 -1
# USB: Altsetting updates for usb/serial
#
# drivers/usb/serial/safe_serial.c
# 2004/04/26 07:38:00-07:00 stern@rowland.harvard.edu +1 -1
# USB: Altsetting updates for usb/serial
#
# drivers/usb/serial/kobil_sct.c
# 2004/04/26 07:38:00-07:00 stern@rowland.harvard.edu +1 -1
# USB: Altsetting updates for usb/serial
#
# drivers/usb/serial/io_ti.c
# 2004/04/26 07:38:00-07:00 stern@rowland.harvard.edu +1 -1
# USB: Altsetting updates for usb/serial
#
# ChangeSet
# 2004/04/26 16:09:06-07:00 baldrick@free.fr
# [PATCH] USB: be assertive in usbfs
#
# Be assertive.
#
# drivers/usb/core/devio.c
# 2004/04/26 06:48:28-07:00 baldrick@free.fr +2 -2
# USB: be assertive in usbfs
#
# ChangeSet
# 2004/04/26 16:08:38-07:00 bellucda@tiscali.it
# [PATCH] USB: audits in usb_init()
#
# there were some missing audits in usb_init()
#
# drivers/usb/core/usb.c
# 2004/04/26 14:55:56-07:00 bellucda@tiscali.it +26 -6
# USB: audits in usb_init()
#
# ChangeSet
# 2004/04/26 16:08:12-07:00 tejohnson@yahoo.com
# [PATCH] USB: mtouchusb update for 2.6.6-rc2
#
# The attached patch for the 3M Touch Systems Capacitive controller.
#
# Quick list of changes:
#
# * Changed reset from standard USB dev reset to vendor reset
# * Changed data sent to host from compensated to raw coordinates
# * Eliminated vendor/product module params
# * Performed multiple successfull tests with an EXII-5010UC
#
# The changes are primarily due to comments from Vojtech Pavlik, as well
# as making the newer EXII-50XXUC controllers work.
#
# Thanks to 3M Touch Systems for sending me some new controllers to test with!
#
# An updated HOWTO is also available at:
#
#
# http://groomlakelabs.com/grandamp/code/microtouch/Linux-Input-USB-Touchscreen-HowTo.txt
#
# drivers/usb/input/mtouchusb.c
# 2004/04/25 12:16:01-07:00 tejohnson@yahoo.com +35 -72
# USB: mtouchusb update for 2.6.6-rc2
#
# Documentation/usb/mtouchusb.txt
# 2004/04/25 12:16:49-07:00 tejohnson@yahoo.com +42 -51
# USB: mtouchusb update for 2.6.6-rc2
#
# ChangeSet
# 2004/04/25 23:06:05-07:00 akpm@bix.(none)
# Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
#
# include/linux/pci_ids.h
# 2004/04/25 23:06:02-07:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/04/24 23:51:05-07:00 akpm@bix.(none)
# Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
# into bix.(none):/usr/src/bk-usb
#
# drivers/usb/core/usb.c
# 2004/04/24 23:51:02-07:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/04/23 16:41:30-07:00 stern@rowland.harvard.edu
# [PATCH] USB: Altsetting update for USB net drivers
#
# The only driver under usb/net that needed any altsetting changes was
# usbnet. I'm not looking forward to going through all the source files
# under usb/serial. :-(
#
# drivers/usb/net/usbnet.c
# 2004/04/22 09:56:28-07:00 stern@rowland.harvard.edu +4 -4
# USB: Altsetting update for USB net drivers
#
# ChangeSet
# 2004/04/23 16:41:04-07:00 stern@rowland.harvard.edu
# [PATCH] USB: Altsetting update for USB misc drivers
#
# This is the altsetting update for the drivers under usb/misc. As you can,
# not much was needed at all.
#
# drivers/usb/misc/uss720.c
# 2004/04/22 09:08:37-07:00 stern@rowland.harvard.edu +1 -1
# USB: Altsetting update for USB misc drivers
#
# drivers/usb/misc/legousbtower.c
# 2004/04/22 09:01:26-07:00 stern@rowland.harvard.edu +1 -1
# USB: Altsetting update for USB misc drivers
#
# ChangeSet
# 2004/04/23 16:40:35-07:00 stern@rowland.harvard.edu
# [PATCH] USB: Altsetting updates for USB media drivers
#
# This patch implements the new altsetting regime for the drivers under
# usb/media. Not much needed to be changed. I'm unable to test any of the
# changes, but at least they compile all right (except that I didn't even
# try to compile the pwc driver since it's marked BROKEN).
#
# The stv680 and w9968cf drivers still include an assumption that they are
# bound to interface number 0. Since that the drivers are fairly tightly
# linked to a specific kind of device I didn't try to change those
# assumptions, but maybe they should be changed.
#
# drivers/usb/media/vicam.c
# 2004/04/22 04:41:49-07:00 stern@rowland.harvard.edu +1 -1
# USB: Altsetting updates for USB media drivers
#
# drivers/usb/media/ultracam.c
# 2004/04/21 09:26:45-07:00 stern@rowland.harvard.edu +4 -3
# USB: Altsetting updates for USB media drivers
#
# drivers/usb/media/se401.c
# 2004/04/21 09:21:19-07:00 stern@rowland.harvard.edu +1 -1
# USB: Altsetting updates for USB media drivers
#
# drivers/usb/media/pwc-if.c
# 2004/04/21 09:18:47-07:00 stern@rowland.harvard.edu +5 -2
# USB: Altsetting updates for USB media drivers
#
# drivers/usb/media/ov511.c
# 2004/04/22 04:40:56-07:00 stern@rowland.harvard.edu +11 -3
# USB: Altsetting updates for USB media drivers
#
# drivers/usb/media/konicawc.c
# 2004/04/21 09:41:57-07:00 stern@rowland.harvard.edu +12 -5
# USB: Altsetting updates for USB media drivers
#
# drivers/usb/media/ibmcam.c
# 2004/04/21 09:32:00-07:00 stern@rowland.harvard.edu +5 -4
# USB: Altsetting updates for USB media drivers
#
# ChangeSet
# 2004/04/23 16:40:06-07:00 stern@rowland.harvard.edu
# [PATCH] USB: Cosmetic improvements for the UHCI driver
#
# This patch makes a few minor improvements to the appearance of the UHCI
# driver. Please apply.
#
# drivers/usb/host/uhci-hcd.h
# 2004/04/19 04:05:56-07:00 stern@rowland.harvard.edu +7 -7
# USB: Cosmetic improvements for the UHCI driver
#
# drivers/usb/host/uhci-hcd.c
# 2004/04/14 03:19:54-07:00 stern@rowland.harvard.edu +10 -10
# USB: Cosmetic improvements for the UHCI driver
#
# ChangeSet
# 2004/04/23 16:39:38-07:00 stern@rowland.harvard.edu
# [PATCH] USB: Ignore URB_NO_INTERRUPT flag in UHCI
#
# Following a suggestion of David Brownell's I have decided to remove
# support for the URB_NO_INTERRUPT flag in the UHCI driver. The overall
# effect of the flag is to reduce the number of interrupts, thereby
# improving throughput somewhat while increasing the duration of the
# remaining IRQ handlers quite a lot (i.e., increasing interrupt variance).
# So I think we're better off without it. Mind you, this is all in the
# absence of any firm measurements.
#
# A common case where this will come up is during usb-storage bulk
# transfers. Such transfers are generally divided into scatter-gather
# components each corresponding to a single URB and transferring one memory
# page (4 KB). While generating an interrupt for each one is a little
# faster than ideal -- about every 3 ms -- it's better than waiting until 64
# KB has been transferred and there are 1024 individual TDs to clean up
# during the IRQ.
#
# drivers/usb/host/uhci-hcd.c
# 2004/04/16 04:02:37-07:00 stern@rowland.harvard.edu +7 -3
# USB: Ignore URB_NO_INTERRUPT flag in UHCI
#
# ChangeSet
# 2004/04/23 16:20:26-07:00 baldrick@free.fr
# [PATCH] USB usbfs: drop pointless racy check
#
# The check of interface->dev.driver requires a lock to be taken
# to protect against driver binding changes. But in fact I think it
# is better just to drop the test. The result is that the caller is
# required to claim an interface before changing the altsetting,
# which is consistent with the other routines that operate on
# interfaces.
#
# devio.c | 6 ++----
# 1 files changed, 2 insertions(+), 4 deletions(-)
#
# drivers/usb/core/devio.c
# 2004/04/14 05:18:37-07:00 baldrick@free.fr +2 -4
# USB usbfs: drop pointless racy check
#
# ChangeSet
# 2004/04/23 16:20:07-07:00 baldrick@free.fr
# [PATCH] USB usbfs: missing lock in proc_getdriver
#
# Hi Oliver,
#
# > I expect it to rarely matter, but it might matter now and then. It's
# > just a question of hygiene. If you are using a temporary buffer I'd
# > like to see it used to full advantage. So either drop the lock or do
# > a direct copy. I'd prefer the first option your patch implemented.
#
# I agree. Greg, please consider applying the updated patch:
#
#
#
# Protect against driver binding changes while reading the driver name.
#
# drivers/usb/core/devio.c
# 2004/04/14 07:03:12-07:00 baldrick@free.fr +6 -4
# USB usbfs: missing lock in proc_getdriver
#
# ChangeSet
# 2004/04/23 16:19:43-07:00 baldrick@free.fr
# [PATCH] USB usbfs: destroy submitted urbs only on the disconnected interface
#
# The remaining three patches contain miscellaneous fixes to usbfs.
# This one fixes up the disconnect callback to only shoot down urbs
# on the disconnected interface, and not on all interfaces. It also adds
# a sanity check (this check is pointless because the interface could
# never have been claimed in the first place if it failed, but I feel better
# having it there).
#
# devio.c | 6 ++++--
# 1 files changed, 4 insertions(+), 2 deletions(-)
#
# drivers/usb/core/devio.c
# 2004/04/14 05:18:20-07:00 baldrick@free.fr +4 -2
# USB usbfs: destroy submitted urbs only on the disconnected interface
#
# ChangeSet
# 2004/04/23 16:19:14-07:00 baldrick@free.fr
# [PATCH] USB usbfs: fix up releaseintf
#
# The semaphore is now taken in the callers.
#
# devio.c | 2 --
# 1 files changed, 2 deletions(-)
#
# drivers/usb/core/devio.c
# 2004/04/14 05:18:08-07:00 baldrick@free.fr +0 -2
# USB usbfs: fix up releaseintf
#
# ChangeSet
# 2004/04/23 16:18:50-07:00 baldrick@free.fr
# [PATCH] USB usbfs: fix up proc_ioctl
#
# The semaphore is now taken in the caller.
#
# devio.c | 2 --
# 1 files changed, 2 deletions(-)
#
# drivers/usb/core/devio.c
# 2004/04/14 05:17:56-07:00 baldrick@free.fr +0 -2
# USB usbfs: fix up proc_ioctl
#
# ChangeSet
# 2004/04/23 16:18:24-07:00 baldrick@free.fr
# [PATCH] USB usbfs: fix up proc_setconfig
#
# The semaphore is now taken in the caller.
#
# devio.c | 2 --
# 1 files changed, 2 deletions(-)
#
# drivers/usb/core/devio.c
# 2004/04/14 05:17:46-07:00 baldrick@free.fr +0 -2
# USB usbfs: fix up proc_setconfig
#
# ChangeSet
# 2004/04/23 16:17:59-07:00 baldrick@free.fr
# [PATCH] USB usbfs: remove obsolete comment from proc_resetdevice
#
# devio.c | 3 ---
# 1 files changed, 3 deletions(-)
#
# drivers/usb/core/devio.c
# 2004/04/14 05:17:37-07:00 baldrick@free.fr +0 -3
# USB usbfs: remove obsolete comment from proc_resetdevice
#
# ChangeSet
# 2004/04/23 16:17:35-07:00 baldrick@free.fr
# [PATCH] USB usbfs: replace the per-file semaphore with the per-device semaphore
#
# devio.c | 43 +++++++++++++++++++++++--------------------
# usbdevice_fs.h | 1 -
# 2 files changed, 23 insertions(+), 21 deletions(-)
#
# include/linux/usbdevice_fs.h
# 2004/04/14 05:34:00-07:00 baldrick@free.fr +0 -1
# USB usbfs: replace the per-file semaphore with the per-device semaphore
#
# drivers/usb/core/devio.c
# 2004/04/14 05:17:29-07:00 baldrick@free.fr +23 -20
# USB usbfs: replace the per-file semaphore with the per-device semaphore
#
# ChangeSet
# 2004/04/23 16:17:09-07:00 baldrick@free.fr
# [PATCH] USB usbfs: take a reference to the usb device
#
# Hi Greg, this is the first of a series of patches that replace the
# per-file semaphore ps->devsem with the per-device semaphore
# ps->dev->serialize. The role of devsem was to protect against
# device disconnection. This can be done equally well using
# ps->dev->serialize. On the other hand, ps->dev->serialize
# protects against configuration and other changes, and has
# already been introduced into usbfs in several places. Using
# just one semaphore simplifies the code and removes some
# remaining race conditions. It should also fix the oopses some
# people have been seeing. In this first patch, a reference is
# taken to the usb device as long as the usbfs file is open. That
# way we can use ps->dev->serialize for as long as ps exists.
#
# devio.c | 27 ++++++++++++++++-----------
# inode.c | 3 ---
# 2 files changed, 16 insertions(+), 14 deletions(-)
#
# drivers/usb/core/inode.c
# 2004/04/14 05:15:29-07:00 baldrick@free.fr +0 -3
# USB usbfs: take a reference to the usb device
#
# drivers/usb/core/devio.c
# 2004/04/14 05:15:29-07:00 baldrick@free.fr +16 -11
# USB usbfs: take a reference to the usb device
#
# ChangeSet
# 2004/04/23 15:45:24-07:00 david-b@pacbell.net
# [PATCH] USB: khubd fixes
#
# This goes on top of the other enumeration patch I just sent,
# to handle some dubious and/or broken hub configurations better.
#
#
# Make khubd handle some cases better:
#
# - Track power budget for bus-powered hubs. This version only warns
# when the budgets are exceeded. Eventually, the budgets should help
# prevent such errors.
#
# - Rejects illegal USB setup: two consecutive bus powered hubs
# would exceed the voltage drop budget, causing much flakiness.
#
# - For hosts with high speed hubs, warn when devices are hooked up
# to full speed hubs if they'd be faster on a high speed one.
#
# - For hubs that don't do power switching, don't try to use it
#
# - For hubs that aren't self-powered, don't report local power status
#
# drivers/usb/core/hub.h
# 2004/04/19 08:29:02-07:00 david-b@pacbell.net +2 -0
# USB: khubd fixes
#
# drivers/usb/core/hub.c
# 2004/04/20 20:44:45-07:00 david-b@pacbell.net +143 -15
# USB: khubd fixes
#
# ChangeSet
# 2004/04/23 15:44:57-07:00 david-b@pacbell.net
# [PATCH] USB: re-factor enumeration logic
#
# This is an update to some patches from the December/January
# timeframe, which will help sort out some of the mess for
# drivers that need to use the reset logic. It's one of the
# last significant patches in my gadget-2.6 tree that haven't
# yet been merged into the main kernel tree.
#
#
# More refactoring of the enumeration code paths:
#
# * The first half of usb_new_device() becomes the second half of a new
# hub_port_init() routine (resets, sets address, gets descriptor)
#
# * The middle chunk of hub_port_connect_change() becomes the first half
# of that new hub_port_init() routine.
#
# * Khubd uses that new routine in hub_port_connect_change().
#
# * Now usb_new_device() cleans up better after faults, and has
# a more useful locking policy (caller owns dev->serialize).
#
# * Has related minor cleanups including commenting some of
# the curious request sequences coming from khubd.
#
# Refactoring means a lot of the current usb_reset_device() logic won't
# need to stay an imperfect clone of the enumeration code ... soon, it
# can just call hub_port_init().
#
# Even without touching usb_reset_device(), this eliminates a deadlock.
# Previously, address0_sem was used both during probe and during reset,
# so probe routines can't implement DFU firmware download (involves a
# reset; DFU also uncovers other problems) or safely recover from probe
# faults by resetting (usb-storage can try that). Now that lock is no
# longer held during probe(); so those deadlocks are gone. (And some
# drivers, like at76c503, can start to remove ugly workarounds.)
#
# drivers/usb/core/usb.c
# 2004/04/21 03:46:29-07:00 david-b@pacbell.net +13 -79
# USB: re-factor enumeration logic
#
# drivers/usb/core/hub.c
# 2004/04/21 03:46:29-07:00 david-b@pacbell.net +215 -72
# USB: re-factor enumeration logic
#
# drivers/usb/core/hcd.c
# 2004/04/21 03:46:29-07:00 david-b@pacbell.net +12 -0
# USB: re-factor enumeration logic
#
# ChangeSet
# 2004/04/23 15:44:32-07:00 david-b@pacbell.net
# [PATCH] USB: usbtest, smp unlink modes
#
# Handle some SMP-visible unlink states better.
#
# drivers/usb/misc/usbtest.c
# 2004/04/14 20:23:11-07:00 david-b@pacbell.net +3 -3
# USB: usbtest, smp unlink modes
#
# ChangeSet
# 2004/04/23 14:50:19-07:00 greg@kroah.com
# [PATCH] USB: fix devio compiler warnings created by previous patch.
#
# drivers/usb/core/devio.c
# 2004/04/23 07:33:30-07:00 greg@kroah.com +2 -2
# USB: fix devio compiler warnings created by previous patch.
#
# ChangeSet
# 2004/04/23 14:49:56-07:00 stern@rowland.harvard.edu
# [PATCH] USB: Eliminate dead code from the UHCI driver
#
# I'm not sure what this piece of code is doing in the UHCI driver. It
# looks like someone envisioned queuing several URBs for the same endpoint
# simultaneously. Anyway, the driver can't do that and this code can never
# run.
#
# drivers/usb/host/uhci-hcd.c
# 2004/04/16 04:02:37-07:00 stern@rowland.harvard.edu +1 -11
# USB: Eliminate dead code from the UHCI driver
#
# ChangeSet
# 2004/04/23 14:49:33-07:00 stern@rowland.harvard.edu
# [PATCH] USB: Implement endpoint_disable() for UHCI
#
# This patch implements the endpoint_disable method for the UHCI driver, as
# you requested a while back. It guarantees that during unbinding events
# (disconnect, configuration change, rmmod) the UHCI driver will have
# finished using every URB for the interface being unbound. It doesn't
# quite guarantee that the completion handlers will have finished running,
# but it would take a pretty unlikely race to violate that assumption. (I
# think it's the same with the OHCI and EHCI drivers.)
#
# Despite the patch numbering this one applies _after_ as249, which is a
# more important bugfix.
#
# drivers/usb/host/uhci-hcd.h
# 2004/04/19 04:05:56-07:00 stern@rowland.harvard.edu +2 -0
# USB: Implement endpoint_disable() for UHCI
#
# drivers/usb/host/uhci-hcd.c
# 2004/04/14 03:19:54-07:00 stern@rowland.harvard.edu +49 -0
# USB: Implement endpoint_disable() for UHCI
#
# ChangeSet
# 2004/04/23 14:49:10-07:00 stern@rowland.harvard.edu
# [PATCH] USB: unusual_devs.h update
#
# On Tue, 20 Apr 2004, Damian Ivereigh wrote:
#
# > Here is the output of dmesg when plugging in an IBM USB MemKey
# >
# > usb-storage: This device (0a16,8888,0100 S 06 P 50) has unneeded SubClass and Protocol entries in unusual_devs.h
# > Please send a copy of this message to
#
# Thank you for sending this in. Greg and Pete, here's the patch.
#
# drivers/usb/storage/unusual_devs.h
# 2004/04/19 05:11:29-07:00 stern@rowland.harvard.edu +1 -1
# USB: unusual_devs.h update
#
# ChangeSet
# 2004/04/23 14:48:47-07:00 stern@rowland.harvard.edu
# [PATCH] USB: Remove unusual_devs entries for Minolta DiMAGE 7, 7Hi
#
# It looks safe to conclude that the unusual_devs.h entries for the Minolta
# DiMAGE 7x cameras aren't needed. (Michael has tested the 7Hi and it's
# definitely unnecessary.) The two other DiMAGE entries probably aren't
# needed either, but we don't have any evidence of that so I'm leaving them.
#
# drivers/usb/storage/unusual_devs.h
# 2004/04/16 04:37:06-07:00 stern@rowland.harvard.edu +0 -16
# USB: Remove unusual_devs entries for Minolta DiMAGE 7, 7Hi
#
# ChangeSet
# 2004/04/23 14:48:28-07:00 david-b@pacbell.net
# [PATCH] USB: root hubs can report remote wakeup feature
#
# The patch lets HCDs report the root hub remote wakeup feature to usbcore
# through config descriptors, and lets usbcore say whether or not remote
# wakeup (of host from sleep, by devices) should be enabled.
#
# Both OHCI and UHCI HCDs have some remote wakeup support already; I'm not
# too sure how well it works. Given (separate) patches, their root hubs
# can start to act more like other hubs in this area too. That'll make
# it easier to start using USB suspend mode.
#
# drivers/usb/core/hcd.h
# 2004/04/13 11:48:39-07:00 david-b@pacbell.net +10 -1
# USB: root hubs can report remote wakeup feature
#
# drivers/usb/core/hcd.c
# 2004/04/13 11:33:31-07:00 david-b@pacbell.net +28 -11
# USB: root hubs can report remote wakeup feature
#
# ChangeSet
# 2004/04/23 14:48:02-07:00 david-b@pacbell.net
# [PATCH] USB: fix usbfs iso interval problem
#
# In 2.6, ISO transfers on USB require a value for urb->interval ... which
# usbfs didn't provide (until this patch), or let user mode drivers specify.
#
# This patch initializes the urb->interval from the endpoint's descriptor,
# so ISO transfers should now work from userspace. It also fixes a related
# problem for interrupt transfers.
#
# drivers/usb/core/devio.c
# 2004/04/14 13:36:53-07:00 david-b@pacbell.net +7 -1
# USB: fix usbfs iso interval problem
#
# ChangeSet
# 2004/04/23 12:58:38-07:00 akpm@bix.(none)
# Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
#
# CREDITS
# 2004/04/23 12:58:35-07:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/04/19 19:45:10-07:00 akpm@bix.(none)
# Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
#
# include/linux/pci_ids.h
# 2004/04/19 19:45:07-07:00 akpm@bix.(none) +0 -0
# Auto merged
#
# MAINTAINERS
# 2004/04/19 19:45:07-07:00 akpm@bix.(none) +0 -0
# Auto merged
#
# CREDITS
# 2004/04/19 19:45:06-07:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/04/07 20:17:13-07:00 akpm@bix.(none)
# Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
# into bix.(none):/usr/src/bk-usb
#
# drivers/usb/core/message.c
# 2004/04/07 20:17:11-07:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/04/02 11:35:28-08:00 akpm@bix.(none)
# Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
# into bix.(none):/usr/src/bk-usb
#
# include/linux/pci_ids.h
# 2004/04/02 11:35:25-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/04/01 15:16:14-08:00 akpm@bix.(none)
# Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
#
# CREDITS
# 2004/04/01 15:16:11-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/03/31 19:24:39-08:00 akpm@bix.(none)
# Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
# into bix.(none):/usr/src/bk-usb
#
# include/linux/usb.h
# 2004/03/31 19:24:37-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# drivers/usb/core/usb.c
# 2004/03/31 19:24:37-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# drivers/usb/core/message.c
# 2004/03/31 19:24:37-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# arch/ppc64/defconfig
# 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# arch/ppc64/configs/pSeries_defconfig
# 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# arch/ppc/defconfig
# 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# arch/ppc/configs/pmac_defconfig
# 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# arch/ppc/configs/common_defconfig
# 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# arch/parisc/configs/c3000_defconfig
# 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# arch/ia64/defconfig
# 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# arch/ia64/configs/zx1_defconfig
# 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# arch/ia64/configs/generic_defconfig
# 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# arch/arm/configs/neponset_defconfig
# 2004/03/31 19:24:36-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/03/30 20:18:36-08:00 akpm@bix.(none)
# Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
# into bix.(none):/usr/src/bk-usb
#
# arch/ppc64/defconfig
# 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# arch/ppc64/configs/pSeries_defconfig
# 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# arch/ppc/defconfig
# 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# arch/ppc/configs/pmac_defconfig
# 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# arch/ppc/configs/common_defconfig
# 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# arch/parisc/configs/c3000_defconfig
# 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# arch/ia64/defconfig
# 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# arch/ia64/configs/zx1_defconfig
# 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# arch/ia64/configs/generic_defconfig
# 2004/03/30 20:18:33-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# arch/arm/configs/neponset_defconfig
# 2004/03/30 20:18:32-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/03/30 12:09:32-08:00 akpm@bix.(none)
# Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
# into bix.(none):/usr/src/bk-usb
#
# include/linux/usb.h
# 2004/03/30 12:09:29-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# drivers/usb/core/usb.c
# 2004/03/30 12:09:29-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# drivers/usb/core/message.c
# 2004/03/30 12:09:29-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/03/29 18:05:43-08:00 akpm@bix.(none)
# Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
#
# MAINTAINERS
# 2004/03/29 18:05:41-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/03/29 13:51:58-08:00 akpm@bix.(none)
# Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
#
# CREDITS
# 2004/03/29 13:51:56-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/03/28 12:29:41-08:00 akpm@bix.(none)
# Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
#
# drivers/usb/core/message.c
# 2004/03/28 12:29:38-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/03/27 02:28:18-08:00 akpm@bix.(none)
# Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
# into bix.(none):/usr/src/bk-usb
#
# drivers/usb/input/wacom.c
# 2004/03/27 02:28:16-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/03/26 12:24:49-08:00 akpm@bix.(none)
# Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
# into bix.(none):/usr/src/bk-usb
#
# include/linux/usb_gadget.h
# 2004/03/26 12:24:46-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# drivers/usb/core/usb.c
# 2004/03/26 12:24:46-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/03/20 13:26:55-08:00 akpm@bix.(none)
# Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
#
# CREDITS
# 2004/03/20 13:26:53-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/03/16 21:53:42-08:00 akpm@bix.(none)
# Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
#
# drivers/usb/input/wacom.c
# 2004/03/16 21:53:39-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# drivers/usb/input/hid-core.c
# 2004/03/16 21:53:39-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/03/16 12:59:58-08:00 akpm@bix.(none)
# Merge bk://kernel.bkbits.net/gregkh/linux/usb-2.6
# into bix.(none):/usr/src/bk-usb
#
# include/linux/usb_gadget.h
# 2004/03/16 12:59:47-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# include/linux/usb.h
# 2004/03/16 12:59:47-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# drivers/usb/core/usb.c
# 2004/03/16 12:59:46-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# MAINTAINERS
# 2004/03/16 12:59:46-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# CREDITS
# 2004/03/16 12:59:46-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/03/16 12:58:57-08:00 akpm@bix.(none)
# Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
#
# drivers/usb/input/wacom.c
# 2004/03/16 12:58:47-08:00 akpm@bix.(none) +0 -4
# Auto merged
#
# drivers/usb/input/hid-core.c
# 2004/03/16 12:58:47-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# CREDITS
# 2004/03/16 12:58:46-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/03/14 11:03:00-08:00 akpm@bix.(none)
# Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
#
# include/linux/usb_gadget.h
# 2004/03/14 11:02:47-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# include/linux/usb.h
# 2004/03/14 11:02:47-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# drivers/usb/core/usb.c
# 2004/03/14 11:02:47-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# MAINTAINERS
# 2004/03/14 11:02:47-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# ChangeSet
# 2004/03/12 10:57:17-08:00 akpm@bix.(none)
# Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-usb
#
# MAINTAINERS
# 2004/03/12 10:57:02-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
# CREDITS
# 2004/03/12 10:57:01-08:00 akpm@bix.(none) +0 -0
# Auto merged
#
diff -Nru a/Documentation/usb/mtouchusb.txt b/Documentation/usb/mtouchusb.txt
--- a/Documentation/usb/mtouchusb.txt Tue May 4 22:21:21 2004
+++ b/Documentation/usb/mtouchusb.txt Tue May 4 22:21:21 2004
@@ -1,26 +1,38 @@
CHANGES
-- Created based off of scanner & INSTALL from the original touchscreen
+- 0.3 - Created based off of scanner & INSTALL from the original touchscreen
driver on freshmeat (http://freshmeat.net/projects/3mtouchscreendriver)
- Amended for linux-2.4.18, then 2.4.19
-- Complete rewrite using Linux Input in 2.6.3
+- 0.5 - Complete rewrite using Linux Input in 2.6.3
Unfortunately no calibration support at this time
+- 1.4 - Multiple changes to support the EXII 5000UC and house cleaning
+ Changed reset from standard USB dev reset to vendor reset
+ Changed data sent to host from compensated to raw coordinates
+ Eliminated vendor/product module params
+ Performed multiple successfull tests with an EXII-5010UC
-DRIVER NOTES:
+SUPPORTED HARDWARE:
+
+ All controllers have the Vendor: 0x0596 & Product: 0x0001
-Installation is simple, you only need to add Linux Input, Linux USB, and the
-driver to the kernel. The driver can also be optionally built as a module.
-If you have another MicroTouch device that you wish to experiment with
-or try using this driver with, but the Vendor and Product ID's are not
-coded in, don't despair. If the driver was compiled as a module, you can
-pass options to the driver. Simply try:
+ Controller Description Part Number
+ ------------------------------------------------------
- /sbin/modprobe mtouchusb vendor=0x#### product=0x****
+ USB Capacitive - Pearl Case 14-205 (Discontinued)
+ USB Capacitive - Black Case 14-124 (Discontinued)
+ USB Capacitive - No Case 14-206 (Discontinued)
+
+ USB Capacitive - Pearl Case EXII-5010UC
+ USB Capacitive - Black Case EXII-5030UC
+ USB Capacitive - No Case EXII-5050UC
+
+DRIVER NOTES:
-If it works, send me the iVendor & iProduct (or a patch) and I will add...
+Installation is simple, you only need to add Linux Input, Linux USB, and the
+driver to the kernel. The driver can also be optionally built as a module.
This driver appears to be one of possible 2 Linux USB Input Touchscreen
drivers. Although 3M produces a binary only driver available for
@@ -28,53 +40,28 @@
touchscreen for embedded apps using QTEmbedded, DirectFB, etc. So I feel the
logical choice is to use Linux Imput.
-A little info about the MicroTouch USB controller (14-206):
-
-Y is inverted, and the device has a total possible resolution of 0 - 65535.
-
-Y is inverted by the driver by:
+Currently there is no way to calibrate the device via this driver. Even if
+the device could be calibrated, the driver pulls to raw coordinate data from
+the controller. This means calibration must be performed within the
+userspace.
+
+The controller screen resolution is now 0 to 16384 for both X and Y reporting
+the raw touch data. This is the same for the old and new capacitive USB
+controllers.
+
+Perhaps at some point an abstract function will be placed into evdev so
+generic functions like calibrations, resets, and vendor information can be
+requested from the userspace (And the drivers would handle the vendor specific
+tasks).
- input.absmin[ABS_Y] = MTOUCHUSB_MAX_YC;
- input.absmax[ABS_Y] = MTOUCHUSB_MIN_YC;
-
-absmin & absmax are also used to scale the data, sine it is rather high
-resolution.
-
- ---------------touch screen area-----------------
- I MicroTouch (xmax,ymax) @I
- I X I
- I ########visible monitor area############## I
- I #@ (xmin,ymin) # I
- I # # I
- I # # I
- I # # I
- I # # I
- I # # I
- I Y # # I
- I # # I
- I # # I
- I # # I
- I # # I
- I # # I
- I # (xmax,ymax) @# I
- I ########################################## I
- I I
- I@ MicroTouch (xmin,ymin) I
- -------------------------------------------------
-
-Currently there is no way to calibrate the device via this driver. Perhaps
-at some point an abstract function will be placed into evdev so generic
-functions like calibrations, resets, and vendor information can be requested
-(And the drivers would handle the vendor specific tasks).
-
-ADDITIONAL INFORMATION/UPDATES:
+ADDITIONAL INFORMATION/UPDATES/X CONFIGURATION EXAMPLE:
http://groomlakelabs.com/grandamp/code/microtouch/
TODO:
Implement a control urb again to handle requests to and from the device
-such as calibration, etc.
+such as calibration, etc once/if it becomes available.
DISCLAMER:
@@ -83,3 +70,7 @@
http://www.3m.com/3MTouchSystems/downloads/
+THANKS:
+
+A huge thank you to 3M Touch Systems for the EXII-5010UC controllers for
+testing!
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS Tue May 4 22:21:21 2004
+++ b/MAINTAINERS Tue May 4 22:21:21 2004
@@ -1228,6 +1228,13 @@
L: linux-scsi@vger.kernel.org
S: Maintained
+LEGO USB Tower driver
+P: Juergen Stuber
+M: starblue@users.sourceforge.net
+L: legousb-devel@lists.sourceforge.net
+W: http://legousb.sourceforge.net/
+S: Maintained
+
LINUX FOR IBM pSERIES (RS/6000)
P: Paul Mackerras
M: paulus@au.ibm.com
diff -Nru a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
--- a/drivers/bluetooth/bfusb.c Tue May 4 22:21:21 2004
+++ b/drivers/bluetooth/bfusb.c Tue May 4 22:21:21 2004
@@ -98,14 +98,6 @@
static void bfusb_tx_complete(struct urb *urb, struct pt_regs *regs);
static void bfusb_rx_complete(struct urb *urb, struct pt_regs *regs);
-static inline void bfusb_wait_for_urb(struct urb *urb)
-{
- while (atomic_read(&urb->count) > 1) {
- current->state = TASK_UNINTERRUPTIBLE;
- schedule_timeout((5 * HZ + 999) / 1000);
- }
-}
-
static struct urb *bfusb_get_completed(struct bfusb *bfusb)
{
struct sk_buff *skb;
@@ -132,7 +124,6 @@
while ((skb = skb_dequeue(&bfusb->pending_q))) {
urb = ((struct bfusb_scb *) skb->cb)->urb;
usb_unlink_urb(urb);
- bfusb_wait_for_urb(urb);
skb_queue_tail(&bfusb->completed_q, skb);
}
diff -Nru a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
--- a/drivers/bluetooth/hci_usb.c Tue May 4 22:21:21 2004
+++ b/drivers/bluetooth/hci_usb.c Tue May 4 22:21:21 2004
@@ -342,7 +342,7 @@
static inline void hci_usb_wait_for_urb(struct urb *urb)
{
- while (atomic_read(&urb->count) > 1) {
+ while (atomic_read(&urb->kref.refcount) > 1) {
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout((5 * HZ + 999) / 1000);
}
diff -Nru a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c
--- a/drivers/isdn/hisax/st5481_b.c Tue May 4 22:21:21 2004
+++ b/drivers/isdn/hisax/st5481_b.c Tue May 4 22:21:21 2004
@@ -257,13 +257,18 @@
static int st5481_setup_b_out(struct st5481_bcs *bcs)
{
struct usb_device *dev = bcs->adapter->usb_dev;
- struct usb_host_interface *altsetting;
+ struct usb_interface *intf;
+ struct usb_host_interface *altsetting = NULL;
struct usb_host_endpoint *endpoint;
struct st5481_b_out *b_out = &bcs->b_out;
DBG(4,"");
- altsetting = &(dev->config->interface[0]->altsetting[3]);
+ intf = usb_ifnum_to_if(dev, 0);
+ if (intf)
+ altsetting = usb_altnum_to_altsetting(intf, 3);
+ if (!altsetting)
+ return -ENXIO;
// Allocate URBs and buffers for the B channel out
endpoint = &altsetting->endpoint[EP_B1_OUT - 1 + bcs->channel * 2];
diff -Nru a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c
--- a/drivers/isdn/hisax/st5481_d.c Tue May 4 22:21:21 2004
+++ b/drivers/isdn/hisax/st5481_d.c Tue May 4 22:21:21 2004
@@ -652,13 +652,18 @@
static int st5481_setup_d_out(struct st5481_adapter *adapter)
{
struct usb_device *dev = adapter->usb_dev;
- struct usb_host_interface *altsetting;
+ struct usb_interface *intf;
+ struct usb_host_interface *altsetting = NULL;
struct usb_host_endpoint *endpoint;
struct st5481_d_out *d_out = &adapter->d_out;
DBG(2,"");
- altsetting = &(dev->config->interface[0]->altsetting[3]);
+ intf = usb_ifnum_to_if(dev, 0);
+ if (intf)
+ altsetting = usb_altnum_to_altsetting(intf, 3);
+ if (!altsetting)
+ return -ENXIO;
// Allocate URBs and buffers for the D channel out
endpoint = &altsetting->endpoint[EP_D_OUT-1];
diff -Nru a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c
--- a/drivers/isdn/hisax/st5481_usb.c Tue May 4 22:21:21 2004
+++ b/drivers/isdn/hisax/st5481_usb.c Tue May 4 22:21:21 2004
@@ -244,7 +244,8 @@
struct usb_device *dev = adapter->usb_dev;
struct st5481_ctrl *ctrl = &adapter->ctrl;
struct st5481_intr *intr = &adapter->intr;
- struct usb_host_interface *altsetting;
+ struct usb_interface *intf;
+ struct usb_host_interface *altsetting = NULL;
struct usb_host_endpoint *endpoint;
int status;
struct urb *urb;
@@ -257,8 +258,11 @@
return status;
}
-
- altsetting = &(dev->config->interface[0]->altsetting[3]);
+ intf = usb_ifnum_to_if(dev, 0);
+ if (intf)
+ altsetting = usb_altnum_to_altsetting(intf, 3);
+ if (!altsetting)
+ return -ENXIO;
// Check if the config is sane
if ( altsetting->desc.bNumEndpoints != 7 ) {
diff -Nru a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
--- a/drivers/net/irda/irda-usb.c Tue May 4 22:21:21 2004
+++ b/drivers/net/irda/irda-usb.c Tue May 4 22:21:21 2004
@@ -1421,7 +1421,7 @@
}
/* Find our endpoints */
- interface = &intf->altsetting[0];
+ interface = intf->cur_altsetting;
if(!irda_usb_parse_endpoints(self, interface->endpoint,
interface->desc.bNumEndpoints)) {
ERROR("%s(), Bogus endpoints...\n", __FUNCTION__);
diff -Nru a/drivers/usb/Makefile b/drivers/usb/Makefile
--- a/drivers/usb/Makefile Tue May 4 22:21:21 2004
+++ b/drivers/usb/Makefile Tue May 4 22:21:21 2004
@@ -66,3 +66,4 @@
obj-$(CONFIG_USB_TEST) += misc/
obj-$(CONFIG_USB_TIGL) += misc/
obj-$(CONFIG_USB_USS720) += misc/
+obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
diff -Nru a/drivers/usb/core/config.c b/drivers/usb/core/config.c
--- a/drivers/usb/core/config.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/core/config.c Tue May 4 22:21:21 2004
@@ -96,19 +96,14 @@
return buffer - buffer0 + i;
}
-static void usb_free_intf(struct usb_interface *intf)
+static void usb_release_interface_cache(struct kref *ref)
{
+ struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref);
int j;
- if (intf->altsetting) {
- for (j = 0; j < intf->num_altsetting; j++) {
- struct usb_host_interface *alt = &intf->altsetting[j];
-
- kfree(alt->endpoint);
- }
- kfree(intf->altsetting);
- }
- kfree(intf);
+ for (j = 0; j < intfc->num_altsetting; j++)
+ kfree(intfc->altsetting[j].endpoint);
+ kfree(intfc);
}
static int usb_parse_interface(struct device *ddev, int cfgno,
@@ -117,7 +112,7 @@
unsigned char *buffer0 = buffer;
struct usb_interface_descriptor *d;
int inum, asnum;
- struct usb_interface *interface;
+ struct usb_interface_cache *intfc;
struct usb_host_interface *alt;
int i, n;
int len, retval;
@@ -137,16 +132,16 @@
if (inum >= config->desc.bNumInterfaces)
goto skip_to_next_interface_descriptor;
- interface = config->interface[inum];
+ intfc = config->intf_cache[inum];
asnum = d->bAlternateSetting;
- if (asnum >= interface->num_altsetting) {
+ if (asnum >= intfc->num_altsetting) {
dev_err(ddev, "config %d interface %d has an invalid "
"alternate setting number: %d but max is %d\n",
- cfgno, inum, asnum, interface->num_altsetting - 1);
+ cfgno, inum, asnum, intfc->num_altsetting - 1);
return -EINVAL;
}
- alt = &interface->altsetting[asnum];
+ alt = &intfc->altsetting[asnum];
if (alt->desc.bLength) {
dev_err(ddev, "Duplicate descriptor for config %d "
"interface %d altsetting %d\n", cfgno, inum, asnum);
@@ -210,11 +205,12 @@
int cfgno;
int nintf, nintf_orig;
int i, j, n;
- struct usb_interface *interface;
+ struct usb_interface_cache *intfc;
unsigned char *buffer2;
int size2;
struct usb_descriptor_header *header;
int len, retval;
+ u8 nalts[USB_MAXINTERFACES];
memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
if (config->desc.bDescriptorType != USB_DT_CONFIG ||
@@ -237,14 +233,7 @@
cfgno, nintf, USB_MAXINTERFACES);
config->desc.bNumInterfaces = nintf = USB_MAXINTERFACES;
}
-
- for (i = 0; i < nintf; ++i) {
- interface = config->interface[i] =
- kmalloc(sizeof(struct usb_interface), GFP_KERNEL);
- if (!interface)
- return -ENOMEM;
- memset(interface, 0, sizeof(struct usb_interface));
- }
+ memset(nalts, 0, nintf);
/* Go through the descriptors, checking their length and counting the
* number of altsettings for each interface */
@@ -277,8 +266,8 @@
cfgno, i, nintf_orig - 1);
return -EINVAL;
}
- if (i < nintf)
- ++config->interface[i]->num_altsetting;
+ if (i < nintf && nalts[i] < 255)
+ ++nalts[i];
} else if (header->bDescriptorType == USB_DT_DEVICE ||
header->bDescriptorType == USB_DT_CONFIG) {
@@ -290,29 +279,29 @@
} /* for ((buffer2 = buffer, size2 = size); ...) */
- /* Allocate the altsetting arrays */
+ /* Allocate the usb_interface_caches and altsetting arrays */
for (i = 0; i < nintf; ++i) {
- interface = config->interface[i];
- if (interface->num_altsetting > USB_MAXALTSETTING) {
+ j = nalts[i];
+ if (j > USB_MAXALTSETTING) {
dev_err(ddev, "too many alternate settings for "
"config %d interface %d: %d, "
"maximum allowed: %d\n",
- cfgno, i, interface->num_altsetting,
- USB_MAXALTSETTING);
+ cfgno, i, j, USB_MAXALTSETTING);
return -EINVAL;
}
- if (interface->num_altsetting == 0) {
+ if (j == 0) {
dev_err(ddev, "config %d has no interface number "
"%d\n", cfgno, i);
return -EINVAL;
}
- len = sizeof(*interface->altsetting) *
- interface->num_altsetting;
- interface->altsetting = kmalloc(len, GFP_KERNEL);
- if (!interface->altsetting)
+ len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j;
+ config->intf_cache[i] = intfc = kmalloc(len, GFP_KERNEL);
+ if (!intfc)
return -ENOMEM;
- memset(interface->altsetting, 0, len);
+ memset(intfc, 0, len);
+ intfc->num_altsetting = j;
+ kref_init(&intfc->ref, usb_release_interface_cache);
}
/* Skip over any Class Specific or Vendor Specific descriptors;
@@ -340,9 +329,9 @@
/* Check for missing altsettings */
for (i = 0; i < nintf; ++i) {
- interface = config->interface[i];
- for (j = 0; j < interface->num_altsetting; ++j) {
- if (!interface->altsetting[j].desc.bLength) {
+ intfc = config->intf_cache[i];
+ for (j = 0; j < intfc->num_altsetting; ++j) {
+ if (!intfc->altsetting[j].desc.bLength) {
dev_err(ddev, "config %d interface %d has no "
"altsetting %d\n", cfgno, i, j);
return -EINVAL;
@@ -374,10 +363,8 @@
struct usb_host_config *cf = &dev->config[c];
for (i = 0; i < cf->desc.bNumInterfaces; i++) {
- struct usb_interface *ifp = cf->interface[i];
-
- if (ifp)
- usb_free_intf(ifp);
+ if (cf->intf_cache[i])
+ kref_put(&cf->intf_cache[i]->ref);
}
}
kfree(dev->config);
diff -Nru a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
--- a/drivers/usb/core/devices.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/core/devices.c Tue May 4 22:21:21 2004
@@ -232,13 +232,21 @@
return start;
}
-static char *usb_dump_interface_descriptor(char *start, char *end, const struct usb_interface *iface, int setno)
+static char *usb_dump_interface_descriptor(char *start, char *end,
+ const struct usb_interface_cache *intfc,
+ const struct usb_interface *iface,
+ int setno)
{
- struct usb_interface_descriptor *desc = &iface->altsetting[setno].desc;
+ const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc;
+ char *driver_name = "";
if (start > end)
return start;
down_read(&usb_bus_type.subsys.rwsem);
+ if (iface)
+ driver_name = (iface->dev.driver
+ ? iface->dev.driver->name
+ : "(none)");
start += sprintf(start, format_iface,
desc->bInterfaceNumber,
desc->bAlternateSetting,
@@ -247,9 +255,7 @@
class_decode(desc->bInterfaceClass),
desc->bInterfaceSubClass,
desc->bInterfaceProtocol,
- iface->dev.driver
- ? iface->dev.driver->name
- : "(none)");
+ driver_name);
up_read(&usb_bus_type.subsys.rwsem);
return start;
}
@@ -258,13 +264,14 @@
int speed,
char *start,
char *end,
+ const struct usb_interface_cache *intfc,
const struct usb_interface *iface,
int setno
) {
- struct usb_host_interface *desc = &iface->altsetting[setno];
+ const struct usb_host_interface *desc = &intfc->altsetting[setno];
int i;
- start = usb_dump_interface_descriptor(start, end, iface, setno);
+ start = usb_dump_interface_descriptor(start, end, intfc, iface, setno);
for (i = 0; i < desc->desc.bNumEndpoints; i++) {
if (start > end)
return start;
@@ -303,6 +310,7 @@
)
{
int i, j;
+ struct usb_interface_cache *intfc;
struct usb_interface *interface;
if (start > end)
@@ -311,14 +319,13 @@
return start + sprintf(start, "(null Cfg. desc.)\n");
start = usb_dump_config_descriptor(start, end, &config->desc, active);
for (i = 0; i < config->desc.bNumInterfaces; i++) {
+ intfc = config->intf_cache[i];
interface = config->interface[i];
- if (!interface)
- break;
- for (j = 0; j < interface->num_altsetting; j++) {
+ for (j = 0; j < intfc->num_altsetting; j++) {
if (start > end)
return start;
start = usb_dump_interface(speed,
- start, end, interface, j);
+ start, end, intfc, interface, j);
}
}
return start;
@@ -395,7 +402,7 @@
return start;
start = usb_dump_device_strings (start, end, dev);
-
+
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
if (start > end)
return start;
@@ -445,6 +452,7 @@
* nbytes - the maximum number of bytes to write
* skip_bytes - the number of bytes to skip before writing anything
* file_offset - the offset into the devices file on completion
+ * The caller must own the usbdev->serialize semaphore.
*/
static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *skip_bytes, loff_t *file_offset,
struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count)
@@ -545,9 +553,13 @@
/* Now look at all of this device's children. */
for (chix = 0; chix < usbdev->maxchild; chix++) {
- if (usbdev->children[chix]) {
- ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, usbdev->children[chix],
+ struct usb_device *childdev = usbdev->children[chix];
+
+ if (childdev) {
+ down(&childdev->serialize);
+ ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, childdev,
bus, level + 1, chix, ++cnt);
+ up(&childdev->serialize);
if (ret == -EFAULT)
return total_written;
total_written += ret;
@@ -575,8 +587,11 @@
for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) {
/* print devices for this bus */
bus = list_entry(buslist, struct usb_bus, bus_list);
+
/* recurse through all children of the root hub */
+ down(&bus->root_hub->serialize);
ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0);
+ up(&bus->root_hub->serialize);
if (ret < 0) {
up(&usb_bus_list_lock);
return ret;
diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
--- a/drivers/usb/core/devio.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/core/devio.c Tue May 4 22:21:21 2004
@@ -60,6 +60,11 @@
struct urb *urb;
};
+static inline int connected (struct usb_device *dev)
+{
+ return dev->state != USB_STATE_NOTATTACHED;
+}
+
static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
{
loff_t ret;
@@ -87,14 +92,15 @@
static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
struct dev_state *ps = (struct dev_state *)file->private_data;
+ struct usb_device *dev = ps->dev;
ssize_t ret = 0;
unsigned len;
loff_t pos;
int i;
pos = *ppos;
- down_read(&ps->devsem);
- if (!ps->dev) {
+ down(&dev->serialize);
+ if (!connected(dev)) {
ret = -ENODEV;
goto err;
} else if (pos < 0) {
@@ -106,7 +112,7 @@
len = sizeof(struct usb_device_descriptor) - pos;
if (len > nbytes)
len = nbytes;
- if (copy_to_user(buf, ((char *)&ps->dev->descriptor) + pos, len)) {
+ if (copy_to_user(buf, ((char *)&dev->descriptor) + pos, len)) {
ret = -EFAULT;
goto err;
}
@@ -118,9 +124,9 @@
}
pos = sizeof(struct usb_device_descriptor);
- for (i = 0; nbytes && i < ps->dev->descriptor.bNumConfigurations; i++) {
+ for (i = 0; nbytes && i < dev->descriptor.bNumConfigurations; i++) {
struct usb_config_descriptor *config =
- (struct usb_config_descriptor *)ps->dev->rawdescriptors[i];
+ (struct usb_config_descriptor *)dev->rawdescriptors[i];
unsigned int length = le16_to_cpu(config->wTotalLength);
if (*ppos < pos + length) {
@@ -128,7 +134,7 @@
/* The descriptor may claim to be longer than it
* really is. Here is the actual allocated length. */
unsigned alloclen =
- ps->dev->config[i].desc.wTotalLength;
+ dev->config[i].desc.wTotalLength;
len = length - (*ppos - pos);
if (len > nbytes)
@@ -138,7 +144,7 @@
if (alloclen > (*ppos - pos)) {
alloclen -= (*ppos - pos);
if (copy_to_user(buf,
- ps->dev->rawdescriptors[i] + (*ppos - pos),
+ dev->rawdescriptors[i] + (*ppos - pos),
min(len, alloclen))) {
ret = -EFAULT;
goto err;
@@ -155,35 +161,10 @@
}
err:
- up_read(&ps->devsem);
+ up(&dev->serialize);
return ret;
}
-extern inline unsigned int ld2(unsigned int x)
-{
- unsigned int r = 0;
-
- if (x >= 0x10000) {
- x >>= 16;
- r += 16;
- }
- if (x >= 0x100) {
- x >>= 8;
- r += 8;
- }
- if (x >= 0x10) {
- x >>= 4;
- r += 4;
- }
- if (x >= 4) {
- x >>= 2;
- r += 2;
- }
- if (x >= 2)
- r++;
- return r;
-}
-
/*
* async list handling
*/
@@ -213,7 +194,7 @@
kfree(as);
}
-extern __inline__ void async_newpending(struct async *as)
+static inline void async_newpending(struct async *as)
{
struct dev_state *ps = as->ps;
unsigned long flags;
@@ -223,7 +204,7 @@
spin_unlock_irqrestore(&ps->lock, flags);
}
-extern __inline__ void async_removepending(struct async *as)
+static inline void async_removepending(struct async *as)
{
struct dev_state *ps = as->ps;
unsigned long flags;
@@ -233,7 +214,7 @@
spin_unlock_irqrestore(&ps->lock, flags);
}
-extern __inline__ struct async *async_getcompleted(struct dev_state *ps)
+static inline struct async *async_getcompleted(struct dev_state *ps)
{
unsigned long flags;
struct async *as = NULL;
@@ -247,7 +228,7 @@
return as;
}
-extern __inline__ struct async *async_getpending(struct dev_state *ps, void __user *userurb)
+static inline struct async *async_getpending(struct dev_state *ps, void __user *userurb)
{
unsigned long flags;
struct async *as;
@@ -315,7 +296,7 @@
destroy_async(ps, &hitlist);
}
-extern __inline__ void destroy_all_async(struct dev_state *ps)
+static inline void destroy_all_async(struct dev_state *ps)
{
destroy_async(ps, &ps->async_pending);
}
@@ -335,6 +316,7 @@
static void driver_disconnect(struct usb_interface *intf)
{
struct dev_state *ps = usb_get_intfdata (intf);
+ unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber;
if (!ps)
return;
@@ -343,13 +325,15 @@
* all pending I/O requests; 2.6 does that.
*/
- /* prevent new I/O requests */
- ps->dev = 0;
- clear_bit(intf->cur_altsetting->desc.bInterfaceNumber, &ps->ifclaimed);
+ if (likely(ifnum < 8*sizeof(ps->ifclaimed)))
+ clear_bit(ifnum, &ps->ifclaimed);
+ else
+ warn("interface number %u out of range", ifnum);
+
usb_set_intfdata (intf, NULL);
/* force async requests to complete */
- destroy_all_async (ps);
+ destroy_async_on_interface(ps, ifnum);
}
struct usb_driver usbdevfs_driver = {
@@ -365,7 +349,7 @@
struct usb_interface *iface;
int err;
- if (intf >= 8*sizeof(ps->ifclaimed) || !dev
+ if (intf >= 8*sizeof(ps->ifclaimed)
|| intf >= dev->actconfig->desc.bNumInterfaces)
return -EINVAL;
/* already claimed */
@@ -395,7 +379,6 @@
return -EINVAL;
err = -EINVAL;
dev = ps->dev;
- down(&dev->serialize);
/* lock against other changes to driver bindings */
down_write(&usb_bus_type.subsys.rwsem);
if (test_and_clear_bit(intf, &ps->ifclaimed)) {
@@ -404,7 +387,6 @@
err = 0;
}
up_write(&usb_bus_type.subsys.rwsem);
- up(&dev->serialize);
return err;
}
@@ -506,7 +488,7 @@
lock_kernel();
ret = -ENOENT;
- dev = inode->u.generic_ip;
+ dev = usb_get_dev(inode->u.generic_ip);
if (!dev) {
kfree(ps);
goto out;
@@ -518,7 +500,6 @@
INIT_LIST_HEAD(&ps->async_pending);
INIT_LIST_HEAD(&ps->async_completed);
init_waitqueue_head(&ps->wait);
- init_rwsem(&ps->devsem);
ps->discsignr = 0;
ps->disctask = current;
ps->disccontext = NULL;
@@ -535,18 +516,21 @@
static int usbdev_release(struct inode *inode, struct file *file)
{
struct dev_state *ps = (struct dev_state *)file->private_data;
+ struct usb_device *dev = ps->dev;
unsigned int i;
- lock_kernel();
+ down(&dev->serialize);
list_del_init(&ps->list);
- if (ps->dev) {
+ if (connected(dev)) {
for (i = 0; ps->ifclaimed && i < 8*sizeof(ps->ifclaimed); i++)
if (test_bit(i, &ps->ifclaimed))
releaseintf(ps, i);
+ destroy_all_async(ps);
}
- unlock_kernel();
- destroy_all_async(ps);
+ up(&dev->serialize);
+ usb_put_dev(dev);
+ ps->dev = NULL;
kfree(ps);
return 0;
}
@@ -702,13 +686,15 @@
return -EFAULT;
if ((ret = findintfif(ps->dev, gd.interface)) < 0)
return ret;
+ down_read(&usb_bus_type.subsys.rwsem);
interface = ps->dev->actconfig->interface[ret];
- if (!interface->dev.driver)
+ if (!interface || !interface->dev.driver) {
+ up_read(&usb_bus_type.subsys.rwsem);
return -ENODATA;
+ }
strncpy(gd.driver, interface->dev.driver->name, sizeof(gd.driver));
- if (copy_to_user(arg, &gd, sizeof(gd)))
- return -EFAULT;
- return 0;
+ up_read(&usb_bus_type.subsys.rwsem);
+ return copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0;
}
static int proc_connectinfo(struct dev_state *ps, void __user *arg)
@@ -724,9 +710,6 @@
static int proc_resetdevice(struct dev_state *ps)
{
- /* FIXME when usb_reset_device() is fixed we'll need to grab
- * ps->dev->serialize before calling it.
- */
return usb_reset_device(ps->dev);
}
@@ -742,10 +725,8 @@
if ((ret = findintfif(ps->dev, setintf.interface)) < 0)
return ret;
interface = ps->dev->actconfig->interface[ret];
- if (interface->dev.driver) {
- if ((ret = checkintf(ps, ret)))
- return ret;
- }
+ if ((ret = checkintf(ps, ret)))
+ return ret;
if (usb_set_interface(ps->dev, setintf.interface, setintf.altsetting))
return -EINVAL;
return 0;
@@ -760,7 +741,6 @@
if (get_user(u, (unsigned int __user *)arg))
return -EFAULT;
- down(&ps->dev->serialize);
actconfig = ps->dev->actconfig;
/* Don't touch the device if any interfaces are claimed.
@@ -796,7 +776,6 @@
else
status = usb_set_configuration(ps->dev, u);
}
- up(&ps->dev->serialize);
return status;
}
@@ -873,6 +852,9 @@
/* arbitrary limit */
if (uurb.number_of_packets < 1 || uurb.number_of_packets > 128)
return -EINVAL;
+ if (!(ep_desc = usb_epnum_to_ep_desc(ps->dev, uurb.endpoint)))
+ return -ENOENT;
+ interval = 1 << min (15, ep_desc->bInterval - 1);
isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb.number_of_packets;
if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
return -ENOMEM;
@@ -898,7 +880,10 @@
uurb.number_of_packets = 0;
if (!(ep_desc = usb_epnum_to_ep_desc(ps->dev, uurb.endpoint)))
return -ENOENT;
- interval = ep_desc->bInterval;
+ if (ps->dev->speed == USB_SPEED_HIGH)
+ interval = 1 << min (15, ep_desc->bInterval - 1);
+ else
+ interval = ep_desc->bInterval;
if (uurb.buffer_length > 16384)
return -EINVAL;
if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length))
@@ -1012,18 +997,19 @@
DECLARE_WAITQUEUE(wait, current);
struct async *as = NULL;
void __user *addr;
+ struct usb_device *dev = ps->dev;
int ret;
add_wait_queue(&ps->wait, &wait);
- while (ps->dev) {
+ while (connected(dev)) {
__set_current_state(TASK_INTERRUPTIBLE);
if ((as = async_getcompleted(ps)))
break;
if (signal_pending(current))
break;
- up_read(&ps->devsem);
+ up(&dev->serialize);
schedule();
- down_read(&ps->devsem);
+ down(&dev->serialize);
}
remove_wait_queue(&ps->wait, &wait);
set_current_state(TASK_RUNNING);
@@ -1125,13 +1111,12 @@
}
}
- if (!ps->dev) {
+ if (!connected(ps->dev)) {
if (buf)
kfree(buf);
return -ENODEV;
}
- down(&ps->dev->serialize);
if (ps->dev->state != USB_STATE_CONFIGURED)
retval = -ENODEV;
else if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
@@ -1169,7 +1154,6 @@
}
up_read(&usb_bus_type.subsys.rwsem);
}
- up(&ps->dev->serialize);
/* cleanup and return */
if (retval >= 0
@@ -1190,13 +1174,14 @@
static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
struct dev_state *ps = (struct dev_state *)file->private_data;
+ struct usb_device *dev = ps->dev;
int ret = -ENOTTY;
if (!(file->f_mode & FMODE_WRITE))
return -EPERM;
- down_read(&ps->devsem);
- if (!ps->dev) {
- up_read(&ps->devsem);
+ down(&dev->serialize);
+ if (!connected(dev)) {
+ up(&dev->serialize);
return -ENODEV;
}
switch (cmd) {
@@ -1278,7 +1263,7 @@
ret = proc_ioctl(ps, (void __user *) arg);
break;
}
- up_read(&ps->devsem);
+ up(&dev->serialize);
if (ret >= 0)
inode->i_atime = CURRENT_TIME;
return ret;
@@ -1293,7 +1278,7 @@
poll_wait(file, &ps->wait, wait);
if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed))
mask |= POLLOUT | POLLWRNORM;
- if (!ps->dev)
+ if (!connected(ps->dev))
mask |= POLLERR | POLLHUP;
return mask;
}
diff -Nru a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
--- a/drivers/usb/core/hcd-pci.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/core/hcd-pci.c Tue May 4 22:21:21 2004
@@ -293,7 +293,7 @@
case USB_STATE_HALT:
dev_dbg (hcd->self.controller, "halted; hcd not suspended\n");
break;
- case USB_STATE_SUSPENDED:
+ case HCD_STATE_SUSPENDED:
dev_dbg (hcd->self.controller, "hcd already suspended\n");
break;
default:
@@ -310,7 +310,7 @@
"suspend fail, retval %d\n",
retval);
else
- hcd->state = USB_STATE_SUSPENDED;
+ hcd->state = HCD_STATE_SUSPENDED;
}
pci_set_power_state (dev, state);
@@ -333,7 +333,7 @@
dev_dbg (hcd->self.controller, "resume from state D%d\n",
dev->current_state);
- if (hcd->state != USB_STATE_SUSPENDED) {
+ if (hcd->state != HCD_STATE_SUSPENDED) {
dev_dbg (hcd->self.controller,
"can't resume, not suspended!\n");
return -EL3HLT;
diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/core/hcd.c Tue May 4 22:21:21 2004
@@ -171,10 +171,10 @@
0x01, /* __u8 bNumInterfaces; (1) */
0x01, /* __u8 bConfigurationValue; */
0x00, /* __u8 iConfiguration; */
- 0x40, /* __u8 bmAttributes;
- Bit 7: Bus-powered,
+ 0xc0, /* __u8 bmAttributes;
+ Bit 7: must be set,
6: Self-powered,
- 5 Remote-wakwup,
+ 5: Remote wakeup,
4..0: resvd */
0x00, /* __u8 MaxPower; */
@@ -218,10 +218,10 @@
0x01, /* __u8 bNumInterfaces; (1) */
0x01, /* __u8 bConfigurationValue; */
0x00, /* __u8 iConfiguration; */
- 0x40, /* __u8 bmAttributes;
- Bit 7: Bus-powered,
+ 0xc0, /* __u8 bmAttributes;
+ Bit 7: must be set,
6: Self-powered,
- 5 Remote-wakwup,
+ 5: Remote wakeup,
4..0: resvd */
0x00, /* __u8 MaxPower; */
@@ -324,13 +324,15 @@
/* Root hub control transfers execute synchronously */
static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
{
- struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
+ struct usb_ctrlrequest *cmd;
u16 typeReq, wValue, wIndex, wLength;
const u8 *bufp = 0;
u8 *ubuf = urb->transfer_buffer;
int len = 0;
+ int patch_wakeup = 0;
unsigned long flags;
+ cmd = (struct usb_ctrlrequest *) urb->setup_packet;
typeReq = (cmd->bRequestType << 8) | cmd->bRequest;
wValue = le16_to_cpu (cmd->wValue);
wIndex = le16_to_cpu (cmd->wIndex);
@@ -347,13 +349,21 @@
/* DEVICE REQUESTS */
case DeviceRequest | USB_REQ_GET_STATUS:
- // DEVICE_REMOTE_WAKEUP
- ubuf [0] = 1; // selfpowered
+ ubuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP)
+ | (1 << USB_DEVICE_SELF_POWERED);
ubuf [1] = 0;
- /* FALLTHROUGH */
+ break;
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
+ if (wValue == USB_DEVICE_REMOTE_WAKEUP)
+ hcd->remote_wakeup = 0;
+ else
+ goto error;
+ break;
case DeviceOutRequest | USB_REQ_SET_FEATURE:
- dev_dbg (hcd->self.controller, "no device features yet yet\n");
+ if (hcd->can_wakeup && wValue == USB_DEVICE_REMOTE_WAKEUP)
+ hcd->remote_wakeup = 1;
+ else
+ goto error;
break;
case DeviceRequest | USB_REQ_GET_CONFIGURATION:
ubuf [0] = 1;
@@ -379,6 +389,8 @@
bufp = fs_rh_config_descriptor;
len = sizeof fs_rh_config_descriptor;
}
+ if (hcd->can_wakeup)
+ patch_wakeup = 1;
break;
case USB_DT_STRING << 8:
urb->actual_length = rh_string (
@@ -444,6 +456,11 @@
urb->actual_length = len;
// always USB_DIR_IN, toward host
memcpy (ubuf, bufp, len);
+
+ /* report whether RH hardware supports remote wakeup */
+ if (patch_wakeup)
+ ((struct usb_config_descriptor *)ubuf)->bmAttributes
+ |= USB_CONFIG_ATT_WAKEUP;
}
/* any errors get returned through the urb completion */
@@ -762,10 +779,22 @@
set_bit (devnum, usb_dev->bus->devmap.devicemap);
usb_dev->state = USB_STATE_ADDRESS;
+ usb_dev->epmaxpacketin[0] = usb_dev->epmaxpacketout[0] = 64;
+ retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
+ if (retval != sizeof usb_dev->descriptor) {
+ dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
+ usb_dev->dev.bus_id, retval);
+ return (retval < 0) ? retval : -EMSGSIZE;
+ }
+
+ (void) usb_get_dev (usb_dev);
+ down (&usb_dev->serialize);
retval = usb_new_device (usb_dev);
if (retval)
dev_err (parent_dev, "can't register root hub for %s, %d\n",
usb_dev->dev.bus_id, retval);
+ up (&usb_dev->serialize);
+ usb_put_dev (usb_dev);
return retval;
}
EXPORT_SYMBOL (usb_register_root_hub);
diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
--- a/drivers/usb/core/hcd.h Tue May 4 22:21:21 2004
+++ b/drivers/usb/core/hcd.h Tue May 4 22:21:21 2004
@@ -74,6 +74,8 @@
*/
struct hc_driver *driver; /* hw-specific hooks */
unsigned saw_irq : 1;
+ unsigned can_wakeup:1; /* hw supports wakeup? */
+ unsigned remote_wakeup:1;/* sw should use wakeup? */
int irq; /* irq allocated */
void *regs; /* device memory/io */
@@ -94,7 +96,7 @@
# define USB_STATE_RUNNING (__ACTIVE)
# define USB_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE)
# define USB_STATE_RESUMING (__SUSPEND|__TRANSIENT)
-# define USB_STATE_SUSPENDED (__SUSPEND)
+# define HCD_STATE_SUSPENDED (__SUSPEND)
#define HCD_IS_RUNNING(state) ((state) & __ACTIVE)
#define HCD_IS_SUSPENDED(state) ((state) & __SUSPEND)
@@ -344,9 +346,16 @@
extern int usb_register_root_hub (struct usb_device *usb_dev,
struct device *parent_dev);
-/* for portability to 2.4, hcds should call this */
static inline int hcd_register_root (struct usb_hcd *hcd)
{
+ /* hcd->driver->start() reported can_wakeup, probably with
+ * assistance from board's boot firmware.
+ * NOTE: normal devices won't enable wakeup by default.
+ */
+ if (hcd->can_wakeup)
+ dev_dbg (hcd->self.controller, "supports USB remote wakeup\n");
+ hcd->remote_wakeup = hcd->can_wakeup;
+
return usb_register_root_hub (
hcd_to_bus (hcd)->root_hub, hcd->self.controller);
}
diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/core/hub.c Tue May 4 22:21:21 2004
@@ -373,12 +373,13 @@
struct usb_device *dev;
int i;
- /* Enable power to the ports */
- dev_dbg(hubdev(interface_to_usbdev(hub->intf)),
- "enabling power on all ports\n");
- dev = interface_to_usbdev(hub->intf);
- for (i = 0; i < hub->descriptor->bNbrPorts; i++)
- set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
+ /* if hub supports power switching, enable power on each port */
+ if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) < 2) {
+ dev_dbg(&hub->intf->dev, "enabling power on all ports\n");
+ dev = interface_to_usbdev(hub->intf);
+ for (i = 0; i < hub->descriptor->bNbrPorts; i++)
+ set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
+ }
/* Wait for power to be enabled */
wait_ms(hub->descriptor->bPwrOn2PwrGood * 2);
@@ -545,8 +546,25 @@
dev_dbg(hub_dev, "power on to power good time: %dms\n",
hub->descriptor->bPwrOn2PwrGood * 2);
- dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
- hub->descriptor->bHubContrCurrent);
+
+ /* power budgeting mostly matters with bus-powered hubs,
+ * and battery-powered root hubs (may provide just 8 mA).
+ */
+ ret = usb_get_status(dev, USB_RECIP_DEVICE, 0, &hubstatus);
+ if (ret < 0) {
+ message = "can't get hubdev status";
+ goto fail;
+ }
+ cpu_to_le16s(&hubstatus);
+ if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
+ dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
+ hub->descriptor->bHubContrCurrent);
+ hub->power_budget = (501 - hub->descriptor->bHubContrCurrent)
+ / 2;
+ dev_dbg(hub_dev, "%dmA bus power budget for children\n",
+ hub->power_budget * 2);
+ }
+
ret = hub_hub_status(hub, &hubstatus, &hubchange);
if (ret < 0) {
@@ -554,12 +572,11 @@
goto fail;
}
- /* FIXME implement per-port power budgeting;
- * enable it for bus-powered hubs.
- */
- dev_dbg(hub_dev, "local power source is %s\n",
- (hubstatus & HUB_STATUS_LOCAL_POWER)
- ? "lost (inactive)" : "good");
+ /* local power status reports aren't always correct */
+ if (dev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_SELFPOWER)
+ dev_dbg(hub_dev, "local power source is %s\n",
+ (hubstatus & HUB_STATUS_LOCAL_POWER)
+ ? "lost (inactive)" : "good");
if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) == 0)
dev_dbg(hub_dev, "%sover-current condition exists\n",
@@ -611,6 +628,8 @@
return ret;
}
+static unsigned highspeed_hubs;
+
static void hub_disconnect(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata (intf);
@@ -620,6 +639,9 @@
if (!hub)
return;
+ if (interface_to_usbdev(intf)->speed == USB_SPEED_HIGH)
+ highspeed_hubs--;
+
usb_set_intfdata (intf, NULL);
spin_lock_irqsave(&hub_event_lock, flags);
hub->urb_complete = &urb_complete;
@@ -731,6 +753,9 @@
usb_set_intfdata (intf, hub);
+ if (dev->speed == USB_SPEED_HIGH)
+ highspeed_hubs++;
+
if (hub_configure(hub, endpoint) >= 0)
return 0;
@@ -841,8 +866,11 @@
return ret;
}
-#define HUB_RESET_TRIES 5
-#define HUB_PROBE_TRIES 2
+#define PORT_RESET_TRIES 5
+#define SET_ADDRESS_TRIES 2
+#define GET_DESCRIPTOR_TRIES 2
+#define SET_CONFIG_TRIES 2
+
#define HUB_ROOT_RESET_TIME 50 /* times are in msec */
#define HUB_SHORT_RESET_TIME 10
#define HUB_LONG_RESET_TIME 200
@@ -907,7 +935,7 @@
int i, status;
/* Reset the port */
- for (i = 0; i < HUB_RESET_TRIES; i++) {
+ for (i = 0; i < PORT_RESET_TRIES; i++) {
set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
/* return on disconnect or reset */
@@ -1003,40 +1031,20 @@
return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1;
}
-static void hub_port_connect_change(struct usb_hub *hubstate, int port,
- u16 portstatus, u16 portchange)
+/* reset device, (re)assign address, get device descriptor.
+ * device connection is stable, no more debouncing needed.
+ * returns device in USB_STATE_ADDRESS, except on error.
+ * on error return, device is no longer usable (ref dropped).
+ *
+ * caller owns dev->serialize for the device, guarding against
+ * config changes and disconnect processing.
+ */
+static int
+hub_port_init (struct usb_device *hub, struct usb_device *dev, int port)
{
- struct usb_device *hub = interface_to_usbdev(hubstate->intf);
- struct usb_device *dev;
- unsigned int delay = HUB_SHORT_RESET_TIME;
- int i;
-
- dev_dbg (&hubstate->intf->dev,
- "port %d, status %x, change %x, %s\n",
- port + 1, portstatus, portchange, portspeed (portstatus));
-
- /* Clear the connection change status */
- clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);
-
- /* Disconnect any existing devices under this port */
- if (hub->children[port])
- usb_disconnect(&hub->children[port]);
-
- /* Return now if nothing is connected */
- if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
- if (portstatus & USB_PORT_STAT_ENABLE)
- hub_port_disable(hub, port);
-
- return;
- }
-
- if (hub_port_debounce(hub, port)) {
- dev_err (&hubstate->intf->dev,
- "connect-debounce failed, port %d disabled\n",
- port+1);
- hub_port_disable(hub, port);
- return;
- }
+ int i, j, retval = -ENODEV;
+ unsigned delay = HUB_SHORT_RESET_TIME;
+ enum usb_device_speed oldspeed = dev->speed;
/* root hub ports have a slightly longer reset period
* (from USB 2.0 spec, section 7.1.7.5)
@@ -1046,31 +1054,53 @@
/* Some low speed devices have problems with the quick delay, so */
/* be a bit pessimistic with those devices. RHbug #23670 */
- if (portstatus & USB_PORT_STAT_LOW_SPEED)
+ if (oldspeed == USB_SPEED_LOW)
delay = HUB_LONG_RESET_TIME;
down(&usb_address0_sem);
- for (i = 0; i < HUB_PROBE_TRIES; i++) {
-
- /* Allocate a new device struct */
- dev = usb_alloc_dev(hub, hub->bus, port);
- if (!dev) {
- dev_err (&hubstate->intf->dev,
- "couldn't allocate usb_device\n");
- break;
- }
-
- dev->state = USB_STATE_POWERED;
-
- /* Reset the device, and detect its speed */
- if (hub_port_reset(hub, port, dev, delay)) {
- usb_put_dev(dev);
- break;
- }
-
- /* Find a new address for it */
+ /* Reset the device; full speed may morph to high speed */
+ switch (hub_port_reset(hub, port, dev, delay)) {
+ case 0: /* success, speed is known */
+ break;
+ case 1: /* disconnect, give to companion */
+ retval = -EBUSY;
+ /* FALL THROUGH */
+ default: /* error */
+ goto fail;
+ }
+ if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != dev->speed) {
+ dev_dbg(&dev->dev, "device reset changed speed!\n");
+ goto fail;
+ }
+
+ /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
+ * it's fixed size except for full speed devices.
+ */
+ switch (dev->speed) {
+ case USB_SPEED_HIGH: /* fixed at 64 */
+ i = 64;
+ break;
+ case USB_SPEED_FULL: /* 8, 16, 32, or 64 */
+ /* to determine the ep0 maxpacket size, read the first 8
+ * bytes from the device descriptor to get bMaxPacketSize0;
+ * then correct our initial (small) guess.
+ */
+ // FALLTHROUGH
+ case USB_SPEED_LOW: /* fixed at 8 */
+ i = 8;
+ break;
+ default:
+ goto fail;
+ }
+ dev->epmaxpacketin [0] = i;
+ dev->epmaxpacketout[0] = i;
+
+ /* set the address */
+ if (dev->devnum <= 0) {
usb_choose_address(dev);
+ if (dev->devnum <= 0)
+ goto fail;
/* Set up TT records, if needed */
if (hub->tt) {
@@ -1078,12 +1108,21 @@
dev->ttport = hub->ttport;
} else if (dev->speed != USB_SPEED_HIGH
&& hub->speed == USB_SPEED_HIGH) {
+ struct usb_hub *hubstate;
+
+ hubstate = usb_get_intfdata (hub->actconfig
+ ->interface[0]);
dev->tt = &hubstate->tt;
dev->ttport = port + 1;
}
- dev_info (&dev->dev,
- "new %s speed USB device using address %d\n",
+ /* force the right log message (below) at low speed */
+ oldspeed = USB_SPEED_UNKNOWN;
+ }
+
+ dev_info (&dev->dev,
+ "%s %s speed USB device using address %d\n",
+ (oldspeed == USB_SPEED_UNKNOWN) ? "new" : "reset",
({ char *speed; switch (dev->speed) {
case USB_SPEED_LOW: speed = "low"; break;
case USB_SPEED_FULL: speed = "full"; break;
@@ -1091,23 +1130,258 @@
default: speed = "?"; break;
}; speed;}),
dev->devnum);
+
+ /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?
+ * Because device hardware and firmware is sometimes buggy in
+ * this area, and this is how Linux has done it for ages.
+ * Change it cautiously.
+ *
+ * NOTE: Windows gets the descriptor first, seemingly to help
+ * work around device bugs like "can't use addresses with bit 3
+ * set in certain configurations". Yes, really.
+ */
+ for (i = 0; i < GET_DESCRIPTOR_TRIES; ++i) {
+ for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
+ retval = usb_set_address(dev);
+ if (retval >= 0)
+ break;
+ wait_ms(200);
+ }
+ if (retval < 0) {
+ dev_err(&dev->dev,
+ "device not accepting address %d, error %d\n",
+ dev->devnum, retval);
+ fail:
+ hub_port_disable(hub, port);
+ clear_bit(dev->devnum, dev->bus->devmap.devicemap);
+ dev->devnum = -1;
+ usb_put_dev(dev);
+ up(&usb_address0_sem);
+ return retval;
+ }
+
+ /* cope with hardware quirkiness:
+ * - let SET_ADDRESS settle, some device hardware wants it
+ * - read ep0 maxpacket even for high and low speed,
+ */
+ wait_ms(10);
+ retval = usb_get_device_descriptor(dev, 8);
+ if (retval >= 8)
+ break;
+ wait_ms(100);
+ }
+ if (retval != 8) {
+ dev_err(&dev->dev, "device descriptor read/%s, error %d\n",
+ "8", retval);
+ if (retval >= 0)
+ retval = -EMSGSIZE;
+ goto fail;
+ }
+ if (dev->speed == USB_SPEED_FULL
+ && (dev->epmaxpacketin [0]
+ != dev->descriptor.bMaxPacketSize0)) {
+ usb_disable_endpoint(dev, 0);
+ usb_endpoint_running(dev, 0, 1);
+ usb_endpoint_running(dev, 0, 0);
+ dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
+ dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
+ }
+
+ retval = usb_get_device_descriptor(dev, USB_DT_DEVICE_SIZE);
+ if (retval < (signed)sizeof(dev->descriptor)) {
+ dev_err(&dev->dev, "device descriptor read/%s, error %d\n",
+ "all", retval);
+ if (retval >= 0)
+ retval = -ENOMSG;
+ goto fail;
+ }
- /* Run it through the hoops (find a driver, etc) */
- if (usb_new_device(dev) == 0) {
- hub->children[port] = dev;
- goto done;
+ /* now dev is visible to other tasks */
+ hub->children[port] = dev;
+
+ up(&usb_address0_sem);
+ return 0;
+}
+
+static void
+check_highspeed (struct usb_hub *hub, struct usb_device *dev, int port)
+{
+ struct usb_qualifier_descriptor *qual;
+ int status;
+
+ qual = kmalloc (sizeof *qual, SLAB_KERNEL);
+ if (qual == 0)
+ return;
+
+ status = usb_get_descriptor (dev, USB_DT_DEVICE_QUALIFIER, 0,
+ qual, sizeof *qual);
+ if (status == sizeof *qual) {
+ dev_info(&dev->dev, "not running at top speed; "
+ "connect to a high speed hub\n");
+ /* hub LEDs are probably harder to miss than syslog */
+ if (hub->has_indicators) {
+ hub->indicator[port] = INDICATOR_GREEN_BLINK;
+ schedule_work (&hub->leds);
}
+ }
+ kfree (qual);
+}
- /* Free the configuration if there was an error */
- usb_put_dev(dev);
+static unsigned
+hub_power_remaining (struct usb_hub *hubstate, struct usb_device *hub)
+{
+ int remaining;
+ unsigned i;
- /* Switch to a long reset time */
- delay = HUB_LONG_RESET_TIME;
+ remaining = hubstate->power_budget;
+ if (!remaining) /* self-powered */
+ return 0;
+
+ for (i = 0; i < hub->maxchild; i++) {
+ struct usb_device *dev = hub->children[i];
+ int delta;
+
+ if (!dev)
+ continue;
+
+ if (dev->actconfig)
+ delta = dev->actconfig->desc.bMaxPower;
+ else
+ delta = 50;
+ // dev_dbg(&dev->dev, "budgeted %dmA\n", 2 * delta);
+ remaining -= delta;
+ }
+ if (remaining < 0) {
+ dev_warn(&hubstate->intf->dev,
+ "%dmA over power budget!\n",
+ -2 * remaining);
+ remaining = 0;
}
+ return remaining;
+}
+
+static void hub_port_connect_change(struct usb_hub *hubstate, int port,
+ u16 portstatus, u16 portchange)
+{
+ struct usb_device *hub = interface_to_usbdev(hubstate->intf);
+ int status, i;
+
+ dev_dbg (&hubstate->intf->dev,
+ "port %d, status %04x, change %04x, %s\n",
+ port + 1, portstatus, portchange, portspeed (portstatus));
+
+ /* Clear the connection change status */
+ clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);
- hub_port_disable(hub, port);
+ if (hubstate->has_indicators) {
+ set_port_led(hub, hubstate, port + 1, HUB_LED_AUTO);
+ hubstate->indicator[port] = INDICATOR_AUTO;
+ }
+
+ /* Disconnect any existing devices under this port */
+ if (hub->children[port])
+ usb_disconnect(&hub->children[port]);
+
+ /* Return now if nothing is connected */
+ if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
+ if (portstatus & USB_PORT_STAT_ENABLE)
+ goto done;
+ return;
+ }
+
+ if (hub_port_debounce(hub, port)) {
+ dev_err (&hubstate->intf->dev,
+ "connect-debounce failed, port %d disabled\n",
+ port+1);
+ goto done;
+ }
+
+ for (i = 0; i < SET_CONFIG_TRIES; i++) {
+ struct usb_device *dev;
+
+ /* reallocate for each attempt, since references
+ * to the previous one can escape in various ways
+ */
+ dev = usb_alloc_dev(hub, hub->bus, port);
+ if (!dev) {
+ dev_err (&hubstate->intf->dev,
+ "couldn't allocate port %d usb_device\n", port+1);
+ goto done;
+ }
+ dev->state = USB_STATE_POWERED;
+
+ /* hub can tell if it's lowspeed already: D- pullup (not D+) */
+ if (portstatus & USB_PORT_STAT_LOW_SPEED)
+ dev->speed = USB_SPEED_LOW;
+ else
+ dev->speed = USB_SPEED_UNKNOWN;
+
+ /* reset, set address, get descriptor, add to hub's children */
+ down (&dev->serialize);
+ status = hub_port_init(hub, dev, port);
+ if (status == -EBUSY)
+ break;
+ if (status < 0)
+ continue;
+
+ /* consecutive bus-powered hubs aren't reliable; they can
+ * violate the voltage drop budget. if the new child has
+ * a "powered" LED, users should notice we didn't enable it
+ * (without reading syslog), even without per-port LEDs
+ * on the parent.
+ */
+ if (dev->descriptor.bDeviceClass == USB_CLASS_HUB
+ && hubstate->power_budget) {
+ u16 devstat;
+
+ status = usb_get_status(dev, USB_RECIP_DEVICE, 0,
+ &devstat);
+ if (status < 0) {
+ dev_dbg(&dev->dev, "get status %d ?\n", status);
+ continue;
+ }
+ cpu_to_le16s(&devstat);
+ if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
+ dev_err(&dev->dev,
+ "can't connect bus-powered hub "
+ "to this port\n");
+ if (hubstate->has_indicators) {
+ hubstate->indicator[port] =
+ INDICATOR_AMBER_BLINK;
+ schedule_work (&hubstate->leds);
+ }
+ hub->children[port] = NULL;
+ usb_put_dev(dev);
+ hub_port_disable(hub, port);
+ return;
+ }
+ }
+
+ /* check for devices running slower than they could */
+ if (dev->descriptor.bcdUSB >= 0x0200
+ && dev->speed == USB_SPEED_FULL
+ && highspeed_hubs != 0)
+ check_highspeed (hubstate, dev, port);
+
+ /* Run it through the hoops (find a driver, etc) */
+ status = usb_new_device(dev);
+ if (status != 0) {
+ hub->children[port] = NULL;
+ continue;
+ }
+ up (&dev->serialize);
+
+ status = hub_power_remaining(hubstate, hub);
+ if (status)
+ dev_dbg(&hubstate->intf->dev,
+ "%dmA power budget left\n",
+ 2 * status);
+
+ return;
+ }
+
done:
- up(&usb_address0_sem);
+ hub_port_disable(hub, port);
}
static void hub_events(void)
@@ -1285,9 +1559,6 @@
.id_table = hub_id_table,
};
-/*
- * This should be a separate module.
- */
int usb_hub_init(void)
{
pid_t pid;
diff -Nru a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
--- a/drivers/usb/core/hub.h Tue May 4 22:21:21 2004
+++ b/drivers/usb/core/hub.h Tue May 4 22:21:21 2004
@@ -209,6 +209,8 @@
struct semaphore khubd_sem;
struct usb_tt tt; /* Transaction Translator */
+ u8 power_budget; /* in 2mA units; or zero */
+
unsigned has_indicators:1;
enum hub_led_mode indicator[USB_MAXCHILDREN];
struct work_struct leds;
diff -Nru a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
--- a/drivers/usb/core/inode.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/core/inode.c Tue May 4 22:21:21 2004
@@ -717,9 +717,6 @@
while (!list_empty(&dev->filelist)) {
ds = list_entry(dev->filelist.next, struct dev_state, list);
list_del_init(&ds->list);
- down_write(&ds->devsem);
- ds->dev = NULL;
- up_write(&ds->devsem);
if (ds->discsignr) {
sinfo.si_signo = SIGPIPE;
sinfo.si_errno = EPIPE;
diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c
--- a/drivers/usb/core/message.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/core/message.c Tue May 4 22:21:21 2004
@@ -796,10 +796,6 @@
}
}
-static void release_interface(struct device *dev)
-{
-}
-
/*
* usb_disable_device - Disable all the endpoints for a USB device
* @dev: the device whose endpoints are being disabled
@@ -835,6 +831,7 @@
dev_dbg (&dev->dev, "unregistering interface %s\n",
interface->dev.bus_id);
device_unregister (&interface->dev);
+ dev->actconfig->interface[i] = NULL;
}
dev->actconfig = 0;
if (dev->state == USB_STATE_CONFIGURED)
@@ -1071,6 +1068,16 @@
return 0;
}
+static void release_interface(struct device *dev)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usb_interface_cache *intfc =
+ altsetting_to_usb_interface_cache(intf->altsetting);
+
+ kref_put(&intfc->ref);
+ kfree(intf);
+}
+
/*
* usb_set_configuration - Makes a particular device setting be current
* @dev: the device whose configuration is being updated
@@ -1109,19 +1116,19 @@
{
int i, ret;
struct usb_host_config *cp = NULL;
-
+ struct usb_interface *new_interfaces[USB_MAXINTERFACES];
+ int n;
+
/* dev->serialize guards all config changes */
- for (i=0; idescriptor.bNumConfigurations; i++) {
+ for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
if (dev->config[i].desc.bConfigurationValue == configuration) {
cp = &dev->config[i];
break;
}
}
- if ((!cp && configuration != 0)) {
- ret = -EINVAL;
- goto out;
- }
+ if ((!cp && configuration != 0))
+ return -EINVAL;
/* The USB spec says configuration 0 means unconfigured.
* But if a device includes a configuration numbered 0,
@@ -1130,6 +1137,25 @@
if (cp && configuration == 0)
dev_warn(&dev->dev, "config 0 descriptor??\n");
+ /* Allocate memory for new interfaces before doing anything else,
+ * so that if we run out then nothing will have changed. */
+ n = 0;
+ if (cp) {
+ for (; n < cp->desc.bNumInterfaces; ++n) {
+ new_interfaces[n] = kmalloc(
+ sizeof(struct usb_interface),
+ GFP_KERNEL);
+ if (!new_interfaces[n]) {
+ dev_err(&dev->dev, "Out of memory");
+ ret = -ENOMEM;
+free_interfaces:
+ while (--n >= 0)
+ kfree(new_interfaces[n]);
+ return ret;
+ }
+ }
+ }
+
/* if it's already configured, clear out old state first.
* getting rid of old interfaces means unbinding their drivers.
*/
@@ -1139,7 +1165,7 @@
if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0)
- goto out;
+ goto free_interfaces;
dev->actconfig = cp;
if (!cp)
@@ -1152,9 +1178,17 @@
* maybe probe() calls will choose different altsettings.
*/
for (i = 0; i < cp->desc.bNumInterfaces; ++i) {
- struct usb_interface *intf = cp->interface[i];
+ struct usb_interface_cache *intfc;
+ struct usb_interface *intf;
struct usb_host_interface *alt;
+ cp->interface[i] = intf = new_interfaces[i];
+ memset(intf, 0, sizeof(*intf));
+ intfc = cp->intf_cache[i];
+ intf->altsetting = intfc->altsetting;
+ intf->num_altsetting = intfc->num_altsetting;
+ kref_get(&intfc->ref);
+
alt = usb_altnum_to_altsetting(intf, 0);
/* No altsetting 0? We'll assume the first altsetting.
@@ -1204,7 +1238,6 @@
}
}
-out:
return ret;
}
diff -Nru a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
--- a/drivers/usb/core/urb.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/core/urb.c Tue May 4 22:21:21 2004
@@ -13,6 +13,14 @@
#include
#include "hcd.h"
+#define to_urb(d) container_of(d, struct urb, kref)
+
+static void urb_destroy(struct kref *kref)
+{
+ struct urb *urb = to_urb(kref);
+ kfree(urb);
+}
+
/**
* usb_init_urb - initializes a urb so that it can be used by a USB driver
* @urb: pointer to the urb to initialize
@@ -31,7 +39,7 @@
{
if (urb) {
memset(urb, 0, sizeof(*urb));
- urb->count = (atomic_t)ATOMIC_INIT(1);
+ kref_init(&urb->kref, urb_destroy);
spin_lock_init(&urb->lock);
}
}
@@ -80,8 +88,7 @@
void usb_free_urb(struct urb *urb)
{
if (urb)
- if (atomic_dec_and_test(&urb->count))
- kfree(urb);
+ kref_put(&urb->kref);
}
/**
@@ -96,11 +103,9 @@
*/
struct urb * usb_get_urb(struct urb *urb)
{
- if (urb) {
- atomic_inc(&urb->count);
- return urb;
- } else
- return NULL;
+ if (urb)
+ kref_get(&urb->kref);
+ return urb;
}
@@ -232,6 +237,8 @@
(dev->state < USB_STATE_DEFAULT) ||
(!dev->bus) || (dev->devnum <= 0))
return -ENODEV;
+ if (dev->state == USB_STATE_SUSPENDED)
+ return -EHOSTUNREACH;
if (!(op = dev->bus->op) || !op->submit_urb)
return -ENODEV;
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/core/usb.c Tue May 4 22:21:21 2004
@@ -1064,92 +1064,29 @@
}
/*
- * By the time we get here, we chose a new device address
- * and is in the default state. We need to identify the thing and
- * get the ball rolling..
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @dev: newly addressed device (in ADDRESS state)
*
- * Returns 0 for success, != 0 for error.
+ * This is called with devices which have been enumerated, but not yet
+ * configured. The device descriptor is available, but not descriptors
+ * for any device configuration. The caller owns dev->serialize, and
+ * the device is not visible through sysfs or other filesystem code.
+ *
+ * Returns 0 for success (device is configured and listed, with its
+ * interfaces, in sysfs); else a negative errno value. On error, one
+ * reference count to the device has been dropped.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Only the hub driver should ever call this; root hub registration
* uses it only indirectly.
*/
-#define NEW_DEVICE_RETRYS 2
-#define SET_ADDRESS_RETRYS 2
int usb_new_device(struct usb_device *dev)
{
- int err = -EINVAL;
+ int err;
int i;
- int j;
int config;
- /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
- * it's fixed size except for full speed devices.
- */
- switch (dev->speed) {
- case USB_SPEED_HIGH: /* fixed at 64 */
- i = 64;
- break;
- case USB_SPEED_FULL: /* 8, 16, 32, or 64 */
- /* to determine the ep0 maxpacket size, read the first 8
- * bytes from the device descriptor to get bMaxPacketSize0;
- * then correct our initial (small) guess.
- */
- // FALLTHROUGH
- case USB_SPEED_LOW: /* fixed at 8 */
- i = 8;
- break;
- default:
- goto fail;
- }
- dev->epmaxpacketin [0] = i;
- dev->epmaxpacketout[0] = i;
-
- for (i = 0; i < NEW_DEVICE_RETRYS; ++i) {
-
- for (j = 0; j < SET_ADDRESS_RETRYS; ++j) {
- err = usb_set_address(dev);
- if (err >= 0)
- break;
- wait_ms(200);
- }
- if (err < 0) {
- dev_err(&dev->dev,
- "device not accepting address %d, error %d\n",
- dev->devnum, err);
- goto fail;
- }
-
- wait_ms(10); /* Let the SET_ADDRESS settle */
-
- /* high and low speed devices don't need this... */
- err = usb_get_device_descriptor(dev, 8);
- if (err >= 8)
- break;
- wait_ms(100);
- }
-
- if (err < 8) {
- dev_err(&dev->dev, "device descriptor read/8, error %d\n", err);
- goto fail;
- }
- if (dev->speed == USB_SPEED_FULL) {
- usb_disable_endpoint(dev, 0);
- usb_endpoint_running(dev, 0, 1);
- usb_endpoint_running(dev, 0, 0);
- dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
- dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
- }
-
- /* USB device state == addressed ... still not usable */
-
- err = usb_get_device_descriptor(dev, sizeof(dev->descriptor));
- if (err != (signed)sizeof(dev->descriptor)) {
- dev_err(&dev->dev, "device descriptor read/all, error %d\n", err);
- goto fail;
- }
-
err = usb_get_configuration(dev);
if (err < 0) {
dev_err(&dev->dev, "can't read configurations, error %d\n",
@@ -1170,13 +1107,10 @@
usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
#endif
- down(&dev->serialize);
-
/* put device-specific files into sysfs */
err = device_add (&dev->dev);
if (err) {
dev_err(&dev->dev, "can't device_add, error %d\n", err);
- up(&dev->serialize);
goto fail;
}
usb_create_driverfs_dev_files (dev);
@@ -1193,7 +1127,7 @@
/* heuristic: Linux is more likely to have class
* drivers, so avoid vendor-specific interfaces.
*/
- desc = &dev->config[i].interface[0]
+ desc = &dev->config[i].intf_cache[0]
->altsetting->desc;
if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
continue;
@@ -1211,7 +1145,6 @@
dev->descriptor.bNumConfigurations);
}
err = usb_set_configuration(dev, config);
- up(&dev->serialize);
if (err) {
dev_err(&dev->dev, "can't set config #%d, error %d\n",
config, err);
@@ -1226,9 +1159,10 @@
return 0;
fail:
- dev->state = USB_STATE_DEFAULT;
+ dev->state = USB_STATE_NOTATTACHED;
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
dev->devnum = -1;
+ usb_put_dev(dev);
return err;
}
@@ -1577,20 +1511,40 @@
*/
static int __init usb_init(void)
{
+ int retval;
if (nousb) {
pr_info ("%s: USB support disabled\n", usbcore_name);
return 0;
}
- bus_register(&usb_bus_type);
+ retval = bus_register(&usb_bus_type);
+ if (retval)
+ goto out;
usb_host_init();
- usb_major_init();
- usbfs_init();
- usb_hub_init();
-
- driver_register(&usb_generic_driver);
-
- return 0;
+ retval = usb_major_init();
+ if (retval)
+ goto major_init_failed;
+ retval = usbfs_init();
+ if (retval)
+ goto fs_init_failed;
+ retval = usb_hub_init();
+ if (retval)
+ goto hub_init_failed;
+
+ retval = driver_register(&usb_generic_driver);
+ if (!retval)
+ goto out;
+
+ usb_hub_cleanup();
+hub_init_failed:
+ usbfs_cleanup();
+fs_init_failed:
+ usb_major_cleanup();
+major_init_failed:
+ usb_host_cleanup();
+ bus_unregister(&usb_bus_type);
+out:
+ return retval;
}
/*
diff -Nru a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
--- a/drivers/usb/gadget/dummy_hcd.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/gadget/dummy_hcd.c Tue May 4 22:21:21 2004
@@ -144,6 +144,7 @@
struct usb_gadget_driver *driver;
struct dummy_request fifo_req;
u8 fifo_buf [FIFO_SIZE];
+ u16 devstatus;
struct hcd_dev *hdev;
@@ -156,6 +157,8 @@
u32 port_status;
int started;
struct completion released;
+ unsigned resuming:1;
+ unsigned long re_timeout;
};
static struct dummy *the_controller;
@@ -556,8 +559,37 @@
return tv.tv_usec / 1000;
}
+static int dummy_wakeup (struct usb_gadget *_gadget)
+{
+ struct dummy *dum;
+
+ dum = container_of (_gadget, struct dummy, gadget);
+ if ((dum->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) == 0
+ || !(dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)))
+ return -EINVAL;
+
+ /* hub notices our request, issues downstream resume, etc */
+ dum->resuming = 1;
+ dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND);
+ return 0;
+}
+
+static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
+{
+ struct dummy *dum;
+
+ dum = container_of (_gadget, struct dummy, gadget);
+ if (value)
+ dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
+ else
+ dum->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
+ return 0;
+}
+
static const struct usb_gadget_ops dummy_ops = {
.get_frame = dummy_g_get_frame,
+ .wakeup = dummy_wakeup,
+ .set_selfpowered = dummy_set_selfpowered,
};
/*-------------------------------------------------------------------------*/
@@ -653,6 +685,9 @@
dum->gadget.ops = &dummy_ops;
dum->gadget.is_dualspeed = 1;
+ dum->devstatus = 0;
+ dum->resuming = 0;
+
INIT_LIST_HEAD (&dum->gadget.ep_list);
for (i = 0; i < DUMMY_ENDPOINTS; i++) {
struct dummy_ep *ep = &dum->ep [i];
@@ -1130,8 +1165,19 @@
break;
case USB_REQ_SET_FEATURE:
if (setup.bRequestType == Dev_Request) {
- // remote wakeup, and (hs) test mode
- value = -EOPNOTSUPP;
+ value = 0;
+ switch (setup.wValue) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ break;
+ default:
+ value = -EOPNOTSUPP;
+ }
+ if (value == 0) {
+ dum->devstatus |=
+ (1 << setup.wValue);
+ maybe_set_status (urb, 0);
+ }
+
} else if (setup.bRequestType == Ep_Request) {
// endpoint halt
ep2 = find_endpoint (dum,
@@ -1147,9 +1193,17 @@
break;
case USB_REQ_CLEAR_FEATURE:
if (setup.bRequestType == Dev_Request) {
- // remote wakeup
- value = 0;
- maybe_set_status (urb, 0);
+ switch (setup.wValue) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ dum->devstatus &= ~(1 <<
+ USB_DEVICE_REMOTE_WAKEUP);
+ value = 0;
+ maybe_set_status (urb, 0);
+ break;
+ default:
+ value = -EOPNOTSUPP;
+ break;
+ }
} else if (setup.bRequestType == Ep_Request) {
// endpoint halt
ep2 = find_endpoint (dum,
@@ -1185,6 +1239,10 @@
break;
}
buf [0] = ep2->halted;
+ } else if (setup.bRequestType ==
+ Dev_InRequest) {
+ buf [0] = (u8)
+ dum->devstatus;
} else
buf [0] = 0;
}
@@ -1338,8 +1396,21 @@
case ClearHubFeature:
break;
case ClearPortFeature:
- // FIXME won't some of these need special handling?
- dum->port_status &= ~(1 << wValue);
+ switch (wValue) {
+ case USB_PORT_FEAT_SUSPEND:
+ /* 20msec resume signaling */
+ dum->resuming = 1;
+ dum->re_timeout = jiffies + ((HZ * 20)/1000);
+ break;
+ case USB_PORT_FEAT_POWER:
+ dum->port_status = 0;
+ dum->address = 0;
+ dum->hdev = 0;
+ dum->resuming = 0;
+ break;
+ default:
+ dum->port_status &= ~(1 << wValue);
+ }
break;
case GetHubDescriptor:
hub_descriptor ((struct usb_hub_descriptor *) buf);
@@ -1350,33 +1421,28 @@
case GetPortStatus:
if (wIndex != 1)
retval = -EPIPE;
- ((u16 *) buf)[0] = cpu_to_le16 (dum->port_status);
- ((u16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
- break;
- case SetHubFeature:
- retval = -EPIPE;
- break;
- case SetPortFeature:
- if (wValue == USB_PORT_FEAT_RESET) {
- /* if it's already running, disconnect first */
- if (dum->port_status & USB_PORT_STAT_ENABLE) {
- dum->port_status &= ~(USB_PORT_STAT_ENABLE
- | USB_PORT_STAT_LOW_SPEED
- | USB_PORT_STAT_HIGH_SPEED);
- if (dum->driver) {
- dev_dbg (hardware, "disconnect\n");
- stop_activity (dum, dum->driver);
- }
- /* FIXME test that code path! */
- } else
- dum->port_status |=
- (1 << USB_PORT_FEAT_C_ENABLE);
-
- dum->port_status |= USB_PORT_STAT_ENABLE |
- (1 << USB_PORT_FEAT_C_RESET);
+ /* whoever resets or resumes must GetPortStatus to
+ * complete it!!
+ */
+ if (dum->resuming && time_after (jiffies, dum->re_timeout)) {
+ dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND);
+ dum->port_status &= ~(1 << USB_PORT_FEAT_SUSPEND);
+ dum->resuming = 0;
+ dum->re_timeout = 0;
+ if (dum->driver->resume) {
+ spin_unlock (&dum->lock);
+ dum->driver->resume (&dum->gadget);
+ spin_lock (&dum->lock);
+ }
+ }
+ if ((dum->port_status & (1 << USB_PORT_FEAT_RESET)) != 0
+ && time_after (jiffies, dum->re_timeout)) {
+ dum->port_status |= (1 << USB_PORT_FEAT_C_RESET);
+ dum->port_status &= ~(1 << USB_PORT_FEAT_RESET);
+ dum->re_timeout = 0;
if (dum->driver) {
-
+ dum->port_status |= USB_PORT_STAT_ENABLE;
/* give it the best speed we agree on */
dum->gadget.speed = dum->driver->speed;
dum->gadget.ep0->maxpacket = 64;
@@ -1395,8 +1461,42 @@
break;
}
}
- } else
+ }
+ ((u16 *) buf)[0] = cpu_to_le16 (dum->port_status);
+ ((u16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
+ break;
+ case SetHubFeature:
+ retval = -EPIPE;
+ break;
+ case SetPortFeature:
+ switch (wValue) {
+ case USB_PORT_FEAT_SUSPEND:
+ dum->port_status |= (1 << USB_PORT_FEAT_SUSPEND);
+ if (dum->driver->suspend) {
+ spin_unlock (&dum->lock);
+ dum->driver->suspend (&dum->gadget);
+ spin_lock (&dum->lock);
+ }
+ break;
+ case USB_PORT_FEAT_RESET:
+ /* if it's already running, disconnect first */
+ if (dum->port_status & USB_PORT_STAT_ENABLE) {
+ dum->port_status &= ~(USB_PORT_STAT_ENABLE
+ | USB_PORT_STAT_LOW_SPEED
+ | USB_PORT_STAT_HIGH_SPEED);
+ if (dum->driver) {
+ dev_dbg (hardware, "disconnect\n");
+ stop_activity (dum, dum->driver);
+ }
+
+ /* FIXME test that code path! */
+ }
+ /* 50msec reset signaling */
+ dum->re_timeout = jiffies + ((HZ * 50)/1000);
+ /* FALLTHROUGH */
+ default:
dum->port_status |= (1 << wValue);
+ }
break;
default:
diff -Nru a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
--- a/drivers/usb/gadget/zero.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/gadget/zero.c Tue May 4 22:21:21 2004
@@ -130,6 +130,9 @@
*/
u8 config;
struct usb_ep *in_ep, *out_ep;
+
+ /* autoresume timer */
+ struct timer_list resume;
};
#define xprintk(d,level,fmt,args...) \
@@ -167,6 +170,12 @@
module_param (qlen, uint, S_IRUGO|S_IWUSR);
module_param (pattern, uint, S_IRUGO|S_IWUSR);
+/*
+ * if it's nonzero, autoresume says how many seconds to wait
+ * before trying to wake up the host after suspend.
+ */
+static unsigned autoresume = 0;
+module_param (autoresume, uint, 0);
/*
* Normally the "loopback" configuration is second (index 1) so
@@ -224,7 +233,7 @@
.bNumConfigurations = 2,
};
-static const struct usb_config_descriptor
+static struct usb_config_descriptor
source_sink_config = {
.bLength = sizeof source_sink_config,
.bDescriptorType = USB_DT_CONFIG,
@@ -237,7 +246,7 @@
.bMaxPower = 1, /* self-powered */
};
-static const struct usb_config_descriptor
+static struct usb_config_descriptor
loopback_config = {
.bLength = sizeof loopback_config,
.bDescriptorType = USB_DT_CONFIG,
@@ -1060,6 +1069,19 @@
*/
}
+static void
+zero_autoresume (unsigned long _dev)
+{
+ struct zero_dev *dev = (struct zero_dev *) _dev;
+ int status;
+
+ /* normally the host would be woken up for something
+ * more significant than just a timer firing...
+ */
+ status = usb_gadget_wakeup (dev->gadget);
+ DBG (dev, "wakeup --> %d\n", status);
+}
+
/*-------------------------------------------------------------------------*/
static void
@@ -1072,6 +1094,7 @@
/* we've already been disconnected ... no i/o is active */
if (dev->req)
free_ep_req (gadget->ep0, dev->req);
+ del_timer_sync (&dev->resume);
kfree (dev);
set_gadget_data (gadget, 0);
}
@@ -1176,6 +1199,14 @@
usb_gadget_set_selfpowered (gadget);
+ init_timer (&dev->resume);
+ dev->resume.function = zero_autoresume;
+ dev->resume.data = (unsigned long) dev;
+ if (autoresume) {
+ source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ }
+
gadget->ep0->driver_data = dev;
INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
@@ -1195,6 +1226,33 @@
/*-------------------------------------------------------------------------*/
+static void
+zero_suspend (struct usb_gadget *gadget)
+{
+ struct zero_dev *dev = get_gadget_data (gadget);
+
+ if (gadget->speed == USB_SPEED_UNKNOWN)
+ return;
+
+ if (autoresume) {
+ mod_timer (&dev->resume, jiffies + (HZ * autoresume));
+ DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
+ } else
+ DBG (dev, "suspend\n");
+}
+
+static void
+zero_resume (struct usb_gadget *gadget)
+{
+ struct zero_dev *dev = get_gadget_data (gadget);
+
+ DBG (dev, "resume\n");
+ del_timer (&dev->resume);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
static struct usb_gadget_driver zero_driver = {
#ifdef CONFIG_USB_GADGET_DUALSPEED
.speed = USB_SPEED_HIGH,
@@ -1207,6 +1265,9 @@
.setup = zero_setup,
.disconnect = zero_disconnect,
+
+ .suspend = zero_suspend,
+ .resume = zero_resume,
.driver = {
.name = (char *) shortname,
diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/host/ehci-hcd.c Tue May 4 22:21:21 2004
@@ -965,7 +965,7 @@
goto rescan;
case QH_STATE_IDLE: /* fully unlinked */
if (list_empty (&qh->qtd_list)) {
- qh_put (ehci, qh);
+ qh_put (qh);
break;
}
/* else FALL THROUGH */
diff -Nru a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
--- a/drivers/usb/host/ehci-mem.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/host/ehci-mem.c Tue May 4 22:21:21 2004
@@ -87,6 +87,22 @@
}
+static void qh_destroy (struct kref *kref)
+{
+ struct ehci_qh *qh = container_of(kref, struct ehci_qh, kref);
+ struct ehci_hcd *ehci = qh->ehci;
+
+ /* clean qtds first, and know this is not linked */
+ if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
+ ehci_dbg (ehci, "unused qh not empty!\n");
+ BUG ();
+ }
+ if (qh->dummy)
+ ehci_qtd_free (ehci, qh->dummy);
+ usb_put_dev (qh->dev);
+ dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
+}
+
static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
{
struct ehci_qh *qh;
@@ -98,7 +114,8 @@
return qh;
memset (qh, 0, sizeof *qh);
- atomic_set (&qh->refcount, 1);
+ kref_init(&qh->kref, qh_destroy);
+ qh->ehci = ehci;
qh->qh_dma = dma;
// INIT_LIST_HEAD (&qh->qh_list);
INIT_LIST_HEAD (&qh->qtd_list);
@@ -114,25 +131,15 @@
}
/* to share a qh (cpu threads, or hc) */
-static inline struct ehci_qh *qh_get (/* ehci, */ struct ehci_qh *qh)
+static inline struct ehci_qh *qh_get (struct ehci_qh *qh)
{
- atomic_inc (&qh->refcount);
+ kref_get(&qh->kref);
return qh;
}
-static void qh_put (struct ehci_hcd *ehci, struct ehci_qh *qh)
+static inline void qh_put (struct ehci_qh *qh)
{
- if (!atomic_dec_and_test (&qh->refcount))
- return;
- /* clean qtds first, and know this is not linked */
- if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
- ehci_dbg (ehci, "unused qh not empty!\n");
- BUG ();
- }
- if (qh->dummy)
- ehci_qtd_free (ehci, qh->dummy);
- usb_put_dev (qh->dev);
- dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
+ kref_put(&qh->kref);
}
/*-------------------------------------------------------------------------*/
@@ -145,7 +152,7 @@
static void ehci_mem_cleanup (struct ehci_hcd *ehci)
{
if (ehci->async)
- qh_put (ehci, ehci->async);
+ qh_put (ehci->async);
ehci->async = 0;
/* DMA consistent memory and pools */
diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
--- a/drivers/usb/host/ehci-q.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/host/ehci-q.c Tue May 4 22:21:21 2004
@@ -193,7 +193,7 @@
/* ... update hc-wide periodic stats (for usbfs) */
hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs--;
}
- qh_put (ehci, qh);
+ qh_put (qh);
}
spin_lock (&urb->lock);
@@ -708,7 +708,7 @@
default:
dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
done:
- qh_put (ehci, qh);
+ qh_put (qh);
return 0;
}
@@ -951,7 +951,7 @@
// qh->hw_next = cpu_to_le32 (qh->qh_dma);
qh->qh_state = QH_STATE_IDLE;
qh->qh_next.qh = 0;
- qh_put (ehci, qh); // refcount from reclaim
+ qh_put (qh); // refcount from reclaim
/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
next = qh->reclaim;
@@ -965,7 +965,7 @@
&& HCD_IS_RUNNING (ehci->hcd.state))
qh_link_async (ehci, qh);
else {
- qh_put (ehci, qh); // refcount from async list
+ qh_put (qh); // refcount from async list
/* it's not free to turn the async schedule on/off; leave it
* active but idle for a while once it empties.
@@ -1067,7 +1067,7 @@
qh = qh_get (qh);
qh->stamp = ehci->stamp;
temp = qh_completions (ehci, qh, regs);
- qh_put (ehci, qh);
+ qh_put (qh);
if (temp != 0) {
goto rescan;
}
diff -Nru a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
--- a/drivers/usb/host/ehci-sched.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/host/ehci-sched.c Tue May 4 22:21:21 2004
@@ -312,7 +312,7 @@
do {
periodic_unlink (ehci, frame, qh);
- qh_put (ehci, qh);
+ qh_put (qh);
frame += qh->period;
} while (frame < ehci->periodic_size);
@@ -355,7 +355,7 @@
dbg ("descheduled qh %p, period = %d frame = %d count = %d, urbs = %d",
qh, qh->period, frame,
- atomic_read (&qh->refcount), ehci->periodic_sched);
+ atomic_read (&qh->kref.refcount), ehci->periodic_sched);
}
static int check_period (
@@ -1846,7 +1846,7 @@
modified = qh_completions (ehci, temp.qh, regs);
if (unlikely (list_empty (&temp.qh->qtd_list)))
intr_deschedule (ehci, temp.qh, 0);
- qh_put (ehci, temp.qh);
+ qh_put (temp.qh);
break;
case Q_TYPE_FSTN:
/* for "save place" FSTNs, look at QH entries
diff -Nru a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
--- a/drivers/usb/host/ehci.h Tue May 4 22:21:21 2004
+++ b/drivers/usb/host/ehci.h Tue May 4 22:21:21 2004
@@ -366,7 +366,8 @@
struct ehci_qtd *dummy;
struct ehci_qh *reclaim; /* next to reclaim */
- atomic_t refcount;
+ struct ehci_hcd *ehci;
+ struct kref kref;
unsigned stamp;
u8 qh_state;
diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/host/uhci-hcd.c Tue May 4 22:21:21 2004
@@ -157,8 +157,8 @@
return td;
}
-static inline void uhci_fill_td(struct uhci_td *td, __u32 status,
- __u32 token, __u32 buffer)
+static inline void uhci_fill_td(struct uhci_td *td, u32 status,
+ u32 token, u32 buffer)
{
td->status = cpu_to_le32(status);
td->token = cpu_to_le32(token);
@@ -184,11 +184,11 @@
list_add_tail(&td->fl_list, &ftd->fl_list);
td->link = ltd->link;
- mb();
+ wmb();
ltd->link = cpu_to_le32(td->dma_handle);
} else {
td->link = uhci->fl->frame[framenum];
- mb();
+ wmb();
uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle);
uhci->fl->frame_cpu[framenum] = td;
}
@@ -218,7 +218,7 @@
ptd->link = td->link;
}
- mb();
+ wmb();
td->link = UHCI_PTR_TERM;
list_del_init(&td->fl_list);
@@ -332,17 +332,7 @@
/* Grab the last QH */
lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
- /*
- * Patch this endpoint's URB's QHs to point to the next skelqh:
- * skelqh --> ... lqh --> newqh --> next skelqh
- * Do this first, so the HC always sees the right QH after this one.
- */
- list_for_each (tmp, &urbp->queue_list) {
- struct urb_priv *turbp =
- list_entry(tmp, struct urb_priv, queue_list);
-
- turbp->qh->link = lqh->link;
- }
+ /* Point to the next skelqh */
urbp->qh->link = lqh->link;
wmb(); /* Ordering is important */
@@ -362,15 +352,15 @@
*
* The HC could see (and use!) any of these as we write them.
*/
+ lqh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
if (lqh->urbp) {
list_for_each (tmp, &lqh->urbp->queue_list) {
struct urb_priv *turbp =
list_entry(tmp, struct urb_priv, queue_list);
- turbp->qh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
+ turbp->qh->link = lqh->link;
}
}
- lqh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
list_add_tail(&urbp->qh->list, &skelqh->list);
}
@@ -382,7 +372,7 @@
static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
{
struct uhci_qh *pqh;
- __u32 newlink;
+ u32 newlink;
if (!qh)
return;
@@ -423,7 +413,7 @@
turbp->qh->link = newlink;
}
}
- mb();
+ wmb();
/* Leave qh->link in case the HC is on the QH now, it will */
/* continue the rest of the schedule */
@@ -510,7 +500,7 @@
/* All qh's in the queue need to link to the next queue */
urbp->qh->link = eurbp->qh->link;
- mb(); /* Make sure we flush everything */
+ wmb(); /* Make sure we flush everything */
lltd->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
@@ -1044,9 +1034,13 @@
usb_pipeout(urb->pipe));
}
- /* Set the flag on the last packet */
- if (!(urb->transfer_flags & URB_NO_INTERRUPT))
- td->status |= cpu_to_le32(TD_CTRL_IOC);
+ /* Set the interrupt-on-completion flag on the last packet.
+ * A more-or-less typical 4 KB URB (= size of one memory page)
+ * will require about 3 ms to transfer; that's a little on the
+ * fast side but not enough to justify delaying an interrupt
+ * more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT
+ * flag setting. */
+ td->status |= cpu_to_le32(TD_CTRL_IOC);
qh = uhci_alloc_qh(uhci, urb->dev);
if (!qh)
@@ -1786,6 +1780,9 @@
spin_unlock(&uhci->schedule_lock);
+ /* Wake up anyone waiting for an URB to complete */
+ wake_up_all(&uhci->waitqh);
+
return IRQ_HANDLED;
}
@@ -2086,6 +2083,8 @@
INIT_LIST_HEAD(&uhci->complete_list);
+ init_waitqueue_head(&uhci->waitqh);
+
uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
&dma_handle, 0);
if (!uhci->fl) {
@@ -2296,6 +2295,9 @@
uhci_free_pending_qhs(uhci);
uhci_free_pending_tds(uhci);
spin_unlock_irq(&uhci->schedule_lock);
+
+ /* Wake up anyone waiting for an URB to complete */
+ wake_up_all(&uhci->waitqh);
release_uhci(uhci);
}
@@ -2361,6 +2363,46 @@
kfree(hcd_to_uhci(hcd));
}
+/* Are there any URBs for a particular device/endpoint on a given list? */
+static int urbs_for_ep_list(struct list_head *head,
+ struct hcd_dev *hdev, int ep)
+{
+ struct urb_priv *urbp;
+
+ list_for_each_entry(urbp, head, urb_list) {
+ struct urb *urb = urbp->urb;
+
+ if (hdev == urb->dev->hcpriv && ep ==
+ (usb_pipeendpoint(urb->pipe) |
+ usb_pipein(urb->pipe)))
+ return 1;
+ }
+ return 0;
+}
+
+/* Are there any URBs for a particular device/endpoint? */
+static int urbs_for_ep(struct uhci_hcd *uhci, struct hcd_dev *hdev, int ep)
+{
+ int rc;
+
+ spin_lock_irq(&uhci->schedule_lock);
+ rc = (urbs_for_ep_list(&uhci->urb_list, hdev, ep) ||
+ urbs_for_ep_list(&uhci->complete_list, hdev, ep) ||
+ urbs_for_ep_list(&uhci->urb_remove_list, hdev, ep));
+ spin_unlock_irq(&uhci->schedule_lock);
+ return rc;
+}
+
+/* Wait until all the URBs for a particular device/endpoint are gone */
+static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd,
+ struct hcd_dev *hdev, int endpoint)
+{
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+
+ wait_event_interruptible(uhci->waitqh,
+ !urbs_for_ep(uhci, hdev, endpoint));
+}
+
static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
{
return uhci_get_current_frame_number(hcd_to_uhci(hcd));
@@ -2390,6 +2432,7 @@
.urb_enqueue = uhci_urb_enqueue,
.urb_dequeue = uhci_urb_dequeue,
+ .endpoint_disable = uhci_hcd_endpoint_disable,
.get_frame_number = uhci_hcd_get_frame_number,
.hub_status_data = uhci_hub_status_data,
diff -Nru a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
--- a/drivers/usb/host/uhci-hcd.h Tue May 4 22:21:21 2004
+++ b/drivers/usb/host/uhci-hcd.h Tue May 4 22:21:21 2004
@@ -80,7 +80,7 @@
#define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */
struct uhci_frame_list {
- __u32 frame[UHCI_NUMFRAMES];
+ u32 frame[UHCI_NUMFRAMES];
void *frame_cpu[UHCI_NUMFRAMES];
@@ -105,8 +105,8 @@
*/
struct uhci_qh {
/* Hardware fields */
- __u32 link; /* Next queue */
- __u32 element; /* Queue element pointer */
+ u32 link; /* Next queue */
+ u32 element; /* Queue element pointer */
/* Software fields */
dma_addr_t dma_handle;
@@ -185,10 +185,10 @@
*/
struct uhci_td {
/* Hardware fields */
- __u32 link;
- __u32 status;
- __u32 token;
- __u32 buffer;
+ u32 link;
+ u32 status;
+ u32 token;
+ u32 buffer;
/* Software fields */
dma_addr_t dma_handle;
@@ -370,6 +370,8 @@
int rh_numports;
struct timer_list stall_timer;
+
+ wait_queue_head_t waitqh; /* endpoint_disable waiters */
};
struct urb_priv {
diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
--- a/drivers/usb/input/hid-core.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/input/hid-core.c Tue May 4 22:21:21 2004
@@ -1412,6 +1412,14 @@
#define USB_VENDOR_ID_CHIC 0x05fe
#define USB_DEVICE_ID_CHIC_GAMEPAD 0x0014
+#define USB_VENDOR_ID_GLAB 0x06c2
+#define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038
+#define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039
+
+#define USB_VENDOR_ID_WISEGROUP 0x0925
+#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101
+#define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104
+
struct hid_blacklist {
__u16 idVendor;
__u16 idProduct;
@@ -1459,6 +1467,10 @@
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 7, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PTU, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
diff -Nru a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c
--- a/drivers/usb/input/mtouchusb.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/input/mtouchusb.c Tue May 4 22:21:21 2004
@@ -28,6 +28,12 @@
* Complete rewrite using Linux Input in 2.6.3
* Unfortunately no calibration support at this time
*
+ * 1.4 04/25/2004 (TEJ) tejohnson@yahoo.com
+ * Changed reset from standard USB dev reset to vendor reset
+ * Changed data sent to host from compensated to raw coordinates
+ * Eliminated vendor/product module params
+ * Performed multiple successfull tests with an EXII-5010UC
+ *
*****************************************************************************/
#include
@@ -45,25 +51,28 @@
#include
#include
-#define MTOUCHUSB_MIN_XC 0xc8
-#define MTOUCHUSB_MAX_XC 0xff78
+#define MTOUCHUSB_MIN_XC 0x0
+#define MTOUCHUSB_MAX_XC 0x4000
#define MTOUCHUSB_XC_FUZZ 0x0
#define MTOUCHUSB_XC_FLAT 0x0
#define MTOUCHUSB_MIN_YC 0x0
-#define MTOUCHUSB_MAX_YC 0xff78
+#define MTOUCHUSB_MAX_YC 0x4000
#define MTOUCHUSB_YC_FUZZ 0x0
#define MTOUCHUSB_YC_FLAT 0x0
-#define MTOUCHUSB_ASYC_REPORT 1
-#define MTOUCHUSB_REPORT_SIZE_DATA 11
+
+#define MTOUCHUSB_ASYNC_REPORT 1
+#define MTOUCHUSB_RESET 7
+#define MTOUCHUSB_REPORT_DATA_SIZE 11
#define MTOUCHUSB_REQ_CTRLLR_ID 10
-#define MTOUCHUSB_GET_XC(data) (data[4]<<8 | data[3])
-#define MTOUCHUSB_GET_YC(data) (data[6]<<8 | data[5])
+#define MTOUCHUSB_GET_XC(data) (data[8]<<8 | data[7])
+#define MTOUCHUSB_GET_YC(data) (data[10]<<8 | data[9])
#define MTOUCHUSB_GET_TOUCHED(data) ((data[2] & 0x40) ? 1:0)
-#define DRIVER_VERSION "v0.1"
+#define DRIVER_VERSION "v1.4"
#define DRIVER_AUTHOR "Todd E. Johnson, tejohnson@yahoo.com"
-#define DRIVER_DESC "Microtouch USB HID Touchscreen Driver"
+#define DRIVER_DESC "3M USB Touchscreen Driver"
+#define DRIVER_LICENSE "GPL"
struct mtouch_usb {
unsigned char *data;
@@ -76,11 +85,9 @@
char phys[64];
};
-static __s32 vendor=-1, product=-1;
-
static struct usb_device_id mtouchusb_devices [] = {
- { USB_DEVICE(0x0596, 0x0001) }, /* 3M (Formerly MicroTouch) 14-206 */
- { } /* Terminating entry */
+ { USB_DEVICE(0x0596, 0x0001) },
+ { }
};
static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs)
@@ -135,8 +142,10 @@
mtouch->irq->dev = mtouch->udev;
- if (usb_submit_urb (mtouch->irq, GFP_ATOMIC))
+ if (usb_submit_urb (mtouch->irq, GFP_ATOMIC)) {
+ mtouch->open--;
return -EIO;
+ }
return 0;
}
@@ -153,7 +162,7 @@
{
dbg("%s - called", __FUNCTION__);
- mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_SIZE_DATA,
+ mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_DATA_SIZE,
SLAB_ATOMIC, &mtouch->data_dma);
if (!mtouch->data)
@@ -167,7 +176,7 @@
dbg("%s - called", __FUNCTION__);
if (mtouch->data)
- usb_buffer_free(udev, MTOUCHUSB_REPORT_SIZE_DATA,
+ usb_buffer_free(udev, MTOUCHUSB_REPORT_DATA_SIZE,
mtouch->data, mtouch->data_dma);
}
@@ -180,41 +189,8 @@
char path[64];
char *buf;
int nRet;
- int ix;
- char valid_device = 0;
dbg("%s - called", __FUNCTION__);
- if (vendor != -1 && product != -1) {
- info("%s - User specified USB Touch -- Vend:Prod - %x:%x",
- __FUNCTION__, vendor, product);
- }
-
- for (ix = 0; ix < sizeof (mtouchusb_devices) /
- sizeof (struct usb_device_id); ix++) {
- if ((udev->descriptor.idVendor ==
- mtouchusb_devices [ix].idVendor) &&
- (udev->descriptor.idProduct ==
- mtouchusb_devices [ix].idProduct)) {
- valid_device = 1;
- break;
- }
- }
-
- if (udev->descriptor.idVendor == vendor &&
- udev->descriptor.idProduct == product) { /* User specified */
- valid_device = 1;
- }
-
- if (!valid_device) {
- err("%s - No valid device!", __FUNCTION__);
- return -EIO;
- }
-
- if (udev->descriptor.bNumConfigurations != 1) {
- err("%s - Only one device configuration is supported.",
- __FUNCTION__);
- return -EIO;
- }
dbg("%s - setting interface", __FUNCTION__);
interface = intf->cur_altsetting;
@@ -222,11 +198,6 @@
dbg("%s - setting endpoint", __FUNCTION__);
endpoint = &interface->endpoint[0].desc;
- if (interface->desc.bNumEndpoints != 1) {
- err("%s - Only one endpoint is supported.", __FUNCTION__);
- return -EIO;
- }
-
if (!(mtouch = kmalloc (sizeof (struct mtouch_usb), GFP_KERNEL))) {
err("%s - Out of memory.", __FUNCTION__);
return -ENOMEM;
@@ -266,8 +237,8 @@
mtouch->input.absmax[ABS_X] = MTOUCHUSB_MAX_XC;
mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ;
mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT;
- mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MAX_YC;
- mtouch->input.absmax[ABS_Y] = MTOUCHUSB_MIN_YC;
+ mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MIN_YC;
+ mtouch->input.absmax[ABS_Y] = MTOUCHUSB_MAX_YC;
mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ;
mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT;
@@ -290,15 +261,15 @@
kfree(buf);
nRet = usb_control_msg(mtouch->udev,
- usb_rcvctrlpipe(udev, 0x80),
- USB_REQ_GET_CONFIGURATION,
- USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ usb_rcvctrlpipe(udev, 0),
+ MTOUCHUSB_RESET,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 1,
0,
- 0x81,
NULL,
0,
HZ * USB_CTRL_SET_TIMEOUT);
- dbg("%s - usb_control_msg - USB_REQ_GET_CONFIGURATION - bytes|err: %d",
+ dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
__FUNCTION__, nRet);
dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__);
@@ -315,7 +286,7 @@
mtouch->udev,
usb_rcvintpipe(mtouch->udev, 0x81),
mtouch->data,
- MTOUCHUSB_REPORT_SIZE_DATA,
+ MTOUCHUSB_REPORT_DATA_SIZE,
mtouchusb_irq,
mtouch,
endpoint->bInterval);
@@ -324,15 +295,15 @@
input_register_device(&mtouch->input);
nRet = usb_control_msg(mtouch->udev,
- usb_rcvctrlpipe(udev, 0x80),
- MTOUCHUSB_ASYC_REPORT,
+ usb_rcvctrlpipe(udev, 0),
+ MTOUCHUSB_ASYNC_REPORT,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- MTOUCHUSB_ASYC_REPORT,
- MTOUCHUSB_ASYC_REPORT,
+ 1,
+ 1,
NULL,
0,
HZ * USB_CTRL_SET_TIMEOUT);
- dbg("%s - usb_control_msg - MTOUCHUSB_ASYC_REPORT - bytes|err: %d",
+ dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
__FUNCTION__, nRet);
printk(KERN_INFO "input: %s on %s\n", mtouch->name, path);
@@ -383,9 +354,3 @@
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");
-MODULE_PARM(vendor, "i");
-MODULE_PARM_DESC(vendor, "User specified USB idVendor");
-MODULE_PARM(product, "i");
-MODULE_PARM_DESC(product, "User specified USB idProduct");
-
-
diff -Nru a/drivers/usb/media/dsbr100.c b/drivers/usb/media/dsbr100.c
--- a/drivers/usb/media/dsbr100.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/media/dsbr100.c Tue May 4 22:21:21 2004
@@ -33,6 +33,9 @@
History:
+ Version 0.40:
+ Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
+
Version 0.30:
Markus: Updates for 2.5.x kernel and more ISO compliant source
@@ -75,13 +78,17 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v0.30"
+#define DRIVER_VERSION "v0.40"
#define DRIVER_AUTHOR "Markus Demleitner "
#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
#define DSB100_VENDOR 0x04b4
#define DSB100_PRODUCT 0x1002
+/* Commands the device appears to understand */
+#define DSB100_TUNE 1
+#define DSB100_ONOFF 2
+
#define TB_LEN 16
/* Frequency limits in MHz -- these are European values. For Japanese
@@ -102,15 +109,19 @@
static int radio_nr = -1;
MODULE_PARM(radio_nr, "i");
-typedef struct
-{
- struct usb_device *dev;
+/* Data for one (physical) device */
+typedef struct {
+ struct usb_device *usbdev;
+ struct video_device *videodev;
unsigned char transfer_buffer[TB_LEN];
int curfreq;
int stereo;
-} usb_dsbr100;
+ int users;
+ int removed;
+} dsbr100_device;
+/* File system interface */
static struct file_operations usb_dsbr100_fops = {
.owner = THIS_MODULE,
.open = usb_dsbr100_open,
@@ -118,65 +129,84 @@
.ioctl = usb_dsbr100_ioctl,
.llseek = no_llseek,
};
-static struct video_device usb_dsbr100_radio=
+
+/* V4L interface */
+static struct video_device dsbr100_videodev_template=
{
.owner = THIS_MODULE,
.name = "D-Link DSB-R 100",
.type = VID_TYPE_TUNER,
.hardware = VID_HARDWARE_AZTECH,
.fops = &usb_dsbr100_fops,
+ .release = video_device_release,
};
-static int users = 0;
-
-static struct usb_device_id usb_dsbr100_table [] = {
+static struct usb_device_id usb_dsbr100_device_table [] = {
{ USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
{ } /* Terminating entry */
};
-MODULE_DEVICE_TABLE (usb, usb_dsbr100_table);
+MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
+/* USB subsystem interface */
static struct usb_driver usb_dsbr100_driver = {
.owner = THIS_MODULE,
.name = "dsbr100",
.probe = usb_dsbr100_probe,
.disconnect = usb_dsbr100_disconnect,
- .id_table = usb_dsbr100_table,
+ .id_table = usb_dsbr100_device_table,
};
+/* Low-level device interface begins here */
-static int dsbr100_start(usb_dsbr100 *radio)
+/* switch on radio */
+static int dsbr100_start(dsbr100_device *radio)
{
- if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
- 0x00, 0xC0, 0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
- usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
- 0x02, 0xC0, 0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
+ if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+ USB_REQ_GET_STATUS,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
+ usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+ DSB100_ONOFF,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
return -1;
return (radio->transfer_buffer)[0];
}
-static int dsbr100_stop(usb_dsbr100 *radio)
+/* switch off radio */
+static int dsbr100_stop(dsbr100_device *radio)
{
- if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
- 0x00, 0xC0, 0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
- usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
- 0x02, 0xC0, 0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
+ if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+ USB_REQ_GET_STATUS,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
+ usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+ DSB100_ONOFF,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
return -1;
return (radio->transfer_buffer)[0];
}
-
-static int dsbr100_setfreq(usb_dsbr100 *radio, int freq)
+/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
+static int dsbr100_setfreq(dsbr100_device *radio, int freq)
{
freq = (freq/16*80)/1000+856;
- if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
- 0x01, 0xC0, (freq>>8)&0x00ff, freq&0xff,
- radio->transfer_buffer, 8, 300)<0 ||
- usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
- 0x00, 0xC0, 0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
- usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
- 0x00, 0xC0, 0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
+ if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+ DSB100_TUNE,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ (freq>>8)&0x00ff, freq&0xff,
+ radio->transfer_buffer, 8, 300)<0 ||
+ usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+ USB_REQ_GET_STATUS,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
+ usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+ USB_REQ_GET_STATUS,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
radio->stereo = -1;
return -1;
}
@@ -184,61 +214,92 @@
return (radio->transfer_buffer)[0];
}
-static void dsbr100_getstat(usb_dsbr100 *radio)
-{
- if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
- 0x00, 0xC0, 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
+/* return the device status. This is, in effect, just whether it
+sees a stereo signal or not. Pity. */
+static void dsbr100_getstat(dsbr100_device *radio)
+{
+ if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+ USB_REQ_GET_STATUS,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
radio->stereo = -1;
else
radio->stereo = ! (radio->transfer_buffer[0]&0x01);
}
+/* USB subsystem interface begins here */
+
+/* check if the device is present and register with v4l and
+usb if it is */
static int usb_dsbr100_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- usb_dsbr100 *radio;
+ dsbr100_device *radio;
+ struct video_device *videodev;
- if (!(radio = kmalloc(sizeof(usb_dsbr100),GFP_KERNEL)))
+ if (!(radio = kmalloc(sizeof(dsbr100_device), GFP_KERNEL)))
return -ENOMEM;
- usb_dsbr100_radio.priv = radio;
- radio->dev = interface_to_usbdev (intf);
+ if (!(radio->videodev = video_device_alloc())) {
+ kfree(radio);
+ return -ENOMEM;
+ }
+ memcpy(radio->videodev, &dsbr100_videodev_template,
+ sizeof(dsbr100_videodev_template));
+ radio->removed = 0;
+ radio->users = 0;
+ radio->usbdev = interface_to_usbdev(intf);
radio->curfreq = FREQ_MIN*FREQ_MUL;
- usb_set_intfdata (intf, radio);
+ video_set_drvdata(radio->videodev, radio);
+ if (video_register_device(radio->videodev, VFL_TYPE_RADIO,
+ radio_nr)) {
+ warn("Could not register video device");
+ video_device_release(radio->videodev);
+ kfree(radio);
+ return -EIO;
+ }
+ usb_set_intfdata(intf, radio);
return 0;
}
+/* handle unplugging of the device, release data structures
+if nothing keeps us from doing it. If something is still
+keeping us busy, the release callback of v4l will take care
+of releasing it. stv680.c does not relase its private
+data, so I don't do this here either. Checking out the
+code I'd expect I better did that, but if there's a memory
+leak here it's tiny (~50 bytes per disconnect) */
static void usb_dsbr100_disconnect(struct usb_interface *intf)
{
- usb_dsbr100 *radio = usb_get_intfdata (intf);
+ dsbr100_device *radio = usb_get_intfdata(intf);
usb_set_intfdata (intf, NULL);
-
if (radio) {
- lock_kernel();
- if (users) {
- unlock_kernel();
- return;
+ video_unregister_device(radio->videodev);
+ radio->videodev = NULL;
+ if (radio->users) {
+ kfree(radio);
+ } else {
+ radio->removed = 1;
}
- kfree(radio);
- usb_dsbr100_radio.priv = NULL;
- unlock_kernel();
}
}
+
+/* Video for Linux interface */
+
static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
- struct video_device *dev = video_devdata(file);
- usb_dsbr100 *radio=dev->priv;
+ dsbr100_device *radio=video_get_drvdata(video_devdata(file));
if (!radio)
- return -EINVAL;
+ return -EIO;
- switch(cmd)
- {
+ switch(cmd) {
case VIDIOCGCAP: {
struct video_capability *v = arg;
+
memset(v, 0, sizeof(*v));
v->type = VID_TYPE_TUNER;
v->channels = 1;
@@ -248,6 +309,7 @@
}
case VIDIOCGTUNER: {
struct video_tuner *v = arg;
+
dsbr100_getstat(radio);
if(v->tuner) /* Only 1 tuner */
return -EINVAL;
@@ -263,21 +325,21 @@
}
case VIDIOCSTUNER: {
struct video_tuner *v = arg;
+
if(v->tuner!=0)
return -EINVAL;
/* Only 1 tuner so no setting needed ! */
return 0;
}
- case VIDIOCGFREQ:
- {
+ case VIDIOCGFREQ: {
int *freq = arg;
+
if (radio->curfreq==-1)
return -EINVAL;
*freq = radio->curfreq;
return 0;
}
- case VIDIOCSFREQ:
- {
+ case VIDIOCSFREQ: {
int *freq = arg;
radio->curfreq = *freq;
@@ -287,6 +349,7 @@
}
case VIDIOCGAUDIO: {
struct video_audio *v = arg;
+
memset(v, 0, sizeof(*v));
v->flags |= VIDEO_AUDIO_MUTABLE;
v->mode = VIDEO_SOUND_STEREO;
@@ -297,9 +360,9 @@
}
case VIDIOCSAUDIO: {
struct video_audio *v = arg;
+
if (v->audio)
return -EINVAL;
-
if (v->flags&VIDEO_AUDIO_MUTE) {
if (dsbr100_stop(radio)==-1)
warn("Radio did not respond properly");
@@ -322,64 +385,40 @@
static int usb_dsbr100_open(struct inode *inode, struct file *file)
{
- struct video_device *dev = video_devdata(file);
- usb_dsbr100 *radio=dev->priv;
+ dsbr100_device *radio=video_get_drvdata(video_devdata(file));
- if (! radio) {
- warn("Radio not initialised");
- return -EAGAIN;
- }
- if(users)
- {
- warn("Radio in use");
- return -EBUSY;
- }
- users++;
- if (dsbr100_start(radio)<0)
+ radio->users = 1;
+ if (dsbr100_start(radio)<0) {
warn("Radio did not start up properly");
+ radio->users = 0;
+ return -EIO;
+ }
dsbr100_setfreq(radio, radio->curfreq);
return 0;
}
static int usb_dsbr100_close(struct inode *inode, struct file *file)
{
- struct video_device *dev = video_devdata(file);
- usb_dsbr100 *radio=dev->priv;
+ dsbr100_device *radio=video_get_drvdata(video_devdata(file));
if (!radio)
return -ENODEV;
- users--;
+ radio->users = 0;
+ if (radio->removed) {
+ kfree(radio);
+ }
return 0;
}
static int __init dsbr100_init(void)
{
- int retval;
- usb_dsbr100_radio.priv = NULL;
- retval = usb_register(&usb_dsbr100_driver);
- if (retval)
- goto failed_usb_register;
- retval = video_register_device(&usb_dsbr100_radio, VFL_TYPE_RADIO,
- radio_nr);
- if (retval) {
- warn("Couldn't register video device");
- goto failed_video_register;
- }
+ int retval = usb_register(&usb_dsbr100_driver);
info(DRIVER_VERSION ":" DRIVER_DESC);
- return 0;
-failed_video_register:
- usb_deregister(&usb_dsbr100_driver);
-failed_usb_register:
return retval;
}
static void __exit dsbr100_exit(void)
{
- usb_dsbr100 *radio=usb_dsbr100_radio.priv;
-
- if (radio)
- dsbr100_stop(radio);
- video_unregister_device(&usb_dsbr100_radio);
usb_deregister(&usb_dsbr100_driver);
}
diff -Nru a/drivers/usb/media/ibmcam.c b/drivers/usb/media/ibmcam.c
--- a/drivers/usb/media/ibmcam.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/media/ibmcam.c Tue May 4 22:21:21 2004
@@ -3647,7 +3647,7 @@
{
struct usb_device *dev = interface_to_usbdev(intf);
struct uvd *uvd = NULL;
- int i, nas, model=0, canvasX=0, canvasY=0;
+ int ix, i, nas, model=0, canvasX=0, canvasY=0;
int actInterface=-1, inactInterface=-1, maxPS=0;
__u8 ifnum = intf->altsetting->desc.bInterfaceNumber;
unsigned char video_ep = 0;
@@ -3718,7 +3718,7 @@
} while (0);
/* Validate found interface: must have one ISO endpoint */
- nas = dev->actconfig->interface[ifnum]->num_altsetting;
+ nas = intf->num_altsetting;
if (debug > 0)
info("Number of alternate settings=%d.", nas);
if (nas < 2) {
@@ -3726,11 +3726,12 @@
return -ENODEV;
}
/* Validate all alternate settings */
- for (i=0; i < nas; i++) {
+ for (ix=0; ix < nas; ix++) {
const struct usb_host_interface *interface;
const struct usb_endpoint_descriptor *endpoint;
- interface = &dev->actconfig->interface[ifnum]->altsetting[i];
+ interface = &intf->altsetting[ix];
+ i = interface->desc.bAlternateSetting;
if (interface->desc.bNumEndpoints != 1) {
err("Interface %d. has %u. endpoints!",
ifnum, (unsigned)(interface->desc.bNumEndpoints));
diff -Nru a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c
--- a/drivers/usb/media/konicawc.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/media/konicawc.c Tue May 4 22:21:21 2004
@@ -381,9 +381,15 @@
int i, errFlag;
struct konicawc *cam = (struct konicawc *)uvd->user_data;
int pktsz;
- struct usb_host_interface *interface;
+ struct usb_interface *intf;
+ struct usb_host_interface *interface = NULL;
- interface = &dev->actconfig->interface[uvd->iface]->altsetting[spd_to_iface[cam->speed]];
+ intf = usb_ifnum_to_if(dev, uvd->iface);
+ if (intf)
+ interface = usb_altnum_to_altsetting(intf,
+ spd_to_iface[cam->speed]);
+ if (!interface)
+ return -ENXIO;
pktsz = interface->endpoint[1].desc.wMaxPacketSize;
DEBUG(1, "pktsz = %d", pktsz);
if (!CAMERA_IS_OPERATIONAL(uvd)) {
@@ -721,7 +727,7 @@
{
struct usb_device *dev = interface_to_usbdev(intf);
struct uvd *uvd = NULL;
- int i, nas;
+ int ix, i, nas;
int actInterface=-1, inactInterface=-1, maxPS=0;
unsigned char video_ep = 0;
@@ -741,11 +747,12 @@
return -ENODEV;
}
/* Validate all alternate settings */
- for (i=0; i < nas; i++) {
+ for (ix=0; ix < nas; ix++) {
const struct usb_host_interface *interface;
const struct usb_endpoint_descriptor *endpoint;
- interface = &intf->altsetting[i];
+ interface = &intf->altsetting[ix];
+ i = interface->desc.bAlternateSetting;
if (interface->desc.bNumEndpoints != 2) {
err("Interface %d. has %u. endpoints!",
interface->desc.bInterfaceNumber,
diff -Nru a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c
--- a/drivers/usb/media/ov511.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/media/ov511.c Tue May 4 22:21:21 2004
@@ -5603,8 +5603,16 @@
if (ov->bridge == BRG_OV518)
{
- struct usb_interface *ifp = ov->dev->config[0].interface[0];
- __u16 mxps = ifp->altsetting[7].endpoint[0].desc.wMaxPacketSize;
+ struct usb_interface *ifp;
+ struct usb_host_interface *alt;
+ __u16 mxps = 0;
+
+ ifp = usb_ifnum_to_if(ov->dev, 0);
+ if (ifp) {
+ alt = usb_altnum_to_altsetting(ifp, 7);
+ if (alt)
+ mxps = alt->endpoint[0].desc.wMaxPacketSize;
+ }
/* Some OV518s have packet numbering by default, some don't */
if (mxps == 897)
@@ -5805,7 +5813,7 @@
if (dev->descriptor.bNumConfigurations != 1)
return -ENODEV;
- idesc = &intf->altsetting[0].desc;
+ idesc = &intf->cur_altsetting->desc;
if (idesc->bInterfaceClass != 0xFF)
return -ENODEV;
diff -Nru a/drivers/usb/media/pwc-if.c b/drivers/usb/media/pwc-if.c
--- a/drivers/usb/media/pwc-if.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/media/pwc-if.c Tue May 4 22:21:21 2004
@@ -789,7 +789,8 @@
struct urb *urb;
int i, j, ret;
- struct usb_host_interface *idesc;
+ struct usb_interface *intf;
+ struct usb_host_interface *idesc = NULL;
if (pdev == NULL)
return -EFAULT;
@@ -801,7 +802,9 @@
/* Get the current alternate interface, adjust packet size */
if (!udev->actconfig)
return -EFAULT;
- idesc = &udev->actconfig->interface[0]->altsetting[pdev->valternate];
+ intf = usb_ifnum_to_if(udev, 0);
+ if (intf)
+ idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
if (!idesc)
return -EFAULT;
diff -Nru a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c
--- a/drivers/usb/media/se401.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/media/se401.c Tue May 4 22:21:21 2004
@@ -1326,7 +1326,7 @@
if (dev->descriptor.bNumConfigurations != 1)
return -ENODEV;
- interface = &intf->altsetting[0].desc;
+ interface = &intf->cur_altsetting->desc;
/* Is it an se401? */
if (dev->descriptor.idVendor == 0x03e8 &&
diff -Nru a/drivers/usb/media/ultracam.c b/drivers/usb/media/ultracam.c
--- a/drivers/usb/media/ultracam.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/media/ultracam.c Tue May 4 22:21:21 2004
@@ -513,7 +513,7 @@
{
struct usb_device *dev = interface_to_usbdev(intf);
struct uvd *uvd = NULL;
- int i, nas;
+ int ix, i, nas;
int actInterface=-1, inactInterface=-1, maxPS=0;
unsigned char video_ep = 0;
@@ -540,11 +540,12 @@
return -ENODEV;
}
/* Validate all alternate settings */
- for (i=0; i < nas; i++) {
+ for (ix=0; ix < nas; ix++) {
const struct usb_host_interface *interface;
const struct usb_endpoint_descriptor *endpoint;
- interface = &intf->altsetting[i];
+ interface = &intf->altsetting[ix];
+ i = interface->desc.bAlternateSetting;
if (interface->desc.bNumEndpoints != 1) {
err("Interface %d. has %u. endpoints!",
interface->desc.bInterfaceNumber,
diff -Nru a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c
--- a/drivers/usb/media/vicam.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/media/vicam.c Tue May 4 22:21:21 2004
@@ -1303,7 +1303,7 @@
printk(KERN_INFO "ViCam based webcam connected\n");
- interface = &intf->altsetting[0];
+ interface = intf->cur_altsetting;
DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
diff -Nru a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
--- a/drivers/usb/misc/Kconfig Tue May 4 22:21:21 2004
+++ b/drivers/usb/misc/Kconfig Tue May 4 22:21:21 2004
@@ -133,6 +133,18 @@
To compile this driver as a module, choose M here: the
module will be called speedtch.
+config USB_PHIDGETSERVO
+ tristate "USB PhidgetServo support"
+ depends on USB
+ help
+ Say Y here if you want to connect an 1 or 4 Motor PhidgetServo
+ servo controller version 2.0 or 3.0.
+
+ Phidgets Inc. has a web page at .
+
+ To compile this driver as a module, choose M here: the
+ module will be called phidgetservo.
+
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 Tue May 4 22:21:21 2004
+++ b/drivers/usb/misc/Makefile Tue May 4 22:21:21 2004
@@ -15,3 +15,4 @@
obj-$(CONFIG_USB_TEST) += usbtest.o
obj-$(CONFIG_USB_TIGL) += tiglusb.o
obj-$(CONFIG_USB_USS720) += uss720.o
+obj-$(CONFIG_USB_PHIDGETSERVO) += phidgetservo.o
diff -Nru a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
--- a/drivers/usb/misc/legousbtower.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/misc/legousbtower.c Tue May 4 22:21:21 2004
@@ -1,8 +1,8 @@
/*
* LEGO USB Tower driver
*
- * Copyright (C) 2003 David Glance
- * 2001 Juergen Stuber
+ * Copyright (C) 2003 David Glance
+ * 2001-2004 Juergen Stuber
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -33,14 +33,44 @@
* - changed to use lego0 rather than tower0
* - changed dbg() to use __func__ rather than deprecated __FUNCTION__
* 2003-01-12 - 0.53 david (david@csse.uwa.edu.au)
- * - changed read and write to write everything or timeout (from a patch by Chris Riesen and
- * Brett Thaeler driver)
+ * - changed read and write to write everything or
+ * timeout (from a patch by Chris Riesen and Brett Thaeler driver)
* - added ioctl functionality to set timeouts
- * 2003-07-18 - 0.54 davidgsf (david@csse.uwa.edu.au)
+ * 2003-07-18 - 0.54 davidgsf (david@csse.uwa.edu.au)
* - initial import into LegoUSB project
* - merge of existing LegoUSB.c driver
- * 2003-07-18 - 0.56 davidgsf (david@csse.uwa.edu.au)
+ * 2003-07-18 - 0.56 davidgsf (david@csse.uwa.edu.au)
* - port to 2.6 style driver
+ * 2004-02-29 - 0.6 Juergen Stuber
+ * - fix locking
+ * - unlink read URBs which are no longer needed
+ * - allow increased buffer size, eliminates need for timeout on write
+ * - have read URB running continuously
+ * - added poll
+ * - forbid seeking
+ * - added nonblocking I/O
+ * - changed back __func__ to __FUNCTION__
+ * - read and log tower firmware version
+ * - reset tower on probe, avoids failure of first write
+ * 2004-03-09 - 0.7 Juergen Stuber
+ * - timeout read now only after inactivity, shorten default accordingly
+ * 2004-03-11 - 0.8 Juergen Stuber
+ * - log major, minor instead of possibly confusing device filename
+ * - whitespace cleanup
+ * 2004-03-12 - 0.9 Juergen Stuber
+ * - normalize whitespace in debug messages
+ * - take care about endianness in control message responses
+ * 2004-03-13 - 0.91 Juergen Stuber
+ * - make default intervals longer to accommodate current EHCI driver
+ * 2004-03-19 - 0.92 Juergen Stuber
+ * - replaced atomic_t by memory barriers
+ * 2004-04-21 - 0.93 Juergen Stuber
+ * - wait for completion of write urb in release (needed for remotecontrol)
+ * - corrected poll for write direction (missing negation)
+ * 2004-04-22 - 0.94 Juergen Stuber
+ * - make device locking interruptible
+ * 2004-04-30 - 0.95 Juergen Stuber
+ * - check for valid udev on resubmitting and unlinking urbs
*/
#include
@@ -53,33 +83,113 @@
#include
#include
#include
+#include
#ifdef CONFIG_USB_DEBUG
static int debug = 4;
#else
- static int debug = 1;
+ static int debug = 0;
#endif
/* Use our own dbg macro */
#undef dbg
-#define dbg(lvl, format, arg...) do { if (debug >= lvl) printk(KERN_DEBUG __FILE__ " : " format " \n", ## arg); } while (0)
+#define dbg(lvl, format, arg...) do { if (debug >= lvl) printk(KERN_DEBUG __FILE__ ": " format "\n", ## arg); } while (0)
/* Version Information */
-#define DRIVER_VERSION "v0.56"
-#define DRIVER_AUTHOR "David Glance, davidgsf@sourceforge.net"
+#define DRIVER_VERSION "v0.95"
+#define DRIVER_AUTHOR "Juergen Stuber "
#define DRIVER_DESC "LEGO USB Tower Driver"
-/* Module paramaters */
+/* Module parameters */
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Debug enabled or not");
+/* The defaults are chosen to work with the latest versions of leJOS and NQC.
+ */
+
+/* Some legacy software likes to receive packets in one piece.
+ * In this case read_buffer_size should exceed the maximal packet length
+ * (417 for datalog uploads), and packet_timeout should be set.
+ */
+static size_t read_buffer_size = 480;
+MODULE_PARM(read_buffer_size, "i");
+MODULE_PARM_DESC(read_buffer_size, "Read buffer size");
+
+/* Some legacy software likes to send packets in one piece.
+ * In this case write_buffer_size should exceed the maximal packet length
+ * (417 for firmware and program downloads).
+ * A problem with long writes is that the following read may time out
+ * if the software is not prepared to wait long enough.
+ */
+static size_t write_buffer_size = 480;
+MODULE_PARM(write_buffer_size, "i");
+MODULE_PARM_DESC(write_buffer_size, "Write buffer size");
+
+/* Some legacy software expects reads to contain whole LASM packets.
+ * To achieve this, characters which arrive before a packet timeout
+ * occurs will be returned in a single read operation.
+ * A problem with long reads is that the software may time out
+ * if it is not prepared to wait long enough.
+ * The packet timeout should be greater than the time between the
+ * reception of subsequent characters, which should arrive about
+ * every 5ms for the standard 2400 baud.
+ * Set it to 0 to disable.
+ */
+static int packet_timeout = 50;
+MODULE_PARM(packet_timeout, "i");
+MODULE_PARM_DESC(packet_timeout, "Packet timeout in ms");
+
+/* Some legacy software expects blocking reads to time out.
+ * Timeout occurs after the specified time of read and write inactivity.
+ * Set it to 0 to disable.
+ */
+static int read_timeout = 200;
+MODULE_PARM(read_timeout, "i");
+MODULE_PARM_DESC(read_timeout, "Read timeout in ms");
+
+/* As of kernel version 2.6.4 ehci-hcd uses an
+ * "only one interrupt transfer per frame" shortcut
+ * to simplify the scheduling of periodic transfers.
+ * This conflicts with our standard 1ms intervals for in and out URBs.
+ * We use default intervals of 2ms for in and 8ms for out transfers,
+ * which is fast enough for 2400 baud and allows a small additional load.
+ * Increase the interval to allow more devices that do interrupt transfers,
+ * or set to 0 to use the standard interval from the endpoint descriptors.
+ */
+static int interrupt_in_interval = 2;
+MODULE_PARM(interrupt_in_interval, "i");
+MODULE_PARM_DESC(interrupt_in_interval, "Interrupt in interval in ms");
+
+static int interrupt_out_interval = 8;
+MODULE_PARM(interrupt_out_interval, "i");
+MODULE_PARM_DESC(interrupt_out_interval, "Interrupt out interval in ms");
/* Define these values to match your device */
#define LEGO_USB_TOWER_VENDOR_ID 0x0694
#define LEGO_USB_TOWER_PRODUCT_ID 0x0001
+/* Vendor requests */
+#define LEGO_USB_TOWER_REQUEST_RESET 0x04
+#define LEGO_USB_TOWER_REQUEST_GET_VERSION 0xFD
+
+struct tower_reset_reply {
+ __u16 size; /* little-endian */
+ __u8 err_code;
+ __u8 spare;
+} __attribute__ ((packed));
+
+struct tower_get_version_reply {
+ __u16 size; /* little-endian */
+ __u8 err_code;
+ __u8 spare;
+ __u8 major;
+ __u8 minor;
+ __u16 build_no; /* little-endian */
+} __attribute__ ((packed));
+
+
/* table of devices that work with this driver */
static struct usb_device_id tower_table [] = {
{ USB_DEVICE(LEGO_USB_TOWER_VENDOR_ID, LEGO_USB_TOWER_PRODUCT_ID) },
@@ -90,22 +200,21 @@
#define LEGO_USB_TOWER_MINOR_BASE 160
-/* we can have up to this number of device plugged in at once */
-#define MAX_DEVICES 16
-
-#define COMMAND_TIMEOUT (2*HZ) /* 2 second timeout for a command */
/* Structure to hold all of our device specific stuff */
struct lego_usb_tower {
struct semaphore sem; /* locks this structure */
- struct usb_device* udev; /* save off the usb device pointer */
- struct usb_interface* interface;
+ struct usb_device* udev; /* save off the usb device pointer */
unsigned char minor; /* the starting minor number for this device */
int open_count; /* number of times this port has been opened */
char* read_buffer;
- int read_buffer_length;
+ size_t read_buffer_length; /* this much came in */
+ size_t read_packet_length; /* this much will be returned on read */
+ spinlock_t read_buffer_lock;
+ int packet_timeout_jiffies;
+ unsigned long read_last_arrival;
wait_queue_head_t read_wait;
wait_queue_head_t write_wait;
@@ -113,18 +222,18 @@
char* interrupt_in_buffer;
struct usb_endpoint_descriptor* interrupt_in_endpoint;
struct urb* interrupt_in_urb;
+ int interrupt_in_interval;
+ int interrupt_in_running;
+ int interrupt_in_done;
char* interrupt_out_buffer;
struct usb_endpoint_descriptor* interrupt_out_endpoint;
struct urb* interrupt_out_urb;
+ int interrupt_out_interval;
+ int interrupt_out_busy;
};
-/* Note that no locking is needed:
- * read_buffer is arbitrated by read_buffer_length == 0
- * interrupt_out_buffer is arbitrated by interrupt_out_urb->status == -EINPROGRESS
- * interrupt_in_buffer belongs to urb alone and is overwritten on overflow
- */
/* local function prototypes */
static ssize_t tower_read (struct file *file, char *buffer, size_t count, loff_t *ppos);
@@ -132,8 +241,11 @@
static inline void tower_delete (struct lego_usb_tower *dev);
static int tower_open (struct inode *inode, struct file *file);
static int tower_release (struct inode *inode, struct file *file);
-static int tower_release_internal (struct lego_usb_tower *dev);
+static unsigned int tower_poll (struct file *file, poll_table *wait);
+static loff_t tower_llseek (struct file *file, loff_t off, int whence);
+
static void tower_abort_transfers (struct lego_usb_tower *dev);
+static void tower_check_for_read_packet (struct lego_usb_tower *dev);
static void tower_interrupt_in_callback (struct urb *urb, struct pt_regs *regs);
static void tower_interrupt_out_callback (struct urb *urb, struct pt_regs *regs);
@@ -146,14 +258,16 @@
/* file operations needed when we register this driver */
static struct file_operations tower_fops = {
- .owner = THIS_MODULE,
- .read = tower_read,
+ .owner = THIS_MODULE,
+ .read = tower_read,
.write = tower_write,
.open = tower_open,
- .release = tower_release,
+ .release = tower_release,
+ .poll = tower_poll,
+ .llseek = tower_llseek,
};
-/*
+/*
* usb class driver info in order to get a minor number from the usb core,
* and to have the device registered with devfs and the driver core
*/
@@ -167,11 +281,11 @@
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver tower_driver = {
- .owner = THIS_MODULE,
- .name = "legousbtower",
- .probe = tower_probe,
- .disconnect = tower_disconnect,
- .id_table = tower_table,
+ .owner = THIS_MODULE,
+ .name = "legousbtower",
+ .probe = tower_probe,
+ .disconnect = tower_disconnect,
+ .id_table = tower_table,
};
@@ -183,8 +297,8 @@
int i;
if (debug < level)
- return;
-
+ return;
+
printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", function, size);
for (i = 0; i < size; ++i) {
printk ("%.2x ", data[i]);
@@ -198,7 +312,7 @@
*/
static inline void tower_delete (struct lego_usb_tower *dev)
{
- dbg(2, "%s enter", __func__);
+ dbg(2, "%s: enter", __FUNCTION__);
tower_abort_transfers (dev);
@@ -214,7 +328,7 @@
kfree (dev->interrupt_out_buffer);
kfree (dev);
- dbg(2, "%s : leave", __func__);
+ dbg(2, "%s: leave", __FUNCTION__);
}
@@ -228,7 +342,7 @@
int retval = 0;
struct usb_interface *interface;
- dbg(2,"%s : enter", __func__);
+ dbg(2, "%s: enter", __FUNCTION__);
subminor = iminor(inode);
@@ -240,37 +354,63 @@
err ("%s - error, can't find device for minor %d",
__FUNCTION__, subminor);
retval = -ENODEV;
- goto exit_no_device;
+ goto unlock_disconnect_exit;
}
dev = usb_get_intfdata(interface);
if (!dev) {
retval = -ENODEV;
- goto exit_no_device;
+ goto unlock_disconnect_exit;
}
/* lock this device */
- down (&dev->sem);
-
-
- /* increment our usage count for the device */
- ++dev->open_count;
-
- /* save device in the file's private structure */
- file->private_data = dev;
+ if (down_interruptible (&dev->sem)) {
+ retval = -ERESTARTSYS;
+ goto unlock_disconnect_exit;
+ }
+ /* allow opening only once */
+ if (dev->open_count) {
+ retval = -EBUSY;
+ goto unlock_exit;
+ }
+ dev->open_count = 1;
/* initialize in direction */
dev->read_buffer_length = 0;
+ dev->read_packet_length = 0;
+ usb_fill_int_urb (dev->interrupt_in_urb,
+ dev->udev,
+ usb_rcvintpipe(dev->udev, dev->interrupt_in_endpoint->bEndpointAddress),
+ dev->interrupt_in_buffer,
+ dev->interrupt_in_endpoint->wMaxPacketSize,
+ tower_interrupt_in_callback,
+ dev,
+ dev->interrupt_in_interval);
+
+ dev->interrupt_in_running = 1;
+ dev->interrupt_in_done = 0;
+ mb();
- up (&dev->sem);
+ retval = usb_submit_urb (dev->interrupt_in_urb, GFP_KERNEL);
+ if (retval) {
+ err("Couldn't submit interrupt_in_urb %d", retval);
+ dev->interrupt_in_running = 0;
+ dev->open_count = 0;
+ goto unlock_exit;
+ }
-exit_no_device:
+ /* save device in the file's private structure */
+ file->private_data = dev;
+unlock_exit:
+ up (&dev->sem);
+
+unlock_disconnect_exit:
up (&disconnect_sem);
- dbg(2,"%s : leave, return value %d ", __func__, retval);
+ dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval);
return retval;
}
@@ -283,87 +423,137 @@
struct lego_usb_tower *dev;
int retval = 0;
- dbg(2," %s : enter", __func__);
+ dbg(2, "%s: enter", __FUNCTION__);
dev = (struct lego_usb_tower *)file->private_data;
if (dev == NULL) {
- dbg(1," %s : object is NULL", __func__);
+ dbg(1, "%s: object is NULL", __FUNCTION__);
retval = -ENODEV;
goto exit;
}
+ if (down_interruptible (&dev->sem)) {
+ retval = -ERESTARTSYS;
+ goto exit;
+ }
- /* lock our device */
- down (&dev->sem);
-
- if (dev->open_count <= 0) {
- dbg(1," %s : device not opened", __func__);
+ if (dev->open_count != 1) {
+ dbg(1, "%s: device not opened exactly once", __FUNCTION__);
retval = -ENODEV;
+ goto unlock_exit;
+ }
+ if (dev->udev == NULL) {
+ /* the device was unplugged before the file was released */
+ up (&dev->sem); /* unlock here as tower_delete frees dev */
+ tower_delete (dev);
goto exit;
}
- /* do the work */
- retval = tower_release_internal (dev);
+ /* wait until write transfer is finished */
+ if (dev->interrupt_out_busy) {
+ wait_event_interruptible_timeout (dev->write_wait, !dev->interrupt_out_busy, 2 * HZ);
+ }
+ tower_abort_transfers (dev);
+ dev->open_count = 0;
-exit:
+unlock_exit:
up (&dev->sem);
- dbg(2," %s : leave, return value %d", __func__, retval);
+
+exit:
+ dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);
return retval;
}
/**
- * tower_release_internal
+ * tower_abort_transfers
+ * aborts transfers and frees associated data structures
*/
-static int tower_release_internal (struct lego_usb_tower *dev)
+static void tower_abort_transfers (struct lego_usb_tower *dev)
{
- int retval = 0;
+ dbg(2, "%s: enter", __FUNCTION__);
- dbg(2," %s : enter", __func__);
-
- if (dev->udev == NULL) {
- /* the device was unplugged before the file was released */
- tower_delete (dev);
+ if (dev == NULL) {
+ dbg(1, "%s: dev is null", __FUNCTION__);
goto exit;
}
- /* decrement our usage count for the device */
- --dev->open_count;
- if (dev->open_count <= 0) {
- tower_abort_transfers (dev);
- dev->open_count = 0;
+ /* shutdown transfer */
+ if (dev->interrupt_in_running) {
+ dev->interrupt_in_running = 0;
+ mb();
+ if (dev->interrupt_in_urb != NULL && dev->udev) {
+ usb_unlink_urb (dev->interrupt_in_urb);
+ }
+ }
+ if (dev->interrupt_out_busy) {
+ if (dev->interrupt_out_urb != NULL && dev->udev) {
+ usb_unlink_urb (dev->interrupt_out_urb);
+ }
}
exit:
- dbg(2," %s : leave", __func__);
- return retval;
+ dbg(2, "%s: leave", __FUNCTION__);
}
/**
- * tower_abort_transfers
- * aborts transfers and frees associated data structures
+ * tower_check_for_read_packet
+ *
+ * To get correct semantics for signals and non-blocking I/O
+ * with packetizing we pretend not to see any data in the read buffer
+ * until it has been there unchanged for at least
+ * dev->packet_timeout_jiffies, or until the buffer is full.
*/
-static void tower_abort_transfers (struct lego_usb_tower *dev)
+static void tower_check_for_read_packet (struct lego_usb_tower *dev)
{
- dbg(2," %s : enter", __func__);
-
- if (dev == NULL) {
- dbg(1," %s : dev is null", __func__);
- goto exit;
+ spin_lock_irq (&dev->read_buffer_lock);
+ if (!packet_timeout
+ || time_after(jiffies, dev->read_last_arrival + dev->packet_timeout_jiffies)
+ || dev->read_buffer_length == read_buffer_size) {
+ dev->read_packet_length = dev->read_buffer_length;
}
+ dev->interrupt_in_done = 0;
+ spin_unlock_irq (&dev->read_buffer_lock);
+}
- /* shutdown transfer */
- if (dev->interrupt_in_urb != NULL) {
- usb_unlink_urb (dev->interrupt_in_urb);
+
+/**
+ * tower_poll
+ */
+static unsigned int tower_poll (struct file *file, poll_table *wait)
+{
+ struct lego_usb_tower *dev;
+ unsigned int mask = 0;
+
+ dbg(2, "%s: enter", __FUNCTION__);
+
+ dev = file->private_data;
+
+ poll_wait(file, &dev->read_wait, wait);
+ poll_wait(file, &dev->write_wait, wait);
+
+ tower_check_for_read_packet(dev);
+ if (dev->read_packet_length > 0) {
+ mask |= POLLIN | POLLRDNORM;
}
- if (dev->interrupt_out_urb != NULL) {
- usb_unlink_urb (dev->interrupt_out_urb);
+ if (!dev->interrupt_out_busy) {
+ mask |= POLLOUT | POLLWRNORM;
}
-exit:
- dbg(2," %s : leave", __func__);
+ dbg(2, "%s: leave, mask = %d", __FUNCTION__, mask);
+
+ return mask;
+}
+
+
+/**
+ * tower_llseek
+ */
+static loff_t tower_llseek (struct file *file, loff_t off, int whence)
+{
+ return -ESPIPE; /* unseekable */
}
@@ -373,96 +563,87 @@
static ssize_t tower_read (struct file *file, char *buffer, size_t count, loff_t *ppos)
{
struct lego_usb_tower *dev;
- size_t bytes_read = 0;
size_t bytes_to_read;
int i;
int retval = 0;
- int timeout = 0;
+ unsigned long timeout = 0;
- dbg(2," %s : enter, count = %Zd", __func__, count);
+ dbg(2, "%s: enter, count = %Zd", __FUNCTION__, count);
dev = (struct lego_usb_tower *)file->private_data;
-
+
/* lock this object */
- down (&dev->sem);
+ if (down_interruptible (&dev->sem)) {
+ retval = -ERESTARTSYS;
+ goto exit;
+ }
/* verify that the device wasn't unplugged */
if (dev->udev == NULL) {
retval = -ENODEV;
err("No device or device unplugged %d", retval);
- goto exit;
+ goto unlock_exit;
}
/* verify that we actually have some data to read */
if (count == 0) {
- dbg(1," %s : read request of 0 bytes", __func__);
- goto exit;
+ dbg(1, "%s: read request of 0 bytes", __FUNCTION__);
+ goto unlock_exit;
}
+ if (read_timeout) {
+ timeout = jiffies + read_timeout * HZ / 1000;
+ }
+
+ /* wait for data */
+ tower_check_for_read_packet (dev);
+ while (dev->read_packet_length == 0) {
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ goto unlock_exit;
+ }
+ retval = wait_event_interruptible_timeout(dev->read_wait, dev->interrupt_in_done, dev->packet_timeout_jiffies);
+ if (retval < 0) {
+ goto unlock_exit;
+ }
- timeout = COMMAND_TIMEOUT;
+ /* reset read timeout during read or write activity */
+ if (read_timeout
+ && (dev->read_buffer_length || dev->interrupt_out_busy)) {
+ timeout = jiffies + read_timeout * HZ / 1000;
+ }
+ /* check for read timeout */
+ if (read_timeout && time_after (jiffies, timeout)) {
+ retval = -ETIMEDOUT;
+ goto unlock_exit;
+ }
+ tower_check_for_read_packet (dev);
+ }
- while (1) {
- if (dev->read_buffer_length == 0) {
+ /* copy the data from read_buffer into userspace */
+ bytes_to_read = min(count, dev->read_packet_length);
- /* start reading */
- usb_fill_int_urb (dev->interrupt_in_urb,dev->udev,
- usb_rcvintpipe(dev->udev, dev->interrupt_in_endpoint->bEndpointAddress),
- dev->interrupt_in_buffer,
- dev->interrupt_in_endpoint->wMaxPacketSize,
- tower_interrupt_in_callback,
- dev,
- dev->interrupt_in_endpoint->bInterval);
-
- retval = usb_submit_urb (dev->interrupt_in_urb, GFP_KERNEL);
-
- if (retval < 0) {
- err("Couldn't submit interrupt_in_urb");
- goto exit;
- }
-
- if (timeout <= 0) {
- retval = -ETIMEDOUT;
- goto exit;
- }
-
- if (signal_pending(current)) {
- retval = -EINTR;
- goto exit;
- }
-
- up (&dev->sem);
- timeout = interruptible_sleep_on_timeout (&dev->read_wait, timeout);
- down (&dev->sem);
+ if (copy_to_user (buffer, dev->read_buffer, bytes_to_read)) {
+ retval = -EFAULT;
+ goto unlock_exit;
+ }
- } else {
- /* copy the data from read_buffer into userspace */
- bytes_to_read = count > dev->read_buffer_length ? dev->read_buffer_length : count;
- if (copy_to_user (buffer, dev->read_buffer, bytes_to_read) != 0) {
- retval = -EFAULT;
- goto exit;
- }
- dev->read_buffer_length -= bytes_to_read;
- for (i=0; iread_buffer_length; i++) {
- dev->read_buffer[i] = dev->read_buffer[i+bytes_to_read];
- }
-
- buffer += bytes_to_read;
- count -= bytes_to_read;
- bytes_read += bytes_to_read;
- if (count == 0) {
- break;
- }
- }
+ spin_lock_irq (&dev->read_buffer_lock);
+ dev->read_buffer_length -= bytes_to_read;
+ dev->read_packet_length -= bytes_to_read;
+ for (i=0; iread_buffer_length; i++) {
+ dev->read_buffer[i] = dev->read_buffer[i+bytes_to_read];
}
+ spin_unlock_irq (&dev->read_buffer_lock);
- retval = bytes_read;
+ retval = bytes_to_read;
-exit:
+unlock_exit:
/* unlock the device */
up (&dev->sem);
- dbg(2," %s : leave, return value %d", __func__, retval);
+exit:
+ dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);
return retval;
}
@@ -473,107 +654,80 @@
static ssize_t tower_write (struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
struct lego_usb_tower *dev;
- size_t bytes_written = 0;
size_t bytes_to_write;
- size_t buffer_size;
int retval = 0;
- int timeout = 0;
- dbg(2," %s : enter, count = %Zd", __func__, count);
+ dbg(2, "%s: enter, count = %Zd", __FUNCTION__, count);
dev = (struct lego_usb_tower *)file->private_data;
/* lock this object */
- down (&dev->sem);
+ if (down_interruptible (&dev->sem)) {
+ retval = -ERESTARTSYS;
+ goto exit;
+ }
/* verify that the device wasn't unplugged */
if (dev->udev == NULL) {
retval = -ENODEV;
err("No device or device unplugged %d", retval);
- goto exit;
+ goto unlock_exit;
}
/* verify that we actually have some data to write */
if (count == 0) {
- dbg(1," %s : write request of 0 bytes", __func__);
- goto exit;
+ dbg(1, "%s: write request of 0 bytes", __FUNCTION__);
+ goto unlock_exit;
}
+ /* wait until previous transfer is finished */
+ while (dev->interrupt_out_busy) {
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ goto unlock_exit;
+ }
+ retval = wait_event_interruptible (dev->write_wait, !dev->interrupt_out_busy);
+ if (retval) {
+ goto unlock_exit;
+ }
+ }
- while (count > 0) {
- if (dev->interrupt_out_urb->status == -EINPROGRESS) {
- timeout = COMMAND_TIMEOUT;
-
- while (timeout > 0) {
- if (signal_pending(current)) {
- dbg(1," %s : interrupted", __func__);
- retval = -EINTR;
- goto exit;
- }
- up (&dev->sem);
- timeout = interruptible_sleep_on_timeout (&dev->write_wait, timeout);
- down (&dev->sem);
- if (timeout > 0) {
- break;
- }
- dbg(1," %s : interrupted timeout: %d", __func__, timeout);
- }
-
-
- dbg(1," %s : final timeout: %d", __func__, timeout);
-
- if (timeout == 0) {
- dbg(1, "%s - command timed out.", __func__);
- retval = -ETIMEDOUT;
- goto exit;
- }
-
- dbg(4," %s : in progress, count = %Zd", __func__, count);
- } else {
- dbg(4," %s : sending, count = %Zd", __func__, count);
-
- /* write the data into interrupt_out_buffer from userspace */
- buffer_size = dev->interrupt_out_endpoint->wMaxPacketSize;
- bytes_to_write = count > buffer_size ? buffer_size : count;
- dbg(4," %s : buffer_size = %Zd, count = %Zd, bytes_to_write = %Zd", __func__, buffer_size, count, bytes_to_write);
-
- if (copy_from_user (dev->interrupt_out_buffer, buffer, bytes_to_write) != 0) {
- retval = -EFAULT;
- goto exit;
- }
-
- /* send off the urb */
- usb_fill_int_urb(dev->interrupt_out_urb,
- dev->udev,
- usb_sndintpipe(dev->udev, dev->interrupt_out_endpoint->bEndpointAddress),
- dev->interrupt_out_buffer,
- bytes_to_write,
- tower_interrupt_out_callback,
- dev,
- dev->interrupt_in_endpoint->bInterval);
-
- dev->interrupt_out_urb->actual_length = bytes_to_write;
- retval = usb_submit_urb (dev->interrupt_out_urb, GFP_KERNEL);
-
- if (retval < 0) {
- err("Couldn't submit interrupt_out_urb %d", retval);
- goto exit;
- }
+ /* write the data into interrupt_out_buffer from userspace */
+ bytes_to_write = min(count, write_buffer_size);
+ dbg(4, "%s: count = %Zd, bytes_to_write = %Zd", __FUNCTION__, count, bytes_to_write);
+
+ if (copy_from_user (dev->interrupt_out_buffer, buffer, bytes_to_write)) {
+ retval = -EFAULT;
+ goto unlock_exit;
+ }
+
+ /* send off the urb */
+ usb_fill_int_urb(dev->interrupt_out_urb,
+ dev->udev,
+ usb_sndintpipe(dev->udev, dev->interrupt_out_endpoint->bEndpointAddress),
+ dev->interrupt_out_buffer,
+ bytes_to_write,
+ tower_interrupt_out_callback,
+ dev,
+ dev->interrupt_out_interval);
- buffer += bytes_to_write;
- count -= bytes_to_write;
+ dev->interrupt_out_busy = 1;
+ wmb();
- bytes_written += bytes_to_write;
- }
+ retval = usb_submit_urb (dev->interrupt_out_urb, GFP_KERNEL);
+ if (retval) {
+ dev->interrupt_out_busy = 0;
+ err("Couldn't submit interrupt_out_urb %d", retval);
+ goto unlock_exit;
}
+ retval = bytes_to_write;
- retval = bytes_written;
-
-exit:
+unlock_exit:
/* unlock the device */
up (&dev->sem);
- dbg(2," %s : leave, return value %d", __func__, retval);
+exit:
+ dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);
return retval;
}
@@ -585,39 +739,53 @@
static void tower_interrupt_in_callback (struct urb *urb, struct pt_regs *regs)
{
struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+ int retval;
- dbg(4," %s : enter, status %d", __func__, urb->status);
+ dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);
- lego_usb_tower_debug_data(5,__func__, urb->actual_length, urb->transfer_buffer);
+ lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
- if (urb->status != 0) {
- if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET)) {
- dbg(1," %s : nonzero status received: %d", __func__, urb->status);
+ if (urb->status) {
+ if (urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -ESHUTDOWN) {
+ goto exit;
+ } else {
+ dbg(1, "%s: nonzero status received: %d", __FUNCTION__, urb->status);
+ goto resubmit; /* maybe we can recover */
}
- goto exit;
}
- down (&dev->sem);
-
if (urb->actual_length > 0) {
- if (dev->read_buffer_length < (4 * dev->interrupt_in_endpoint->wMaxPacketSize) - (urb->actual_length)) {
-
- memcpy (dev->read_buffer+dev->read_buffer_length, dev->interrupt_in_buffer, urb->actual_length);
-
+ spin_lock (&dev->read_buffer_lock);
+ if (dev->read_buffer_length + urb->actual_length < read_buffer_size) {
+ memcpy (dev->read_buffer + dev->read_buffer_length,
+ dev->interrupt_in_buffer,
+ urb->actual_length);
dev->read_buffer_length += urb->actual_length;
- dbg(1," %s reading %d ", __func__, urb->actual_length);
- wake_up_interruptible (&dev->read_wait);
-
+ dev->read_last_arrival = jiffies;
+ dbg(3, "%s: received %d bytes", __FUNCTION__, urb->actual_length);
} else {
- dbg(1," %s : read_buffer overflow", __func__);
+ printk(KERN_WARNING "%s: read_buffer overflow, %d bytes dropped", __FUNCTION__, urb->actual_length);
}
+ spin_unlock (&dev->read_buffer_lock);
}
- up (&dev->sem);
+resubmit:
+ /* resubmit if we're still running */
+ if (dev->interrupt_in_running && dev->udev) {
+ retval = usb_submit_urb (dev->interrupt_in_urb, GFP_ATOMIC);
+ if (retval) {
+ err("%s: usb_submit_urb failed (%d)", __FUNCTION__, retval);
+ }
+ }
exit:
- lego_usb_tower_debug_data(5,__func__, urb->actual_length, urb->transfer_buffer);
- dbg(4," %s : leave, status %d", __func__, urb->status);
+ dev->interrupt_in_done = 1;
+ wake_up_interruptible (&dev->read_wait);
+
+ lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
+ dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);
}
@@ -628,22 +796,22 @@
{
struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
- dbg(4," %s : enter, status %d", __func__, urb->status);
- lego_usb_tower_debug_data(5,__func__, urb->actual_length, urb->transfer_buffer);
+ dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);
+ lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
- if (urb->status != 0) {
- if ((urb->status != -ENOENT) &&
- (urb->status != -ECONNRESET)) {
- dbg(1, " %s :nonzero status received: %d", __func__, urb->status);
- }
- goto exit;
- }
+ /* sync/async unlink faults aren't errors */
+ if (urb->status && !(urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -ESHUTDOWN)) {
+ dbg(1, "%s - nonzero write bulk status received: %d",
+ __FUNCTION__, urb->status);
+ }
+ dev->interrupt_out_busy = 0;
wake_up_interruptible(&dev->write_wait);
-exit:
- lego_usb_tower_debug_data(5,__func__, urb->actual_length, urb->transfer_buffer);
- dbg(4," %s : leave, status %d", __func__, urb->status);
+ lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
+ dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);
}
@@ -659,15 +827,18 @@
struct lego_usb_tower *dev = NULL;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor* endpoint;
+ struct tower_reset_reply reset_reply;
+ struct tower_get_version_reply get_version_reply;
int i;
int retval = -ENOMEM;
+ int result;
- dbg(2," %s : enter", __func__);
+ dbg(2, "%s: enter", __FUNCTION__);
if (udev == NULL) {
info ("udev is NULL.");
}
-
+
/* See if the device offered us matches what we can accept */
if ((udev->descriptor.idVendor != LEGO_USB_TOWER_VENDOR_ID) ||
(udev->descriptor.idProduct != LEGO_USB_TOWER_PRODUCT_ID)) {
@@ -691,6 +862,10 @@
dev->read_buffer = NULL;
dev->read_buffer_length = 0;
+ dev->read_packet_length = 0;
+ spin_lock_init (&dev->read_buffer_lock);
+ dev->packet_timeout_jiffies = packet_timeout * HZ / 1000;
+ dev->read_last_arrival = jiffies;
init_waitqueue_head (&dev->read_wait);
init_waitqueue_head (&dev->write_wait);
@@ -698,13 +873,15 @@
dev->interrupt_in_buffer = NULL;
dev->interrupt_in_endpoint = NULL;
dev->interrupt_in_urb = NULL;
+ dev->interrupt_in_running = 0;
+ dev->interrupt_in_done = 0;
dev->interrupt_out_buffer = NULL;
dev->interrupt_out_endpoint = NULL;
dev->interrupt_out_urb = NULL;
+ dev->interrupt_out_busy = 0;
-
- iface_desc = &interface->altsetting[0];
+ iface_desc = interface->cur_altsetting;
/* set up the endpoint information */
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
@@ -714,7 +891,7 @@
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
dev->interrupt_in_endpoint = endpoint;
}
-
+
if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) &&
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
dev->interrupt_out_endpoint = endpoint;
@@ -729,7 +906,7 @@
goto error;
}
- dev->read_buffer = kmalloc ((4*dev->interrupt_in_endpoint->wMaxPacketSize), GFP_KERNEL);
+ dev->read_buffer = kmalloc (read_buffer_size, GFP_KERNEL);
if (!dev->read_buffer) {
err("Couldn't allocate read_buffer");
goto error;
@@ -744,7 +921,7 @@
err("Couldn't allocate interrupt_in_urb");
goto error;
}
- dev->interrupt_out_buffer = kmalloc (dev->interrupt_out_endpoint->wMaxPacketSize, GFP_KERNEL);
+ dev->interrupt_out_buffer = kmalloc (write_buffer_size, GFP_KERNEL);
if (!dev->interrupt_out_buffer) {
err("Couldn't allocate interrupt_out_buffer");
goto error;
@@ -753,7 +930,9 @@
if (!dev->interrupt_out_urb) {
err("Couldn't allocate interrupt_out_urb");
goto error;
- }
+ }
+ dev->interrupt_in_interval = interrupt_in_interval ? interrupt_in_interval : dev->interrupt_in_endpoint->bInterval;
+ dev->interrupt_out_interval = interrupt_out_interval ? interrupt_out_interval : dev->interrupt_out_endpoint->bInterval;
/* we can register the device now, as it is ready */
usb_set_intfdata (interface, dev);
@@ -766,16 +945,50 @@
usb_set_intfdata (interface, NULL);
goto error;
}
-
dev->minor = interface->minor;
/* let the user know what node this device is now attached to */
- info ("LEGO USB Tower device now attached to /dev/usb/lego%d", (dev->minor - LEGO_USB_TOWER_MINOR_BASE));
+ info ("LEGO USB Tower #%d now attached to major %d minor %d", (dev->minor - LEGO_USB_TOWER_MINOR_BASE), USB_MAJOR, dev->minor);
+ /* reset the tower */
+ result = usb_control_msg (udev,
+ usb_rcvctrlpipe(udev, 0),
+ LEGO_USB_TOWER_REQUEST_RESET,
+ USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
+ 0,
+ 0,
+ &reset_reply,
+ sizeof(reset_reply),
+ HZ);
+ if (result < 0) {
+ err("LEGO USB Tower reset control request failed");
+ retval = result;
+ goto error;
+ }
+
+ /* get the firmware version and log it */
+ result = usb_control_msg (udev,
+ usb_rcvctrlpipe(udev, 0),
+ LEGO_USB_TOWER_REQUEST_GET_VERSION,
+ USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
+ 0,
+ 0,
+ &get_version_reply,
+ sizeof(get_version_reply),
+ HZ);
+ if (result < 0) {
+ err("LEGO USB Tower get version control request failed");
+ retval = result;
+ goto error;
+ }
+ info("LEGO USB Tower firmware version is %d.%d build %d",
+ get_version_reply.major,
+ get_version_reply.minor,
+ le16_to_cpu(get_version_reply.build_no));
exit:
- dbg(2," %s : leave, return value 0x%.8lx (dev)", __func__, (long) dev);
+ dbg(2, "%s: leave, return value 0x%.8lx (dev)", __FUNCTION__, (long) dev);
return retval;
@@ -795,7 +1008,7 @@
struct lego_usb_tower *dev;
int minor;
- dbg(2," %s : enter", __func__);
+ dbg(2, "%s: enter", __FUNCTION__);
down (&disconnect_sem);
@@ -823,7 +1036,7 @@
info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE));
- dbg(2," %s : leave", __func__);
+ dbg(2, "%s: leave", __FUNCTION__);
}
@@ -836,7 +1049,7 @@
int result;
int retval = 0;
- dbg(2," %s : enter", __func__);
+ dbg(2, "%s: enter", __FUNCTION__);
/* register this driver with the USB subsystem */
result = usb_register(&tower_driver);
@@ -849,7 +1062,7 @@
info(DRIVER_DESC " " DRIVER_VERSION);
exit:
- dbg(2," %s : leave, return value %d", __func__, retval);
+ dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);
return retval;
}
@@ -860,12 +1073,12 @@
*/
static void __exit lego_usb_tower_exit(void)
{
- dbg(2," %s : enter", __func__);
+ dbg(2, "%s: enter", __FUNCTION__);
/* deregister this driver with the USB subsystem */
usb_deregister (&tower_driver);
- dbg(2," %s : leave", __func__);
+ dbg(2, "%s: leave", __FUNCTION__);
}
module_init (lego_usb_tower_init);
diff -Nru a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/misc/phidgetservo.c Tue May 4 22:21:21 2004
@@ -0,0 +1,327 @@
+/*
+ * USB PhidgetServo driver 1.0
+ *
+ * Copyright (C) 2004 Sean Young
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This is a driver for the USB PhidgetServo version 2.0 and 3.0 servo
+ * controllers available at: http://www.phidgets.com/
+ *
+ * Note that the driver takes input as: degrees.minutes
+ * -23 < degrees < 203
+ * 0 < minutes < 59
+ *
+ * CAUTION: Generally you should use 0 < degrees < 180 as anything else
+ * is probably beyond the range of your servo and may damage it.
+ */
+
+#include
+#ifdef CONFIG_USB_DEBUG
+#define DEBUG 1
+#endif
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define DRIVER_AUTHOR "Sean Young "
+#define DRIVER_DESC "USB PhidgetServo Driver"
+
+#define VENDOR_ID_GLAB 0x06c2
+#define DEVICE_ID_4MOTOR_SERVO_30 0x0038
+#define DEVICE_ID_1MOTOR_SERVO_30 0x0039
+
+#define VENDOR_ID_WISEGROUP 0x0925
+#define DEVICE_ID_1MOTOR_SERVO_20 0x8101
+#define DEVICE_ID_4MOTOR_SERVO_20 0x8104
+
+static struct usb_device_id id_table[] = {
+ {USB_DEVICE(VENDOR_ID_GLAB, DEVICE_ID_4MOTOR_SERVO_30)},
+ {USB_DEVICE(VENDOR_ID_GLAB, DEVICE_ID_1MOTOR_SERVO_30)},
+ {USB_DEVICE(VENDOR_ID_WISEGROUP, DEVICE_ID_4MOTOR_SERVO_20)},
+ {USB_DEVICE(VENDOR_ID_WISEGROUP, DEVICE_ID_1MOTOR_SERVO_20)},
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+struct phidget_servo {
+ struct usb_device *udev;
+ int version;
+ int quad_servo;
+ int pulse[4];
+ int degrees[4];
+ int minutes[4];
+};
+
+static void
+change_position_v30(struct phidget_servo *servo, int servo_no, int degrees,
+ int minutes)
+{
+ int retval;
+ unsigned char *buffer;
+
+ buffer = kmalloc(6, GFP_KERNEL);
+ if (!buffer) {
+ dev_err(&servo->udev->dev, "%s - out of memory\n",
+ __FUNCTION__);
+ return;
+ }
+
+ /*
+ * pulse = 0 - 4095
+ * angle = 0 - 180 degrees
+ *
+ * pulse = angle * 10.6 + 243.8
+ */
+ servo->pulse[servo_no] = ((degrees*60 + minutes)*106 + 2438*60)/600;
+ servo->degrees[servo_no]= degrees;
+ servo->minutes[servo_no]= minutes;
+
+ /*
+ * The PhidgetServo v3.0 is controlled by sending 6 bytes,
+ * 4 * 12 bits for each servo.
+ *
+ * low = lower 8 bits pulse
+ * high = higher 4 bits pulse
+ *
+ * offset bits
+ * +---+-----------------+
+ * | 0 | low 0 |
+ * +---+--------+--------+
+ * | 1 | high 1 | high 0 |
+ * +---+--------+--------+
+ * | 2 | low 1 |
+ * +---+-----------------+
+ * | 3 | low 2 |
+ * +---+--------+--------+
+ * | 4 | high 3 | high 2 |
+ * +---+--------+--------+
+ * | 5 | low 3 |
+ * +---+-----------------+
+ */
+
+ buffer[0] = servo->pulse[0] & 0xff;
+ buffer[1] = (servo->pulse[0] >> 8 & 0x0f)
+ | (servo->pulse[1] >> 4 & 0xf0);
+ buffer[2] = servo->pulse[1] & 0xff;
+ buffer[3] = servo->pulse[2] & 0xff;
+ buffer[4] = (servo->pulse[2] >> 8 & 0x0f)
+ | (servo->pulse[3] >> 4 & 0xf0);
+ buffer[5] = servo->pulse[3] & 0xff;
+
+ dev_dbg(&servo->udev->dev,
+ "data: %02x %02x %02x %02x %02x %02x\n",
+ buffer[0], buffer[1], buffer[2],
+ buffer[3], buffer[4], buffer[5]);
+
+ retval = usb_control_msg(servo->udev,
+ usb_sndctrlpipe(servo->udev, 0),
+ 0x09, 0x21, 0x0200, 0x0000, buffer, 6, 2 * HZ);
+ if (retval != 6)
+ dev_err(&servo->udev->dev, "retval = %d\n", retval);
+ kfree(buffer);
+}
+
+static void
+change_position_v20(struct phidget_servo *servo, int servo_no, int degrees,
+ int minutes)
+{
+ int retval;
+ unsigned char *buffer;
+
+ buffer = kmalloc(2, GFP_KERNEL);
+ if (!buffer) {
+ dev_err(&servo->udev->dev, "%s - out of memory\n",
+ __FUNCTION__);
+ return;
+ }
+
+ /*
+ * angle = 0 - 180 degrees
+ * pulse = angle + 23
+ */
+ servo->pulse[servo_no]= degrees + 23;
+ servo->degrees[servo_no]= degrees;
+ servo->minutes[servo_no]= 0;
+
+ /*
+ * The PhidgetServo v2.0 is controlled by sending two bytes. The
+ * first byte is the servo number xor'ed with 2:
+ *
+ * servo 0 = 2
+ * servo 1 = 3
+ * servo 2 = 0
+ * servo 3 = 1
+ *
+ * The second byte is the position.
+ */
+
+ buffer[0] = servo_no ^ 2;
+ buffer[1] = servo->pulse[servo_no];
+
+ dev_dbg(&servo->udev->dev, "data: %02x %02x\n", buffer[0], buffer[1]);
+
+ retval = usb_control_msg(servo->udev,
+ usb_sndctrlpipe(servo->udev, 0),
+ 0x09, 0x21, 0x0200, 0x0000, buffer, 2, 2 * HZ);
+ if (retval != 2)
+ dev_err(&servo->udev->dev, "retval = %d\n", retval);
+ kfree(buffer);
+}
+
+#define show_set(value) \
+static ssize_t set_servo##value (struct device *dev, \
+ const char *buf, size_t count) \
+{ \
+ int degrees, minutes; \
+ struct usb_interface *intf = to_usb_interface (dev); \
+ struct phidget_servo *servo = usb_get_intfdata (intf); \
+ \
+ minutes = 0; \
+ /* must at least convert degrees */ \
+ if (sscanf (buf, "%d.%d", °rees, &minutes) < 1) { \
+ return -EINVAL; \
+ } \
+ \
+ if (degrees < -23 || degrees > (180 + 23) || \
+ minutes < 0 || minutes > 59) { \
+ return -EINVAL; \
+ } \
+ \
+ if (servo->version >= 3) \
+ change_position_v30 (servo, value, degrees, minutes); \
+ else \
+ change_position_v20 (servo, value, degrees, minutes); \
+ \
+ return count; \
+} \
+ \
+static ssize_t show_servo##value (struct device *dev, char *buf) \
+{ \
+ struct usb_interface *intf = to_usb_interface (dev); \
+ struct phidget_servo *servo = usb_get_intfdata (intf); \
+ \
+ return sprintf (buf, "%d.%02d\n", servo->degrees[value], \
+ servo->minutes[value]); \
+} \
+static DEVICE_ATTR(servo##value, S_IWUGO | S_IRUGO, \
+ show_servo##value, set_servo##value);
+
+show_set(0);
+show_set(1);
+show_set(2);
+show_set(3);
+
+static int
+servo_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(interface);
+ struct phidget_servo *dev = NULL;
+
+ dev = kmalloc(sizeof (struct phidget_servo), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+ memset(dev, 0x00, sizeof (*dev));
+
+ dev->udev = usb_get_dev(udev);
+ switch (udev->descriptor.idVendor) {
+ case VENDOR_ID_WISEGROUP:
+ dev->version = 2;
+ break;
+ case VENDOR_ID_GLAB:
+ dev->version = 3;
+ break;
+ }
+ switch (udev->descriptor.idProduct) {
+ case DEVICE_ID_4MOTOR_SERVO_20:
+ case DEVICE_ID_4MOTOR_SERVO_30:
+ dev->quad_servo = 1;
+ break;
+ case DEVICE_ID_1MOTOR_SERVO_20:
+ case DEVICE_ID_1MOTOR_SERVO_30:
+ dev->quad_servo = 0;
+ break;
+ }
+
+ usb_set_intfdata(interface, dev);
+
+ device_create_file(&interface->dev, &dev_attr_servo0);
+ if (dev->quad_servo) {
+ device_create_file(&interface->dev, &dev_attr_servo1);
+ device_create_file(&interface->dev, &dev_attr_servo2);
+ device_create_file(&interface->dev, &dev_attr_servo3);
+ }
+
+ dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 attached\n",
+ dev->quad_servo ? 4 : 1, dev->version);
+ if (dev->version == 2)
+ dev_info(&interface->dev,
+ "WARNING: v2.0 not tested! Please report if it works.\n");
+
+ return 0;
+}
+
+static void
+servo_disconnect(struct usb_interface *interface)
+{
+ struct phidget_servo *dev;
+
+ dev = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+ device_remove_file(&interface->dev, &dev_attr_servo0);
+ if (dev->quad_servo) {
+ device_remove_file(&interface->dev, &dev_attr_servo1);
+ device_remove_file(&interface->dev, &dev_attr_servo2);
+ device_remove_file(&interface->dev, &dev_attr_servo3);
+ }
+
+ usb_put_dev(dev->udev);
+
+ kfree(dev);
+
+ dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 detached\n",
+ dev->quad_servo ? 4 : 1, dev->version);
+}
+
+static struct usb_driver servo_driver = {
+ .owner = THIS_MODULE,
+ .name = "phidgetservo",
+ .probe = servo_probe,
+ .disconnect = servo_disconnect,
+ .id_table = id_table
+};
+
+static int __init
+phidget_servo_init(void)
+{
+ int retval = 0;
+
+ retval = usb_register(&servo_driver);
+ if (retval)
+ err("usb_register failed. Error number %d", retval);
+
+ return retval;
+}
+
+static void __exit
+phidget_servo_exit(void)
+{
+ usb_deregister(&servo_driver);
+}
+
+module_init(phidget_servo_init);
+module_exit(phidget_servo_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 Tue May 4 22:21:21 2004
+++ b/drivers/usb/misc/usbtest.c Tue May 4 22:21:21 2004
@@ -802,6 +802,7 @@
switch (status) {
case -EINPROGRESS:
case -EBUSY:
+ case -EIDRM:
continue;
default:
dbg ("urb unlink --> %d", status);
@@ -1038,8 +1039,6 @@
if (!status)
status = usb_submit_urb (urb, SLAB_ATOMIC);
if (status) {
- if (status == -ECONNRESET || status == -ENOENT)
- status = 0;
urb->status = status;
complete ((struct completion *) urb->context);
}
@@ -1077,8 +1076,9 @@
wait_ms (jiffies % (2 * INTERRUPT_RATE));
retry:
retval = usb_unlink_urb (urb);
- if (retval == -EBUSY) {
+ if (retval == -EBUSY || retval == -EIDRM) {
/* we can't unlink urbs while they're completing.
+ * or if they've completed, and we haven't resubmitted.
* "normal" drivers would prevent resubmission, but
* since we're testing unlink paths, we can't.
*/
diff -Nru a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
--- a/drivers/usb/misc/uss720.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/misc/uss720.c Tue May 4 22:21:21 2004
@@ -553,7 +553,7 @@
i = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2);
printk(KERN_DEBUG "uss720: set inteface result %d\n", i);
- interface = &intf->altsetting[2];
+ interface = intf->cur_altsetting;
/*
* Allocate parport interface
diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
--- a/drivers/usb/net/usbnet.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/net/usbnet.c Tue May 4 22:21:21 2004
@@ -928,8 +928,8 @@
*/
static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf)
{
- u8 *buf = intf->altsetting->extra;
- int len = intf->altsetting->extralen;
+ u8 *buf = intf->cur_altsetting->extra;
+ int len = intf->cur_altsetting->extralen;
struct usb_interface_descriptor *d;
struct cdc_state *info = (void *) &dev->data;
int status;
@@ -955,7 +955,7 @@
/* this assumes that if there's a non-RNDIS vendor variant
* of cdc-acm, it'll fail RNDIS requests cleanly.
*/
- rndis = (intf->altsetting->desc.bInterfaceProtocol == 0xff);
+ rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff);
memset (info, 0, sizeof *info);
info->control = intf;
@@ -1025,7 +1025,7 @@
}
/* a data interface altsetting does the real i/o */
- d = &info->data->altsetting->desc;
+ d = &info->data->cur_altsetting->desc;
if (d->bInterfaceClass != USB_CLASS_CDC_DATA) {
dev_dbg (&intf->dev, "slave class %u\n",
d->bInterfaceClass);
diff -Nru a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
--- a/drivers/usb/serial/io_ti.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/serial/io_ti.c Tue May 4 22:21:21 2004
@@ -995,7 +995,7 @@
if (status)
return status;
- interface = &serial->serial->dev->config->interface[0]->altsetting->desc;
+ interface = &serial->serial->interface->cur_altsetting->desc;
if (!interface) {
dev_err (&serial->serial->dev->dev, "%s - no interface set, error!", __FUNCTION__);
return -ENODEV;
diff -Nru a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
--- a/drivers/usb/serial/keyspan.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/serial/keyspan.c Tue May 4 22:21:21 2004
@@ -133,9 +133,6 @@
/* Per device and per port private data */
struct keyspan_serial_private {
- /* number of active ports */
- atomic_t active_count;
-
const struct keyspan_device_details *device_details;
struct urb *instat_urb;
diff -Nru a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
--- a/drivers/usb/serial/kobil_sct.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/serial/kobil_sct.c Tue May 4 22:21:21 2004
@@ -183,7 +183,7 @@
pdev = serial->dev;
actconfig = pdev->actconfig;
interface = actconfig->interface[0];
- altsetting = interface->altsetting;
+ altsetting = interface->cur_altsetting;
endpoint = altsetting->endpoint;
for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
diff -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
--- a/drivers/usb/serial/pl2303.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/serial/pl2303.c Tue May 4 22:21:21 2004
@@ -80,6 +80,7 @@
{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
{ USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
+ { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
{ } /* Terminating entry */
};
diff -Nru a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
--- a/drivers/usb/serial/pl2303.h Tue May 4 22:21:21 2004
+++ b/drivers/usb/serial/pl2303.h Tue May 4 22:21:21 2004
@@ -41,3 +41,6 @@
#define SITECOM_VENDOR_ID 0x6189
#define SITECOM_PRODUCT_ID 0x2068
+
+#define ALCATEL_VENDOR_ID 0x11f7
+#define ALCATEL_PRODUCT_ID 0x02df
diff -Nru a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
--- a/drivers/usb/serial/safe_serial.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/serial/safe_serial.c Tue May 4 22:21:21 2004
@@ -395,7 +395,7 @@
static int safe_startup (struct usb_serial *serial)
{
- switch (serial->interface->altsetting->desc.bInterfaceProtocol) {
+ switch (serial->interface->cur_altsetting->desc.bInterfaceProtocol) {
case LINEO_SAFESERIAL_CRC:
break;
case LINEO_SAFESERIAL_CRC_PADDED:
diff -Nru a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
--- a/drivers/usb/serial/usb-serial.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/serial/usb-serial.c Tue May 4 22:21:21 2004
@@ -1037,7 +1037,7 @@
(dev->descriptor.idProduct == ATEN_PRODUCT_ID))) {
if (interface != dev->actconfig->interface[0]) {
/* check out the endpoints of the other interface*/
- iface_desc = &dev->actconfig->interface[0]->altsetting[0];
+ iface_desc = dev->actconfig->interface[0]->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
if ((endpoint->bEndpointAddress & 0x80) &&
diff -Nru a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
--- a/drivers/usb/storage/scsiglue.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/storage/scsiglue.c Tue May 4 22:21:21 2004
@@ -159,14 +159,18 @@
return FAILED;
}
- /* Set state to ABORTING, set the ABORTING bit, and release the lock */
+ /* Set state to ABORTING and set the ABORTING bit, but only if
+ * a device reset isn't already in progress (to avoid interfering
+ * with the reset). To prevent races with auto-reset, we must
+ * stop any ongoing USB transfers while still holding the host
+ * lock. */
us->sm_state = US_STATE_ABORTING;
- set_bit(US_FLIDX_ABORTING, &us->flags);
+ if (!test_bit(US_FLIDX_RESETTING, &us->flags)) {
+ set_bit(US_FLIDX_ABORTING, &us->flags);
+ usb_stor_stop_transport(us);
+ }
scsi_unlock(host);
- /* Stop an ongoing USB transfer */
- usb_stor_stop_transport(us);
-
/* Wait for the aborted command to finish */
wait_for_completion(&us->notify);
@@ -254,18 +258,17 @@
}
/* Report a driver-initiated device reset to the SCSI layer.
- * Calling this for a SCSI-initiated reset is unnecessary but harmless. */
+ * Calling this for a SCSI-initiated reset is unnecessary but harmless.
+ * The caller must own the SCSI host lock. */
void usb_stor_report_device_reset(struct us_data *us)
{
int i;
- scsi_lock(us->host);
scsi_report_device_reset(us->host, 0, 0);
if (us->flags & US_FL_SCM_MULT_TARG) {
for (i = 1; i < us->host->max_id; ++i)
scsi_report_device_reset(us->host, 0, i);
}
- scsi_unlock(us->host);
}
/***********************************************************************
diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
--- a/drivers/usb/storage/transport.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/storage/transport.c Tue May 4 22:21:21 2004
@@ -137,7 +137,7 @@
int status;
/* don't submit URBs during abort/disconnect processing */
- if (us->flags & DONT_SUBMIT)
+ if (us->flags & ABORTING_OR_DISCONNECTING)
return -EIO;
/* set up data structures for the wakeup system */
@@ -172,7 +172,7 @@
set_bit(US_FLIDX_URB_ACTIVE, &us->flags);
/* did an abort/disconnect occur during the submission? */
- if (us->flags & DONT_SUBMIT) {
+ if (us->flags & ABORTING_OR_DISCONNECTING) {
/* cancel the URB, if it hasn't been cancelled already */
if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->flags)) {
@@ -440,7 +440,7 @@
int result;
/* don't submit s-g requests during abort/disconnect processing */
- if (us->flags & DONT_SUBMIT)
+ if (us->flags & ABORTING_OR_DISCONNECTING)
return USB_STOR_XFER_ERROR;
/* initialize the scatter-gather request block */
@@ -458,7 +458,7 @@
set_bit(US_FLIDX_SG_ACTIVE, &us->flags);
/* did an abort/disconnect occur during the submission? */
- if (us->flags & DONT_SUBMIT) {
+ if (us->flags & ABORTING_OR_DISCONNECTING) {
/* cancel the request, if it hasn't been cancelled already */
if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->flags)) {
@@ -712,14 +712,10 @@
/* abort processing: the bulk-only transport requires a reset
* following an abort */
- Handle_Abort:
+ Handle_Abort:
srb->result = DID_ABORT << 16;
- if (us->protocol == US_PR_BULK) {
-
- /* permit the reset transfer to take place */
- clear_bit(US_FLIDX_ABORTING, &us->flags);
+ if (us->protocol == US_PR_BULK)
us->transport_reset(us);
- }
}
/* Stop the current URB transfer */
@@ -912,6 +908,17 @@
USB_RECIP_INTERFACE,
0, us->ifnum, us->iobuf, 1, HZ);
+ /*
+ * Some devices (i.e. Iomega Zip100) need this -- apparently
+ * the bulk pipes get STALLed when the GetMaxLUN request is
+ * processed. This is, in theory, harmless to all other devices
+ * (regardless of if they stall or not).
+ */
+ if (result < 0) {
+ usb_stor_clear_halt(us, us->recv_bulk_pipe);
+ usb_stor_clear_halt(us, us->send_bulk_pipe);
+ }
+
US_DEBUGP("GetMaxLUN command result is %d, data is %d\n",
result, us->iobuf[0]);
@@ -1079,20 +1086,28 @@
{
int result;
int result2;
+ int rc = FAILED;
- /* Let the SCSI layer know we are doing a reset */
+ /* Let the SCSI layer know we are doing a reset, set the
+ * RESETTING bit, and clear the ABORTING bit so that the reset
+ * may proceed.
+ */
+ scsi_lock(us->host);
usb_stor_report_device_reset(us);
+ set_bit(US_FLIDX_RESETTING, &us->flags);
+ clear_bit(US_FLIDX_ABORTING, &us->flags);
+ scsi_unlock(us->host);
/* A 20-second timeout may seem rather long, but a LaCie
- * StudioDrive USB2 device takes 16+ seconds to get going
- * following a powerup or USB attach event. */
-
+ * StudioDrive USB2 device takes 16+ seconds to get going
+ * following a powerup or USB attach event.
+ */
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
request, requesttype, value, index, data, size,
20*HZ);
if (result < 0) {
US_DEBUGP("Soft reset failed: %d\n", result);
- return FAILED;
+ goto Done;
}
/* long wait for reset, so unlock to allow disconnects */
@@ -1102,12 +1117,9 @@
down(&us->dev_semaphore);
if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
US_DEBUGP("Reset interrupted by disconnect\n");
- return FAILED;
+ goto Done;
}
- /* permit the clear-halt transfers to take place */
- clear_bit(US_FLIDX_ABORTING, &us->flags);
-
US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n");
result = usb_stor_clear_halt(us, us->recv_bulk_pipe);
@@ -1117,10 +1129,14 @@
/* return a result code based on the result of the control message */
if (result < 0 || result2 < 0) {
US_DEBUGP("Soft reset failed\n");
- return FAILED;
+ goto Done;
}
US_DEBUGP("Soft reset done\n");
- return SUCCESS;
+ rc = SUCCESS;
+
+ Done:
+ clear_bit(US_FLIDX_RESETTING, &us->flags);
+ return rc;
}
/* This issues a CB[I] Reset to the device in question
diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
--- a/drivers/usb/storage/unusual_devs.h Tue May 4 22:21:21 2004
+++ b/drivers/usb/storage/unusual_devs.h Tue May 4 22:21:21 2004
@@ -438,22 +438,6 @@
US_FL_SINGLE_LUN ),
#endif
-/* Following three Minolta cameras reported by Martin Pool
- * . Originally discovered by Kedar Petankar,
- * Matthew Geier, Mikael Lofj"ard, Marcel de Boer.
- */
-UNUSUAL_DEV( 0x0686, 0x4006, 0x0001, 0x0001,
- "Minolta",
- "DiMAGE 7",
- US_SC_SCSI, US_PR_DEVICE, NULL,
- 0 ),
-
-UNUSUAL_DEV( 0x0686, 0x400f, 0x0001, 0x0001,
- "Minolta",
- "DiMAGE 7Hi",
- US_SC_SCSI, US_PR_DEVICE, NULL,
- 0 ),
-
/* Submitted by Benny Sjostrand */
UNUSUAL_DEV( 0x0686, 0x4011, 0x0001, 0x0001,
"Minolta",
@@ -629,7 +613,7 @@
"Casio",
"QV DigitalCamera",
US_SC_DEVICE, US_PR_CB, NULL,
- US_FL_FIX_INQUIRY ),
+ US_FL_NEED_OVERRIDE | US_FL_FIX_INQUIRY ),
/* Later Casio cameras apparently tell the truth */
UNUSUAL_DEV( 0x07cf, 0x1001, 0x9010, 0x9999,
@@ -688,7 +672,7 @@
UNUSUAL_DEV( 0x0a16, 0x8888, 0x0100, 0x0100,
"IBM",
"IBM USB Memory Key",
- US_SC_SCSI, US_PR_BULK, NULL,
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
/* This Pentax still camera is not conformant
diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
--- a/drivers/usb/storage/usb.c Tue May 4 22:21:21 2004
+++ b/drivers/usb/storage/usb.c Tue May 4 22:21:21 2004
@@ -84,8 +84,6 @@
#include
-#include
-#include
#include
#include
@@ -490,7 +488,7 @@
if (unusual_dev->useTransport != US_PR_DEVICE &&
us->protocol == idesc->bInterfaceProtocol)
msg += 2;
- if (msg >= 0)
+ if (msg >= 0 && !(unusual_dev->flags & US_FL_NEED_OVERRIDE))
printk(KERN_NOTICE USB_STORAGE "This device "
"(%04x,%04x,%04x S %02x P %02x)"
" has %s in unusual_devs.h\n"
diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
--- a/drivers/usb/storage/usb.h Tue May 4 22:21:21 2004
+++ b/drivers/usb/storage/usb.h Tue May 4 22:21:21 2004
@@ -69,6 +69,7 @@
/* Flag definitions: these entries are static */
#define US_FL_SINGLE_LUN 0x00000001 /* allow access to only LUN 0 */
#define US_FL_MODE_XLATE 0 /* [no longer used] */
+#define US_FL_NEED_OVERRIDE 0x00000004 /* unusual_devs entry is necessary */
#define US_FL_IGNORE_SER 0 /* [no longer used] */
#define US_FL_SCM_MULT_TARG 0x00000020 /* supports multiple targets */
#define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs faking */
@@ -79,8 +80,9 @@
#define US_FLIDX_SG_ACTIVE 19 /* 0x00080000 current_sg is in use */
#define US_FLIDX_ABORTING 20 /* 0x00100000 abort is in progress */
#define US_FLIDX_DISCONNECTING 21 /* 0x00200000 disconnect in progress */
-#define DONT_SUBMIT ((1UL << US_FLIDX_ABORTING) | \
- (1UL << US_FLIDX_DISCONNECTING))
+#define ABORTING_OR_DISCONNECTING ((1UL << US_FLIDX_ABORTING) | \
+ (1UL << US_FLIDX_DISCONNECTING))
+#define US_FLIDX_RESETTING 22 /* 0x00400000 device reset in progress */
/* processing state machine states */
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h Tue May 4 22:21:21 2004
+++ b/include/linux/usb.h Tue May 4 22:21:21 2004
@@ -14,6 +14,7 @@
#include /* for mdelay() */
#include /* for in_interrupt() */
#include /* for struct list_head */
+#include /* for struct kref */
#include /* for struct device */
#include /* for struct file_operations */
#include /* for struct completion */
@@ -147,11 +148,42 @@
#define USB_MAXINTERFACES 32
/**
+ * struct usb_interface_cache - long-term representation of a device interface
+ * @num_altsetting: number of altsettings defined.
+ * @ref: reference counter.
+ * @altsetting: variable-length array of interface structures, one for
+ * each alternate setting that may be selected. Each one includes a
+ * set of endpoint configurations. They will be in no particular order.
+ *
+ * These structures persist for the lifetime of a usb_device, unlike
+ * struct usb_interface (which persists only as long as its configuration
+ * is installed). The altsetting arrays can be accessed through these
+ * structures at any time, permitting comparison of configurations and
+ * providing support for the /proc/bus/usb/devices pseudo-file.
+ */
+struct usb_interface_cache {
+ unsigned num_altsetting; /* number of alternate settings */
+ struct kref ref; /* reference counter */
+
+ /* variable-length array of alternate settings for this interface,
+ * stored in no particular order */
+ struct usb_host_interface altsetting[0];
+};
+#define ref_to_usb_interface_cache(r) \
+ container_of(r, struct usb_interface_cache, ref)
+#define altsetting_to_usb_interface_cache(a) \
+ container_of(a, struct usb_interface_cache, altsetting[0])
+
+/**
* struct usb_host_config - representation of a device's configuration
* @desc: the device's configuration descriptor.
- * @interface: array of usb_interface structures, one for each interface
- * in the configuration. The number of interfaces is stored in
- * desc.bNumInterfaces.
+ * @interface: array of pointers to usb_interface structures, one for each
+ * interface in the configuration. The number of interfaces is stored
+ * in desc.bNumInterfaces. These pointers are valid only while the
+ * the configuration is active.
+ * @intf_cache: array of pointers to usb_interface_cache structures, one
+ * for each interface in the configuration. These structures exist
+ * for the entire life of the device.
* @extra: pointer to buffer containing all extra descriptors associated
* with this configuration (those preceding the first interface
* descriptor).
@@ -185,6 +217,10 @@
* stored in no particular order */
struct usb_interface *interface[USB_MAXINTERFACES];
+ /* Interface information available even when this is not the
+ * active configuration */
+ struct usb_interface_cache *intf_cache[USB_MAXINTERFACES];
+
unsigned char *extra; /* Extra descriptors */
int extralen;
};
@@ -676,7 +712,7 @@
* URB_NO_SETUP_DMA_MAP indicate which buffers have already been mapped.
* URB_NO_SETUP_DMA_MAP is ignored for non-control URBs.
*
- * Interrupt UBS must provide an interval, saying how often (in milliseconds
+ * Interrupt URBs must provide an interval, saying how often (in milliseconds
* or, for highspeed devices, 125 microsecond units)
* to poll for transfers. After the URB has been submitted, the interval
* field reflects how the transfer was actually scheduled.
@@ -731,8 +767,8 @@
struct urb
{
/* private, usb core and host controller only fields in the urb */
+ struct kref kref; /* reference count of the URB */
spinlock_t lock; /* lock for the URB */
- atomic_t count; /* reference count of the URB */
void *hcpriv; /* private data for host controller */
struct list_head urb_list; /* list pointer to all active urbs */
int bandwidth; /* bandwidth for INT/ISO request */
diff -Nru a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h
--- a/include/linux/usbdevice_fs.h Tue May 4 22:21:21 2004
+++ b/include/linux/usbdevice_fs.h Tue May 4 22:21:21 2004
@@ -154,7 +154,6 @@
struct dev_state {
struct list_head list; /* state list */
- struct rw_semaphore devsem; /* protects modifications to dev (dev == NULL indicating disconnect) */
struct usb_device *dev;
struct file *file;
spinlock_t lock; /* protects the async urb lists */