Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Fri, 12 Oct 2007 22:49:10 +0000 (15:49 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Fri, 12 Oct 2007 22:49:10 +0000 (15:49 -0700)
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6: (142 commits)
  USB: fix race in autosuspend reschedule
  atmel_usba_udc: Keep track of the device status
  USB: Nikon D40X unusual_devs entry
  USB: serial core should respect driver requirements
  USB: documentation for USB power management
  USB: skip autosuspended devices during system resume
  USB: mutual exclusion for EHCI init and port resets
  USB: allow usbstorage to have LUNS greater than 2Tb
  USB: Adding support for SHARP WS011SH to ipaq.c
  USB: add atmel_usba_udc driver
  USB: ohci SSB bus glue
  USB: ehci build fixes on au1xxx, ppc-soc
  USB: add runtime frame_no quirk for big-endian OHCI
  USB: funsoft: Fix termios
  USB: visor: termios bits
  USB: unusual_devs entry for Nikon DSC D2Xs
  USB: re-remove <linux/usb_sl811.h>
  USB: move <linux/usb_gadget.h> to <linux/usb/gadget.h>
  USB: Export URB statistics for powertop
  USB: serial gadget: Disable endpoints on unload
  ...

117 files changed:
Documentation/usb/authorization.txt [new file with mode: 0644]
Documentation/usb/power-management.txt [new file with mode: 0644]
Documentation/usb/usb-serial.txt
Documentation/usb/usbmon.txt
MAINTAINERS
arch/blackfin/mach-bf537/boards/generic_board.c
arch/blackfin/mach-bf537/boards/pnav10.c
arch/blackfin/mach-bf537/boards/stamp.c
drivers/usb/Makefile
drivers/usb/atm/cxacru.c
drivers/usb/atm/speedtch.c
drivers/usb/atm/ueagle-atm.c
drivers/usb/class/usblp.c
drivers/usb/core/config.c
drivers/usb/core/devio.c
drivers/usb/core/driver.c
drivers/usb/core/endpoint.c
drivers/usb/core/generic.c
drivers/usb/core/hcd.c
drivers/usb/core/hcd.h
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/quirks.c
drivers/usb/core/sysfs.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
drivers/usb/core/usb.h
drivers/usb/gadget/Kconfig
drivers/usb/gadget/Makefile
drivers/usb/gadget/amd5536udc.c
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/atmel_usba_udc.c [new file with mode: 0644]
drivers/usb/gadget/atmel_usba_udc.h [new file with mode: 0644]
drivers/usb/gadget/config.c
drivers/usb/gadget/dummy_hcd.c
drivers/usb/gadget/epautoconf.c
drivers/usb/gadget/ether.c
drivers/usb/gadget/file_storage.c
drivers/usb/gadget/fsl_usb2_udc.c
drivers/usb/gadget/gmidi.c
drivers/usb/gadget/goku_udc.c
drivers/usb/gadget/inode.c
drivers/usb/gadget/lh7a40x_udc.h
drivers/usb/gadget/m66592-udc.c
drivers/usb/gadget/net2280.c
drivers/usb/gadget/omap_udc.c
drivers/usb/gadget/pxa2xx_udc.c
drivers/usb/gadget/s3c2410_udc.c
drivers/usb/gadget/serial.c
drivers/usb/gadget/usbstring.c
drivers/usb/gadget/zero.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-au1xxx.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-ppc-soc.c
drivers/usb/host/ehci-ps3.c
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/isp116x-hcd.c
drivers/usb/host/ohci-dbg.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-mem.c
drivers/usb/host/ohci-pci.c
drivers/usb/host/ohci-ppc-of.c
drivers/usb/host/ohci-ppc-soc.c
drivers/usb/host/ohci-q.c
drivers/usb/host/ohci-ssb.c [new file with mode: 0644]
drivers/usb/host/ohci.h
drivers/usb/host/r8a66597-hcd.c
drivers/usb/host/sl811-hcd.c
drivers/usb/host/u132-hcd.c
drivers/usb/host/uhci-debug.c
drivers/usb/host/uhci-hcd.h
drivers/usb/host/uhci-q.c
drivers/usb/misc/adutux.c
drivers/usb/misc/berry_charge.c
drivers/usb/misc/ftdi-elan.c
drivers/usb/misc/sisusbvga/sisusb.c
drivers/usb/misc/sisusbvga/sisusb.h
drivers/usb/misc/sisusbvga/sisusb_con.c
drivers/usb/misc/sisusbvga/sisusb_init.c
drivers/usb/misc/sisusbvga/sisusb_init.h
drivers/usb/misc/sisusbvga/sisusb_struct.h
drivers/usb/mon/mon_bin.c
drivers/usb/mon/mon_main.c
drivers/usb/mon/mon_text.c
drivers/usb/mon/usb_mon.h
drivers/usb/serial/Kconfig
drivers/usb/serial/Makefile
drivers/usb/serial/ark3116.c
drivers/usb/serial/bus.c
drivers/usb/serial/ch341.c [new file with mode: 0644]
drivers/usb/serial/cp2101.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/funsoft.c
drivers/usb/serial/ipaq.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/serial/kobil_sct.c
drivers/usb/serial/mct_u232.c
drivers/usb/serial/oti6858.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/pl2303.h
drivers/usb/serial/safe_serial.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/visor.c
drivers/usb/storage/initializers.c
drivers/usb/storage/initializers.h
drivers/usb/storage/shuttle_usbat.c
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/usb.c
drivers/usb/usb-skeleton.c
include/linux/usb.h
include/linux/usb/gadget.h [moved from include/linux/usb_gadget.h with 92% similarity]
include/linux/usb/quirks.h
include/linux/usb/serial.h
include/linux/usb_sl811.h [deleted file]

diff --git a/Documentation/usb/authorization.txt b/Documentation/usb/authorization.txt
new file mode 100644 (file)
index 0000000..2af4006
--- /dev/null
@@ -0,0 +1,92 @@
+
+Authorizing (or not) your USB devices to connect to the system
+
+(C) 2007 Inaky Perez-Gonzalez <inaky@linux.intel.com> Intel Corporation
+
+This feature allows you to control if a USB device can be used (or
+not) in a system. This feature will allow you to implement a lock-down
+of USB devices, fully controlled by user space.
+
+As of now, when a USB device is connected it is configured and
+it's interfaces inmediately made available to the users. With this
+modification, only if root authorizes the device to be configured will
+then it be possible to use it.
+
+Usage:
+
+Authorize a device to connect:
+
+$ echo 1 > /sys/usb/devices/DEVICE/authorized
+
+Deauthorize a device:
+
+$ echo 0 > /sys/usb/devices/DEVICE/authorized
+
+Set new devices connected to hostX to be deauthorized by default (ie:
+lock down):
+
+$ echo 0 > /sys/bus/devices/usbX/authorized_default
+
+Remove the lock down:
+
+$ echo 1 > /sys/bus/devices/usbX/authorized_default
+
+By default, Wired USB devices are authorized by default to
+connect. Wireless USB hosts deauthorize by default all new connected
+devices (this is so because we need to do an authentication phase
+before authorizing).
+
+
+Example system lockdown (lame)
+-----------------------
+
+Imagine you want to implement a lockdown so only devices of type XYZ
+can be connected (for example, it is a kiosk machine with a visible
+USB port):
+
+boot up
+rc.local ->
+
+ for host in /sys/bus/devices/usb*
+ do
+    echo 0 > $host/authorized_default
+ done
+
+Hookup an script to udev, for new USB devices
+
+ if device_is_my_type $DEV
+ then
+   echo 1 > $device_path/authorized
+ done
+
+
+Now, device_is_my_type() is where the juice for a lockdown is. Just
+checking if the class, type and protocol match something is the worse
+security verification you can make (or the best, for someone willing
+to break it). If you need something secure, use crypto and Certificate
+Authentication or stuff like that. Something simple for an storage key
+could be:
+
+function device_is_my_type()
+{
+   echo 1 > authorized         # temporarily authorize it
+                                # FIXME: make sure none can mount it
+   mount DEVICENODE /mntpoint
+   sum=$(md5sum /mntpoint/.signature)
+   if [ $sum = $(cat /etc/lockdown/keysum) ]
+   then
+        echo "We are good, connected"
+        umount /mntpoint
+        # Other stuff so others can use it
+   else
+        echo 0 > authorized
+   fi
+}
+
+
+Of course, this is lame, you'd want to do a real certificate
+verification stuff with PKI, so you don't depend on a shared secret,
+etc, but you get the idea. Anybody with access to a device gadget kit
+can fake descriptors and device info. Don't trust that. You are
+welcome.
+
diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt
new file mode 100644 (file)
index 0000000..97842de
--- /dev/null
@@ -0,0 +1,517 @@
+                       Power Management for USB
+
+                Alan Stern <stern@rowland.harvard.edu>
+
+                           October 5, 2007
+
+
+
+       What is Power Management?
+       -------------------------
+
+Power Management (PM) is the practice of saving energy by suspending
+parts of a computer system when they aren't being used.  While a
+component is "suspended" it is in a nonfunctional low-power state; it
+might even be turned off completely.  A suspended component can be
+"resumed" (returned to a functional full-power state) when the kernel
+needs to use it.  (There also are forms of PM in which components are
+placed in a less functional but still usable state instead of being
+suspended; an example would be reducing the CPU's clock rate.  This
+document will not discuss those other forms.)
+
+When the parts being suspended include the CPU and most of the rest of
+the system, we speak of it as a "system suspend".  When a particular
+device is turned off while the system as a whole remains running, we
+call it a "dynamic suspend" (also known as a "runtime suspend" or
+"selective suspend").  This document concentrates mostly on how
+dynamic PM is implemented in the USB subsystem, although system PM is
+covered to some extent (see Documentation/power/*.txt for more
+information about system PM).
+
+Note: Dynamic PM support for USB is present only if the kernel was
+built with CONFIG_USB_SUSPEND enabled.  System PM support is present
+only if the kernel was built with CONFIG_SUSPEND or CONFIG_HIBERNATION
+enabled.
+
+
+       What is Remote Wakeup?
+       ----------------------
+
+When a device has been suspended, it generally doesn't resume until
+the computer tells it to.  Likewise, if the entire computer has been
+suspended, it generally doesn't resume until the user tells it to, say
+by pressing a power button or opening the cover.
+
+However some devices have the capability of resuming by themselves, or
+asking the kernel to resume them, or even telling the entire computer
+to resume.  This capability goes by several names such as "Wake On
+LAN"; we will refer to it generically as "remote wakeup".  When a
+device is enabled for remote wakeup and it is suspended, it may resume
+itself (or send a request to be resumed) in response to some external
+event.  Examples include a suspended keyboard resuming when a key is
+pressed, or a suspended USB hub resuming when a device is plugged in.
+
+
+       When is a USB device idle?
+       --------------------------
+
+A device is idle whenever the kernel thinks it's not busy doing
+anything important and thus is a candidate for being suspended.  The
+exact definition depends on the device's driver; drivers are allowed
+to declare that a device isn't idle even when there's no actual
+communication taking place.  (For example, a hub isn't considered idle
+unless all the devices plugged into that hub are already suspended.)
+In addition, a device isn't considered idle so long as a program keeps
+its usbfs file open, whether or not any I/O is going on.
+
+If a USB device has no driver, its usbfs file isn't open, and it isn't
+being accessed through sysfs, then it definitely is idle.
+
+
+       Forms of dynamic PM
+       -------------------
+
+Dynamic suspends can occur in two ways: manual and automatic.
+"Manual" means that the user has told the kernel to suspend a device,
+whereas "automatic" means that the kernel has decided all by itself to
+suspend a device.  Automatic suspend is called "autosuspend" for
+short.  In general, a device won't be autosuspended unless it has been
+idle for some minimum period of time, the so-called idle-delay time.
+
+Of course, nothing the kernel does on its own initiative should
+prevent the computer or its devices from working properly.  If a
+device has been autosuspended and a program tries to use it, the
+kernel will automatically resume the device (autoresume).  For the
+same reason, an autosuspended device will usually have remote wakeup
+enabled, if the device supports remote wakeup.
+
+It is worth mentioning that many USB drivers don't support
+autosuspend.  In fact, at the time of this writing (Linux 2.6.23) the
+only drivers which do support it are the hub driver, kaweth, asix,
+usblp, usblcd, and usb-skeleton (which doesn't count).  If a
+non-supporting driver is bound to a device, the device won't be
+autosuspended.  In effect, the kernel pretends the device is never
+idle.
+
+We can categorize power management events in two broad classes:
+external and internal.  External events are those triggered by some
+agent outside the USB stack: system suspend/resume (triggered by
+userspace), manual dynamic suspend/resume (also triggered by
+userspace), and remote wakeup (triggered by the device).  Internal
+events are those triggered within the USB stack: autosuspend and
+autoresume.
+
+
+       The user interface for dynamic PM
+       ---------------------------------
+
+The user interface for controlling dynamic PM is located in the power/
+subdirectory of each USB device's sysfs directory, that is, in
+/sys/bus/usb/devices/.../power/ where "..." is the device's ID.  The
+relevant attribute files are: wakeup, level, and autosuspend.
+
+       power/wakeup
+
+               This file is empty if the device does not support
+               remote wakeup.  Otherwise the file contains either the
+               word "enabled" or the word "disabled", and you can
+               write those words to the file.  The setting determines
+               whether or not remote wakeup will be enabled when the
+               device is next suspended.  (If the setting is changed
+               while the device is suspended, the change won't take
+               effect until the following suspend.)
+
+       power/level
+
+               This file contains one of three words: "on", "auto",
+               or "suspend".  You can write those words to the file
+               to change the device's setting.
+
+               "on" means that the device should be resumed and
+               autosuspend is not allowed.  (Of course, system
+               suspends are still allowed.)
+
+               "auto" is the normal state in which the kernel is
+               allowed to autosuspend and autoresume the device.
+
+               "suspend" means that the device should remain
+               suspended, and autoresume is not allowed.  (But remote
+               wakeup may still be allowed, since it is controlled
+               separately by the power/wakeup attribute.)
+
+       power/autosuspend
+
+               This file contains an integer value, which is the
+               number of seconds the device should remain idle before
+               the kernel will autosuspend it (the idle-delay time).
+               The default is 2.  0 means to autosuspend as soon as
+               the device becomes idle, and -1 means never to
+               autosuspend.  You can write a number to the file to
+               change the autosuspend idle-delay time.
+
+Writing "-1" to power/autosuspend and writing "on" to power/level do
+essentially the same thing -- they both prevent the device from being
+autosuspended.  Yes, this is a redundancy in the API.
+
+(In 2.6.21 writing "0" to power/autosuspend would prevent the device
+from being autosuspended; the behavior was changed in 2.6.22.  The
+power/autosuspend attribute did not exist prior to 2.6.21, and the
+power/level attribute did not exist prior to 2.6.22.)
+
+
+       Changing the default idle-delay time
+       ------------------------------------
+
+The default autosuspend idle-delay time is controlled by a module
+parameter in usbcore.  You can specify the value when usbcore is
+loaded.  For example, to set it to 5 seconds instead of 2 you would
+do:
+
+       modprobe usbcore autosuspend=5
+
+Equivalently, you could add to /etc/modprobe.conf a line saying:
+
+       options usbcore autosuspend=5
+
+Some distributions load the usbcore module very early during the boot
+process, by means of a program or script running from an initramfs
+image.  To alter the parameter value you would have to rebuild that
+image.
+
+If usbcore is compiled into the kernel rather than built as a loadable
+module, you can add
+
+       usbcore.autosuspend=5
+
+to the kernel's boot command line.
+
+Finally, the parameter value can be changed while the system is
+running.  If you do:
+
+       echo 5 >/sys/module/usbcore/parameters/autosuspend
+
+then each new USB device will have its autosuspend idle-delay
+initialized to 5.  (The idle-delay values for already existing devices
+will not be affected.)
+
+Setting the initial default idle-delay to -1 will prevent any
+autosuspend of any USB device.  This is a simple alternative to
+disabling CONFIG_USB_SUSPEND and rebuilding the kernel, and it has the
+added benefit of allowing you to enable autosuspend for selected
+devices.
+
+
+       Warnings
+       --------
+
+The USB specification states that all USB devices must support power
+management.  Nevertheless, the sad fact is that many devices do not
+support it very well.  You can suspend them all right, but when you
+try to resume them they disconnect themselves from the USB bus or
+they stop working entirely.  This seems to be especially prevalent
+among printers and scanners, but plenty of other types of device have
+the same deficiency.
+
+For this reason, by default the kernel disables autosuspend (the
+power/level attribute is initialized to "on") for all devices other
+than hubs.  Hubs, at least, appear to be reasonably well-behaved in
+this regard.
+
+(In 2.6.21 and 2.6.22 this wasn't the case.  Autosuspend was enabled
+by default for almost all USB devices.  A number of people experienced
+problems as a result.)
+
+This means that non-hub devices won't be autosuspended unless the user
+or a program explicitly enables it.  As of this writing there aren't
+any widespread programs which will do this; we hope that in the near
+future device managers such as HAL will take on this added
+responsibility.  In the meantime you can always carry out the
+necessary operations by hand or add them to a udev script.  You can
+also change the idle-delay time; 2 seconds is not the best choice for
+every device.
+
+Sometimes it turns out that even when a device does work okay with
+autosuspend there are still problems.  For example, there are
+experimental patches adding autosuspend support to the usbhid driver,
+which manages keyboards and mice, among other things.  Tests with a
+number of keyboards showed that typing on a suspended keyboard, while
+causing the keyboard to do a remote wakeup all right, would
+nonetheless frequently result in lost keystrokes.  Tests with mice
+showed that some of them would issue a remote-wakeup request in
+response to button presses but not to motion, and some in response to
+neither.
+
+The kernel will not prevent you from enabling autosuspend on devices
+that can't handle it.  It is even possible in theory to damage a
+device by suspending it at the wrong time -- for example, suspending a
+USB hard disk might cause it to spin down without parking the heads.
+(Highly unlikely, but possible.)  Take care.
+
+
+       The driver interface for Power Management
+       -----------------------------------------
+
+The requirements for a USB driver to support external power management
+are pretty modest; the driver need only define
+
+       .suspend
+       .resume
+       .reset_resume
+
+methods in its usb_driver structure, and the reset_resume method is
+optional.  The methods' jobs are quite simple:
+
+       The suspend method is called to warn the driver that the
+       device is going to be suspended.  If the driver returns a
+       negative error code, the suspend will be aborted.  Normally
+       the driver will return 0, in which case it must cancel all
+       outstanding URBs (usb_kill_urb()) and not submit any more.
+
+       The resume method is called to tell the driver that the
+       device has been resumed and the driver can return to normal
+       operation.  URBs may once more be submitted.
+
+       The reset_resume method is called to tell the driver that
+       the device has been resumed and it also has been reset.
+       The driver should redo any necessary device initialization,
+       since the device has probably lost most or all of its state
+       (although the interfaces will be in the same altsettings as
+       before the suspend).
+
+The reset_resume method is used by the USB Persist facility (see
+Documentation/usb/persist.txt) and it can also be used under certain
+circumstances when CONFIG_USB_PERSIST is not enabled.  Currently, if a
+device is reset during a resume and the driver does not have a
+reset_resume method, the driver won't receive any notification about
+the resume.  Later kernels will call the driver's disconnect method;
+2.6.23 doesn't do this.
+
+USB drivers are bound to interfaces, so their suspend and resume
+methods get called when the interfaces are suspended or resumed.  In
+principle one might want to suspend some interfaces on a device (i.e.,
+force the drivers for those interface to stop all activity) without
+suspending the other interfaces.  The USB core doesn't allow this; all
+interfaces are suspended when the device itself is suspended and all
+interfaces are resumed when the device is resumed.  It isn't possible
+to suspend or resume some but not all of a device's interfaces.  The
+closest you can come is to unbind the interfaces' drivers.
+
+
+       The driver interface for autosuspend and autoresume
+       ---------------------------------------------------
+
+To support autosuspend and autoresume, a driver should implement all
+three of the methods listed above.  In addition, a driver indicates
+that it supports autosuspend by setting the .supports_autosuspend flag
+in its usb_driver structure.  It is then responsible for informing the
+USB core whenever one of its interfaces becomes busy or idle.  The
+driver does so by calling these three functions:
+
+       int  usb_autopm_get_interface(struct usb_interface *intf);
+       void usb_autopm_put_interface(struct usb_interface *intf);
+       int  usb_autopm_set_interface(struct usb_interface *intf);
+
+The functions work by maintaining a counter in the usb_interface
+structure.  When intf->pm_usage_count is > 0 then the interface is
+deemed to be busy, and the kernel will not autosuspend the interface's
+device.  When intf->pm_usage_count is <= 0 then the interface is
+considered to be idle, and the kernel may autosuspend the device.
+
+(There is a similar pm_usage_count field in struct usb_device,
+associated with the device itself rather than any of its interfaces.
+This field is used only by the USB core.)
+
+The driver owns intf->pm_usage_count; it can modify the value however
+and whenever it likes.  A nice aspect of the usb_autopm_* routines is
+that the changes they make are protected by the usb_device structure's
+PM mutex (udev->pm_mutex); however drivers may change pm_usage_count
+without holding the mutex.
+
+       usb_autopm_get_interface() increments pm_usage_count and
+       attempts an autoresume if the new value is > 0 and the
+       device is suspended.
+
+       usb_autopm_put_interface() decrements pm_usage_count and
+       attempts an autosuspend if the new value is <= 0 and the
+       device isn't suspended.
+
+       usb_autopm_set_interface() leaves pm_usage_count alone.
+       It attempts an autoresume if the value is > 0 and the device
+       is suspended, and it attempts an autosuspend if the value is
+       <= 0 and the device isn't suspended.
+
+There also are a couple of utility routines drivers can use:
+
+       usb_autopm_enable() sets pm_usage_cnt to 1 and then calls
+       usb_autopm_set_interface(), which will attempt an autoresume.
+
+       usb_autopm_disable() sets pm_usage_cnt to 0 and then calls
+       usb_autopm_set_interface(), which will attempt an autosuspend.
+
+The conventional usage pattern is that a driver calls
+usb_autopm_get_interface() in its open routine and
+usb_autopm_put_interface() in its close or release routine.  But
+other patterns are possible.
+
+The autosuspend attempts mentioned above will often fail for one
+reason or another.  For example, the power/level attribute might be
+set to "on", or another interface in the same device might not be
+idle.  This is perfectly normal.  If the reason for failure was that
+the device hasn't been idle for long enough, a delayed workqueue
+routine is automatically set up to carry out the operation when the
+autosuspend idle-delay has expired.
+
+Autoresume attempts also can fail.  This will happen if power/level is
+set to "suspend" or if the device doesn't manage to resume properly.
+Unlike autosuspend, there's no delay for an autoresume.
+
+
+       Other parts of the driver interface
+       -----------------------------------
+
+Sometimes a driver needs to make sure that remote wakeup is enabled
+during autosuspend.  For example, there's not much point
+autosuspending a keyboard if the user can't cause the keyboard to do a
+remote wakeup by typing on it.  If the driver sets
+intf->needs_remote_wakeup to 1, the kernel won't autosuspend the
+device if remote wakeup isn't available or has been disabled through
+the power/wakeup attribute.  (If the device is already autosuspended,
+though, setting this flag won't cause the kernel to autoresume it.
+Normally a driver would set this flag in its probe method, at which
+time the device is guaranteed not to be autosuspended.)
+
+The usb_autopm_* routines have to run in a sleepable process context;
+they must not be called from an interrupt handler or while holding a
+spinlock.  In fact, the entire autosuspend mechanism is not well geared
+toward interrupt-driven operation.  However there is one thing a
+driver can do in an interrupt handler:
+
+       usb_mark_last_busy(struct usb_device *udev);
+
+This sets udev->last_busy to the current time.  udev->last_busy is the
+field used for idle-delay calculations; updating it will cause any
+pending autosuspend to be moved back.  The usb_autopm_* routines will
+also set the last_busy field to the current time.
+
+Calling urb_mark_last_busy() from within an URB completion handler is
+subject to races: The kernel may have just finished deciding the
+device has been idle for long enough but not yet gotten around to
+calling the driver's suspend method.  The driver would have to be
+responsible for synchronizing its suspend method with its URB
+completion handler and causing the autosuspend to fail with -EBUSY if
+an URB had completed too recently.
+
+External suspend calls should never be allowed to fail in this way,
+only autosuspend calls.  The driver can tell them apart by checking
+udev->auto_pm; this flag will be set to 1 for internal PM events
+(autosuspend or autoresume) and 0 for external PM events.
+
+Many of the ingredients in the autosuspend framework are oriented
+towards interfaces: The usb_interface structure contains the
+pm_usage_cnt field, and the usb_autopm_* routines take an interface
+pointer as their argument.  But somewhat confusingly, a few of the
+pieces (usb_mark_last_busy() and udev->auto_pm) use the usb_device
+structure instead.  Drivers need to keep this straight; they can call
+interface_to_usbdev() to find the device structure for a given
+interface.
+
+
+       Locking requirements
+       --------------------
+
+All three suspend/resume methods are always called while holding the
+usb_device's PM mutex.  For external events -- but not necessarily for
+autosuspend or autoresume -- the device semaphore (udev->dev.sem) will
+also be held.  This implies that external suspend/resume events are
+mutually exclusive with calls to probe, disconnect, pre_reset, and
+post_reset; the USB core guarantees that this is true of internal
+suspend/resume events as well.
+
+If a driver wants to block all suspend/resume calls during some
+critical section, it can simply acquire udev->pm_mutex.
+Alternatively, if the critical section might call some of the
+usb_autopm_* routines, the driver can avoid deadlock by doing:
+
+       down(&udev->dev.sem);
+       rc = usb_autopm_get_interface(intf);
+
+and at the end of the critical section:
+
+       if (!rc)
+               usb_autopm_put_interface(intf);
+       up(&udev->dev.sem);
+
+Holding the device semaphore will block all external PM calls, and the
+usb_autopm_get_interface() will prevent any internal PM calls, even if
+it fails.  (Exercise: Why?)
+
+The rules for locking order are:
+
+       Never acquire any device semaphore while holding any PM mutex.
+
+       Never acquire udev->pm_mutex while holding the PM mutex for
+       a device that isn't a descendant of udev.
+
+In other words, PM mutexes should only be acquired going up the device
+tree, and they should be acquired only after locking all the device
+semaphores you need to hold.  These rules don't matter to drivers very
+much; they usually affect just the USB core.
+
+Still, drivers do need to be careful.  For example, many drivers use a
+private mutex to synchronize their normal I/O activities with their
+disconnect method.  Now if the driver supports autosuspend then it
+must call usb_autopm_put_interface() from somewhere -- maybe from its
+close method.  It should make the call while holding the private mutex,
+since a driver shouldn't call any of the usb_autopm_* functions for an
+interface from which it has been unbound.
+
+But the usb_autpm_* routines always acquire the device's PM mutex, and
+consequently the locking order has to be: private mutex first, PM
+mutex second.  Since the suspend method is always called with the PM
+mutex held, it mustn't try to acquire the private mutex.  It has to
+synchronize with the driver's I/O activities in some other way.
+
+
+       Interaction between dynamic PM and system PM
+       --------------------------------------------
+
+Dynamic power management and system power management can interact in
+a couple of ways.
+
+Firstly, a device may already be manually suspended or autosuspended
+when a system suspend occurs.  Since system suspends are supposed to
+be as transparent as possible, the device should remain suspended
+following the system resume.  The 2.6.23 kernel obeys this principle
+for manually suspended devices but not for autosuspended devices; they
+do get resumed when the system wakes up.  (Presumably they will be
+autosuspended again after their idle-delay time expires.)  In later
+kernels this behavior will be fixed.
+
+(There is an exception.  If a device would undergo a reset-resume
+instead of a normal resume, and the device is enabled for remote
+wakeup, then the reset-resume takes place even if the device was
+already suspended when the system suspend began.  The justification is
+that a reset-resume is a kind of remote-wakeup event.  Or to put it
+another way, a device which needs a reset won't be able to generate
+normal remote-wakeup signals, so it ought to be resumed immediately.)
+
+Secondly, a dynamic power-management event may occur as a system
+suspend is underway.  The window for this is short, since system
+suspends don't take long (a few seconds usually), but it can happen.
+For example, a suspended device may send a remote-wakeup signal while
+the system is suspending.  The remote wakeup may succeed, which would
+cause the system suspend to abort.  If the remote wakeup doesn't
+succeed, it may still remain active and thus cause the system to
+resume as soon as the system suspend is complete.  Or the remote
+wakeup may fail and get lost.  Which outcome occurs depends on timing
+and on the hardware and firmware design.
+
+More interestingly, a device might undergo a manual resume or
+autoresume during system suspend.  With current kernels this shouldn't
+happen, because manual resumes must be initiated by userspace and
+autoresumes happen in response to I/O requests, but all user processes
+and I/O should be quiescent during a system suspend -- thanks to the
+freezer.  However there are plans to do away with the freezer, which
+would mean these things would become possible.  If and when this comes
+about, the USB core will carefully arrange matters so that either type
+of resume will block until the entire system has resumed.
index 5b635ae..4e0b62b 100644 (file)
@@ -428,6 +428,17 @@ Options supported:
   See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
   information on this driver.
 
+Winchiphead CH341 Driver
+
+  This driver is for the Winchiphead CH341 USB-RS232 Converter. This chip
+  also implements an IEEE 1284 parallel port, I2C and SPI, but that is not
+  supported by the driver. The protocol was analyzed from the behaviour
+  of the Windows driver, no datasheet is available at present.
+  The manufacturer's website: http://www.winchiphead.com/.
+  For any questions or problems with this driver, please contact
+  frank@kingswood-consulting.co.uk.
+
+
 Generic Serial driver
 
   If your device is not one of the above listed devices, compatible with
index 53ae866..2917ce4 100644 (file)
@@ -34,9 +34,12 @@ if usbmon is built into the kernel.
 Verify that bus sockets are present.
 
 # ls /sys/kernel/debug/usbmon
-1s  1t  1u  2s  2t  2u  3s  3t  3u  4s  4t  4u
+0s  0t  0u  1s  1t  1u  2s  2t  2u  3s  3t  3u  4s  4t  4u
 #
 
+Now you can choose to either use the sockets numbered '0' (to capture packets on
+all buses), and skip to step #3, or find the bus used by your device with step #2.
+
 2. Find which bus connects to the desired device
 
 Run "cat /proc/bus/usb/devices", and find the T-line which corresponds to
@@ -56,6 +59,10 @@ Bus=03 means it's bus 3.
 
 # cat /sys/kernel/debug/usbmon/3u > /tmp/1.mon.out
 
+to listen on a single bus, otherwise, to listen on all buses, type:
+
+# cat /sys/kernel/debug/usbmon/0u > /tmp/1.mon.out
+
 This process will be reading until killed. Naturally, the output can be
 redirected to a desirable location. This is preferred, because it is going
 to be quite long.
index c4eca56..60e649f 100644 (file)
@@ -677,6 +677,13 @@ P: Haavard Skinnemoen
 M:     hskinnemoen@atmel.com
 S:     Supported
 
+ATMEL USBA UDC DRIVER
+P:     Haavard Skinnemoen
+M:     hskinnemoen@atmel.com
+L:     kernel@avr32linux.org
+W:     http://avr32linux.org/twiki/bin/view/Main/AtmelUsbDeviceDriver
+S:     Supported
+
 ATMEL WIRELESS DRIVER
 P:     Simon Kelley
 M:     simon@thekelleys.org.uk
index 5e9d09e..6668c8e 100644 (file)
@@ -40,7 +40,7 @@
 #include <linux/pata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>
index 20507e9..f83a254 100644 (file)
@@ -40,7 +40,7 @@
 #include <linux/irq.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 
 #include <linux/spi/ad7877.h>
 
index 47d7d4a..f42ba3a 100644 (file)
@@ -40,7 +40,7 @@
 #include <linux/pata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>
index ac49b15..516a640 100644 (file)
@@ -28,27 +28,7 @@ obj-$(CONFIG_USB_MICROTEK)   += image/
 
 obj-$(CONFIG_USB_SERIAL)       += serial/
 
-obj-$(CONFIG_USB_ADUTUX)       += misc/
-obj-$(CONFIG_USB_APPLEDISPLAY) += misc/
-obj-$(CONFIG_USB_AUERSWALD)    += misc/
-obj-$(CONFIG_USB_BERRY_CHARGE) += misc/
-obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/
-obj-$(CONFIG_USB_CYTHERM)      += misc/
-obj-$(CONFIG_USB_EMI26)                += misc/
-obj-$(CONFIG_USB_EMI62)                += misc/
-obj-$(CONFIG_USB_FTDI_ELAN)    += misc/
-obj-$(CONFIG_USB_IDMOUSE)      += misc/
-obj-$(CONFIG_USB_LCD)          += misc/
-obj-$(CONFIG_USB_LD)           += misc/
-obj-$(CONFIG_USB_LED)          += misc/
-obj-$(CONFIG_USB_LEGOTOWER)    += misc/
-obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
-obj-$(CONFIG_USB_RIO500)       += misc/
-obj-$(CONFIG_USB_SISUSBVGA)    += misc/
-obj-$(CONFIG_USB_TEST)         += misc/
-obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/
-obj-$(CONFIG_USB_USS720)       += misc/
-obj-$(CONFIG_USB_IOWARRIOR)    += misc/
+obj-$(CONFIG_USB)              += misc/
 
 obj-$(CONFIG_USB_ATM)          += atm/
 obj-$(CONFIG_USB_SPEEDTOUCH)   += atm/
index a73e714..a51eeed 100644 (file)
@@ -482,7 +482,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
        int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE;
 
        if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) {
-               dbg("too big transfer requested");
+               if (printk_ratelimit())
+                       usb_err(instance->usbatm, "requested transfer size too large (%d, %d)\n",
+                               wbuflen, rbuflen);
                ret = -ENOMEM;
                goto fail;
        }
@@ -493,8 +495,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
        init_completion(&instance->rcv_done);
        ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL);
        if (ret < 0) {
-               dbg("submitting read urb for cm %#x failed", cm);
-               ret = ret;
+               if (printk_ratelimit())
+                       usb_err(instance->usbatm, "submit of read urb for cm %#x failed (%d)\n",
+                               cm, ret);
                goto fail;
        }
 
@@ -510,27 +513,29 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
        init_completion(&instance->snd_done);
        ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL);
        if (ret < 0) {
-               dbg("submitting write urb for cm %#x failed", cm);
-               ret = ret;
+               if (printk_ratelimit())
+                       usb_err(instance->usbatm, "submit of write urb for cm %#x failed (%d)\n",
+                               cm, ret);
                goto fail;
        }
 
        ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL);
        if (ret < 0) {
-               dbg("sending cm %#x failed", cm);
-               ret = ret;
+               if (printk_ratelimit())
+                       usb_err(instance->usbatm, "send of cm %#x failed (%d)\n", cm, ret);
                goto fail;
        }
 
        ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen);
        if (ret < 0) {
-               dbg("receiving cm %#x failed", cm);
-               ret = ret;
+               if (printk_ratelimit())
+                       usb_err(instance->usbatm, "receive of cm %#x failed (%d)\n", cm, ret);
                goto fail;
        }
        if (actlen % CMD_PACKET_SIZE || !actlen) {
-               dbg("response is not a positive multiple of %d: %#x",
-                               CMD_PACKET_SIZE, actlen);
+               if (printk_ratelimit())
+                       usb_err(instance->usbatm, "invalid response length to cm %#x: %d\n",
+                               cm, actlen);
                ret = -EIO;
                goto fail;
        }
@@ -538,12 +543,16 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
        /* check the return status and copy the data to the output buffer, if needed */
        for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) {
                if (rbuf[offb] != cm) {
-                       dbg("wrong cm %#x in response", rbuf[offb]);
+                       if (printk_ratelimit())
+                               usb_err(instance->usbatm, "wrong cm %#x in response to cm %#x\n",
+                                       rbuf[offb], cm);
                        ret = -EIO;
                        goto fail;
                }
                if (rbuf[offb + 1] != CM_STATUS_SUCCESS) {
-                       dbg("response failed: %#x", rbuf[offb + 1]);
+                       if (printk_ratelimit())
+                               usb_err(instance->usbatm, "response to cm %#x failed: %#x\n",
+                                       cm, rbuf[offb + 1]);
                        ret = -EIO;
                        goto fail;
                }
@@ -582,14 +591,18 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ
        for (offb = 0; offb < len; ) {
                int l = le32_to_cpu(buf[offb++]);
                if (l > stride || l > (len - offb) / 2) {
-                       dbg("wrong data length %#x in response", l);
+                       if (printk_ratelimit())
+                               usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n",
+                                       cm, l);
                        ret = -EIO;
                        goto cleanup;
                }
                while (l--) {
                        offd = le32_to_cpu(buf[offb++]);
                        if (offd >= size) {
-                               dbg("wrong index %#x in response", offd);
+                               if (printk_ratelimit())
+                                       usb_err(instance->usbatm, "wrong index #%x in response to cm #%x\n",
+                                               offd, cm);
                                ret = -EIO;
                                goto cleanup;
                        }
index eb0615a..8b132c4 100644 (file)
@@ -251,7 +251,6 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
 {
        unsigned char *buffer;
        struct usbatm_data *usbatm = instance->usbatm;
-       struct usb_interface *intf;
        struct usb_device *usb_dev = usbatm->usb_dev;
        int actual_length;
        int ret = 0;
@@ -265,7 +264,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
                goto out;
        }
 
-       if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {
+       if (!usb_ifnum_to_if(usb_dev, 2)) {
                ret = -ENODEV;
                usb_dbg(usbatm, "%s: interface not found!\n", __func__);
                goto out_free;
index 29807d0..389c5b1 100644 (file)
@@ -2,7 +2,8 @@
  * Copyright (c) 2003, 2004
  *     Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
  *
- * Copyright (c) 2005 Matthieu Castet <castet.matthieu@free.fr>
+ * Copyright (c) 2005-2007 Matthieu Castet <castet.matthieu@free.fr>
+ * Copyright (c) 2005-2007 Stanislaw Gruszka <stf_xl@wp.pl>
  *
  * This software is available to you under a choice of one of two
  * licenses. You may choose to be licensed under the terms of the GNU
 #define uea_info(usb_dev, format,args...) \
        dev_info(&(usb_dev)->dev ,"[ueagle-atm] " format, ##args)
 
-struct uea_cmvs {
+struct intr_pkt;
+
+/* cmv's from firmware */
+struct uea_cmvs_v1 {
        u32 address;
        u16 offset;
        u32 data;
 } __attribute__ ((packed));
 
+struct uea_cmvs_v2 {
+       u32 group;
+       u32 address;
+       u32 offset;
+       u32 data;
+} __attribute__ ((packed));
+
+/* information about currently processed cmv */
+struct cmv_dsc_e1 {
+       u8 function;
+       u16 idx;
+       u32 address;
+       u16 offset;
+};
+
+struct cmv_dsc_e4 {
+       u16 function;
+       u16 offset;
+       u16 address;
+       u16 group;
+};
+
+union cmv_dsc {
+       struct cmv_dsc_e1 e1;
+       struct cmv_dsc_e4 e4;
+};
+
 struct uea_softc {
        struct usb_device *usb_dev;
        struct usbatm_data *usbatm;
 
        int modem_index;
        unsigned int driver_info;
+       int annex;
+#define ANNEXA 0
+#define ANNEXB 1
 
        int booting;
        int reset;
@@ -127,20 +161,23 @@ struct uea_softc {
 
        struct task_struct *kthread;
        u32 data;
-       wait_queue_head_t cmv_ack_wait;
+       u32 data1;
+
        int cmv_ack;
+       union cmv_dsc cmv_dsc;
 
        struct work_struct task;
+       struct workqueue_struct *work_q;
        u16 pageno;
        u16 ovl;
 
        const struct firmware *dsp_firm;
        struct urb *urb_int;
 
-       u8 cmv_function;
-       u16 cmv_idx;
-       u32 cmv_address;
-       u16 cmv_offset;
+       void (*dispatch_cmv) (struct uea_softc *, struct intr_pkt *);
+       void (*schedule_load_page) (struct uea_softc *, struct intr_pkt *);
+       int (*stat) (struct uea_softc *);
+       int (*send_cmvs) (struct uea_softc *);
 
        /* keep in sync with eaglectl */
        struct uea_stats {
@@ -174,10 +211,34 @@ struct uea_softc {
 #define ELSA_PID_PSTFIRM       0x3350
 #define ELSA_PID_PREFIRM       0x3351
 
+#define ELSA_PID_A_PREFIRM     0x3352
+#define ELSA_PID_A_PSTFIRM     0x3353
+#define ELSA_PID_B_PREFIRM     0x3362
+#define ELSA_PID_B_PSTFIRM     0x3363
+
 /*
- * Sagem USB IDs
+ * Devolo IDs : pots if (pid & 0x10)
  */
-#define EAGLE_VID              0x1110
+#define DEVOLO_VID                     0x1039
+#define DEVOLO_EAGLE_I_A_PID_PSTFIRM   0x2110
+#define DEVOLO_EAGLE_I_A_PID_PREFIRM   0x2111
+
+#define DEVOLO_EAGLE_I_B_PID_PSTFIRM   0x2100
+#define DEVOLO_EAGLE_I_B_PID_PREFIRM   0x2101
+
+#define DEVOLO_EAGLE_II_A_PID_PSTFIRM  0x2130
+#define DEVOLO_EAGLE_II_A_PID_PREFIRM  0x2131
+
+#define DEVOLO_EAGLE_II_B_PID_PSTFIRM  0x2120
+#define DEVOLO_EAGLE_II_B_PID_PREFIRM  0x2121
+
+/*
+ * Reference design USB IDs
+ */
+#define ANALOG_VID             0x1110
+#define ADI930_PID_PREFIRM     0x9001
+#define ADI930_PID_PSTFIRM     0x9000
+
 #define EAGLE_I_PID_PREFIRM    0x9010  /* Eagle I */
 #define EAGLE_I_PID_PSTFIRM    0x900F  /* Eagle I */
 
@@ -187,12 +248,12 @@ struct uea_softc {
 #define EAGLE_II_PID_PREFIRM   0x9022  /* Eagle II */
 #define EAGLE_II_PID_PSTFIRM   0x9021  /* Eagle II */
 
-/*
- *  Eagle III Pid
- */
 #define EAGLE_III_PID_PREFIRM  0x9032  /* Eagle III */
 #define EAGLE_III_PID_PSTFIRM  0x9031  /* Eagle III */
 
+#define EAGLE_IV_PID_PREFIRM   0x9042  /* Eagle IV */
+#define EAGLE_IV_PID_PSTFIRM   0x9041  /* Eagle IV */
+
 /*
  * USR USB IDs
  */
@@ -208,11 +269,15 @@ struct uea_softc {
 
 #define PREFIRM 0
 #define PSTFIRM (1<<7)
+#define AUTO_ANNEX_A (1<<8)
+#define AUTO_ANNEX_B (1<<9)
+
 enum {
        ADI930 = 0,
        EAGLE_I,
        EAGLE_II,
-       EAGLE_III
+       EAGLE_III,
+       EAGLE_IV
 };
 
 /* macros for both struct usb_device_id and struct uea_softc */
@@ -221,15 +286,18 @@ enum {
 #define UEA_CHIP_VERSION(x) \
        ((x)->driver_info & 0xf)
 
-#define IS_ISDN(usb_dev) \
-       (le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80)
+#define IS_ISDN(x) \
+       ((x)->annex & ANNEXB)
 
 #define INS_TO_USBDEV(ins) ins->usb_dev
 
 #define GET_STATUS(data) \
        ((data >> 8) & 0xf)
+
 #define IS_OPERATIONAL(sc) \
-       (GET_STATUS(sc->stats.phy.state) == 2)
+       ((UEA_CHIP_VERSION(sc) != EAGLE_IV) ? \
+       (GET_STATUS(sc->stats.phy.state) == 2) : \
+       (sc->stats.phy.state == 7))
 
 /*
  * Set of macros to handle unaligned data in the firmware blob.
@@ -259,7 +327,8 @@ enum {
 #define UEA_INTR_PIPE          0x04
 #define UEA_ISO_DATA_PIPE      0x08
 
-#define UEA_SET_BLOCK          0x0001
+#define UEA_E1_SET_BLOCK       0x0001
+#define UEA_E4_SET_BLOCK       0x002c
 #define UEA_SET_MODE           0x0003
 #define UEA_SET_2183_DATA      0x0004
 #define UEA_SET_TIMEOUT                0x0011
@@ -275,71 +344,179 @@ enum {
 #define UEA_MPTX_MAILBOX       (0x3fd6 | 0x4000)
 #define UEA_MPRX_MAILBOX       (0x3fdf | 0x4000)
 
-/* structure describing a block within a DSP page */
-struct block_info {
+/* block information in eagle4 dsp firmware  */
+struct block_index {
+       __le32 PageOffset;
+       __le32 NotLastBlock;
+       __le32 dummy;
+       __le32 PageSize;
+       __le32 PageAddress;
+       __le16 dummy1;
+       __le16 PageNumber;
+} __attribute__ ((packed));
+
+#define E4_IS_BOOT_PAGE(PageSize) ((le32_to_cpu(PageSize)) & 0x80000000)
+#define E4_PAGE_BYTES(PageSize) ((le32_to_cpu(PageSize) & 0x7fffffff) * 4)
+
+#define E4_L1_STRING_HEADER 0x10
+#define E4_MAX_PAGE_NUMBER 0x58
+#define E4_NO_SWAPPAGE_HEADERS 0x31
+
+/* l1_code is eagle4 dsp firmware format */
+struct l1_code {
+       u8 string_header[E4_L1_STRING_HEADER];
+       u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER];
+       struct block_index page_header[E4_NO_SWAPPAGE_HEADERS];
+       u8 code [0];
+} __attribute__ ((packed));
+
+/* structures describing a block within a DSP page */
+struct block_info_e1 {
        __le16 wHdr;
-#define UEA_BIHDR 0xabcd
        __le16 wAddress;
        __le16 wSize;
        __le16 wOvlOffset;
        __le16 wOvl;            /* overlay */
        __le16 wLast;
 } __attribute__ ((packed));
-#define BLOCK_INFO_SIZE 12
+#define E1_BLOCK_INFO_SIZE 12
+
+struct block_info_e4 {
+       __be16 wHdr;
+       __u8 bBootPage;
+       __u8 bPageNumber;
+       __be32 dwSize;
+       __be32 dwAddress;
+       __be16 wReserved;
+} __attribute__ ((packed));
+#define E4_BLOCK_INFO_SIZE 14
 
-/* structure representing a CMV (Configuration and Management Variable) */
-struct cmv {
-       __le16 wPreamble;
-#define PREAMBLE 0x535c
-       __u8 bDirection;
-#define MODEMTOHOST 0x01
-#define HOSTTOMODEM 0x10
-       __u8 bFunction;
-#define FUNCTION_TYPE(f)    ((f) >> 4)
-#define MEMACCESS      0x1
-#define ADSLDIRECTIVE  0x7
+#define UEA_BIHDR 0xabcd
+#define UEA_RESERVED 0xffff
+
+/* constants describing cmv type */
+#define E1_PREAMBLE 0x535c
+#define E1_MODEMTOHOST 0x01
+#define E1_HOSTTOMODEM 0x10
+
+#define E1_MEMACCESS 0x1
+#define E1_ADSLDIRECTIVE 0x7
+#define E1_FUNCTION_TYPE(f) ((f) >> 4)
+#define E1_FUNCTION_SUBTYPE(f) ((f) & 0x0f)
+
+#define E4_MEMACCESS 0
+#define E4_ADSLDIRECTIVE 0xf
+#define E4_FUNCTION_TYPE(f) ((f) >> 8)
+#define E4_FUNCTION_SIZE(f) ((f) & 0x0f)
+#define E4_FUNCTION_SUBTYPE(f) (((f) >> 4) & 0x0f)
 
-#define FUNCTION_SUBTYPE(f) ((f) & 0x0f)
 /* for MEMACCESS */
-#define REQUESTREAD    0x0
-#define REQUESTWRITE   0x1
-#define REPLYREAD      0x2
-#define REPLYWRITE     0x3
+#define E1_REQUESTREAD 0x0
+#define E1_REQUESTWRITE        0x1
+#define E1_REPLYREAD   0x2
+#define E1_REPLYWRITE  0x3
+
+#define E4_REQUESTREAD 0x0
+#define E4_REQUESTWRITE        0x4
+#define E4_REPLYREAD   (E4_REQUESTREAD | 1)
+#define E4_REPLYWRITE  (E4_REQUESTWRITE | 1)
+
 /* for ADSLDIRECTIVE */
-#define KERNELREADY    0x0
-#define MODEMREADY     0x1
+#define E1_KERNELREADY 0x0
+#define E1_MODEMREADY  0x1
 
-#define MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf))
-       __le16 wIndex;
-       __le32 dwSymbolicAddress;
-#define MAKESA(a, b, c, d)                                             \
+#define E4_KERNELREADY 0x0
+#define E4_MODEMREADY  0x1
+
+#define E1_MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf))
+#define E4_MAKEFUNCTION(t, st, s) (((t) & 0xf) << 8 | ((st) & 0xf) << 4 | ((s) & 0xf))
+
+#define E1_MAKESA(a, b, c, d)                                          \
        (((c) & 0xff) << 24 |                                           \
         ((d) & 0xff) << 16 |                                           \
         ((a) & 0xff) << 8  |                                           \
         ((b) & 0xff))
-#define GETSA1(a) ((a >> 8) & 0xff)
-#define GETSA2(a) (a & 0xff)
-#define GETSA3(a) ((a >> 24) & 0xff)
-#define GETSA4(a) ((a >> 16) & 0xff)
-
-#define SA_CNTL MAKESA('C', 'N', 'T', 'L')
-#define SA_DIAG MAKESA('D', 'I', 'A', 'G')
-#define SA_INFO MAKESA('I', 'N', 'F', 'O')
-#define SA_OPTN MAKESA('O', 'P', 'T', 'N')
-#define SA_RATE MAKESA('R', 'A', 'T', 'E')
-#define SA_STAT MAKESA('S', 'T', 'A', 'T')
+
+#define E1_GETSA1(a) ((a >> 8) & 0xff)
+#define E1_GETSA2(a) (a & 0xff)
+#define E1_GETSA3(a) ((a >> 24) & 0xff)
+#define E1_GETSA4(a) ((a >> 16) & 0xff)
+
+#define E1_SA_CNTL E1_MAKESA('C', 'N', 'T', 'L')
+#define E1_SA_DIAG E1_MAKESA('D', 'I', 'A', 'G')
+#define E1_SA_INFO E1_MAKESA('I', 'N', 'F', 'O')
+#define E1_SA_OPTN E1_MAKESA('O', 'P', 'T', 'N')
+#define E1_SA_RATE E1_MAKESA('R', 'A', 'T', 'E')
+#define E1_SA_STAT E1_MAKESA('S', 'T', 'A', 'T')
+
+#define E4_SA_CNTL 1
+#define E4_SA_STAT 2
+#define E4_SA_INFO 3
+#define E4_SA_TEST 4
+#define E4_SA_OPTN 5
+#define E4_SA_RATE 6
+#define E4_SA_DIAG 7
+#define E4_SA_CNFG 8
+
+/* structures representing a CMV (Configuration and Management Variable) */
+struct cmv_e1 {
+       __le16 wPreamble;
+       __u8 bDirection;
+       __u8 bFunction;
+       __le16 wIndex;
+       __le32 dwSymbolicAddress;
        __le16 wOffsetAddress;
        __le32 dwData;
 } __attribute__ ((packed));
-#define CMV_SIZE 16
 
-/* structure representing swap information */
-struct swap_info {
+struct cmv_e4 {
+       __be16 wGroup;
+       __be16 wFunction;
+       __be16 wOffset;
+       __be16 wAddress;
+       __be32 dwData [6];
+} __attribute__ ((packed));
+
+/* structures representing swap information */
+struct swap_info_e1 {
        __u8 bSwapPageNo;
        __u8 bOvl;              /* overlay */
 } __attribute__ ((packed));
 
-/* structure representing interrupt data */
+struct swap_info_e4 {
+       __u8 bSwapPageNo;
+} __attribute__ ((packed));
+
+/* structures representing interrupt data */
+#define e1_bSwapPageNo u.e1.s1.swapinfo.bSwapPageNo
+#define e1_bOvl                u.e1.s1.swapinfo.bOvl
+#define e4_bSwapPageNo  u.e4.s1.swapinfo.bSwapPageNo
+
+#define INT_LOADSWAPPAGE 0x0001
+#define INT_INCOMINGCMV  0x0002
+
+union intr_data_e1 {
+       struct {
+               struct swap_info_e1 swapinfo;
+               __le16 wDataSize;
+       } __attribute__ ((packed)) s1;
+       struct {
+               struct cmv_e1 cmv;
+               __le16 wDataSize;
+       } __attribute__ ((packed)) s2;
+} __attribute__ ((packed));
+
+union intr_data_e4 {
+       struct {
+               struct swap_info_e4 swapinfo;
+               __le16 wDataSize;
+       } __attribute__ ((packed)) s1;
+       struct {
+               struct cmv_e4 cmv;
+               __le16 wDataSize;
+       } __attribute__ ((packed)) s2;
+} __attribute__ ((packed));
+
 struct intr_pkt {
        __u8 bType;
        __u8 bNotification;
@@ -347,43 +524,48 @@ struct intr_pkt {
        __le16 wIndex;
        __le16 wLength;
        __le16 wInterrupt;
-#define INT_LOADSWAPPAGE 0x0001
-#define INT_INCOMINGCMV  0x0002
        union {
-               struct {
-                       struct swap_info swapinfo;
-                       __le16 wDataSize;
-               } __attribute__ ((packed)) s1;
-
-               struct {
-                       struct cmv cmv;
-                       __le16 wDataSize;
-               } __attribute__ ((packed)) s2;
-       } __attribute__ ((packed)) u;
-#define bSwapPageNo    u.s1.swapinfo.bSwapPageNo
-#define bOvl           u.s1.swapinfo.bOvl
+               union intr_data_e1 e1;
+               union intr_data_e4 e4;
+       } u;
 } __attribute__ ((packed));
-#define INTR_PKT_SIZE 28
+
+#define E1_INTR_PKT_SIZE 28
+#define E4_INTR_PKT_SIZE 64
 
 static struct usb_driver uea_driver;
 static DEFINE_MUTEX(uea_mutex);
-static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III"};
+static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"};
 
 static int modem_index;
 static unsigned int debug;
-static int use_iso[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = 1};
+static unsigned int altsetting[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF};
 static int sync_wait[NB_MODEM];
 static char *cmv_file[NB_MODEM];
+static int annex[NB_MODEM];
 
 module_param(debug, uint, 0644);
 MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)");
-module_param_array(use_iso, bool, NULL, 0644);
-MODULE_PARM_DESC(use_iso, "use isochronous usb pipe for incoming traffic");
+module_param_array(altsetting, uint, NULL, 0644);
+MODULE_PARM_DESC(altsetting, "alternate setting for incoming traffic: 0=bulk, "
+                            "1=isoc slowest, ... , 8=isoc fastest (default)");
 module_param_array(sync_wait, bool, NULL, 0644);
 MODULE_PARM_DESC(sync_wait, "wait the synchronisation before starting ATM");
 module_param_array(cmv_file, charp, NULL, 0644);
 MODULE_PARM_DESC(cmv_file,
                "file name with configuration and management variables");
+module_param_array(annex, uint, NULL, 0644);
+MODULE_PARM_DESC(annex,
+                 "manually set annex a/b (0=auto, 1=annex a, 2=annex b)");
+
+#define uea_wait(sc, cond, timeo) \
+({ \
+       int _r = wait_event_interruptible_timeout(sc->sync_q, \
+                       (cond) || kthread_should_stop(), timeo); \
+       if (kthread_should_stop()) \
+               _r = -ENODEV; \
+       _r; \
+})
 
 #define UPDATE_ATM_STAT(type, val) \
        do { \
@@ -519,6 +701,9 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
        case EAGLE_III:
                fw_name = FW_DIR "eagleIII.fw";
                break;
+       case EAGLE_IV:
+               fw_name = FW_DIR "eagleIV.fw";
+               break;
        }
 
        ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, usb, uea_upload_pre_firmware);
@@ -537,7 +722,7 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
 /*
  * Make sure that the DSP code provided is safe to use.
  */
-static int check_dsp(u8 *dsp, unsigned int len)
+static int check_dsp_e1(u8 *dsp, unsigned int len)
 {
        u8 pagecount, blockcount;
        u16 blocksize;
@@ -588,6 +773,51 @@ static int check_dsp(u8 *dsp, unsigned int len)
        return 0;
 }
 
+static int check_dsp_e4(u8 *dsp, int len)
+{
+       int i;
+       struct l1_code *p = (struct l1_code *) dsp;
+       unsigned int sum = p->code - dsp;
+
+       if (len < sum)
+               return 1;
+
+       if (strcmp("STRATIPHY ANEXA", p->string_header) != 0 &&
+           strcmp("STRATIPHY ANEXB", p->string_header) != 0)
+               return 1;
+
+       for (i = 0; i < E4_MAX_PAGE_NUMBER; i++) {
+               struct block_index *blockidx;
+               u8 blockno = p->page_number_to_block_index[i];
+               if (blockno >= E4_NO_SWAPPAGE_HEADERS)
+                       continue;
+
+               do {
+                       u64 l;
+
+                       if (blockno >= E4_NO_SWAPPAGE_HEADERS)
+                               return 1;
+
+                       blockidx = &p->page_header[blockno++];
+                       if ((u8 *)(blockidx + 1) - dsp  >= len)
+                               return 1;
+
+                       if (le16_to_cpu(blockidx->PageNumber) != i)
+                               return 1;
+
+                       l = E4_PAGE_BYTES(blockidx->PageSize);
+                       sum += l;
+                       l += le32_to_cpu(blockidx->PageOffset);
+                       if (l > len)
+                               return 1;
+
+               /* zero is zero regardless endianes */
+               } while (blockidx->NotLastBlock);
+       }
+
+       return (sum == len) ? 0 : 1;
+}
+
 /*
  * send data to the idma pipe
  * */
@@ -624,13 +854,18 @@ static int request_dsp(struct uea_softc *sc)
        int ret;
        char *dsp_name;
 
-       if (UEA_CHIP_VERSION(sc) == ADI930) {
-               if (IS_ISDN(sc->usb_dev))
+       if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+               if (IS_ISDN(sc))
+                       dsp_name = FW_DIR "DSP4i.bin";
+               else
+                       dsp_name = FW_DIR "DSP4p.bin";
+       } else if (UEA_CHIP_VERSION(sc) == ADI930) {
+               if (IS_ISDN(sc))
                        dsp_name = FW_DIR "DSP9i.bin";
                else
                        dsp_name = FW_DIR "DSP9p.bin";
        } else {
-               if (IS_ISDN(sc->usb_dev))
+               if (IS_ISDN(sc))
                        dsp_name = FW_DIR "DSPei.bin";
                else
                        dsp_name = FW_DIR "DSPep.bin";
@@ -640,11 +875,16 @@ static int request_dsp(struct uea_softc *sc)
        if (ret < 0) {
                uea_err(INS_TO_USBDEV(sc),
                       "requesting firmware %s failed with error %d\n",
-                      dsp_name, ret);
+                       dsp_name, ret);
                return ret;
        }
 
-       if (check_dsp(sc->dsp_firm->data, sc->dsp_firm->size)) {
+       if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+               ret = check_dsp_e4(sc->dsp_firm->data, sc->dsp_firm->size);
+       else
+               ret = check_dsp_e1(sc->dsp_firm->data, sc->dsp_firm->size);
+
+       if (ret) {
                uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n",
                       dsp_name);
                release_firmware(sc->dsp_firm);
@@ -658,12 +898,12 @@ static int request_dsp(struct uea_softc *sc)
 /*
  * The uea_load_page() function must be called within a process context
  */
-static void uea_load_page(struct work_struct *work)
+static void uea_load_page_e1(struct work_struct *work)
 {
        struct uea_softc *sc = container_of(work, struct uea_softc, task);
        u16 pageno = sc->pageno;
        u16 ovl = sc->ovl;
-       struct block_info bi;
+       struct block_info_e1 bi;
 
        u8 *p;
        u8 pagecount, blockcount;
@@ -716,7 +956,7 @@ static void uea_load_page(struct work_struct *work)
                bi.wLast = cpu_to_le16((i == blockcount - 1) ? 1 : 0);
 
                /* send block info through the IDMA pipe */
-               if (uea_idma_write(sc, &bi, BLOCK_INFO_SIZE))
+               if (uea_idma_write(sc, &bi, E1_BLOCK_INFO_SIZE))
                        goto bad2;
 
                /* send block data through the IDMA pipe */
@@ -735,17 +975,114 @@ bad1:
        uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
 }
 
+static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot)
+{
+       struct block_info_e4 bi;
+       struct block_index *blockidx;
+       struct l1_code *p = (struct l1_code *) sc->dsp_firm->data;
+       u8 blockno = p->page_number_to_block_index[pageno];
+
+       bi.wHdr = cpu_to_be16(UEA_BIHDR);
+       bi.bBootPage = boot;
+       bi.bPageNumber = pageno;
+       bi.wReserved = cpu_to_be16(UEA_RESERVED);
+
+       do {
+               u8 *blockoffset;
+               unsigned int blocksize;
+
+               blockidx = &p->page_header[blockno];
+               blocksize = E4_PAGE_BYTES(blockidx->PageSize);
+               blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset);
+
+               bi.dwSize = cpu_to_be32(blocksize);
+               bi.dwAddress = swab32(blockidx->PageAddress);
+
+               uea_dbg(INS_TO_USBDEV(sc),
+                      "sending block %u for DSP page %u size %u adress %x\n",
+                      blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress));
+
+               /* send block info through the IDMA pipe */
+               if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
+                       goto bad;
+
+               /* send block data through the IDMA pipe */
+               if (uea_idma_write(sc, blockoffset, blocksize))
+                       goto bad;
+
+               blockno++;
+       } while (blockidx->NotLastBlock);
+
+       return;
+
+bad:
+       uea_err(INS_TO_USBDEV(sc), "sending DSP block %u failed\n", blockno);
+       return;
+}
+
+static void uea_load_page_e4(struct work_struct *work)
+{
+       struct uea_softc *sc = container_of(work, struct uea_softc, task);
+       u8 pageno = sc->pageno;
+       int i;
+       struct block_info_e4 bi;
+       struct l1_code *p;
+
+       uea_dbg(INS_TO_USBDEV(sc), "sending DSP page %u\n", pageno);
+
+       /* reload firmware when reboot start and it's loaded already */
+       if (pageno == 0 && sc->dsp_firm) {
+               release_firmware(sc->dsp_firm);
+               sc->dsp_firm = NULL;
+       }
+
+       if (sc->dsp_firm == NULL && request_dsp(sc) < 0)
+               return;
+
+       p = (struct l1_code *) sc->dsp_firm->data;
+       if (pageno >= p->page_header[0].PageNumber) {
+               uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
+               return;
+       }
+
+       if (pageno != 0) {
+               __uea_load_page_e4(sc, pageno, 0);
+               return;
+       }
+
+       uea_dbg(INS_TO_USBDEV(sc),
+              "sending Main DSP page %u\n", p->page_header[0].PageNumber);
+
+       for (i = 0; i < le16_to_cpu(p->page_header[0].PageNumber); i++) {
+               if (E4_IS_BOOT_PAGE(p->page_header[i].PageSize))
+                       __uea_load_page_e4(sc, i, 1);
+       }
+
+       uea_dbg(INS_TO_USBDEV(sc),"sending start bi\n");
+
+       bi.wHdr = cpu_to_be16(UEA_BIHDR);
+       bi.bBootPage = 0;
+       bi.bPageNumber = 0xff;
+       bi.wReserved = cpu_to_be16(UEA_RESERVED);
+       bi.dwSize = cpu_to_be32(E4_PAGE_BYTES(p->page_header[0].PageSize));
+       bi.dwAddress = swab32(p->page_header[0].PageAddress);
+
+       /* send block info through the IDMA pipe */
+       if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
+               uea_err(INS_TO_USBDEV(sc), "sending DSP start bi failed\n");
+}
+
 static inline void wake_up_cmv_ack(struct uea_softc *sc)
 {
        BUG_ON(sc->cmv_ack);
        sc->cmv_ack = 1;
-       wake_up(&sc->cmv_ack_wait);
+       wake_up(&sc->sync_q);
 }
 
 static inline int wait_cmv_ack(struct uea_softc *sc)
 {
-       int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait,
-                                                  sc->cmv_ack, ACK_TIMEOUT);
+       int ret = uea_wait(sc, sc->cmv_ack , ACK_TIMEOUT);
+
        sc->cmv_ack = 0;
 
        uea_dbg(INS_TO_USBDEV(sc), "wait_event_timeout : %d ms\n",
@@ -792,33 +1129,68 @@ static int uea_request(struct uea_softc *sc,
        return 0;
 }
 
-static int uea_cmv(struct uea_softc *sc,
+static int uea_cmv_e1(struct uea_softc *sc,
                u8 function, u32 address, u16 offset, u32 data)
 {
-       struct cmv cmv;
+       struct cmv_e1 cmv;
        int ret;
 
        uea_enters(INS_TO_USBDEV(sc));
        uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, "
                        "offset : 0x%04x, data : 0x%08x\n",
-                       FUNCTION_TYPE(function), FUNCTION_SUBTYPE(function),
-                       GETSA1(address), GETSA2(address), GETSA3(address),
-                       GETSA4(address), offset, data);
+                       E1_FUNCTION_TYPE(function), E1_FUNCTION_SUBTYPE(function),
+                       E1_GETSA1(address), E1_GETSA2(address), E1_GETSA3(address),
+                       E1_GETSA4(address), offset, data);
+
        /* we send a request, but we expect a reply */
-       sc->cmv_function = function | 0x2;
-       sc->cmv_idx++;
-       sc->cmv_address = address;
-       sc->cmv_offset = offset;
+       sc->cmv_dsc.e1.function = function | 0x2;
+       sc->cmv_dsc.e1.idx++;
+       sc->cmv_dsc.e1.address = address;
+       sc->cmv_dsc.e1.offset = offset;
 
-       cmv.wPreamble = cpu_to_le16(PREAMBLE);
-       cmv.bDirection = HOSTTOMODEM;
+       cmv.wPreamble = cpu_to_le16(E1_PREAMBLE);
+       cmv.bDirection = E1_HOSTTOMODEM;
        cmv.bFunction = function;
-       cmv.wIndex = cpu_to_le16(sc->cmv_idx);
+       cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx);
        put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress);
        cmv.wOffsetAddress = cpu_to_le16(offset);
        put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData);
 
-       ret = uea_request(sc, UEA_SET_BLOCK, UEA_MPTX_START, CMV_SIZE, &cmv);
+       ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
+       if (ret < 0)
+               return ret;
+       ret = wait_cmv_ack(sc);
+       uea_leaves(INS_TO_USBDEV(sc));
+       return ret;
+}
+
+static int uea_cmv_e4(struct uea_softc *sc,
+               u16 function, u16 group, u16 address, u16 offset, u32 data)
+{
+       struct cmv_e4 cmv;
+       int ret;
+
+       uea_enters(INS_TO_USBDEV(sc));
+       memset(&cmv, 0, sizeof(cmv));
+
+       uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Group : 0x%04x, "
+                "Address : 0x%04x, offset : 0x%04x, data : 0x%08x\n",
+                E4_FUNCTION_TYPE(function), E4_FUNCTION_SUBTYPE(function),
+                group, address, offset, data);
+
+       /* we send a request, but we expect a reply */
+       sc->cmv_dsc.e4.function = function | (0x1 << 4);
+       sc->cmv_dsc.e4.offset = offset;
+       sc->cmv_dsc.e4.address = address;
+       sc->cmv_dsc.e4.group = group;
+
+       cmv.wFunction = cpu_to_be16(function);
+       cmv.wGroup = cpu_to_be16(group);
+       cmv.wAddress = cpu_to_be16(address);
+       cmv.wOffset = cpu_to_be16(offset);
+       cmv.dwData[0] = cpu_to_be32(data);
+
+       ret = uea_request(sc, UEA_E4_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
        if (ret < 0)
                return ret;
        ret = wait_cmv_ack(sc);
@@ -826,10 +1198,10 @@ static int uea_cmv(struct uea_softc *sc,
        return ret;
 }
 
-static inline int uea_read_cmv(struct uea_softc *sc,
+static inline int uea_read_cmv_e1(struct uea_softc *sc,
                u32 address, u16 offset, u32 *data)
 {
-       int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTREAD),
+       int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTREAD),
                          address, offset, 0);
        if (ret < 0)
                uea_err(INS_TO_USBDEV(sc),
@@ -840,10 +1212,27 @@ static inline int uea_read_cmv(struct uea_softc *sc,
        return ret;
 }
 
-static inline int uea_write_cmv(struct uea_softc *sc,
+static inline int uea_read_cmv_e4(struct uea_softc *sc,
+               u8 size, u16 group, u16 address, u16 offset, u32 *data)
+{
+       int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTREAD, size),
+                         group, address, offset, 0);
+       if (ret < 0)
+               uea_err(INS_TO_USBDEV(sc),
+                       "reading cmv failed with error %d\n", ret);
+       else {
+               *data = sc->data;
+               /* size is in 16-bit word quantities */
+               if (size > 2)
+                       *(data + 1) = sc->data1;
+       }
+       return ret;
+}
+
+static inline int uea_write_cmv_e1(struct uea_softc *sc,
                u32 address, u16 offset, u32 data)
 {
-       int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTWRITE),
+       int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTWRITE),
                          address, offset, data);
        if (ret < 0)
                uea_err(INS_TO_USBDEV(sc),
@@ -852,12 +1241,48 @@ static inline int uea_write_cmv(struct uea_softc *sc,
        return ret;
 }
 
+static inline int uea_write_cmv_e4(struct uea_softc *sc,
+               u8 size, u16 group, u16 address, u16 offset, u32 data)
+{
+       int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTWRITE, size),
+                         group, address, offset, data);
+       if (ret < 0)
+               uea_err(INS_TO_USBDEV(sc),
+                       "writing cmv failed with error %d\n", ret);
+
+       return ret;
+}
+
+static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate)
+{
+       int ret;
+       u16 timeout;
+
+       /* in bulk mode the modem have problem with high rate
+        * changing internal timing could improve things, but the
+        * value is misterious.
+        * ADI930 don't support it (-EPIPE error).
+        */
+
+       if (UEA_CHIP_VERSION(sc) == ADI930 ||
+           altsetting[sc->modem_index] > 0 ||
+           sc->stats.phy.dsrate == dsrate)
+               return;
+
+       /* Original timming (1Mbit/s) from ADI (used in windows driver) */
+       timeout = (dsrate <= 1024*1024) ? 0 : 1;
+       ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL);
+       uea_info(INS_TO_USBDEV(sc), "setting new timeout %d%s\n",
+                timeout,  ret < 0 ? " failed" : "");
+
+}
+
 /*
  * Monitor the modem and update the stat
  * return 0 if everything is ok
  * return < 0 if an error occurs (-EAGAIN reboot needed)
  */
-static int uea_stat(struct uea_softc *sc)
+static int uea_stat_e1(struct uea_softc *sc)
 {
        u32 data;
        int ret;
@@ -865,7 +1290,7 @@ static int uea_stat(struct uea_softc *sc)
        uea_enters(INS_TO_USBDEV(sc));
        data = sc->stats.phy.state;
 
-       ret = uea_read_cmv(sc, SA_STAT, 0, &sc->stats.phy.state);
+       ret = uea_read_cmv_e1(sc, E1_SA_STAT, 0, &sc->stats.phy.state);
        if (ret < 0)
                return ret;
 
@@ -885,7 +1310,7 @@ static int uea_stat(struct uea_softc *sc)
 
        case 3:         /* fail ... */
                uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
-                               " (may be try other cmv/dsp)\n");
+                                       " (may be try other cmv/dsp)\n");
                return -EAGAIN;
 
        case 4 ... 6:   /* test state */
@@ -923,7 +1348,7 @@ static int uea_stat(struct uea_softc *sc)
        /* wake up processes waiting for synchronization */
        wake_up(&sc->sync_q);
 
-       ret = uea_read_cmv(sc, SA_DIAG, 2, &sc->stats.phy.flags);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 2, &sc->stats.phy.flags);
        if (ret < 0)
                return ret;
        sc->stats.phy.mflags |= sc->stats.phy.flags;
@@ -937,105 +1362,223 @@ static int uea_stat(struct uea_softc *sc)
                return 0;
        }
 
-       ret = uea_read_cmv(sc, SA_RATE, 0, &data);
+       ret = uea_read_cmv_e1(sc, E1_SA_RATE, 0, &data);
        if (ret < 0)
                return ret;
 
-       /* in bulk mode the modem have problem with high rate
-        * changing internal timing could improve things, but the
-        * value is misterious.
-        * ADI930 don't support it (-EPIPE error).
-        */
-       if (UEA_CHIP_VERSION(sc) != ADI930
-                   && !use_iso[sc->modem_index]
-                   && sc->stats.phy.dsrate != (data >> 16) * 32) {
-               /* Original timming from ADI(used in windows driver)
-                * 0x20ffff>>16 * 32 = 32 * 32 = 1Mbits
-                */
-               u16 timeout = (data <= 0x20ffff) ? 0 : 1;
-               ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL);
-               uea_info(INS_TO_USBDEV(sc),
-                               "setting new timeout %d%s\n", timeout,
-                               ret < 0?" failed":"");
-       }
+       uea_set_bulk_timeout(sc, (data >> 16) * 32);
        sc->stats.phy.dsrate = (data >> 16) * 32;
        sc->stats.phy.usrate = (data & 0xffff) * 32;
        UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424);
 
-       ret = uea_read_cmv(sc, SA_DIAG, 23, &data);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 23, &data);
        if (ret < 0)
                return ret;
        sc->stats.phy.dsattenuation = (data & 0xff) / 2;
 
-       ret = uea_read_cmv(sc, SA_DIAG, 47, &data);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 47, &data);
        if (ret < 0)
                return ret;
        sc->stats.phy.usattenuation = (data & 0xff) / 2;
 
-       ret = uea_read_cmv(sc, SA_DIAG, 25, &sc->stats.phy.dsmargin);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 25, &sc->stats.phy.dsmargin);
        if (ret < 0)
                return ret;
 
-       ret = uea_read_cmv(sc, SA_DIAG, 49, &sc->stats.phy.usmargin);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 49, &sc->stats.phy.usmargin);
        if (ret < 0)
                return ret;
 
-       ret = uea_read_cmv(sc, SA_DIAG, 51, &sc->stats.phy.rxflow);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 51, &sc->stats.phy.rxflow);
        if (ret < 0)
                return ret;
 
-       ret = uea_read_cmv(sc, SA_DIAG, 52, &sc->stats.phy.txflow);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 52, &sc->stats.phy.txflow);
        if (ret < 0)
                return ret;
 
-       ret = uea_read_cmv(sc, SA_DIAG, 54, &sc->stats.phy.dsunc);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 54, &sc->stats.phy.dsunc);
        if (ret < 0)
                return ret;
 
        /* only for atu-c */
-       ret = uea_read_cmv(sc, SA_DIAG, 58, &sc->stats.phy.usunc);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 58, &sc->stats.phy.usunc);
        if (ret < 0)
                return ret;
 
-       ret = uea_read_cmv(sc, SA_DIAG, 53, &sc->stats.phy.dscorr);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 53, &sc->stats.phy.dscorr);
        if (ret < 0)
                return ret;
 
        /* only for atu-c */
-       ret = uea_read_cmv(sc, SA_DIAG, 57, &sc->stats.phy.uscorr);
+       ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 57, &sc->stats.phy.uscorr);
        if (ret < 0)
                return ret;
 
-       ret = uea_read_cmv(sc, SA_INFO, 8, &sc->stats.phy.vidco);
+       ret = uea_read_cmv_e1(sc, E1_SA_INFO, 8, &sc->stats.phy.vidco);
        if (ret < 0)
                return ret;
 
-       ret = uea_read_cmv(sc, SA_INFO, 13, &sc->stats.phy.vidcpe);
+       ret = uea_read_cmv_e1(sc, E1_SA_INFO, 13, &sc->stats.phy.vidcpe);
        if (ret < 0)
                return ret;
 
        return 0;
 }
 
-static int request_cmvs(struct uea_softc *sc,
-                struct uea_cmvs **cmvs, const struct firmware **fw)
+static int uea_stat_e4(struct uea_softc *sc)
 {
-       int ret, size;
-       u8 *data;
+       u32 data;
+       u32 tmp_arr[2];
+       int ret;
+
+       uea_enters(INS_TO_USBDEV(sc));
+       data = sc->stats.phy.state;
+
+       /* XXX only need to be done before operationnal... */
+       ret = uea_read_cmv_e4(sc, 1, E4_SA_STAT, 0, 0, &sc->stats.phy.state);
+       if (ret < 0)
+               return ret;
+
+       switch (sc->stats.phy.state) {
+               case 0x0:       /* not yet synchronized */
+               case 0x1:
+               case 0x3:
+               case 0x4:
+                       uea_dbg(INS_TO_USBDEV(sc), "modem not yet synchronized\n");
+                       return 0;
+               case 0x5:       /* initialization */
+               case 0x6:
+               case 0x9:
+               case 0xa:
+                       uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n");
+                       return 0;
+               case 0x2:       /* fail ... */
+                       uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
+                                       " (may be try other cmv/dsp)\n");
+                       return -EAGAIN;
+               case 0x7:       /* operational */
+                       break;
+               default:
+                       uea_warn(INS_TO_USBDEV(sc), "unknown state: %x\n", sc->stats.phy.state);
+                       return 0;
+       }
+
+       if (data != 7) {
+               uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_OFF, 0, NULL);
+               uea_info(INS_TO_USBDEV(sc), "modem operational\n");
+
+               /* release the dsp firmware as it is not needed until
+                * the next failure
+                */
+               if (sc->dsp_firm) {
+                       release_firmware(sc->dsp_firm);
+                       sc->dsp_firm = NULL;
+               }
+       }
+
+       /* always update it as atm layer could not be init when we switch to
+        * operational state
+        */
+       UPDATE_ATM_STAT(signal, ATM_PHY_SIG_FOUND);
+
+       /* wake up processes waiting for synchronization */
+       wake_up(&sc->sync_q);
+
+       /* TODO improve this state machine :
+        * we need some CMV info : what they do and their unit
+        * we should find the equivalent of eagle3- CMV
+        */
+       /* check flags */
+       ret = uea_read_cmv_e4(sc, 1, E4_SA_DIAG, 0, 0, &sc->stats.phy.flags);
+       if (ret < 0)
+               return ret;
+       sc->stats.phy.mflags |= sc->stats.phy.flags;
+
+       /* in case of a flags ( for example delineation LOSS (& 0x10)),
+        * we check the status again in order to detect the failure earlier
+        */
+       if (sc->stats.phy.flags) {
+               uea_dbg(INS_TO_USBDEV(sc), "Stat flag = 0x%x\n",
+                      sc->stats.phy.flags);
+               if (sc->stats.phy.flags & 1) //delineation LOSS
+                       return -EAGAIN;
+               if (sc->stats.phy.flags & 0x4000) //Reset Flag
+                       return -EAGAIN;
+               return 0;
+       }
+
+       /* rate data may be in upper or lower half of 64 bit word, strange */
+       ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 0, 0, tmp_arr);
+       if (ret < 0)
+               return ret;
+       data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1];
+       sc->stats.phy.usrate = data / 1000;
+
+       ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 1, 0, tmp_arr);
+       if (ret < 0)
+               return ret;
+       data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1];
+       uea_set_bulk_timeout(sc, data / 1000);
+       sc->stats.phy.dsrate = data / 1000;
+       UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424);
+
+       ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 1, &data);
+       if (ret < 0)
+               return ret;
+       sc->stats.phy.dsattenuation = data / 10;
+
+       ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 1, &data);
+       if (ret < 0)
+               return ret;
+       sc->stats.phy.usattenuation = data / 10;
+
+       ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 3, &data);
+       if (ret < 0)
+               return ret;
+       sc->stats.phy.dsmargin = data / 2;
+
+       ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 3, &data);
+       if (ret < 0)
+               return ret;
+       sc->stats.phy.usmargin = data / 10;
+
+       return 0;
+}
+
+static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver)
+{
+       char file_arr[] = "CMVxy.bin";
        char *file;
-       char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
 
+       /* set proper name corresponding modem version and line type */
        if (cmv_file[sc->modem_index] == NULL) {
                if (UEA_CHIP_VERSION(sc) == ADI930)
-                       file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin";
+                       file_arr[3] = '9';
+               else if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+                       file_arr[3] = '4';
                else
-                       file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin";
+                       file_arr[3] = 'e';
+
+               file_arr[4] = IS_ISDN(sc) ? 'i' : 'p';
+               file = file_arr;
        } else
                file = cmv_file[sc->modem_index];
 
        strcpy(cmv_name, FW_DIR);
-       strlcat(cmv_name, file, sizeof(cmv_name));
+       strlcat(cmv_name, file, FIRMWARE_NAME_MAX);
+       if (ver == 2)
+               strlcat(cmv_name, ".v2", FIRMWARE_NAME_MAX);
+}
+
+static int request_cmvs_old(struct uea_softc *sc,
+                void **cmvs, const struct firmware **fw)
+{
+       int ret, size;
+       u8 *data;
+       char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
 
+       cmvs_file_name(sc, cmv_name, 1);
        ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
        if (ret < 0) {
                uea_err(INS_TO_USBDEV(sc),
@@ -1045,16 +1588,197 @@ static int request_cmvs(struct uea_softc *sc,
        }
 
        data = (u8 *) (*fw)->data;
-       size = *data * sizeof(struct uea_cmvs) + 1;
-       if (size != (*fw)->size) {
-               uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n",
-                      cmv_name);
-               release_firmware(*fw);
-               return -EILSEQ;
+       size = (*fw)->size;
+       if (size < 1)
+               goto err_fw_corrupted;
+
+       if (size != *data * sizeof(struct uea_cmvs_v1) + 1)
+               goto err_fw_corrupted;
+
+       *cmvs = (void *)(data + 1);
+       return *data;
+
+err_fw_corrupted:
+       uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name);
+       release_firmware(*fw);
+       return -EILSEQ;
+}
+
+static int request_cmvs(struct uea_softc *sc,
+                void **cmvs, const struct firmware **fw, int *ver)
+{
+       int ret, size;
+       u32 crc;
+       u8 *data;
+       char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+
+       cmvs_file_name(sc, cmv_name, 2);
+       ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
+       if (ret < 0) {
+               /* if caller can handle old version, try to provide it */
+               if (*ver == 1) {
+                       uea_warn(INS_TO_USBDEV(sc), "requesting firmware %s failed, "
+                               "try to get older cmvs\n", cmv_name);
+                       return request_cmvs_old(sc, cmvs, fw);
+               }
+               uea_err(INS_TO_USBDEV(sc),
+                      "requesting firmware %s failed with error %d\n",
+                      cmv_name, ret);
+               return ret;
+       }
+
+       size = (*fw)->size;
+       data = (u8 *) (*fw)->data;
+       if (size < 4 || strncmp(data, "cmv2", 4) != 0) {
+               if (*ver == 1) {
+                       uea_warn(INS_TO_USBDEV(sc), "firmware %s is corrupted, "
+                               "try to get older cmvs\n", cmv_name);
+                       release_firmware(*fw);
+                       return request_cmvs_old(sc, cmvs, fw);
+               }
+               goto err_fw_corrupted;
        }
 
-       *cmvs = (struct uea_cmvs *)(data + 1);
+       *ver = 2;
+
+       data += 4;
+       size -= 4;
+       if (size < 5)
+               goto err_fw_corrupted;
+
+       crc = FW_GET_LONG(data);
+       data += 4;
+       size -= 4;
+       if (crc32_be(0, data, size) != crc)
+               goto err_fw_corrupted;
+
+       if (size != *data * sizeof(struct uea_cmvs_v2) + 1)
+               goto err_fw_corrupted;
+
+       *cmvs = (void *) (data + 1);
        return *data;
+
+err_fw_corrupted:
+       uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name);
+       release_firmware(*fw);
+       return -EILSEQ;
+}
+
+static int uea_send_cmvs_e1(struct uea_softc *sc)
+{
+       int i, ret, len;
+       void *cmvs_ptr;
+       const struct firmware *cmvs_fw;
+       int ver = 1; // we can handle v1 cmv firmware version;
+
+       /* Enter in R-IDLE (cmv) until instructed otherwise */
+       ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 1);
+       if (ret < 0)
+               return ret;
+
+       /* Dump firmware version */
+       ret = uea_read_cmv_e1(sc, E1_SA_INFO, 10, &sc->stats.phy.firmid);
+       if (ret < 0)
+               return ret;
+       uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
+                       sc->stats.phy.firmid);
+
+       /* get options */
+       ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
+       if (ret < 0)
+               return ret;
+
+       /* send options */
+       if (ver == 1) {
+               struct uea_cmvs_v1 *cmvs_v1 = cmvs_ptr;
+
+               uea_warn(INS_TO_USBDEV(sc), "use deprecated cmvs version, "
+                       "please update your firmware\n");
+
+               for (i = 0; i < len; i++) {
+                       ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v1[i].address),
+                                               FW_GET_WORD(&cmvs_v1[i].offset),
+                                               FW_GET_LONG(&cmvs_v1[i].data));
+                       if (ret < 0)
+                               goto out;
+               }
+       } else if (ver == 2) {
+               struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
+
+               for (i = 0; i < len; i++) {
+                       ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v2[i].address),
+                                               (u16) FW_GET_LONG(&cmvs_v2[i].offset),
+                                               FW_GET_LONG(&cmvs_v2[i].data));
+                       if (ret < 0)
+                               goto out;
+               }
+       } else {
+               /* This realy should not happen */
+               uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver);
+               goto out;
+       }
+
+       /* Enter in R-ACT-REQ */
+       ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 2);
+       uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
+       uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
+out:
+       release_firmware(cmvs_fw);
+       return ret;
+}
+
+static int uea_send_cmvs_e4(struct uea_softc *sc)
+{
+       int i, ret, len;
+       void *cmvs_ptr;
+       const struct firmware *cmvs_fw;
+       int ver = 2; // we can only handle v2 cmv firmware version;
+
+       /* Enter in R-IDLE (cmv) until instructed otherwise */
+       ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 1);
+       if (ret < 0)
+               return ret;
+
+       /* Dump firmware version */
+       /* XXX don't read the 3th byte as it is always 6 */
+       ret = uea_read_cmv_e4(sc, 2, E4_SA_INFO, 55, 0, &sc->stats.phy.firmid);
+       if (ret < 0)
+               return ret;
+       uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
+                       sc->stats.phy.firmid);
+
+
+       /* get options */
+       ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
+       if (ret < 0)
+               return ret;
+
+       /* send options */
+       if (ver == 2) {
+               struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
+
+               for (i = 0; i < len; i++) {
+                       ret = uea_write_cmv_e4(sc, 1,
+                                               FW_GET_LONG(&cmvs_v2[i].group),
+                                               FW_GET_LONG(&cmvs_v2[i].address),
+                                               FW_GET_LONG(&cmvs_v2[i].offset),
+                                               FW_GET_LONG(&cmvs_v2[i].data));
+                       if (ret < 0)
+                               goto out;
+               }
+       } else {
+               /* This realy should not happen */
+               uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver);
+               goto out;
+       }
+
+       /* Enter in R-ACT-REQ */
+       ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 2);
+       uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
+       uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
+out:
+       release_firmware(cmvs_fw);
+       return ret;
 }
 
 /* Start boot post firmware modem:
@@ -1066,9 +1790,7 @@ static int request_cmvs(struct uea_softc *sc,
 static int uea_start_reset(struct uea_softc *sc)
 {
        u16 zero = 0;   /* ;-) */
-       int i, len, ret;
-       struct uea_cmvs *cmvs;
-       const struct firmware *cmvs_fw;
+       int ret;
 
        uea_enters(INS_TO_USBDEV(sc));
        uea_info(INS_TO_USBDEV(sc), "(re)booting started\n");
@@ -1093,25 +1815,36 @@ static int uea_start_reset(struct uea_softc *sc)
        uea_request(sc, UEA_SET_MODE, UEA_START_RESET, 0, NULL);
 
        /* original driver use 200ms, but windows driver use 100ms */
-       msleep(100);
+       ret = uea_wait(sc, 0, msecs_to_jiffies(100));
+       if (ret < 0)
+               return ret;
 
        /* leave reset mode */
        uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL);
 
-       /* clear tx and rx mailboxes */
-       uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero);
-       uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero);
-       uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero);
+       if (UEA_CHIP_VERSION(sc) != EAGLE_IV) {
+               /* clear tx and rx mailboxes */
+               uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero);
+               uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero);
+               uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero);
+       }
+
+       ret = uea_wait(sc, 0, msecs_to_jiffies(1000));
+       if (ret < 0)
+               return ret;
+
+       if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+               sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1);
+       else
+               sc->cmv_dsc.e1.function = E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY);
 
-       msleep(1000);
-       sc->cmv_function = MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY);
        /* demask interrupt */
        sc->booting = 0;
 
        /* start loading DSP */
        sc->pageno = 0;
        sc->ovl = 0;
-       schedule_work(&sc->task);
+       queue_work(sc->work_q, &sc->task);
 
        /* wait for modem ready CMV */
        ret = wait_cmv_ack(sc);
@@ -1120,38 +1853,10 @@ static int uea_start_reset(struct uea_softc *sc)
 
        uea_vdbg(INS_TO_USBDEV(sc), "Ready CMV received\n");
 
-       /* Enter in R-IDLE (cmv) until instructed otherwise */
-       ret = uea_write_cmv(sc, SA_CNTL, 0, 1);
-       if (ret < 0)
-               return ret;
-
-       /* Dump firmware version */
-       ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid);
+       ret = sc->send_cmvs(sc);
        if (ret < 0)
                return ret;
-       uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
-                       sc->stats.phy.firmid);
 
-       /* get options */
-       ret = len = request_cmvs(sc, &cmvs, &cmvs_fw);
-       if (ret < 0)
-               return ret;
-
-       /* send options */
-       for (i = 0; i < len; i++) {
-               ret = uea_write_cmv(sc, FW_GET_LONG(&cmvs[i].address),
-                                       FW_GET_WORD(&cmvs[i].offset),
-                                       FW_GET_LONG(&cmvs[i].data));
-               if (ret < 0)
-                       goto out;
-       }
-       /* Enter in R-ACT-REQ */
-       ret = uea_write_cmv(sc, SA_CNTL, 0, 2);
-       uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
-       uea_info(INS_TO_USBDEV(sc), "Modem started, "
-               "waiting synchronization\n");
-out:
-       release_firmware(cmvs_fw);
        sc->reset = 0;
        uea_leaves(INS_TO_USBDEV(sc));
        return ret;
@@ -1174,12 +1879,10 @@ static int uea_kthread(void *data)
                if (ret < 0 || sc->reset)
                        ret = uea_start_reset(sc);
                if (!ret)
-                       ret = uea_stat(sc);
+                       ret = sc->stat(sc);
                if (ret != -EAGAIN)
-                       msleep_interruptible(1000);
-               if (try_to_freeze())
-                       uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, "
-                               "please unplug/replug your modem\n");
+                       uea_wait(sc, 0, msecs_to_jiffies(1000));
+               try_to_freeze();
        }
        uea_leaves(INS_TO_USBDEV(sc));
        return ret;
@@ -1234,7 +1937,6 @@ static int load_XILINX_firmware(struct uea_softc *sc)
        if (ret < 0)
                uea_err(sc->usb_dev, "elsa de-assert failed with error %d\n", ret);
 
-
 err1:
        release_firmware(fw_entry);
 err0:
@@ -1243,40 +1945,41 @@ err0:
 }
 
 /* The modem send us an ack. First with check if it right */
-static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv)
+static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
 {
+       struct cmv_dsc_e1 *dsc = &sc->cmv_dsc.e1;
+       struct cmv_e1 *cmv = &intr->u.e1.s2.cmv;
+
        uea_enters(INS_TO_USBDEV(sc));
-       if (le16_to_cpu(cmv->wPreamble) != PREAMBLE)
+       if (le16_to_cpu(cmv->wPreamble) != E1_PREAMBLE)
                goto bad1;
 
-       if (cmv->bDirection != MODEMTOHOST)
+       if (cmv->bDirection != E1_MODEMTOHOST)
                goto bad1;
 
        /* FIXME : ADI930 reply wrong preambule (func = 2, sub = 2) to
         * the first MEMACESS cmv. Ignore it...
         */
-       if (cmv->bFunction != sc->cmv_function) {
+       if (cmv->bFunction != dsc->function) {
                if (UEA_CHIP_VERSION(sc) == ADI930
-                               && cmv->bFunction ==  MAKEFUNCTION(2, 2)) {
-                       cmv->wIndex = cpu_to_le16(sc->cmv_idx);
-                       put_unaligned(cpu_to_le32(sc->cmv_address), &cmv->dwSymbolicAddress);
-                       cmv->wOffsetAddress = cpu_to_le16(sc->cmv_offset);
-               }
-               else
+                               && cmv->bFunction ==  E1_MAKEFUNCTION(2, 2)) {
+                       cmv->wIndex = cpu_to_le16(dsc->idx);
+                       put_unaligned(cpu_to_le32(dsc->address), &cmv->dwSymbolicAddress);
+                       cmv->wOffsetAddress = cpu_to_le16(dsc->offset);
+               } else
                        goto bad2;
        }
 
-       if (cmv->bFunction == MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY)) {
+       if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY)) {
                wake_up_cmv_ack(sc);
                uea_leaves(INS_TO_USBDEV(sc));
                return;
        }
 
        /* in case of MEMACCESS */
-       if (le16_to_cpu(cmv->wIndex) != sc->cmv_idx ||
-           le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) !=
-           sc->cmv_address
-           || le16_to_cpu(cmv->wOffsetAddress) != sc->cmv_offset)
+       if (le16_to_cpu(cmv->wIndex) != dsc->idx ||
+           le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address ||
+           le16_to_cpu(cmv->wOffsetAddress) != dsc->offset)
                goto bad2;
 
        sc->data = le32_to_cpu(get_unaligned(&cmv->dwData));
@@ -1289,8 +1992,8 @@ static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv)
 bad2:
        uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
                        "Function : %d, Subfunction : %d\n",
-                       FUNCTION_TYPE(cmv->bFunction),
-                       FUNCTION_SUBTYPE(cmv->bFunction));
+                       E1_FUNCTION_TYPE(cmv->bFunction),
+                       E1_FUNCTION_SUBTYPE(cmv->bFunction));
        uea_leaves(INS_TO_USBDEV(sc));
        return;
 
@@ -1301,6 +2004,61 @@ bad1:
        uea_leaves(INS_TO_USBDEV(sc));
 }
 
+/* The modem send us an ack. First with check if it right */
+static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr)
+{
+       struct cmv_dsc_e4 *dsc = &sc->cmv_dsc.e4;
+       struct cmv_e4 *cmv = &intr->u.e4.s2.cmv;
+
+       uea_enters(INS_TO_USBDEV(sc));
+       uea_dbg(INS_TO_USBDEV(sc), "cmv %x %x %x %x %x %x\n",
+               be16_to_cpu(cmv->wGroup), be16_to_cpu(cmv->wFunction),
+               be16_to_cpu(cmv->wOffset), be16_to_cpu(cmv->wAddress),
+               be32_to_cpu(cmv->dwData[0]), be32_to_cpu(cmv->dwData[1]));
+
+       if (be16_to_cpu(cmv->wFunction) != dsc->function)
+               goto bad2;
+
+       if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1)) {
+               wake_up_cmv_ack(sc);
+               uea_leaves(INS_TO_USBDEV(sc));
+               return;
+       }
+
+       /* in case of MEMACCESS */
+       if (be16_to_cpu(cmv->wOffset) != dsc->offset ||
+           be16_to_cpu(cmv->wGroup) != dsc->group ||
+           be16_to_cpu(cmv->wAddress) != dsc->address)
+               goto bad2;
+
+       sc->data = be32_to_cpu(cmv->dwData[0]);
+       sc->data1 = be32_to_cpu(cmv->dwData[1]);
+       wake_up_cmv_ack(sc);
+       uea_leaves(INS_TO_USBDEV(sc));
+       return;
+
+bad2:
+       uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
+                       "Function : %d, Subfunction : %d\n",
+                       E4_FUNCTION_TYPE(cmv->wFunction),
+                       E4_FUNCTION_SUBTYPE(cmv->wFunction));
+       uea_leaves(INS_TO_USBDEV(sc));
+       return;
+}
+
+static void uea_schedule_load_page_e1(struct uea_softc *sc, struct intr_pkt *intr)
+{
+       sc->pageno = intr->e1_bSwapPageNo;
+       sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4;
+       queue_work(sc->work_q, &sc->task);
+}
+
+static void uea_schedule_load_page_e4(struct uea_softc *sc, struct intr_pkt *intr)
+{
+       sc->pageno = intr->e4_bSwapPageNo;
+       queue_work(sc->work_q, &sc->task);
+}
+
 /*
  * interrupt handler
  */
@@ -1326,13 +2084,11 @@ static void uea_intr(struct urb *urb)
 
        switch (le16_to_cpu(intr->wInterrupt)) {
        case INT_LOADSWAPPAGE:
-               sc->pageno = intr->bSwapPageNo;
-               sc->ovl = intr->bOvl >> 4 | intr->bOvl << 4;
-               schedule_work(&sc->task);
+               sc->schedule_load_page(sc, intr);
                break;
 
        case INT_INCOMINGCMV:
-               uea_dispatch_cmv(sc, &intr->u.s2.cmv);
+               sc->dispatch_cmv(sc, intr);
                break;
 
        default:
@@ -1349,35 +2105,55 @@ resubmit:
  */
 static int uea_boot(struct uea_softc *sc)
 {
-       int ret;
+       int ret, size;
        struct intr_pkt *intr;
 
        uea_enters(INS_TO_USBDEV(sc));
 
-       INIT_WORK(&sc->task, uea_load_page);
+       if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+               size = E4_INTR_PKT_SIZE;
+               sc->dispatch_cmv = uea_dispatch_cmv_e4;
+               sc->schedule_load_page = uea_schedule_load_page_e4;
+               sc->stat = uea_stat_e4;
+               sc->send_cmvs = uea_send_cmvs_e4;
+               INIT_WORK(&sc->task, uea_load_page_e4);
+       } else {
+               size = E1_INTR_PKT_SIZE;
+               sc->dispatch_cmv = uea_dispatch_cmv_e1;
+               sc->schedule_load_page = uea_schedule_load_page_e1;
+               sc->stat = uea_stat_e1;
+               sc->send_cmvs = uea_send_cmvs_e1;
+               INIT_WORK(&sc->task, uea_load_page_e1);
+       }
+
        init_waitqueue_head(&sc->sync_q);
-       init_waitqueue_head(&sc->cmv_ack_wait);
+
+       sc->work_q = create_workqueue("ueagle-dsp");
+       if (!sc->work_q) {
+               uea_err(INS_TO_USBDEV(sc), "cannot allocate workqueue\n");
+               uea_leaves(INS_TO_USBDEV(sc));
+               return -ENOMEM;
+       }
 
        if (UEA_CHIP_VERSION(sc) == ADI930)
                load_XILINX_firmware(sc);
 
-       intr = kmalloc(INTR_PKT_SIZE, GFP_KERNEL);
+       intr = kmalloc(size, GFP_KERNEL);
        if (!intr) {
                uea_err(INS_TO_USBDEV(sc),
                       "cannot allocate interrupt package\n");
-               uea_leaves(INS_TO_USBDEV(sc));
-               return -ENOMEM;
+               goto err0;
        }
 
        sc->urb_int = usb_alloc_urb(0, GFP_KERNEL);
        if (!sc->urb_int) {
                uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt URB\n");
-               goto err;
+               goto err1;
        }
 
        usb_fill_int_urb(sc->urb_int, sc->usb_dev,
                         usb_rcvintpipe(sc->usb_dev, UEA_INTR_PIPE),
-                        intr, INTR_PKT_SIZE, uea_intr, sc,
+                        intr, size, uea_intr, sc,
                         sc->usb_dev->actconfig->interface[0]->altsetting[0].
                         endpoint[0].desc.bInterval);
 
@@ -1385,7 +2161,7 @@ static int uea_boot(struct uea_softc *sc)
        if (ret < 0) {
                uea_err(INS_TO_USBDEV(sc),
                       "urb submition failed with error %d\n", ret);
-               goto err;
+               goto err1;
        }
 
        sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm");
@@ -1399,10 +2175,12 @@ static int uea_boot(struct uea_softc *sc)
 
 err2:
        usb_kill_urb(sc->urb_int);
-err:
+err1:
        usb_free_urb(sc->urb_int);
        sc->urb_int = NULL;
        kfree(intr);
+err0:
+       destroy_workqueue(sc->work_q);
        uea_leaves(INS_TO_USBDEV(sc));
        return -ENOMEM;
 }
@@ -1417,15 +2195,15 @@ static void uea_stop(struct uea_softc *sc)
        ret = kthread_stop(sc->kthread);
        uea_dbg(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret);
 
-       /* stop any pending boot process */
-       flush_scheduled_work();
-
        uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL);
 
        usb_kill_urb(sc->urb_int);
        kfree(sc->urb_int->transfer_buffer);
        usb_free_urb(sc->urb_int);
 
+       /* stop any pending boot process, when no one can schedule work */
+       destroy_workqueue(sc->work_q);
+
        if (sc->dsp_firm)
                release_firmware(sc->dsp_firm);
        uea_leaves(INS_TO_USBDEV(sc));
@@ -1487,6 +2265,7 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
                char *buf)
 {
        int ret = -ENODEV;
+       int modem_state;
        struct uea_softc *sc;
 
        mutex_lock(&uea_mutex);
@@ -1494,7 +2273,34 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
        if (!sc)
                goto out;
 
-       switch (GET_STATUS(sc->stats.phy.state)) {
+       if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+               switch (sc->stats.phy.state) {
+               case 0x0:       /* not yet synchronized */
+               case 0x1:
+               case 0x3:
+               case 0x4:
+                       modem_state = 0;
+                       break;
+               case 0x5:       /* initialization */
+               case 0x6:
+               case 0x9:
+               case 0xa:
+                       modem_state = 1;
+                       break;
+               case 0x7:       /* operational */
+                       modem_state = 2;
+                       break;
+               case 0x2:       /* fail ... */
+                       modem_state = 3;
+                       break;
+               default:        /* unknown */
+                       modem_state = 4;
+                       break;
+               }
+       } else
+               modem_state = GET_STATUS(sc->stats.phy.state);
+
+       switch (modem_state) {
        case 0:
                ret = sprintf(buf, "Modem is booting\n");
                break;
@@ -1504,9 +2310,12 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
        case 2:
                ret = sprintf(buf, "Modem is operational\n");
                break;
-       default:
+       case 3:
                ret = sprintf(buf, "Modem synchronization failed\n");
                break;
+       default:
+               ret = sprintf(buf, "Modem state is unknown\n");
+               break;
        }
 out:
        mutex_unlock(&uea_mutex);
@@ -1520,18 +2329,26 @@ static ssize_t read_delin(struct device *dev, struct device_attribute *attr,
 {
        int ret = -ENODEV;
        struct uea_softc *sc;
+       char *delin = "GOOD";
 
        mutex_lock(&uea_mutex);
        sc = dev_to_uea(dev);
        if (!sc)
                goto out;
 
-       if (sc->stats.phy.flags & 0x0C00)
-               ret = sprintf(buf, "ERROR\n");
-       else if (sc->stats.phy.flags & 0x0030)
-               ret = sprintf(buf, "LOSS\n");
-       else
-               ret = sprintf(buf, "GOOD\n");
+       if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+               if (sc->stats.phy.flags & 0x4000)
+                       delin = "RESET";
+               else if (sc->stats.phy.flags & 0x0001)
+                       delin = "LOSS";
+       } else {
+               if (sc->stats.phy.flags & 0x0C00)
+                       delin = "ERROR";
+               else if (sc->stats.phy.flags & 0x0030)
+                       delin = "LOSS";
+       }
+
+       ret = sprintf(buf, "%s\n", delin);
 out:
        mutex_unlock(&uea_mutex);
        return ret;
@@ -1662,6 +2479,7 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
        struct usb_device *usb = interface_to_usbdev(intf);
        struct uea_softc *sc;
        int ret, ifnum = intf->altsetting->desc.bInterfaceNumber;
+       unsigned int alt;
 
        uea_enters(usb);
 
@@ -1696,22 +2514,29 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
        sc->modem_index = (modem_index < NB_MODEM) ? modem_index++ : 0;
        sc->driver_info = id->driver_info;
 
-       /* ADI930 don't support iso */
-       if (UEA_CHIP_VERSION(id) != ADI930 && use_iso[sc->modem_index]) {
-               int i;
-
-               /* try set fastest alternate for inbound traffic interface */
-               for (i = FASTEST_ISO_INTF; i > 0; i--)
-                       if (usb_set_interface(usb, UEA_DS_IFACE_NO, i) == 0)
-                               break;
+       /* first try to use module parameter */
+       if (annex[sc->modem_index] == 1)
+               sc->annex = ANNEXA;
+       else if (annex[sc->modem_index] == 2)
+               sc->annex = ANNEXB;
+       /* try to autodetect annex */
+       else if (sc->driver_info & AUTO_ANNEX_A)
+               sc->annex = ANNEXA;
+       else if (sc->driver_info & AUTO_ANNEX_B)
+               sc->annex = ANNEXB;
+       else
+               sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA;
 
-               if (i > 0) {
-                       uea_dbg(usb, "set alternate %d for 2 interface\n", i);
+       alt = altsetting[sc->modem_index];
+       /* ADI930 don't support iso */
+       if (UEA_CHIP_VERSION(id) != ADI930 && alt > 0) {
+               if (alt <= 8 && usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) {
+                       uea_dbg(usb, "set alternate %u for 2 interface\n", alt);
                        uea_info(usb, "using iso mode\n");
                        usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ;
                } else {
-                       uea_err(usb, "setting any alternate failed for "
-                                       "2 interface, using bulk mode\n");
+                       uea_err(usb, "setting alternate %u failed for "
+                                       "2 interface, using bulk mode\n", alt);
                }
        }
 
@@ -1757,10 +2582,11 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
        struct usb_device *usb = interface_to_usbdev(intf);
 
        uea_enters(usb);
-       uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n",
-              le16_to_cpu(usb->descriptor.idVendor),
-              le16_to_cpu(usb->descriptor.idProduct),
-              chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots");
+       uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) Rev (%#X): %s\n",
+               le16_to_cpu(usb->descriptor.idVendor),
+               le16_to_cpu(usb->descriptor.idProduct),
+               le16_to_cpu(usb->descriptor.bcdDevice),
+               chip_name[UEA_CHIP_VERSION(id)]);
 
        usb_reset_device(usb);
 
@@ -1793,24 +2619,40 @@ static void uea_disconnect(struct usb_interface *intf)
  * List of supported VID/PID
  */
 static const struct usb_device_id uea_ids[] = {
+       {USB_DEVICE(ANALOG_VID, ADI930_PID_PREFIRM),    .driver_info = ADI930 | PREFIRM},
+       {USB_DEVICE(ANALOG_VID, ADI930_PID_PSTFIRM),    .driver_info = ADI930 | PSTFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PREFIRM),   .driver_info = EAGLE_I | PREFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PSTFIRM),   .driver_info = EAGLE_I | PSTFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PREFIRM),  .driver_info = EAGLE_II | PREFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PSTFIRM),  .driver_info = EAGLE_II | PSTFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PREFIRM),  .driver_info = EAGLE_IV | PREFIRM},
+       {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PSTFIRM),  .driver_info = EAGLE_IV | PSTFIRM},
+       {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PREFIRM),  .driver_info = EAGLE_I | PREFIRM},
+       {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PSTFIRM),  .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
+       {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PREFIRM),  .driver_info = EAGLE_I | PREFIRM},
+       {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PSTFIRM),  .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
+       {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+       {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_A},
+       {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+       {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_B},
        {USB_DEVICE(ELSA_VID,   ELSA_PID_PREFIRM),      .driver_info = ADI930 | PREFIRM},
        {USB_DEVICE(ELSA_VID,   ELSA_PID_PSTFIRM),      .driver_info = ADI930 | PSTFIRM},
-       {USB_DEVICE(EAGLE_VID,  EAGLE_I_PID_PREFIRM),   .driver_info = EAGLE_I | PREFIRM},
-       {USB_DEVICE(EAGLE_VID,  EAGLE_I_PID_PSTFIRM),   .driver_info = EAGLE_I | PSTFIRM},
-       {USB_DEVICE(EAGLE_VID,  EAGLE_II_PID_PREFIRM),  .driver_info = EAGLE_II | PREFIRM},
-       {USB_DEVICE(EAGLE_VID,  EAGLE_II_PID_PSTFIRM),  .driver_info = EAGLE_II | PSTFIRM},
-       {USB_DEVICE(EAGLE_VID,  EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
-       {USB_DEVICE(EAGLE_VID,  EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
-       {USB_DEVICE(EAGLE_VID,  EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM},
-       {USB_DEVICE(EAGLE_VID,  EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM},
+       {USB_DEVICE(ELSA_VID,   ELSA_PID_A_PREFIRM),    .driver_info = ADI930 | PREFIRM},
+       {USB_DEVICE(ELSA_VID,   ELSA_PID_A_PSTFIRM),    .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_A},
+       {USB_DEVICE(ELSA_VID,   ELSA_PID_B_PREFIRM),    .driver_info = ADI930 | PREFIRM},
+       {USB_DEVICE(ELSA_VID,   ELSA_PID_B_PSTFIRM),    .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_B},
        {USB_DEVICE(USR_VID,    MILLER_A_PID_PREFIRM),  .driver_info = EAGLE_I | PREFIRM},
-       {USB_DEVICE(USR_VID,    MILLER_A_PID_PSTFIRM),  .driver_info = EAGLE_I | PSTFIRM},
+       {USB_DEVICE(USR_VID,    MILLER_A_PID_PSTFIRM),  .driver_info = EAGLE_I | PSTFIRM  | AUTO_ANNEX_A},
        {USB_DEVICE(USR_VID,    MILLER_B_PID_PREFIRM),  .driver_info = EAGLE_I | PREFIRM},
-       {USB_DEVICE(USR_VID,    MILLER_B_PID_PSTFIRM),  .driver_info = EAGLE_I | PSTFIRM},
+       {USB_DEVICE(USR_VID,    MILLER_B_PID_PSTFIRM),  .driver_info = EAGLE_I | PSTFIRM  | AUTO_ANNEX_B},
        {USB_DEVICE(USR_VID,    HEINEKEN_A_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
-       {USB_DEVICE(USR_VID,    HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM},
+       {USB_DEVICE(USR_VID,    HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
        {USB_DEVICE(USR_VID,    HEINEKEN_B_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
-       {USB_DEVICE(USR_VID,    HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM},
+       {USB_DEVICE(USR_VID,    HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
        {}
 };
 
index 5192cd9..ad632f2 100644 (file)
@@ -28,6 +28,7 @@
  *     v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
  *     v0.13 - alloc space for statusbuf (<status> not on stack);
  *             use usb_buffer_alloc() for read buf & write buf;
+ *      none  - Maintained in Linux kernel after v0.13
  */
 
 /*
@@ -69,7 +70,6 @@
 #define USBLP_DEVICE_ID_SIZE   1024
 
 /* ioctls: */
-#define LPGETSTATUS            0x060b          /* same as in drivers/char/lp.c */
 #define IOCNR_GET_DEVICE_ID            1
 #define IOCNR_GET_PROTOCOLS            2
 #define IOCNR_SET_PROTOCOL             3
@@ -115,7 +115,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
 #define USBLP_MINORS           16
 #define USBLP_MINOR_BASE       0
 
-#define USBLP_WRITE_TIMEOUT    (5000)                  /* 5 seconds */
+#define USBLP_CTL_TIMEOUT      5000                    /* 5 seconds */
 
 #define USBLP_FIRST_PROTOCOL   1
 #define USBLP_LAST_PROTOCOL    3
@@ -159,10 +159,12 @@ struct usblp {
        int                     wstatus;        /* bytes written or error */
        int                     rstatus;        /* bytes ready or error */
        unsigned int            quirks;                 /* quirks flags */
+       unsigned int            flags;                  /* mode flags */
        unsigned char           used;                   /* True if open */
        unsigned char           present;                /* True if not disconnected */
        unsigned char           bidir;                  /* interface is bidirectional */
        unsigned char           sleeping;               /* interface is suspended */
+       unsigned char           no_paper;               /* Paper Out happened */
        unsigned char           *device_id_string;      /* IEEE 1284 DEVICE ID string (ptr) */
                                                        /* first 2 bytes are (big-endian) length */
 };
@@ -259,7 +261,7 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i
 
        retval = usb_control_msg(usblp->dev,
                dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
-               request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT);
+               request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT);
        dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d",
                request, !!dir, recip, value, index, len, retval);
        return retval < 0 ? retval : 0;
@@ -325,13 +327,11 @@ static void usblp_bulk_write(struct urb *urb)
                usblp->wstatus = status;
        else
                usblp->wstatus = urb->actual_length;
+       usblp->no_paper = 0;
        usblp->wcomplete = 1;
        wake_up(&usblp->wwait);
        spin_unlock(&usblp->lock);
 
-       /* XXX Use usb_setup_bulk_urb when available. Talk to Marcel. */
-       kfree(urb->transfer_buffer);
-       urb->transfer_buffer = NULL;    /* Not refcounted, so to be safe... */
        usb_free_urb(urb);
 }
 
@@ -346,16 +346,17 @@ static int usblp_check_status(struct usblp *usblp, int err)
        unsigned char status, newerr = 0;
        int error;
 
-       error = usblp_read_status (usblp, usblp->statusbuf);
-       if (error < 0) {
+       mutex_lock(&usblp->mut);
+       if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) {
+               mutex_unlock(&usblp->mut);
                if (printk_ratelimit())
                        printk(KERN_ERR
                                "usblp%d: error %d reading printer status\n",
                                usblp->minor, error);
                return 0;
        }
-
        status = *usblp->statusbuf;
+       mutex_unlock(&usblp->mut);
 
        if (~status & LP_PERRORP)
                newerr = 3;
@@ -411,18 +412,10 @@ static int usblp_open(struct inode *inode, struct file *file)
                goto out;
 
        /*
-        * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ???
-        * This is #if 0-ed because we *don't* want to fail an open
-        * just because the printer is off-line.
+        * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons:
+        *  - We do not want persistent state which close(2) does not clear
+        *  - It is not used anyway, according to CUPS people
         */
-#if 0
-       if ((retval = usblp_check_status(usblp, 0))) {
-               retval = retval > 1 ? -EIO : -ENOSPC;
-               goto out;
-       }
-#else
-       retval = 0;
-#endif
 
        retval = usb_autopm_get_interface(intf);
        if (retval < 0)
@@ -463,6 +456,8 @@ static int usblp_release(struct inode *inode, struct file *file)
 {
        struct usblp *usblp = file->private_data;
 
+       usblp->flags &= ~LP_ABORT;
+
        mutex_lock (&usblp_mutex);
        usblp->used = 0;
        if (usblp->present) {
@@ -485,8 +480,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait
        poll_wait(file, &usblp->rwait, wait);
        poll_wait(file, &usblp->wwait, wait);
        spin_lock_irqsave(&usblp->lock, flags);
-       ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN  | POLLRDNORM)
-                              | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM);
+       ret = ((usblp->bidir && usblp->rcomplete) ? POLLIN  | POLLRDNORM : 0) |
+          ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0);
        spin_unlock_irqrestore(&usblp->lock, flags);
        return ret;
 }
@@ -675,6 +670,13 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                                        retval = -EFAULT;
                                break;
 
+                       case LPABORT:
+                               if (arg)
+                                       usblp->flags |= LP_ABORT;
+                               else
+                                       usblp->flags &= ~LP_ABORT;
+                               break;
+
                        default:
                                retval = -ENOTTY;
                }
@@ -684,10 +686,30 @@ done:
        return retval;
 }
 
+static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length)
+{
+       struct urb *urb;
+       char *writebuf;
+
+       if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL)
+               return NULL;
+       if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
+               kfree(writebuf);
+               return NULL;
+       }
+
+       usb_fill_bulk_urb(urb, usblp->dev,
+               usb_sndbulkpipe(usblp->dev,
+                usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
+               writebuf, transfer_length, usblp_bulk_write, usblp);
+       urb->transfer_flags |= URB_FREE_BUFFER;
+
+       return urb;
+}
+
 static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 {
        struct usblp *usblp = file->private_data;
-       char *writebuf;
        struct urb *writeurb;
        int rv;
        int transfer_length;
@@ -708,17 +730,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
                        transfer_length = USBLP_BUF_SIZE;
 
                rv = -ENOMEM;
-               if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL)
-                       goto raise_buf;
-               if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == NULL)
+               if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL)
                        goto raise_urb;
-               usb_fill_bulk_urb(writeurb, usblp->dev,
-                       usb_sndbulkpipe(usblp->dev,
-                         usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
-                       writebuf, transfer_length, usblp_bulk_write, usblp);
                usb_anchor_urb(writeurb, &usblp->urbs);
 
-               if (copy_from_user(writebuf,
+               if (copy_from_user(writeurb->transfer_buffer,
                                   buffer + writecount, transfer_length)) {
                        rv = -EFAULT;
                        goto raise_badaddr;
@@ -730,6 +746,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
                if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) {
                        usblp->wstatus = 0;
                        spin_lock_irq(&usblp->lock);
+                       usblp->no_paper = 0;
                        usblp->wcomplete = 1;
                        wake_up(&usblp->wwait);
                        spin_unlock_irq(&usblp->lock);
@@ -747,12 +764,17 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
                                /* Presume that it's going to complete well. */
                                writecount += transfer_length;
                        }
+                       if (rv == -ENOSPC) {
+                               spin_lock_irq(&usblp->lock);
+                               usblp->no_paper = 1;    /* Mark for poll(2) */
+                               spin_unlock_irq(&usblp->lock);
+                               writecount += transfer_length;
+                       }
                        /* Leave URB dangling, to be cleaned on close. */
                        goto collect_error;
                }
 
                if (usblp->wstatus < 0) {
-                       usblp_check_status(usblp, 0);
                        rv = -EIO;
                        goto collect_error;
                }
@@ -771,8 +793,6 @@ raise_badaddr:
        usb_unanchor_urb(writeurb);
        usb_free_urb(writeurb);
 raise_urb:
-       kfree(writebuf);
-raise_buf:
 raise_wait:
 collect_error:         /* Out of raise sequence */
        mutex_unlock(&usblp->wmut);
@@ -838,32 +858,36 @@ done:
  * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use
  * select(2) or poll(2) to wait for the buffer to drain before closing.
  * Alternatively, set blocking mode with fcntl and issue a zero-size write.
- *
- * Old v0.13 code had a non-functional timeout for wait_event(). Someone forgot
- * to check the return code for timeout expiration, so it had no effect.
- * Apparently, it was intended to check for error conditons, such as out
- * of paper. It is going to return when we settle things with CUPS. XXX
  */
 static int usblp_wwait(struct usblp *usblp, int nonblock)
 {
        DECLARE_WAITQUEUE(waita, current);
        int rc;
+       int err = 0;
 
        add_wait_queue(&usblp->wwait, &waita);
        for (;;) {
+               set_current_state(TASK_INTERRUPTIBLE);
                if (mutex_lock_interruptible(&usblp->mut)) {
                        rc = -EINTR;
                        break;
                }
-               set_current_state(TASK_INTERRUPTIBLE);
-               if ((rc = usblp_wtest(usblp, nonblock)) < 0) {
-                       mutex_unlock(&usblp->mut);
-                       break;
-               }
+               rc = usblp_wtest(usblp, nonblock);
                mutex_unlock(&usblp->mut);
-               if (rc == 0)
+               if (rc <= 0)
                        break;
-               schedule();
+
+               if (usblp->flags & LP_ABORT) {
+                       if (schedule_timeout(msecs_to_jiffies(5000)) == 0) {
+                               err = usblp_check_status(usblp, err);
+                               if (err == 1) { /* Paper out */
+                                       rc = -ENOSPC;
+                                       break;
+                               }
+                       }
+               } else {
+                       schedule();
+               }
        }
        set_current_state(TASK_RUNNING);
        remove_wait_queue(&usblp->wwait, &waita);
index cb69aa1..1a8edce 100644 (file)
@@ -507,18 +507,30 @@ void usb_destroy_configuration(struct usb_device *dev)
 }
 
 
-// hub-only!! ... and only in reset path, or usb_new_device()
-// (used by real hubs and virtual root hubs)
+/*
+ * Get the USB config descriptors, cache and parse'em
+ *
+ * hub-only!! ... and only in reset path, or usb_new_device()
+ * (used by real hubs and virtual root hubs)
+ *
+ * NOTE: if this is a WUSB device and is not authorized, we skip the
+ *       whole thing. A non-authorized USB device has no
+ *       configurations.
+ */
 int usb_get_configuration(struct usb_device *dev)
 {
        struct device *ddev = &dev->dev;
        int ncfg = dev->descriptor.bNumConfigurations;
-       int result = -ENOMEM;
+       int result = 0;
        unsigned int cfgno, length;
        unsigned char *buffer;
        unsigned char *bigbuffer;
        struct usb_config_descriptor *desc;
 
+       cfgno = 0;
+       if (dev->authorized == 0)       /* Not really an error */
+               goto out_not_authorized;
+       result = -ENOMEM;
        if (ncfg > USB_MAXCONFIG) {
                dev_warn(ddev, "too many configurations: %d, "
                    "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
@@ -545,14 +557,15 @@ int usb_get_configuration(struct usb_device *dev)
                goto err2;
        desc = (struct usb_config_descriptor *)buffer;
 
-       for (cfgno = 0; cfgno < ncfg; cfgno++) {
+       result = 0;
+       for (; cfgno < ncfg; cfgno++) {
                /* We grab just the first descriptor so we know how long
                 * the whole configuration is */
                result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
                    buffer, USB_DT_CONFIG_SIZE);
                if (result < 0) {
                        dev_err(ddev, "unable to read config index %d "
-                           "descriptor/%s\n", cfgno, "start");
+                           "descriptor/%s: %d\n", cfgno, "start", result);
                        dev_err(ddev, "chopping to %d config(s)\n", cfgno);
                        dev->descriptor.bNumConfigurations = cfgno;
                        break;
@@ -599,6 +612,7 @@ int usb_get_configuration(struct usb_device *dev)
 
 err:
        kfree(buffer);
+out_not_authorized:
        dev->descriptor.bNumConfigurations = cfgno;
 err2:
        if (result == -ENOMEM)
index 927a181..e5ad76b 100644 (file)
@@ -71,6 +71,7 @@ struct async {
        void __user *userbuffer;
        void __user *userurb;
        struct urb *urb;
+       int status;
        u32 secid;
 };
 
@@ -289,10 +290,8 @@ static void snoop_urb(struct urb *urb, void __user *userurb)
        if (!usbfs_snoop)
                return;
 
-       if (urb->pipe & USB_DIR_IN)
-               dev_info(&urb->dev->dev, "direction=IN\n");
-       else
-               dev_info(&urb->dev->dev, "direction=OUT\n");
+       dev_info(&urb->dev->dev, "direction=%s\n",
+                       usb_urb_dir_in(urb) ? "IN" : "OUT");
        dev_info(&urb->dev->dev, "userurb=%p\n", userurb);
        dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n",
                 urb->transfer_buffer_length);
@@ -312,9 +311,10 @@ static void async_completed(struct urb *urb)
         spin_lock(&ps->lock);
         list_move_tail(&as->asynclist, &ps->async_completed);
         spin_unlock(&ps->lock);
+       as->status = urb->status;
        if (as->signr) {
                sinfo.si_signo = as->signr;
-               sinfo.si_errno = as->urb->status;
+               sinfo.si_errno = as->status;
                sinfo.si_code = SI_ASYNCIO;
                sinfo.si_addr = as->userurb;
                kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
@@ -910,6 +910,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
        struct usb_ctrlrequest *dr = NULL;
        unsigned int u, totlen, isofrmlen;
        int ret, ifnum = -1;
+       int is_in;
 
        if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
                           URB_NO_FSBR|URB_ZERO_PACKET))
@@ -924,16 +925,18 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                if ((ret = checkintf(ps, ifnum)))
                        return ret;
        }
-       if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0)
-               ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
-       else
-               ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+       if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) {
+               is_in = 1;
+               ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+       } else {
+               is_in = 0;
+               ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+       }
        if (!ep)
                return -ENOENT;
        switch(uurb->type) {
        case USBDEVFS_URB_TYPE_CONTROL:
-               if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-                               != USB_ENDPOINT_XFER_CONTROL)
+               if (!usb_endpoint_xfer_control(&ep->desc))
                        return -EINVAL;
                /* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */
                if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
@@ -952,23 +955,32 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                        kfree(dr);
                        return ret;
                }
-               uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK);
                uurb->number_of_packets = 0;
                uurb->buffer_length = le16_to_cpup(&dr->wLength);
                uurb->buffer += 8;
-               if (!access_ok((uurb->endpoint & USB_DIR_IN) ?  VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) {
+               if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
+                       is_in = 1;
+                       uurb->endpoint |= USB_DIR_IN;
+               } else {
+                       is_in = 0;
+                       uurb->endpoint &= ~USB_DIR_IN;
+               }
+               if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+                               uurb->buffer, uurb->buffer_length)) {
                        kfree(dr);
                        return -EFAULT;
                }
                snoop(&ps->dev->dev, "control urb: bRequest=%02x "
                        "bRrequestType=%02x wValue=%04x "
                        "wIndex=%04x wLength=%04x\n",
-                       dr->bRequest, dr->bRequestType, dr->wValue,
-                       dr->wIndex, dr->wLength);
+                       dr->bRequest, dr->bRequestType,
+                       __le16_to_cpup(&dr->wValue),
+                       __le16_to_cpup(&dr->wIndex),
+                       __le16_to_cpup(&dr->wLength));
                break;
 
        case USBDEVFS_URB_TYPE_BULK:
-               switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+               switch (usb_endpoint_type(&ep->desc)) {
                case USB_ENDPOINT_XFER_CONTROL:
                case USB_ENDPOINT_XFER_ISOC:
                        return -EINVAL;
@@ -977,7 +989,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                uurb->number_of_packets = 0;
                if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
                        return -EINVAL;
-               if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
+               if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+                               uurb->buffer, uurb->buffer_length))
                        return -EFAULT;
                snoop(&ps->dev->dev, "bulk urb\n");
                break;
@@ -986,8 +999,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                /* arbitrary limit */
                if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128)
                        return -EINVAL;
-               if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-                               != USB_ENDPOINT_XFER_ISOC)
+               if (!usb_endpoint_xfer_isoc(&ep->desc))
                        return -EINVAL;
                isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
                if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
@@ -1014,12 +1026,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 
        case USBDEVFS_URB_TYPE_INTERRUPT:
                uurb->number_of_packets = 0;
-               if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-                               != USB_ENDPOINT_XFER_INT)
+               if (!usb_endpoint_xfer_int(&ep->desc))
                        return -EINVAL;
                if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
                        return -EINVAL;
-               if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
+               if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+                               uurb->buffer, uurb->buffer_length))
                        return -EFAULT;
                snoop(&ps->dev->dev, "interrupt urb\n");
                break;
@@ -1039,8 +1051,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                return -ENOMEM;
        }
         as->urb->dev = ps->dev;
-        as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN);
-        as->urb->transfer_flags = uurb->flags;
+        as->urb->pipe = (uurb->type << 30) |
+                       __create_pipe(ps->dev, uurb->endpoint & 0xf) |
+                       (uurb->endpoint & USB_DIR_IN);
+        as->urb->transfer_flags = uurb->flags |
+                       (is_in ? URB_DIR_IN : URB_DIR_OUT);
        as->urb->transfer_buffer_length = uurb->buffer_length;
        as->urb->setup_packet = (unsigned char*)dr;
        as->urb->start_frame = uurb->start_frame;
@@ -1070,13 +1085,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
        as->uid = current->uid;
        as->euid = current->euid;
        security_task_getsecid(current, &as->secid);
-       if (!(uurb->endpoint & USB_DIR_IN)) {
-               if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) {
+       if (!is_in) {
+               if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
+                               as->urb->transfer_buffer_length)) {
                        free_async(as);
                        return -EFAULT;
                }
        }
-       snoop(&as->urb->dev->dev, "submit urb\n");
        snoop_urb(as->urb, as->userurb);
         async_newpending(as);
         if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
@@ -1119,14 +1134,14 @@ static int processcompl(struct async *as, void __user * __user *arg)
        if (as->userbuffer)
                if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
                        return -EFAULT;
-       if (put_user(urb->status, &userurb->status))
+       if (put_user(as->status, &userurb->status))
                return -EFAULT;
        if (put_user(urb->actual_length, &userurb->actual_length))
                return -EFAULT;
        if (put_user(urb->error_count, &userurb->error_count))
                return -EFAULT;
 
-       if (usb_pipeisoc(urb->pipe)) {
+       if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
                for (i = 0; i < urb->number_of_packets; i++) {
                        if (put_user(urb->iso_frame_desc[i].actual_length,
                                     &userurb->iso_frame_desc[i].actual_length))
@@ -1233,14 +1248,14 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
        if (as->userbuffer)
                if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
                        return -EFAULT;
-       if (put_user(urb->status, &userurb->status))
+       if (put_user(as->status, &userurb->status))
                return -EFAULT;
        if (put_user(urb->actual_length, &userurb->actual_length))
                return -EFAULT;
        if (put_user(urb->error_count, &userurb->error_count))
                return -EFAULT;
 
-       if (usb_pipeisoc(urb->pipe)) {
+       if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
                for (i = 0; i < urb->number_of_packets; i++) {
                        if (put_user(urb->iso_frame_desc[i].actual_length,
                                     &userurb->iso_frame_desc[i].actual_length))
index 63b1243..c27bc08 100644 (file)
@@ -202,6 +202,11 @@ static int usb_probe_interface(struct device *dev)
        intf = to_usb_interface(dev);
        udev = interface_to_usbdev(intf);
 
+       if (udev->authorized == 0) {
+               dev_err(&intf->dev, "Device is not authorized for usage\n");
+               return -ENODEV;
+       }
+
        id = usb_match_id(intf, driver->id_table);
        if (!id)
                id = usb_match_dynamic_id(intf, driver);
@@ -945,11 +950,11 @@ done:
 #ifdef CONFIG_USB_SUSPEND
 
 /* Internal routine to check whether we may autosuspend a device. */
-static int autosuspend_check(struct usb_device *udev)
+static int autosuspend_check(struct usb_device *udev, int reschedule)
 {
        int                     i;
        struct usb_interface    *intf;
-       unsigned long           suspend_time;
+       unsigned long           suspend_time, j;
 
        /* For autosuspend, fail fast if anything is in use or autosuspend
         * is disabled.  Also fail if any interfaces require remote wakeup
@@ -991,20 +996,20 @@ static int autosuspend_check(struct usb_device *udev)
        }
 
        /* If everything is okay but the device hasn't been idle for long
-        * enough, queue a delayed autosuspend request.
+        * enough, queue a delayed autosuspend request.  If the device
+        * _has_ been idle for long enough and the reschedule flag is set,
+        * likewise queue a delayed (1 second) autosuspend request.
         */
-       if (time_after(suspend_time, jiffies)) {
+       j = jiffies;
+       if (time_before(j, suspend_time))
+               reschedule = 1;
+       else
+               suspend_time = j + HZ;
+       if (reschedule) {
                if (!timer_pending(&udev->autosuspend.timer)) {
-
-                       /* The value of jiffies may change between the
-                        * time_after() comparison above and the subtraction
-                        * below.  That's okay; the system behaves sanely
-                        * when a timer is registered for the present moment
-                        * or for the past.
-                        */
                        queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
-                               round_jiffies_relative(suspend_time - jiffies));
-                       }
+                               round_jiffies_relative(suspend_time - j));
+               }
                return -EAGAIN;
        }
        return 0;
@@ -1012,7 +1017,7 @@ static int autosuspend_check(struct usb_device *udev)
 
 #else
 
-static inline int autosuspend_check(struct usb_device *udev)
+static inline int autosuspend_check(struct usb_device *udev, int reschedule)
 {
        return 0;
 }
@@ -1069,7 +1074,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
        udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
 
        if (udev->auto_pm) {
-               status = autosuspend_check(udev);
+               status = autosuspend_check(udev, 0);
                if (status < 0)
                        goto done;
        }
@@ -1083,15 +1088,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
                                break;
                }
        }
-       if (status == 0) {
-
-               /* Non-root devices don't need to do anything for FREEZE
-                * or PRETHAW. */
-               if (udev->parent && (msg.event == PM_EVENT_FREEZE ||
-                               msg.event == PM_EVENT_PRETHAW))
-                       goto done;
+       if (status == 0)
                status = usb_suspend_device(udev, msg);
-       }
 
        /* If the suspend failed, resume interfaces that did get suspended */
        if (status != 0) {
@@ -1102,12 +1100,24 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
 
                /* Try another autosuspend when the interfaces aren't busy */
                if (udev->auto_pm)
-                       autosuspend_check(udev);
+                       autosuspend_check(udev, status == -EBUSY);
 
-       /* If the suspend succeeded, propagate it up the tree */
+       /* If the suspend succeeded then prevent any more URB submissions,
+        * flush any outstanding URBs, and propagate the suspend up the tree.
+        */
        } else {
                cancel_delayed_work(&udev->autosuspend);
-               if (parent)
+               udev->can_submit = 0;
+               for (i = 0; i < 16; ++i) {
+                       usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
+                       usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
+               }
+
+               /* If this is just a FREEZE or a PRETHAW, udev might
+                * not really be suspended.  Only true suspends get
+                * propagated up the device tree.
+                */
+               if (parent && udev->state == USB_STATE_SUSPENDED)
                        usb_autosuspend_device(parent);
        }
 
@@ -1156,6 +1166,7 @@ static int usb_resume_both(struct usb_device *udev)
                status = -ENODEV;
                goto done;
        }
+       udev->can_submit = 1;
 
        /* Propagate the resume up the tree, if necessary */
        if (udev->state == USB_STATE_SUSPENDED) {
@@ -1529,9 +1540,21 @@ int usb_external_resume_device(struct usb_device *udev)
 
 static int usb_suspend(struct device *dev, pm_message_t message)
 {
+       struct usb_device       *udev;
+
        if (!is_usb_device(dev))        /* Ignore PM for interfaces */
                return 0;
-       return usb_external_suspend_device(to_usb_device(dev), message);
+       udev = to_usb_device(dev);
+
+       /* If udev is already suspended, we can skip this suspend and
+        * we should also skip the upcoming system resume. */
+       if (udev->state == USB_STATE_SUSPENDED) {
+               udev->skip_sys_resume = 1;
+               return 0;
+       }
+
+       udev->skip_sys_resume = 0;
+       return usb_external_suspend_device(udev, message);
 }
 
 static int usb_resume(struct device *dev)
@@ -1542,13 +1565,14 @@ static int usb_resume(struct device *dev)
                return 0;
        udev = to_usb_device(dev);
 
-       /* If autoresume is disabled then we also want to prevent resume
-        * during system wakeup.  However, a "persistent-device" reset-resume
-        * after power loss counts as a wakeup event.  So allow a
-        * reset-resume to occur if remote wakeup is enabled. */
-       if (udev->autoresume_disabled) {
+       /* If udev->skip_sys_resume is set then udev was already suspended
+        * when the system suspend started, so we don't want to resume
+        * udev during this system wakeup.  However a reset-resume counts
+        * as a wakeup event, so allow a reset-resume to occur if remote
+        * wakeup is enabled. */
+       if (udev->skip_sys_resume) {
                if (!(udev->reset_resume && udev->do_remote_wakeup))
-                       return -EPERM;
+                       return -EHOSTUNREACH;
        }
        return usb_external_resume_device(udev);
 }
index e0ec704..7dc123d 100644 (file)
@@ -267,7 +267,6 @@ static void ep_device_release(struct device *dev)
 {
        struct ep_device *ep_dev = to_ep_device(dev);
 
-       dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id);
        endpoint_free_minor(ep_dev);
        kfree(ep_dev);
 }
index b2fc2b1..c1cb94e 100644 (file)
@@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc)
                && desc->bInterfaceProtocol == 1;
 }
 
-static int choose_configuration(struct usb_device *udev)
+int usb_choose_configuration(struct usb_device *udev)
 {
        int i;
        int num_configs;
@@ -161,17 +161,20 @@ static int generic_probe(struct usb_device *udev)
        /* Choose and set the configuration.  This registers the interfaces
         * with the driver core and lets interface drivers bind to them.
         */
-       c = choose_configuration(udev);
-       if (c >= 0) {
-               err = usb_set_configuration(udev, c);
-               if (err) {
-                       dev_err(&udev->dev, "can't set config #%d, error %d\n",
+       if (udev->authorized == 0)
+               dev_err(&udev->dev, "Device is not authorized for usage\n");
+       else {
+               c = usb_choose_configuration(udev);
+               if (c >= 0) {
+                       err = usb_set_configuration(udev, c);
+                       if (err) {
+                               dev_err(&udev->dev, "can't set config #%d, error %d\n",
                                        c, err);
-                       /* This need not be fatal.  The user can try to
-                        * set other configurations. */
+                               /* This need not be fatal.  The user can try to
+                                * set other configurations. */
+                       }
                }
        }
-
        /* USB device state == configured ... usable */
        usb_notify_add_device(udev);
 
@@ -203,8 +206,13 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)
         */
        if (!udev->parent)
                rc = hcd_bus_suspend(udev);
+
+       /* Non-root devices don't need to do anything for FREEZE or PRETHAW */
+       else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
+               rc = 0;
        else
                rc = usb_port_suspend(udev);
+
        return rc;
 }
 
index 42ef1d5..3dd997d 100644 (file)
@@ -356,10 +356,18 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
        const u8        *bufp = tbuf;
        int             len = 0;
        int             patch_wakeup = 0;
-       unsigned long   flags;
-       int             status = 0;
+       int             status;
        int             n;
 
+       might_sleep();
+
+       spin_lock_irq(&hcd_root_hub_lock);
+       status = usb_hcd_link_urb_to_ep(hcd, urb);
+       spin_unlock_irq(&hcd_root_hub_lock);
+       if (status)
+               return status;
+       urb->hcpriv = hcd;      /* Indicate it's queued */
+
        cmd = (struct usb_ctrlrequest *) urb->setup_packet;
        typeReq  = (cmd->bRequestType << 8) | cmd->bRequest;
        wValue   = le16_to_cpu (cmd->wValue);
@@ -523,13 +531,18 @@ error:
        }
 
        /* any errors get returned through the urb completion */
-       local_irq_save (flags);
-       spin_lock (&urb->lock);
-       if (urb->status == -EINPROGRESS)
-               urb->status = status;
-       spin_unlock (&urb->lock);
-       usb_hcd_giveback_urb (hcd, urb);
-       local_irq_restore (flags);
+       spin_lock_irq(&hcd_root_hub_lock);
+       usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+       /* This peculiar use of spinlocks echoes what real HC drivers do.
+        * Avoiding calls to local_irq_disable/enable makes the code
+        * RT-friendly.
+        */
+       spin_unlock(&hcd_root_hub_lock);
+       usb_hcd_giveback_urb(hcd, urb, status);
+       spin_lock(&hcd_root_hub_lock);
+
+       spin_unlock_irq(&hcd_root_hub_lock);
        return 0;
 }
 
@@ -559,31 +572,23 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
        if (length > 0) {
 
                /* try to complete the status urb */
-               local_irq_save (flags);
-               spin_lock(&hcd_root_hub_lock);
+               spin_lock_irqsave(&hcd_root_hub_lock, flags);
                urb = hcd->status_urb;
                if (urb) {
-                       spin_lock(&urb->lock);
-                       if (urb->status == -EINPROGRESS) {
-                               hcd->poll_pending = 0;
-                               hcd->status_urb = NULL;
-                               urb->status = 0;
-                               urb->hcpriv = NULL;
-                               urb->actual_length = length;
-                               memcpy(urb->transfer_buffer, buffer, length);
-                       } else          /* urb has been unlinked */
-                               length = 0;
-                       spin_unlock(&urb->lock);
-               } else
-                       length = 0;
-               spin_unlock(&hcd_root_hub_lock);
+                       hcd->poll_pending = 0;
+                       hcd->status_urb = NULL;
+                       urb->actual_length = length;
+                       memcpy(urb->transfer_buffer, buffer, length);
 
-               /* local irqs are always blocked in completions */
-               if (length > 0)
-                       usb_hcd_giveback_urb (hcd, urb);
-               else
+                       usb_hcd_unlink_urb_from_ep(hcd, urb);
+                       spin_unlock(&hcd_root_hub_lock);
+                       usb_hcd_giveback_urb(hcd, urb, 0);
+                       spin_lock(&hcd_root_hub_lock);
+               } else {
+                       length = 0;
                        hcd->poll_pending = 1;
-               local_irq_restore (flags);
+               }
+               spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
        }
 
        /* The USB 2.0 spec says 256 ms.  This is close enough and won't
@@ -611,33 +616,35 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
        int             len = 1 + (urb->dev->maxchild / 8);
 
        spin_lock_irqsave (&hcd_root_hub_lock, flags);
-       if (urb->status != -EINPROGRESS)        /* already unlinked */
-               retval = urb->status;
-       else if (hcd->status_urb || urb->transfer_buffer_length < len) {
+       if (hcd->status_urb || urb->transfer_buffer_length < len) {
                dev_dbg (hcd->self.controller, "not queuing rh status urb\n");
                retval = -EINVAL;
-       } else {
-               hcd->status_urb = urb;
-               urb->hcpriv = hcd;      /* indicate it's queued */
+               goto done;
+       }
 
-               if (!hcd->uses_new_polling)
-                       mod_timer (&hcd->rh_timer,
-                               (jiffies/(HZ/4) + 1) * (HZ/4));
+       retval = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (retval)
+               goto done;
 
-               /* If a status change has already occurred, report it ASAP */
-               else if (hcd->poll_pending)
-                       mod_timer (&hcd->rh_timer, jiffies);
-               retval = 0;
-       }
+       hcd->status_urb = urb;
+       urb->hcpriv = hcd;      /* indicate it's queued */
+       if (!hcd->uses_new_polling)
+               mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
+
+       /* If a status change has already occurred, report it ASAP */
+       else if (hcd->poll_pending)
+               mod_timer(&hcd->rh_timer, jiffies);
+       retval = 0;
+ done:
        spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
        return retval;
 }
 
 static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
 {
-       if (usb_pipeint (urb->pipe))
+       if (usb_endpoint_xfer_int(&urb->ep->desc))
                return rh_queue_status (hcd, urb);
-       if (usb_pipecontrol (urb->pipe))
+       if (usb_endpoint_xfer_control(&urb->ep->desc))
                return rh_call_control (hcd, urb);
        return -EINVAL;
 }
@@ -647,32 +654,96 @@ static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
 /* Unlinks of root-hub control URBs are legal, but they don't do anything
  * since these URBs always execute synchronously.
  */
-static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
        unsigned long   flags;
+       int             rc;
+
+       spin_lock_irqsave(&hcd_root_hub_lock, flags);
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (rc)
+               goto done;
 
-       if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */
+       if (usb_endpoint_num(&urb->ep->desc) == 0) {    /* Control URB */
                ;       /* Do nothing */
 
        } else {                                /* Status URB */
                if (!hcd->uses_new_polling)
                        del_timer (&hcd->rh_timer);
-               local_irq_save (flags);
-               spin_lock (&hcd_root_hub_lock);
                if (urb == hcd->status_urb) {
                        hcd->status_urb = NULL;
-                       urb->hcpriv = NULL;
-               } else
-                       urb = NULL;             /* wasn't fully queued */
-               spin_unlock (&hcd_root_hub_lock);
-               if (urb)
-                       usb_hcd_giveback_urb (hcd, urb);
-               local_irq_restore (flags);
+                       usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+                       spin_unlock(&hcd_root_hub_lock);
+                       usb_hcd_giveback_urb(hcd, urb, status);
+                       spin_lock(&hcd_root_hub_lock);
+               }
        }
+ done:
+       spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
+       return rc;
+}
 
-       return 0;
+
+
+/*
+ * Show & store the current value of authorized_default
+ */
+static ssize_t usb_host_authorized_default_show(struct device *dev,
+                                               struct device_attribute *attr,
+                                               char *buf)
+{
+       struct usb_device *rh_usb_dev = to_usb_device(dev);
+       struct usb_bus *usb_bus = rh_usb_dev->bus;
+       struct usb_hcd *usb_hcd;
+
+       if (usb_bus == NULL)    /* FIXME: not sure if this case is possible */
+               return -ENODEV;
+       usb_hcd = bus_to_hcd(usb_bus);
+       return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default);
+}
+
+static ssize_t usb_host_authorized_default_store(struct device *dev,
+                                                struct device_attribute *attr,
+                                                const char *buf, size_t size)
+{
+       ssize_t result;
+       unsigned val;
+       struct usb_device *rh_usb_dev = to_usb_device(dev);
+       struct usb_bus *usb_bus = rh_usb_dev->bus;
+       struct usb_hcd *usb_hcd;
+
+       if (usb_bus == NULL)    /* FIXME: not sure if this case is possible */
+               return -ENODEV;
+       usb_hcd = bus_to_hcd(usb_bus);
+       result = sscanf(buf, "%u\n", &val);
+       if (result == 1) {
+               usb_hcd->authorized_default = val? 1 : 0;
+               result = size;
+       }
+       else
+               result = -EINVAL;
+       return result;
 }
 
+static DEVICE_ATTR(authorized_default, 0644,
+           usb_host_authorized_default_show,
+           usb_host_authorized_default_store);
+
+
+/* Group all the USB bus attributes */
+static struct attribute *usb_bus_attrs[] = {
+               &dev_attr_authorized_default.attr,
+               NULL,
+};
+
+static struct attribute_group usb_bus_attr_group = {
+       .name = NULL,   /* we want them in the same directory */
+       .attrs = usb_bus_attrs,
+};
+
+
+
 /*-------------------------------------------------------------------------*/
 
 static struct class *usb_host_class;
@@ -726,27 +797,23 @@ static void usb_bus_init (struct usb_bus *bus)
  */
 static int usb_register_bus(struct usb_bus *bus)
 {
+       int result = -E2BIG;
        int busnum;
 
        mutex_lock(&usb_bus_list_lock);
        busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
-       if (busnum < USB_MAXBUS) {
-               set_bit (busnum, busmap.busmap);
-               bus->busnum = busnum;
-       } else {
+       if (busnum >= USB_MAXBUS) {
                printk (KERN_ERR "%s: too many buses\n", usbcore_name);
-               mutex_unlock(&usb_bus_list_lock);
-               return -E2BIG;
+               goto error_find_busnum;
        }
-
+       set_bit (busnum, busmap.busmap);
+       bus->busnum = busnum;
        bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0),
-                                            bus->controller, "usb_host%d", busnum);
-       if (IS_ERR(bus->class_dev)) {
-               clear_bit(busnum, busmap.busmap);
-               mutex_unlock(&usb_bus_list_lock);
-               return PTR_ERR(bus->class_dev);
-       }
-
+                                            bus->controller, "usb_host%d",
+                                            busnum);
+       result = PTR_ERR(bus->class_dev);
+       if (IS_ERR(bus->class_dev))
+               goto error_create_class_dev;
        class_set_devdata(bus->class_dev, bus);
 
        /* Add it to the local list of buses */
@@ -755,8 +822,15 @@ static int usb_register_bus(struct usb_bus *bus)
 
        usb_notify_add_bus(bus);
 
-       dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);
+       dev_info (bus->controller, "new USB bus registered, assigned bus "
+                 "number %d\n", bus->busnum);
        return 0;
+
+error_create_class_dev:
+       clear_bit(busnum, busmap.busmap);
+error_find_busnum:
+       mutex_unlock(&usb_bus_list_lock);
+       return result;
 }
 
 /**
@@ -908,103 +982,145 @@ EXPORT_SYMBOL (usb_calc_bus_time);
 
 /*-------------------------------------------------------------------------*/
 
-static void urb_unlink(struct usb_hcd *hcd, struct urb *urb)
+/**
+ * usb_hcd_link_urb_to_ep - add an URB to its endpoint queue
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being submitted
+ *
+ * Host controller drivers should call this routine in their enqueue()
+ * method.  The HCD's private spinlock must be held and interrupts must
+ * be disabled.  The actions carried out here are required for URB
+ * submission, as well as for endpoint shutdown and for usb_kill_urb.
+ *
+ * Returns 0 for no error, otherwise a negative error code (in which case
+ * the enqueue() method must fail).  If no error occurs but enqueue() fails
+ * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing
+ * the private spinlock and returning.
+ */
+int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb)
 {
-       unsigned long           flags;
+       int             rc = 0;
 
-       /* clear all state linking urb to this dev (and hcd) */
-       spin_lock_irqsave(&hcd_urb_list_lock, flags);
-       list_del_init (&urb->urb_list);
-       spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
+       spin_lock(&hcd_urb_list_lock);
 
-       if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
-               if (usb_pipecontrol (urb->pipe)
-                       && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
-                       dma_unmap_single (hcd->self.controller, urb->setup_dma,
-                                       sizeof (struct usb_ctrlrequest),
-                                       DMA_TO_DEVICE);
-               if (urb->transfer_buffer_length != 0
-                       && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
-                       dma_unmap_single (hcd->self.controller,
-                                       urb->transfer_dma,
-                                       urb->transfer_buffer_length,
-                                       usb_pipein (urb->pipe)
-                                           ? DMA_FROM_DEVICE
-                                           : DMA_TO_DEVICE);
+       /* Check that the URB isn't being killed */
+       if (unlikely(urb->reject)) {
+               rc = -EPERM;
+               goto done;
        }
-}
-
-/* may be called in any context with a valid urb->dev usecount
- * caller surrenders "ownership" of urb
- * expects usb_submit_urb() to have sanity checked and conditioned all
- * inputs in the urb
- */
-int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
-{
-       int                     status;
-       struct usb_hcd          *hcd = bus_to_hcd(urb->dev->bus);
-       struct usb_host_endpoint *ep;
-       unsigned long           flags;
 
-       if (!hcd)
-               return -ENODEV;
+       if (unlikely(!urb->ep->enabled)) {
+               rc = -ENOENT;
+               goto done;
+       }
 
-       usbmon_urb_submit(&hcd->self, urb);
+       if (unlikely(!urb->dev->can_submit)) {
+               rc = -EHOSTUNREACH;
+               goto done;
+       }
 
        /*
-        * Atomically queue the urb,  first to our records, then to the HCD.
-        * Access to urb->status is controlled by urb->lock ... changes on
-        * i/o completion (normal or fault) or unlinking.
+        * Check the host controller's state and add the URB to the
+        * endpoint's queue.
         */
-
-       // FIXME:  verify that quiescing hc works right (RH cleans up)
-
-       spin_lock_irqsave(&hcd_urb_list_lock, flags);
-       ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
-                       [usb_pipeendpoint(urb->pipe)];
-       if (unlikely (!ep))
-               status = -ENOENT;
-       else if (unlikely (urb->reject))
-               status = -EPERM;
-       else switch (hcd->state) {
+       switch (hcd->state) {
        case HC_STATE_RUNNING:
        case HC_STATE_RESUMING:
-               list_add_tail (&urb->urb_list, &ep->urb_list);
-               status = 0;
+               urb->unlinked = 0;
+               list_add_tail(&urb->urb_list, &urb->ep->urb_list);
                break;
        default:
-               status = -ESHUTDOWN;
-               break;
+               rc = -ESHUTDOWN;
+               goto done;
        }
-       spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
-       if (status) {
-               INIT_LIST_HEAD (&urb->urb_list);
-               usbmon_urb_submit_error(&hcd->self, urb, status);
-               return status;
+ done:
+       spin_unlock(&hcd_urb_list_lock);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep);
+
+/**
+ * usb_hcd_check_unlink_urb - check whether an URB may be unlinked
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being checked for unlinkability
+ * @status: error code to store in @urb if the unlink succeeds
+ *
+ * Host controller drivers should call this routine in their dequeue()
+ * method.  The HCD's private spinlock must be held and interrupts must
+ * be disabled.  The actions carried out here are required for making
+ * sure than an unlink is valid.
+ *
+ * Returns 0 for no error, otherwise a negative error code (in which case
+ * the dequeue() method must fail).  The possible error codes are:
+ *
+ *     -EIDRM: @urb was not submitted or has already completed.
+ *             The completion function may not have been called yet.
+ *
+ *     -EBUSY: @urb has already been unlinked.
+ */
+int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
+               int status)
+{
+       struct list_head        *tmp;
+
+       /* insist the urb is still queued */
+       list_for_each(tmp, &urb->ep->urb_list) {
+               if (tmp == &urb->urb_list)
+                       break;
        }
+       if (tmp != &urb->urb_list)
+               return -EIDRM;
 
-       /* increment urb's reference count as part of giving it to the HCD
-        * (which now controls it).  HCD guarantees that it either returns
-        * an error or calls giveback(), but not both.
+       /* Any status except -EINPROGRESS means something already started to
+        * unlink this URB from the hardware.  So there's no more work to do.
         */
-       urb = usb_get_urb (urb);
-       atomic_inc (&urb->use_count);
-
-       if (is_root_hub(urb->dev)) {
-               /* NOTE:  requirement on hub callers (usbfs and the hub
-                * driver, for now) that URBs' urb->transfer_buffer be
-                * valid and usb_buffer_{sync,unmap}() not be needed, since
-                * they could clobber root hub response data.
-                */
-               status = rh_urb_enqueue (hcd, urb);
-               goto done;
+       if (urb->unlinked)
+               return -EBUSY;
+       urb->unlinked = status;
+
+       /* IRQ setup can easily be broken so that USB controllers
+        * never get completion IRQs ... maybe even the ones we need to
+        * finish unlinking the initial failed usb_set_address()
+        * or device descriptor fetch.
+        */
+       if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
+                       !is_root_hub(urb->dev)) {
+               dev_warn(hcd->self.controller, "Unlink after no-IRQ?  "
+                       "Controller is probably using the wrong IRQ.\n");
+               set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
        }
 
-       /* lower level hcd code should use *_dma exclusively,
+       return 0;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb);
+
+/**
+ * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being unlinked
+ *
+ * Host controller drivers should call this routine before calling
+ * usb_hcd_giveback_urb().  The HCD's private spinlock must be held and
+ * interrupts must be disabled.  The actions carried out here are required
+ * for URB completion.
+ */
+void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb)
+{
+       /* clear all state linking urb to this dev (and hcd) */
+       spin_lock(&hcd_urb_list_lock);
+       list_del_init(&urb->urb_list);
+       spin_unlock(&hcd_urb_list_lock);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
+
+static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+       /* Map the URB's buffers for DMA access.
+        * Lower level HCD code should use *_dma exclusively,
         * unless it uses pio or talks to another transport.
         */
-       if (hcd->self.uses_dma) {
-               if (usb_pipecontrol (urb->pipe)
+       if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+               if (usb_endpoint_xfer_control(&urb->ep->desc)
                        && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
                        urb->setup_dma = dma_map_single (
                                        hcd->self.controller,
@@ -1017,20 +1133,75 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
                                        hcd->self.controller,
                                        urb->transfer_buffer,
                                        urb->transfer_buffer_length,
-                                       usb_pipein (urb->pipe)
+                                       usb_urb_dir_in(urb)
                                            ? DMA_FROM_DEVICE
                                            : DMA_TO_DEVICE);
        }
+}
 
-       status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags);
-done:
-       if (unlikely (status)) {
-               urb_unlink(hcd, urb);
-               atomic_dec (&urb->use_count);
-               if (urb->reject)
-                       wake_up (&usb_kill_urb_queue);
+static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+       if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+               if (usb_endpoint_xfer_control(&urb->ep->desc)
+                       && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+                       dma_unmap_single(hcd->self.controller, urb->setup_dma,
+                                       sizeof(struct usb_ctrlrequest),
+                                       DMA_TO_DEVICE);
+               if (urb->transfer_buffer_length != 0
+                       && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+                       dma_unmap_single(hcd->self.controller,
+                                       urb->transfer_dma,
+                                       urb->transfer_buffer_length,
+                                       usb_urb_dir_in(urb)
+                                           ? DMA_FROM_DEVICE
+                                           : DMA_TO_DEVICE);
+       }
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* may be called in any context with a valid urb->dev usecount
+ * caller surrenders "ownership" of urb
+ * expects usb_submit_urb() to have sanity checked and conditioned all
+ * inputs in the urb
+ */
+int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
+{
+       int                     status;
+       struct usb_hcd          *hcd = bus_to_hcd(urb->dev->bus);
+
+       /* increment urb's reference count as part of giving it to the HCD
+        * (which will control it).  HCD guarantees that it either returns
+        * an error or calls giveback(), but not both.
+        */
+       usb_get_urb(urb);
+       atomic_inc(&urb->use_count);
+       atomic_inc(&urb->dev->urbnum);
+       usbmon_urb_submit(&hcd->self, urb);
+
+       /* NOTE requirements on root-hub callers (usbfs and the hub
+        * driver, for now):  URBs' urb->transfer_buffer must be
+        * valid and usb_buffer_{sync,unmap}() not be needed, since
+        * they could clobber root hub response data.  Also, control
+        * URBs must be submitted in process context with interrupts
+        * enabled.
+        */
+       map_urb_for_dma(hcd, urb);
+       if (is_root_hub(urb->dev))
+               status = rh_urb_enqueue(hcd, urb);
+       else
+               status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
+
+       if (unlikely(status)) {
                usbmon_urb_submit_error(&hcd->self, urb, status);
-               usb_put_urb (urb);
+               unmap_urb_for_dma(hcd, urb);
+               urb->hcpriv = NULL;
+               INIT_LIST_HEAD(&urb->urb_list);
+               atomic_dec(&urb->use_count);
+               atomic_dec(&urb->dev->urbnum);
+               if (urb->reject)
+                       wake_up(&usb_kill_urb_queue);
+               usb_put_urb(urb);
        }
        return status;
 }
@@ -1042,24 +1213,19 @@ done:
  * soon as practical.  we've already set up the urb's return status,
  * but we can't know if the callback completed already.
  */
-static int
-unlink1 (struct usb_hcd *hcd, struct urb *urb)
+static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status)
 {
        int             value;
 
        if (is_root_hub(urb->dev))
-               value = usb_rh_urb_dequeue (hcd, urb);
+               value = usb_rh_urb_dequeue(hcd, urb, status);
        else {
 
                /* The only reason an HCD might fail this call is if
                 * it has not yet fully queued the urb to begin with.
                 * Such failures should be harmless. */
-               value = hcd->driver->urb_dequeue (hcd, urb);
+               value = hcd->driver->urb_dequeue(hcd, urb, status);
        }
-
-       if (value != 0)
-               dev_dbg (hcd->self.controller, "dequeue %p --> %d\n",
-                               urb, value);
        return value;
 }
 
@@ -1071,88 +1237,17 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb)
  */
 int usb_hcd_unlink_urb (struct urb *urb, int status)
 {
-       struct usb_host_endpoint        *ep;
-       struct usb_hcd                  *hcd = NULL;
-       struct device                   *sys = NULL;
-       unsigned long                   flags;
-       struct list_head                *tmp;
-       int                             retval;
-
-       if (!urb)
-               return -EINVAL;
-       if (!urb->dev || !urb->dev->bus)
-               return -ENODEV;
-       ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
-                       [usb_pipeendpoint(urb->pipe)];
-       if (!ep)
-               return -ENODEV;
-
-       /*
-        * we contend for urb->status with the hcd core,
-        * which changes it while returning the urb.
-        *
-        * Caller guaranteed that the urb pointer hasn't been freed, and
-        * that it was submitted.  But as a rule it can't know whether or
-        * not it's already been unlinked ... so we respect the reversed
-        * lock sequence needed for the usb_hcd_giveback_urb() code paths
-        * (urb lock, then hcd_urb_list_lock) in case some other CPU is now
-        * unlinking it.
-        */
-       spin_lock_irqsave (&urb->lock, flags);
-       spin_lock(&hcd_urb_list_lock);
+       struct usb_hcd          *hcd;
+       int                     retval;
 
-       sys = &urb->dev->dev;
        hcd = bus_to_hcd(urb->dev->bus);
-       if (hcd == NULL) {
-               retval = -ENODEV;
-               goto done;
-       }
+       retval = unlink1(hcd, urb, status);
 
-       /* insist the urb is still queued */
-       list_for_each(tmp, &ep->urb_list) {
-               if (tmp == &urb->urb_list)
-                       break;
-       }
-       if (tmp != &urb->urb_list) {
-               retval = -EIDRM;
-               goto done;
-       }
-
-       /* Any status except -EINPROGRESS means something already started to
-        * unlink this URB from the hardware.  So there's no more work to do.
-        */
-       if (urb->status != -EINPROGRESS) {
-               retval = -EBUSY;
-               goto done;
-       }
-
-       /* IRQ setup can easily be broken so that USB controllers
-        * never get completion IRQs ... maybe even the ones we need to
-        * finish unlinking the initial failed usb_set_address()
-        * or device descriptor fetch.
-        */
-       if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
-                       !is_root_hub(urb->dev)) {
-               dev_warn (hcd->self.controller, "Unlink after no-IRQ?  "
-                       "Controller is probably using the wrong IRQ.\n");
-               set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
-       }
-
-       urb->status = status;
-
-       spin_unlock(&hcd_urb_list_lock);
-       spin_unlock_irqrestore (&urb->lock, flags);
-
-       retval = unlink1 (hcd, urb);
        if (retval == 0)
                retval = -EINPROGRESS;
-       return retval;
-
-done:
-       spin_unlock(&hcd_urb_list_lock);
-       spin_unlock_irqrestore (&urb->lock, flags);
-       if (retval != -EIDRM && sys && sys->driver)
-               dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
+       else if (retval != -EIDRM && retval != -EBUSY)
+               dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n",
+                               urb, retval);
        return retval;
 }
 
@@ -1162,6 +1257,7 @@ done:
  * usb_hcd_giveback_urb - return URB from HCD to device driver
  * @hcd: host controller returning the URB
  * @urb: urb being returned to the USB device driver.
+ * @status: completion status code for the URB.
  * Context: in_interrupt()
  *
  * This hands the URB from HCD to its USB device driver, using its
@@ -1169,14 +1265,27 @@ done:
  * (and is done using urb->hcpriv).  It also released all HCD locks;
  * the device driver won't cause problems if it frees, modifies,
  * or resubmits this URB.
+ *
+ * If @urb was unlinked, the value of @status will be overridden by
+ * @urb->unlinked.  Erroneous short transfers are detected in case
+ * the HCD hasn't checked for them.
  */
-void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
+void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
 {
-       urb_unlink(hcd, urb);
-       usbmon_urb_complete (&hcd->self, urb);
+       urb->hcpriv = NULL;
+       if (unlikely(urb->unlinked))
+               status = urb->unlinked;
+       else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+                       urb->actual_length < urb->transfer_buffer_length &&
+                       !status))
+               status = -EREMOTEIO;
+
+       unmap_urb_for_dma(hcd, urb);
+       usbmon_urb_complete(&hcd->self, urb, status);
        usb_unanchor_urb(urb);
 
        /* pass ownership to the completion handler */
+       urb->status = status;
        urb->complete (urb);
        atomic_dec (&urb->use_count);
        if (unlikely (urb->reject))
@@ -1187,78 +1296,61 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb);
 
 /*-------------------------------------------------------------------------*/
 
-/* disables the endpoint: cancels any pending urbs, then synchronizes with
- * the hcd to make sure all endpoint state is gone from hardware, and then
- * waits until the endpoint's queue is completely drained. use for
- * set_configuration, set_interface, driver removal, physical disconnect.
- *
- * example:  a qh stored in ep->hcpriv, holding state related to endpoint
- * type, maxpacket size, toggle, halt status, and scheduling.
+/* Cancel all URBs pending on this endpoint and wait for the endpoint's
+ * queue to drain completely.  The caller must first insure that no more
+ * URBs can be submitted for this endpoint.
  */
-void usb_hcd_endpoint_disable (struct usb_device *udev,
+void usb_hcd_flush_endpoint(struct usb_device *udev,
                struct usb_host_endpoint *ep)
 {
        struct usb_hcd          *hcd;
        struct urb              *urb;
 
+       if (!ep)
+               return;
+       might_sleep();
        hcd = bus_to_hcd(udev->bus);
-       local_irq_disable ();
 
-       /* ep is already gone from udev->ep_{in,out}[]; no more submits */
+       /* No more submits can occur */
 rescan:
-       spin_lock(&hcd_urb_list_lock);
+       spin_lock_irq(&hcd_urb_list_lock);
        list_for_each_entry (urb, &ep->urb_list, urb_list) {
-               int     tmp;
+               int     is_in;
 
-               /* the urb may already have been unlinked */
-               if (urb->status != -EINPROGRESS)
+               if (urb->unlinked)
                        continue;
                usb_get_urb (urb);
+               is_in = usb_urb_dir_in(urb);
                spin_unlock(&hcd_urb_list_lock);
 
-               spin_lock (&urb->lock);
-               tmp = urb->status;
-               if (tmp == -EINPROGRESS)
-                       urb->status = -ESHUTDOWN;
-               spin_unlock (&urb->lock);
-
-               /* kick hcd unless it's already returning this */
-               if (tmp == -EINPROGRESS) {
-                       tmp = urb->pipe;
-                       unlink1 (hcd, urb);
-                       dev_dbg (hcd->self.controller,
-                               "shutdown urb %p pipe %08x ep%d%s%s\n",
-                               urb, tmp, usb_pipeendpoint (tmp),
-                               (tmp & USB_DIR_IN) ? "in" : "out",
-                               ({ char *s; \
-                                switch (usb_pipetype (tmp)) { \
-                                case PIPE_CONTROL:     s = ""; break; \
-                                case PIPE_BULK:        s = "-bulk"; break; \
-                                case PIPE_INTERRUPT:   s = "-intr"; break; \
-                                default:               s = "-iso"; break; \
-                               }; s;}));
-               }
+               /* kick hcd */
+               unlink1(hcd, urb, -ESHUTDOWN);
+               dev_dbg (hcd->self.controller,
+                       "shutdown urb %p ep%d%s%s\n",
+                       urb, usb_endpoint_num(&ep->desc),
+                       is_in ? "in" : "out",
+                       ({      char *s;
+
+                                switch (usb_endpoint_type(&ep->desc)) {
+                                case USB_ENDPOINT_XFER_CONTROL:
+                                       s = ""; break;
+                                case USB_ENDPOINT_XFER_BULK:
+                                       s = "-bulk"; break;
+                                case USB_ENDPOINT_XFER_INT:
+                                       s = "-intr"; break;
+                                default:
+                                       s = "-iso"; break;
+                               };
+                               s;
+                       }));
                usb_put_urb (urb);
 
                /* list contents may have changed */
                goto rescan;
        }
-       spin_unlock(&hcd_urb_list_lock);
-       local_irq_enable ();
-
-       /* synchronize with the hardware, so old configuration state
-        * clears out immediately (and will be freed).
-        */
-       might_sleep ();
-       if (hcd->driver->endpoint_disable)
-               hcd->driver->endpoint_disable (hcd, ep);
+       spin_unlock_irq(&hcd_urb_list_lock);
 
-       /* Wait until the endpoint queue is completely empty.  Most HCDs
-        * will have done this already in their endpoint_disable method,
-        * but some might not.  And there could be root-hub control URBs
-        * still pending since they aren't affected by the HCDs'
-        * endpoint_disable methods.
-        */
+       /* Wait until the endpoint queue is completely empty */
        while (!list_empty (&ep->urb_list)) {
                spin_lock_irq(&hcd_urb_list_lock);
 
@@ -1278,6 +1370,25 @@ rescan:
        }
 }
 
+/* Disables the endpoint: synchronizes with the hcd to make sure all
+ * endpoint state is gone from hardware.  usb_hcd_flush_endpoint() must
+ * have been called previously.  Use for set_configuration, set_interface,
+ * driver removal, physical disconnect.
+ *
+ * example:  a qh stored in ep->hcpriv, holding state related to endpoint
+ * type, maxpacket size, toggle, halt status, and scheduling.
+ */
+void usb_hcd_disable_endpoint(struct usb_device *udev,
+               struct usb_host_endpoint *ep)
+{
+       struct usb_hcd          *hcd;
+
+       might_sleep();
+       hcd = bus_to_hcd(udev->bus);
+       if (hcd->driver->endpoint_disable)
+               hcd->driver->endpoint_disable(hcd, ep);
+}
+
 /*-------------------------------------------------------------------------*/
 
 /* called in any context */
@@ -1525,7 +1636,6 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
        hcd->driver = driver;
        hcd->product_desc = (driver->product_desc) ? driver->product_desc :
                        "USB Host Controller";
-
        return hcd;
 }
 EXPORT_SYMBOL (usb_create_hcd);
@@ -1570,6 +1680,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
 
        dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
 
+       hcd->authorized_default = hcd->wireless? 0 : 1;
        set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 
        /* HC is in reset state, but accessible.  Now do the one-time init,
@@ -1646,10 +1757,20 @@ int usb_add_hcd(struct usb_hcd *hcd,
        if ((retval = register_root_hub(hcd)) != 0)
                goto err_register_root_hub;
 
+       retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);
+       if (retval < 0) {
+               printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n",
+                      retval);
+               goto error_create_attr_group;
+       }
        if (hcd->uses_new_polling && hcd->poll_rh)
                usb_hcd_poll_rh_status(hcd);
        return retval;
 
+error_create_attr_group:
+       mutex_lock(&usb_bus_list_lock);
+       usb_disconnect(&hcd->self.root_hub);
+       mutex_unlock(&usb_bus_list_lock);
 err_register_root_hub:
        hcd->driver->stop(hcd);
 err_hcd_driver_start:
@@ -1691,6 +1812,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
        cancel_work_sync(&hcd->wakeup_work);
 #endif
 
+       sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group);
        mutex_lock(&usb_bus_list_lock);
        usb_disconnect(&hcd->self.root_hub);
        mutex_unlock(&usb_bus_list_lock);
index b5ebb73..98e2419 100644 (file)
@@ -19,6 +19,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/rwsem.h>
+
 /* This file contains declarations of usbcore internals that are mostly
  * used or exposed by Host Controller Drivers.
  */
  *
  * Since "struct usb_bus" is so thin, you can't share much code in it.
  * This framework is a layer over that, and should be more sharable.
+ *
+ * @authorized_default: Specifies if new devices are authorized to
+ *                      connect by default or they require explicit
+ *                      user space authorization; this bit is settable
+ *                      through /sys/class/usb_host/X/authorized_default.
+ *                      For the rest is RO, so we don't lock to r/w it.
  */
 
 /*-------------------------------------------------------------------------*/
@@ -90,6 +98,7 @@ struct usb_hcd {
        unsigned                poll_rh:1;      /* poll for rh status? */
        unsigned                poll_pending:1; /* status has changed? */
        unsigned                wireless:1;     /* Wireless USB HCD */
+       unsigned                authorized_default:1;
 
        int                     irq;            /* irq allocated */
        void __iomem            *regs;          /* device memory/io */
@@ -182,11 +191,10 @@ struct hc_driver {
        int     (*get_frame_number) (struct usb_hcd *hcd);
 
        /* manage i/o requests, device state */
-       int     (*urb_enqueue) (struct usb_hcd *hcd,
-                                       struct usb_host_endpoint *ep,
-                                       struct urb *urb,
-                                       gfp_t mem_flags);
-       int     (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
+       int     (*urb_enqueue)(struct usb_hcd *hcd,
+                               struct urb *urb, gfp_t mem_flags);
+       int     (*urb_dequeue)(struct usb_hcd *hcd,
+                               struct urb *urb, int status);
 
        /* hw synch, freeing endpoint resources that urb_dequeue can't */
        void    (*endpoint_disable)(struct usb_hcd *hcd,
@@ -204,10 +212,18 @@ struct hc_driver {
                /* Needed only if port-change IRQs are level-triggered */
 };
 
+extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
+extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
+               int status);
+extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb);
+
 extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
 extern int usb_hcd_unlink_urb (struct urb *urb, int status);
-extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
-extern void usb_hcd_endpoint_disable (struct usb_device *udev,
+extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb,
+               int status);
+extern void usb_hcd_flush_endpoint(struct usb_device *udev,
+               struct usb_host_endpoint *ep);
+extern void usb_hcd_disable_endpoint(struct usb_device *udev,
                struct usb_host_endpoint *ep);
 extern int usb_hcd_get_frame_number (struct usb_device *udev);
 
@@ -402,7 +418,7 @@ static inline void usbfs_cleanup(void) { }
 struct usb_mon_operations {
        void (*urb_submit)(struct usb_bus *bus, struct urb *urb);
        void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err);
-       void (*urb_complete)(struct usb_bus *bus, struct urb *urb);
+       void (*urb_complete)(struct usb_bus *bus, struct urb *urb, int status);
        /* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */
 };
 
@@ -421,10 +437,11 @@ static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
                (*mon_ops->urb_submit_error)(bus, urb, error);
 }
 
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb)
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
+               int status)
 {
        if (bus->monitored)
-               (*mon_ops->urb_complete)(bus, urb);
+               (*mon_ops->urb_complete)(bus, urb, status);
 }
 
 int usb_mon_register(struct usb_mon_operations *ops);
@@ -435,7 +452,8 @@ void usb_mon_deregister(void);
 static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {}
 static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
     int error) {}
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
+               int status) {}
 
 #endif /* CONFIG_USB_MON */
 
@@ -454,5 +472,9 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
                : (in_interrupt () ? "in_interrupt" : "can sleep"))
 
 
-#endif /* __KERNEL__ */
+/* This rwsem is for use only by the hub driver and ehci-hcd.
+ * Nobody else should touch it.
+ */
+extern struct rw_semaphore ehci_cf_port_reset_rwsem;
 
+#endif /* __KERNEL__ */
index f7b337f..d20cb54 100644 (file)
@@ -125,6 +125,12 @@ MODULE_PARM_DESC(use_both_schemes,
                "try the other device initialization scheme if the "
                "first one fails");
 
+/* Mutual exclusion for EHCI CF initialization.  This interferes with
+ * port reset on some companion controllers.
+ */
+DECLARE_RWSEM(ehci_cf_port_reset_rwsem);
+EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
+
 
 static inline char *portspeed(int portstatus)
 {
@@ -347,11 +353,11 @@ void usb_kick_khubd(struct usb_device *hdev)
 static void hub_irq(struct urb *urb)
 {
        struct usb_hub *hub = urb->context;
-       int status;
+       int status = urb->status;
        int i;
        unsigned long bits;
 
-       switch (urb->status) {
+       switch (status) {
        case -ENOENT:           /* synchronous unlink */
        case -ECONNRESET:       /* async unlink */
        case -ESHUTDOWN:        /* hardware going away */
@@ -359,10 +365,10 @@ static void hub_irq(struct urb *urb)
 
        default:                /* presumably an error */
                /* Cause a hub reset after 10 consecutive errors */
-               dev_dbg (hub->intfdev, "transfer --> %d\n", urb->status);
+               dev_dbg (hub->intfdev, "transfer --> %d\n", status);
                if ((++hub->nerrors < 10) || hub->error)
                        goto resubmit;
-               hub->error = urb->status;
+               hub->error = status;
                /* FALL THROUGH */
 
        /* let khubd handle things */
@@ -1220,54 +1226,14 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
 #endif
 
 /**
- * usb_new_device - perform initial device setup (usbcore-internal)
+ * usb_configure_device_otg - FIXME (usbcore-internal)
  * @udev: newly addressed device (in ADDRESS state)
  *
- * 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 must have locked either
- * the parent hub (if udev is a normal device) or else the
- * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
- * udev has already been installed, but udev is not yet visible through
- * sysfs or other filesystem code.
- *
- * It will return if the device is configured properly or not.  Zero if
- * the interface was registered with the driver core; else a negative
- * errno value.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver or root-hub registrar should ever call this.
+ * Do configuration for On-The-Go devices
  */
-int usb_new_device(struct usb_device *udev)
+static int usb_configure_device_otg(struct usb_device *udev)
 {
-       int err;
-
-       /* Determine quirks */
-       usb_detect_quirks(udev);
-
-       err = usb_get_configuration(udev);
-       if (err < 0) {
-               dev_err(&udev->dev, "can't read configurations, error %d\n",
-                       err);
-               goto fail;
-       }
-
-       /* read the standard strings and cache them if present */
-       udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
-       udev->manufacturer = usb_cache_string(udev,
-                       udev->descriptor.iManufacturer);
-       udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
-
-       /* Tell the world! */
-       dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
-                       "SerialNumber=%d\n",
-                       udev->descriptor.iManufacturer,
-                       udev->descriptor.iProduct,
-                       udev->descriptor.iSerialNumber);
-       show_string(udev, "Product", udev->product);
-       show_string(udev, "Manufacturer", udev->manufacturer);
-       show_string(udev, "SerialNumber", udev->serial);
+       int err = 0;
 
 #ifdef CONFIG_USB_OTG
        /*
@@ -1329,8 +1295,82 @@ int usb_new_device(struct usb_device *udev)
                err = -ENOTSUPP;
                goto fail;
        }
+fail:
 #endif
+       return err;
+}
+
+
+/**
+ * usb_configure_device - Detect and probe device intfs/otg (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is only called by usb_new_device() and usb_authorize_device()
+ * and FIXME -- all comments that apply to them apply here wrt to
+ * environment.
+ *
+ * If the device is WUSB and not authorized, we don't attempt to read
+ * the string descriptors, as they will be errored out by the device
+ * until it has been authorized.
+ */
+static int usb_configure_device(struct usb_device *udev)
+{
+       int err;
 
+       if (udev->config == NULL) {
+               err = usb_get_configuration(udev);
+               if (err < 0) {
+                       dev_err(&udev->dev, "can't read configurations, error %d\n",
+                               err);
+                       goto fail;
+               }
+       }
+       if (udev->wusb == 1 && udev->authorized == 0) {
+               udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+               udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+               udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+       }
+       else {
+               /* read the standard strings and cache them if present */
+               udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
+               udev->manufacturer = usb_cache_string(udev,
+                                                     udev->descriptor.iManufacturer);
+               udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
+       }
+       err = usb_configure_device_otg(udev);
+fail:
+       return err;
+}
+
+
+/**
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * 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 must have locked either
+ * the parent hub (if udev is a normal device) or else the
+ * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
+ *
+ * It will return if the device is configured properly or not.  Zero if
+ * the interface was registered with the driver core; else a negative
+ * errno value.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver or root-hub registrar should ever call this.
+ */
+int usb_new_device(struct usb_device *udev)
+{
+       int err;
+
+       usb_detect_quirks(udev);                /* Determine quirks */
+       err = usb_configure_device(udev);       /* detect & probe dev/intfs */
+       if (err < 0)
+               goto fail;
        /* export the usbdev device-node for libusb */
        udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
                        (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
@@ -1346,19 +1386,106 @@ int usb_new_device(struct usb_device *udev)
        err = device_add(&udev->dev);
        if (err) {
                dev_err(&udev->dev, "can't device_add, error %d\n", err);
-               if (udev->parent)
-                       usb_autosuspend_device(udev->parent);
                goto fail;
        }
 
-exit:
+       /* Tell the world! */
+       dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
+               "SerialNumber=%d\n",
+               udev->descriptor.iManufacturer,
+               udev->descriptor.iProduct,
+               udev->descriptor.iSerialNumber);
+       show_string(udev, "Product", udev->product);
+       show_string(udev, "Manufacturer", udev->manufacturer);
+       show_string(udev, "SerialNumber", udev->serial);
        return err;
 
 fail:
        usb_set_device_state(udev, USB_STATE_NOTATTACHED);
-       goto exit;
+       return err;
 }
 
+
+/**
+ * Similar to usb_disconnect()
+ *
+ * We share a lock (that we have) with device_del(), so we need to
+ * defer its call.
+ */
+int usb_deauthorize_device(struct usb_device *usb_dev)
+{
+       unsigned cnt;
+       usb_lock_device(usb_dev);
+       if (usb_dev->authorized == 0)
+               goto out_unauthorized;
+       usb_dev->authorized = 0;
+       usb_set_configuration(usb_dev, -1);
+       usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+       usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+       usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+       kfree(usb_dev->config);
+       usb_dev->config = NULL;
+       for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++)
+               kfree(usb_dev->rawdescriptors[cnt]);
+       usb_dev->descriptor.bNumConfigurations = 0;
+       kfree(usb_dev->rawdescriptors);
+out_unauthorized:
+       usb_unlock_device(usb_dev);
+       return 0;
+}
+
+
+int usb_authorize_device(struct usb_device *usb_dev)
+{
+       int result = 0, c;
+       usb_lock_device(usb_dev);
+       if (usb_dev->authorized == 1)
+               goto out_authorized;
+       kfree(usb_dev->product);
+       usb_dev->product = NULL;
+       kfree(usb_dev->manufacturer);
+       usb_dev->manufacturer = NULL;
+       kfree(usb_dev->serial);
+       usb_dev->serial = NULL;
+       result = usb_autoresume_device(usb_dev);
+       if (result < 0) {
+               dev_err(&usb_dev->dev,
+                       "can't autoresume for authorization: %d\n", result);
+               goto error_autoresume;
+       }
+       result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
+       if (result < 0) {
+               dev_err(&usb_dev->dev, "can't re-read device descriptor for "
+                       "authorization: %d\n", result);
+               goto error_device_descriptor;
+       }
+       usb_dev->authorized = 1;
+       result = usb_configure_device(usb_dev);
+       if (result < 0)
+               goto error_configure;
+       /* Choose and set the configuration.  This registers the interfaces
+        * with the driver core and lets interface drivers bind to them.
+        */
+       c = usb_choose_configuration(usb_dev);
+       if (c >= 0) {
+               result = usb_set_configuration(usb_dev, c);
+               if (result) {
+                       dev_err(&usb_dev->dev,
+                               "can't set config #%d, error %d\n", c, result);
+                       /* This need not be fatal.  The user can try to
+                        * set other configurations. */
+               }
+       }
+       dev_info(&usb_dev->dev, "authorized to connect\n");
+error_configure:
+error_device_descriptor:
+error_autoresume:
+out_authorized:
+       usb_unlock_device(usb_dev);     // complements locktree
+       return result;
+}
+
+
 static int hub_port_status(struct usb_hub *hub, int port1,
                               u16 *status, u16 *change)
 {
@@ -1460,6 +1587,11 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 {
        int i, status;
 
+       /* Block EHCI CF initialization during the port reset.
+        * Some companion controllers don't like it when they mix.
+        */
+       down_read(&ehci_cf_port_reset_rwsem);
+
        /* Reset the port */
        for (i = 0; i < PORT_RESET_TRIES; i++) {
                status = set_port_feature(hub->hdev,
@@ -1481,6 +1613,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
                case 0:
                        /* TRSTRCY = 10 ms; plus some extra */
                        msleep(10 + 40);
+                       udev->devnum = 0;       /* Device now at address 0 */
                        /* FALL THROUGH */
                case -ENOTCONN:
                case -ENODEV:
@@ -1490,7 +1623,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
                        usb_set_device_state(udev, status
                                        ? USB_STATE_NOTATTACHED
                                        : USB_STATE_DEFAULT);
-                       return status;
+                       goto done;
                }
 
                dev_dbg (hub->intfdev,
@@ -1503,6 +1636,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
                "Cannot enable port %i.  Maybe the USB cable is bad?\n",
                port1);
 
+ done:
+       up_read(&ehci_cf_port_reset_rwsem);
        return status;
 }
 
@@ -1833,14 +1968,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
                struct usb_device       *udev;
 
                udev = hdev->children [port1-1];
-               if (udev && msg.event == PM_EVENT_SUSPEND &&
-#ifdef CONFIG_USB_SUSPEND
-                               udev->state != USB_STATE_SUSPENDED
-#else
-                               udev->dev.power.power_state.event
-                                       == PM_EVENT_ON
-#endif
-                               ) {
+               if (udev && udev->can_submit) {
                        if (!hdev->auto_pm)
                                dev_dbg(&intf->dev, "port %d nyet suspended\n",
                                                port1);
@@ -1999,26 +2127,27 @@ static void ep0_reinit(struct usb_device *udev)
 {
        usb_disable_endpoint(udev, 0 + USB_DIR_IN);
        usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
-       udev->ep_in[0] = udev->ep_out[0] = &udev->ep0;
+       usb_enable_endpoint(udev, &udev->ep0);
 }
 
 #define usb_sndaddr0pipe()     (PIPE_CONTROL << 30)
 #define usb_rcvaddr0pipe()     ((PIPE_CONTROL << 30) | USB_DIR_IN)
 
-static int hub_set_address(struct usb_device *udev)
+static int hub_set_address(struct usb_device *udev, int devnum)
 {
        int retval;
 
-       if (udev->devnum == 0)
+       if (devnum <= 1)
                return -EINVAL;
        if (udev->state == USB_STATE_ADDRESS)
                return 0;
        if (udev->state != USB_STATE_DEFAULT)
                return -EINVAL;
        retval = usb_control_msg(udev, usb_sndaddr0pipe(),
-               USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
+               USB_REQ_SET_ADDRESS, 0, devnum, 0,
                NULL, 0, USB_CTRL_SET_TIMEOUT);
        if (retval == 0) {
+               udev->devnum = devnum;  /* Device now using proper address */
                usb_set_device_state(udev, USB_STATE_ADDRESS);
                ep0_reinit(udev);
        }
@@ -2045,6 +2174,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
        unsigned                delay = HUB_SHORT_RESET_TIME;
        enum usb_device_speed   oldspeed = udev->speed;
        char                    *speed, *type;
+       int                     devnum = udev->devnum;
 
        /* root hub ports have a slightly longer reset period
         * (from USB 2.0 spec, section 7.1.7.5)
@@ -2074,7 +2204,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
                goto fail;
        }
        oldspeed = udev->speed;
-  
+
        /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
         * it's fixed size except for full speed devices.
         * For Wireless USB devices, ep0 max packet is always 512 (tho
@@ -2115,7 +2245,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
        dev_info (&udev->dev,
                  "%s %s speed %sUSB device using %s and address %d\n",
                  (udev->config) ? "reset" : "new", speed, type,
-                 udev->bus->controller->driver->name, udev->devnum);
+                 udev->bus->controller->driver->name, devnum);
 
        /* Set up TT records, if needed  */
        if (hdev->tt) {
@@ -2202,7 +2332,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
                }
 
                for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
-                       retval = hub_set_address(udev);
+                       retval = hub_set_address(udev, devnum);
                        if (retval >= 0)
                                break;
                        msleep(200);
@@ -2210,7 +2340,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
                if (retval < 0) {
                        dev_err(&udev->dev,
                                "device not accepting address %d, error %d\n",
-                               udev->devnum, retval);
+                               devnum, retval);
                        goto fail;
                }
  
@@ -2263,8 +2393,10 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
        retval = 0;
 
 fail:
-       if (retval)
+       if (retval) {
                hub_port_disable(hub, port1, 0);
+               udev->devnum = devnum;  /* for disconnect processing */
+       }
        mutex_unlock(&usb_address0_mutex);
        return retval;
 }
@@ -2699,9 +2831,9 @@ static void hub_events(void)
                                clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
                                if (hubstatus & HUB_STATUS_LOCAL_POWER)
                                        /* FIXME: Is this always true? */
-                                       hub->limited_power = 0;
-                               else
                                        hub->limited_power = 1;
+                               else
+                                       hub->limited_power = 0;
                        }
                        if (hubchange & HUB_CHANGE_OVERCURRENT) {
                                dev_dbg (hub_dev, "overcurrent change\n");
index d8f7b08..98fcddb 100644 (file)
@@ -59,8 +59,8 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
                dev_dbg(&urb->dev->dev,
                        "%s timed out on ep%d%s len=%d/%d\n",
                        current->comm,
-                       usb_pipeendpoint(urb->pipe),
-                       usb_pipein(urb->pipe) ? "in" : "out",
+                       usb_endpoint_num(&urb->ep->desc),
+                       usb_urb_dir_in(urb) ? "in" : "out",
                        urb->actual_length,
                        urb->transfer_buffer_length);
        } else
@@ -250,7 +250,8 @@ static void sg_clean (struct usb_sg_request *io)
                io->urbs = NULL;
        }
        if (io->dev->dev.dma_mask != NULL)
-               usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
+               usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe),
+                               io->sg, io->nents);
        io->dev = NULL;
 }
 
@@ -278,8 +279,8 @@ static void sg_complete (struct urb *urb)
                dev_err (io->dev->bus->controller,
                        "dev %s ep%d%s scatterlist error %d/%d\n",
                        io->dev->devpath,
-                       usb_pipeendpoint (urb->pipe),
-                       usb_pipein (urb->pipe) ? "in" : "out",
+                       usb_endpoint_num(&urb->ep->desc),
+                       usb_urb_dir_in(urb) ? "in" : "out",
                        status, io->status);
                // BUG ();
        }
@@ -379,7 +380,8 @@ int usb_sg_init (
         */
        dma = (dev->dev.dma_mask != NULL);
        if (dma)
-               io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
+               io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
+                               sg, nents);
        else
                io->entries = nents;
 
@@ -1013,8 +1015,11 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr)
                ep = dev->ep_in[epnum];
                dev->ep_in[epnum] = NULL;
        }
-       if (ep && dev->bus)
-               usb_hcd_endpoint_disable(dev, ep);
+       if (ep) {
+               ep->enabled = 0;
+               usb_hcd_flush_endpoint(dev, ep);
+               usb_hcd_disable_endpoint(dev, ep);
+       }
 }
 
 /**
@@ -1096,23 +1101,21 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
  * Resets the endpoint toggle, and sets dev->ep_{in,out} pointers.
  * For control endpoints, both the input and output sides are handled.
  */
-static void
-usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
+void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
 {
-       unsigned int epaddr = ep->desc.bEndpointAddress;
-       unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
-       int is_control;
+       int epnum = usb_endpoint_num(&ep->desc);
+       int is_out = usb_endpoint_dir_out(&ep->desc);
+       int is_control = usb_endpoint_xfer_control(&ep->desc);
 
-       is_control = ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-                       == USB_ENDPOINT_XFER_CONTROL);
-       if (usb_endpoint_out(epaddr) || is_control) {
+       if (is_out || is_control) {
                usb_settoggle(dev, epnum, 1, 0);
                dev->ep_out[epnum] = ep;
        }
-       if (!usb_endpoint_out(epaddr) || is_control) {
+       if (!is_out || is_control) {
                usb_settoggle(dev, epnum, 0, 0);
                dev->ep_in[epnum] = ep;
        }
+       ep->enabled = 1;
 }
 
 /*
@@ -1171,6 +1174,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
        struct usb_host_interface *alt;
        int ret;
        int manual = 0;
+       int changed;
 
        if (dev->state == USB_STATE_SUSPENDED)
                return -EHOSTUNREACH;
@@ -1210,7 +1214,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
         */
 
        /* prevent submissions using previous endpoint settings */
-       if (device_is_registered(&iface->dev))
+       changed = (iface->cur_altsetting != alt);
+       if (changed && device_is_registered(&iface->dev))
                usb_remove_sysfs_intf_files(iface);
        usb_disable_interface(dev, iface);
 
@@ -1247,7 +1252,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
         * (Likewise, EP0 never "halts" on well designed devices.)
         */
        usb_enable_interface(dev, iface);
-       if (device_is_registered(&iface->dev))
+       if (changed && device_is_registered(&iface->dev))
                usb_create_sysfs_intf_files(iface);
 
        return 0;
@@ -1328,7 +1333,7 @@ int usb_reset_configuration(struct usb_device *dev)
        return 0;
 }
 
-void usb_release_interface(struct device *dev)
+static void usb_release_interface(struct device *dev)
 {
        struct usb_interface *intf = to_usb_interface(dev);
        struct usb_interface_cache *intfc =
@@ -1481,6 +1486,9 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
  * channels are available independently; and choosing between open
  * standard device protocols (like CDC) or proprietary ones.
  *
+ * Note that a non-authorized device (dev->authorized == 0) will only
+ * be put in unconfigured mode.
+ *
  * Note that USB has an additional level of device configurability,
  * associated with interfaces.  That configurability is accessed using
  * usb_set_interface().
@@ -1502,7 +1510,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
        struct usb_interface **new_interfaces = NULL;
        int n, nintf;
 
-       if (configuration == -1)
+       if (dev->authorized == 0 || configuration == -1)
                configuration = 0;
        else {
                for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
index ebf3dc2..d42c561 100644 (file)
@@ -32,52 +32,6 @@ static const struct usb_device_id usb_quirk_list[] = {
        { USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME },
        /* HP 5300/5370C scanner */
        { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
-       /* Hewlett-Packard PhotoSmart 720 / PhotoSmart 935 (storage) */
-       { USB_DEVICE(0x03f0, 0x4002), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-       /* SGS Thomson Microelectronics 4in1 card reader */
-       { USB_DEVICE(0x0483, 0x0321), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-       /* Acer Peripherals Inc. (now BenQ Corp.) Prisa 640BU */
-       { USB_DEVICE(0x04a5, 0x207e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Benq S2W 3300U */
-       { USB_DEVICE(0x04a5, 0x20b0), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Canon, Inc. CanoScan N1240U/LiDE30 */
-       { USB_DEVICE(0x04a9, 0x220e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Canon, Inc. CanoScan N650U/N656U */
-       { USB_DEVICE(0x04a9, 0x2206), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Canon, Inc. CanoScan 1220U */
-       { USB_DEVICE(0x04a9, 0x2207), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Canon, Inc. CanoScan N670U/N676U/LiDE 20 */
-       { USB_DEVICE(0x04a9, 0x220d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* old Cannon scanner */
-       { USB_DEVICE(0x04a9, 0x2220), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Seiko Epson Corp. Perfection 1200 */
-       { USB_DEVICE(0x04b8, 0x0104), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Seiko Epson Corp. Perfection 660 */
-       { USB_DEVICE(0x04b8, 0x0114), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Epson Perfection 1260 Photo */
-       { USB_DEVICE(0x04b8, 0x011d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Seiko Epson Corp - Perfection 1670 */
-       { USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* EPSON Perfection 2480 */
-       { USB_DEVICE(0x04b8, 0x0121), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Seiko Epson Corp.*/
-       { USB_DEVICE(0x04b8, 0x0122), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Samsung ML-2010 printer */
-       { USB_DEVICE(0x04e8, 0x326c), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Samsung ML-2510 Series printer */
-       { USB_DEVICE(0x04e8, 0x327e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Elsa MicroLink 56k (V.250) */
-       { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Ultima Electronics Corp.*/
-       { USB_DEVICE(0x05d8, 0x4005), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-       /* Genesys USB-to-IDE */
-       { USB_DEVICE(0x0503, 0x0702), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-       /* USB Graphical LCD - EEH Datalink GmbH */
-       { USB_DEVICE(0x060c, 0x04eb), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
 
        /* INTEL VALUE SSD */
        { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
@@ -85,44 +39,15 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* M-Systems Flash Disk Pioneers */
        { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
 
-       /* Agfa Snapscan1212u */
-       { USB_DEVICE(0x06bd, 0x2061), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Seagate RSS LLC */
-       { USB_DEVICE(0x0bc2, 0x3000), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       /* Umax [hex] Astra 3400U */
-       { USB_DEVICE(0x1606, 0x0060), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
        /* Philips PSC805 audio device */
        { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
 
-       /* Alcor multi-card reader */
-       { USB_DEVICE(0x058f, 0x6366), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-       /* Canon EOS 5D in PC Connection mode */
-       { USB_DEVICE(0x04a9, 0x3101), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-       /* RIM Blackberry */
-       { USB_DEVICE(0x0fca, 0x0001), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       { USB_DEVICE(0x0fca, 0x0004), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-       { USB_DEVICE(0x0fca, 0x0006), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-       /* Apple iPhone */
-       { USB_DEVICE(0x05ac, 0x1290), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
        /* SKYMEDI USB_DRIVE */
        { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
 
        { }  /* terminating entry must be last */
 };
 
-static void usb_autosuspend_quirk(struct usb_device *udev)
-{
-#ifdef CONFIG_USB_SUSPEND
-       /* disable autosuspend, but allow the user to re-enable it via sysfs */
-       udev->autosuspend_disabled = 1;
-#endif
-}
-
 static const struct usb_device_id *find_id(struct usb_device *udev)
 {
        const struct usb_device_id *id = usb_quirk_list;
@@ -149,13 +74,9 @@ void usb_detect_quirks(struct usb_device *udev)
                dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
                                udev->quirks);
 
-       /* do any special quirk handling here if needed */
-       if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND)
-               usb_autosuspend_quirk(udev);
-
        /* By default, disable autosuspend for all non-hubs */
 #ifdef CONFIG_USB_SUSPEND
        if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
-               udev->autosuspend_delay = -1;
+               udev->autosuspend_disabled = 1;
 #endif
 }
index 2ab222b..b04afd0 100644 (file)
@@ -169,6 +169,16 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
 }
 static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
 
+static ssize_t
+show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct usb_device *udev;
+
+       udev = to_usb_device(dev);
+       return sprintf(buf, "%d\n", atomic_read(&udev->urbnum));
+}
+static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
+
 
 #if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND)
 static const char power_group[] = "power";
@@ -413,6 +423,44 @@ usb_descriptor_attr(bDeviceProtocol, "%02x\n")
 usb_descriptor_attr(bNumConfigurations, "%d\n")
 usb_descriptor_attr(bMaxPacketSize0, "%d\n")
 
+
+
+/* show if the device is authorized (1) or not (0) */
+static ssize_t usb_dev_authorized_show(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *buf)
+{
+       struct usb_device *usb_dev = to_usb_device(dev);
+       return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized);
+}
+
+
+/*
+ * Authorize a device to be used in the system
+ *
+ * Writing a 0 deauthorizes the device, writing a 1 authorizes it.
+ */
+static ssize_t usb_dev_authorized_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t size)
+{
+       ssize_t result;
+       struct usb_device *usb_dev = to_usb_device(dev);
+       unsigned val;
+       result = sscanf(buf, "%u\n", &val);
+       if (result != 1)
+               result = -EINVAL;
+       else if (val == 0)
+               result = usb_deauthorize_device(usb_dev);
+       else
+               result = usb_authorize_device(usb_dev);
+       return result < 0? result : size;
+}
+
+static DEVICE_ATTR(authorized, 0644,
+           usb_dev_authorized_show, usb_dev_authorized_store);
+
+
 static struct attribute *dev_attrs[] = {
        /* current configuration's attributes */
        &dev_attr_configuration.attr,
@@ -420,6 +468,7 @@ static struct attribute *dev_attrs[] = {
        &dev_attr_bConfigurationValue.attr,
        &dev_attr_bmAttributes.attr,
        &dev_attr_bMaxPower.attr,
+       &dev_attr_urbnum.attr,
        /* device attributes */
        &dev_attr_idVendor.attr,
        &dev_attr_idProduct.attr,
@@ -435,6 +484,7 @@ static struct attribute *dev_attrs[] = {
        &dev_attr_version.attr,
        &dev_attr_maxchild.attr,
        &dev_attr_quirks.attr,
+       &dev_attr_authorized.attr,
        NULL,
 };
 static struct attribute_group dev_attr_grp = {
index be63022..c20c03a 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/bitops.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/log2.h>
 #include <linux/usb.h>
 #include <linux/wait.h>
 #include "hcd.h"
@@ -38,7 +39,6 @@ void usb_init_urb(struct urb *urb)
        if (urb) {
                memset(urb, 0, sizeof(*urb));
                kref_init(&urb->kref);
-               spin_lock_init(&urb->lock);
                INIT_LIST_HEAD(&urb->anchor_list);
        }
 }
@@ -277,44 +277,58 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
  */
 int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 {
-       int                     pipe, temp, max;
-       struct usb_device       *dev;
-       int                     is_out;
+       int                             xfertype, max;
+       struct usb_device               *dev;
+       struct usb_host_endpoint        *ep;
+       int                             is_out;
 
        if (!urb || urb->hcpriv || !urb->complete)
                return -EINVAL;
-       if (!(dev = urb->dev) ||
-           (dev->state < USB_STATE_DEFAULT) ||
-           (!dev->bus) || (dev->devnum <= 0))
+       if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT)
                return -ENODEV;
-       if (dev->bus->controller->power.power_state.event != PM_EVENT_ON
-                       || dev->state == USB_STATE_SUSPENDED)
-               return -EHOSTUNREACH;
 
+       /* For now, get the endpoint from the pipe.  Eventually drivers
+        * will be required to set urb->ep directly and we will eliminate
+        * urb->pipe.
+        */
+       ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)
+                       [usb_pipeendpoint(urb->pipe)];
+       if (!ep)
+               return -ENOENT;
+
+       urb->ep = ep;
        urb->status = -EINPROGRESS;
        urb->actual_length = 0;
 
        /* Lots of sanity checks, so HCDs can rely on clean data
         * and don't need to duplicate tests
         */
-       pipe = urb->pipe;
-       temp = usb_pipetype(pipe);
-       is_out = usb_pipeout(pipe);
+       xfertype = usb_endpoint_type(&ep->desc);
+       if (xfertype == USB_ENDPOINT_XFER_CONTROL) {
+               struct usb_ctrlrequest *setup =
+                               (struct usb_ctrlrequest *) urb->setup_packet;
+
+               if (!setup)
+                       return -ENOEXEC;
+               is_out = !(setup->bRequestType & USB_DIR_IN) ||
+                               !setup->wLength;
+       } else {
+               is_out = usb_endpoint_dir_out(&ep->desc);
+       }
 
-       if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
-               return -ENODEV;
+       /* Cache the direction for later use */
+       urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) |
+                       (is_out ? URB_DIR_OUT : URB_DIR_IN);
 
-       /* FIXME there should be a sharable lock protecting us against
-        * config/altsetting changes and disconnects, kicking in here.
-        * (here == before maxpacket, and eventually endpoint type,
-        * checks get made.)
-        */
+       if (xfertype != USB_ENDPOINT_XFER_CONTROL &&
+                       dev->state < USB_STATE_CONFIGURED)
+               return -ENODEV;
 
-       max = usb_maxpacket(dev, pipe, is_out);
+       max = le16_to_cpu(ep->desc.wMaxPacketSize);
        if (max <= 0) {
                dev_dbg(&dev->dev,
                        "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
-                       usb_pipeendpoint(pipe), is_out ? "out" : "in",
+                       usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
                        __FUNCTION__, max);
                return -EMSGSIZE;
        }
@@ -323,7 +337,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
         * but drivers only control those sizes for ISO.
         * while we're checking, initialize return status.
         */
-       if (temp == PIPE_ISOCHRONOUS) {
+       if (xfertype == USB_ENDPOINT_XFER_ISOC) {
                int     n, len;
 
                /* "high bandwidth" mode, 1-3 packets/uframe? */
@@ -358,20 +372,20 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 
        /* enforce simple/standard policy */
        allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
-                       URB_NO_INTERRUPT);
-       switch (temp) {
-       case PIPE_BULK:
+                       URB_NO_INTERRUPT | URB_DIR_MASK);
+       switch (xfertype) {
+       case USB_ENDPOINT_XFER_BULK:
                if (is_out)
                        allowed |= URB_ZERO_PACKET;
                /* FALLTHROUGH */
-       case PIPE_CONTROL:
+       case USB_ENDPOINT_XFER_CONTROL:
                allowed |= URB_NO_FSBR; /* only affects UHCI */
                /* FALLTHROUGH */
        default:                        /* all non-iso endpoints */
                if (!is_out)
                        allowed |= URB_SHORT_NOT_OK;
                break;
-       case PIPE_ISOCHRONOUS:
+       case USB_ENDPOINT_XFER_ISOC:
                allowed |= URB_ISO_ASAP;
                break;
        }
@@ -393,9 +407,9 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
         * supports different values... this uses EHCI/UHCI defaults (and
         * EHCI can use smaller non-default values).
         */
-       switch (temp) {
-       case PIPE_ISOCHRONOUS:
-       case PIPE_INTERRUPT:
+       switch (xfertype) {
+       case USB_ENDPOINT_XFER_ISOC:
+       case USB_ENDPOINT_XFER_INT:
                /* too small? */
                if (urb->interval <= 0)
                        return -EINVAL;
@@ -405,29 +419,27 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                        // NOTE usb handles 2^15
                        if (urb->interval > (1024 * 8))
                                urb->interval = 1024 * 8;
-                       temp = 1024 * 8;
+                       max = 1024 * 8;
                        break;
                case USB_SPEED_FULL:    /* units are frames/msec */
                case USB_SPEED_LOW:
-                       if (temp == PIPE_INTERRUPT) {
+                       if (xfertype == USB_ENDPOINT_XFER_INT) {
                                if (urb->interval > 255)
                                        return -EINVAL;
                                // NOTE ohci only handles up to 32
-                               temp = 128;
+                               max = 128;
                        } else {
                                if (urb->interval > 1024)
                                        urb->interval = 1024;
                                // NOTE usb and ohci handle up to 2^15
-                               temp = 1024;
+                               max = 1024;
                        }
                        break;
                default:
                        return -EINVAL;
                }
-               /* power of two? */
-               while (temp > urb->interval)
-                       temp >>= 1;
-               urb->interval = temp;
+               /* Round down to a power of 2, no more than max */
+               urb->interval = min(max, 1 << ilog2(urb->interval));
        }
 
        return usb_hcd_submit_urb(urb, mem_flags);
@@ -496,8 +508,10 @@ int usb_unlink_urb(struct urb *urb)
 {
        if (!urb)
                return -EINVAL;
-       if (!(urb->dev && urb->dev->bus))
+       if (!urb->dev)
                return -ENODEV;
+       if (!urb->ep)
+               return -EIDRM;
        return usb_hcd_unlink_urb(urb, -ECONNRESET);
 }
 
@@ -523,19 +537,21 @@ int usb_unlink_urb(struct urb *urb)
  */
 void usb_kill_urb(struct urb *urb)
 {
+       static DEFINE_MUTEX(reject_mutex);
+
        might_sleep();
-       if (!(urb && urb->dev && urb->dev->bus))
+       if (!(urb && urb->dev && urb->ep))
                return;
-       spin_lock_irq(&urb->lock);
+       mutex_lock(&reject_mutex);
        ++urb->reject;
-       spin_unlock_irq(&urb->lock);
+       mutex_unlock(&reject_mutex);
 
        usb_hcd_unlink_urb(urb, -ENOENT);
        wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
 
-       spin_lock_irq(&urb->lock);
+       mutex_lock(&reject_mutex);
        --urb->reject;
-       spin_unlock_irq(&urb->lock);
+       mutex_unlock(&reject_mutex);
 }
 
 /**
index 0fee5c6..c99938d 100644 (file)
@@ -223,6 +223,15 @@ static void ksuspend_usb_cleanup(void)
 
 #endif /* CONFIG_PM */
 
+
+/* Returns 1 if @usb_bus is WUSB, 0 otherwise */
+static unsigned usb_bus_is_wusb(struct usb_bus *bus)
+{
+       struct usb_hcd *hcd = container_of(bus, struct usb_hcd, self);
+       return hcd->wireless;
+}
+
+
 /**
  * usb_alloc_dev - usb device constructor (usbcore-internal)
  * @parent: hub to which device is connected; null to allocate a root hub
@@ -239,6 +248,8 @@ struct usb_device *
 usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
 {
        struct usb_device *dev;
+       struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
+       unsigned root_hub = 0;
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (!dev)
@@ -255,12 +266,14 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
        dev->dev.dma_mask = bus->controller->dma_mask;
        set_dev_node(&dev->dev, dev_to_node(bus->controller));
        dev->state = USB_STATE_ATTACHED;
+       atomic_set(&dev->urbnum, 0);
 
        INIT_LIST_HEAD(&dev->ep0.urb_list);
        dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
        dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
        /* ep0 maxpacket comes later, from device descriptor */
-       dev->ep_in[0] = dev->ep_out[0] = &dev->ep0;
+       usb_enable_endpoint(dev, &dev->ep0);
+       dev->can_submit = 1;
 
        /* Save readable and stable topology id, distinguishing devices
         * by location for diagnostics, tools, driver model, etc.  The
@@ -275,6 +288,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
 
                dev->dev.parent = bus->controller;
                sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
+               root_hub = 1;
        } else {
                /* match any labeling on the hubs; it's one-based */
                if (parent->devpath[0] == '0')
@@ -301,6 +315,12 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
        INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
        dev->autosuspend_delay = usb_autosuspend_delay * HZ;
 #endif
+       if (root_hub)   /* Root hub always ok [and always wired] */
+               dev->authorized = 1;
+       else {
+               dev->authorized = usb_hcd->authorized_default;
+               dev->wusb = usb_bus_is_wusb(bus)? 1 : 0;
+       }
        return dev;
 }
 
@@ -748,7 +768,7 @@ void usb_buffer_unmap(struct urb *urb)
 /**
  * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
  * @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
  * @sg: the scatterlist to map
  * @nents: the number of entries in the scatterlist
  *
@@ -771,14 +791,13 @@ void usb_buffer_unmap(struct urb *urb)
  *
  * Reverse the effect of this call with usb_buffer_unmap_sg().
  */
-int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
+int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
                      struct scatterlist *sg, int nents)
 {
        struct usb_bus          *bus;
        struct device           *controller;
 
        if (!dev
-                       || usb_pipecontrol(pipe)
                        || !(bus = dev->bus)
                        || !(controller = bus->controller)
                        || !controller->dma_mask)
@@ -786,7 +805,7 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
 
        // FIXME generic api broken like pci, can't report errors
        return dma_map_sg(controller, sg, nents,
-                       usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+                       is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /* XXX DISABLED, no users currently.  If you wish to re-enable this
@@ -799,14 +818,14 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
 /**
  * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s)
  * @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
  * @sg: the scatterlist to synchronize
  * @n_hw_ents: the positive return value from usb_buffer_map_sg
  *
  * Use this when you are re-using a scatterlist's data buffers for
  * another USB request.
  */
-void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
                           struct scatterlist *sg, int n_hw_ents)
 {
        struct usb_bus          *bus;
@@ -819,20 +838,20 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
                return;
 
        dma_sync_sg(controller, sg, n_hw_ents,
-                       usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+                       is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 #endif
 
 /**
  * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
  * @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
  * @sg: the scatterlist to unmap
  * @n_hw_ents: the positive return value from usb_buffer_map_sg
  *
  * Reverses the effect of usb_buffer_map_sg().
  */
-void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
                         struct scatterlist *sg, int n_hw_ents)
 {
        struct usb_bus          *bus;
@@ -845,7 +864,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
                return;
 
        dma_unmap_sg(controller, sg, n_hw_ents,
-                       usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+                       is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /* format to disable USB on kernel command line is: nousb */
index ad5fa03..c52626c 100644 (file)
@@ -8,17 +8,22 @@ extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint *
                                struct usb_device *udev);
 extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
 
+extern void usb_enable_endpoint(struct usb_device *dev,
+               struct usb_host_endpoint *ep);
 extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr);
 extern void usb_disable_interface (struct usb_device *dev,
                struct usb_interface *intf);
 extern void usb_release_interface_cache(struct kref *ref);
 extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
+extern int usb_deauthorize_device (struct usb_device *);
+extern int usb_authorize_device (struct usb_device *);
 extern void usb_detect_quirks(struct usb_device *udev);
 
 extern int usb_get_device_descriptor(struct usb_device *dev,
                unsigned int size);
 extern char *usb_cache_string(struct usb_device *udev, int index);
 extern int usb_set_configuration(struct usb_device *dev, int configuration);
+extern int usb_choose_configuration(struct usb_device *udev);
 
 extern void usb_kick_khubd(struct usb_device *dev);
 extern int usb_match_device(struct usb_device *dev,
index 767aed5..f81d08d 100644 (file)
@@ -67,6 +67,17 @@ config USB_GADGET_DEBUG_FILES
           driver on a new board.   Enable these files by choosing "Y"
           here.  If in doubt, or to conserve kernel memory, say "N".
 
+config USB_GADGET_DEBUG_FS
+       boolean "Debugging information files in debugfs"
+       depends on USB_GADGET && DEBUG_FS
+       help
+          Some of the drivers in the "gadget" framework can expose
+          debugging information in files under /sys/kernel/debug/.
+          The information in these files may help when you're
+          troubleshooting or bringing up a driver on a new board.
+          Enable these files by choosing "Y" here.  If in doubt, or
+          to conserve kernel memory, say "N".
+
 config USB_GADGET_SELECTED
        boolean
 
@@ -103,6 +114,20 @@ config USB_AMD5536UDC
        default USB_GADGET
        select USB_GADGET_SELECTED
 
+config USB_GADGET_ATMEL_USBA
+       boolean "Atmel USBA"
+       select USB_GADGET_DUALSPEED
+       depends on AVR32
+       help
+         USBA is the integrated high-speed USB Device controller on
+         the AT32AP700x processors from Atmel.
+
+config USB_ATMEL_USBA
+       tristate
+       depends on USB_GADGET_ATMEL_USBA
+       default USB_GADGET
+       select USB_GADGET_SELECTED
+
 config USB_GADGET_FSL_USB2
        boolean "Freescale Highspeed USB DR Peripheral Controller"
        depends on MPC834x || PPC_MPC831x
@@ -228,7 +253,6 @@ config USB_LH7A40X
        default USB_GADGET
        select USB_GADGET_SELECTED
 
-
 config USB_GADGET_OMAP
        boolean "OMAP USB Device Controller"
        depends on ARCH_OMAP
index 1bc0f03..904e57b 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_OMAP)                += omap_udc.o
 obj-$(CONFIG_USB_LH7A40X)      += lh7a40x_udc.o
 obj-$(CONFIG_USB_S3C2410)      += s3c2410_udc.o
 obj-$(CONFIG_USB_AT91)         += at91_udc.o
+obj-$(CONFIG_USB_ATMEL_USBA)   += atmel_usba_udc.o
 obj-$(CONFIG_USB_FSL_USB2)     += fsl_usb2_udc.o
 obj-$(CONFIG_USB_M66592)       += m66592-udc.o
 
index 714156c..1c80406 100644 (file)
@@ -69,7 +69,7 @@
 
 /* gadget stack */
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 /* udc specific */
 #include "amd5536udc.h"
@@ -3244,7 +3244,6 @@ static int udc_pci_probe(
                retval = -ENOMEM;
                goto finished;
        }
-       memset(dev, 0, sizeof(struct udc));
 
        /* pci setup */
        if (pci_enable_device(pdev) < 0) {
@@ -3286,14 +3285,12 @@ static int udc_pci_probe(
 
        pci_set_drvdata(pdev, dev);
 
-       /* chip revision */
-       dev->chiprev = 0;
+       /* chip revision for Hs AMD5536 */
+       dev->chiprev = pdev->revision;
 
        pci_set_master(pdev);
        pci_set_mwi(pdev);
 
-       /* chip rev for Hs AMD5536 */
-       pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev);
        /* init dma pools */
        if (use_dma) {
                retval = init_dma_pools(dev);
index 63d7d65..a6adf7e 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/proc_fs.h>
 #include <linux/clk.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/hardware.h>
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
new file mode 100644 (file)
index 0000000..4fb5ff4
--- /dev/null
@@ -0,0 +1,2077 @@
+/*
+ * Driver for the Atmel USBA high speed USB device controller
+ *
+ * Copyright (C) 2005-2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/delay.h>
+
+#include <asm/gpio.h>
+#include <asm/arch/board.h>
+
+#include "atmel_usba_udc.h"
+
+
+static struct usba_udc the_udc;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+static int queue_dbg_open(struct inode *inode, struct file *file)
+{
+       struct usba_ep *ep = inode->i_private;
+       struct usba_request *req, *req_copy;
+       struct list_head *queue_data;
+
+       queue_data = kmalloc(sizeof(*queue_data), GFP_KERNEL);
+       if (!queue_data)
+               return -ENOMEM;
+       INIT_LIST_HEAD(queue_data);
+
+       spin_lock_irq(&ep->udc->lock);
+       list_for_each_entry(req, &ep->queue, queue) {
+               req_copy = kmalloc(sizeof(*req_copy), GFP_ATOMIC);
+               if (!req_copy)
+                       goto fail;
+               memcpy(req_copy, req, sizeof(*req_copy));
+               list_add_tail(&req_copy->queue, queue_data);
+       }
+       spin_unlock_irq(&ep->udc->lock);
+
+       file->private_data = queue_data;
+       return 0;
+
+fail:
+       spin_unlock_irq(&ep->udc->lock);
+       list_for_each_entry_safe(req, req_copy, queue_data, queue) {
+               list_del(&req->queue);
+               kfree(req);
+       }
+       kfree(queue_data);
+       return -ENOMEM;
+}
+
+/*
+ * bbbbbbbb llllllll IZS sssss nnnn FDL\n\0
+ *
+ * b: buffer address
+ * l: buffer length
+ * I/i: interrupt/no interrupt
+ * Z/z: zero/no zero
+ * S/s: short ok/short not ok
+ * s: status
+ * n: nr_packets
+ * F/f: submitted/not submitted to FIFO
+ * D/d: using/not using DMA
+ * L/l: last transaction/not last transaction
+ */
+static ssize_t queue_dbg_read(struct file *file, char __user *buf,
+               size_t nbytes, loff_t *ppos)
+{
+       struct list_head *queue = file->private_data;
+       struct usba_request *req, *tmp_req;
+       size_t len, remaining, actual = 0;
+       char tmpbuf[38];
+
+       if (!access_ok(VERIFY_WRITE, buf, nbytes))
+               return -EFAULT;
+
+       mutex_lock(&file->f_dentry->d_inode->i_mutex);
+       list_for_each_entry_safe(req, tmp_req, queue, queue) {
+               len = snprintf(tmpbuf, sizeof(tmpbuf),
+                               "%8p %08x %c%c%c %5d %c%c%c\n",
+                               req->req.buf, req->req.length,
+                               req->req.no_interrupt ? 'i' : 'I',
+                               req->req.zero ? 'Z' : 'z',
+                               req->req.short_not_ok ? 's' : 'S',
+                               req->req.status,
+                               req->submitted ? 'F' : 'f',
+                               req->using_dma ? 'D' : 'd',
+                               req->last_transaction ? 'L' : 'l');
+               len = min(len, sizeof(tmpbuf));
+               if (len > nbytes)
+                       break;
+
+               list_del(&req->queue);
+               kfree(req);
+
+               remaining = __copy_to_user(buf, tmpbuf, len);
+               actual += len - remaining;
+               if (remaining)
+                       break;
+
+               nbytes -= len;
+               buf += len;
+       }
+       mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+
+       return actual;
+}
+
+static int queue_dbg_release(struct inode *inode, struct file *file)
+{
+       struct list_head *queue_data = file->private_data;
+       struct usba_request *req, *tmp_req;
+
+       list_for_each_entry_safe(req, tmp_req, queue_data, queue) {
+               list_del(&req->queue);
+               kfree(req);
+       }
+       kfree(queue_data);
+       return 0;
+}
+
+static int regs_dbg_open(struct inode *inode, struct file *file)
+{
+       struct usba_udc *udc;
+       unsigned int i;
+       u32 *data;
+       int ret = -ENOMEM;
+
+       mutex_lock(&inode->i_mutex);
+       udc = inode->i_private;
+       data = kmalloc(inode->i_size, GFP_KERNEL);
+       if (!data)
+               goto out;
+
+       spin_lock_irq(&udc->lock);
+       for (i = 0; i < inode->i_size / 4; i++)
+               data[i] = __raw_readl(udc->regs + i * 4);
+       spin_unlock_irq(&udc->lock);
+
+       file->private_data = data;
+       ret = 0;
+
+out:
+       mutex_unlock(&inode->i_mutex);
+
+       return ret;
+}
+
+static ssize_t regs_dbg_read(struct file *file, char __user *buf,
+               size_t nbytes, loff_t *ppos)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       int ret;
+
+       mutex_lock(&inode->i_mutex);
+       ret = simple_read_from_buffer(buf, nbytes, ppos,
+                       file->private_data,
+                       file->f_dentry->d_inode->i_size);
+       mutex_unlock(&inode->i_mutex);
+
+       return ret;
+}
+
+static int regs_dbg_release(struct inode *inode, struct file *file)
+{
+       kfree(file->private_data);
+       return 0;
+}
+
+const struct file_operations queue_dbg_fops = {
+       .owner          = THIS_MODULE,
+       .open           = queue_dbg_open,
+       .llseek         = no_llseek,
+       .read           = queue_dbg_read,
+       .release        = queue_dbg_release,
+};
+
+const struct file_operations regs_dbg_fops = {
+       .owner          = THIS_MODULE,
+       .open           = regs_dbg_open,
+       .llseek         = generic_file_llseek,
+       .read           = regs_dbg_read,
+       .release        = regs_dbg_release,
+};
+
+static void usba_ep_init_debugfs(struct usba_udc *udc,
+               struct usba_ep *ep)
+{
+       struct dentry *ep_root;
+
+       ep_root = debugfs_create_dir(ep->ep.name, udc->debugfs_root);
+       if (!ep_root)
+               goto err_root;
+       ep->debugfs_dir = ep_root;
+
+       ep->debugfs_queue = debugfs_create_file("queue", 0400, ep_root,
+                                               ep, &queue_dbg_fops);
+       if (!ep->debugfs_queue)
+               goto err_queue;
+
+       if (ep->can_dma) {
+               ep->debugfs_dma_status
+                       = debugfs_create_u32("dma_status", 0400, ep_root,
+                                       &ep->last_dma_status);
+               if (!ep->debugfs_dma_status)
+                       goto err_dma_status;
+       }
+       if (ep_is_control(ep)) {
+               ep->debugfs_state
+                       = debugfs_create_u32("state", 0400, ep_root,
+                                       &ep->state);
+               if (!ep->debugfs_state)
+                       goto err_state;
+       }
+
+       return;
+
+err_state:
+       if (ep->can_dma)
+               debugfs_remove(ep->debugfs_dma_status);
+err_dma_status:
+       debugfs_remove(ep->debugfs_queue);
+err_queue:
+       debugfs_remove(ep_root);
+err_root:
+       dev_err(&ep->udc->pdev->dev,
+               "failed to create debugfs directory for %s\n", ep->ep.name);
+}
+
+static void usba_ep_cleanup_debugfs(struct usba_ep *ep)
+{
+       debugfs_remove(ep->debugfs_queue);
+       debugfs_remove(ep->debugfs_dma_status);
+       debugfs_remove(ep->debugfs_state);
+       debugfs_remove(ep->debugfs_dir);
+       ep->debugfs_dma_status = NULL;
+       ep->debugfs_dir = NULL;
+}
+
+static void usba_init_debugfs(struct usba_udc *udc)
+{
+       struct dentry *root, *regs;
+       struct resource *regs_resource;
+
+       root = debugfs_create_dir(udc->gadget.name, NULL);
+       if (IS_ERR(root) || !root)
+               goto err_root;
+       udc->debugfs_root = root;
+
+       regs = debugfs_create_file("regs", 0400, root, udc, &regs_dbg_fops);
+       if (!regs)
+               goto err_regs;
+
+       regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM,
+                               CTRL_IOMEM_ID);
+       regs->d_inode->i_size = regs_resource->end - regs_resource->start + 1;
+       udc->debugfs_regs = regs;
+
+       usba_ep_init_debugfs(udc, to_usba_ep(udc->gadget.ep0));
+
+       return;
+
+err_regs:
+       debugfs_remove(root);
+err_root:
+       udc->debugfs_root = NULL;
+       dev_err(&udc->pdev->dev, "debugfs is not available\n");
+}
+
+static void usba_cleanup_debugfs(struct usba_udc *udc)
+{
+       usba_ep_cleanup_debugfs(to_usba_ep(udc->gadget.ep0));
+       debugfs_remove(udc->debugfs_regs);
+       debugfs_remove(udc->debugfs_root);
+       udc->debugfs_regs = NULL;
+       udc->debugfs_root = NULL;
+}
+#else
+static inline void usba_ep_init_debugfs(struct usba_udc *udc,
+                                        struct usba_ep *ep)
+{
+
+}
+
+static inline void usba_ep_cleanup_debugfs(struct usba_ep *ep)
+{
+
+}
+
+static inline void usba_init_debugfs(struct usba_udc *udc)
+{
+
+}
+
+static inline void usba_cleanup_debugfs(struct usba_udc *udc)
+{
+
+}
+#endif
+
+static int vbus_is_present(struct usba_udc *udc)
+{
+       if (udc->vbus_pin != -1)
+               return gpio_get_value(udc->vbus_pin);
+
+       /* No Vbus detection: Assume always present */
+       return 1;
+}
+
+static void copy_to_fifo(void __iomem *fifo, const void *buf, int len)
+{
+       unsigned long tmp;
+
+       DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len);
+       for (; len > 0; len -= 4, buf += 4, fifo += 4) {
+               tmp = *(unsigned long *)buf;
+               if (len >= 4) {
+                       DBG(DBG_FIFO, "  -> %08lx\n", tmp);
+                       __raw_writel(tmp, fifo);
+               } else {
+                       do {
+                               DBG(DBG_FIFO, "  -> %02lx\n", tmp >> 24);
+                               __raw_writeb(tmp >> 24, fifo);
+                               fifo++;
+                               tmp <<= 8;
+                       } while (--len);
+                       break;
+               }
+       }
+}
+
+static void copy_from_fifo(void *buf, void __iomem *fifo, int len)
+{
+       union {
+               unsigned long *w;
+               unsigned char *b;
+       } p;
+       unsigned long tmp;
+
+       DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len);
+       for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) {
+               if (len >= 4) {
+                       tmp = __raw_readl(fifo);
+                       *p.w = tmp;
+                       DBG(DBG_FIFO, "  -> %08lx\n", tmp);
+               } else {
+                       do {
+                               tmp = __raw_readb(fifo);
+                               *p.b = tmp;
+                               DBG(DBG_FIFO, " -> %02lx\n", tmp);
+                               fifo++, p.b++;
+                       } while (--len);
+               }
+       }
+}
+
+static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
+{
+       unsigned int transaction_len;
+
+       transaction_len = req->req.length - req->req.actual;
+       req->last_transaction = 1;
+       if (transaction_len > ep->ep.maxpacket) {
+               transaction_len = ep->ep.maxpacket;
+               req->last_transaction = 0;
+       } else if (transaction_len == ep->ep.maxpacket && req->req.zero)
+               req->last_transaction = 0;
+
+       DBG(DBG_QUEUE, "%s: submit_transaction, req %p (length %d)%s\n",
+               ep->ep.name, req, transaction_len,
+               req->last_transaction ? ", done" : "");
+
+       copy_to_fifo(ep->fifo, req->req.buf + req->req.actual, transaction_len);
+       usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+       req->req.actual += transaction_len;
+}
+
+static void submit_request(struct usba_ep *ep, struct usba_request *req)
+{
+       DBG(DBG_QUEUE, "%s: submit_request: req %p (length %d)\n",
+               ep->ep.name, req, req->req.length);
+
+       req->req.actual = 0;
+       req->submitted = 1;
+
+       if (req->using_dma) {
+               if (req->req.length == 0) {
+                       usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+                       return;
+               }
+
+               if (req->req.zero)
+                       usba_ep_writel(ep, CTL_ENB, USBA_SHORT_PACKET);
+               else
+                       usba_ep_writel(ep, CTL_DIS, USBA_SHORT_PACKET);
+
+               usba_dma_writel(ep, ADDRESS, req->req.dma);
+               usba_dma_writel(ep, CONTROL, req->ctrl);
+       } else {
+               next_fifo_transaction(ep, req);
+               if (req->last_transaction) {
+                       usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+                       usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+               } else {
+                       usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+                       usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+               }
+       }
+}
+
+static void submit_next_request(struct usba_ep *ep)
+{
+       struct usba_request *req;
+
+       if (list_empty(&ep->queue)) {
+               usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY | USBA_RX_BK_RDY);
+               return;
+       }
+
+       req = list_entry(ep->queue.next, struct usba_request, queue);
+       if (!req->submitted)
+               submit_request(ep, req);
+}
+
+static void send_status(struct usba_udc *udc, struct usba_ep *ep)
+{
+       ep->state = STATUS_STAGE_IN;
+       usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+       usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+}
+
+static void receive_data(struct usba_ep *ep)
+{
+       struct usba_udc *udc = ep->udc;
+       struct usba_request *req;
+       unsigned long status;
+       unsigned int bytecount, nr_busy;
+       int is_complete = 0;
+
+       status = usba_ep_readl(ep, STA);
+       nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+
+       DBG(DBG_QUEUE, "receive data: nr_busy=%u\n", nr_busy);
+
+       while (nr_busy > 0) {
+               if (list_empty(&ep->queue)) {
+                       usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+                       break;
+               }
+               req = list_entry(ep->queue.next,
+                                struct usba_request, queue);
+
+               bytecount = USBA_BFEXT(BYTE_COUNT, status);
+
+               if (status & (1 << 31))
+                       is_complete = 1;
+               if (req->req.actual + bytecount >= req->req.length) {
+                       is_complete = 1;
+                       bytecount = req->req.length - req->req.actual;
+               }
+
+               copy_from_fifo(req->req.buf + req->req.actual,
+                               ep->fifo, bytecount);
+               req->req.actual += bytecount;
+
+               usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+
+               if (is_complete) {
+                       DBG(DBG_QUEUE, "%s: request done\n", ep->ep.name);
+                       req->req.status = 0;
+                       list_del_init(&req->queue);
+                       usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+                       spin_unlock(&udc->lock);
+                       req->req.complete(&ep->ep, &req->req);
+                       spin_lock(&udc->lock);
+               }
+
+               status = usba_ep_readl(ep, STA);
+               nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+
+               if (is_complete && ep_is_control(ep)) {
+                       send_status(udc, ep);
+                       break;
+               }
+       }
+}
+
+static void
+request_complete(struct usba_ep *ep, struct usba_request *req, int status)
+{
+       struct usba_udc *udc = ep->udc;
+
+       WARN_ON(!list_empty(&req->queue));
+
+       if (req->req.status == -EINPROGRESS)
+               req->req.status = status;
+
+       if (req->mapped) {
+               dma_unmap_single(
+                       &udc->pdev->dev, req->req.dma, req->req.length,
+                       ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               req->req.dma = DMA_ADDR_INVALID;
+               req->mapped = 0;
+       }
+
+       DBG(DBG_GADGET | DBG_REQ,
+               "%s: req %p complete: status %d, actual %u\n",
+               ep->ep.name, req, req->req.status, req->req.actual);
+
+       spin_unlock(&udc->lock);
+       req->req.complete(&ep->ep, &req->req);
+       spin_lock(&udc->lock);
+}
+
+static void
+request_complete_list(struct usba_ep *ep, struct list_head *list, int status)
+{
+       struct usba_request *req, *tmp_req;
+
+       list_for_each_entry_safe(req, tmp_req, list, queue) {
+               list_del_init(&req->queue);
+               request_complete(ep, req, status);
+       }
+}
+
+static int
+usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+       struct usba_ep *ep = to_usba_ep(_ep);
+       struct usba_udc *udc = ep->udc;
+       unsigned long flags, ept_cfg, maxpacket;
+       unsigned int nr_trans;
+
+       DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc);
+
+       maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
+
+       if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index)
+                       || ep->index == 0
+                       || desc->bDescriptorType != USB_DT_ENDPOINT
+                       || maxpacket == 0
+                       || maxpacket > ep->fifo_size) {
+               DBG(DBG_ERR, "ep_enable: Invalid argument");
+               return -EINVAL;
+       }
+
+       ep->is_isoc = 0;
+       ep->is_in = 0;
+
+       if (maxpacket <= 8)
+               ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8);
+       else
+               /* LSB is bit 1, not 0 */
+               ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3);
+
+       DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n",
+                       ep->ep.name, ept_cfg, maxpacket);
+
+       if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+               ep->is_in = 1;
+               ept_cfg |= USBA_EPT_DIR_IN;
+       }
+
+       switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL);
+               ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE);
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               if (!ep->can_isoc) {
+                       DBG(DBG_ERR, "ep_enable: %s is not isoc capable\n",
+                                       ep->ep.name);
+                       return -EINVAL;
+               }
+
+               /*
+                * Bits 11:12 specify number of _additional_
+                * transactions per microframe.
+                */
+               nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1;
+               if (nr_trans > 3)
+                       return -EINVAL;
+
+               ep->is_isoc = 1;
+               ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO);
+
+               /*
+                * Do triple-buffering on high-bandwidth iso endpoints.
+                */
+               if (nr_trans > 1 && ep->nr_banks == 3)
+                       ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE);
+               else
+                       ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+               ept_cfg |= USBA_BF(NB_TRANS, nr_trans);
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK);
+               ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT);
+               ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+               break;
+       }
+
+       spin_lock_irqsave(&ep->udc->lock, flags);
+
+       if (ep->desc) {
+               spin_unlock_irqrestore(&ep->udc->lock, flags);
+               DBG(DBG_ERR, "ep%d already enabled\n", ep->index);
+               return -EBUSY;
+       }
+
+       ep->desc = desc;
+       ep->ep.maxpacket = maxpacket;
+
+       usba_ep_writel(ep, CFG, ept_cfg);
+       usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+
+       if (ep->can_dma) {
+               u32 ctrl;
+
+               usba_writel(udc, INT_ENB,
+                               (usba_readl(udc, INT_ENB)
+                                       | USBA_BF(EPT_INT, 1 << ep->index)
+                                       | USBA_BF(DMA_INT, 1 << ep->index)));
+               ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA;
+               usba_ep_writel(ep, CTL_ENB, ctrl);
+       } else {
+               usba_writel(udc, INT_ENB,
+                               (usba_readl(udc, INT_ENB)
+                                       | USBA_BF(EPT_INT, 1 << ep->index)));
+       }
+
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index,
+                       (unsigned long)usba_ep_readl(ep, CFG));
+       DBG(DBG_HW, "INT_ENB after init: %#08lx\n",
+                       (unsigned long)usba_readl(udc, INT_ENB));
+
+       return 0;
+}
+
+static int usba_ep_disable(struct usb_ep *_ep)
+{
+       struct usba_ep *ep = to_usba_ep(_ep);
+       struct usba_udc *udc = ep->udc;
+       LIST_HEAD(req_list);
+       unsigned long flags;
+
+       DBG(DBG_GADGET, "ep_disable: %s\n", ep->ep.name);
+
+       spin_lock_irqsave(&udc->lock, flags);
+
+       if (!ep->desc) {
+               spin_unlock_irqrestore(&udc->lock, flags);
+               DBG(DBG_ERR, "ep_disable: %s not enabled\n", ep->ep.name);
+               return -EINVAL;
+       }
+       ep->desc = NULL;
+
+       list_splice_init(&ep->queue, &req_list);
+       if (ep->can_dma) {
+               usba_dma_writel(ep, CONTROL, 0);
+               usba_dma_writel(ep, ADDRESS, 0);
+               usba_dma_readl(ep, STATUS);
+       }
+       usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE);
+       usba_writel(udc, INT_ENB,
+                       usba_readl(udc, INT_ENB)
+                       & ~USBA_BF(EPT_INT, 1 << ep->index));
+
+       request_complete_list(ep, &req_list, -ESHUTDOWN);
+
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return 0;
+}
+
+static struct usb_request *
+usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+       struct usba_request *req;
+
+       DBG(DBG_GADGET, "ep_alloc_request: %p, 0x%x\n", _ep, gfp_flags);
+
+       req = kzalloc(sizeof(*req), gfp_flags);
+       if (!req)
+               return NULL;
+
+       INIT_LIST_HEAD(&req->queue);
+       req->req.dma = DMA_ADDR_INVALID;
+
+       return &req->req;
+}
+
+static void
+usba_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+       struct usba_request *req = to_usba_req(_req);
+
+       DBG(DBG_GADGET, "ep_free_request: %p, %p\n", _ep, _req);
+
+       kfree(req);
+}
+
+static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
+               struct usba_request *req, gfp_t gfp_flags)
+{
+       unsigned long flags;
+       int ret;
+
+       DBG(DBG_DMA, "%s: req l/%u d/%08x %c%c%c\n",
+               ep->ep.name, req->req.length, req->req.dma,
+               req->req.zero ? 'Z' : 'z',
+               req->req.short_not_ok ? 'S' : 's',
+               req->req.no_interrupt ? 'I' : 'i');
+
+       if (req->req.length > 0x10000) {
+               /* Lengths from 0 to 65536 (inclusive) are supported */
+               DBG(DBG_ERR, "invalid request length %u\n", req->req.length);
+               return -EINVAL;
+       }
+
+       req->using_dma = 1;
+
+       if (req->req.dma == DMA_ADDR_INVALID) {
+               req->req.dma = dma_map_single(
+                       &udc->pdev->dev, req->req.buf, req->req.length,
+                       ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               req->mapped = 1;
+       } else {
+               dma_sync_single_for_device(
+                       &udc->pdev->dev, req->req.dma, req->req.length,
+                       ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               req->mapped = 0;
+       }
+
+       req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)
+                       | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE
+                       | USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE;
+
+       if (ep->is_in)
+               req->ctrl |= USBA_DMA_END_BUF_EN;
+
+       /*
+        * Add this request to the queue and submit for DMA if
+        * possible. Check if we're still alive first -- we may have
+        * received a reset since last time we checked.
+        */
+       ret = -ESHUTDOWN;
+       spin_lock_irqsave(&udc->lock, flags);
+       if (ep->desc) {
+               if (list_empty(&ep->queue))
+                       submit_request(ep, req);
+
+               list_add_tail(&req->queue, &ep->queue);
+               ret = 0;
+       }
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return ret;
+}
+
+static int
+usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+       struct usba_request *req = to_usba_req(_req);
+       struct usba_ep *ep = to_usba_ep(_ep);
+       struct usba_udc *udc = ep->udc;
+       unsigned long flags;
+       int ret;
+
+       DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n",
+                       ep->ep.name, req, _req->length);
+
+       if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc)
+               return -ESHUTDOWN;
+
+       req->submitted = 0;
+       req->using_dma = 0;
+       req->last_transaction = 0;
+
+       _req->status = -EINPROGRESS;
+       _req->actual = 0;
+
+       if (ep->can_dma)
+               return queue_dma(udc, ep, req, gfp_flags);
+
+       /* May have received a reset since last time we checked */
+       ret = -ESHUTDOWN;
+       spin_lock_irqsave(&udc->lock, flags);
+       if (ep->desc) {
+               list_add_tail(&req->queue, &ep->queue);
+
+               if (ep->is_in || (ep_is_control(ep)
+                               && (ep->state == DATA_STAGE_IN
+                                       || ep->state == STATUS_STAGE_IN)))
+                       usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+               else
+                       usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+               ret = 0;
+       }
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return ret;
+}
+
+static void
+usba_update_req(struct usba_ep *ep, struct usba_request *req, u32 status)
+{
+       req->req.actual = req->req.length - USBA_BFEXT(DMA_BUF_LEN, status);
+}
+
+static int stop_dma(struct usba_ep *ep, u32 *pstatus)
+{
+       unsigned int timeout;
+       u32 status;
+
+       /*
+        * Stop the DMA controller. When writing both CH_EN
+        * and LINK to 0, the other bits are not affected.
+        */
+       usba_dma_writel(ep, CONTROL, 0);
+
+       /* Wait for the FIFO to empty */
+       for (timeout = 40; timeout; --timeout) {
+               status = usba_dma_readl(ep, STATUS);
+               if (!(status & USBA_DMA_CH_EN))
+                       break;
+               udelay(1);
+       }
+
+       if (pstatus)
+               *pstatus = status;
+
+       if (timeout == 0) {
+               dev_err(&ep->udc->pdev->dev,
+                       "%s: timed out waiting for DMA FIFO to empty\n",
+                       ep->ep.name);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+       struct usba_ep *ep = to_usba_ep(_ep);
+       struct usba_udc *udc = ep->udc;
+       struct usba_request *req = to_usba_req(_req);
+       unsigned long flags;
+       u32 status;
+
+       DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n",
+                       ep->ep.name, req);
+
+       spin_lock_irqsave(&udc->lock, flags);
+
+       if (req->using_dma) {
+               /*
+                * If this request is currently being transferred,
+                * stop the DMA controller and reset the FIFO.
+                */
+               if (ep->queue.next == &req->queue) {
+                       status = usba_dma_readl(ep, STATUS);
+                       if (status & USBA_DMA_CH_EN)
+                               stop_dma(ep, &status);
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+                       ep->last_dma_status = status;
+#endif
+
+                       usba_writel(udc, EPT_RST, 1 << ep->index);
+
+                       usba_update_req(ep, req, status);
+               }
+       }
+
+       /*
+        * Errors should stop the queue from advancing until the
+        * completion function returns.
+        */
+       list_del_init(&req->queue);
+
+       request_complete(ep, req, -ECONNRESET);
+
+       /* Process the next request if any */
+       submit_next_request(ep);
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return 0;
+}
+
+static int usba_ep_set_halt(struct usb_ep *_ep, int value)
+{
+       struct usba_ep *ep = to_usba_ep(_ep);
+       struct usba_udc *udc = ep->udc;
+       unsigned long flags;
+       int ret = 0;
+
+       DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name,
+                       value ? "set" : "clear");
+
+       if (!ep->desc) {
+               DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n",
+                               ep->ep.name);
+               return -ENODEV;
+       }
+       if (ep->is_isoc) {
+               DBG(DBG_ERR, "Attempted to halt isochronous ep %s\n",
+                               ep->ep.name);
+               return -ENOTTY;
+       }
+
+       spin_lock_irqsave(&udc->lock, flags);
+
+       /*
+        * We can't halt IN endpoints while there are still data to be
+        * transferred
+        */
+       if (!list_empty(&ep->queue)
+                       || ((value && ep->is_in && (usba_ep_readl(ep, STA)
+                                       & USBA_BF(BUSY_BANKS, -1L))))) {
+               ret = -EAGAIN;
+       } else {
+               if (value)
+                       usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+               else
+                       usba_ep_writel(ep, CLR_STA,
+                                       USBA_FORCE_STALL | USBA_TOGGLE_CLR);
+               usba_ep_readl(ep, STA);
+       }
+
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return ret;
+}
+
+static int usba_ep_fifo_status(struct usb_ep *_ep)
+{
+       struct usba_ep *ep = to_usba_ep(_ep);
+
+       return USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+}
+
+static void usba_ep_fifo_flush(struct usb_ep *_ep)
+{
+       struct usba_ep *ep = to_usba_ep(_ep);
+       struct usba_udc *udc = ep->udc;
+
+       usba_writel(udc, EPT_RST, 1 << ep->index);
+}
+
+static const struct usb_ep_ops usba_ep_ops = {
+       .enable         = usba_ep_enable,
+       .disable        = usba_ep_disable,
+       .alloc_request  = usba_ep_alloc_request,
+       .free_request   = usba_ep_free_request,
+       .queue          = usba_ep_queue,
+       .dequeue        = usba_ep_dequeue,
+       .set_halt       = usba_ep_set_halt,
+       .fifo_status    = usba_ep_fifo_status,
+       .fifo_flush     = usba_ep_fifo_flush,
+};
+
+static int usba_udc_get_frame(struct usb_gadget *gadget)
+{
+       struct usba_udc *udc = to_usba_udc(gadget);
+
+       return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM));
+}
+
+static int usba_udc_wakeup(struct usb_gadget *gadget)
+{
+       struct usba_udc *udc = to_usba_udc(gadget);
+       unsigned long flags;
+       u32 ctrl;
+       int ret = -EINVAL;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       if (udc->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
+               ctrl = usba_readl(udc, CTRL);
+               usba_writel(udc, CTRL, ctrl | USBA_REMOTE_WAKE_UP);
+               ret = 0;
+       }
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return ret;
+}
+
+static int
+usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
+{
+       struct usba_udc *udc = to_usba_udc(gadget);
+       unsigned long flags;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       if (is_selfpowered)
+               udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
+       else
+               udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return 0;
+}
+
+static const struct usb_gadget_ops usba_udc_ops = {
+       .get_frame              = usba_udc_get_frame,
+       .wakeup                 = usba_udc_wakeup,
+       .set_selfpowered        = usba_udc_set_selfpowered,
+};
+
+#define EP(nam, idx, maxpkt, maxbk, dma, isoc)                 \
+{                                                              \
+       .ep     = {                                             \
+               .ops            = &usba_ep_ops,                 \
+               .name           = nam,                          \
+               .maxpacket      = maxpkt,                       \
+       },                                                      \
+       .udc            = &the_udc,                             \
+       .queue          = LIST_HEAD_INIT(usba_ep[idx].queue),   \
+       .fifo_size      = maxpkt,                               \
+       .nr_banks       = maxbk,                                \
+       .index          = idx,                                  \
+       .can_dma        = dma,                                  \
+       .can_isoc       = isoc,                                 \
+}
+
+static struct usba_ep usba_ep[] = {
+       EP("ep0", 0, 64, 1, 0, 0),
+       EP("ep1in-bulk", 1, 512, 2, 1, 1),
+       EP("ep2out-bulk", 2, 512, 2, 1, 1),
+       EP("ep3in-int", 3, 64, 3, 1, 0),
+       EP("ep4out-int", 4, 64, 3, 1, 0),
+       EP("ep5in-iso", 5, 1024, 3, 1, 1),
+       EP("ep6out-iso", 6, 1024, 3, 1, 1),
+};
+#undef EP
+
+static struct usb_endpoint_descriptor usba_ep0_desc = {
+       .bLength = USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType = USB_DT_ENDPOINT,
+       .bEndpointAddress = 0,
+       .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+       .wMaxPacketSize = __constant_cpu_to_le16(64),
+       /* FIXME: I have no idea what to put here */
+       .bInterval = 1,
+};
+
+static void nop_release(struct device *dev)
+{
+
+}
+
+static struct usba_udc the_udc = {
+       .gadget = {
+               .ops            = &usba_udc_ops,
+               .ep0            = &usba_ep[0].ep,
+               .ep_list        = LIST_HEAD_INIT(the_udc.gadget.ep_list),
+               .is_dualspeed   = 1,
+               .name           = "atmel_usba_udc",
+               .dev    = {
+                       .bus_id         = "gadget",
+                       .release        = nop_release,
+               },
+       },
+
+       .lock   = SPIN_LOCK_UNLOCKED,
+};
+
+/*
+ * Called with interrupts disabled and udc->lock held.
+ */
+static void reset_all_endpoints(struct usba_udc *udc)
+{
+       struct usba_ep *ep;
+       struct usba_request *req, *tmp_req;
+
+       usba_writel(udc, EPT_RST, ~0UL);
+
+       ep = to_usba_ep(udc->gadget.ep0);
+       list_for_each_entry_safe(req, tmp_req, &ep->queue, queue) {
+               list_del_init(&req->queue);
+               request_complete(ep, req, -ECONNRESET);
+       }
+
+       list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+               if (ep->desc) {
+                       spin_unlock(&udc->lock);
+                       usba_ep_disable(&ep->ep);
+                       spin_lock(&udc->lock);
+               }
+       }
+}
+
+static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex)
+{
+       struct usba_ep *ep;
+
+       if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
+               return to_usba_ep(udc->gadget.ep0);
+
+       list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
+               u8 bEndpointAddress;
+
+               if (!ep->desc)
+                       continue;
+               bEndpointAddress = ep->desc->bEndpointAddress;
+               if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
+                       continue;
+               if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
+                               == (wIndex & USB_ENDPOINT_NUMBER_MASK))
+                       return ep;
+       }
+
+       return NULL;
+}
+
+/* Called with interrupts disabled and udc->lock held */
+static inline void set_protocol_stall(struct usba_udc *udc, struct usba_ep *ep)
+{
+       usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+       ep->state = WAIT_FOR_SETUP;
+}
+
+static inline int is_stalled(struct usba_udc *udc, struct usba_ep *ep)
+{
+       if (usba_ep_readl(ep, STA) & USBA_FORCE_STALL)
+               return 1;
+       return 0;
+}
+
+static inline void set_address(struct usba_udc *udc, unsigned int addr)
+{
+       u32 regval;
+
+       DBG(DBG_BUS, "setting address %u...\n", addr);
+       regval = usba_readl(udc, CTRL);
+       regval = USBA_BFINS(DEV_ADDR, addr, regval);
+       usba_writel(udc, CTRL, regval);
+}
+
+static int do_test_mode(struct usba_udc *udc)
+{
+       static const char test_packet_buffer[] = {
+               /* JKJKJKJK * 9 */
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               /* JJKKJJKK * 8 */
+               0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+               /* JJKKJJKK * 8 */
+               0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
+               /* JJJJJJJKKKKKKK * 8 */
+               0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+               0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+               /* JJJJJJJK * 8 */
+               0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD,
+               /* {JKKKKKKK * 10}, JK */
+               0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E
+       };
+       struct usba_ep *ep;
+       struct device *dev = &udc->pdev->dev;
+       int test_mode;
+
+       test_mode = udc->test_mode;
+
+       /* Start from a clean slate */
+       reset_all_endpoints(udc);
+
+       switch (test_mode) {
+       case 0x0100:
+               /* Test_J */
+               usba_writel(udc, TST, USBA_TST_J_MODE);
+               dev_info(dev, "Entering Test_J mode...\n");
+               break;
+       case 0x0200:
+               /* Test_K */
+               usba_writel(udc, TST, USBA_TST_K_MODE);
+               dev_info(dev, "Entering Test_K mode...\n");
+               break;
+       case 0x0300:
+               /*
+                * Test_SE0_NAK: Force high-speed mode and set up ep0
+                * for Bulk IN transfers
+                */
+               ep = &usba_ep[0];
+               usba_writel(udc, TST,
+                               USBA_BF(SPEED_CFG, USBA_SPEED_CFG_FORCE_HIGH));
+               usba_ep_writel(ep, CFG,
+                               USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
+                               | USBA_EPT_DIR_IN
+                               | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
+                               | USBA_BF(BK_NUMBER, 1));
+               if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
+                       set_protocol_stall(udc, ep);
+                       dev_err(dev, "Test_SE0_NAK: ep0 not mapped\n");
+               } else {
+                       usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+                       dev_info(dev, "Entering Test_SE0_NAK mode...\n");
+               }
+               break;
+       case 0x0400:
+               /* Test_Packet */
+               ep = &usba_ep[0];
+               usba_ep_writel(ep, CFG,
+                               USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
+                               | USBA_EPT_DIR_IN
+                               | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
+                               | USBA_BF(BK_NUMBER, 1));
+               if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
+                       set_protocol_stall(udc, ep);
+                       dev_err(dev, "Test_Packet: ep0 not mapped\n");
+               } else {
+                       usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+                       usba_writel(udc, TST, USBA_TST_PKT_MODE);
+                       copy_to_fifo(ep->fifo, test_packet_buffer,
+                                       sizeof(test_packet_buffer));
+                       usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+                       dev_info(dev, "Entering Test_Packet mode...\n");
+               }
+               break;
+       default:
+               dev_err(dev, "Invalid test mode: 0x%04x\n", test_mode);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Avoid overly long expressions */
+static inline bool feature_is_dev_remote_wakeup(struct usb_ctrlrequest *crq)
+{
+       if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP))
+               return true;
+       return false;
+}
+
+static inline bool feature_is_dev_test_mode(struct usb_ctrlrequest *crq)
+{
+       if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_TEST_MODE))
+               return true;
+       return false;
+}
+
+static inline bool feature_is_ep_halt(struct usb_ctrlrequest *crq)
+{
+       if (crq->wValue == __constant_cpu_to_le16(USB_ENDPOINT_HALT))
+               return true;
+       return false;
+}
+
+static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
+               struct usb_ctrlrequest *crq)
+{
+       int retval = 0;;
+
+       switch (crq->bRequest) {
+       case USB_REQ_GET_STATUS: {
+               u16 status;
+
+               if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) {
+                       status = cpu_to_le16(udc->devstatus);
+               } else if (crq->bRequestType
+                               == (USB_DIR_IN | USB_RECIP_INTERFACE)) {
+                       status = __constant_cpu_to_le16(0);
+               } else if (crq->bRequestType
+                               == (USB_DIR_IN | USB_RECIP_ENDPOINT)) {
+                       struct usba_ep *target;
+
+                       target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+                       if (!target)
+                               goto stall;
+
+                       status = 0;
+                       if (is_stalled(udc, target))
+                               status |= __constant_cpu_to_le16(1);
+               } else
+                       goto delegate;
+
+               /* Write directly to the FIFO. No queueing is done. */
+               if (crq->wLength != __constant_cpu_to_le16(sizeof(status)))
+                       goto stall;
+               ep->state = DATA_STAGE_IN;
+               __raw_writew(status, ep->fifo);
+               usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+               break;
+       }
+
+       case USB_REQ_CLEAR_FEATURE: {
+               if (crq->bRequestType == USB_RECIP_DEVICE) {
+                       if (feature_is_dev_remote_wakeup(crq))
+                               udc->devstatus
+                                       &= ~(1 << USB_DEVICE_REMOTE_WAKEUP);
+                       else
+                               /* Can't CLEAR_FEATURE TEST_MODE */
+                               goto stall;
+               } else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+                       struct usba_ep *target;
+
+                       if (crq->wLength != __constant_cpu_to_le16(0)
+                                       || !feature_is_ep_halt(crq))
+                               goto stall;
+                       target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+                       if (!target)
+                               goto stall;
+
+                       usba_ep_writel(target, CLR_STA, USBA_FORCE_STALL);
+                       if (target->index != 0)
+                               usba_ep_writel(target, CLR_STA,
+                                               USBA_TOGGLE_CLR);
+               } else {
+                       goto delegate;
+               }
+
+               send_status(udc, ep);
+               break;
+       }
+
+       case USB_REQ_SET_FEATURE: {
+               if (crq->bRequestType == USB_RECIP_DEVICE) {
+                       if (feature_is_dev_test_mode(crq)) {
+                               send_status(udc, ep);
+                               ep->state = STATUS_STAGE_TEST;
+                               udc->test_mode = le16_to_cpu(crq->wIndex);
+                               return 0;
+                       } else if (feature_is_dev_remote_wakeup(crq)) {
+                               udc->devstatus |= 1 << USB_DEVICE_REMOTE_WAKEUP;
+                       } else {
+                               goto stall;
+                       }
+               } else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+                       struct usba_ep *target;
+
+                       if (crq->wLength != __constant_cpu_to_le16(0)
+                                       || !feature_is_ep_halt(crq))
+                               goto stall;
+
+                       target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+                       if (!target)
+                               goto stall;
+
+                       usba_ep_writel(target, SET_STA, USBA_FORCE_STALL);
+               } else
+                       goto delegate;
+
+               send_status(udc, ep);
+               break;
+       }
+
+       case USB_REQ_SET_ADDRESS:
+               if (crq->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
+                       goto delegate;
+
+               set_address(udc, le16_to_cpu(crq->wValue));
+               send_status(udc, ep);
+               ep->state = STATUS_STAGE_ADDR;
+               break;
+
+       default:
+delegate:
+               spin_unlock(&udc->lock);
+               retval = udc->driver->setup(&udc->gadget, crq);
+               spin_lock(&udc->lock);
+       }
+
+       return retval;
+
+stall:
+       printk(KERN_ERR
+               "udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, "
+               "halting endpoint...\n",
+               ep->ep.name, crq->bRequestType, crq->bRequest,
+               le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex),
+               le16_to_cpu(crq->wLength));
+       set_protocol_stall(udc, ep);
+       return -1;
+}
+
+static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+       struct usba_request *req;
+       u32 epstatus;
+       u32 epctrl;
+
+restart:
+       epstatus = usba_ep_readl(ep, STA);
+       epctrl = usba_ep_readl(ep, CTL);
+
+       DBG(DBG_INT, "%s [%d]: s/%08x c/%08x\n",
+                       ep->ep.name, ep->state, epstatus, epctrl);
+
+       req = NULL;
+       if (!list_empty(&ep->queue))
+               req = list_entry(ep->queue.next,
+                                struct usba_request, queue);
+
+       if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+               if (req->submitted)
+                       next_fifo_transaction(ep, req);
+               else
+                       submit_request(ep, req);
+
+               if (req->last_transaction) {
+                       usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+                       usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+               }
+               goto restart;
+       }
+       if ((epstatus & epctrl) & USBA_TX_COMPLETE) {
+               usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE);
+
+               switch (ep->state) {
+               case DATA_STAGE_IN:
+                       usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+                       usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+                       ep->state = STATUS_STAGE_OUT;
+                       break;
+               case STATUS_STAGE_ADDR:
+                       /* Activate our new address */
+                       usba_writel(udc, CTRL, (usba_readl(udc, CTRL)
+                                               | USBA_FADDR_EN));
+                       usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+                       ep->state = WAIT_FOR_SETUP;
+                       break;
+               case STATUS_STAGE_IN:
+                       if (req) {
+                               list_del_init(&req->queue);
+                               request_complete(ep, req, 0);
+                               submit_next_request(ep);
+                       }
+                       usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+                       ep->state = WAIT_FOR_SETUP;
+                       break;
+               case STATUS_STAGE_TEST:
+                       usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+                       ep->state = WAIT_FOR_SETUP;
+                       if (do_test_mode(udc))
+                               set_protocol_stall(udc, ep);
+                       break;
+               default:
+                       printk(KERN_ERR
+                               "udc: %s: TXCOMP: Invalid endpoint state %d, "
+                               "halting endpoint...\n",
+                               ep->ep.name, ep->state);
+                       set_protocol_stall(udc, ep);
+                       break;
+               }
+
+               goto restart;
+       }
+       if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+               switch (ep->state) {
+               case STATUS_STAGE_OUT:
+                       usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+                       usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+
+                       if (req) {
+                               list_del_init(&req->queue);
+                               request_complete(ep, req, 0);
+                       }
+                       ep->state = WAIT_FOR_SETUP;
+                       break;
+
+               case DATA_STAGE_OUT:
+                       receive_data(ep);
+                       break;
+
+               default:
+                       usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+                       usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+                       printk(KERN_ERR
+                               "udc: %s: RXRDY: Invalid endpoint state %d, "
+                               "halting endpoint...\n",
+                               ep->ep.name, ep->state);
+                       set_protocol_stall(udc, ep);
+                       break;
+               }
+
+               goto restart;
+       }
+       if (epstatus & USBA_RX_SETUP) {
+               union {
+                       struct usb_ctrlrequest crq;
+                       unsigned long data[2];
+               } crq;
+               unsigned int pkt_len;
+               int ret;
+
+               if (ep->state != WAIT_FOR_SETUP) {
+                       /*
+                        * Didn't expect a SETUP packet at this
+                        * point. Clean up any pending requests (which
+                        * may be successful).
+                        */
+                       int status = -EPROTO;
+
+                       /*
+                        * RXRDY and TXCOMP are dropped when SETUP
+                        * packets arrive.  Just pretend we received
+                        * the status packet.
+                        */
+                       if (ep->state == STATUS_STAGE_OUT
+                                       || ep->state == STATUS_STAGE_IN) {
+                               usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+                               status = 0;
+                       }
+
+                       if (req) {
+                               list_del_init(&req->queue);
+                               request_complete(ep, req, status);
+                       }
+               }
+
+               pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+               DBG(DBG_HW, "Packet length: %u\n", pkt_len);
+               if (pkt_len != sizeof(crq)) {
+                       printk(KERN_WARNING "udc: Invalid packet length %u "
+                               "(expected %lu)\n", pkt_len, sizeof(crq));
+                       set_protocol_stall(udc, ep);
+                       return;
+               }
+
+               DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo);
+               copy_from_fifo(crq.data, ep->fifo, sizeof(crq));
+
+               /* Free up one bank in the FIFO so that we can
+                * generate or receive a reply right away. */
+               usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP);
+
+               /* printk(KERN_DEBUG "setup: %d: %02x.%02x\n",
+                       ep->state, crq.crq.bRequestType,
+                       crq.crq.bRequest); */
+
+               if (crq.crq.bRequestType & USB_DIR_IN) {
+                       /*
+                        * The USB 2.0 spec states that "if wLength is
+                        * zero, there is no data transfer phase."
+                        * However, testusb #14 seems to actually
+                        * expect a data phase even if wLength = 0...
+                        */
+                       ep->state = DATA_STAGE_IN;
+               } else {
+                       if (crq.crq.wLength != __constant_cpu_to_le16(0))
+                               ep->state = DATA_STAGE_OUT;
+                       else
+                               ep->state = STATUS_STAGE_IN;
+               }
+
+               ret = -1;
+               if (ep->index == 0)
+                       ret = handle_ep0_setup(udc, ep, &crq.crq);
+               else {
+                       spin_unlock(&udc->lock);
+                       ret = udc->driver->setup(&udc->gadget, &crq.crq);
+                       spin_lock(&udc->lock);
+               }
+
+               DBG(DBG_BUS, "req %02x.%02x, length %d, state %d, ret %d\n",
+                       crq.crq.bRequestType, crq.crq.bRequest,
+                       le16_to_cpu(crq.crq.wLength), ep->state, ret);
+
+               if (ret < 0) {
+                       /* Let the host know that we failed */
+                       set_protocol_stall(udc, ep);
+               }
+       }
+}
+
+static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+       struct usba_request *req;
+       u32 epstatus;
+       u32 epctrl;
+
+       epstatus = usba_ep_readl(ep, STA);
+       epctrl = usba_ep_readl(ep, CTL);
+
+       DBG(DBG_INT, "%s: interrupt, status: 0x%08x\n", ep->ep.name, epstatus);
+
+       while ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+               DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name);
+
+               if (list_empty(&ep->queue)) {
+                       dev_warn(&udc->pdev->dev, "ep_irq: queue empty\n");
+                       usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+                       return;
+               }
+
+               req = list_entry(ep->queue.next, struct usba_request, queue);
+
+               if (req->using_dma) {
+                       /* Send a zero-length packet */
+                       usba_ep_writel(ep, SET_STA,
+                                       USBA_TX_PK_RDY);
+                       usba_ep_writel(ep, CTL_DIS,
+                                       USBA_TX_PK_RDY);
+                       list_del_init(&req->queue);
+                       submit_next_request(ep);
+                       request_complete(ep, req, 0);
+               } else {
+                       if (req->submitted)
+                               next_fifo_transaction(ep, req);
+                       else
+                               submit_request(ep, req);
+
+                       if (req->last_transaction) {
+                               list_del_init(&req->queue);
+                               submit_next_request(ep);
+                               request_complete(ep, req, 0);
+                       }
+               }
+
+               epstatus = usba_ep_readl(ep, STA);
+               epctrl = usba_ep_readl(ep, CTL);
+       }
+       if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+               DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name);
+               receive_data(ep);
+               usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+       }
+}
+
+static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+       struct usba_request *req;
+       u32 status, control, pending;
+
+       status = usba_dma_readl(ep, STATUS);
+       control = usba_dma_readl(ep, CONTROL);
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+       ep->last_dma_status = status;
+#endif
+       pending = status & control;
+       DBG(DBG_INT | DBG_DMA, "dma irq, s/%#08x, c/%#08x\n", status, control);
+
+       if (status & USBA_DMA_CH_EN) {
+               dev_err(&udc->pdev->dev,
+                       "DMA_CH_EN is set after transfer is finished!\n");
+               dev_err(&udc->pdev->dev,
+                       "status=%#08x, pending=%#08x, control=%#08x\n",
+                       status, pending, control);
+
+               /*
+                * try to pretend nothing happened. We might have to
+                * do something here...
+                */
+       }
+
+       if (list_empty(&ep->queue))
+               /* Might happen if a reset comes along at the right moment */
+               return;
+
+       if (pending & (USBA_DMA_END_TR_ST | USBA_DMA_END_BUF_ST)) {
+               req = list_entry(ep->queue.next, struct usba_request, queue);
+               usba_update_req(ep, req, status);
+
+               list_del_init(&req->queue);
+               submit_next_request(ep);
+               request_complete(ep, req, 0);
+       }
+}
+
+static irqreturn_t usba_udc_irq(int irq, void *devid)
+{
+       struct usba_udc *udc = devid;
+       u32 status;
+       u32 dma_status;
+       u32 ep_status;
+
+       spin_lock(&udc->lock);
+
+       status = usba_readl(udc, INT_STA);
+       DBG(DBG_INT, "irq, status=%#08x\n", status);
+
+       if (status & USBA_DET_SUSPEND) {
+               usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
+               DBG(DBG_BUS, "Suspend detected\n");
+               if (udc->gadget.speed != USB_SPEED_UNKNOWN
+                               && udc->driver && udc->driver->suspend) {
+                       spin_unlock(&udc->lock);
+                       udc->driver->suspend(&udc->gadget);
+                       spin_lock(&udc->lock);
+               }
+       }
+
+       if (status & USBA_WAKE_UP) {
+               usba_writel(udc, INT_CLR, USBA_WAKE_UP);
+               DBG(DBG_BUS, "Wake Up CPU detected\n");
+       }
+
+       if (status & USBA_END_OF_RESUME) {
+               usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
+               DBG(DBG_BUS, "Resume detected\n");
+               if (udc->gadget.speed != USB_SPEED_UNKNOWN
+                               && udc->driver && udc->driver->resume) {
+                       spin_unlock(&udc->lock);
+                       udc->driver->resume(&udc->gadget);
+                       spin_lock(&udc->lock);
+               }
+       }
+
+       dma_status = USBA_BFEXT(DMA_INT, status);
+       if (dma_status) {
+               int i;
+
+               for (i = 1; i < USBA_NR_ENDPOINTS; i++)
+                       if (dma_status & (1 << i))
+                               usba_dma_irq(udc, &usba_ep[i]);
+       }
+
+       ep_status = USBA_BFEXT(EPT_INT, status);
+       if (ep_status) {
+               int i;
+
+               for (i = 0; i < USBA_NR_ENDPOINTS; i++)
+                       if (ep_status & (1 << i)) {
+                               if (ep_is_control(&usba_ep[i]))
+                                       usba_control_irq(udc, &usba_ep[i]);
+                               else
+                                       usba_ep_irq(udc, &usba_ep[i]);
+                       }
+       }
+
+       if (status & USBA_END_OF_RESET) {
+               struct usba_ep *ep0;
+
+               usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
+               reset_all_endpoints(udc);
+
+               if (status & USBA_HIGH_SPEED) {
+                       DBG(DBG_BUS, "High-speed bus reset detected\n");
+                       udc->gadget.speed = USB_SPEED_HIGH;
+               } else {
+                       DBG(DBG_BUS, "Full-speed bus reset detected\n");
+                       udc->gadget.speed = USB_SPEED_FULL;
+               }
+
+               ep0 = &usba_ep[0];
+               ep0->desc = &usba_ep0_desc;
+               ep0->state = WAIT_FOR_SETUP;
+               usba_ep_writel(ep0, CFG,
+                               (USBA_BF(EPT_SIZE, EP0_EPT_SIZE)
+                               | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL)
+                               | USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
+               usba_ep_writel(ep0, CTL_ENB,
+                               USBA_EPT_ENABLE | USBA_RX_SETUP);
+               usba_writel(udc, INT_ENB,
+                               (usba_readl(udc, INT_ENB)
+                               | USBA_BF(EPT_INT, 1)
+                               | USBA_DET_SUSPEND
+                               | USBA_END_OF_RESUME));
+
+               if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED))
+                       dev_warn(&udc->pdev->dev,
+                                "WARNING: EP0 configuration is invalid!\n");
+       }
+
+       spin_unlock(&udc->lock);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t usba_vbus_irq(int irq, void *devid)
+{
+       struct usba_udc *udc = devid;
+       int vbus;
+
+       /* debounce */
+       udelay(10);
+
+       spin_lock(&udc->lock);
+
+       /* May happen if Vbus pin toggles during probe() */
+       if (!udc->driver)
+               goto out;
+
+       vbus = gpio_get_value(udc->vbus_pin);
+       if (vbus != udc->vbus_prev) {
+               if (vbus) {
+                       usba_writel(udc, CTRL, USBA_EN_USBA);
+                       usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+               } else {
+                       udc->gadget.speed = USB_SPEED_UNKNOWN;
+                       reset_all_endpoints(udc);
+                       usba_writel(udc, CTRL, 0);
+                       spin_unlock(&udc->lock);
+                       udc->driver->disconnect(&udc->gadget);
+                       spin_lock(&udc->lock);
+               }
+               udc->vbus_prev = vbus;
+       }
+
+out:
+       spin_unlock(&udc->lock);
+
+       return IRQ_HANDLED;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+       struct usba_udc *udc = &the_udc;
+       unsigned long flags;
+       int ret;
+
+       if (!udc->pdev)
+               return -ENODEV;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       if (udc->driver) {
+               spin_unlock_irqrestore(&udc->lock, flags);
+               return -EBUSY;
+       }
+
+       udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
+       udc->driver = driver;
+       udc->gadget.dev.driver = &driver->driver;
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       clk_enable(udc->pclk);
+       clk_enable(udc->hclk);
+
+       ret = driver->bind(&udc->gadget);
+       if (ret) {
+               DBG(DBG_ERR, "Could not bind to driver %s: error %d\n",
+                       driver->driver.name, ret);
+               goto err_driver_bind;
+       }
+
+       DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name);
+
+       udc->vbus_prev = 0;
+       if (udc->vbus_pin != -1)
+               enable_irq(gpio_to_irq(udc->vbus_pin));
+
+       /* If Vbus is present, enable the controller and wait for reset */
+       spin_lock_irqsave(&udc->lock, flags);
+       if (vbus_is_present(udc) && udc->vbus_prev == 0) {
+               usba_writel(udc, CTRL, USBA_EN_USBA);
+               usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+       }
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return 0;
+
+err_driver_bind:
+       udc->driver = NULL;
+       udc->gadget.dev.driver = NULL;
+       return ret;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+       struct usba_udc *udc = &the_udc;
+       unsigned long flags;
+
+       if (!udc->pdev)
+               return -ENODEV;
+       if (driver != udc->driver)
+               return -EINVAL;
+
+       if (udc->vbus_pin != -1)
+               disable_irq(gpio_to_irq(udc->vbus_pin));
+
+       spin_lock_irqsave(&udc->lock, flags);
+       udc->gadget.speed = USB_SPEED_UNKNOWN;
+       reset_all_endpoints(udc);
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       /* This will also disable the DP pullup */
+       usba_writel(udc, CTRL, 0);
+
+       driver->unbind(&udc->gadget);
+       udc->gadget.dev.driver = NULL;
+       udc->driver = NULL;
+
+       clk_disable(udc->hclk);
+       clk_disable(udc->pclk);
+
+       DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name);
+
+       return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+static int __init usba_udc_probe(struct platform_device *pdev)
+{
+       struct usba_platform_data *pdata = pdev->dev.platform_data;
+       struct resource *regs, *fifo;
+       struct clk *pclk, *hclk;
+       struct usba_udc *udc = &the_udc;
+       int irq, ret, i;
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID);
+       fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID);
+       if (!regs || !fifo)
+               return -ENXIO;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       pclk = clk_get(&pdev->dev, "pclk");
+       if (IS_ERR(pclk))
+               return PTR_ERR(pclk);
+       hclk = clk_get(&pdev->dev, "hclk");
+       if (IS_ERR(hclk)) {
+               ret = PTR_ERR(hclk);
+               goto err_get_hclk;
+       }
+
+       udc->pdev = pdev;
+       udc->pclk = pclk;
+       udc->hclk = hclk;
+       udc->vbus_pin = -1;
+
+       ret = -ENOMEM;
+       udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+       if (!udc->regs) {
+               dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n");
+               goto err_map_regs;
+       }
+       dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n",
+                (unsigned long)regs->start, udc->regs);
+       udc->fifo = ioremap(fifo->start, fifo->end - fifo->start + 1);
+       if (!udc->fifo) {
+               dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n");
+               goto err_map_fifo;
+       }
+       dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n",
+                (unsigned long)fifo->start, udc->fifo);
+
+       device_initialize(&udc->gadget.dev);
+       udc->gadget.dev.parent = &pdev->dev;
+       udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+       platform_set_drvdata(pdev, udc);
+
+       /* Make sure we start from a clean slate */
+       clk_enable(pclk);
+       usba_writel(udc, CTRL, 0);
+       clk_disable(pclk);
+
+       INIT_LIST_HEAD(&usba_ep[0].ep.ep_list);
+       usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0);
+       usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0);
+       usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0);
+       for (i = 1; i < ARRAY_SIZE(usba_ep); i++) {
+               struct usba_ep *ep = &usba_ep[i];
+
+               ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
+               ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
+               ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
+
+               list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+       }
+
+       ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc);
+       if (ret) {
+               dev_err(&pdev->dev, "Cannot request irq %d (error %d)\n",
+                       irq, ret);
+               goto err_request_irq;
+       }
+       udc->irq = irq;
+
+       ret = device_add(&udc->gadget.dev);
+       if (ret) {
+               dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret);
+               goto err_device_add;
+       }
+
+       if (pdata && pdata->vbus_pin != GPIO_PIN_NONE) {
+               if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
+                       udc->vbus_pin = pdata->vbus_pin;
+
+                       ret = request_irq(gpio_to_irq(udc->vbus_pin),
+                                       usba_vbus_irq, 0,
+                                       "atmel_usba_udc", udc);
+                       if (ret) {
+                               gpio_free(udc->vbus_pin);
+                               udc->vbus_pin = -1;
+                               dev_warn(&udc->pdev->dev,
+                                        "failed to request vbus irq; "
+                                        "assuming always on\n");
+                       } else {
+                               disable_irq(gpio_to_irq(udc->vbus_pin));
+                       }
+               }
+       }
+
+       usba_init_debugfs(udc);
+       for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
+               usba_ep_init_debugfs(udc, &usba_ep[i]);
+
+       return 0;
+
+err_device_add:
+       free_irq(irq, udc);
+err_request_irq:
+       iounmap(udc->fifo);
+err_map_fifo:
+       iounmap(udc->regs);
+err_map_regs:
+       clk_put(hclk);
+err_get_hclk:
+       clk_put(pclk);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return ret;
+}
+
+static int __exit usba_udc_remove(struct platform_device *pdev)
+{
+       struct usba_udc *udc;
+       int i;
+
+       udc = platform_get_drvdata(pdev);
+
+       for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
+               usba_ep_cleanup_debugfs(&usba_ep[i]);
+       usba_cleanup_debugfs(udc);
+
+       if (udc->vbus_pin != -1)
+               gpio_free(udc->vbus_pin);
+
+       free_irq(udc->irq, udc);
+       iounmap(udc->fifo);
+       iounmap(udc->regs);
+       clk_put(udc->hclk);
+       clk_put(udc->pclk);
+
+       device_unregister(&udc->gadget.dev);
+
+       return 0;
+}
+
+static struct platform_driver udc_driver = {
+       .remove         = __exit_p(usba_udc_remove),
+       .driver         = {
+               .name           = "atmel_usba_udc",
+       },
+};
+
+static int __init udc_init(void)
+{
+       return platform_driver_probe(&udc_driver, usba_udc_probe);
+}
+module_init(udc_init);
+
+static void __exit udc_exit(void)
+{
+       platform_driver_unregister(&udc_driver);
+}
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION("Atmel USBA UDC driver");
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h
new file mode 100644 (file)
index 0000000..a68304e
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * Driver for the Atmel USBA high speed USB device controller
+ *
+ * Copyright (C) 2005-2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __LINUX_USB_GADGET_USBA_UDC_H__
+#define __LINUX_USB_GADGET_USBA_UDC_H__
+
+/* USB register offsets */
+#define USBA_CTRL                              0x0000
+#define USBA_FNUM                              0x0004
+#define USBA_INT_ENB                           0x0010
+#define USBA_INT_STA                           0x0014
+#define USBA_INT_CLR                           0x0018
+#define USBA_EPT_RST                           0x001c
+#define USBA_TST                               0x00e0
+
+/* USB endpoint register offsets */
+#define USBA_EPT_CFG                           0x0000
+#define USBA_EPT_CTL_ENB                       0x0004
+#define USBA_EPT_CTL_DIS                       0x0008
+#define USBA_EPT_CTL                           0x000c
+#define USBA_EPT_SET_STA                       0x0014
+#define USBA_EPT_CLR_STA                       0x0018
+#define USBA_EPT_STA                           0x001c
+
+/* USB DMA register offsets */
+#define USBA_DMA_NXT_DSC                       0x0000
+#define USBA_DMA_ADDRESS                       0x0004
+#define USBA_DMA_CONTROL                       0x0008
+#define USBA_DMA_STATUS                                0x000c
+
+/* Bitfields in CTRL */
+#define USBA_DEV_ADDR_OFFSET                   0
+#define USBA_DEV_ADDR_SIZE                     7
+#define USBA_FADDR_EN                          (1 <<  7)
+#define USBA_EN_USBA                           (1 <<  8)
+#define USBA_DETACH                            (1 <<  9)
+#define USBA_REMOTE_WAKE_UP                    (1 << 10)
+
+/* Bitfields in FNUM */
+#define USBA_MICRO_FRAME_NUM_OFFSET            0
+#define USBA_MICRO_FRAME_NUM_SIZE              3
+#define USBA_FRAME_NUMBER_OFFSET               3
+#define USBA_FRAME_NUMBER_SIZE                 11
+#define USBA_FRAME_NUM_ERROR                   (1 << 31)
+
+/* Bitfields in INT_ENB/INT_STA/INT_CLR */
+#define USBA_HIGH_SPEED                                (1 <<  0)
+#define USBA_DET_SUSPEND                       (1 <<  1)
+#define USBA_MICRO_SOF                         (1 <<  2)
+#define USBA_SOF                               (1 <<  3)
+#define USBA_END_OF_RESET                      (1 <<  4)
+#define USBA_WAKE_UP                           (1 <<  5)
+#define USBA_END_OF_RESUME                     (1 <<  6)
+#define USBA_UPSTREAM_RESUME                   (1 <<  7)
+#define USBA_EPT_INT_OFFSET                    8
+#define USBA_EPT_INT_SIZE                      16
+#define USBA_DMA_INT_OFFSET                    24
+#define USBA_DMA_INT_SIZE                      8
+
+/* Bitfields in EPT_RST */
+#define USBA_RST_OFFSET                                0
+#define USBA_RST_SIZE                          16
+
+/* Bitfields in USBA_TST */
+#define USBA_SPEED_CFG_OFFSET                  0
+#define USBA_SPEED_CFG_SIZE                    2
+#define USBA_TST_J_MODE                                (1 <<  2)
+#define USBA_TST_K_MODE                                (1 <<  3)
+#define USBA_TST_PKT_MODE                      (1 <<  4)
+#define USBA_OPMODE2                           (1 <<  5)
+
+/* Bitfields in EPT_CFG */
+#define USBA_EPT_SIZE_OFFSET                   0
+#define USBA_EPT_SIZE_SIZE                     3
+#define USBA_EPT_DIR_IN                                (1 <<  3)
+#define USBA_EPT_TYPE_OFFSET                   4
+#define USBA_EPT_TYPE_SIZE                     2
+#define USBA_BK_NUMBER_OFFSET                  6
+#define USBA_BK_NUMBER_SIZE                    2
+#define USBA_NB_TRANS_OFFSET                   8
+#define USBA_NB_TRANS_SIZE                     2
+#define USBA_EPT_MAPPED                                (1 << 31)
+
+/* Bitfields in EPT_CTL/EPT_CTL_ENB/EPT_CTL_DIS */
+#define USBA_EPT_ENABLE                                (1 <<  0)
+#define USBA_AUTO_VALID                                (1 <<  1)
+#define USBA_INTDIS_DMA                                (1 <<  3)
+#define USBA_NYET_DIS                          (1 <<  4)
+#define USBA_DATAX_RX                          (1 <<  6)
+#define USBA_MDATA_RX                          (1 <<  7)
+/* Bits 8-15 and 31 enable interrupts for respective bits in EPT_STA */
+#define USBA_BUSY_BANK_IE                      (1 << 18)
+
+/* Bitfields in EPT_SET_STA/EPT_CLR_STA/EPT_STA */
+#define USBA_FORCE_STALL                       (1 <<  5)
+#define USBA_TOGGLE_CLR                                (1 <<  6)
+#define USBA_TOGGLE_SEQ_OFFSET                 6
+#define USBA_TOGGLE_SEQ_SIZE                   2
+#define USBA_ERR_OVFLW                         (1 <<  8)
+#define USBA_RX_BK_RDY                         (1 <<  9)
+#define USBA_KILL_BANK                         (1 <<  9)
+#define USBA_TX_COMPLETE                       (1 << 10)
+#define USBA_TX_PK_RDY                         (1 << 11)
+#define USBA_ISO_ERR_TRANS                     (1 << 11)
+#define USBA_RX_SETUP                          (1 << 12)
+#define USBA_ISO_ERR_FLOW                      (1 << 12)
+#define USBA_STALL_SENT                                (1 << 13)
+#define USBA_ISO_ERR_CRC                       (1 << 13)
+#define USBA_ISO_ERR_NBTRANS                   (1 << 13)
+#define USBA_NAK_IN                            (1 << 14)
+#define USBA_ISO_ERR_FLUSH                     (1 << 14)
+#define USBA_NAK_OUT                           (1 << 15)
+#define USBA_CURRENT_BANK_OFFSET               16
+#define USBA_CURRENT_BANK_SIZE                 2
+#define USBA_BUSY_BANKS_OFFSET                 18
+#define USBA_BUSY_BANKS_SIZE                   2
+#define USBA_BYTE_COUNT_OFFSET                 20
+#define USBA_BYTE_COUNT_SIZE                   11
+#define USBA_SHORT_PACKET                      (1 << 31)
+
+/* Bitfields in DMA_CONTROL */
+#define USBA_DMA_CH_EN                         (1 <<  0)
+#define USBA_DMA_LINK                          (1 <<  1)
+#define USBA_DMA_END_TR_EN                     (1 <<  2)
+#define USBA_DMA_END_BUF_EN                    (1 <<  3)
+#define USBA_DMA_END_TR_IE                     (1 <<  4)
+#define USBA_DMA_END_BUF_IE                    (1 <<  5)
+#define USBA_DMA_DESC_LOAD_IE                  (1 <<  6)
+#define USBA_DMA_BURST_LOCK                    (1 <<  7)
+#define USBA_DMA_BUF_LEN_OFFSET                        16
+#define USBA_DMA_BUF_LEN_SIZE                  16
+
+/* Bitfields in DMA_STATUS */
+#define USBA_DMA_CH_ACTIVE                     (1 <<  1)
+#define USBA_DMA_END_TR_ST                     (1 <<  4)
+#define USBA_DMA_END_BUF_ST                    (1 <<  5)
+#define USBA_DMA_DESC_LOAD_ST                  (1 <<  6)
+
+/* Constants for SPEED_CFG */
+#define USBA_SPEED_CFG_NORMAL                  0
+#define USBA_SPEED_CFG_FORCE_HIGH              2
+#define USBA_SPEED_CFG_FORCE_FULL              3
+
+/* Constants for EPT_SIZE */
+#define USBA_EPT_SIZE_8                                0
+#define USBA_EPT_SIZE_16                       1
+#define USBA_EPT_SIZE_32                       2
+#define USBA_EPT_SIZE_64                       3
+#define USBA_EPT_SIZE_128                      4
+#define USBA_EPT_SIZE_256                      5
+#define USBA_EPT_SIZE_512                      6
+#define USBA_EPT_SIZE_1024                     7
+
+/* Constants for EPT_TYPE */
+#define USBA_EPT_TYPE_CONTROL                  0
+#define USBA_EPT_TYPE_ISO                      1
+#define USBA_EPT_TYPE_BULK                     2
+#define USBA_EPT_TYPE_INT                      3
+
+/* Constants for BK_NUMBER */
+#define USBA_BK_NUMBER_ZERO                    0
+#define USBA_BK_NUMBER_ONE                     1
+#define USBA_BK_NUMBER_DOUBLE                  2
+#define USBA_BK_NUMBER_TRIPLE                  3
+
+/* Bit manipulation macros */
+#define USBA_BF(name, value)                                   \
+       (((value) & ((1 << USBA_##name##_SIZE) - 1))            \
+        << USBA_##name##_OFFSET)
+#define USBA_BFEXT(name, value)                                        \
+       (((value) >> USBA_##name##_OFFSET)                      \
+        & ((1 << USBA_##name##_SIZE) - 1))
+#define USBA_BFINS(name, value, old)                           \
+       (((old) & ~(((1 << USBA_##name##_SIZE) - 1)             \
+                   << USBA_##name##_OFFSET))                   \
+        | USBA_BF(name, value))
+
+/* Register access macros */
+#define usba_readl(udc, reg)                                   \
+       __raw_readl((udc)->regs + USBA_##reg)
+#define usba_writel(udc, reg, value)                           \
+       __raw_writel((value), (udc)->regs + USBA_##reg)
+#define usba_ep_readl(ep, reg)                                 \
+       __raw_readl((ep)->ep_regs + USBA_EPT_##reg)
+#define usba_ep_writel(ep, reg, value)                         \
+       __raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg)
+#define usba_dma_readl(ep, reg)                                        \
+       __raw_readl((ep)->dma_regs + USBA_DMA_##reg)
+#define usba_dma_writel(ep, reg, value)                                \
+       __raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg)
+
+/* Calculate base address for a given endpoint or DMA controller */
+#define USBA_EPT_BASE(x)       (0x100 + (x) * 0x20)
+#define USBA_DMA_BASE(x)       (0x300 + (x) * 0x10)
+#define USBA_FIFO_BASE(x)      ((x) << 16)
+
+/* Synth parameters */
+#define USBA_NR_ENDPOINTS      7
+
+#define EP0_FIFO_SIZE          64
+#define EP0_EPT_SIZE           USBA_EPT_SIZE_64
+#define EP0_NR_BANKS           1
+
+/*
+ * REVISIT: Try to eliminate this value. Can we rely on req->mapped to
+ * provide this information?
+ */
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+#define FIFO_IOMEM_ID  0
+#define CTRL_IOMEM_ID  1
+
+#ifdef DEBUG
+#define DBG_ERR                0x0001  /* report all error returns */
+#define DBG_HW         0x0002  /* debug hardware initialization */
+#define DBG_GADGET     0x0004  /* calls to/from gadget driver */
+#define DBG_INT                0x0008  /* interrupts */
+#define DBG_BUS                0x0010  /* report changes in bus state */
+#define DBG_QUEUE      0x0020  /* debug request queue processing */
+#define DBG_FIFO       0x0040  /* debug FIFO contents */
+#define DBG_DMA                0x0080  /* debug DMA handling */
+#define DBG_REQ                0x0100  /* print out queued request length */
+#define DBG_ALL                0xffff
+#define DBG_NONE       0x0000
+
+#define DEBUG_LEVEL    (DBG_ERR)
+#define DBG(level, fmt, ...)                                   \
+       do {                                                    \
+               if ((level) & DEBUG_LEVEL)                      \
+                       printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__); \
+       } while (0)
+#else
+#define DBG(level, fmt...)
+#endif
+
+enum usba_ctrl_state {
+       WAIT_FOR_SETUP,
+       DATA_STAGE_IN,
+       DATA_STAGE_OUT,
+       STATUS_STAGE_IN,
+       STATUS_STAGE_OUT,
+       STATUS_STAGE_ADDR,
+       STATUS_STAGE_TEST,
+};
+/*
+  EP_STATE_IDLE,
+  EP_STATE_SETUP,
+  EP_STATE_IN_DATA,
+  EP_STATE_OUT_DATA,
+  EP_STATE_SET_ADDR_STATUS,
+  EP_STATE_RX_STATUS,
+  EP_STATE_TX_STATUS,
+  EP_STATE_HALT,
+*/
+
+struct usba_dma_desc {
+       dma_addr_t next;
+       dma_addr_t addr;
+       u32 ctrl;
+};
+
+struct usba_ep {
+       int                                     state;
+       void __iomem                            *ep_regs;
+       void __iomem                            *dma_regs;
+       void __iomem                            *fifo;
+       struct usb_ep                           ep;
+       struct usba_udc                         *udc;
+
+       struct list_head                        queue;
+       const struct usb_endpoint_descriptor    *desc;
+
+       u16                                     fifo_size;
+       u8                                      nr_banks;
+       u8                                      index;
+       unsigned int                            can_dma:1;
+       unsigned int                            can_isoc:1;
+       unsigned int                            is_isoc:1;
+       unsigned int                            is_in:1;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+       u32                                     last_dma_status;
+       struct dentry                           *debugfs_dir;
+       struct dentry                           *debugfs_queue;
+       struct dentry                           *debugfs_dma_status;
+       struct dentry                           *debugfs_state;
+#endif
+};
+
+struct usba_request {
+       struct usb_request                      req;
+       struct list_head                        queue;
+
+       u32                                     ctrl;
+
+       unsigned int                            submitted:1;
+       unsigned int                            last_transaction:1;
+       unsigned int                            using_dma:1;
+       unsigned int                            mapped:1;
+};
+
+struct usba_udc {
+       /* Protect hw registers from concurrent modifications */
+       spinlock_t lock;
+
+       void __iomem *regs;
+       void __iomem *fifo;
+
+       struct usb_gadget gadget;
+       struct usb_gadget_driver *driver;
+       struct platform_device *pdev;
+       int irq;
+       int vbus_pin;
+       struct clk *pclk;
+       struct clk *hclk;
+
+       u16 devstatus;
+
+       u16 test_mode;
+       int vbus_prev;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+       struct dentry *debugfs_root;
+       struct dentry *debugfs_regs;
+#endif
+};
+
+static inline struct usba_ep *to_usba_ep(struct usb_ep *ep)
+{
+       return container_of(ep, struct usba_ep, ep);
+}
+
+static inline struct usba_request *to_usba_req(struct usb_request *req)
+{
+       return container_of(req, struct usba_request, req);
+}
+
+static inline struct usba_udc *to_usba_udc(struct usb_gadget *gadget)
+{
+       return container_of(gadget, struct usba_udc, gadget);
+}
+
+#define ep_is_control(ep)      ((ep)->index == 0)
+#define ep_is_idle(ep)         ((ep)->state == EP_STATE_IDLE)
+
+#endif /* __LINUX_USB_GADGET_USBA_UDC_H */
index c6760ae..a4e54b2 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/device.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 
 /**
index d008d13..9db2482 100644 (file)
@@ -46,7 +46,7 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/usb.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -962,13 +962,13 @@ static struct platform_driver dummy_udc_driver = {
 
 static int dummy_urb_enqueue (
        struct usb_hcd                  *hcd,
-       struct usb_host_endpoint        *ep,
        struct urb                      *urb,
        gfp_t                           mem_flags
 ) {
        struct dummy    *dum;
        struct urbp     *urbp;
        unsigned long   flags;
+       int             rc;
 
        if (!urb->transfer_buffer && urb->transfer_buffer_length)
                return -EINVAL;
@@ -980,6 +980,11 @@ static int dummy_urb_enqueue (
 
        dum = hcd_to_dummy (hcd);
        spin_lock_irqsave (&dum->lock, flags);
+       rc = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (rc) {
+               kfree(urbp);
+               goto done;
+       }
 
        if (!dum->udev) {
                dum->udev = urb->dev;
@@ -996,36 +1001,35 @@ static int dummy_urb_enqueue (
        if (!timer_pending (&dum->timer))
                mod_timer (&dum->timer, jiffies + 1);
 
-       spin_unlock_irqrestore (&dum->lock, flags);
-       return 0;
+ done:
+       spin_unlock_irqrestore(&dum->lock, flags);
+       return rc;
 }
 
-static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
        struct dummy    *dum;
        unsigned long   flags;
+       int             rc;
 
        /* giveback happens automatically in timer callback,
         * so make sure the callback happens */
        dum = hcd_to_dummy (hcd);
        spin_lock_irqsave (&dum->lock, flags);
-       if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list))
+
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (!rc && dum->rh_state != DUMMY_RH_RUNNING &&
+                       !list_empty(&dum->urbp_list))
                mod_timer (&dum->timer, jiffies);
-       spin_unlock_irqrestore (&dum->lock, flags);
-       return 0;
-}
 
-static void maybe_set_status (struct urb *urb, int status)
-{
-       spin_lock (&urb->lock);
-       if (urb->status == -EINPROGRESS)
-               urb->status = status;
-       spin_unlock (&urb->lock);
+       spin_unlock_irqrestore (&dum->lock, flags);
+       return rc;
 }
 
 /* transfer up to a frame's worth; caller must own lock */
 static int
-transfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit)
+transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
+               int *status)
 {
        struct dummy_request    *req;
 
@@ -1088,24 +1092,20 @@ top:
                 *
                 * partially filling a buffer optionally blocks queue advances
                 * (so completion handlers can clean up the queue) but we don't
-                * need to emulate such data-in-flight.  so we only show part
-                * of the URB_SHORT_NOT_OK effect: completion status.
+                * need to emulate such data-in-flight.
                 */
                if (is_short) {
                        if (host_len == dev_len) {
                                req->req.status = 0;
-                               maybe_set_status (urb, 0);
+                               *status = 0;
                        } else if (to_host) {
                                req->req.status = 0;
                                if (dev_len > host_len)
-                                       maybe_set_status (urb, -EOVERFLOW);
+                                       *status = -EOVERFLOW;
                                else
-                                       maybe_set_status (urb,
-                                               (urb->transfer_flags
-                                                       & URB_SHORT_NOT_OK)
-                                               ? -EREMOTEIO : 0);
+                                       *status = 0;
                        } else if (!to_host) {
-                               maybe_set_status (urb, 0);
+                               *status = 0;
                                if (host_len > dev_len)
                                        req->req.status = -EOVERFLOW;
                                else
@@ -1119,9 +1119,8 @@ top:
                                req->req.status = 0;
                        if (urb->transfer_buffer_length == urb->actual_length
                                        && !(urb->transfer_flags
-                                               & URB_ZERO_PACKET)) {
-                               maybe_set_status (urb, 0);
-                       }
+                                               & URB_ZERO_PACKET))
+                               *status = 0;
                }
 
                /* device side completion --> continuable */
@@ -1137,7 +1136,7 @@ top:
                }
 
                /* host side completion --> terminate */
-               if (urb->status != -EINPROGRESS)
+               if (*status != -EINPROGRESS)
                        break;
 
                /* rescan to continue with any other queued i/o */
@@ -1248,12 +1247,12 @@ restart:
                u8                      address;
                struct dummy_ep         *ep = NULL;
                int                     type;
+               int                     status = -EINPROGRESS;
 
                urb = urbp->urb;
-               if (urb->status != -EINPROGRESS) {
-                       /* likely it was just unlinked */
+               if (urb->unlinked)
                        goto return_urb;
-               else if (dum->rh_state != DUMMY_RH_RUNNING)
+               else if (dum->rh_state != DUMMY_RH_RUNNING)
                        continue;
                type = usb_pipetype (urb->pipe);
 
@@ -1274,7 +1273,7 @@ restart:
                        dev_dbg (dummy_dev(dum),
                                "no ep configured for urb %p\n",
                                urb);
-                       maybe_set_status (urb, -EPROTO);
+                       status = -EPROTO;
                        goto return_urb;
                }
 
@@ -1289,7 +1288,7 @@ restart:
                        /* NOTE: must not be iso! */
                        dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
                                        ep->ep.name, urb);
-                       maybe_set_status (urb, -EPIPE);
+                       status = -EPIPE;
                        goto return_urb;
                }
                /* FIXME make sure both ends agree on maxpacket */
@@ -1307,7 +1306,7 @@ restart:
                        w_value = le16_to_cpu(setup.wValue);
                        if (le16_to_cpu(setup.wLength) !=
                                        urb->transfer_buffer_length) {
-                               maybe_set_status (urb, -EOVERFLOW);
+                               status = -EOVERFLOW;
                                goto return_urb;
                        }
 
@@ -1337,7 +1336,7 @@ restart:
                                if (setup.bRequestType != Dev_Request)
                                        break;
                                dum->address = w_value;
-                               maybe_set_status (urb, 0);
+                               status = 0;
                                dev_dbg (udc_dev(dum), "set_address = %d\n",
                                                w_value);
                                value = 0;
@@ -1364,7 +1363,7 @@ restart:
                                        if (value == 0) {
                                                dum->devstatus |=
                                                        (1 << w_value);
-                                               maybe_set_status (urb, 0);
+                                               status = 0;
                                        }
 
                                } else if (setup.bRequestType == Ep_Request) {
@@ -1376,7 +1375,7 @@ restart:
                                        }
                                        ep2->halted = 1;
                                        value = 0;
-                                       maybe_set_status (urb, 0);
+                                       status = 0;
                                }
                                break;
                        case USB_REQ_CLEAR_FEATURE:
@@ -1386,7 +1385,7 @@ restart:
                                                dum->devstatus &= ~(1 <<
                                                        USB_DEVICE_REMOTE_WAKEUP);
                                                value = 0;
-                                               maybe_set_status (urb, 0);
+                                               status = 0;
                                                break;
                                        default:
                                                value = -EOPNOTSUPP;
@@ -1401,7 +1400,7 @@ restart:
                                        }
                                        ep2->halted = 0;
                                        value = 0;
-                                       maybe_set_status (urb, 0);
+                                       status = 0;
                                }
                                break;
                        case USB_REQ_GET_STATUS:
@@ -1438,7 +1437,7 @@ restart:
                                        urb->actual_length = min (2,
                                                urb->transfer_buffer_length);
                                        value = 0;
-                                       maybe_set_status (urb, 0);
+                                       status = 0;
                                }
                                break;
                        }
@@ -1465,7 +1464,7 @@ restart:
                                        dev_dbg (udc_dev(dum),
                                                "setup --> %d\n",
                                                value);
-                               maybe_set_status (urb, -EPIPE);
+                               status = -EPIPE;
                                urb->actual_length = 0;
                        }
 
@@ -1482,7 +1481,7 @@ restart:
                         * report random errors, to debug drivers.
                         */
                        limit = max (limit, periodic_bytes (dum, ep));
-                       maybe_set_status (urb, -ENOSYS);
+                       status = -ENOSYS;
                        break;
 
                case PIPE_INTERRUPT:
@@ -1496,23 +1495,23 @@ restart:
                default:
                treat_control_like_bulk:
                        ep->last_io = jiffies;
-                       total = transfer (dum, urb, ep, limit);
+                       total = transfer(dum, urb, ep, limit, &status);
                        break;
                }
 
                /* incomplete transfer? */
-               if (urb->status == -EINPROGRESS)
+               if (status == -EINPROGRESS)
                        continue;
 
 return_urb:
-               urb->hcpriv = NULL;
                list_del (&urbp->urbp_list);
                kfree (urbp);
                if (ep)
                        ep->already_seen = ep->setup_stage = 0;
 
+               usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb);
                spin_unlock (&dum->lock);
-               usb_hcd_giveback_urb (dummy_to_hcd(dum), urb);
+               usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status);
                spin_lock (&dum->lock);
 
                goto restart;
index 3aa46cf..f9d0710 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/string.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
index f700554..9e732bf 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+/* #define VERBOSE_DEBUG */
 
-// #define DEBUG 1
-// #define VERBOSE
-
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
 #include <linux/utsname.h>
 #include <linux/device.h>
-#include <linux/moduleparam.h>
 #include <linux/ctype.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/unaligned.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
-#include <linux/usb_gadget.h>
-
-#include <linux/random.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
@@ -356,15 +334,15 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR);
 #define qlen(gadget) \
        (DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1))
 
-/* also defer IRQs on highspeed TX */
-#define TX_DELAY       qmult
-
 static inline int BITRATE(struct usb_gadget *g)
 {
        return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS;
 }
 
 #else  /* full speed (low speed doesn't do bulk) */
+
+#define qmult          1
+
 #define        DEVSPEED        USB_SPEED_FULL
 
 #define qlen(gadget) DEFAULT_QLEN
@@ -390,7 +368,7 @@ static inline int BITRATE(struct usb_gadget *g)
        do { } while (0)
 #endif /* DEBUG */
 
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
 #define VDEBUG DEBUG
 #else
 #define VDEBUG(dev,fmt,args...) \
@@ -830,8 +808,6 @@ static const struct usb_descriptor_header *fs_rndis_function [] = {
 };
 #endif
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-
 /*
  * usb 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at full speed.
@@ -934,18 +910,15 @@ static const struct usb_descriptor_header *hs_rndis_function [] = {
 
 
 /* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
-
-#else
-
-/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g,hs,fs) (((void)(g)), (fs))
-
-static inline void __init hs_subset_descriptors(void)
+static inline struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+               struct usb_endpoint_descriptor *fs)
 {
+       if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+               return hs;
+       return fs;
 }
 
-#endif /* !CONFIG_USB_GADGET_DUALSPEED */
 
 /*-------------------------------------------------------------------------*/
 
@@ -989,22 +962,19 @@ static struct usb_gadget_strings  stringtab = {
  * complications: class descriptors, and an altsetting.
  */
 static int
-config_buf (enum usb_device_speed speed,
-       u8 *buf, u8 type,
-       unsigned index, int is_otg)
+config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg)
 {
        int                                     len;
        const struct usb_config_descriptor      *config;
        const struct usb_descriptor_header      **function;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       int                             hs = (speed == USB_SPEED_HIGH);
+       int                                     hs = 0;
 
-       if (type == USB_DT_OTHER_SPEED_CONFIG)
-               hs = !hs;
+       if (gadget_is_dualspeed(g)) {
+               hs = (g->speed == USB_SPEED_HIGH);
+               if (type == USB_DT_OTHER_SPEED_CONFIG)
+                       hs = !hs;
+       }
 #define which_fn(t)    (hs ? hs_ ## t ## _function : fs_ ## t ## _function)
-#else
-#define        which_fn(t)     (fs_ ## t ## _function)
-#endif
 
        if (index >= device_desc.bNumConfigurations)
                return -EINVAL;
@@ -1217,7 +1187,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags)
                if (number)
                        eth_reset_config (dev);
                usb_gadget_vbus_draw(dev->gadget,
-                               dev->gadget->is_otg ? 8 : 100);
+                               gadget_is_otg(dev->gadget) ? 8 : 100);
        } else {
                char *speed;
                unsigned power;
@@ -1399,24 +1369,22 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                        value = min (wLength, (u16) sizeof device_desc);
                        memcpy (req->buf, &device_desc, value);
                        break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
                case USB_DT_DEVICE_QUALIFIER:
-                       if (!gadget->is_dualspeed)
+                       if (!gadget_is_dualspeed(gadget))
                                break;
                        value = min (wLength, (u16) sizeof dev_qualifier);
                        memcpy (req->buf, &dev_qualifier, value);
                        break;
 
                case USB_DT_OTHER_SPEED_CONFIG:
-                       if (!gadget->is_dualspeed)
+                       if (!gadget_is_dualspeed(gadget))
                                break;
                        // FALLTHROUGH
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
                case USB_DT_CONFIG:
-                       value = config_buf (gadget->speed, req->buf,
+                       value = config_buf(gadget, req->buf,
                                        wValue >> 8,
                                        wValue & 0xff,
-                                       gadget->is_otg);
+                                       gadget_is_otg(gadget));
                        if (value >= 0)
                                value = min (wLength, (u16) value);
                        break;
@@ -1585,12 +1553,12 @@ done_set_intf:
                                && rndis_control_intf.bInterfaceNumber
                                        == wIndex) {
                        u8 *buf;
+                       u32 n;
 
                        /* return the result */
-                       buf = rndis_get_next_response (dev->rndis_config,
-                                                      &value);
+                       buf = rndis_get_next_response(dev->rndis_config, &n);
                        if (buf) {
-                               memcpy (req->buf, buf, value);
+                               memcpy(req->buf, buf, n);
                                req->complete = rndis_response_complete;
                                rndis_free_response(dev->rndis_config, buf);
                        }
@@ -1989,8 +1957,20 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
        }
 
        spin_lock_irqsave(&dev->req_lock, flags);
+       /*
+        * this freelist can be empty if an interrupt triggered disconnect()
+        * and reconfigured the gadget (shutting down this queue) after the
+        * network stack decided to xmit but before we got the spinlock.
+        */
+       if (list_empty(&dev->tx_reqs)) {
+               spin_unlock_irqrestore(&dev->req_lock, flags);
+               return 1;
+       }
+
        req = container_of (dev->tx_reqs.next, struct usb_request, list);
        list_del (&req->list);
+
+       /* temporarily stop TX queue when the freelist empties */
        if (list_empty (&dev->tx_reqs))
                netif_stop_queue (net);
        spin_unlock_irqrestore(&dev->req_lock, flags);
@@ -2026,12 +2006,11 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
 
        req->length = length;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
        /* throttle highspeed IRQ rate back slightly */
-       req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
-               ? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0)
-               : 0;
-#endif
+       if (gadget_is_dualspeed(dev->gadget))
+               req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
+                       ? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
+                       : 0;
 
        retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
        switch (retval) {
@@ -2188,8 +2167,7 @@ static int eth_stop (struct net_device *net)
        }
 
        if (rndis_active(dev)) {
-               rndis_set_param_medium (dev->rndis_config,
-                                       NDIS_MEDIUM_802_3, 0);
+               rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0);
                (void) rndis_signal_disconnect (dev->rndis_config);
        }
 
@@ -2443,26 +2421,28 @@ autoconf_fail:
        if (rndis)
                device_desc.bNumConfigurations = 2;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       if (rndis)
-               dev_qualifier.bNumConfigurations = 2;
-       else if (!cdc)
-               dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
+       if (gadget_is_dualspeed(gadget)) {
+               if (rndis)
+                       dev_qualifier.bNumConfigurations = 2;
+               else if (!cdc)
+                       dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
 
-       /* assumes ep0 uses the same value for both speeds ... */
-       dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+               /* assumes ep0 uses the same value for both speeds ... */
+               dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
 
-       /* and that all endpoints are dual-speed */
-       hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
-       hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
+               /* and that all endpoints are dual-speed */
+               hs_source_desc.bEndpointAddress =
+                               fs_source_desc.bEndpointAddress;
+               hs_sink_desc.bEndpointAddress =
+                               fs_sink_desc.bEndpointAddress;
 #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
-       if (status_ep)
-               hs_status_desc.bEndpointAddress =
-                               fs_status_desc.bEndpointAddress;
+               if (status_ep)
+                       hs_status_desc.bEndpointAddress =
+                                       fs_status_desc.bEndpointAddress;
 #endif
-#endif /* DUALSPEED */
+       }
 
-       if (gadget->is_otg) {
+       if (gadget_is_otg(gadget)) {
                otg_descriptor.bmAttributes |= USB_OTG_HNP,
                eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
                eth_config.bMaxPower = 4;
@@ -2598,12 +2578,11 @@ fail0:
                if (rndis_set_param_dev (dev->rndis_config, dev->net,
                                         &dev->stats, &dev->cdc_filter))
                        goto fail0;
-               if (rndis_set_param_vendor (dev->rndis_config, vendorID,
-                                           manufacturer))
+               if (rndis_set_param_vendor(dev->rndis_config, vendorID,
+                                       manufacturer))
                        goto fail0;
-               if (rndis_set_param_medium (dev->rndis_config,
-                                           NDIS_MEDIUM_802_3,
-                                           0))
+               if (rndis_set_param_medium(dev->rndis_config,
+                                       NDIS_MEDIUM_802_3, 0))
                        goto fail0;
                INFO (dev, "RNDIS ready\n");
        }
index 965ad7b..73726c5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * file_storage.c -- File-backed USB Storage Gadget, for USB development
  *
- * Copyright (C) 2003-2005 Alan Stern
+ * Copyright (C) 2003-2007 Alan Stern
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  */
 
 
-#undef DEBUG
-#undef VERBOSE
-#undef DUMP_MSGS
-
+/* #define VERBOSE_DEBUG */
+/* #define DUMP_MSGS */
 
-#include <asm/system.h>
-#include <asm/uaccess.h>
 
-#include <linux/bitops.h>
 #include <linux/blkdev.h>
-#include <linux/compiler.h>
 #include <linux/completion.h>
 #include <linux/dcache.h>
 #include <linux/delay.h>
 #include <linux/fcntl.h>
 #include <linux/file.h>
 #include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
 #include <linux/kref.h>
 #include <linux/kthread.h>
 #include <linux/limits.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/pagemap.h>
 #include <linux/rwsem.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/utsname.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
 
 #define DRIVER_DESC            "File-backed Storage Gadget"
 #define DRIVER_NAME            "g_file_storage"
-#define DRIVER_VERSION         "28 November 2005"
+#define DRIVER_VERSION         "7 August 2007"
 
 static const char longname[] = DRIVER_DESC;
 static const char shortname[] = DRIVER_NAME;
@@ -289,57 +275,48 @@ MODULE_LICENSE("Dual BSD/GPL");
 
 /*-------------------------------------------------------------------------*/
 
-#define xprintk(f,level,fmt,args...) \
-       dev_printk(level , &(f)->gadget->dev , fmt , ## args)
-#define yprintk(l,level,fmt,args...) \
-       dev_printk(level , &(l)->dev , fmt , ## args)
-
 #ifdef DEBUG
-#define DBG(fsg,fmt,args...) \
-       xprintk(fsg , KERN_DEBUG , fmt , ## args)
 #define LDBG(lun,fmt,args...) \
-       yprintk(lun , KERN_DEBUG , fmt , ## args)
+       dev_dbg(&(lun)->dev , fmt , ## args)
 #define MDBG(fmt,args...) \
        printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args)
 #else
-#define DBG(fsg,fmt,args...) \
-       do { } while (0)
 #define LDBG(lun,fmt,args...) \
        do { } while (0)
 #define MDBG(fmt,args...) \
        do { } while (0)
-#undef VERBOSE
+#undef VERBOSE_DEBUG
 #undef DUMP_MSGS
 #endif /* DEBUG */
 
-#ifdef VERBOSE
-#define VDBG   DBG
+#ifdef VERBOSE_DEBUG
 #define VLDBG  LDBG
 #else
-#define VDBG(fsg,fmt,args...) \
-       do { } while (0)
 #define VLDBG(lun,fmt,args...) \
        do { } while (0)
-#endif /* VERBOSE */
+#endif /* VERBOSE_DEBUG */
 
-#define ERROR(fsg,fmt,args...) \
-       xprintk(fsg , KERN_ERR , fmt , ## args)
 #define LERROR(lun,fmt,args...) \
-       yprintk(lun , KERN_ERR , fmt , ## args)
-
-#define WARN(fsg,fmt,args...) \
-       xprintk(fsg , KERN_WARNING , fmt , ## args)
+       dev_err(&(lun)->dev , fmt , ## args)
 #define LWARN(lun,fmt,args...) \
-       yprintk(lun , KERN_WARNING , fmt , ## args)
-
-#define INFO(fsg,fmt,args...) \
-       xprintk(fsg , KERN_INFO , fmt , ## args)
+       dev_warn(&(lun)->dev , fmt , ## args)
 #define LINFO(lun,fmt,args...) \
-       yprintk(lun , KERN_INFO , fmt , ## args)
+       dev_info(&(lun)->dev , fmt , ## args)
 
 #define MINFO(fmt,args...) \
        printk(KERN_INFO DRIVER_NAME ": " fmt , ## args)
 
+#define DBG(d, fmt, args...) \
+       dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+       dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+       dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+       dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+       dev_info(&(d)->gadget->dev , fmt , ## args)
+
 
 /*-------------------------------------------------------------------------*/
 
@@ -350,8 +327,8 @@ MODULE_LICENSE("Dual BSD/GPL");
 static struct {
        char            *file[MAX_LUNS];
        int             ro[MAX_LUNS];
-       int             num_filenames;
-       int             num_ros;
+       unsigned int    num_filenames;
+       unsigned int    num_ros;
        unsigned int    nluns;
 
        int             removable;
@@ -578,7 +555,7 @@ struct lun {
 
 #define backing_file_is_open(curlun)   ((curlun)->filp != NULL)
 
-static inline struct lun *dev_to_lun(struct device *dev)
+static struct lun *dev_to_lun(struct device *dev)
 {
        return container_of(dev, struct lun, dev);
 }
@@ -711,13 +688,13 @@ struct fsg_dev {
 
 typedef void (*fsg_routine_t)(struct fsg_dev *);
 
-static int inline exception_in_progress(struct fsg_dev *fsg)
+static int exception_in_progress(struct fsg_dev *fsg)
 {
        return (fsg->state > FSG_STATE_IDLE);
 }
 
 /* Make bulk-out requests be divisible by the maxpacket size */
-static void inline set_bulk_out_req_length(struct fsg_dev *fsg,
+static void set_bulk_out_req_length(struct fsg_dev *fsg,
                struct fsg_buffhd *bh, unsigned int length)
 {
        unsigned int    rem;
@@ -743,50 +720,36 @@ static void       close_all_backing_files(struct fsg_dev *fsg);
 static void dump_msg(struct fsg_dev *fsg, const char *label,
                const u8 *buf, unsigned int length)
 {
-       unsigned int    start, num, i;
-       char            line[52], *p;
-
-       if (length >= 512)
-               return;
-       DBG(fsg, "%s, length %u:\n", label, length);
-
-       start = 0;
-       while (length > 0) {
-               num = min(length, 16u);
-               p = line;
-               for (i = 0; i < num; ++i) {
-                       if (i == 8)
-                               *p++ = ' ';
-                       sprintf(p, " %02x", buf[i]);
-                       p += 3;
-               }
-               *p = 0;
-               printk(KERN_DEBUG "%6x: %s\n", start, line);
-               buf += num;
-               start += num;
-               length -= num;
+       if (length < 512) {
+               DBG(fsg, "%s, length %u:\n", label, length);
+               print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,
+                               16, 1, buf, length, 0);
        }
 }
 
-static void inline dump_cdb(struct fsg_dev *fsg)
+static void dump_cdb(struct fsg_dev *fsg)
 {}
 
 #else
 
-static void inline dump_msg(struct fsg_dev *fsg, const char *label,
+static void dump_msg(struct fsg_dev *fsg, const char *label,
                const u8 *buf, unsigned int length)
 {}
 
-static void inline dump_cdb(struct fsg_dev *fsg)
-{
-       int     i;
-       char    cmdbuf[3*MAX_COMMAND_SIZE + 1];
+#ifdef VERBOSE_DEBUG
 
-       for (i = 0; i < fsg->cmnd_size; ++i)
-               sprintf(cmdbuf + i*3, " %02x", fsg->cmnd[i]);
-       VDBG(fsg, "SCSI CDB: %s\n", cmdbuf);
+static void dump_cdb(struct fsg_dev *fsg)
+{
+       print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE,
+                       16, 1, fsg->cmnd, fsg->cmnd_size, 0);
 }
 
+#else
+
+static void dump_cdb(struct fsg_dev *fsg)
+{}
+
+#endif /* VERBOSE_DEBUG */
 #endif /* DUMP_MSGS */
 
 
@@ -809,24 +772,24 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
 
 /* Routines for unaligned data access */
 
-static u16 inline get_be16(u8 *buf)
+static u16 get_be16(u8 *buf)
 {
        return ((u16) buf[0] << 8) | ((u16) buf[1]);
 }
 
-static u32 inline get_be32(u8 *buf)
+static u32 get_be32(u8 *buf)
 {
        return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) |
                        ((u32) buf[2] << 8) | ((u32) buf[3]);
 }
 
-static void inline put_be16(u8 *buf, u16 val)
+static void put_be16(u8 *buf, u16 val)
 {
        buf[0] = val >> 8;
        buf[1] = val;
 }
 
-static void inline put_be32(u8 *buf, u32 val)
+static void put_be32(u8 *buf, u32 val)
 {
        buf[0] = val >> 24;
        buf[1] = val >> 16;
@@ -950,8 +913,6 @@ static const struct usb_descriptor_header *fs_function[] = {
 #define FS_FUNCTION_PRE_EP_ENTRIES     2
 
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-
 /*
  * USB 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at full speed.
@@ -1014,14 +975,14 @@ static const struct usb_descriptor_header *hs_function[] = {
 #define HS_FUNCTION_PRE_EP_ENTRIES     2
 
 /* Maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,fs,hs)       (((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs))
-
-#else
-
-/* If there's no high speed support, always use the full-speed descriptor. */
-#define ep_desc(g,fs,hs)       fs
-
-#endif /* !CONFIG_USB_GADGET_DUALSPEED */
+static struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
+               struct usb_endpoint_descriptor *hs)
+{
+       if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+               return hs;
+       return fs;
+}
 
 
 /* The CBI specification limits the serial string to 12 uppercase hexadecimal
@@ -1053,26 +1014,22 @@ static struct usb_gadget_strings        stringtab = {
 static int populate_config_buf(struct usb_gadget *gadget,
                u8 *buf, u8 type, unsigned index)
 {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
        enum usb_device_speed                   speed = gadget->speed;
-#endif
        int                                     len;
        const struct usb_descriptor_header      **function;
 
        if (index > 0)
                return -EINVAL;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       if (type == USB_DT_OTHER_SPEED_CONFIG)
+       if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
                speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
-       if (speed == USB_SPEED_HIGH)
+       if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH)
                function = hs_function;
        else
-#endif
                function = fs_function;
 
        /* for now, don't advertise srp-only devices */
-       if (!gadget->is_otg)
+       if (!gadget_is_otg(gadget))
                function++;
 
        len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
@@ -1394,10 +1351,9 @@ static int standard_setup_req(struct fsg_dev *fsg,
                        value = sizeof device_desc;
                        memcpy(req->buf, &device_desc, value);
                        break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
                case USB_DT_DEVICE_QUALIFIER:
                        VDBG(fsg, "get device qualifier\n");
-                       if (!fsg->gadget->is_dualspeed)
+                       if (!gadget_is_dualspeed(fsg->gadget))
                                break;
                        value = sizeof dev_qualifier;
                        memcpy(req->buf, &dev_qualifier, value);
@@ -1405,15 +1361,12 @@ static int standard_setup_req(struct fsg_dev *fsg,
 
                case USB_DT_OTHER_SPEED_CONFIG:
                        VDBG(fsg, "get other-speed config descriptor\n");
-                       if (!fsg->gadget->is_dualspeed)
+                       if (!gadget_is_dualspeed(fsg->gadget))
                                break;
                        goto get_config;
-#endif
                case USB_DT_CONFIG:
                        VDBG(fsg, "get configuration descriptor\n");
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-               get_config:
-#endif
+get_config:
                        value = populate_config_buf(fsg->gadget,
                                        req->buf,
                                        w_value >> 8,
@@ -1646,7 +1599,8 @@ static int do_read(struct fsg_dev *fsg)
                /* Wait for the next buffer to become available */
                bh = fsg->next_buffhd_to_fill;
                while (bh->state != BUF_STATE_EMPTY) {
-                       if ((rc = sleep_thread(fsg)) != 0)
+                       rc = sleep_thread(fsg);
+                       if (rc)
                                return rc;
                }
 
@@ -1885,7 +1839,8 @@ static int do_write(struct fsg_dev *fsg)
                }
 
                /* Wait for something to happen */
-               if ((rc = sleep_thread(fsg)) != 0)
+               rc = sleep_thread(fsg);
+               if (rc)
                        return rc;
        }
 
@@ -2369,7 +2324,8 @@ static int pad_with_zeros(struct fsg_dev *fsg)
 
                /* Wait for the next buffer to be free */
                while (bh->state != BUF_STATE_EMPTY) {
-                       if ((rc = sleep_thread(fsg)) != 0)
+                       rc = sleep_thread(fsg);
+                       if (rc)
                                return rc;
                }
 
@@ -2429,7 +2385,8 @@ static int throw_away_data(struct fsg_dev *fsg)
                }
 
                /* Otherwise wait for something to happen */
-               if ((rc = sleep_thread(fsg)) != 0)
+               rc = sleep_thread(fsg);
+               if (rc)
                        return rc;
        }
        return 0;
@@ -2551,7 +2508,8 @@ static int send_status(struct fsg_dev *fsg)
        /* Wait for the next buffer to become available */
        bh = fsg->next_buffhd_to_fill;
        while (bh->state != BUF_STATE_EMPTY) {
-               if ((rc = sleep_thread(fsg)) != 0)
+               rc = sleep_thread(fsg);
+               if (rc)
                        return rc;
        }
 
@@ -2771,9 +2729,10 @@ static int do_scsi_command(struct fsg_dev *fsg)
        /* Wait for the next buffer to become available for data or status */
        bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
        while (bh->state != BUF_STATE_EMPTY) {
-               if ((rc = sleep_thread(fsg)) != 0)
+               rc = sleep_thread(fsg);
+               if (rc)
                        return rc;
-               }
+       }
        fsg->phase_error = 0;
        fsg->short_packet_received = 0;
 
@@ -3005,7 +2964,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
 
        /* Is the CBW meaningful? */
        if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG ||
-                       cbw->Length < 6 || cbw->Length > MAX_COMMAND_SIZE) {
+                       cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
                DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
                                "cmdlen %u\n",
                                cbw->Lun, cbw->Flags, cbw->Length);
@@ -3045,9 +3004,10 @@ static int get_next_command(struct fsg_dev *fsg)
                /* Wait for the next buffer to become available */
                bh = fsg->next_buffhd_to_fill;
                while (bh->state != BUF_STATE_EMPTY) {
-                       if ((rc = sleep_thread(fsg)) != 0)
+                       rc = sleep_thread(fsg);
+                       if (rc)
                                return rc;
-                       }
+               }
 
                /* Queue a request to read a Bulk-only CBW */
                set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
@@ -3061,9 +3021,10 @@ static int get_next_command(struct fsg_dev *fsg)
 
                /* Wait for the CBW to arrive */
                while (bh->state != BUF_STATE_FULL) {
-                       if ((rc = sleep_thread(fsg)) != 0)
+                       rc = sleep_thread(fsg);
+                       if (rc)
                                return rc;
-                       }
+               }
                smp_rmb();
                rc = received_cbw(fsg, bh);
                bh->state = BUF_STATE_EMPTY;
@@ -3072,9 +3033,10 @@ static int get_next_command(struct fsg_dev *fsg)
 
                /* Wait for the next command to arrive */
                while (fsg->cbbuf_cmnd_size == 0) {
-                       if ((rc = sleep_thread(fsg)) != 0)
+                       rc = sleep_thread(fsg);
+                       if (rc)
                                return rc;
-                       }
+               }
 
                /* Is the previous status interrupt request still busy?
                 * The host is allowed to skip reading the status,
@@ -3595,7 +3557,8 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *
        return sprintf(buf, "%d\n", curlun->ro);
 }
 
-static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_file(struct device *dev, struct device_attribute *attr,
+               char *buf)
 {
        struct lun      *curlun = dev_to_lun(dev);
        struct fsg_dev  *fsg = dev_get_drvdata(dev);
@@ -3604,8 +3567,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char
 
        down_read(&fsg->filesem);
        if (backing_file_is_open(curlun)) {     // Get the complete pathname
-               p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt,
-                               buf, PAGE_SIZE - 1);
+               p = d_path(curlun->filp->f_path.dentry,
+                               curlun->filp->f_path.mnt, buf, PAGE_SIZE - 1);
                if (IS_ERR(p))
                        rc = PTR_ERR(p);
                else {
@@ -3623,7 +3586,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char
 }
 
 
-static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_ro(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
 {
        ssize_t         rc = count;
        struct lun      *curlun = dev_to_lun(dev);
@@ -3647,7 +3611,8 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
        return rc;
 }
 
-static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_file(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
 {
        struct lun      *curlun = dev_to_lun(dev);
        struct fsg_dev  *fsg = dev_get_drvdata(dev);
@@ -3859,7 +3824,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
        /* Find out how many LUNs there should be */
        i = mod_data.nluns;
        if (i == 0)
-               i = max(mod_data.num_filenames, 1);
+               i = max(mod_data.num_filenames, 1u);
        if (i > MAX_LUNS) {
                ERROR(fsg, "invalid number of LUNs: %d\n", i);
                rc = -EINVAL;
@@ -3944,21 +3909,23 @@ static int __init fsg_bind(struct usb_gadget *gadget)
        intf_desc.bInterfaceProtocol = mod_data.transport_type;
        fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
+       if (gadget_is_dualspeed(gadget)) {
+               hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
 
-       /* Assume ep0 uses the same maxpacket value for both speeds */
-       dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
+               /* Assume ep0 uses the same maxpacket value for both speeds */
+               dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
 
-       /* Assume that all endpoint addresses are the same for both speeds */
-       hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress;
-       hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress;
-       hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress;
-#endif
+               /* Assume endpoint addresses are the same for both speeds */
+               hs_bulk_in_desc.bEndpointAddress =
+                               fs_bulk_in_desc.bEndpointAddress;
+               hs_bulk_out_desc.bEndpointAddress =
+                               fs_bulk_out_desc.bEndpointAddress;
+               hs_intr_in_desc.bEndpointAddress =
+                               fs_intr_in_desc.bEndpointAddress;
+       }
 
-       if (gadget->is_otg) {
+       if (gadget_is_otg(gadget))
                otg_desc.bmAttributes |= USB_OTG_HNP;
-       }
 
        rc = -ENOMEM;
 
index d57bcfb..9bb7f64 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
@@ -1090,14 +1090,11 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
  */
 static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
 {
-#ifdef CONFIG_USB_OTG
        struct fsl_udc *udc;
 
        udc = container_of(gadget, struct fsl_udc, gadget);
-
        if (udc->transceiver)
                return otg_set_power(udc->transceiver, mA);
-#endif
        return -ENOTSUPP;
 }
 
@@ -1120,7 +1117,7 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)
        return 0;
 }
 
-/* defined in usb_gadget.h */
+/* defined in gadget.h */
 static struct usb_gadget_ops fsl_gadget_ops = {
        .get_frame = fsl_get_frame,
        .wakeup = fsl_wakeup,
@@ -1321,7 +1318,7 @@ static void setup_received_irq(struct fsl_udc *udc,
                                | USB_TYPE_STANDARD)) {
                        /* Note: The driver has not include OTG support yet.
                         * This will be set when OTG support is added */
-                       if (!udc->gadget.is_otg)
+                       if (!gadget_is_otg(udc->gadget))
                                break;
                        else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
                                udc->gadget.b_hnp_enable = 1;
@@ -1330,6 +1327,8 @@ static void setup_received_irq(struct fsl_udc *udc,
                        else if (setup->bRequest ==
                                        USB_DEVICE_A_ALT_HNP_SUPPORT)
                                udc->gadget.a_alt_hnp_support = 1;
+                       else
+                               break;
                        rc = 0;
                } else
                        break;
@@ -1840,10 +1839,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
        if (!driver || driver != udc_controller->driver || !driver->unbind)
                return -EINVAL;
 
-#ifdef CONFIG_USB_OTG
        if (udc_controller->transceiver)
                (void)otg_set_peripheral(udc_controller->transceiver, 0);
-#endif
 
        /* stop DR, disable intr */
        dr_controller_stop(udc_controller);
index 1c5aa49..0689189 100644 (file)
  * http://www.usb.org/developers/devclass_docs/midi10.pdf
  */
 
-#define DEBUG 1
-// #define VERBOSE
+/* #define VERBOSE_DEBUG */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
 #include <linux/utsname.h>
 #include <linux/device.h>
-#include <linux/moduleparam.h>
 
 #include <sound/driver.h>
 #include <sound/core.h>
@@ -36,7 +30,7 @@
 #include <sound/rawmidi.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/audio.h>
 #include <linux/usb/midi.h>
 
@@ -139,30 +133,16 @@ struct gmidi_device {
 static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req);
 
 
-#define xprintk(d,level,fmt,args...) \
-       dev_printk(level , &(d)->gadget->dev , fmt , ## args)
-
-#ifdef DEBUG
-#define DBG(dev,fmt,args...) \
-       xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev,fmt,args...) \
-       do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG   DBG
-#else
-#define VDBG(dev,fmt,args...) \
-       do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev,fmt,args...) \
-       xprintk(dev , KERN_ERR , fmt , ## args)
-#define WARN(dev,fmt,args...) \
-       xprintk(dev , KERN_WARNING , fmt , ## args)
-#define INFO(dev,fmt,args...) \
-       xprintk(dev , KERN_INFO , fmt , ## args)
+#define DBG(d, fmt, args...) \
+       dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+       dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+       dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+       dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+       dev_info(&(d)->gadget->dev , fmt , ## args)
 
 
 static unsigned buflen = 256;
@@ -425,7 +405,7 @@ static int config_buf(struct usb_gadget *gadget,
        return len;
 }
 
-static struct usb_requestalloc_ep_req(struct usb_ep *ep, unsigned length)
+static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
 {
        struct usb_request      *req;
 
@@ -455,7 +435,7 @@ static const uint8_t gmidi_cin_length[] = {
  * Receives a chunk of MIDI data.
  */
 static void gmidi_read_data(struct usb_ep *ep, int cable,
-                                  uint8_tdata, int length)
+                                  uint8_t *data, int length)
 {
        struct gmidi_device *dev = ep->driver_data;
        /* cable is ignored, because for now we only have one. */
@@ -541,7 +521,7 @@ static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags)
 {
        int err = 0;
        struct usb_request *req;
-       struct usb_epep;
+       struct usb_ep *ep;
        unsigned i;
 
        err = usb_ep_enable(dev->in_ep, &bulk_in_desc);
@@ -628,7 +608,7 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags)
 
        if (gadget_is_sa1100(gadget) && dev->config) {
                /* tx fifo is full, but we can't clear it...*/
-               INFO(dev, "can't change configurations\n");
+               ERROR(dev, "can't change configurations\n");
                return -ESPIPE;
        }
        gmidi_reset_config(dev);
@@ -843,7 +823,7 @@ static void gmidi_disconnect(struct usb_gadget *gadget)
 static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget)
 {
        struct gmidi_device *dev = get_gadget_data(gadget);
-       struct snd_cardcard;
+       struct snd_card *card;
 
        DBG(dev, "unbind\n");
 
@@ -867,12 +847,12 @@ static int gmidi_snd_free(struct snd_device *device)
        return 0;
 }
 
-static void gmidi_transmit_packet(struct usb_requestreq, uint8_t p0,
+static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0,
                                        uint8_t p1, uint8_t p2, uint8_t p3)
 {
        unsigned length = req->length;
+       u8 *buf = (u8 *)req->buf + length;
 
-       uint8_t* buf = (uint8_t*)req->buf + length;
        buf[0] = p0;
        buf[1] = p1;
        buf[2] = p2;
@@ -883,8 +863,8 @@ static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0,
 /*
  * Converts MIDI commands to USB MIDI packets.
  */
-static void gmidi_transmit_byte(struct usb_requestreq,
-                               struct gmidi_in_portport, uint8_t b)
+static void gmidi_transmit_byte(struct usb_request *req,
+                               struct gmidi_in_port *port, uint8_t b)
 {
        uint8_t p0 = port->cable;
 
@@ -981,10 +961,10 @@ static void gmidi_transmit_byte(struct usb_request* req,
        }
 }
 
-static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req)
+static void gmidi_transmit(struct gmidi_device *dev, struct usb_request *req)
 {
-       struct usb_epep = dev->in_ep;
-       struct gmidi_in_portport = &dev->in_port;
+       struct usb_ep *ep = dev->in_ep;
+       struct gmidi_in_port *port = &dev->in_port;
 
        if (!ep) {
                return;
@@ -1020,14 +1000,14 @@ static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req)
 
 static void gmidi_in_tasklet(unsigned long data)
 {
-       struct gmidi_device* dev = (struct gmidi_device*)data;
+       struct gmidi_device *dev = (struct gmidi_device *)data;
 
        gmidi_transmit(dev, NULL);
 }
 
 static int gmidi_in_open(struct snd_rawmidi_substream *substream)
 {
-       struct gmidi_devicedev = substream->rmidi->private_data;
+       struct gmidi_device *dev = substream->rmidi->private_data;
 
        VDBG(dev, "gmidi_in_open\n");
        dev->in_substream = substream;
@@ -1037,13 +1017,15 @@ static int gmidi_in_open(struct snd_rawmidi_substream *substream)
 
 static int gmidi_in_close(struct snd_rawmidi_substream *substream)
 {
+       struct gmidi_device *dev = substream->rmidi->private_data;
+
        VDBG(dev, "gmidi_in_close\n");
        return 0;
 }
 
 static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
 {
-       struct gmidi_devicedev = substream->rmidi->private_data;
+       struct gmidi_device *dev = substream->rmidi->private_data;
 
        VDBG(dev, "gmidi_in_trigger %d\n", up);
        dev->in_port.active = up;
@@ -1054,7 +1036,7 @@ static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
 
 static int gmidi_out_open(struct snd_rawmidi_substream *substream)
 {
-       struct gmidi_devicedev = substream->rmidi->private_data;
+       struct gmidi_device *dev = substream->rmidi->private_data;
 
        VDBG(dev, "gmidi_out_open\n");
        dev->out_substream = substream;
@@ -1063,13 +1045,15 @@ static int gmidi_out_open(struct snd_rawmidi_substream *substream)
 
 static int gmidi_out_close(struct snd_rawmidi_substream *substream)
 {
+       struct gmidi_device *dev = substream->rmidi->private_data;
+
        VDBG(dev, "gmidi_out_close\n");
        return 0;
 }
 
 static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up)
 {
-       struct gmidi_devicedev = substream->rmidi->private_data;
+       struct gmidi_device *dev = substream->rmidi->private_data;
 
        VDBG(dev, "gmidi_out_trigger %d\n", up);
        if (up) {
index 349b816..2ec9d19 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/proc_fs.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
index 173004f..47ef8bd 100644 (file)
@@ -20,8 +20,7 @@
  */
 
 
-// #define     DEBUG                   /* data to help fault diagnosis */
-// #define     VERBOSE         /* extra debug messages (success too) */
+/* #define VERBOSE_DEBUG */
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -38,7 +37,7 @@
 #include <linux/moduleparam.h>
 
 #include <linux/usb/gadgetfs.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 
 /*
@@ -253,7 +252,7 @@ static const char *CHIP;
        do { } while (0)
 #endif /* DEBUG */
 
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
 #define VDEBUG DBG
 #else
 #define VDEBUG(dev,fmt,args...) \
@@ -1010,11 +1009,12 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
                        /* assume that was SET_CONFIGURATION */
                        if (dev->current_config) {
                                unsigned power;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-                               if (dev->gadget->speed == USB_SPEED_HIGH)
+
+                               if (gadget_is_dualspeed(dev->gadget)
+                                               && (dev->gadget->speed
+                                                       == USB_SPEED_HIGH))
                                        power = dev->hs_config->bMaxPower;
                                else
-#endif
                                        power = dev->config->bMaxPower;
                                usb_gadget_vbus_draw(dev->gadget, 2 * power);
                        }
@@ -1355,24 +1355,21 @@ static int
 config_buf (struct dev_data *dev, u8 type, unsigned index)
 {
        int             len;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       int             hs;
-#endif
+       int             hs = 0;
 
        /* only one configuration */
        if (index > 0)
                return -EINVAL;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       hs = (dev->gadget->speed == USB_SPEED_HIGH);
-       if (type == USB_DT_OTHER_SPEED_CONFIG)
-               hs = !hs;
+       if (gadget_is_dualspeed(dev->gadget)) {
+               hs = (dev->gadget->speed == USB_SPEED_HIGH);
+               if (type == USB_DT_OTHER_SPEED_CONFIG)
+                       hs = !hs;
+       }
        if (hs) {
                dev->req->buf = dev->hs_config;
                len = le16_to_cpu(dev->hs_config->wTotalLength);
-       } else
-#endif
-       {
+       } else {
                dev->req->buf = dev->config;
                len = le16_to_cpu(dev->config->wTotalLength);
        }
@@ -1393,13 +1390,13 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
        spin_lock (&dev->lock);
        dev->setup_abort = 0;
        if (dev->state == STATE_DEV_UNCONNECTED) {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-               if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == NULL) {
+               if (gadget_is_dualspeed(gadget)
+                               && gadget->speed == USB_SPEED_HIGH
+                               && dev->hs_config == NULL) {
                        spin_unlock(&dev->lock);
                        ERROR (dev, "no high speed config??\n");
                        return -EINVAL;
                }
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
 
                dev->state = STATE_DEV_CONNECTED;
                dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
@@ -1469,13 +1466,12 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                        // user mode expected to disable endpoints
                } else {
                        u8      config, power;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-                       if (gadget->speed == USB_SPEED_HIGH) {
+
+                       if (gadget_is_dualspeed(gadget)
+                                       && gadget->speed == USB_SPEED_HIGH) {
                                config = dev->hs_config->bConfigurationValue;
                                power = dev->hs_config->bMaxPower;
-                       } else
-#endif
-                       {
+                       } else {
                                config = dev->config->bConfigurationValue;
                                power = dev->config->bMaxPower;
                        }
index b3fe197..1ecfd63 100644 (file)
@@ -50,7 +50,7 @@
 #include <asm/hardware.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 /*
  * Memory map
index 4b27d12..ebc5536 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/platform_device.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "m66592-udc.h"
 
index c3d364e..d5d473f 100644 (file)
@@ -62,7 +62,7 @@
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
index 9b0f092..87c4f50 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
 #include <linux/clk.h>
@@ -1241,19 +1241,15 @@ static void pullup_enable(struct omap_udc *udc)
        udc->gadget.dev.parent->power.power_state = PMSG_ON;
        udc->gadget.dev.power.power_state = PMSG_ON;
        UDC_SYSCON1_REG |= UDC_PULLUP_EN;
-#ifndef CONFIG_USB_OTG
-       if (!cpu_is_omap15xx())
+       if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx())
                OTG_CTRL_REG |= OTG_BSESSVLD;
-#endif
        UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
 }
 
 static void pullup_disable(struct omap_udc *udc)
 {
-#ifndef CONFIG_USB_OTG
-       if (!cpu_is_omap15xx())
+       if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx())
                OTG_CTRL_REG &= ~OTG_BSESSVLD;
-#endif
        UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
        UDC_SYSCON1_REG &= ~UDC_PULLUP_EN;
 }
@@ -1390,7 +1386,7 @@ static void update_otg(struct omap_udc *udc)
 {
        u16     devstat;
 
-       if (!udc->gadget.is_otg)
+       if (!gadget_is_otg(udc->gadget))
                return;
 
        if (OTG_CTRL_REG & OTG_ID)
index 1407ad1..3e71508 100644 (file)
@@ -54,7 +54,7 @@
 #include <asm/hardware.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/mach/udc_pxa2xx.h>
 
index 0be80c6..e3e90f8 100644 (file)
@@ -42,7 +42,7 @@
 #include <linux/seq_file.h>
 
 #include <linux/usb.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
index ce4d2e0..f5738eb 100644 (file)
  *
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
 #include <linux/utsname.h>
-#include <linux/wait.h>
-#include <linux/proc_fs.h>
 #include <linux/device.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
-#include <linux/mutex.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
-#include <asm/uaccess.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
 #define GS_DEFAULT_PARITY              USB_CDC_NO_PARITY
 #define GS_DEFAULT_CHAR_FORMAT         USB_CDC_1_STOP_BITS
 
-/* select highspeed/fullspeed, hiding highspeed if not configured */
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-#define GS_SPEED_SELECT(is_hs,hs,fs) ((is_hs) ? (hs) : (fs))
-#else
-#define GS_SPEED_SELECT(is_hs,hs,fs) (fs)
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+/* maxpacket and other transfer characteristics vary by speed. */
+static inline struct usb_endpoint_descriptor *
+choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+               struct usb_endpoint_descriptor *fs)
+{
+       if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+               return hs;
+       return fs;
+}
+
 
 /* debug settings */
-#ifdef GS_DEBUG
+#ifdef DEBUG
 static int debug = 1;
+#else
+#define        debug 0
+#endif
 
 #define gs_debug(format, arg...) \
        do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
 #define gs_debug_level(level, format, arg...) \
        do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0)
 
-#else
-
-#define gs_debug(format, arg...) \
-       do { } while(0)
-#define gs_debug_level(level, format, arg...) \
-       do { } while(0)
-
-#endif /* GS_DEBUG */
 
 /* Thanks to NetChip Technologies for donating this product ID.
  *
@@ -147,10 +127,10 @@ struct gs_req_entry {
 
 /* the port structure holds info for each port, one for each minor number */
 struct gs_port {
-       struct gs_dev           *port_dev;      /* pointer to device struct */
+       struct gs_dev           *port_dev;      /* pointer to device struct */
        struct tty_struct       *port_tty;      /* pointer to tty struct */
        spinlock_t              port_lock;
-       int                     port_num;
+       int                     port_num;
        int                     port_open_count;
        int                     port_in_use;    /* open/close in progress */
        wait_queue_head_t       port_write_wait;/* waiting to write */
@@ -188,7 +168,7 @@ static void __exit gs_module_exit(void);
 /* tty driver */
 static int gs_open(struct tty_struct *tty, struct file *file);
 static void gs_close(struct tty_struct *tty, struct file *file);
-static int gs_write(struct tty_struct *tty, 
+static int gs_write(struct tty_struct *tty,
        const unsigned char *buf, int count);
 static void gs_put_char(struct tty_struct *tty, unsigned char ch);
 static void gs_flush_chars(struct tty_struct *tty);
@@ -222,7 +202,7 @@ static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req);
 static void gs_disconnect(struct usb_gadget *gadget);
 static int gs_set_config(struct gs_dev *dev, unsigned config);
 static void gs_reset_config(struct gs_dev *dev);
-static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
+static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
                u8 type, unsigned int index, int is_otg);
 
 static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
@@ -415,18 +395,18 @@ static const struct usb_cdc_header_desc gs_header_desc = {
 };
 
 static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = {
-       .bLength =              sizeof(gs_call_mgmt_descriptor),
-       .bDescriptorType =      USB_DT_CS_INTERFACE,
-       .bDescriptorSubType =   USB_CDC_CALL_MANAGEMENT_TYPE,
-       .bmCapabilities =       0,
-       .bDataInterface =       1,      /* index of data interface */
+       .bLength =              sizeof(gs_call_mgmt_descriptor),
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_CALL_MANAGEMENT_TYPE,
+       .bmCapabilities =       0,
+       .bDataInterface =       1,      /* index of data interface */
 };
 
 static struct usb_cdc_acm_descriptor gs_acm_descriptor = {
-       .bLength =              sizeof(gs_acm_descriptor),
-       .bDescriptorType =      USB_DT_CS_INTERFACE,
-       .bDescriptorSubType =   USB_CDC_ACM_TYPE,
-       .bmCapabilities =       0,
+       .bLength =              sizeof(gs_acm_descriptor),
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_ACM_TYPE,
+       .bmCapabilities =       0,
 };
 
 static const struct usb_cdc_union_desc gs_union_desc = {
@@ -436,7 +416,7 @@ static const struct usb_cdc_union_desc gs_union_desc = {
        .bMasterInterface0 =    0,      /* index of control interface */
        .bSlaveInterface0 =     1,      /* index of data interface */
 };
+
 static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
@@ -482,7 +462,6 @@ static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = {
        NULL,
 };
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 static struct usb_endpoint_descriptor gs_highspeed_notify_desc = {
        .bLength =              USB_DT_ENDPOINT_SIZE,
        .bDescriptorType =      USB_DT_ENDPOINT,
@@ -536,15 +515,13 @@ static const struct usb_descriptor_header *gs_acm_highspeed_function[] = {
        NULL,
 };
 
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
-
 
 /* Module */
 MODULE_DESCRIPTION(GS_LONG_NAME);
 MODULE_AUTHOR("Al Borchers");
 MODULE_LICENSE("GPL");
 
-#ifdef GS_DEBUG
+#ifdef DEBUG
 module_param(debug, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
 #endif
@@ -915,7 +892,8 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch)
                return;
        }
 
-       gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p, %p, %p\n", port->port_num, tty, ch, __builtin_return_address(0), __builtin_return_address(1), __builtin_return_address(2));
+       gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n",
+               port->port_num, tty, ch, __builtin_return_address(0));
 
        spin_lock_irqsave(&port->port_lock, flags);
 
@@ -1116,7 +1094,11 @@ static int gs_send(struct gs_dev *dev)
                len = gs_send_packet(dev, req->buf, ep->maxpacket);
 
                if (len > 0) {
-gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2));
+                       gs_debug_level(3, "gs_send: len=%d, 0x%2.2x "
+                                       "0x%2.2x 0x%2.2x ...\n", len,
+                                       *((unsigned char *)req->buf),
+                                       *((unsigned char *)req->buf+1),
+                                       *((unsigned char *)req->buf+2));
                        list_del(&req_entry->re_entry);
                        req->length = len;
                        spin_unlock_irqrestore(&dev->dev_lock, flags);
@@ -1269,7 +1251,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req)
 
        switch(req->status) {
        case 0:
-               /* normal completion */
+               /* normal completion */
                gs_recv_packet(dev, req->buf, req->actual);
 requeue:
                req->length = ep->maxpacket;
@@ -1406,23 +1388,24 @@ static int __init gs_bind(struct usb_gadget *gadget)
                ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
        gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       gs_qualifier_desc.bDeviceClass = use_acm
-               ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
-       /* assume ep0 uses the same packet size for both speeds */
-       gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0;
-       /* assume endpoints are dual-speed */
-       gs_highspeed_notify_desc.bEndpointAddress =
-               gs_fullspeed_notify_desc.bEndpointAddress;
-       gs_highspeed_in_desc.bEndpointAddress =
-               gs_fullspeed_in_desc.bEndpointAddress;
-       gs_highspeed_out_desc.bEndpointAddress =
-               gs_fullspeed_out_desc.bEndpointAddress;
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+       if (gadget_is_dualspeed(gadget)) {
+               gs_qualifier_desc.bDeviceClass = use_acm
+                       ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
+               /* assume ep0 uses the same packet size for both speeds */
+               gs_qualifier_desc.bMaxPacketSize0 =
+                       gs_device_desc.bMaxPacketSize0;
+               /* assume endpoints are dual-speed */
+               gs_highspeed_notify_desc.bEndpointAddress =
+                       gs_fullspeed_notify_desc.bEndpointAddress;
+               gs_highspeed_in_desc.bEndpointAddress =
+                       gs_fullspeed_in_desc.bEndpointAddress;
+               gs_highspeed_out_desc.bEndpointAddress =
+                       gs_fullspeed_out_desc.bEndpointAddress;
+       }
 
        usb_gadget_set_selfpowered(gadget);
 
-       if (gadget->is_otg) {
+       if (gadget_is_otg(gadget)) {
                gs_otg_descriptor.bmAttributes |= USB_OTG_HNP,
                gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
                gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -1487,6 +1470,12 @@ static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget)
                        dev->dev_ctrl_req = NULL;
                }
                gs_free_ports(dev);
+               if (dev->dev_notify_ep)
+                       usb_ep_disable(dev->dev_notify_ep);
+               if (dev->dev_in_ep)
+                       usb_ep_disable(dev->dev_in_ep);
+               if (dev->dev_out_ep)
+                       usb_ep_disable(dev->dev_out_ep);
                kfree(dev);
                set_gadget_data(gadget, NULL);
        }
@@ -1570,9 +1559,8 @@ static int gs_setup_standard(struct usb_gadget *gadget,
                        memcpy(req->buf, &gs_device_desc, ret);
                        break;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
                case USB_DT_DEVICE_QUALIFIER:
-                       if (!gadget->is_dualspeed)
+                       if (!gadget_is_dualspeed(gadget))
                                break;
                        ret = min(wLength,
                                (u16)sizeof(struct usb_qualifier_descriptor));
@@ -1580,14 +1568,13 @@ static int gs_setup_standard(struct usb_gadget *gadget,
                        break;
 
                case USB_DT_OTHER_SPEED_CONFIG:
-                       if (!gadget->is_dualspeed)
+                       if (!gadget_is_dualspeed(gadget))
                                break;
                        /* fall through */
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
                case USB_DT_CONFIG:
-                       ret = gs_build_config_buf(req->buf, gadget->speed,
+                       ret = gs_build_config_buf(req->buf, gadget,
                                wValue >> 8, wValue & 0xff,
-                               gadget->is_otg);
+                               gadget_is_otg(gadget));
                        if (ret >= 0)
                                ret = min(wLength, (u16)ret);
                        break;
@@ -1827,8 +1814,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
 
                if (EP_NOTIFY_NAME
                && strcmp(ep->name, EP_NOTIFY_NAME) == 0) {
-                       ep_desc = GS_SPEED_SELECT(
-                               gadget->speed == USB_SPEED_HIGH,
+                       ep_desc = choose_ep_desc(gadget,
                                &gs_highspeed_notify_desc,
                                &gs_fullspeed_notify_desc);
                        ret = usb_ep_enable(ep,ep_desc);
@@ -1844,9 +1830,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
                }
 
                else if (strcmp(ep->name, EP_IN_NAME) == 0) {
-                       ep_desc = GS_SPEED_SELECT(
-                               gadget->speed == USB_SPEED_HIGH,
-                               &gs_highspeed_in_desc,
+                       ep_desc = choose_ep_desc(gadget,
+                               &gs_highspeed_in_desc,
                                &gs_fullspeed_in_desc);
                        ret = usb_ep_enable(ep,ep_desc);
                        if (ret == 0) {
@@ -1861,8 +1846,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
                }
 
                else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
-                       ep_desc = GS_SPEED_SELECT(
-                               gadget->speed == USB_SPEED_HIGH,
+                       ep_desc = choose_ep_desc(gadget,
                                &gs_highspeed_out_desc,
                                &gs_fullspeed_out_desc);
                        ret = usb_ep_enable(ep,ep_desc);
@@ -1981,11 +1965,11 @@ static void gs_reset_config(struct gs_dev *dev)
  * Builds the config descriptors in the given buffer and returns the
  * length, or a negative error number.
  */
-static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
+static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
        u8 type, unsigned int index, int is_otg)
 {
        int len;
-       int high_speed;
+       int high_speed = 0;
        const struct usb_config_descriptor *config_desc;
        const struct usb_descriptor_header **function;
 
@@ -1993,20 +1977,22 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
                return -EINVAL;
 
        /* other speed switches high and full speed */
-       high_speed = (speed == USB_SPEED_HIGH);
-       if (type == USB_DT_OTHER_SPEED_CONFIG)
-               high_speed = !high_speed;
+       if (gadget_is_dualspeed(g)) {
+               high_speed = (g->speed == USB_SPEED_HIGH);
+               if (type == USB_DT_OTHER_SPEED_CONFIG)
+                       high_speed = !high_speed;
+       }
 
        if (use_acm) {
                config_desc = &gs_acm_config_desc;
-               function = GS_SPEED_SELECT(high_speed,
-                       gs_acm_highspeed_function,
-                       gs_acm_fullspeed_function);
+               function = high_speed
+                       ? gs_acm_highspeed_function
+                       : gs_acm_fullspeed_function;
        } else {
                config_desc = &gs_bulk_config_desc;
-               function = GS_SPEED_SELECT(high_speed,
-                       gs_bulk_highspeed_function,
-                       gs_bulk_fullspeed_function);
+               function = high_speed
+                       ? gs_bulk_highspeed_function
+                       : gs_bulk_fullspeed_function;
        }
 
        /* for now, don't advertise srp-only devices */
index 3459ea6..878e428 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/init.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/unaligned.h>
 
index fcfe869..fcde5d9 100644 (file)
@@ -1,38 +1,22 @@
 /*
  * zero.c -- Gadget Zero, for USB development
  *
- * Copyright (C) 2003-2004 David Brownell
+ * Copyright (C) 2003-2007 David Brownell
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * 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.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation, either version 2 of that License or (at your option) any
- * later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 
  * Many drivers will only have one configuration, letting them be much
  * simpler if they also don't support high speed operation (like this
  * driver does).
+ *
+ * Why is *this* driver using two configurations, rather than setting up
+ * two interfaces with different functions?  To help verify that multiple
+ * configuration infrastucture is working correctly; also, so that it can
+ * work with low capability USB controllers without four bulk endpoints.
  */
 
-#define DEBUG 1
-// #define VERBOSE
+/* #define VERBOSE_DEBUG */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
 #include <linux/utsname.h>
 #include <linux/device.h>
-#include <linux/moduleparam.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
 
 /*-------------------------------------------------------------------------*/
 
-#define DRIVER_VERSION         "St Patrick's Day 2004"
+#define DRIVER_VERSION         "Lughnasadh, 2007"
 
 static const char shortname [] = "zero";
 static const char longname [] = "Gadget Zero";
@@ -131,30 +103,16 @@ struct zero_dev {
        struct timer_list       resume;
 };
 
-#define xprintk(d,level,fmt,args...) \
-       dev_printk(level , &(d)->gadget->dev , fmt , ## args)
-
-#ifdef DEBUG
-#define DBG(dev,fmt,args...) \
-       xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev,fmt,args...) \
-       do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG   DBG
-#else
-#define VDBG(dev,fmt,args...) \
-       do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev,fmt,args...) \
-       xprintk(dev , KERN_ERR , fmt , ## args)
-#define WARN(dev,fmt,args...) \
-       xprintk(dev , KERN_WARNING , fmt , ## args)
-#define INFO(dev,fmt,args...) \
-       xprintk(dev , KERN_INFO , fmt , ## args)
+#define DBG(d, fmt, args...) \
+       dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+       dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+       dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+       dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+       dev_info(&(d)->gadget->dev , fmt , ## args)
 
 /*-------------------------------------------------------------------------*/
 
@@ -326,8 +284,6 @@ static const struct usb_descriptor_header *fs_loopback_function [] = {
        NULL,
 };
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-
 /*
  * usb 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at full speed.
@@ -383,17 +339,20 @@ static const struct usb_descriptor_header *hs_loopback_function [] = {
 };
 
 /* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
-
-#else
+static inline struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+               struct usb_endpoint_descriptor *fs)
+{
+       if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+               return hs;
+       return fs;
+}
 
-/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g,hs,fs) fs
+static char manufacturer[50];
 
-#endif /* !CONFIG_USB_GADGET_DUALSPEED */
+/* default serial number takes at least two packets */
+static char serial[] = "0123456789.0123456789.0123456789";
 
-static char                            manufacturer [50];
-static char                            serial [40];
 
 /* static strings, in UTF-8 */
 static struct usb_string               strings [] = {
@@ -435,30 +394,29 @@ config_buf (struct usb_gadget *gadget,
        int                             is_source_sink;
        int                             len;
        const struct usb_descriptor_header **function;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       int                             hs = (gadget->speed == USB_SPEED_HIGH);
-#endif
+       int                             hs = 0;
 
        /* two configurations will always be index 0 and index 1 */
        if (index > 1)
                return -EINVAL;
        is_source_sink = loopdefault ? (index == 1) : (index == 0);
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       if (type == USB_DT_OTHER_SPEED_CONFIG)
-               hs = !hs;
+       if (gadget_is_dualspeed(gadget)) {
+               hs = (gadget->speed == USB_SPEED_HIGH);
+               if (type == USB_DT_OTHER_SPEED_CONFIG)
+                       hs = !hs;
+       }
        if (hs)
                function = is_source_sink
                        ? hs_source_sink_function
                        : hs_loopback_function;
        else
-#endif
                function = is_source_sink
                        ? fs_source_sink_function
                        : fs_loopback_function;
 
        /* for now, don't advertise srp-only devices */
-       if (!gadget->is_otg)
+       if (!gadget_is_otg(gadget))
                function++;
 
        len = usb_gadget_config_buf (is_source_sink
@@ -498,6 +456,19 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
 
 /*-------------------------------------------------------------------------*/
 
+/*
+ * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripherals,
+ * this just sinks bulk packets OUT to the peripheral and sources them IN
+ * to the host, optionally with specific data patterns.
+ *
+ * In terms of control messaging, this supports all the standard requests
+ * plus two that support control-OUT tests.
+ *
+ * Note that because this doesn't queue more than one request at a time,
+ * some other function must be used to test queueing logic.  The network
+ * link (g_ether) is probably the best option for that.
+ */
+
 /* optionally require specific source/sink data patterns  */
 
 static int
@@ -534,12 +505,7 @@ check_read_data (
        return 0;
 }
 
-static void
-reinit_write_data (
-       struct zero_dev         *dev,
-       struct usb_ep           *ep,
-       struct usb_request      *req
-)
+static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
 {
        unsigned        i;
        u8              *buf = req->buf;
@@ -566,16 +532,16 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
 
        switch (status) {
 
-       case 0:                         /* normal completion? */
+       case 0:                         /* normal completion? */
                if (ep == dev->out_ep) {
                        check_read_data (dev, ep, req);
                        memset (req->buf, 0x55, req->length);
                } else
-                       reinit_write_data (dev, ep, req);
+                       reinit_write_data(ep, req);
                break;
 
        /* this endpoint is normally active while we're configured */
-       case -ECONNABORTED:             /* hardware forced ep reset */
+       case -ECONNABORTED:             /* hardware forced ep reset */
        case -ECONNRESET:               /* request dequeued */
        case -ESHUTDOWN:                /* disconnect from host */
                VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
@@ -607,8 +573,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
        }
 }
 
-static struct usb_request *
-source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
+static struct usb_request *source_sink_start_ep(struct usb_ep *ep)
 {
        struct usb_request      *req;
        int                     status;
@@ -621,11 +586,11 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
        req->complete = source_sink_complete;
 
        if (strcmp (ep->name, EP_IN_NAME) == 0)
-               reinit_write_data (ep->driver_data, ep, req);
+               reinit_write_data(ep, req);
        else
                memset (req->buf, 0x55, req->length);
 
-       status = usb_ep_queue (ep, req, gfp_flags);
+       status = usb_ep_queue(ep, req, GFP_ATOMIC);
        if (status) {
                struct zero_dev *dev = ep->driver_data;
 
@@ -637,8 +602,7 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
        return req;
 }
 
-static int
-set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
+static int set_source_sink_config(struct zero_dev *dev)
 {
        int                     result = 0;
        struct usb_ep           *ep;
@@ -653,8 +617,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
                        result = usb_ep_enable (ep, d);
                        if (result == 0) {
                                ep->driver_data = dev;
-                               if (source_sink_start_ep(ep, gfp_flags)
-                                               != NULL) {
+                               if (source_sink_start_ep(ep) != NULL) {
                                        dev->in_ep = ep;
                                        continue;
                                }
@@ -668,8 +631,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
                        result = usb_ep_enable (ep, d);
                        if (result == 0) {
                                ep->driver_data = dev;
-                               if (source_sink_start_ep(ep, gfp_flags)
-                                               != NULL) {
+                               if (source_sink_start_ep(ep) != NULL) {
                                        dev->out_ep = ep;
                                        continue;
                                }
@@ -701,7 +663,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
 
        switch (status) {
 
-       case 0:                         /* normal completion? */
+       case 0:                         /* normal completion? */
                if (ep == dev->out_ep) {
                        /* loop this OUT packet back IN to the host */
                        req->zero = (req->actual < req->length);
@@ -735,7 +697,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
         * rely on the hardware driver to clean up on disconnect or
         * endpoint disable.
         */
-       case -ECONNABORTED:             /* hardware forced ep reset */
+       case -ECONNABORTED:             /* hardware forced ep reset */
        case -ECONNRESET:               /* request dequeued */
        case -ESHUTDOWN:                /* disconnect from host */
                free_ep_req (ep, req);
@@ -743,8 +705,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
        }
 }
 
-static int
-set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags)
+static int set_loopback_config(struct zero_dev *dev)
 {
        int                     result = 0;
        struct usb_ep           *ep;
@@ -844,8 +805,7 @@ static void zero_reset_config (struct zero_dev *dev)
  * code can do, perhaps by disallowing more than one configuration or
  * by limiting configuration choices (like the pxa2xx).
  */
-static int
-zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
+static int zero_set_config(struct zero_dev *dev, unsigned number)
 {
        int                     result = 0;
        struct usb_gadget       *gadget = dev->gadget;
@@ -855,17 +815,17 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
 
        if (gadget_is_sa1100 (gadget) && dev->config) {
                /* tx fifo is full, but we can't clear it...*/
-               INFO (dev, "can't change configurations\n");
+               ERROR(dev, "can't change configurations\n");
                return -ESPIPE;
        }
        zero_reset_config (dev);
 
        switch (number) {
        case CONFIG_SOURCE_SINK:
-               result = set_source_sink_config (dev, gfp_flags);
+               result = set_source_sink_config(dev);
                break;
        case CONFIG_LOOPBACK:
-               result = set_loopback_config (dev, gfp_flags);
+               result = set_loopback_config(dev);
                break;
        default:
                result = -EINVAL;
@@ -885,7 +845,7 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
                case USB_SPEED_LOW:     speed = "low"; break;
                case USB_SPEED_FULL:    speed = "full"; break;
                case USB_SPEED_HIGH:    speed = "high"; break;
-               default:                speed = "?"; break;
+               default:                speed = "?"; break;
                }
 
                dev->config = number;
@@ -938,19 +898,17 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                        value = min (w_length, (u16) sizeof device_desc);
                        memcpy (req->buf, &device_desc, value);
                        break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
                case USB_DT_DEVICE_QUALIFIER:
-                       if (!gadget->is_dualspeed)
+                       if (!gadget_is_dualspeed(gadget))
                                break;
                        value = min (w_length, (u16) sizeof dev_qualifier);
                        memcpy (req->buf, &dev_qualifier, value);
                        break;
 
                case USB_DT_OTHER_SPEED_CONFIG:
-                       if (!gadget->is_dualspeed)
+                       if (!gadget_is_dualspeed(gadget))
                                break;
                        // FALLTHROUGH
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
                case USB_DT_CONFIG:
                        value = config_buf (gadget, req->buf,
                                        w_value >> 8,
@@ -984,7 +942,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                else
                        VDBG (dev, "HNP inactive\n");
                spin_lock (&dev->lock);
-               value = zero_set_config (dev, w_value, GFP_ATOMIC);
+               value = zero_set_config(dev, w_value);
                spin_unlock (&dev->lock);
                break;
        case USB_REQ_GET_CONFIGURATION:
@@ -1013,7 +971,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                         * use this "reset the config" shortcut.
                         */
                        zero_reset_config (dev);
-                       zero_set_config (dev, config, GFP_ATOMIC);
+                       zero_set_config(dev, config);
                        value = 0;
                }
                spin_unlock (&dev->lock);
@@ -1163,7 +1121,7 @@ autoconf_fail:
        }
        EP_IN_NAME = ep->name;
        ep->driver_data = ep;   /* claim */
-       
+
        ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
        if (!ep)
                goto autoconf_fail;
@@ -1207,16 +1165,18 @@ autoconf_fail:
 
        device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-       /* assume ep0 uses the same value for both speeds ... */
-       dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+       if (gadget_is_dualspeed(gadget)) {
+               /* assume ep0 uses the same value for both speeds ... */
+               dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
 
-       /* and that all endpoints are dual-speed */
-       hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
-       hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
-#endif
+               /* and that all endpoints are dual-speed */
+               hs_source_desc.bEndpointAddress =
+                               fs_source_desc.bEndpointAddress;
+               hs_sink_desc.bEndpointAddress =
+                               fs_sink_desc.bEndpointAddress;
+       }
 
-       if (gadget->is_otg) {
+       if (gadget_is_otg(gadget)) {
                otg_descriptor.bmAttributes |= USB_OTG_HNP,
                source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
                loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -1294,23 +1254,18 @@ static struct usb_gadget_driver zero_driver = {
        .suspend        = zero_suspend,
        .resume         = zero_resume,
 
-       .driver         = {
+       .driver         = {
                .name           = (char *) shortname,
                .owner          = THIS_MODULE,
        },
 };
 
-MODULE_AUTHOR ("David Brownell");
-MODULE_LICENSE ("Dual BSD/GPL");
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
 
 
 static int __init init (void)
 {
-       /* a real value would likely come through some id prom
-        * or module option.  this one takes at least two packets.
-        */
-       strlcpy (serial, "0123456789.0123456789.0123456789", sizeof serial);
-
        return usb_gadget_register_driver (&zero_driver);
 }
 module_init (init);
index 565d6ef..c978d62 100644 (file)
@@ -154,6 +154,19 @@ config USB_OHCI_HCD_PCI
          Enables support for PCI-bus plug-in USB controller cards.
          If unsure, say Y.
 
+config USB_OHCI_HCD_SSB
+       bool "OHCI support for Broadcom SSB OHCI core"
+       depends on USB_OHCI_HCD && SSB && EXPERIMENTAL
+       default n
+       ---help---
+         Support for the Sonics Silicon Backplane (SSB) attached
+         Broadcom USB OHCI core.
+
+         This device is present in some embedded devices with
+         Broadcom based SSB bus.
+
+         If unsure, say N.
+
 config USB_OHCI_BIG_ENDIAN_DESC
        bool
        depends on USB_OHCI_HCD
index b1d1926..766ef68 100644 (file)
@@ -220,10 +220,8 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
         */
        .hub_status_data = ehci_hub_status_data,
        .hub_control = ehci_hub_control,
-#ifdef CONFIG_PM
-       .hub_suspend = ehci_hub_suspend,
-       .hub_resume = ehci_hub_resume,
-#endif
+       .bus_suspend = ehci_bus_suspend,
+       .bus_resume = ehci_bus_resume,
 };
 
 /*-------------------------------------------------------------------------*/
index 35cdba1..c151444 100644 (file)
@@ -570,10 +570,18 @@ static int ehci_run (struct usb_hcd *hcd)
         * are explicitly handed to companion controller(s), so no TT is
         * involved with the root hub.  (Except where one is integrated,
         * and there's no companion controller unless maybe for USB OTG.)
+        *
+        * Turning on the CF flag will transfer ownership of all ports
+        * from the companions to the EHCI controller.  If any of the
+        * companions are in the middle of a port reset at the time, it
+        * could cause trouble.  Write-locking ehci_cf_port_reset_rwsem
+        * guarantees that no resets are in progress.
         */
+       down_write(&ehci_cf_port_reset_rwsem);
        hcd->state = HC_STATE_RUNNING;
        ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
        ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
+       up_write(&ehci_cf_port_reset_rwsem);
 
        temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
        ehci_info (ehci,
@@ -719,7 +727,6 @@ dead:
  */
 static int ehci_urb_enqueue (
        struct usb_hcd  *hcd,
-       struct usb_host_endpoint *ep,
        struct urb      *urb,
        gfp_t           mem_flags
 ) {
@@ -734,12 +741,12 @@ static int ehci_urb_enqueue (
        default:
                if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
                        return -ENOMEM;
-               return submit_async (ehci, ep, urb, &qtd_list, mem_flags);
+               return submit_async(ehci, urb, &qtd_list, mem_flags);
 
        case PIPE_INTERRUPT:
                if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
                        return -ENOMEM;
-               return intr_submit (ehci, ep, urb, &qtd_list, mem_flags);
+               return intr_submit(ehci, urb, &qtd_list, mem_flags);
 
        case PIPE_ISOCHRONOUS:
                if (urb->dev->speed == USB_SPEED_HIGH)
@@ -777,13 +784,18 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
  * completions normally happen asynchronously
  */
 
-static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
        struct ehci_qh          *qh;
        unsigned long           flags;
+       int                     rc;
 
        spin_lock_irqsave (&ehci->lock, flags);
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (rc)
+               goto done;
+
        switch (usb_pipetype (urb->pipe)) {
        // case PIPE_CONTROL:
        // case PIPE_BULK:
@@ -838,7 +850,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
        }
 done:
        spin_unlock_irqrestore (&ehci->lock, flags);
-       return 0;
+       return rc;
 }
 
 /*-------------------------------------------------------------------------*/
index a7816e3..ad0d496 100644 (file)
@@ -58,8 +58,6 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
        if (!retval)
                ehci_dbg(ehci, "MWI active\n");
 
-       ehci_port_power(ehci, 0);
-
        return 0;
 }
 
@@ -156,8 +154,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
                break;
        }
 
-       if (ehci_is_TDI(ehci))
-               ehci_reset(ehci);
+       ehci_reset(ehci);
 
        /* at least the Genesys GL880S needs fixup here */
        temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
index 4f99b0e..452d4b1 100644 (file)
@@ -160,10 +160,8 @@ static const struct hc_driver ehci_ppc_soc_hc_driver = {
         */
        .hub_status_data = ehci_hub_status_data,
        .hub_control = ehci_hub_control,
-#ifdef CONFIG_PM
-       .hub_suspend = ehci_hub_suspend,
-       .hub_resume = ehci_hub_resume,
-#endif
+       .bus_suspend = ehci_bus_suspend,
+       .bus_resume = ehci_bus_resume,
 };
 
 static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev)
index 829fe64..03a6b2f 100644 (file)
@@ -47,7 +47,7 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
        if (result)
                return result;
 
-       ehci_port_power(ehci, 0);
+       ehci_reset(ehci);
 
        return result;
 }
index 140bfa4..b10f39c 100644 (file)
@@ -139,63 +139,65 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
 /*-------------------------------------------------------------------------*/
 
-static void qtd_copy_status (
+static int qtd_copy_status (
        struct ehci_hcd *ehci,
        struct urb *urb,
        size_t length,
        u32 token
 )
 {
+       int     status = -EINPROGRESS;
+
        /* count IN/OUT bytes, not SETUP (even short packets) */
        if (likely (QTD_PID (token) != 2))
                urb->actual_length += length - QTD_LENGTH (token);
 
        /* don't modify error codes */
-       if (unlikely (urb->status != -EINPROGRESS))
-               return;
+       if (unlikely(urb->unlinked))
+               return status;
 
        /* force cleanup after short read; not always an error */
        if (unlikely (IS_SHORT_READ (token)))
-               urb->status = -EREMOTEIO;
+               status = -EREMOTEIO;
 
        /* serious "can't proceed" faults reported by the hardware */
        if (token & QTD_STS_HALT) {
                if (token & QTD_STS_BABBLE) {
                        /* FIXME "must" disable babbling device's port too */
-                       urb->status = -EOVERFLOW;
+                       status = -EOVERFLOW;
                } else if (token & QTD_STS_MMF) {
                        /* fs/ls interrupt xfer missed the complete-split */
-                       urb->status = -EPROTO;
+                       status = -EPROTO;
                } else if (token & QTD_STS_DBE) {
-                       urb->status = (QTD_PID (token) == 1) /* IN ? */
+                       status = (QTD_PID (token) == 1) /* IN ? */
                                ? -ENOSR  /* hc couldn't read data */
                                : -ECOMM; /* hc couldn't write data */
                } else if (token & QTD_STS_XACT) {
                        /* timeout, bad crc, wrong PID, etc; retried */
                        if (QTD_CERR (token))
-                               urb->status = -EPIPE;
+                               status = -EPIPE;
                        else {
                                ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n",
                                        urb->dev->devpath,
                                        usb_pipeendpoint (urb->pipe),
                                        usb_pipein (urb->pipe) ? "in" : "out");
-                               urb->status = -EPROTO;
+                               status = -EPROTO;
                        }
                /* CERR nonzero + no errors + halt --> stall */
                } else if (QTD_CERR (token))
-                       urb->status = -EPIPE;
+                       status = -EPIPE;
                else    /* unknown */
-                       urb->status = -EPROTO;
+                       status = -EPROTO;
 
                ehci_vdbg (ehci,
                        "dev%d ep%d%s qtd token %08x --> status %d\n",
                        usb_pipedevice (urb->pipe),
                        usb_pipeendpoint (urb->pipe),
                        usb_pipein (urb->pipe) ? "in" : "out",
-                       token, urb->status);
+                       token, status);
 
                /* if async CSPLIT failed, try cleaning out the TT buffer */
-               if (urb->status != -EPIPE
+               if (status != -EPIPE
                                && urb->dev->tt && !usb_pipeint (urb->pipe)
                                && ((token & QTD_STS_MMF) != 0
                                        || QTD_CERR(token) == 0)
@@ -212,10 +214,12 @@ static void qtd_copy_status (
                        usb_hub_tt_clear_buffer (urb->dev, urb->pipe);
                }
        }
+
+       return status;
 }
 
 static void
-ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb)
+ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status)
 __releases(ehci->lock)
 __acquires(ehci->lock)
 {
@@ -231,25 +235,13 @@ __acquires(ehci->lock)
                qh_put (qh);
        }
 
-       spin_lock (&urb->lock);
-       urb->hcpriv = NULL;
-       switch (urb->status) {
-       case -EINPROGRESS:              /* success */
-               urb->status = 0;
-       default:                        /* fault */
-               COUNT (ehci->stats.complete);
-               break;
-       case -EREMOTEIO:                /* fault or normal */
-               if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
-                       urb->status = 0;
-               COUNT (ehci->stats.complete);
-               break;
-       case -ECONNRESET:               /* canceled */
-       case -ENOENT:
-               COUNT (ehci->stats.unlink);
-               break;
+       if (unlikely(urb->unlinked)) {
+               COUNT(ehci->stats.unlink);
+       } else {
+               if (likely(status == -EINPROGRESS))
+                       status = 0;
+               COUNT(ehci->stats.complete);
        }
-       spin_unlock (&urb->lock);
 
 #ifdef EHCI_URB_TRACE
        ehci_dbg (ehci,
@@ -257,13 +249,14 @@ __acquires(ehci->lock)
                __FUNCTION__, urb->dev->devpath, urb,
                usb_pipeendpoint (urb->pipe),
                usb_pipein (urb->pipe) ? "in" : "out",
-               urb->status,
+               status,
                urb->actual_length, urb->transfer_buffer_length);
 #endif
 
        /* complete() can reenter this HCD */
+       usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
        spin_unlock (&ehci->lock);
-       usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb);
+       usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status);
        spin_lock (&ehci->lock);
 }
 
@@ -283,6 +276,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
        struct ehci_qtd         *last = NULL, *end = qh->dummy;
        struct list_head        *entry, *tmp;
+       int                     last_status = -EINPROGRESS;
        int                     stopped;
        unsigned                count = 0;
        int                     do_status = 0;
@@ -311,6 +305,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
                struct ehci_qtd *qtd;
                struct urb      *urb;
                u32             token = 0;
+               int             qtd_status;
 
                qtd = list_entry (entry, struct ehci_qtd, qtd_list);
                urb = qtd->urb;
@@ -318,11 +313,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
                /* clean up any state from previous QTD ...*/
                if (last) {
                        if (likely (last->urb != urb)) {
-                               ehci_urb_done (ehci, last->urb);
+                               ehci_urb_done(ehci, last->urb, last_status);
                                count++;
                        }
                        ehci_qtd_free (ehci, last);
                        last = NULL;
+                       last_status = -EINPROGRESS;
                }
 
                /* ignore urbs submitted during completions we reported */
@@ -358,13 +354,14 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
                        stopped = 1;
 
                        if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)))
-                               urb->status = -ESHUTDOWN;
+                               last_status = -ESHUTDOWN;
 
                        /* ignore active urbs unless some previous qtd
                         * for the urb faulted (including short read) or
                         * its urb was canceled.  we may patch qh or qtds.
                         */
-                       if (likely (urb->status == -EINPROGRESS))
+                       if (likely(last_status == -EINPROGRESS &&
+                                       !urb->unlinked))
                                continue;
 
                        /* issue status after short control reads */
@@ -392,11 +389,14 @@ halt:
                }
 
                /* remove it from the queue */
-               spin_lock (&urb->lock);
-               qtd_copy_status (ehci, urb, qtd->length, token);
-               do_status = (urb->status == -EREMOTEIO)
-                               && usb_pipecontrol (urb->pipe);
-               spin_unlock (&urb->lock);
+               qtd_status = qtd_copy_status(ehci, urb, qtd->length, token);
+               if (unlikely(qtd_status == -EREMOTEIO)) {
+                       do_status = (!urb->unlinked &&
+                                       usb_pipecontrol(urb->pipe));
+                       qtd_status = 0;
+               }
+               if (likely(last_status == -EINPROGRESS))
+                       last_status = qtd_status;
 
                if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
                        last = list_entry (qtd->qtd_list.prev,
@@ -409,7 +409,7 @@ halt:
 
        /* last urb's completion might still need calling */
        if (likely (last != NULL)) {
-               ehci_urb_done (ehci, last->urb);
+               ehci_urb_done(ehci, last->urb, last_status);
                count++;
                ehci_qtd_free (ehci, last);
        }
@@ -913,7 +913,6 @@ static struct ehci_qh *qh_append_tds (
 static int
 submit_async (
        struct ehci_hcd         *ehci,
-       struct usb_host_endpoint *ep,
        struct urb              *urb,
        struct list_head        *qtd_list,
        gfp_t                   mem_flags
@@ -922,10 +921,10 @@ submit_async (
        int                     epnum;
        unsigned long           flags;
        struct ehci_qh          *qh = NULL;
-       int                     rc = 0;
+       int                     rc;
 
        qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
-       epnum = ep->desc.bEndpointAddress;
+       epnum = urb->ep->desc.bEndpointAddress;
 
 #ifdef EHCI_URB_TRACE
        ehci_dbg (ehci,
@@ -933,7 +932,7 @@ submit_async (
                __FUNCTION__, urb->dev->devpath, urb,
                epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
                urb->transfer_buffer_length,
-               qtd, ep->hcpriv);
+               qtd, urb->ep->hcpriv);
 #endif
 
        spin_lock_irqsave (&ehci->lock, flags);
@@ -942,9 +941,13 @@ submit_async (
                rc = -ESHUTDOWN;
                goto done;
        }
+       rc = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+       if (unlikely(rc))
+               goto done;
 
-       qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+       qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
        if (unlikely(qh == NULL)) {
+               usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
                rc = -ENOMEM;
                goto done;
        }
index e682f23..80d99bc 100644 (file)
@@ -797,7 +797,6 @@ done:
 
 static int intr_submit (
        struct ehci_hcd         *ehci,
-       struct usb_host_endpoint *ep,
        struct urb              *urb,
        struct list_head        *qtd_list,
        gfp_t                   mem_flags
@@ -805,23 +804,26 @@ static int intr_submit (
        unsigned                epnum;
        unsigned long           flags;
        struct ehci_qh          *qh;
-       int                     status = 0;
+       int                     status;
        struct list_head        empty;
 
        /* get endpoint and transfer/schedule data */
-       epnum = ep->desc.bEndpointAddress;
+       epnum = urb->ep->desc.bEndpointAddress;
 
        spin_lock_irqsave (&ehci->lock, flags);
 
        if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
                        &ehci_to_hcd(ehci)->flags))) {
                status = -ESHUTDOWN;
-               goto done;
+               goto done_not_linked;
        }
+       status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+       if (unlikely(status))
+               goto done_not_linked;
 
        /* get qh and force any scheduling errors */
        INIT_LIST_HEAD (&empty);
-       qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv);
+       qh = qh_append_tds(ehci, urb, &empty, epnum, &urb->ep->hcpriv);
        if (qh == NULL) {
                status = -ENOMEM;
                goto done;
@@ -832,13 +834,16 @@ static int intr_submit (
        }
 
        /* then queue the urb's tds to the qh */
-       qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+       qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
        BUG_ON (qh == NULL);
 
        /* ... update usbfs periodic stats */
        ehci_to_hcd(ehci)->self.bandwidth_int_reqs++;
 
 done:
+       if (unlikely(status))
+               usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
        spin_unlock_irqrestore (&ehci->lock, flags);
        if (status)
                qtd_list_free (ehci, urb, qtd_list);
@@ -1622,7 +1627,7 @@ itd_complete (
 
        /* give urb back to the driver ... can be out-of-order */
        dev = urb->dev;
-       ehci_urb_done (ehci, urb);
+       ehci_urb_done(ehci, urb, 0);
        urb = NULL;
 
        /* defer stopping schedule; completion can submit */
@@ -1686,12 +1691,19 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
        /* schedule ... need to lock */
        spin_lock_irqsave (&ehci->lock, flags);
        if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
-                              &ehci_to_hcd(ehci)->flags)))
+                              &ehci_to_hcd(ehci)->flags))) {
                status = -ESHUTDOWN;
-       else
-               status = iso_stream_schedule (ehci, urb, stream);
+               goto done_not_linked;
+       }
+       status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+       if (unlikely(status))
+               goto done_not_linked;
+       status = iso_stream_schedule(ehci, urb, stream);
        if (likely (status == 0))
                itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+       else
+               usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
        spin_unlock_irqrestore (&ehci->lock, flags);
 
 done:
@@ -1988,7 +2000,7 @@ sitd_complete (
 
        /* give urb back to the driver */
        dev = urb->dev;
-       ehci_urb_done (ehci, urb);
+       ehci_urb_done(ehci, urb, 0);
        urb = NULL;
 
        /* defer stopping schedule; completion can submit */
@@ -2049,12 +2061,19 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
        /* schedule ... need to lock */
        spin_lock_irqsave (&ehci->lock, flags);
        if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
-                              &ehci_to_hcd(ehci)->flags)))
+                              &ehci_to_hcd(ehci)->flags))) {
                status = -ESHUTDOWN;
-       else
-               status = iso_stream_schedule (ehci, urb, stream);
+               goto done_not_linked;
+       }
+       status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+       if (unlikely(status))
+               goto done_not_linked;
+       status = iso_stream_schedule(ehci, urb, stream);
        if (status == 0)
                sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+       else
+               usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
        spin_unlock_irqrestore (&ehci->lock, flags);
 
 done:
index 5c851a3..c27417f 100644 (file)
@@ -277,12 +277,11 @@ static void preproc_atl_queue(struct isp116x *isp116x)
   processed urbs.
 */
 static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
-                          struct urb *urb)
+                          struct urb *urb, int status)
 __releases(isp116x->lock) __acquires(isp116x->lock)
 {
        unsigned i;
 
-       urb->hcpriv = NULL;
        ep->error_count = 0;
 
        if (usb_pipecontrol(urb->pipe))
@@ -290,8 +289,9 @@ __releases(isp116x->lock) __acquires(isp116x->lock)
 
        urb_dbg(urb, "Finish");
 
+       usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb);
        spin_unlock(&isp116x->lock);
-       usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
+       usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, status);
        spin_lock(&isp116x->lock);
 
        /* take idle endpoints out of the schedule */
@@ -445,12 +445,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
                        if (PTD_GET_ACTIVE(ptd)
                            || (cc != TD_CC_NOERROR && cc < 0x0E))
                                break;
-                       if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
-                                       urb->actual_length <
-                                               urb->transfer_buffer_length)
-                               status = -EREMOTEIO;
-                       else
-                               status = 0;
+                       status = 0;
                        ep->nextpid = 0;
                        break;
                default:
@@ -458,14 +453,8 @@ static void postproc_atl_queue(struct isp116x *isp116x)
                }
 
  done:
-               if (status != -EINPROGRESS) {
-                       spin_lock(&urb->lock);
-                       if (urb->status == -EINPROGRESS)
-                               urb->status = status;
-                       spin_unlock(&urb->lock);
-               }
-               if (urb->status != -EINPROGRESS)
-                       finish_request(isp116x, ep, urb);
+               if (status != -EINPROGRESS || urb->unlinked)
+                       finish_request(isp116x, ep, urb, status);
        }
 }
 
@@ -673,7 +662,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load)
 /*-----------------------------------------------------------------*/
 
 static int isp116x_urb_enqueue(struct usb_hcd *hcd,
-                              struct usb_host_endpoint *hep, struct urb *urb,
+                              struct urb *urb,
                               gfp_t mem_flags)
 {
        struct isp116x *isp116x = hcd_to_isp116x(hcd);
@@ -682,6 +671,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
        int is_out = !usb_pipein(pipe);
        int type = usb_pipetype(pipe);
        int epnum = usb_pipeendpoint(pipe);
+       struct usb_host_endpoint *hep = urb->ep;
        struct isp116x_ep *ep = NULL;
        unsigned long flags;
        int i;
@@ -705,7 +695,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
        if (!HC_IS_RUNNING(hcd->state)) {
                kfree(ep);
                ret = -ENODEV;
-               goto fail;
+               goto fail_not_linked;
+       }
+       ret = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (ret) {
+               kfree(ep);
+               goto fail_not_linked;
        }
 
        if (hep->hcpriv)
@@ -808,16 +803,13 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
                }
        }
 
-       /* in case of unlink-during-submit */
-       if (urb->status != -EINPROGRESS) {
-               finish_request(isp116x, ep, urb);
-               ret = 0;
-               goto fail;
-       }
        urb->hcpriv = hep;
        start_atl_transfers(isp116x);
 
       fail:
+       if (ret)
+               usb_hcd_unlink_urb_from_ep(hcd, urb);
+      fail_not_linked:
        spin_unlock_irqrestore(&isp116x->lock, flags);
        return ret;
 }
@@ -825,20 +817,21 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
 /*
    Dequeue URBs.
 */
-static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+               int status)
 {
        struct isp116x *isp116x = hcd_to_isp116x(hcd);
        struct usb_host_endpoint *hep;
        struct isp116x_ep *ep, *ep_act;
        unsigned long flags;
+       int rc;
 
        spin_lock_irqsave(&isp116x->lock, flags);
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (rc)
+               goto done;
+
        hep = urb->hcpriv;
-       /* URB already unlinked (or never linked)? */
-       if (!hep) {
-               spin_unlock_irqrestore(&isp116x->lock, flags);
-               return 0;
-       }
        ep = hep->hcpriv;
        WARN_ON(hep != ep->hep);
 
@@ -855,10 +848,10 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
                        }
 
        if (urb)
-               finish_request(isp116x, ep, urb);
-
+               finish_request(isp116x, ep, urb, status);
+ done:
        spin_unlock_irqrestore(&isp116x->lock, flags);
-       return 0;
+       return rc;
 }
 
 static void isp116x_endpoint_disable(struct usb_hcd *hcd,
index f61c6cd..ebab5ce 100644 (file)
@@ -24,7 +24,7 @@
  * small: 0) header + data packets 1) just header
  */
 static void __maybe_unused
-urb_print (struct urb * urb, char * str, int small)
+urb_print(struct urb * urb, char * str, int small, int status)
 {
        unsigned int pipe= urb->pipe;
 
@@ -34,7 +34,7 @@ urb_print (struct urb * urb, char * str, int small)
        }
 
 #ifndef        OHCI_VERBOSE_DEBUG
-       if (urb->status != 0)
+       if (status != 0)
 #endif
        dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d",
                    str,
@@ -46,7 +46,7 @@ urb_print (struct urb * urb, char * str, int small)
                    urb->transfer_flags,
                    urb->actual_length,
                    urb->transfer_buffer_length,
-                   urb->status);
+                   status);
 
 #ifdef OHCI_VERBOSE_DEBUG
        if (!small) {
@@ -66,7 +66,7 @@ urb_print (struct urb * urb, char * str, int small)
                                                urb->transfer_buffer_length: urb->actual_length;
                        for (i = 0; i < 16 && i < len; i++)
                                printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
-                       printk ("%s stat:%d\n", i < len? "...": "", urb->status);
+                       printk ("%s stat:%d\n", i < len? "...": "", status);
                }
        }
 #endif
index 6edf409..240c7f5 100644 (file)
@@ -81,7 +81,6 @@ static void ohci_dump (struct ohci_hcd *ohci, int verbose);
 static int ohci_init (struct ohci_hcd *ohci);
 static void ohci_stop (struct usb_hcd *hcd);
 static int ohci_restart (struct ohci_hcd *ohci);
-static void ohci_quirk_nec_worker (struct work_struct *work);
 
 #include "ohci-hub.c"
 #include "ohci-dbg.c"
@@ -118,7 +117,6 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake");
  */
 static int ohci_urb_enqueue (
        struct usb_hcd  *hcd,
-       struct usb_host_endpoint *ep,
        struct urb      *urb,
        gfp_t           mem_flags
 ) {
@@ -131,11 +129,11 @@ static int ohci_urb_enqueue (
        int             retval = 0;
 
 #ifdef OHCI_VERBOSE_DEBUG
-       urb_print (urb, "SUB", usb_pipein (pipe));
+       urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS);
 #endif
 
        /* every endpoint has a ed, locate and maybe (re)initialize it */
-       if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval)))
+       if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval)))
                return -ENOMEM;
 
        /* for the private part of the URB we need the number of TDs (size) */
@@ -200,22 +198,17 @@ static int ohci_urb_enqueue (
                retval = -ENODEV;
                goto fail;
        }
-
-       /* in case of unlink-during-submit */
-       spin_lock (&urb->lock);
-       if (urb->status != -EINPROGRESS) {
-               spin_unlock (&urb->lock);
-               urb->hcpriv = urb_priv;
-               finish_urb (ohci, urb);
-               retval = 0;
+       retval = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (retval)
                goto fail;
-       }
 
        /* schedule the ed if needed */
        if (ed->state == ED_IDLE) {
                retval = ed_schedule (ohci, ed);
-               if (retval < 0)
-                       goto fail0;
+               if (retval < 0) {
+                       usb_hcd_unlink_urb_from_ep(hcd, urb);
+                       goto fail;
+               }
                if (ed->type == PIPE_ISOCHRONOUS) {
                        u16     frame = ohci_frame_no(ohci);
 
@@ -239,8 +232,6 @@ static int ohci_urb_enqueue (
        urb->hcpriv = urb_priv;
        td_submit_urb (ohci, urb);
 
-fail0:
-       spin_unlock (&urb->lock);
 fail:
        if (retval)
                urb_free_priv (ohci, urb_priv);
@@ -249,22 +240,26 @@ fail:
 }
 
 /*
- * decouple the URB from the HC queues (TDs, urb_priv); it's
- * already marked using urb->status.  reporting is always done
+ * decouple the URB from the HC queues (TDs, urb_priv).
+ * reporting is always done
  * asynchronously, and we might be dealing with an urb that's
  * partially transferred, or an ED with other urbs being unlinked.
  */
-static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
        struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
        unsigned long           flags;
+       int                     rc;
 
 #ifdef OHCI_VERBOSE_DEBUG
-       urb_print (urb, "UNLINK", 1);
+       urb_print(urb, "UNLINK", 1, status);
 #endif
 
        spin_lock_irqsave (&ohci->lock, flags);
-       if (HC_IS_RUNNING(hcd->state)) {
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (rc) {
+               ;       /* Do nothing */
+       } else if (HC_IS_RUNNING(hcd->state)) {
                urb_priv_t  *urb_priv;
 
                /* Unless an IRQ completed the unlink while it was being
@@ -282,10 +277,10 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
                 * any more ... just clean up every urb's memory.
                 */
                if (urb->hcpriv)
-                       finish_urb (ohci, urb);
+                       finish_urb(ohci, urb, status);
        }
        spin_unlock_irqrestore (&ohci->lock, flags);
-       return 0;
+       return rc;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -314,6 +309,8 @@ rescan:
        if (!HC_IS_RUNNING (hcd->state)) {
 sanitize:
                ed->state = ED_IDLE;
+               if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+                       ohci->eds_scheduled--;
                finish_unlinks (ohci, 0);
        }
 
@@ -321,7 +318,12 @@ sanitize:
        case ED_UNLINK:         /* wait for hw to finish? */
                /* major IRQ delivery trouble loses INTR_SF too... */
                if (limit-- == 0) {
-                       ohci_warn (ohci, "IRQ INTR_SF lossage\n");
+                       ohci_warn(ohci, "ED unlink timeout\n");
+                       if (quirk_zfmicro(ohci)) {
+                               ohci_warn(ohci, "Attempting ZF TD recovery\n");
+                               ohci->ed_to_check = ed;
+                               ohci->zf_delay = 2;
+                       }
                        goto sanitize;
                }
                spin_unlock_irqrestore (&ohci->lock, flags);
@@ -379,6 +381,93 @@ ohci_shutdown (struct usb_hcd *hcd)
        (void) ohci_readl (ohci, &ohci->regs->control);
 }
 
+static int check_ed(struct ohci_hcd *ohci, struct ed *ed)
+{
+       return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0
+               && (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK)
+                       == (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK)
+               && !list_empty(&ed->td_list);
+}
+
+/* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes
+ * an interrupt TD but neglects to add it to the donelist.  On systems with
+ * this chipset, we need to periodically check the state of the queues to look
+ * for such "lost" TDs.
+ */
+static void unlink_watchdog_func(unsigned long _ohci)
+{
+       long            flags;
+       unsigned        max;
+       unsigned        seen_count = 0;
+       unsigned        i;
+       struct ed       **seen = NULL;
+       struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci;
+
+       spin_lock_irqsave(&ohci->lock, flags);
+       max = ohci->eds_scheduled;
+       if (!max)
+               goto done;
+
+       if (ohci->ed_to_check)
+               goto out;
+
+       seen = kcalloc(max, sizeof *seen, GFP_ATOMIC);
+       if (!seen)
+               goto out;
+
+       for (i = 0; i < NUM_INTS; i++) {
+               struct ed       *ed = ohci->periodic[i];
+
+               while (ed) {
+                       unsigned        temp;
+
+                       /* scan this branch of the periodic schedule tree */
+                       for (temp = 0; temp < seen_count; temp++) {
+                               if (seen[temp] == ed) {
+                                       /* we've checked it and what's after */
+                                       ed = NULL;
+                                       break;
+                               }
+                       }
+                       if (!ed)
+                               break;
+                       seen[seen_count++] = ed;
+                       if (!check_ed(ohci, ed)) {
+                               ed = ed->ed_next;
+                               continue;
+                       }
+
+                       /* HC's TD list is empty, but HCD sees at least one
+                        * TD that's not been sent through the donelist.
+                        */
+                       ohci->ed_to_check = ed;
+                       ohci->zf_delay = 2;
+
+                       /* The HC may wait until the next frame to report the
+                        * TD as done through the donelist and INTR_WDH.  (We
+                        * just *assume* it's not a multi-TD interrupt URB;
+                        * those could defer the IRQ more than one frame, using
+                        * DI...)  Check again after the next INTR_SF.
+                        */
+                       ohci_writel(ohci, OHCI_INTR_SF,
+                                       &ohci->regs->intrstatus);
+                       ohci_writel(ohci, OHCI_INTR_SF,
+                                       &ohci->regs->intrenable);
+
+                       /* flush those writes */
+                       (void) ohci_readl(ohci, &ohci->regs->control);
+
+                       goto out;
+               }
+       }
+out:
+       kfree(seen);
+       if (ohci->eds_scheduled)
+               mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
+done:
+       spin_unlock_irqrestore(&ohci->lock, flags);
+}
+
 /*-------------------------------------------------------------------------*
  * HC functions
  *-------------------------------------------------------------------------*/
@@ -616,6 +705,15 @@ retry:
        mdelay ((temp >> 23) & 0x1fe);
        hcd->state = HC_STATE_RUNNING;
 
+       if (quirk_zfmicro(ohci)) {
+               /* Create timer to watch for bad queue state on ZF Micro */
+               setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func,
+                               (unsigned long) ohci);
+
+               ohci->eds_scheduled = 0;
+               ohci->ed_to_check = NULL;
+       }
+
        ohci_dump (ohci, 1);
 
        return 0;
@@ -629,10 +727,11 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
 {
        struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
        struct ohci_regs __iomem *regs = ohci->regs;
-       int                     ints; 
+       int                     ints;
 
        /* we can eliminate a (slow) ohci_readl()
-          if _only_ WDH caused this irq */
+        * if _only_ WDH caused this irq
+        */
        if ((ohci->hcca->done_head != 0)
                        && ! (hc32_to_cpup (ohci, &ohci->hcca->done_head)
                                & 0x01)) {
@@ -651,7 +750,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
 
        if (ints & OHCI_INTR_UE) {
                // e.g. due to PCI Master/Target Abort
-               if (ohci->flags & OHCI_QUIRK_NEC) {
+               if (quirk_nec(ohci)) {
                        /* Workaround for a silicon bug in some NEC chips used
                         * in Apple's PowerBooks. Adapted from Darwin code.
                         */
@@ -713,6 +812,31 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
                        ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrenable);
        }
 
+       if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) {
+               spin_lock(&ohci->lock);
+               if (ohci->ed_to_check) {
+                       struct ed *ed = ohci->ed_to_check;
+
+                       if (check_ed(ohci, ed)) {
+                               /* HC thinks the TD list is empty; HCD knows
+                                * at least one TD is outstanding
+                                */
+                               if (--ohci->zf_delay == 0) {
+                                       struct td *td = list_entry(
+                                               ed->td_list.next,
+                                               struct td, td_list);
+                                       ohci_warn(ohci,
+                                                 "Reclaiming orphan TD %p\n",
+                                                 td);
+                                       takeback_td(ohci, td);
+                                       ohci->ed_to_check = NULL;
+                               }
+                       } else
+                               ohci->ed_to_check = NULL;
+               }
+               spin_unlock(&ohci->lock);
+       }
+
        /* could track INTR_SO to reduce available PCI/... bandwidth */
 
        /* handle any pending URB/ED unlinks, leaving INTR_SF enabled
@@ -721,7 +845,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
        spin_lock (&ohci->lock);
        if (ohci->ed_rm_list)
                finish_unlinks (ohci, ohci_frame_no(ohci));
-       if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
+       if ((ints & OHCI_INTR_SF) != 0
+                       && !ohci->ed_rm_list
+                       && !ohci->ed_to_check
                        && HC_IS_RUNNING(hcd->state))
                ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
        spin_unlock (&ohci->lock);
@@ -751,6 +877,9 @@ static void ohci_stop (struct usb_hcd *hcd)
        free_irq(hcd->irq, hcd);
        hcd->irq = -1;
 
+       if (quirk_zfmicro(ohci))
+               del_timer(&ohci->unlink_watchdog);
+
        remove_debug_files (ohci);
        ohci_mem_cleanup (ohci);
        if (ohci->hcca) {
@@ -798,9 +927,8 @@ static int ohci_restart (struct ohci_hcd *ohci)
                                        ed, ed->state);
                }
 
-               spin_lock (&urb->lock);
-               urb->status = -ESHUTDOWN;
-               spin_unlock (&urb->lock);
+               if (!urb->unlinked)
+                       urb->unlinked = -ESHUTDOWN;
        }
        finish_unlinks (ohci, 0);
        spin_unlock_irq(&ohci->lock);
@@ -828,27 +956,6 @@ static int ohci_restart (struct ohci_hcd *ohci)
 
 /*-------------------------------------------------------------------------*/
 
-/* NEC workaround */
-static void ohci_quirk_nec_worker(struct work_struct *work)
-{
-       struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
-       int status;
-
-       status = ohci_init(ohci);
-       if (status != 0) {
-               ohci_err(ohci, "Restarting NEC controller failed "
-                        "in ohci_init, %d\n", status);
-               return;
-       }
-
-       status = ohci_restart(ohci);
-       if (status != 0)
-               ohci_err(ohci, "Restarting NEC controller failed "
-                        "in ohci_restart, %d\n", status);
-}
-
-/*-------------------------------------------------------------------------*/
-
 #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
 
 MODULE_AUTHOR (DRIVER_AUTHOR);
@@ -926,11 +1033,17 @@ MODULE_LICENSE ("GPL");
 #define PS3_SYSTEM_BUS_DRIVER  ps3_ohci_driver
 #endif
 
+#ifdef CONFIG_USB_OHCI_HCD_SSB
+#include "ohci-ssb.c"
+#define SSB_OHCI_DRIVER                ssb_ohci_driver
+#endif
+
 #if    !defined(PCI_DRIVER) &&         \
        !defined(PLATFORM_DRIVER) &&    \
        !defined(OF_PLATFORM_DRIVER) && \
        !defined(SA1111_DRIVER) &&      \
-       !defined(PS3_SYSTEM_BUS_DRIVER)
+       !defined(PS3_SYSTEM_BUS_DRIVER) && \
+       !defined(SSB_OHCI_DRIVER)
 #error "missing bus glue for ohci-hcd"
 #endif
 
@@ -975,10 +1088,20 @@ static int __init ohci_hcd_mod_init(void)
                goto error_pci;
 #endif
 
+#ifdef SSB_OHCI_DRIVER
+       retval = ssb_driver_register(&SSB_OHCI_DRIVER);
+       if (retval)
+               goto error_ssb;
+#endif
+
        return retval;
 
        /* Error path */
+#ifdef SSB_OHCI_DRIVER
+ error_ssb:
+#endif
 #ifdef PCI_DRIVER
+       pci_unregister_driver(&PCI_DRIVER);
  error_pci:
 #endif
 #ifdef SA1111_DRIVER
@@ -1003,6 +1126,9 @@ module_init(ohci_hcd_mod_init);
 
 static void __exit ohci_hcd_mod_exit(void)
 {
+#ifdef SSB_OHCI_DRIVER
+       ssb_driver_unregister(&SSB_OHCI_DRIVER);
+#endif
 #ifdef PCI_DRIVER
        pci_unregister_driver(&PCI_DRIVER);
 #endif
index 450c7b4..2f20d3d 100644 (file)
@@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
        ohci->next_statechange = jiffies;
        spin_lock_init (&ohci->lock);
        INIT_LIST_HEAD (&ohci->pending);
-       INIT_WORK (&ohci->nec_work, ohci_quirk_nec_worker);
 }
 
 /*-------------------------------------------------------------------------*/
index a5e2eb8..d0360f6 100644 (file)
@@ -84,7 +84,7 @@ static int ohci_quirk_zfmicro(struct usb_hcd *hcd)
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
 
        ohci->flags |= OHCI_QUIRK_ZFMICRO;
-       ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
+       ohci_dbg(ohci, "enabled Compaq ZFMicro chipset quirks\n");
 
        return 0;
 }
@@ -113,11 +113,31 @@ static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
 
 /* Check for NEC chip and apply quirk for allegedly lost interrupts.
  */
+
+static void ohci_quirk_nec_worker(struct work_struct *work)
+{
+       struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
+       int status;
+
+       status = ohci_init(ohci);
+       if (status != 0) {
+               ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
+                        "ohci_init", status);
+               return;
+       }
+
+       status = ohci_restart(ohci);
+       if (status != 0)
+               ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
+                        "ohci_restart", status);
+}
+
 static int ohci_quirk_nec(struct usb_hcd *hcd)
 {
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
 
        ohci->flags |= OHCI_QUIRK_NEC;
+       INIT_WORK(&ohci->nec_work, ohci_quirk_nec_worker);
        ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n");
 
        return 0;
index c43b66a..0a74269 100644 (file)
@@ -134,8 +134,11 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
        }
 
        ohci = hcd_to_ohci(hcd);
-       if (is_bigendian)
+       if (is_bigendian) {
                ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+               if (of_device_is_compatible(dn, "mpc5200-ohci"))
+                       ohci->flags |= OHCI_QUIRK_FRAME_NO;
+       }
 
        ohci_hcd_init(ohci);
 
index 1a2e177..f95be18 100644 (file)
@@ -73,6 +73,11 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
 
        ohci = hcd_to_ohci(hcd);
        ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+
+#ifdef CONFIG_PPC_MPC52xx
+       /* MPC52xx doesn't need frame_no shift */
+       ohci->flags |= OHCI_QUIRK_FRAME_NO;
+#endif
        ohci_hcd_init(ohci);
 
        retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
index 830a3fe..5181732 100644 (file)
@@ -36,29 +36,15 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
  * PRECONDITION:  ohci lock held, irqs blocked.
  */
 static void
-finish_urb (struct ohci_hcd *ohci, struct urb *urb)
+finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status)
 __releases(ohci->lock)
 __acquires(ohci->lock)
 {
        // ASSERT (urb->hcpriv != 0);
 
        urb_free_priv (ohci, urb->hcpriv);
-       urb->hcpriv = NULL;
-
-       spin_lock (&urb->lock);
-       if (likely (urb->status == -EINPROGRESS))
-               urb->status = 0;
-       /* report short control reads right even though the data TD always
-        * has TD_R set.  (much simpler, but creates the 1-td limit.)
-        */
-       if (unlikely (urb->transfer_flags & URB_SHORT_NOT_OK)
-                       && unlikely (usb_pipecontrol (urb->pipe))
-                       && urb->actual_length < urb->transfer_buffer_length
-                       && usb_pipein (urb->pipe)
-                       && urb->status == 0) {
-               urb->status = -EREMOTEIO;
-       }
-       spin_unlock (&urb->lock);
+       if (likely(status == -EINPROGRESS))
+               status = 0;
 
        switch (usb_pipetype (urb->pipe)) {
        case PIPE_ISOCHRONOUS:
@@ -70,12 +56,13 @@ __acquires(ohci->lock)
        }
 
 #ifdef OHCI_VERBOSE_DEBUG
-       urb_print (urb, "RET", usb_pipeout (urb->pipe));
+       urb_print(urb, "RET", usb_pipeout (urb->pipe), status);
 #endif
 
        /* urb->complete() can reenter this HCD */
+       usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb);
        spin_unlock (&ohci->lock);
-       usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb);
+       usb_hcd_giveback_urb(ohci_to_hcd(ohci), urb, status);
        spin_lock (&ohci->lock);
 
        /* stop periodic dma if it's not needed */
@@ -179,6 +166,10 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
        ed->ed_prev = NULL;
        ed->ed_next = NULL;
        ed->hwNextED = 0;
+       if (quirk_zfmicro(ohci)
+                       && (ed->type == PIPE_INTERRUPT)
+                       && !(ohci->eds_scheduled++))
+               mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
        wmb ();
 
        /* we care about rm_list when setting CLE/BLE in case the HC was at
@@ -708,19 +699,18 @@ static void td_submit_urb (
  * Done List handling functions
  *-------------------------------------------------------------------------*/
 
-/* calculate transfer length/status and update the urb
- * PRECONDITION:  irqsafe (only for urb->status locking)
- */
-static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
+/* calculate transfer length/status and update the urb */
+static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td)
 {
        u32     tdINFO = hc32_to_cpup (ohci, &td->hwINFO);
        int     cc = 0;
+       int     status = -EINPROGRESS;
 
        list_del (&td->td_list);
 
        /* ISO ... drivers see per-TD length/status */
        if (tdINFO & TD_ISO) {
-               u16     tdPSW = ohci_hwPSW (ohci, td, 0);
+               u16     tdPSW = ohci_hwPSW(ohci, td, 0);
                int     dlen = 0;
 
                /* NOTE:  assumes FC in tdINFO == 0, and that
@@ -729,7 +719,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
 
                cc = (tdPSW >> 12) & 0xF;
                if (tdINFO & TD_CC)     /* hc didn't touch? */
-                       return;
+                       return status;
 
                if (usb_pipeout (urb->pipe))
                        dlen = urb->iso_frame_desc [td->index].length;
@@ -762,12 +752,8 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
                if (cc == TD_DATAUNDERRUN
                                && !(urb->transfer_flags & URB_SHORT_NOT_OK))
                        cc = TD_CC_NOERROR;
-               if (cc != TD_CC_NOERROR && cc < 0x0E) {
-                       spin_lock (&urb->lock);
-                       if (urb->status == -EINPROGRESS)
-                               urb->status = cc_to_error [cc];
-                       spin_unlock (&urb->lock);
-               }
+               if (cc != TD_CC_NOERROR && cc < 0x0E)
+                       status = cc_to_error[cc];
 
                /* count all non-empty packets except control SETUP packet */
                if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) {
@@ -786,14 +772,15 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
                                urb->actual_length,
                                urb->transfer_buffer_length);
        }
+       return status;
 }
 
 /*-------------------------------------------------------------------------*/
 
-static inline struct td *
-ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
+static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc)
 {
        struct urb              *urb = td->urb;
+       urb_priv_t              *urb_priv = urb->hcpriv;
        struct ed               *ed = td->ed;
        struct list_head        *tmp = td->td_list.next;
        __hc32                  toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C);
@@ -805,13 +792,12 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
        wmb ();
        ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H);
 
-       /* put any later tds from this urb onto the donelist, after 'td',
-        * order won't matter here: no errors, and nothing was transferred.
-        * also patch the ed so it looks as if those tds completed normally.
+       /* Get rid of all later tds from this urb.  We don't have
+        * to be careful: no errors and nothing was transferred.
+        * Also patch the ed so it looks as if those tds completed normally.
         */
        while (tmp != &ed->td_list) {
                struct td       *next;
-               __hc32          info;
 
                next = list_entry (tmp, struct td, td_list);
                tmp = next->td_list.next;
@@ -826,14 +812,9 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
                 * then we need to leave the control STATUS packet queued
                 * and clear ED_SKIP.
                 */
-               info = next->hwINFO;
-               info |= cpu_to_hc32 (ohci, TD_DONE);
-               info &= ~cpu_to_hc32 (ohci, TD_CC);
-               next->hwINFO = info;
-
-               next->next_dl_td = rev;
-               rev = next;
 
+               list_del(&next->td_list);
+               urb_priv->td_cnt++;
                ed->hwHeadP = next->hwNextTD | toggle;
        }
 
@@ -859,8 +840,6 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
                        hc32_to_cpu (ohci, td->hwINFO),
                        cc, cc_to_error [cc]);
        }
-
-       return rev;
 }
 
 /* replies to the request have to be on a FIFO basis so
@@ -897,7 +876,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
                 */
                if (cc != TD_CC_NOERROR
                                && (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H)))
-                       td_rev = ed_halted (ohci, td, cc, td_rev);
+                       ed_halted(ohci, td, cc);
 
                td->next_dl_td = td_rev;
                td_rev = td;
@@ -940,8 +919,12 @@ skip_ed:
                                                                TD_MASK;
 
                                /* INTR_WDH may need to clean up first */
-                               if (td->td_dma != head)
-                                       goto skip_ed;
+                               if (td->td_dma != head) {
+                                       if (ed == ohci->ed_to_check)
+                                               ohci->ed_to_check = NULL;
+                                       else
+                                               goto skip_ed;
+                               }
                        }
                }
 
@@ -974,7 +957,7 @@ rescan_this:
                        urb = td->urb;
                        urb_priv = td->urb->hcpriv;
 
-                       if (urb->status == -EINPROGRESS) {
+                       if (!urb->unlinked) {
                                prev = &td->hwNextTD;
                                continue;
                        }
@@ -990,7 +973,7 @@ rescan_this:
                        /* if URB is done, clean up */
                        if (urb_priv->td_cnt == urb_priv->length) {
                                modified = completed = 1;
-                               finish_urb (ohci, urb);
+                               finish_urb(ohci, urb, 0);
                        }
                }
                if (completed && !list_empty (&ed->td_list))
@@ -998,6 +981,8 @@ rescan_this:
 
                /* ED's now officially unlinked, hc doesn't see */
                ed->state = ED_IDLE;
+               if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+                       ohci->eds_scheduled--;
                ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
                ed->hwNextED = 0;
                wmb ();
@@ -1021,7 +1006,7 @@ rescan_this:
 
                if (ohci->ed_controltail) {
                        command |= OHCI_CLF;
-                       if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+                       if (quirk_zfmicro(ohci))
                                mdelay(1);
                        if (!(ohci->hc_control & OHCI_CTRL_CLE)) {
                                control |= OHCI_CTRL_CLE;
@@ -1031,7 +1016,7 @@ rescan_this:
                }
                if (ohci->ed_bulktail) {
                        command |= OHCI_BLF;
-                       if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+                       if (quirk_zfmicro(ohci))
                                mdelay(1);
                        if (!(ohci->hc_control & OHCI_CTRL_BLE)) {
                                control |= OHCI_CTRL_BLE;
@@ -1043,13 +1028,13 @@ rescan_this:
                /* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */
                if (control) {
                        ohci->hc_control |= control;
-                       if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+                       if (quirk_zfmicro(ohci))
                                mdelay(1);
                        ohci_writel (ohci, ohci->hc_control,
                                        &ohci->regs->control);
                }
                if (command) {
-                       if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+                       if (quirk_zfmicro(ohci))
                                mdelay(1);
                        ohci_writel (ohci, command, &ohci->regs->cmdstatus);
                }
@@ -1061,11 +1046,60 @@ rescan_this:
 /*-------------------------------------------------------------------------*/
 
 /*
+ * Used to take back a TD from the host controller. This would normally be
+ * called from within dl_done_list, however it may be called directly if the
+ * HC no longer sees the TD and it has not appeared on the donelist (after
+ * two frames).  This bug has been observed on ZF Micro systems.
+ */
+static void takeback_td(struct ohci_hcd *ohci, struct td *td)
+{
+       struct urb      *urb = td->urb;
+       urb_priv_t      *urb_priv = urb->hcpriv;
+       struct ed       *ed = td->ed;
+       int             status;
+
+       /* update URB's length and status from TD */
+       status = td_done(ohci, urb, td);
+       urb_priv->td_cnt++;
+
+       /* If all this urb's TDs are done, call complete() */
+       if (urb_priv->td_cnt == urb_priv->length)
+               finish_urb(ohci, urb, status);
+
+       /* clean schedule:  unlink EDs that are no longer busy */
+       if (list_empty(&ed->td_list)) {
+               if (ed->state == ED_OPER)
+                       start_ed_unlink(ohci, ed);
+
+       /* ... reenabling halted EDs only after fault cleanup */
+       } else if ((ed->hwINFO & cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE))
+                       == cpu_to_hc32(ohci, ED_SKIP)) {
+               td = list_entry(ed->td_list.next, struct td, td_list);
+               if (!(td->hwINFO & cpu_to_hc32(ohci, TD_DONE))) {
+                       ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP);
+                       /* ... hc may need waking-up */
+                       switch (ed->type) {
+                       case PIPE_CONTROL:
+                               ohci_writel(ohci, OHCI_CLF,
+                                               &ohci->regs->cmdstatus);
+                               break;
+                       case PIPE_BULK:
+                               ohci_writel(ohci, OHCI_BLF,
+                                               &ohci->regs->cmdstatus);
+                               break;
+                       }
+               }
+       }
+}
+
+/*
  * Process normal completions (error or success) and clean the schedules.
  *
  * This is the main path for handing urbs back to drivers.  The only other
- * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of
- * scanning the (re-reversed) donelist as this does.
+ * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list,
+ * instead of scanning the (re-reversed) donelist as this does.  There's
+ * an abnormal path too, handling a quirk in some Compaq silicon:  URBs
+ * with TDs that appear to be orphaned are directly reclaimed.
  */
 static void
 dl_done_list (struct ohci_hcd *ohci)
@@ -1074,44 +1108,7 @@ dl_done_list (struct ohci_hcd *ohci)
 
        while (td) {
                struct td       *td_next = td->next_dl_td;
-               struct urb      *urb = td->urb;
-               urb_priv_t      *urb_priv = urb->hcpriv;
-               struct ed       *ed = td->ed;
-
-               /* update URB's length and status from TD */
-               td_done (ohci, urb, td);
-               urb_priv->td_cnt++;
-
-               /* If all this urb's TDs are done, call complete() */
-               if (urb_priv->td_cnt == urb_priv->length)
-                       finish_urb (ohci, urb);
-
-               /* clean schedule:  unlink EDs that are no longer busy */
-               if (list_empty (&ed->td_list)) {
-                       if (ed->state == ED_OPER)
-                               start_ed_unlink (ohci, ed);
-
-               /* ... reenabling halted EDs only after fault cleanup */
-               } else if ((ed->hwINFO & cpu_to_hc32 (ohci,
-                                               ED_SKIP | ED_DEQUEUE))
-                                       == cpu_to_hc32 (ohci, ED_SKIP)) {
-                       td = list_entry (ed->td_list.next, struct td, td_list);
-                       if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) {
-                               ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP);
-                               /* ... hc may need waking-up */
-                               switch (ed->type) {
-                               case PIPE_CONTROL:
-                                       ohci_writel (ohci, OHCI_CLF,
-                                               &ohci->regs->cmdstatus);
-                                       break;
-                               case PIPE_BULK:
-                                       ohci_writel (ohci, OHCI_BLF,
-                                               &ohci->regs->cmdstatus);
-                                       break;
-                               }
-                       }
-               }
-
+               takeback_td(ohci, td);
                td = td_next;
        }
 }
diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c
new file mode 100644 (file)
index 0000000..bc3e785
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom USB-core OHCI driver
+ *
+ * Copyright 2007 Michael Buesch <mb@bu3sch.de>
+ *
+ * Derived from the OHCI-PCI driver
+ * Copyright 1999 Roman Weissgaerber
+ * Copyright 2000-2002 David Brownell
+ * Copyright 1999 Linus Torvalds
+ * Copyright 1999 Gregory P. Smith
+ *
+ * Derived from the USBcore related parts of Broadcom-SB
+ * Copyright 2005 Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/ssb/ssb.h>
+
+
+#define SSB_OHCI_TMSLOW_HOSTMODE       (1 << 29)
+
+struct ssb_ohci_device {
+       struct ohci_hcd ohci; /* _must_ be at the beginning. */
+
+       u32 enable_flags;
+};
+
+static inline
+struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd)
+{
+       return (struct ssb_ohci_device *)(hcd->hcd_priv);
+}
+
+
+static int ssb_ohci_reset(struct usb_hcd *hcd)
+{
+       struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+       struct ohci_hcd *ohci = &ohcidev->ohci;
+       int err;
+
+       ohci_hcd_init(ohci);
+       err = ohci_init(ohci);
+
+       return err;
+}
+
+static int ssb_ohci_start(struct usb_hcd *hcd)
+{
+       struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+       struct ohci_hcd *ohci = &ohcidev->ohci;
+       int err;
+
+       err = ohci_run(ohci);
+       if (err < 0) {
+               ohci_err(ohci, "can't start\n");
+               ohci_stop(hcd);
+       }
+
+       return err;
+}
+
+#ifdef CONFIG_PM
+static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message)
+{
+       struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+       struct ohci_hcd *ohci = &ohcidev->ohci;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ohci->lock, flags);
+
+       ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+       ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */
+
+       /* make sure snapshot being resumed re-enumerates everything */
+       if (message.event == PM_EVENT_PRETHAW)
+               ohci_usb_reset(ohci);
+
+       clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+       spin_unlock_irqrestore(&ohci->lock, flags);
+       return 0;
+}
+
+static int ssb_ohci_hcd_resume(struct usb_hcd *hcd)
+{
+       set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+       usb_hcd_resume_root_hub(hcd);
+       return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct hc_driver ssb_ohci_hc_driver = {
+       .description            = "ssb-usb-ohci",
+       .product_desc           = "SSB OHCI Controller",
+       .hcd_priv_size          = sizeof(struct ssb_ohci_device),
+
+       .irq                    = ohci_irq,
+       .flags                  = HCD_MEMORY | HCD_USB11,
+
+       .reset                  = ssb_ohci_reset,
+       .start                  = ssb_ohci_start,
+       .stop                   = ohci_stop,
+       .shutdown               = ohci_shutdown,
+
+#ifdef CONFIG_PM
+       .suspend                = ssb_ohci_hcd_suspend,
+       .resume                 = ssb_ohci_hcd_resume,
+#endif
+
+       .urb_enqueue            = ohci_urb_enqueue,
+       .urb_dequeue            = ohci_urb_dequeue,
+       .endpoint_disable       = ohci_endpoint_disable,
+
+       .get_frame_number       = ohci_get_frame,
+
+       .hub_status_data        = ohci_hub_status_data,
+       .hub_control            = ohci_hub_control,
+       .hub_irq_enable         = ohci_rhsc_enable,
+       .bus_suspend            = ohci_bus_suspend,
+       .bus_resume             = ohci_bus_resume,
+
+       .start_port_reset       = ohci_start_port_reset,
+};
+
+static void ssb_ohci_detach(struct ssb_device *dev)
+{
+       struct usb_hcd *hcd = ssb_get_drvdata(dev);
+
+       usb_remove_hcd(hcd);
+       iounmap(hcd->regs);
+       usb_put_hcd(hcd);
+       ssb_device_disable(dev, 0);
+}
+
+static int ssb_ohci_attach(struct ssb_device *dev)
+{
+       struct ssb_ohci_device *ohcidev;
+       struct usb_hcd *hcd;
+       int err = -ENOMEM;
+       u32 tmp, flags = 0;
+
+       if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
+               flags |= SSB_OHCI_TMSLOW_HOSTMODE;
+
+       ssb_device_enable(dev, flags);
+
+       hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
+                       dev->dev->bus_id);
+       if (!hcd)
+               goto err_dev_disable;
+       ohcidev = hcd_to_ssb_ohci(hcd);
+       ohcidev->enable_flags = flags;
+
+       tmp = ssb_read32(dev, SSB_ADMATCH0);
+       hcd->rsrc_start = ssb_admatch_base(tmp);
+       hcd->rsrc_len = ssb_admatch_size(tmp);
+       hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+       if (!hcd->regs)
+               goto err_put_hcd;
+       err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
+       if (err)
+               goto err_iounmap;
+
+       ssb_set_drvdata(dev, hcd);
+
+       return err;
+
+err_iounmap:
+       iounmap(hcd->regs);
+err_put_hcd:
+       usb_put_hcd(hcd);
+err_dev_disable:
+       ssb_device_disable(dev, flags);
+       return err;
+}
+
+static int ssb_ohci_probe(struct ssb_device *dev,
+               const struct ssb_device_id *id)
+{
+       int err;
+       u16 chipid_top;
+
+       /* USBcores are only connected on embedded devices. */
+       chipid_top = (dev->bus->chip_id & 0xFF00);
+       if (chipid_top != 0x4700 && chipid_top != 0x5300)
+               return -ENODEV;
+
+       /* TODO: Probably need checks here; is the core connected? */
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       /* We currently always attach SSB_DEV_USB11_HOSTDEV
+        * as HOST OHCI. If we want to attach it as Client device,
+        * we must branch here and call into the (yet to
+        * be written) Client mode driver. Same for remove(). */
+
+       err = ssb_ohci_attach(dev);
+
+       return err;
+}
+
+static void ssb_ohci_remove(struct ssb_device *dev)
+{
+       ssb_ohci_detach(dev);
+}
+
+#ifdef CONFIG_PM
+
+static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state)
+{
+       ssb_device_disable(dev, 0);
+
+       return 0;
+}
+
+static int ssb_ohci_resume(struct ssb_device *dev)
+{
+       struct usb_hcd *hcd = ssb_get_drvdata(dev);
+       struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+
+       ssb_device_enable(dev, ohcidev->enable_flags);
+
+       return 0;
+}
+
+#else /* !CONFIG_PM */
+#define ssb_ohci_suspend       NULL
+#define ssb_ohci_resume        NULL
+#endif /* CONFIG_PM */
+
+static const struct ssb_device_id ssb_ohci_table[] = {
+       SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
+       SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
+       SSB_DEVTABLE_END
+};
+MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
+
+static struct ssb_driver ssb_ohci_driver = {
+       .name           = KBUILD_MODNAME,
+       .id_table       = ssb_ohci_table,
+       .probe          = ssb_ohci_probe,
+       .remove         = ssb_ohci_remove,
+       .suspend        = ssb_ohci_suspend,
+       .resume         = ssb_ohci_resume,
+};
index 4ada43c..47c5c66 100644 (file)
@@ -398,11 +398,38 @@ struct ohci_hcd {
 #define        OHCI_QUIRK_BE_MMIO      0x10                    /* BE registers */
 #define        OHCI_QUIRK_ZFMICRO      0x20                    /* Compaq ZFMicro chipset*/
 #define        OHCI_QUIRK_NEC          0x40                    /* lost interrupts */
+#define        OHCI_QUIRK_FRAME_NO     0x80                    /* no big endian frame_no shift */
        // there are also chip quirks/bugs in init logic
 
        struct work_struct      nec_work;       /* Worker for NEC quirk */
+
+       /* Needed for ZF Micro quirk */
+       struct timer_list       unlink_watchdog;
+       unsigned                eds_scheduled;
+       struct ed               *ed_to_check;
+       unsigned                zf_delay;
 };
 
+#ifdef CONFIG_PCI
+static inline int quirk_nec(struct ohci_hcd *ohci)
+{
+       return ohci->flags & OHCI_QUIRK_NEC;
+}
+static inline int quirk_zfmicro(struct ohci_hcd *ohci)
+{
+       return ohci->flags & OHCI_QUIRK_ZFMICRO;
+}
+#else
+static inline int quirk_nec(struct ohci_hcd *ohci)
+{
+       return 0;
+}
+static inline int quirk_zfmicro(struct ohci_hcd *ohci)
+{
+       return 0;
+}
+#endif
+
 /* convert between an hcd pointer and the corresponding ohci_hcd */
 static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *hcd)
 {
@@ -607,15 +634,12 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
 /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
  * hardware handles 16 bit reads.  That creates a different confusion on
  * some big-endian SOC implementations.  Same thing happens with PSW access.
- *
- * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over
- * to arch/powerpc
  */
 
-#ifdef CONFIG_STB03xxx
-#define OHCI_BE_FRAME_NO_SHIFT 16
+#ifdef CONFIG_PPC_MPC52xx
+#define big_endian_frame_no_quirk(ohci)        (ohci->flags & OHCI_QUIRK_FRAME_NO)
 #else
-#define OHCI_BE_FRAME_NO_SHIFT 0
+#define big_endian_frame_no_quirk(ohci)        0
 #endif
 
 static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
@@ -623,7 +647,8 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
        u32 tmp;
        if (big_endian_desc(ohci)) {
                tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
-               tmp >>= OHCI_BE_FRAME_NO_SHIFT;
+               if (!big_endian_frame_no_quirk(ohci))
+                       tmp >>= 16;
        } else
                tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no);
 
index 40a1de4..ae8ec44 100644 (file)
@@ -782,10 +782,12 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address)
                kfree(td);
 
                if (urb) {
-                       urb->status = -ENODEV;
-                       urb->hcpriv = NULL;
+                       usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597),
+                                       urb);
+
                        spin_unlock(&r8a66597->lock);
-                       usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb);
+                       usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb,
+                                       -ENODEV);
                        spin_lock(&r8a66597->lock);
                }
                break;
@@ -832,7 +834,7 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
        info.pipenum = get_empty_pipenum(r8a66597, ep);
        info.address = get_urb_to_r8a66597_addr(r8a66597, urb);
        info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-       info.maxpacket = ep->wMaxPacketSize;
+       info.maxpacket = le16_to_cpu(ep->wMaxPacketSize);
        info.type = get_r8a66597_type(ep->bmAttributes
                                      & USB_ENDPOINT_XFERTYPE_MASK);
        info.bufnum = get_bufnum(info.pipenum);
@@ -923,7 +925,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597,
        r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
 
        for (i = 0; i < 4; i++) {
-               r8a66597_write(r8a66597, p[i], setup_addr);
+               r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr);
                setup_addr += 2;
        }
        r8a66597_write(r8a66597, SUREQ, DCPCTR);
@@ -1032,6 +1034,15 @@ static void prepare_status_packet(struct r8a66597 *r8a66597,
        pipe_start(r8a66597, td->pipe);
 }
 
+static int is_set_address(unsigned char *setup_packet)
+{
+       if (((setup_packet[0] & USB_TYPE_MASK) == USB_TYPE_STANDARD) &&
+                       setup_packet[1] == USB_REQ_SET_ADDRESS)
+               return 1;
+       else
+               return 0;
+}
+
 /* this function must be called with interrupt disabled */
 static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
 {
@@ -1039,7 +1050,7 @@ static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
 
        switch (td->type) {
        case USB_PID_SETUP:
-               if (td->urb->setup_packet[1] == USB_REQ_SET_ADDRESS) {
+               if (is_set_address(td->urb->setup_packet)) {
                        td->set_address = 1;
                        td->urb->setup_packet[2] = alloc_usb_address(r8a66597,
                                                                     td->urb);
@@ -1106,8 +1117,9 @@ static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
 }
 
 /* this function must be called with interrupt disabled */
-static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
-                u16 pipenum, struct urb *urb)
+static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
+               u16 pipenum, struct urb *urb, int status)
+__releases(r8a66597->lock) __acquires(r8a66597->lock)
 {
        int restart = 0;
        struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
@@ -1115,7 +1127,7 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
        r8a66597->timeout_map &= ~(1 << pipenum);
 
        if (likely(td)) {
-               if (td->set_address && urb->status != 0)
+               if (td->set_address && (status != 0 || urb->unlinked))
                        r8a66597->address_map &= ~(1 << urb->setup_packet[2]);
 
                pipe_toggle_save(r8a66597, td->pipe, urb);
@@ -1130,9 +1142,9 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
                if (usb_pipeisoc(urb->pipe))
                        urb->start_frame = r8a66597_get_frame(hcd);
 
-               urb->hcpriv = NULL;
+               usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb);
                spin_unlock(&r8a66597->lock);
-               usb_hcd_giveback_urb(hcd, urb);
+               usb_hcd_giveback_urb(hcd, urb, status);
                spin_lock(&r8a66597->lock);
        }
 
@@ -1146,14 +1158,6 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
        }
 }
 
-/* this function must be called with interrupt disabled */
-static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
-                          u16 pipenum, struct urb *urb)
-__releases(r8a66597->lock) __acquires(r8a66597->lock)
-{
-       done(r8a66597, td, pipenum, urb);
-}
-
 static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
 {
        u16 tmp;
@@ -1162,6 +1166,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
        struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
        struct urb *urb;
        int finish = 0;
+       int status = 0;
 
        if (unlikely(!td))
                return;
@@ -1170,17 +1175,15 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
        fifo_change_from_pipe(r8a66597, td->pipe);
        tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
        if (unlikely((tmp & FRDY) == 0)) {
-               urb->status = -EPIPE;
                pipe_stop(r8a66597, td->pipe);
                pipe_irq_disable(r8a66597, pipenum);
                err("in fifo not ready (%d)", pipenum);
-               finish_request(r8a66597, td, pipenum, td->urb);
+               finish_request(r8a66597, td, pipenum, td->urb, -EPIPE);
                return;
        }
 
        /* prepare parameters */
        rcv_len = tmp & DTLN;
-       bufsize = td->maxpacket;
        if (usb_pipeisoc(urb->pipe)) {
                buf = (u16 *)(urb->transfer_buffer +
                                urb->iso_frame_desc[td->iso_cnt].offset);
@@ -1189,29 +1192,31 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
                buf = (void *)urb->transfer_buffer + urb->actual_length;
                urb_len = urb->transfer_buffer_length - urb->actual_length;
        }
-       if (rcv_len < bufsize)
-               size = min(rcv_len, urb_len);
-       else
-               size = min(bufsize, urb_len);
+       bufsize = min(urb_len, (int) td->maxpacket);
+       if (rcv_len <= bufsize) {
+               size = rcv_len;
+       } else {
+               size = bufsize;
+               status = -EOVERFLOW;
+               finish = 1;
+       }
 
        /* update parameters */
        urb->actual_length += size;
        if (rcv_len == 0)
                td->zero_packet = 1;
-       if ((size % td->maxpacket) > 0) {
+       if (rcv_len < bufsize) {
                td->short_packet = 1;
-               if (urb->transfer_buffer_length != urb->actual_length &&
-                   urb->transfer_flags & URB_SHORT_NOT_OK)
-                       td->urb->status = -EREMOTEIO;
        }
        if (usb_pipeisoc(urb->pipe)) {
                urb->iso_frame_desc[td->iso_cnt].actual_length = size;
-               urb->iso_frame_desc[td->iso_cnt].status = 0;
+               urb->iso_frame_desc[td->iso_cnt].status = status;
                td->iso_cnt++;
+               finish = 0;
        }
 
        /* check transfer finish */
-       if (check_transfer_finish(td, urb)) {
+       if (finish || check_transfer_finish(td, urb)) {
                pipe_stop(r8a66597, td->pipe);
                pipe_irq_disable(r8a66597, pipenum);
                finish = 1;
@@ -1226,11 +1231,8 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
                                           buf, size);
        }
 
-       if (finish && pipenum != 0) {
-               if (td->urb->status == -EINPROGRESS)
-                       td->urb->status = 0;
-               finish_request(r8a66597, td, pipenum, urb);
-       }
+       if (finish && pipenum != 0)
+               finish_request(r8a66597, td, pipenum, urb, status);
 }
 
 static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
@@ -1248,11 +1250,10 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
        fifo_change_from_pipe(r8a66597, td->pipe);
        tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
        if (unlikely((tmp & FRDY) == 0)) {
-               urb->status = -EPIPE;
                pipe_stop(r8a66597, td->pipe);
                pipe_irq_disable(r8a66597, pipenum);
                err("out write fifo not ready. (%d)", pipenum);
-               finish_request(r8a66597, td, pipenum, td->urb);
+               finish_request(r8a66597, td, pipenum, urb, -EPIPE);
                return;
        }
 
@@ -1297,7 +1298,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
 }
 
 
-static void check_next_phase(struct r8a66597 *r8a66597)
+static void check_next_phase(struct r8a66597 *r8a66597, int status)
 {
        struct r8a66597_td *td = r8a66597_get_td(r8a66597, 0);
        struct urb *urb;
@@ -1310,49 +1311,41 @@ static void check_next_phase(struct r8a66597 *r8a66597)
        switch (td->type) {
        case USB_PID_IN:
        case USB_PID_OUT:
-               if (urb->status != -EINPROGRESS) {
-                       finish = 1;
-                       break;
-               }
                if (check_transfer_finish(td, urb))
                        td->type = USB_PID_ACK;
                break;
        case USB_PID_SETUP:
-               if (urb->status != -EINPROGRESS)
-                       finish = 1;
-               else if (urb->transfer_buffer_length == urb->actual_length) {
+               if (urb->transfer_buffer_length == urb->actual_length)
                        td->type = USB_PID_ACK;
-                       urb->status = 0;
-               } else if (usb_pipeout(urb->pipe))
+               else if (usb_pipeout(urb->pipe))
                        td->type = USB_PID_OUT;
                else
                        td->type = USB_PID_IN;
                break;
        case USB_PID_ACK:
                finish = 1;
-               if (urb->status == -EINPROGRESS)
-                       urb->status = 0;
                break;
        }
 
-       if (finish)
-               finish_request(r8a66597, td, 0, urb);
+       if (finish || status != 0 || urb->unlinked)
+               finish_request(r8a66597, td, 0, urb, status);
        else
                start_transfer(r8a66597, td);
 }
 
-static void set_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
+static int get_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
 {
        struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
 
-       if (td && td->urb) {
+       if (td) {
                u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID;
 
                if (pid == PID_NAK)
-                       td->urb->status = -ECONNRESET;
+                       return -ECONNRESET;
                else
-                       td->urb->status = -EPIPE;
+                       return -EPIPE;
        }
+       return 0;
 }
 
 static void irq_pipe_ready(struct r8a66597 *r8a66597)
@@ -1371,7 +1364,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597)
                        packet_read(r8a66597, 0);
                else
                        pipe_irq_disable(r8a66597, 0);
-               check_next_phase(r8a66597);
+               check_next_phase(r8a66597, 0);
        }
 
        for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1405,7 +1398,7 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597)
                td = r8a66597_get_td(r8a66597, 0);
                if (td && td->type != USB_PID_OUT)
                        disable_irq_empty(r8a66597, 0);
-               check_next_phase(r8a66597);
+               check_next_phase(r8a66597, 0);
        }
 
        for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1420,9 +1413,8 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597)
                        if ((tmp & INBUFM) == 0) {
                                disable_irq_empty(r8a66597, pipenum);
                                pipe_irq_disable(r8a66597, pipenum);
-                               if (td->urb->status == -EINPROGRESS)
-                                       td->urb->status = 0;
-                               finish_request(r8a66597, td, pipenum, td->urb);
+                               finish_request(r8a66597, td, pipenum, td->urb,
+                                               0);
                        }
                }
        }
@@ -1433,15 +1425,16 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
        u16 check;
        u16 pipenum;
        u16 mask;
+       int status;
 
        mask = r8a66597_read(r8a66597, NRDYSTS)
               & r8a66597_read(r8a66597, NRDYENB);
        r8a66597_write(r8a66597, ~mask, NRDYSTS);
        if (mask & NRDY0) {
                cfifo_change(r8a66597, 0);
-               set_urb_error(r8a66597, 0);
+               status = get_urb_error(r8a66597, 0);
                pipe_irq_disable(r8a66597, 0);
-               check_next_phase(r8a66597);
+               check_next_phase(r8a66597, status);
        }
 
        for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1452,10 +1445,10 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
                        if (unlikely(!td))
                                continue;
 
-                       set_urb_error(r8a66597, pipenum);
+                       status = get_urb_error(r8a66597, pipenum);
                        pipe_irq_disable(r8a66597, pipenum);
                        pipe_stop(r8a66597, td->pipe);
-                       finish_request(r8a66597, td, pipenum, td->urb);
+                       finish_request(r8a66597, td, pipenum, td->urb, status);
                }
        }
 }
@@ -1475,6 +1468,7 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
        u16 intsts0, intsts1, intsts2;
        u16 intenb0, intenb1, intenb2;
        u16 mask0, mask1, mask2;
+       int status;
 
        spin_lock(&r8a66597->lock);
 
@@ -1518,12 +1512,12 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
                }
                if (mask1 & SIGN) {
                        r8a66597_write(r8a66597, ~SIGN, INTSTS1);
-                       set_urb_error(r8a66597, 0);
-                       check_next_phase(r8a66597);
+                       status = get_urb_error(r8a66597, 0);
+                       check_next_phase(r8a66597, status);
                }
                if (mask1 & SACK) {
                        r8a66597_write(r8a66597, ~SACK, INTSTS1);
-                       check_next_phase(r8a66597);
+                       check_next_phase(r8a66597, 0);
                }
        }
        if (mask0) {
@@ -1722,21 +1716,25 @@ static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597,
 }
 
 static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
-                               struct usb_host_endpoint *hep,
                                struct urb *urb,
                                gfp_t mem_flags)
 {
+       struct usb_host_endpoint *hep = urb->ep;
        struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
        struct r8a66597_td *td = NULL;
-       int ret = 0, request = 0;
+       int ret, request = 0;
        unsigned long flags;
 
        spin_lock_irqsave(&r8a66597->lock, flags);
        if (!get_urb_to_r8a66597_dev(r8a66597, urb)) {
                ret = -ENODEV;
-               goto error;
+               goto error_not_linked;
        }
 
+       ret = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (ret)
+               goto error_not_linked;
+
        if (!hep->hcpriv) {
                hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe),
                                GFP_ATOMIC);
@@ -1761,15 +1759,7 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
        if (list_empty(&r8a66597->pipe_queue[td->pipenum]))
                request = 1;
        list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]);
-
-       spin_lock(&urb->lock);
-       if (urb->status != -EINPROGRESS) {
-               spin_unlock(&urb->lock);
-               ret = -EPIPE;
-               goto error;
-       }
        urb->hcpriv = td;
-       spin_unlock(&urb->lock);
 
        if (request) {
                ret = start_transfer(r8a66597, td);
@@ -1781,26 +1771,36 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
                set_td_timer(r8a66597, td);
 
 error:
+       if (ret)
+               usb_hcd_unlink_urb_from_ep(hcd, urb);
+error_not_linked:
        spin_unlock_irqrestore(&r8a66597->lock, flags);
        return ret;
 }
 
-static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+               int status)
 {
        struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
        struct r8a66597_td *td;
        unsigned long flags;
+       int rc;
 
        spin_lock_irqsave(&r8a66597->lock, flags);
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (rc)
+               goto done;
+
        if (urb->hcpriv) {
                td = urb->hcpriv;
                pipe_stop(r8a66597, td->pipe);
                pipe_irq_disable(r8a66597, td->pipenum);
                disable_irq_empty(r8a66597, td->pipenum);
-               done(r8a66597, td, td->pipenum, urb);
+               finish_request(r8a66597, td, td->pipenum, urb, status);
        }
+ done:
        spin_unlock_irqrestore(&r8a66597->lock, flags);
-       return 0;
+       return rc;
 }
 
 static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
@@ -1830,7 +1830,7 @@ static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
        td = r8a66597_get_td(r8a66597, pipenum);
        if (td)
                urb = td->urb;
-       done(r8a66597, td, pipenum, urb);
+       finish_request(r8a66597, td, pipenum, urb, -ESHUTDOWN);
        kfree(hep->hcpriv);
        hep->hcpriv = NULL;
        spin_unlock_irqrestore(&r8a66597->lock, flags);
@@ -2027,7 +2027,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
        case GetPortStatus:
                if (wIndex > R8A66597_MAX_ROOT_HUB)
                        goto error;
-               *(u32 *)buf = rh->port;
+               *(u32 *)buf = cpu_to_le32(rh->port);
                break;
        case SetPortFeature:
                if (wIndex > R8A66597_MAX_ROOT_HUB)
@@ -2126,8 +2126,8 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
        struct usb_hcd          *hcd = r8a66597_to_hcd(r8a66597);
 
        del_timer_sync(&r8a66597->rh_timer);
-       iounmap((void *)r8a66597->reg);
        usb_remove_hcd(hcd);
+       iounmap((void *)r8a66597->reg);
        usb_put_hcd(hcd);
        return 0;
 }
index 4cfa3ff..94d859a 100644 (file)
@@ -435,14 +435,9 @@ static void finish_request(
        if (usb_pipecontrol(urb->pipe))
                ep->nextpid = USB_PID_SETUP;
 
-       spin_lock(&urb->lock);
-       if (urb->status == -EINPROGRESS)
-               urb->status = status;
-       urb->hcpriv = NULL;
-       spin_unlock(&urb->lock);
-
+       usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb);
        spin_unlock(&sl811->lock);
-       usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb);
+       usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, status);
        spin_lock(&sl811->lock);
 
        /* leave active endpoints in the schedule */
@@ -538,35 +533,21 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank)
                                                bank + SL11H_XFERCNTREG);
                        if (len > ep->length) {
                                len = ep->length;
-                               urb->status = -EOVERFLOW;
+                               urbstat = -EOVERFLOW;
                        }
                        urb->actual_length += len;
                        sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0),
                                        buf, len);
                        usb_dotoggle(udev, ep->epnum, 0);
-                       if (urb->actual_length == urb->transfer_buffer_length)
-                               urbstat = 0;
-                       else if (len < ep->maxpacket) {
-                               if (urb->transfer_flags & URB_SHORT_NOT_OK)
-                                       urbstat = -EREMOTEIO;
+                       if (urbstat == -EINPROGRESS &&
+                                       (len < ep->maxpacket ||
+                                               urb->actual_length ==
+                                               urb->transfer_buffer_length)) {
+                               if (usb_pipecontrol(urb->pipe))
+                                       ep->nextpid = USB_PID_ACK;
                                else
                                        urbstat = 0;
                        }
-                       if (usb_pipecontrol(urb->pipe)
-                                       && (urbstat == -EREMOTEIO
-                                               || urbstat == 0)) {
-
-                               /* NOTE if the status stage STALLs (why?),
-                                * this reports the wrong urb status.
-                                */
-                               spin_lock(&urb->lock);
-                               if (urb->status == -EINPROGRESS)
-                                       urb->status = urbstat;
-                               spin_unlock(&urb->lock);
-
-                               urb = NULL;
-                               ep->nextpid = USB_PID_ACK;
-                       }
                        break;
                case USB_PID_SETUP:
                        // PACKET("...ACK/setup_%02x qh%p\n", bank, ep);
@@ -605,7 +586,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank)
                                bank, status, ep, urbstat);
        }
 
-       if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS))
+       if (urbstat != -EINPROGRESS || urb->unlinked)
                finish_request(sl811, ep, urb, urbstat);
 }
 
@@ -807,7 +788,6 @@ static int balance(struct sl811 *sl811, u16 period, u16 load)
 
 static int sl811h_urb_enqueue(
        struct usb_hcd          *hcd,
-       struct usb_host_endpoint *hep,
        struct urb              *urb,
        gfp_t                   mem_flags
 ) {
@@ -820,7 +800,8 @@ static int sl811h_urb_enqueue(
        struct sl811h_ep        *ep = NULL;
        unsigned long           flags;
        int                     i;
-       int                     retval = 0;
+       int                     retval;
+       struct usb_host_endpoint        *hep = urb->ep;
 
 #ifdef DISABLE_ISO
        if (type == PIPE_ISOCHRONOUS)
@@ -838,7 +819,12 @@ static int sl811h_urb_enqueue(
                        || !HC_IS_RUNNING(hcd->state)) {
                retval = -ENODEV;
                kfree(ep);
-               goto fail;
+               goto fail_not_linked;
+       }
+       retval = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (retval) {
+               kfree(ep);
+               goto fail_not_linked;
        }
 
        if (hep->hcpriv) {
@@ -951,37 +937,31 @@ static int sl811h_urb_enqueue(
                sofirq_on(sl811);
        }
 
-       /* in case of unlink-during-submit */
-       spin_lock(&urb->lock);
-       if (urb->status != -EINPROGRESS) {
-               spin_unlock(&urb->lock);
-               finish_request(sl811, ep, urb, 0);
-               retval = 0;
-               goto fail;
-       }
        urb->hcpriv = hep;
-       spin_unlock(&urb->lock);
-
        start_transfer(sl811);
        sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
 fail:
+       if (retval)
+               usb_hcd_unlink_urb_from_ep(hcd, urb);
+fail_not_linked:
        spin_unlock_irqrestore(&sl811->lock, flags);
        return retval;
 }
 
-static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
        struct sl811            *sl811 = hcd_to_sl811(hcd);
        struct usb_host_endpoint *hep;
        unsigned long           flags;
        struct sl811h_ep        *ep;
-       int                     retval = 0;
+       int                     retval;
 
        spin_lock_irqsave(&sl811->lock, flags);
-       hep = urb->hcpriv;
-       if (!hep)
+       retval = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (retval)
                goto fail;
 
+       hep = urb->hcpriv;
        ep = hep->hcpriv;
        if (ep) {
                /* finish right away if this urb can't be active ...
@@ -1029,8 +1009,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
                        VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
                                (sl811->active_a == ep) ? "A" : "B");
        } else
-fail:
                retval = -EINVAL;
+ fail:
        spin_unlock_irqrestore(&sl811->lock, flags);
        return retval;
 }
index b88eb3c..ac283b0 100644 (file)
@@ -51,7 +51,6 @@
 #include <linux/usb.h>
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
-#include <linux/pci_ids.h>
 #include <linux/mutex.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -184,7 +183,7 @@ struct u132_ring {
 struct u132 {
         struct kref kref;
         struct list_head u132_list;
-        struct semaphore sw_lock;
+        struct mutex sw_lock;
         struct semaphore scheduler_lock;
         struct u132_platform_data *board;
         struct platform_device *platform_dev;
@@ -493,20 +492,20 @@ static void u132_hcd_monitor_work(struct work_struct *work)
                 return;
         } else {
                 int retval;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 retval = read_roothub_info(u132);
                 if (retval) {
                         struct usb_hcd *hcd = u132_to_hcd(u132);
                         u132_disable(u132);
                         u132->going = 1;
-                        up(&u132->sw_lock);
+                        mutex_unlock(&u132->sw_lock);
                         usb_hc_died(hcd);
                         ftdi_elan_gone_away(u132->platform_dev);
                         u132_monitor_put_kref(u132);
                         return;
                 } else {
                         u132_monitor_requeue_work(u132, 500);
-                        up(&u132->sw_lock);
+                        mutex_unlock(&u132->sw_lock);
                         return;
                 }
         }
@@ -519,9 +518,8 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
         unsigned long irqs;
         struct usb_hcd *hcd = u132_to_hcd(u132);
         urb->error_count = 0;
-        urb->status = status;
-        urb->hcpriv = NULL;
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+       usb_hcd_unlink_urb_from_ep(hcd, urb);
         endp->queue_next += 1;
         if (ENDP_QUEUE_SIZE > --endp->queue_size) {
                 endp->active = 0;
@@ -543,7 +541,7 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
         u132_ring_queue_work(u132, ring, 0);
         up(&u132->scheduler_lock);
         u132_endp_put_kref(u132, endp);
-        usb_hcd_giveback_urb(hcd, urb);
+       usb_hcd_giveback_urb(hcd, urb, status);
         return;
 }
 
@@ -559,9 +557,8 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
         unsigned long irqs;
         struct usb_hcd *hcd = u132_to_hcd(u132);
         urb->error_count = 0;
-        urb->status = status;
-        urb->hcpriv = NULL;
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+       usb_hcd_unlink_urb_from_ep(hcd, urb);
         endp->queue_next += 1;
         if (ENDP_QUEUE_SIZE > --endp->queue_size) {
                 endp->active = 0;
@@ -576,7 +573,7 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
                 endp->active = 0;
                 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                 kfree(urbq);
-        } usb_hcd_giveback_urb(hcd, urb);
+       } usb_hcd_giveback_urb(hcd, urb, status);
         return;
 }
 
@@ -646,12 +643,12 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer + urb->actual_length;
                 u8 *b = buf;
@@ -717,10 +714,10 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -745,12 +742,12 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 urb->actual_length += len;
                 endp->toggle_bits = toggle_bits;
@@ -769,10 +766,10 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -798,12 +795,12 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer + urb->actual_length;
                 u8 *b = buf;
@@ -872,10 +869,10 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -899,20 +896,20 @@ static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -937,12 +934,12 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer;
                 u8 *b = buf;
@@ -981,10 +978,10 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1008,20 +1005,20 @@ static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1046,12 +1043,12 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 if (usb_pipein(urb->pipe)) {
                         int retval;
                         struct u132_ring *ring = endp->ring;
@@ -1078,10 +1075,10 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1107,22 +1104,22 @@ static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 u132->addr[0].address = 0;
                 endp->usb_addr = udev->usb_addr;
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1146,12 +1143,12 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 int retval;
                 struct u132_ring *ring = endp->ring;
                 up(&u132->scheduler_lock);
@@ -1163,10 +1160,10 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
                         u132_hcd_giveback_urb(u132, endp, urb, retval);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1190,20 +1187,20 @@ static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1228,12 +1225,12 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 int retval;
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer;
@@ -1252,10 +1249,10 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
                         u132_hcd_giveback_urb(u132, endp, urb, retval);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1280,12 +1277,12 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+       } else if (!urb->unlinked) {
                 int retval;
                 struct u132_ring *ring = endp->ring;
                 up(&u132->scheduler_lock);
@@ -1297,10 +1294,10 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
                         u132_hcd_giveback_urb(u132, endp, urb, retval);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+                               "unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+               u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1805,10 +1802,10 @@ static void u132_hcd_stop(struct usb_hcd *hcd)
                 dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
                         "ed\n", hcd);
         } else {
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 msleep(100);
                 u132_power(u132, 0);
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
         }
 }
 
@@ -1830,7 +1827,7 @@ static int u132_hcd_start(struct usb_hcd *hcd)
                         (pdev->dev.platform_data))->vendor;
                 u16 device = ((struct u132_platform_data *)
                         (pdev->dev.platform_data))->device;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 msleep(10);
                 if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
                         u132->flags = OHCI_QUIRK_AMD756;
@@ -1845,7 +1842,7 @@ static int u132_hcd_start(struct usb_hcd *hcd)
                         u132->going = 1;
                 }
                 msleep(100);
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
                 return retval;
         } else {
                 dev_err(&u132->platform_dev->dev, "platform_device missing\n");
@@ -1865,32 +1862,44 @@ static int u132_hcd_reset(struct usb_hcd *hcd)
                 return -ESHUTDOWN;
         } else {
                 int retval;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 retval = u132_init(u132);
                 if (retval) {
                         u132_disable(u132);
                         u132->going = 1;
                 }
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
                 return retval;
         }
 }
 
 static int create_endpoint_and_queue_int(struct u132 *u132,
-        struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+       struct u132_udev *udev, struct urb *urb,
         struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
         gfp_t mem_flags)
 {
         struct u132_ring *ring;
         unsigned long irqs;
-        u8 endp_number = ++u132->num_endpoints;
-        struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
-                kmalloc(sizeof(struct u132_endp), mem_flags);
+       int rc;
+       u8 endp_number;
+       struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
         if (!endp) {
                 return -ENOMEM;
         }
+
+       spin_lock_init(&endp->queue_lock.slock);
+       spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+       rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+       if (rc) {
+               spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+               kfree(endp);
+               return rc;
+       }
+
+       endp_number = ++u132->num_endpoints;
+       urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
         INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
-        spin_lock_init(&endp->queue_lock.slock);
         INIT_LIST_HEAD(&endp->urb_more);
         ring = endp->ring = &u132->ring[0];
         if (ring->curr_endp) {
@@ -1906,7 +1915,7 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
         endp->delayed = 0;
         endp->endp_number = endp_number;
         endp->u132 = u132;
-        endp->hep = hep;
+       endp->hep = urb->ep;
         endp->pipetype = usb_pipetype(urb->pipe);
         u132_endp_init_kref(u132, endp);
         if (usb_pipein(urb->pipe)) {
@@ -1925,7 +1934,6 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
                 u132_udev_get_kref(u132, udev);
         }
         urb->hcpriv = u132;
-        spin_lock_irqsave(&endp->queue_lock.slock, irqs);
         endp->delayed = 1;
         endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
         endp->udev_number = address;
@@ -1940,8 +1948,8 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
         return 0;
 }
 
-static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
-        struct usb_host_endpoint *hep, struct urb *urb,
+static int queue_int_on_old_endpoint(struct u132 *u132,
+       struct u132_udev *udev, struct urb *urb,
         struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
         u8 usb_endp, u8 address)
 {
@@ -1965,21 +1973,33 @@ static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
 }
 
 static int create_endpoint_and_queue_bulk(struct u132 *u132,
-        struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+       struct u132_udev *udev, struct urb *urb,
         struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
         gfp_t mem_flags)
 {
         int ring_number;
         struct u132_ring *ring;
         unsigned long irqs;
-        u8 endp_number = ++u132->num_endpoints;
-        struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
-                kmalloc(sizeof(struct u132_endp), mem_flags);
+       int rc;
+       u8 endp_number;
+       struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
         if (!endp) {
                 return -ENOMEM;
         }
+
+       spin_lock_init(&endp->queue_lock.slock);
+       spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+       rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+       if (rc) {
+               spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+               kfree(endp);
+               return rc;
+       }
+
+       endp_number = ++u132->num_endpoints;
+       urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
         INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
-        spin_lock_init(&endp->queue_lock.slock);
         INIT_LIST_HEAD(&endp->urb_more);
         endp->dequeueing = 0;
         endp->edset_flush = 0;
@@ -1987,7 +2007,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
         endp->delayed = 0;
         endp->endp_number = endp_number;
         endp->u132 = u132;
-        endp->hep = hep;
+       endp->hep = urb->ep;
         endp->pipetype = usb_pipetype(urb->pipe);
         u132_endp_init_kref(u132, endp);
         if (usb_pipein(urb->pipe)) {
@@ -2016,7 +2036,6 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
         }
         ring->length += 1;
         urb->hcpriv = u132;
-        spin_lock_irqsave(&endp->queue_lock.slock, irqs);
         endp->udev_number = address;
         endp->usb_addr = usb_addr;
         endp->usb_endp = usb_endp;
@@ -2030,7 +2049,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
 }
 
 static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
-         struct usb_host_endpoint *hep, struct urb *urb,
+       struct urb *urb,
         struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
         u8 usb_endp, u8 address)
 {
@@ -2052,19 +2071,32 @@ static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
 }
 
 static int create_endpoint_and_queue_control(struct u132 *u132,
-        struct usb_host_endpoint *hep, struct urb *urb,
+       struct urb *urb,
         struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp,
         gfp_t mem_flags)
 {
         struct u132_ring *ring;
-        u8 endp_number = ++u132->num_endpoints;
-        struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
-                kmalloc(sizeof(struct u132_endp), mem_flags);
+       unsigned long irqs;
+       int rc;
+       u8 endp_number;
+       struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
         if (!endp) {
                 return -ENOMEM;
         }
+
+       spin_lock_init(&endp->queue_lock.slock);
+       spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+       rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+       if (rc) {
+               spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+               kfree(endp);
+               return rc;
+       }
+
+       endp_number = ++u132->num_endpoints;
+       urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
         INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
-        spin_lock_init(&endp->queue_lock.slock);
         INIT_LIST_HEAD(&endp->urb_more);
         ring = endp->ring = &u132->ring[0];
         if (ring->curr_endp) {
@@ -2080,11 +2112,10 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
         endp->delayed = 0;
         endp->endp_number = endp_number;
         endp->u132 = u132;
-        endp->hep = hep;
+       endp->hep = urb->ep;
         u132_endp_init_kref(u132, endp);
         u132_endp_get_kref(u132, endp);
         if (usb_addr == 0) {
-                unsigned long irqs;
                 u8 address = u132->addr[usb_addr].address;
                 struct u132_udev *udev = &u132->udev[address];
                 endp->udev_number = address;
@@ -2098,7 +2129,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
                 udev->endp_number_in[usb_endp] = endp_number;
                 udev->endp_number_out[usb_endp] = endp_number;
                 urb->hcpriv = u132;
-                spin_lock_irqsave(&endp->queue_lock.slock, irqs);
                 endp->queue_size = 1;
                 endp->queue_last = 0;
                 endp->queue_next = 0;
@@ -2107,7 +2137,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
                 u132_endp_queue_work(u132, endp, 0);
                 return 0;
         } else {                /*(usb_addr > 0) */
-                unsigned long irqs;
                 u8 address = u132->addr[usb_addr].address;
                 struct u132_udev *udev = &u132->udev[address];
                 endp->udev_number = address;
@@ -2121,7 +2150,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
                 udev->endp_number_in[usb_endp] = endp_number;
                 udev->endp_number_out[usb_endp] = endp_number;
                 urb->hcpriv = u132;
-                spin_lock_irqsave(&endp->queue_lock.slock, irqs);
                 endp->queue_size = 1;
                 endp->queue_last = 0;
                 endp->queue_next = 0;
@@ -2133,7 +2161,7 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
 }
 
 static int queue_control_on_old_endpoint(struct u132 *u132,
-        struct usb_host_endpoint *hep, struct urb *urb,
+       struct urb *urb,
         struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
         u8 usb_endp)
 {
@@ -2233,8 +2261,8 @@ static int queue_control_on_old_endpoint(struct u132 *u132,
         }
 }
 
-static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
-        struct urb *urb, gfp_t mem_flags)
+static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+               gfp_t mem_flags)
 {
         struct u132 *u132 = hcd_to_u132(hcd);
         if (irqs_disabled()) {
@@ -2249,8 +2277,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                         , u132->going);
                 return -ENODEV;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+               dev_err(&u132->platform_dev->dev, "device is being removed "
+                               "urb=%p\n", urb);
                 return -ESHUTDOWN;
         } else {
                 u8 usb_addr = usb_pipedevice(urb->pipe);
@@ -2259,16 +2287,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                 if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
                         u8 address = u132->addr[usb_addr].address;
                         struct u132_udev *udev = &u132->udev[address];
-                        struct u132_endp *endp = hep->hcpriv;
+                        struct u132_endp *endp = urb->ep->hcpriv;
                         urb->actual_length = 0;
                         if (endp) {
                                 unsigned long irqs;
                                 int retval;
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                         irqs);
-                                retval = queue_int_on_old_endpoint(u132, udev,
-                                        hep, urb, usb_dev, endp, usb_addr,
-                                        usb_endp, address);
+                               retval = usb_hcd_link_urb_to_ep(hcd, urb);
+                               if (retval == 0) {
+                                       retval = queue_int_on_old_endpoint(
+                                                       u132, udev, urb,
+                                                       usb_dev, endp,
+                                                       usb_addr, usb_endp,
+                                                       address);
+                                       if (retval)
+                                               usb_hcd_unlink_urb_from_ep(
+                                                               hcd, urb);
+                               }
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
                                         irqs);
                                 if (retval) {
@@ -2283,8 +2319,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                                 return -EINVAL;
                         } else {        /*(endp == NULL) */
                                 return create_endpoint_and_queue_int(u132, udev,
-                                         hep, urb, usb_dev, usb_addr, usb_endp,
-                                        address, mem_flags);
+                                               urb, usb_dev, usb_addr,
+                                               usb_endp, address, mem_flags);
                         }
                 } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
                         dev_err(&u132->platform_dev->dev, "the hardware does no"
@@ -2293,16 +2329,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                 } else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
                         u8 address = u132->addr[usb_addr].address;
                         struct u132_udev *udev = &u132->udev[address];
-                        struct u132_endp *endp = hep->hcpriv;
+                        struct u132_endp *endp = urb->ep->hcpriv;
                         urb->actual_length = 0;
                         if (endp) {
                                 unsigned long irqs;
                                 int retval;
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                         irqs);
-                                retval = queue_bulk_on_old_endpoint(u132, udev,
-                                        hep, urb, usb_dev, endp, usb_addr,
-                                        usb_endp, address);
+                               retval = usb_hcd_link_urb_to_ep(hcd, urb);
+                               if (retval == 0) {
+                                       retval = queue_bulk_on_old_endpoint(
+                                                       u132, udev, urb,
+                                                       usb_dev, endp,
+                                                       usb_addr, usb_endp,
+                                                       address);
+                                       if (retval)
+                                               usb_hcd_unlink_urb_from_ep(
+                                                               hcd, urb);
+                               }
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
                                         irqs);
                                 if (retval) {
@@ -2315,10 +2359,10 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                                 return -EINVAL;
                         } else
                                 return create_endpoint_and_queue_bulk(u132,
-                                        udev, hep, urb, usb_dev, usb_addr,
+                                       udev, urb, usb_dev, usb_addr,
                                         usb_endp, address, mem_flags);
                 } else {
-                        struct u132_endp *endp = hep->hcpriv;
+                        struct u132_endp *endp = urb->ep->hcpriv;
                         u16 urb_size = 8;
                         u8 *b = urb->setup_packet;
                         int i = 0;
@@ -2341,9 +2385,16 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                                 int retval;
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                         irqs);
-                                retval = queue_control_on_old_endpoint(u132,
-                                        hep, urb, usb_dev, endp, usb_addr,
-                                        usb_endp);
+                               retval = usb_hcd_link_urb_to_ep(hcd, urb);
+                               if (retval == 0) {
+                                       retval = queue_control_on_old_endpoint(
+                                                       u132, urb, usb_dev,
+                                                       endp, usb_addr,
+                                                       usb_endp);
+                                       if (retval)
+                                               usb_hcd_unlink_urb_from_ep(
+                                                               hcd, urb);
+                               }
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
                                         irqs);
                                 if (retval) {
@@ -2356,7 +2407,7 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                                 return -EINVAL;
                         } else
                                 return create_endpoint_and_queue_control(u132,
-                                        hep, urb, usb_dev, usb_addr, usb_endp,
+                                       urb, usb_dev, usb_addr, usb_endp,
                                         mem_flags);
                 }
         }
@@ -2375,8 +2426,7 @@ static int dequeue_from_overflow_chain(struct u132 *u132,
                         list_del(scan);
                         endp->queue_size -= 1;
                         urb->error_count = 0;
-                        urb->hcpriv = NULL;
-                        usb_hcd_giveback_urb(hcd, urb);
+                       usb_hcd_giveback_urb(hcd, urb, 0);
                         return 0;
                 } else
                         continue;
@@ -2391,10 +2441,17 @@ static int dequeue_from_overflow_chain(struct u132 *u132,
 }
 
 static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
-        struct urb *urb)
+               struct urb *urb, int status)
 {
         unsigned long irqs;
+       int rc;
+
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+       rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status);
+       if (rc) {
+               spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+               return rc;
+       }
         if (endp->queue_size == 0) {
                 dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]"
                         "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb,
@@ -2410,11 +2467,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
                         endp->edset_flush = 1;
                         u132_endp_queue_work(u132, endp, 0);
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
-                        urb->hcpriv = NULL;
                         return 0;
                 } else {
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
-                        u132_hcd_abandon_urb(u132, endp, urb, urb->status);
+                       u132_hcd_abandon_urb(u132, endp, urb, status);
                         return 0;
                 }
         } else {
@@ -2439,6 +2495,8 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
                 }
                 if (urb_slot) {
                         struct usb_hcd *hcd = u132_to_hcd(u132);
+
+                       usb_hcd_unlink_urb_from_ep(hcd, urb);
                         endp->queue_size -= 1;
                         if (list_empty(&endp->urb_more)) {
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
@@ -2453,8 +2511,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
                                         irqs);
                                 kfree(urbq);
                         } urb->error_count = 0;
-                        urb->hcpriv = NULL;
-                        usb_hcd_giveback_urb(hcd, urb);
+                       usb_hcd_giveback_urb(hcd, urb, status);
                         return 0;
                 } else if (list_empty(&endp->urb_more)) {
                         dev_err(&u132->platform_dev->dev, "urb=%p not found in "
@@ -2468,7 +2525,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                         return -EINVAL;
                 } else {
-                        int retval = dequeue_from_overflow_chain(u132, endp,
+                       int retval;
+
+                       usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb);
+                       retval = dequeue_from_overflow_chain(u132, endp,
                                 urb);
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                         return retval;
@@ -2476,7 +2536,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
         }
 }
 
-static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
         struct u132 *u132 = hcd_to_u132(hcd);
         if (u132->going > 2) {
@@ -2491,11 +2551,11 @@ static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
                 if (usb_pipein(urb->pipe)) {
                         u8 endp_number = udev->endp_number_in[usb_endp];
                         struct u132_endp *endp = u132->endp[endp_number - 1];
-                        return u132_endp_urb_dequeue(u132, endp, urb);
+                        return u132_endp_urb_dequeue(u132, endp, urb, status);
                 } else {
                         u8 endp_number = udev->endp_number_out[usb_endp];
                         struct u132_endp *endp = u132->endp[endp_number - 1];
-                        return u132_endp_urb_dequeue(u132, endp, urb);
+                        return u132_endp_urb_dequeue(u132, endp, urb, status);
                 }
         }
 }
@@ -2805,7 +2865,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                 return -ESHUTDOWN;
         } else {
                 int retval = 0;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 switch (typeReq) {
                 case ClearHubFeature:
                         switch (wValue) {
@@ -2868,7 +2928,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                       stall:retval = -EPIPE;
                         break;
                 }
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
                 return retval;
         }
 }
@@ -3004,7 +3064,7 @@ static int __devexit u132_remove(struct platform_device *pdev)
                         dev_err(&u132->platform_dev->dev, "removing device u132"
                                ".%d\n", u132->sequence_num);
                         msleep(100);
-                        down(&u132->sw_lock);
+                        mutex_lock(&u132->sw_lock);
                         u132_monitor_cancel_work(u132);
                         while (rings-- > 0) {
                                 struct u132_ring *ring = &u132->ring[rings];
@@ -3017,7 +3077,7 @@ static int __devexit u132_remove(struct platform_device *pdev)
                         u132->going += 1;
                         printk(KERN_INFO "removing device u132.%d\n",
                                 u132->sequence_num);
-                        up(&u132->sw_lock);
+                        mutex_unlock(&u132->sw_lock);
                         usb_remove_hcd(hcd);
                         u132_u132_put_kref(u132);
                         return 0;
@@ -3037,7 +3097,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
         u132->platform_dev = pdev;
         u132->power = 0;
         u132->reset = 0;
-        init_MUTEX(&u132->sw_lock);
+        mutex_init(&u132->sw_lock);
         init_MUTEX(&u132->scheduler_lock);
         while (rings-- > 0) {
                 struct u132_ring *ring = &u132->ring[rings];
@@ -3047,7 +3107,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
                 ring->curr_endp = NULL;
                 INIT_DELAYED_WORK(&ring->scheduler,
                                  u132_hcd_ring_work_scheduler);
-        } down(&u132->sw_lock);
+        } mutex_lock(&u132->sw_lock);
         INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work);
         while (ports-- > 0) {
                 struct u132_port *port = &u132->port[ports];
@@ -3077,7 +3137,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
         while (endps-- > 0) {
                 u132->endp[endps] = NULL;
         }
-        up(&u132->sw_lock);
+        mutex_unlock(&u132->sw_lock);
         return;
 }
 
index 1497371..20cc58b 100644 (file)
@@ -120,8 +120,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
        out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : ""));
        out += sprintf(out, " Actlen=%d", urbp->urb->actual_length);
 
-       if (urbp->urb->status != -EINPROGRESS)
-               out += sprintf(out, " Status=%d", urbp->urb->status);
+       if (urbp->urb->unlinked)
+               out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked);
        out += sprintf(out, "\n");
 
        i = nactive = ninactive = 0;
index 1b3d234..340d6ed 100644 (file)
@@ -146,7 +146,6 @@ struct uhci_qh {
        short phase;                    /* Between 0 and period-1 */
        short load;                     /* Periodic time requirement, in us */
        unsigned int iso_frame;         /* Frame # for iso_packet_desc */
-       int iso_status;                 /* Status for Isochronous URBs */
 
        int state;                      /* QH_STATE_xxx; see above */
        int type;                       /* Queue type (control, bulk, etc) */
@@ -457,21 +456,6 @@ struct urb_priv {
 };
 
 
-/*
- * Locking in uhci.c
- *
- * Almost everything relating to the hardware schedule and processing
- * of URBs is protected by uhci->lock.  urb->status is protected by
- * urb->lock; that's the one exception.
- *
- * To prevent deadlocks, never lock uhci->lock while holding urb->lock.
- * The safe order of locking is:
- *
- * #1 uhci->lock
- * #2 urb->lock
- */
-
-
 /* Some special IDs */
 
 #define PCI_VENDOR_ID_GENESYS          0x17a0
index 3bb908c..e5d60d5 100644 (file)
@@ -757,7 +757,6 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci,
                uhci_free_td(uhci, td);
        }
 
-       urbp->urb->hcpriv = NULL;
        kmem_cache_free(uhci_up_cachep, urbp);
 }
 
@@ -1324,7 +1323,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
        if (list_empty(&qh->queue)) {
                qh->iso_packet_desc = &urb->iso_frame_desc[0];
                qh->iso_frame = urb->start_frame;
-               qh->iso_status = 0;
        }
 
        qh->skel = SKEL_ISO;
@@ -1361,22 +1359,18 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
                        qh->iso_packet_desc->actual_length = actlength;
                        qh->iso_packet_desc->status = status;
                }
-
-               if (status) {
+               if (status)
                        urb->error_count++;
-                       qh->iso_status = status;
-               }
 
                uhci_remove_td_from_urbp(td);
                uhci_free_td(uhci, td);
                qh->iso_frame += qh->period;
                ++qh->iso_packet_desc;
        }
-       return qh->iso_status;
+       return 0;
 }
 
 static int uhci_urb_enqueue(struct usb_hcd *hcd,
-               struct usb_host_endpoint *hep,
                struct urb *urb, gfp_t mem_flags)
 {
        int ret;
@@ -1387,19 +1381,19 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
 
        spin_lock_irqsave(&uhci->lock, flags);
 
-       ret = urb->status;
-       if (ret != -EINPROGRESS)                /* URB already unlinked! */
-               goto done;
+       ret = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (ret)
+               goto done_not_linked;
 
        ret = -ENOMEM;
        urbp = uhci_alloc_urb_priv(uhci, urb);
        if (!urbp)
                goto done;
 
-       if (hep->hcpriv)
-               qh = (struct uhci_qh *) hep->hcpriv;
+       if (urb->ep->hcpriv)
+               qh = urb->ep->hcpriv;
        else {
-               qh = uhci_alloc_qh(uhci, urb->dev, hep);
+               qh = uhci_alloc_qh(uhci, urb->dev, urb->ep);
                if (!qh)
                        goto err_no_qh;
        }
@@ -1440,27 +1434,29 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
 err_submit_failed:
        if (qh->state == QH_STATE_IDLE)
                uhci_make_qh_idle(uhci, qh);    /* Reclaim unused QH */
-
 err_no_qh:
        uhci_free_urb_priv(uhci, urbp);
-
 done:
+       if (ret)
+               usb_hcd_unlink_urb_from_ep(hcd, urb);
+done_not_linked:
        spin_unlock_irqrestore(&uhci->lock, flags);
        return ret;
 }
 
-static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
        unsigned long flags;
-       struct urb_priv *urbp;
        struct uhci_qh *qh;
+       int rc;
 
        spin_lock_irqsave(&uhci->lock, flags);
-       urbp = urb->hcpriv;
-       if (!urbp)                      /* URB was never linked! */
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (rc)
                goto done;
-       qh = urbp->qh;
+
+       qh = ((struct urb_priv *) urb->hcpriv)->qh;
 
        /* Remove Isochronous TDs from the frame list ASAP */
        if (qh->type == USB_ENDPOINT_XFER_ISOC) {
@@ -1477,14 +1473,14 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
 
 done:
        spin_unlock_irqrestore(&uhci->lock, flags);
-       return 0;
+       return rc;
 }
 
 /*
  * Finish unlinking an URB and give it back
  */
 static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh,
-               struct urb *urb)
+               struct urb *urb, int status)
 __releases(uhci->lock)
 __acquires(uhci->lock)
 {
@@ -1497,13 +1493,6 @@ __acquires(uhci->lock)
                 * unlinked first.  Regardless, don't confuse people with a
                 * negative length. */
                urb->actual_length = max(urb->actual_length, 0);
-
-               /* Report erroneous short transfers */
-               if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
-                               urb->actual_length <
-                                       urb->transfer_buffer_length &&
-                               urb->status == 0))
-                       urb->status = -EREMOTEIO;
        }
 
        /* When giving back the first URB in an Isochronous queue,
@@ -1516,7 +1505,6 @@ __acquires(uhci->lock)
 
                qh->iso_packet_desc = &nurb->iso_frame_desc[0];
                qh->iso_frame = nurb->start_frame;
-               qh->iso_status = 0;
        }
 
        /* Take the URB off the QH's queue.  If the queue is now empty,
@@ -1529,9 +1517,10 @@ __acquires(uhci->lock)
        }
 
        uhci_free_urb_priv(uhci, urbp);
+       usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb);
 
        spin_unlock(&uhci->lock);
-       usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
+       usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, status);
        spin_lock(&uhci->lock);
 
        /* If the queue is now empty, we can unlink the QH and give up its
@@ -1567,24 +1556,17 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
                if (status == -EINPROGRESS)
                        break;
 
-               spin_lock(&urb->lock);
-               if (urb->status == -EINPROGRESS)        /* Not dequeued */
-                       urb->status = status;
-               else
-                       status = ECONNRESET;            /* Not -ECONNRESET */
-               spin_unlock(&urb->lock);
-
                /* Dequeued but completed URBs can't be given back unless
                 * the QH is stopped or has finished unlinking. */
-               if (status == ECONNRESET) {
+               if (urb->unlinked) {
                        if (QH_FINISHED_UNLINKING(qh))
                                qh->is_stopped = 1;
                        else if (!qh->is_stopped)
                                return;
                }
 
-               uhci_giveback_urb(uhci, qh, urb);
-               if (status < 0 && qh->type != USB_ENDPOINT_XFER_ISOC)
+               uhci_giveback_urb(uhci, qh, urb, status);
+               if (status < 0)
                        break;
        }
 
@@ -1599,7 +1581,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
 restart:
        list_for_each_entry(urbp, &qh->queue, node) {
                urb = urbp->urb;
-               if (urb->status != -EINPROGRESS) {
+               if (urb->unlinked) {
 
                        /* Fix up the TD links and save the toggles for
                         * non-Isochronous queues.  For Isochronous queues,
@@ -1608,7 +1590,7 @@ restart:
                                qh->is_stopped = 0;
                                return;
                        }
-                       uhci_giveback_urb(uhci, qh, urb);
+                       uhci_giveback_urb(uhci, qh, urb, 0);
                        goto restart;
                }
        }
index e9fdbc8..5131cbf 100644 (file)
@@ -188,7 +188,8 @@ static void adu_interrupt_in_callback(struct urb *urb)
        spin_lock(&dev->buflock);
 
        if (status != 0) {
-               if ((status != -ENOENT) && (status != -ECONNRESET)) {
+               if ((status != -ENOENT) && (status != -ECONNRESET) &&
+                       (status != -ESHUTDOWN)) {
                        dbg(1," %s : nonzero status received: %d",
                            __FUNCTION__, status);
                }
index 92c1d27..24e2dc3 100644 (file)
@@ -71,7 +71,7 @@ static int magic_charge(struct usb_device *udev)
        if (retval != 2) {
                dev_err(&udev->dev, "First magic command failed: %d.\n",
                        retval);
-               return retval;
+               goto exit;
        }
 
        dbg(&udev->dev, "Sending second magic command\n");
@@ -80,7 +80,7 @@ static int magic_charge(struct usb_device *udev)
        if (retval != 0) {
                dev_err(&udev->dev, "Second magic command failed: %d.\n",
                        retval);
-               return retval;
+               goto exit;
        }
 
        dbg(&udev->dev, "Calling set_configuration\n");
@@ -88,6 +88,8 @@ static int magic_charge(struct usb_device *udev)
        if (retval)
                dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
 
+exit:
+       kfree(dummy_buffer);
        return retval;
 }
 
@@ -112,6 +114,7 @@ static int magic_dual_mode(struct usb_device *udev)
        if (retval)
                dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
 
+       kfree(dummy_buffer);
        return retval;
 }
 
index 538b535..d3d8cd6 100644 (file)
@@ -2777,12 +2777,14 @@ static int ftdi_elan_probe(struct usb_interface *interface,
         size_t buffer_size;
         int i;
         int retval = -ENOMEM;
-        struct usb_ftdi *ftdi = kmalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
-        if (ftdi == NULL) {
+        struct usb_ftdi *ftdi;
+
+       ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
+       if (!ftdi) {
                 printk(KERN_ERR "Out of memory\n");
                 return -ENOMEM;
         }
-        memset(ftdi, 0x00, sizeof(struct usb_ftdi));
+
         mutex_lock(&ftdi_module_lock);
         list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
         ftdi->sequence_num = ++ftdi_instances;
index b64ca91..9244d06 100644 (file)
@@ -32,7 +32,7 @@
  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Author:     Thomas Winischhofer <thomas@winischhofer.net>
+ * Author:     Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
@@ -962,12 +962,12 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
                           packet.address = 0x00000194;
                           packet.data    = addr;
                           ret = sisusb_send_bridge_packet(sisusb, 10,
-                                                               &packet, 0);
+                                                               &packet, 0);
                           packet.header  = 0x001f;
                           packet.address = 0x00000190;
                           packet.data    = (length & ~3);
                           ret |= sisusb_send_bridge_packet(sisusb, 10,
-                                                               &packet, 0);
+                                                               &packet, 0);
                           if (sisusb->flagb0 != 0x16) {
                                packet.header  = 0x001f;
                                packet.address = 0x00000180;
@@ -1003,23 +1003,17 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
                        if (ret) {
                                msgcount++;
                                if (msgcount < 500)
-                                       printk(KERN_ERR
-                                               "sisusbvga[%d]: Wrote %zd of "
-                                               "%d bytes, error %d\n",
-                                               sisusb->minor, *bytes_written,
-                                               length, ret);
+                                       dev_err(&sisusb->sisusb_dev->dev, "Wrote %zd of %d bytes, error %d\n",
+                                               *bytes_written, length, ret);
                                else if (msgcount == 500)
-                                       printk(KERN_ERR
-                                               "sisusbvga[%d]: Too many errors"
-                                               ", logging stopped\n",
-                                               sisusb->minor);
+                                       dev_err(&sisusb->sisusb_dev->dev, "Too many errors, logging stopped\n");
                        }
                        addr += (*bytes_written);
                        length -= (*bytes_written);
            }
 
            if (ret)
-               break;
+               break;
 
        }
 
@@ -1261,51 +1255,10 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
                                addr += 4;
                                length -= 4;
                        }
-#if 0          /* That does not work, as EP 2 is an OUT EP! */
-               default:
-                       CLEARPACKET(&packet);
-                       packet.header  = 0x001f;
-                       packet.address = 0x000001a0;
-                       packet.data    = 0x00000006;
-                       ret |= sisusb_send_bridge_packet(sisusb, 10,
-                                                               &packet, 0);
-                       packet.header  = 0x001f;
-                       packet.address = 0x000001b0;
-                       packet.data    = (length & ~3) | 0x40000000;
-                       ret |= sisusb_send_bridge_packet(sisusb, 10,
-                                                               &packet, 0);
-                       packet.header  = 0x001f;
-                       packet.address = 0x000001b4;
-                       packet.data    = addr;
-                       ret |= sisusb_send_bridge_packet(sisusb, 10,
-                                                               &packet, 0);
-                       packet.header  = 0x001f;
-                       packet.address = 0x000001a4;
-                       packet.data    = 0x00000001;
-                       ret |= sisusb_send_bridge_packet(sisusb, 10,
-                                                               &packet, 0);
-                       if (userbuffer) {
-                               ret |= sisusb_recv_bulk_msg(sisusb,
-                                                       SISUSB_EP_GFX_BULK_IN,
-                                                       (length & ~3),
-                                                       NULL, userbuffer,
-                                                       bytes_read, 0);
-                               if (!ret) userbuffer += (*bytes_read);
-                       } else {
-                               ret |= sisusb_recv_bulk_msg(sisusb,
-                                                       SISUSB_EP_GFX_BULK_IN,
-                                                       (length & ~3),
-                                                       kernbuffer, NULL,
-                                                       bytes_read, 0);
-                               if (!ret) kernbuffer += (*bytes_read);
-                       }
-                       addr += (*bytes_read);
-                       length -= (*bytes_read);
-#endif
            }
 
            if (ret)
-               break;
+               break;
        }
 
        return ret;
@@ -1401,22 +1354,6 @@ sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
        return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
 }
 
-#if 0
-
-int
-sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
-{
-       return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
-}
-
-int
-sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
-{
-       return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
-}
-
-#endif  /*  0  */
-
 int
 sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
                        u32 dest, int length, size_t *bytes_written)
@@ -1446,10 +1383,10 @@ sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
     sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
 
     for(i = 1; i <= 7; i++) {
-        printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
+        dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i);
        sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
        for(j = 0; j < i; j++) {
-            printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
+            dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", j, destbuffer[j]);
        }
     }
 }
@@ -1533,9 +1470,9 @@ sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
 #define SETIREGAND(r,i,a)      sisusb_setidxregand(sisusb, r, i, a)
 #define SETIREGANDOR(r,i,a,o)  sisusb_setidxregandor(sisusb, r, i, a, o)
 #define READL(a,d)     sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
-#define WRITEL(a,d)    sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEL(a,d)    sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
 #define READB(a,d)     sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
-#define WRITEB(a,d)    sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEB(a,d)    sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
 
 static int
 sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
@@ -2008,7 +1945,7 @@ sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
                SETIREG(SISSR, 0x26, 0x00);
        }
 
-       SETIREG(SISCR, 0x34, 0x44);     /* we just set std mode #44 */
+       SETIREG(SISCR, 0x34, 0x44);     /* we just set std mode #44 */
 
        return ret;
 }
@@ -2168,17 +2105,12 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
                if (ramtype <= 1) {
                        ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
                        if (iret) {
-                               printk(KERN_ERR "sisusbvga[%d]: RAM size "
-                                       "detection failed, "
-                                       "assuming 8MB video RAM\n",
-                                       sisusb->minor);
+                               dev_err(&sisusb->sisusb_dev->dev,"RAM size detection failed, assuming 8MB video RAM\n");
                                ret |= SETIREG(SISSR,0x14,0x31);
                                /* TODO */
                        }
                } else {
-                       printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
-                                       "assuming 8MB video RAM\n",
-                                       sisusb->minor);
+                       dev_err(&sisusb->sisusb_dev->dev, "DDR RAM device found, assuming 8MB video RAM\n");
                        ret |= SETIREG(SISSR,0x14,0x31);
                        /* *** TODO *** */
                }
@@ -2249,8 +2181,7 @@ sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
                break;
        }
 
-       printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
-                       sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
+       dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %s, bus width %d\n", (sisusb->vramsize >> 20), ramtypetext1,
                        ramtypetext2[ramtype], bw);
 }
 
@@ -2509,11 +2440,8 @@ sisusb_open(struct inode *inode, struct file *file)
        struct usb_interface *interface;
        int subminor = iminor(inode);
 
-       if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
-               printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
-                               subminor);
+       if (!(interface = usb_find_interface(&sisusb_driver, subminor)))
                return -ENODEV;
-       }
 
        if (!(sisusb = usb_get_intfdata(interface)))
                return -ENODEV;
@@ -2534,18 +2462,12 @@ sisusb_open(struct inode *inode, struct file *file)
                if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
                        if (sisusb_init_gfxdevice(sisusb, 0)) {
                                mutex_unlock(&sisusb->lock);
-                               printk(KERN_ERR
-                                       "sisusbvga[%d]: Failed to initialize "
-                                       "device\n",
-                                       sisusb->minor);
+                               dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n");
                                return -EIO;
                        }
                } else {
                        mutex_unlock(&sisusb->lock);
-                       printk(KERN_ERR
-                               "sisusbvga[%d]: Device not attached to "
-                               "USB 2.0 hub\n",
-                               sisusb->minor);
+                       dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n");
                        return -EIO;
                }
        }
@@ -2586,7 +2508,6 @@ static int
 sisusb_release(struct inode *inode, struct file *file)
 {
        struct sisusb_usb_data *sisusb;
-       int myminor;
 
        if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
                return -ENODEV;
@@ -2599,8 +2520,6 @@ sisusb_release(struct inode *inode, struct file *file)
                        sisusb_kill_all_busy(sisusb);
        }
 
-       myminor = sisusb->minor;
-
        sisusb->isopen = 0;
        file->private_data = NULL;
 
@@ -2942,7 +2861,7 @@ static int
 sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
                                                        unsigned long arg)
 {
-       int     retval, port, length;
+       int     retval, port, length;
        u32     address;
 
        /* All our commands require the device
@@ -3065,12 +2984,12 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
 
 static int
 sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                                                       unsigned long arg)
+                                                       unsigned long arg)
 {
        struct sisusb_usb_data *sisusb;
        struct sisusb_info x;
        struct sisusb_command y;
-       int     retval = 0;
+       int     retval = 0;
        u32 __user *argp = (u32 __user *)arg;
 
        if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
@@ -3095,7 +3014,7 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 
                case SISUSB_GET_CONFIG:
 
-                       x.sisusb_id         = SISUSB_ID;
+                       x.sisusb_id         = SISUSB_ID;
                        x.sisusb_version    = SISUSB_VERSION;
                        x.sisusb_revision   = SISUSB_REVISION;
                        x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
@@ -3164,7 +3083,7 @@ static const struct file_operations usb_sisusb_fops = {
        .release =      sisusb_release,
        .read =         sisusb_read,
        .write =        sisusb_write,
-       .llseek =       sisusb_lseek,
+       .llseek =       sisusb_lseek,
 #ifdef SISUSB_NEW_CONFIG_COMPAT
        .compat_ioctl = sisusb_compat_ioctl,
 #endif
@@ -3183,17 +3102,13 @@ static int sisusb_probe(struct usb_interface *intf,
        struct usb_device *dev = interface_to_usbdev(intf);
        struct sisusb_usb_data *sisusb;
        int retval = 0, i;
-       const char *memfail =
-               KERN_ERR
-               "sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
 
-       printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
+       dev_info(&dev->dev, "USB2VGA dongle found at address %d\n",
                dev->devnum);
 
        /* Allocate memory for our private */
        if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
-               printk(KERN_ERR
-                       "sisusb: Failed to allocate memory for private data\n");
+               dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n");
                return -ENOMEM;
        }
        kref_init(&sisusb->kref);
@@ -3202,8 +3117,7 @@ static int sisusb_probe(struct usb_interface *intf,
 
        /* Register device */
        if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
-               printk(KERN_ERR
-                       "sisusb: Failed to get a minor for device %d\n",
+               dev_err(&sisusb->sisusb_dev->dev, "Failed to get a minor for device %d\n",
                        dev->devnum);
                retval = -ENODEV;
                goto error_1;
@@ -3221,7 +3135,7 @@ static int sisusb_probe(struct usb_interface *intf,
        sisusb->ibufsize = SISUSB_IBUF_SIZE;
        if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
                                        GFP_KERNEL, &sisusb->transfer_dma_in))) {
-               printk(memfail, "input", sisusb->minor);
+               dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer");
                retval = -ENOMEM;
                goto error_2;
        }
@@ -3233,7 +3147,7 @@ static int sisusb_probe(struct usb_interface *intf,
                                        GFP_KERNEL,
                                        &sisusb->transfer_dma_out[i]))) {
                        if (i == 0) {
-                               printk(memfail, "output", sisusb->minor);
+                               dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n");
                                retval = -ENOMEM;
                                goto error_3;
                        }
@@ -3245,9 +3159,7 @@ static int sisusb_probe(struct usb_interface *intf,
 
        /* Allocate URBs */
        if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
-               printk(KERN_ERR
-                       "sisusbvga[%d]: Failed to allocate URBs\n",
-                       sisusb->minor);
+               dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
                retval = -ENOMEM;
                goto error_3;
        }
@@ -3255,9 +3167,7 @@ static int sisusb_probe(struct usb_interface *intf,
 
        for (i = 0; i < sisusb->numobufs; i++) {
                if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
-                       printk(KERN_ERR
-                               "sisusbvga[%d]: Failed to allocate URBs\n",
-                               sisusb->minor);
+                       dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
                        retval = -ENOMEM;
                        goto error_4;
                }
@@ -3266,15 +3176,12 @@ static int sisusb_probe(struct usb_interface *intf,
                sisusb->urbstatus[i] = 0;
        }
 
-       printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
-                                       sisusb->minor, sisusb->numobufs);
+       dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs);
 
 #ifdef INCL_SISUSB_CON
        /* Allocate our SiS_Pr */
        if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
-               printk(KERN_ERR
-                       "sisusbvga[%d]: Failed to allocate SiS_Pr\n",
-                       sisusb->minor);
+               dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate SiS_Pr\n");
        }
 #endif
 
@@ -3296,10 +3203,7 @@ static int sisusb_probe(struct usb_interface *intf,
        ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG,      NULL);
        ret |= register_ioctl32_conversion(SISUSB_COMMAND,         NULL);
        if (ret)
-               printk(KERN_ERR
-                       "sisusbvga[%d]: Error registering ioctl32 "
-                       "translations\n",
-                       sisusb->minor);
+               dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n");
        else
                sisusb->ioctl32registered = 1;
        }
@@ -3315,23 +3219,17 @@ static int sisusb_probe(struct usb_interface *intf,
                        initscreen = 0;
 #endif
                if (sisusb_init_gfxdevice(sisusb, initscreen))
-                       printk(KERN_ERR
-                               "sisusbvga[%d]: Failed to early "
-                               "initialize device\n",
-                               sisusb->minor);
+                       dev_err(&sisusb->sisusb_dev->dev, "Failed to early initialize device\n");
 
        } else
-               printk(KERN_INFO
-                       "sisusbvga[%d]: Not attached to USB 2.0 hub, "
-                       "deferring init\n",
-                       sisusb->minor);
+               dev_info(&sisusb->sisusb_dev->dev, "Not attached to USB 2.0 hub, deferring init\n");
 
        sisusb->ready = 1;
 
 #ifdef SISUSBENDIANTEST
-       printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
+       dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST ***\n");
        sisusb_testreadwrite(sisusb);
-       printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
+       dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n");
 #endif
 
 #ifdef INCL_SISUSB_CON
@@ -3354,7 +3252,6 @@ error_1:
 static void sisusb_disconnect(struct usb_interface *intf)
 {
        struct sisusb_usb_data *sisusb;
-       int minor;
 
        /* This should *not* happen */
        if (!(sisusb = usb_get_intfdata(intf)))
@@ -3364,8 +3261,6 @@ static void sisusb_disconnect(struct usb_interface *intf)
        sisusb_console_exit(sisusb);
 #endif
 
-       minor = sisusb->minor;
-
        usb_deregister_dev(intf, &usb_sisusb_class);
 
        mutex_lock(&sisusb->lock);
@@ -3384,10 +3279,7 @@ static void sisusb_disconnect(struct usb_interface *intf)
                ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
                ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
                if (ret) {
-                       printk(KERN_ERR
-                               "sisusbvga[%d]: Error unregistering "
-                               "ioctl32 translations\n",
-                               minor);
+                       dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n");
                }
        }
 #endif
@@ -3400,7 +3292,7 @@ static void sisusb_disconnect(struct usb_interface *intf)
        /* decrement our usage count */
        kref_put(&sisusb->kref, sisusb_delete);
 
-       printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
+       dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n");
 }
 
 static struct usb_device_id sisusb_table [] = {
@@ -3424,22 +3316,12 @@ static struct usb_driver sisusb_driver = {
 
 static int __init usb_sisusb_init(void)
 {
-       int retval;
 
 #ifdef INCL_SISUSB_CON
        sisusb_init_concode();
 #endif
 
-       if (!(retval = usb_register(&sisusb_driver))) {
-
-               printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
-                       SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
-               printk(KERN_INFO
-                       "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
-
-       }
-
-       return retval;
+       return usb_register(&sisusb_driver);
 }
 
 static void __exit usb_sisusb_exit(void)
index 8e1120a..d2d7872 100644 (file)
@@ -8,29 +8,29 @@
  *
  * Otherwise, the following license terms apply:
  *
- * * Redistribution and use in source and binary forms, with or without
- * * modification, are permitted provided that the following conditions
- * * are met:
- * * 1) Redistributions of source code must retain the above copyright
- * *    notice, this list of conditions and the following disclaimer.
- * * 2) Redistributions in binary form must reproduce the above copyright
- * *    notice, this list of conditions and the following disclaimer in the
- * *    documentation and/or other materials provided with the distribution.
- * * 3) The name of the author may not be used to endorse or promote products
- * *    derived from this software without specific prior written permission.
- * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
- * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1) Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2) Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3) The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
  *
- * Author:     Thomas Winischhofer <thomas@winischhofer.net>
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author:     Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
 #include <linux/mutex.h>
 
 /* For older kernels, support for text consoles is by default
- * off. To ensable text console support, change the following:
+ * off. To enable text console support, change the following:
  */
-#if 0
-#define CONFIG_USB_SISUSBVGA_CON
-#endif
+/* #define CONFIG_USB_SISUSBVGA_CON */
 
 /* Version Information */
 
 #define SISUSB_VERSION         0
-#define SISUSB_REVISION        0
+#define SISUSB_REVISION                0
 #define SISUSB_PATCHLEVEL      8
 
 /* Include console and mode switching code? */
@@ -74,7 +72,7 @@
 #define SISUSB_IBUF_SIZE  0x01000
 #define SISUSB_OBUF_SIZE  0x10000      /* fixed */
 
-#define NUMOBUFS 8                     /* max number of output buffers/output URBs */
+#define NUMOBUFS 8             /* max number of output buffers/output URBs */
 
 /* About endianness:
  *
@@ -93,7 +91,7 @@
  */
 
 #ifdef __BIG_ENDIAN
-#define SISUSB_CORRECT_ENDIANNESS_PACKET(p)            \
+#define SISUSB_CORRECT_ENDIANNESS_PACKET(p)            \
        do {                                            \
                p->header  = cpu_to_le16(p->header);    \
                p->address = cpu_to_le32(p->address);   \
 
 struct sisusb_usb_data;
 
-struct sisusb_urb_context {            /* urb->context for outbound bulk URBs */
+struct sisusb_urb_context {    /* urb->context for outbound bulk URBs */
        struct sisusb_usb_data *sisusb;
        int urbindex;
        int *actual_length;
@@ -116,16 +114,16 @@ struct sisusb_usb_data {
        struct usb_interface *interface;
        struct kref kref;
        wait_queue_head_t wait_q;       /* for syncind and timeouts */
-       struct mutex lock;              /* general race avoidance */
-       unsigned int ifnum;             /* interface number of the USB device */
-       int minor;                      /* minor (for logging clarity) */
-       int isopen;                     /* !=0 if open */
-       int present;                    /* !=0 if device is present on the bus */
-       int ready;                      /* !=0 if device is ready for userland */
+       struct mutex lock;      /* general race avoidance */
+       unsigned int ifnum;     /* interface number of the USB device */
+       int minor;              /* minor (for logging clarity) */
+       int isopen;             /* !=0 if open */
+       int present;            /* !=0 if device is present on the bus */
+       int ready;              /* !=0 if device is ready for userland */
 #ifdef SISUSB_OLD_CONFIG_COMPAT
        int ioctl32registered;
 #endif
-       int numobufs;                   /* number of obufs = number of out urbs */
+       int numobufs;           /* number of obufs = number of out urbs */
        char *obuf[NUMOBUFS], *ibuf;    /* transfer buffers */
        int obufsize, ibufsize;
        dma_addr_t transfer_dma_out[NUMOBUFS];
@@ -136,13 +134,13 @@ struct sisusb_usb_data {
        unsigned char completein;
        struct sisusb_urb_context urbout_context[NUMOBUFS];
        unsigned long flagb0;
-       unsigned long vrambase;         /* framebuffer base */
-       unsigned int vramsize;          /* framebuffer size (bytes) */
+       unsigned long vrambase; /* framebuffer base */
+       unsigned int vramsize;  /* framebuffer size (bytes) */
        unsigned long mmiobase;
        unsigned int mmiosize;
        unsigned long ioportbase;
-       unsigned char devinit;          /* device initialized? */
-       unsigned char gfxinit;          /* graphics core initialized? */
+       unsigned char devinit;  /* device initialized? */
+       unsigned char gfxinit;  /* graphics core initialized? */
        unsigned short chipid, chipvendor;
        unsigned short chiprevision;
 #ifdef INCL_SISUSB_CON
@@ -152,7 +150,7 @@ struct sisusb_usb_data {
        int haveconsole, con_first, con_last;
        int havethisconsole[MAX_NR_CONSOLES];
        int textmodedestroyed;
-       unsigned int sisusb_num_columns; /* real number, not vt's idea */
+       unsigned int sisusb_num_columns;        /* real number, not vt's idea */
        int cur_start_addr, con_rolled_over;
        int sisusb_cursor_loc, bad_cursor_pos;
        int sisusb_cursor_size_from;
@@ -197,7 +195,7 @@ struct sisusb_packet {
        unsigned short header;
        u32 address;
        u32 data;
-} __attribute__((__packed__));
+} __attribute__ ((__packed__));
 
 #define CLEARPACKET(packet) memset(packet, 0, 10)
 
@@ -265,36 +263,36 @@ struct sisusb_packet {
 
 /* Structure argument for SISUSB_GET_INFO ioctl  */
 struct sisusb_info {
-       __u32   sisusb_id;              /* for identifying sisusb */
-#define SISUSB_ID  0x53495355          /* Identify myself with 'SISU' */
-       __u8    sisusb_version;
-       __u8    sisusb_revision;
-       __u8    sisusb_patchlevel;
-       __u8    sisusb_gfxinit;         /* graphics core initialized? */
+       __u32 sisusb_id;        /* for identifying sisusb */
+#define SISUSB_ID  0x53495355  /* Identify myself with 'SISU' */
+       __u8 sisusb_version;
+       __u8 sisusb_revision;
+       __u8 sisusb_patchlevel;
+       __u8 sisusb_gfxinit;    /* graphics core initialized? */
 
-       __u32   sisusb_vrambase;
-       __u32   sisusb_mmiobase;
-       __u32   sisusb_iobase;
-       __u32   sisusb_pcibase;
+       __u32 sisusb_vrambase;
+       __u32 sisusb_mmiobase;
+       __u32 sisusb_iobase;
+       __u32 sisusb_pcibase;
 
-       __u32   sisusb_vramsize;        /* framebuffer size in bytes */
+       __u32 sisusb_vramsize;  /* framebuffer size in bytes */
 
-       __u32   sisusb_minor;
+       __u32 sisusb_minor;
 
-       __u32   sisusb_fbdevactive;     /* != 0 if framebuffer device active */
+       __u32 sisusb_fbdevactive;       /* != 0 if framebuffer device active */
 
-       __u32   sisusb_conactive;       /* != 0 if console driver active */
+       __u32 sisusb_conactive; /* != 0 if console driver active */
 
-       __u8    sisusb_reserved[28];    /* for future use */
+       __u8 sisusb_reserved[28];       /* for future use */
 };
 
 struct sisusb_command {
-       __u8   operation;       /* see below */
-       __u8   data0;           /* operation dependent */
-       __u8   data1;           /* operation dependent */
-       __u8   data2;           /* operation dependent */
-       __u32  data3;           /* operation dependent */
-       __u32  data4;           /* for future use */
+       __u8 operation;         /* see below */
+       __u8 data0;             /* operation dependent */
+       __u8 data1;             /* operation dependent */
+       __u8 data2;             /* operation dependent */
+       __u32 data3;            /* operation dependent */
+       __u32 data4;            /* for future use */
 };
 
 #define SUCMD_GET      0x01    /* for all: data0 = index, data3 = port */
@@ -306,7 +304,7 @@ struct sisusb_command {
 
 #define SUCMD_CLRSCR   0x07    /* data0:1:2 = length, data3 = address */
 
-#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */
+#define SUCMD_HANDLETEXTMODE 0x08      /* Reset/destroy text mode */
 
 #define SUCMD_SETMODE  0x09    /* Set a display mode (data3 = SiS mode) */
 #define SUCMD_SETVESAMODE 0x0a /* Set a display mode (data3 = VESA mode) */
@@ -315,6 +313,4 @@ struct sisusb_command {
 #define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32)
 #define SISUSB_GET_CONFIG      _IOR(0xF3,0x3F,struct sisusb_info)
 
-
 #endif /* SISUSB_H */
-
index 8d0edc8..43722e5 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/fs.h>
+#include <linux/usb.h>
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/string.h>
@@ -373,14 +374,6 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x)
                return;
 
        /* sisusb->lock is down */
-
-       /* Don't need to put the character into buffer ourselves,
-        * because the vt does this BEFORE calling us.
-        */
-#if 0
-       sisusbcon_writew(ch, SISUSB_VADDR(x, y));
-#endif
-
        if (sisusb_is_inactive(c, sisusb)) {
                mutex_unlock(&sisusb->lock);
                return;
@@ -490,10 +483,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
        struct sisusb_usb_data *sisusb;
        ssize_t written;
        int cols, length;
-#if 0
-       u16 *src, *dest;
-       int i;
-#endif
 
        if (width <= 0 || height <= 0)
                return;
@@ -505,41 +494,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
 
        cols = sisusb->sisusb_num_columns;
 
-       /* Don't need to move data outselves, because
-        * vt does this BEFORE calling us.
-        * This is only used by vt's insert/deletechar.
-        */
-#if 0
-       if (sx == 0 && dx == 0 && width >= c->vc_cols && width <= cols) {
-
-               sisusbcon_memmovew(SISUSB_VADDR(0, dy), SISUSB_VADDR(0, sy),
-                                       height * width * 2);
-
-       } else if (dy < sy || (dy == sy && dx < sx)) {
-
-               src  = SISUSB_VADDR(sx, sy);
-               dest = SISUSB_VADDR(dx, dy);
-
-               for (i = height; i > 0; i--) {
-                       sisusbcon_memmovew(dest, src, width * 2);
-                       src  += cols;
-                       dest += cols;
-               }
-
-       } else {
-
-               src  = SISUSB_VADDR(sx, sy + height - 1);
-               dest = SISUSB_VADDR(dx, dy + height - 1);
-
-               for (i = height; i > 0; i--) {
-                       sisusbcon_memmovew(dest, src, width * 2);
-                       src  -= cols;
-                       dest -= cols;
-               }
-
-       }
-#endif
-
        if (sisusb_is_inactive(c, sisusb)) {
                mutex_unlock(&sisusb->lock);
                return;
@@ -584,7 +538,7 @@ sisusbcon_switch(struct vc_data *c)
         */
        if (c->vc_origin == (unsigned long)c->vc_screenbuf) {
                mutex_unlock(&sisusb->lock);
-               printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n");
+               dev_dbg(&sisusb->sisusb_dev->dev, "ASSERT ORIGIN != SCREENBUF!\n");
                return 0;
        }
 
@@ -1475,7 +1429,7 @@ static const struct consw sisusb_dummy_con = {
 int
 sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
 {
-       int i, ret, minor = sisusb->minor;
+       int i, ret;
 
        mutex_lock(&sisusb->lock);
 
@@ -1508,9 +1462,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
        /* Set up text mode (and upload  default font) */
        if (sisusb_reset_text_mode(sisusb, 1)) {
                mutex_unlock(&sisusb->lock);
-               printk(KERN_ERR
-                       "sisusbvga[%d]: Failed to set up text mode\n",
-                       minor);
+               dev_err(&sisusb->sisusb_dev->dev, "Failed to set up text mode\n");
                return 1;
        }
 
@@ -1531,9 +1483,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
        /* Allocate screen buffer */
        if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
                mutex_unlock(&sisusb->lock);
-               printk(KERN_ERR
-                       "sisusbvga[%d]: Failed to allocate screen buffer\n",
-                       minor);
+               dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate screen buffer\n");
                return 1;
        }
 
index 9b30f89..273de5d 100644 (file)
@@ -32,7 +32,7 @@
  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Author:     Thomas Winischhofer <thomas@winischhofer.net>
+ * Author:     Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
 /*         POINTER INITIALIZATION            */
 /*********************************************/
 
-static void
-SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
+static void SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
 {
-       SiS_Pr->SiS_ModeResInfo   = SiSUSB_ModeResInfo;
-       SiS_Pr->SiS_StandTable    = SiSUSB_StandTable;
-
-       SiS_Pr->SiS_SModeIDTable  = SiSUSB_SModeIDTable;
-       SiS_Pr->SiS_EModeIDTable  = SiSUSB_EModeIDTable;
-       SiS_Pr->SiS_RefIndex      = SiSUSB_RefIndex;
-       SiS_Pr->SiS_CRT1Table     = SiSUSB_CRT1Table;
-
-       SiS_Pr->SiS_VCLKData      = SiSUSB_VCLKData;
-}
-
-/*********************************************/
-/*            HELPER: Get ModeID             */
-/*********************************************/
+       SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo;
+       SiS_Pr->SiS_StandTable = SiSUSB_StandTable;
 
-#if 0
-unsigned short
-SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
-{
-       unsigned short ModeIndex = 0;
-
-       switch (HDisplay)
-       {
-               case 320:
-                       if (VDisplay == 200)
-                               ModeIndex = ModeIndex_320x200[Depth];
-                       else if (VDisplay == 240)
-                               ModeIndex = ModeIndex_320x240[Depth];
-                       break;
-               case 400:
-                       if (VDisplay == 300)
-                               ModeIndex = ModeIndex_400x300[Depth];
-                       break;
-               case 512:
-                       if (VDisplay == 384)
-                               ModeIndex = ModeIndex_512x384[Depth];
-                       break;
-               case 640:
-                       if (VDisplay == 480)
-                               ModeIndex = ModeIndex_640x480[Depth];
-                       else if (VDisplay == 400)
-                               ModeIndex = ModeIndex_640x400[Depth];
-                       break;
-               case 720:
-                       if (VDisplay == 480)
-                               ModeIndex = ModeIndex_720x480[Depth];
-                       else if (VDisplay == 576)
-                               ModeIndex = ModeIndex_720x576[Depth];
-                       break;
-               case 768:
-                       if (VDisplay == 576)
-                               ModeIndex = ModeIndex_768x576[Depth];
-                       break;
-               case 800:
-                       if (VDisplay == 600)
-                               ModeIndex = ModeIndex_800x600[Depth];
-                       else if (VDisplay == 480)
-                               ModeIndex = ModeIndex_800x480[Depth];
-                       break;
-               case 848:
-                       if (VDisplay == 480)
-                               ModeIndex = ModeIndex_848x480[Depth];
-                       break;
-               case 856:
-                       if (VDisplay == 480)
-                               ModeIndex = ModeIndex_856x480[Depth];
-                       break;
-               case 960:
-                       if (VDisplay == 540)
-                               ModeIndex = ModeIndex_960x540[Depth];
-                       else if (VDisplay == 600)
-                               ModeIndex = ModeIndex_960x600[Depth];
-                       break;
-               case 1024:
-                       if (VDisplay == 576)
-                               ModeIndex = ModeIndex_1024x576[Depth];
-                       else if (VDisplay == 768)
-                               ModeIndex = ModeIndex_1024x768[Depth];
-                       break;
-               case 1152:
-                       if (VDisplay == 864)
-                               ModeIndex = ModeIndex_1152x864[Depth];
-                       break;
-               case 1280:
-                       switch (VDisplay) {
-                               case 720:
-                                       ModeIndex = ModeIndex_1280x720[Depth];
-                                       break;
-                               case 768:
-                                       ModeIndex = ModeIndex_1280x768[Depth];
-                                       break;
-                               case 1024:
-                                       ModeIndex = ModeIndex_1280x1024[Depth];
-                                       break;
-                       }
-       }
+       SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable;
+       SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable;
+       SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex;
+       SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table;
 
-       return ModeIndex;
+       SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData;
 }
-#endif  /*  0  */
 
 /*********************************************/
 /*          HELPER: SetReg, GetReg           */
@@ -165,21 +74,20 @@ SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
 
 static void
 SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port,
-                       unsigned short index, unsigned short data)
+          unsigned short index, unsigned short data)
 {
        sisusb_setidxreg(SiS_Pr->sisusb, port, index, data);
 }
 
 static void
 SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port,
-                                               unsigned short data)
+              unsigned short data)
 {
        sisusb_setreg(SiS_Pr->sisusb, port, data);
 }
 
 static unsigned char
-SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port,
-                                               unsigned short index)
+SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, unsigned short index)
 {
        u8 data;
 
@@ -200,22 +108,22 @@ SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port)
 
 static void
 SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port,
-                       unsigned short index, unsigned short DataAND,
-                                               unsigned short DataOR)
+               unsigned short index, unsigned short DataAND,
+               unsigned short DataOR)
 {
        sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR);
 }
 
 static void
 SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port,
-                       unsigned short index, unsigned short DataAND)
+             unsigned short index, unsigned short DataAND)
 {
        sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND);
 }
 
 static void
-SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port,
-                       unsigned short index, unsigned short DataOR)
+SiS_SetRegOR(struct SiS_Private *SiS_Pr, unsigned long port,
+            unsigned short index, unsigned short DataOR)
 {
        sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR);
 }
@@ -224,8 +132,7 @@ SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port,
 /*      HELPER: DisplayOn, DisplayOff        */
 /*********************************************/
 
-static void
-SiS_DisplayOn(struct SiS_Private *SiS_Pr)
+static void SiS_DisplayOn(struct SiS_Private *SiS_Pr)
 {
        SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF);
 }
@@ -234,8 +141,7 @@ SiS_DisplayOn(struct SiS_Private *SiS_Pr)
 /*        HELPER: Init Port Addresses        */
 /*********************************************/
 
-static void
-SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
+static void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
 {
        SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
        SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
@@ -258,8 +164,7 @@ SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
 /*             HELPER: GetSysFlags           */
 /*********************************************/
 
-static void
-SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
+static void SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
 {
        SiS_Pr->SiS_MyCR63 = 0x63;
 }
@@ -268,8 +173,7 @@ SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
 /*         HELPER: Init PCI & Engines        */
 /*********************************************/
 
-static void
-SiSInitPCIetc(struct SiS_Private *SiS_Pr)
+static void SiSInitPCIetc(struct SiS_Private *SiS_Pr)
 {
        SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1);
        /*  - Enable 2D (0x40)
@@ -285,8 +189,7 @@ SiSInitPCIetc(struct SiS_Private *SiS_Pr)
 /*        HELPER: SET SEGMENT REGISTERS      */
 /*********************************************/
 
-static void
-SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
 {
        unsigned short temp;
 
@@ -299,8 +202,7 @@ SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
        SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
 }
 
-static void
-SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
 {
        unsigned short temp;
 
@@ -313,15 +215,13 @@ SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
        SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
 }
 
-static void
-SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
 {
        SiS_SetSegRegLower(SiS_Pr, value);
        SiS_SetSegRegUpper(SiS_Pr, value);
 }
 
-static void
-SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
 {
        SiS_SetSegmentReg(SiS_Pr, 0);
 }
@@ -337,14 +237,12 @@ SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value)
        SiS_SetSegmentReg(SiS_Pr, value);
 }
 
-static void
-SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
 {
        SiS_SetSegmentRegOver(SiS_Pr, 0);
 }
 
-static void
-SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
 {
        SiS_ResetSegmentReg(SiS_Pr);
        SiS_ResetSegmentRegOver(SiS_Pr);
@@ -356,7 +254,7 @@ SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
 
 static int
 SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
-                                               unsigned short *ModeIdIndex)
+                unsigned short *ModeIdIndex)
 {
        if ((*ModeNo) <= 0x13) {
 
@@ -367,12 +265,14 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
 
        } else {
 
-               for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) {
+               for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
 
-                       if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo))
+                       if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
+                           (*ModeNo))
                                break;
 
-                       if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)
+                       if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
+                           0xFF)
                                return 0;
                }
 
@@ -385,8 +285,7 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
 /*            HELPER: ENABLE CRT1            */
 /*********************************************/
 
-static void
-SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
+static void SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
 {
        /* Enable CRT1 gating */
        SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf);
@@ -398,9 +297,9 @@ SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
 
 static unsigned short
 SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-               unsigned short ModeIdIndex)
+                 unsigned short ModeIdIndex)
 {
-       static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8};
+       static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 };
        unsigned short modeflag;
        short index;
 
@@ -411,7 +310,8 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
        }
 
        index = (modeflag & ModeTypeMask) - ModeEGA;
-       if (index < 0) index = 0;
+       if (index < 0)
+               index = 0;
        return ColorDepth[index];
 }
 
@@ -421,7 +321,7 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static unsigned short
 SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-               unsigned short ModeIdIndex, unsigned short rrti)
+             unsigned short ModeIdIndex, unsigned short rrti)
 {
        unsigned short xres, temp, colordepth, infoflag;
 
@@ -458,8 +358,8 @@ SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
        SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20;
        SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata);
 
-       for(i = 2; i <= 4; i++) {
-               SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1];
+       for (i = 2; i <= 4; i++) {
+               SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1];
                SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata);
        }
 }
@@ -488,7 +388,7 @@ SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
 
        SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
 
-       for(i = 0; i <= 0x18; i++) {
+       for (i = 0; i <= 0x18; i++) {
                CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
                SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata);
        }
@@ -504,7 +404,7 @@ SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
        unsigned char ARdata;
        unsigned short i;
 
-       for(i = 0; i <= 0x13; i++) {
+       for (i = 0; i <= 0x13; i++) {
                ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
                SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
                SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i);
@@ -529,7 +429,7 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
        unsigned char GRdata;
        unsigned short i;
 
-       for(i = 0; i <= 0x08; i++) {
+       for (i = 0; i <= 0x08; i++) {
                GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
                SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata);
        }
@@ -544,12 +444,11 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
 /*          CLEAR EXTENDED REGISTERS         */
 /*********************************************/
 
-static void
-SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+static void SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
 {
        int i;
 
-       for(i = 0x0A; i <= 0x0E; i++) {
+       for (i = 0x0A; i <= 0x0E; i++) {
                SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00);
        }
 
@@ -562,15 +461,16 @@ SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
 
 static unsigned short
 SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-                                       unsigned short ModeIdIndex)
+              unsigned short ModeIdIndex)
 {
        unsigned short rrti, i, index, temp;
 
        if (ModeNo <= 0x13)
                return 0xFFFF;
 
-       index = SiS_GetReg(SiS_Pr,SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
-       if (index > 0) index--;
+       index = SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
+       if (index > 0)
+               index--;
 
        rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
        ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID;
@@ -580,13 +480,14 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
                if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo)
                        break;
 
-               temp = SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
+               temp =
+                   SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
                if (temp < SiS_Pr->SiS_ModeType)
                        break;
 
                i++;
                index--;
-       } while(index != 0xFFFF);
+       } while (index != 0xFFFF);
 
        i--;
 
@@ -597,8 +498,7 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 /*                  SYNC                     */
 /*********************************************/
 
-static void
-SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
+static void SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
 {
        unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8;
        sync &= 0xC0;
@@ -612,39 +512,40 @@ SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
 
 static void
 SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-                       unsigned short ModeIdIndex, unsigned short rrti)
+               unsigned short ModeIdIndex, unsigned short rrti)
 {
-       unsigned char  index;
+       unsigned char index;
        unsigned short temp, i, j, modeflag;
 
-       SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4,0x11,0x7f);
+       SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
 
        modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
        index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC;
 
-       for(i = 0,j = 0; i <= 7; i++, j++) {
+       for (i = 0, j = 0; i <= 7; i++, j++) {
                SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
-                               SiS_Pr->SiS_CRT1Table[index].CR[i]);
+                          SiS_Pr->SiS_CRT1Table[index].CR[i]);
        }
-       for(j = 0x10; i <= 10; i++, j++) {
+       for (j = 0x10; i <= 10; i++, j++) {
                SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
-                               SiS_Pr->SiS_CRT1Table[index].CR[i]);
+                          SiS_Pr->SiS_CRT1Table[index].CR[i]);
        }
-       for(j = 0x15; i <= 12; i++, j++) {
+       for (j = 0x15; i <= 12; i++, j++) {
                SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
-                               SiS_Pr->SiS_CRT1Table[index].CR[i]);
+                          SiS_Pr->SiS_CRT1Table[index].CR[i]);
        }
-       for(j = 0x0A; i <= 15; i++, j++) {
+       for (j = 0x0A; i <= 15; i++, j++) {
                SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j,
-                               SiS_Pr->SiS_CRT1Table[index].CR[i]);
+                          SiS_Pr->SiS_CRT1Table[index].CR[i]);
        }
 
        temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0;
-       SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4, 0x0E, temp);
+       SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, temp);
 
        temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5;
-       if (modeflag & DoubleScanMode)  temp |= 0x80;
+       if (modeflag & DoubleScanMode)
+               temp |= 0x80;
        SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp);
 
        if (SiS_Pr->SiS_ModeType > ModeVGA)
@@ -659,10 +560,10 @@ SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static void
 SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-                       unsigned short ModeIdIndex, unsigned short rrti)
+                 unsigned short ModeIdIndex, unsigned short rrti)
 {
        unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti);
-       unsigned short infoflag =  SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
+       unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
        unsigned short temp;
 
        temp = (du >> 8) & 0x0f;
@@ -670,11 +571,13 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
        SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF));
 
-       if (infoflag & InterlaceMode) du >>= 1;
+       if (infoflag & InterlaceMode)
+               du >>= 1;
 
        du <<= 5;
        temp = (du >> 8) & 0xff;
-       if (du & 0xff) temp++;
+       if (du & 0xff)
+               temp++;
        temp++;
        SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp);
 }
@@ -685,17 +588,17 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static void
 SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-                                               unsigned short rrti)
+               unsigned short rrti)
 {
        unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
        unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B;
        unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C;
 
-       SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4,0x31,0xCF);
+       SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xCF);
 
-       SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2B,clka);
-       SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2C,clkb);
-       SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2D,0x01);
+       SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2B, clka);
+       SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2C, clkb);
+       SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2D, 0x01);
 }
 
 /*********************************************/
@@ -704,7 +607,7 @@ SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static void
 SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-                                                       unsigned short mi)
+                   unsigned short mi)
 {
        unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag;
 
@@ -729,7 +632,7 @@ SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static void
 SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-                                                       unsigned short rrti)
+                unsigned short rrti)
 {
        unsigned short data = 0, VCLK = 0, index = 0;
 
@@ -738,7 +641,8 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
                VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
        }
 
-       if (VCLK >= 166) data |= 0x0c;
+       if (VCLK >= 166)
+               data |= 0x0c;
        SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data);
 
        if (VCLK >= 166)
@@ -758,7 +662,7 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static void
 SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-                       unsigned short ModeIdIndex, unsigned short rrti)
+                   unsigned short ModeIdIndex, unsigned short rrti)
 {
        unsigned short data, infoflag = 0, modeflag;
 
@@ -778,17 +682,22 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
                        data |= 0x02;
                        data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
                }
-               if (infoflag & InterlaceMode) data |= 0x20;
+               if (infoflag & InterlaceMode)
+                       data |= 0x20;
        }
        SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data);
 
        data = 0;
        if (infoflag & InterlaceMode) {
                /* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */
-               unsigned short hrs = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
-                       ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) - 3;
-               unsigned short hto = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
-                       ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + 5;
+               unsigned short hrs =
+                   (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
+                    ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2))
+                   - 3;
+               unsigned short hto =
+                   (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
+                    ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8))
+                   + 5;
                data = hrs - (hto >> 1) + 3;
        }
        SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF));
@@ -829,20 +738,26 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static void
 SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
-               unsigned short shiftflag, unsigned short dl, unsigned short ah,
-               unsigned short al, unsigned short dh)
+            unsigned short shiftflag, unsigned short dl, unsigned short ah,
+            unsigned short al, unsigned short dh)
 {
        unsigned short d1, d2, d3;
 
        switch (dl) {
-               case  0:
-                       d1 = dh; d2 = ah; d3 = al;
-                       break;
-               case  1:
-                       d1 = ah; d2 = al; d3 = dh;
-                       break;
-               default:
-                       d1 = al; d2 = dh; d3 = ah;
+       case 0:
+               d1 = dh;
+               d2 = ah;
+               d3 = al;
+               break;
+       case 1:
+               d1 = ah;
+               d2 = al;
+               d3 = dh;
+               break;
+       default:
+               d1 = al;
+               d2 = dh;
+               d3 = ah;
        }
        SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag));
        SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag));
@@ -850,7 +765,8 @@ SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
 }
 
 static void
-SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi)
+SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+           unsigned short mi)
 {
        unsigned short data, data2, time, i, j, k, m, n, o;
        unsigned short si, di, bx, sf;
@@ -884,41 +800,45 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi
 
        SiS_SetRegByte(SiS_Pr, DACAddr, 0x00);
 
-       for(i = 0; i < j; i++) {
+       for (i = 0; i < j; i++) {
                data = table[i];
-               for(k = 0; k < 3; k++) {
+               for (k = 0; k < 3; k++) {
                        data2 = 0;
-                       if (data & 0x01) data2 += 0x2A;
-                       if (data & 0x02) data2 += 0x15;
+                       if (data & 0x01)
+                               data2 += 0x2A;
+                       if (data & 0x02)
+                               data2 += 0x15;
                        SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf));
                        data >>= 2;
                }
        }
 
        if (time == 256) {
-               for(i = 16; i < 32; i++) {
+               for (i = 16; i < 32; i++) {
                        data = table[i] << sf;
-                       for(k = 0; k < 3; k++)
+                       for (k = 0; k < 3; k++)
                                SiS_SetRegByte(SiS_Pr, DACData, data);
                }
                si = 32;
-               for(m = 0; m < 9; m++) {
+               for (m = 0; m < 9; m++) {
                        di = si;
                        bx = si + 4;
-                       for(n = 0; n < 3; n++) {
-                               for(o = 0; o < 5; o++) {
+                       for (n = 0; n < 3; n++) {
+                               for (o = 0; o < 5; o++) {
                                        SiS_WriteDAC(SiS_Pr, DACData, sf, n,
-                                               table[di], table[bx], table[si]);
+                                                    table[di], table[bx],
+                                                    table[si]);
                                        si++;
                                }
                                si -= 2;
-                               for(o = 0; o < 3; o++) {
+                               for (o = 0; o < 3; o++) {
                                        SiS_WriteDAC(SiS_Pr, DACData, sf, n,
-                                               table[di], table[si], table[bx]);
+                                                    table[di], table[si],
+                                                    table[bx]);
                                        si--;
                                }
                        }
-               si += 5;
+                       si += 5;
                }
        }
 }
@@ -929,7 +849,7 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi
 
 static void
 SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-                                       unsigned short ModeIdIndex)
+                unsigned short ModeIdIndex)
 {
        unsigned short StandTableIndex, rrti;
 
@@ -970,11 +890,10 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 /*                 SiSSetMode()              */
 /*********************************************/
 
-int
-SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
 {
        unsigned short ModeIdIndex;
-       unsigned long  BaseAddr = SiS_Pr->IOAddress;
+       unsigned long BaseAddr = SiS_Pr->IOAddress;
 
        SiSUSB_InitPtr(SiS_Pr);
        SiSUSBRegInit(SiS_Pr, BaseAddr);
@@ -990,7 +909,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
        ModeNo &= 0x7f;
 
        SiS_Pr->SiS_ModeType =
-               SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
+           SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
 
        SiS_Pr->SiS_SetFlag = LowModeTests;
 
@@ -1008,8 +927,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
        return 1;
 }
 
-int
-SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
+int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
 {
        unsigned short ModeNo = 0;
        int i;
@@ -1041,7 +959,3 @@ SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
 }
 
 #endif /* INCL_SISUSB_CON */
-
-
-
-
index 864bc0e..c46ce42 100644 (file)
@@ -46,7 +46,7 @@
  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Author:     Thomas Winischhofer <thomas@winischhofer.net>
+ * Author:     Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
 #define CRT2Mode               0x0800
 #define HalfDCLK               0x1000
 #define NoSupportSimuTV                0x2000
-#define NoSupportLCDScale      0x4000 /* SiS bridge: No scaling possible (no matter what panel) */
+#define NoSupportLCDScale      0x4000  /* SiS bridge: No scaling possible (no matter what panel) */
 #define DoubleScanMode         0x8000
 
 /* Infoflag */
 #define SupportTV              0x0008
 #define SupportTV1024          0x0800
-#define SupportCHTV            0x0800
-#define Support64048060Hz      0x0800  /* Special for 640x480 LCD */
+#define SupportCHTV            0x0800
+#define Support64048060Hz      0x0800  /* Special for 640x480 LCD */
 #define SupportHiVision                0x0010
 #define SupportYPbPr750p       0x1000
 #define SupportLCD             0x0020
 #define SupportRAMDAC2         0x0040  /* All           (<= 100Mhz) */
-#define SupportRAMDAC2_135     0x0100  /* All except DH (<= 135Mhz) */
-#define SupportRAMDAC2_162     0x0200  /* B, C          (<= 162Mhz) */
-#define SupportRAMDAC2_202     0x0400  /* C             (<= 202Mhz) */
+#define SupportRAMDAC2_135     0x0100  /* All except DH (<= 135Mhz) */
+#define SupportRAMDAC2_162     0x0200  /* B, C          (<= 162Mhz) */
+#define SupportRAMDAC2_202     0x0400  /* C             (<= 202Mhz) */
 #define InterlaceMode          0x0080
 #define SyncPP                 0x0000
 #define SyncPN                 0x4000
 #define SIS_RI_856x480         19
 #define SIS_RI_1280x768                20
 #define SIS_RI_1400x1050       21
-#define SIS_RI_1152x864                22  /* Up to here SiS conforming */
+#define SIS_RI_1152x864                22      /* Up to here SiS conforming */
 #define SIS_RI_848x480         23
 #define SIS_RI_1360x768                24
 #define SIS_RI_1024x600                25
 #define SIS_CRT2_PORT_04       0x04 - 0x30
 
 /* Mode numbers */
-static const unsigned short ModeIndex_320x200[]   = {0x59, 0x41, 0x00, 0x4f};
-static const unsigned short ModeIndex_320x240[]   = {0x50, 0x56, 0x00, 0x53};
-static const unsigned short ModeIndex_400x300[]   = {0x51, 0x57, 0x00, 0x54};
-static const unsigned short ModeIndex_512x384[]   = {0x52, 0x58, 0x00, 0x5c};
-static const unsigned short ModeIndex_640x400[]   = {0x2f, 0x5d, 0x00, 0x5e};
-static const unsigned short ModeIndex_640x480[]   = {0x2e, 0x44, 0x00, 0x62};
-static const unsigned short ModeIndex_720x480[]   = {0x31, 0x33, 0x00, 0x35};
-static const unsigned short ModeIndex_720x576[]   = {0x32, 0x34, 0x00, 0x36};
-static const unsigned short ModeIndex_768x576[]   = {0x5f, 0x60, 0x00, 0x61};
-static const unsigned short ModeIndex_800x480[]   = {0x70, 0x7a, 0x00, 0x76};
-static const unsigned short ModeIndex_800x600[]   = {0x30, 0x47, 0x00, 0x63};
-static const unsigned short ModeIndex_848x480[]   = {0x39, 0x3b, 0x00, 0x3e};
-static const unsigned short ModeIndex_856x480[]   = {0x3f, 0x42, 0x00, 0x45};
-static const unsigned short ModeIndex_960x540[]   = {0x1d, 0x1e, 0x00, 0x1f};
-static const unsigned short ModeIndex_960x600[]   = {0x20, 0x21, 0x00, 0x22};
-static const unsigned short ModeIndex_1024x768[]  = {0x38, 0x4a, 0x00, 0x64};
-static const unsigned short ModeIndex_1024x576[]  = {0x71, 0x74, 0x00, 0x77};
-static const unsigned short ModeIndex_1152x864[]  = {0x29, 0x2a, 0x00, 0x2b};
-static const unsigned short ModeIndex_1280x720[]  = {0x79, 0x75, 0x00, 0x78};
-static const unsigned short ModeIndex_1280x768[]  = {0x23, 0x24, 0x00, 0x25};
-static const unsigned short ModeIndex_1280x1024[] = {0x3a, 0x4d, 0x00, 0x65};
+static const unsigned short ModeIndex_320x200[] = { 0x59, 0x41, 0x00, 0x4f };
+static const unsigned short ModeIndex_320x240[] = { 0x50, 0x56, 0x00, 0x53 };
+static const unsigned short ModeIndex_400x300[] = { 0x51, 0x57, 0x00, 0x54 };
+static const unsigned short ModeIndex_512x384[] = { 0x52, 0x58, 0x00, 0x5c };
+static const unsigned short ModeIndex_640x400[] = { 0x2f, 0x5d, 0x00, 0x5e };
+static const unsigned short ModeIndex_640x480[] = { 0x2e, 0x44, 0x00, 0x62 };
+static const unsigned short ModeIndex_720x480[] = { 0x31, 0x33, 0x00, 0x35 };
+static const unsigned short ModeIndex_720x576[] = { 0x32, 0x34, 0x00, 0x36 };
+static const unsigned short ModeIndex_768x576[] = { 0x5f, 0x60, 0x00, 0x61 };
+static const unsigned short ModeIndex_800x480[] = { 0x70, 0x7a, 0x00, 0x76 };
+static const unsigned short ModeIndex_800x600[] = { 0x30, 0x47, 0x00, 0x63 };
+static const unsigned short ModeIndex_848x480[] = { 0x39, 0x3b, 0x00, 0x3e };
+static const unsigned short ModeIndex_856x480[] = { 0x3f, 0x42, 0x00, 0x45 };
+static const unsigned short ModeIndex_960x540[] = { 0x1d, 0x1e, 0x00, 0x1f };
+static const unsigned short ModeIndex_960x600[] = { 0x20, 0x21, 0x00, 0x22 };
+static const unsigned short ModeIndex_1024x768[] = { 0x38, 0x4a, 0x00, 0x64 };
+static const unsigned short ModeIndex_1024x576[] = { 0x71, 0x74, 0x00, 0x77 };
+static const unsigned short ModeIndex_1152x864[] = { 0x29, 0x2a, 0x00, 0x2b };
+static const unsigned short ModeIndex_1280x720[] = { 0x79, 0x75, 0x00, 0x78 };
+static const unsigned short ModeIndex_1280x768[] = { 0x23, 0x24, 0x00, 0x25 };
+static const unsigned short ModeIndex_1280x1024[] = { 0x3a, 0x4d, 0x00, 0x65 };
 
-static const unsigned char SiS_MDA_DAC[] =
-{
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-        0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
-        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-        0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F
+static const unsigned char SiS_MDA_DAC[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+       0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F
 };
 
-static const unsigned char SiS_CGA_DAC[] =
-{
-        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+static const unsigned char SiS_CGA_DAC[] = {
+       0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+       0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+       0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+       0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+       0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+       0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+       0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+       0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
 };
 
-static const unsigned char SiS_EGA_DAC[] =
-{
-        0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15,
-        0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35,
-        0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D,
-        0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D,
-        0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17,
-        0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37,
-        0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+static const unsigned char SiS_EGA_DAC[] = {
+       0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15,
+       0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35,
+       0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D,
+       0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D,
+       0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17,
+       0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37,
+       0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F,
+       0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
 };
 
-static const unsigned char SiS_VGA_DAC[] =
-{
-       0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-       0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-       0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18,
-       0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F,
-       0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F,
-       0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00,
-       0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18,
-       0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04,
-       0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10,
-       0x0B,0x0C,0x0D,0x0F,0x10
+static const unsigned char SiS_VGA_DAC[] = {
+       0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+       0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+       0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18,
+       0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F,
+       0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F,
+       0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00,
+       0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18,
+       0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04,
+       0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10,
+       0x0B, 0x0C, 0x0D, 0x0F, 0x10
 };
 
-static const struct SiS_St SiSUSB_SModeIDTable[] =
-{
-       {0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03,0x40},
-       {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
+static const struct SiS_St SiSUSB_SModeIDTable[] = {
+       {0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03, 0x40},
+       {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
 };
 
-static const struct SiS_StResInfo_S SiSUSB_StResInfo[] =
-{
-       { 640,400},
-       { 640,350},
-       { 720,400},
-       { 720,350},
-       { 640,480}
+static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = {
+       {640, 400},
+       {640, 350},
+       {720, 400},
+       {720, 350},
+       {640, 480}
 };
 
-static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] =
-{
-       {  320, 200, 8, 8},   /* 0x00 */
-       {  320, 240, 8, 8},   /* 0x01 */
-       {  320, 400, 8, 8},   /* 0x02 */
-       {  400, 300, 8, 8},   /* 0x03 */
-       {  512, 384, 8, 8},   /* 0x04 */
-       {  640, 400, 8,16},   /* 0x05 */
-       {  640, 480, 8,16},   /* 0x06 */
-       {  800, 600, 8,16},   /* 0x07 */
-       { 1024, 768, 8,16},   /* 0x08 */
-       { 1280,1024, 8,16},   /* 0x09 */
-       { 1600,1200, 8,16},   /* 0x0a */
-       { 1920,1440, 8,16},   /* 0x0b */
-       { 2048,1536, 8,16},   /* 0x0c */
-       {  720, 480, 8,16},   /* 0x0d */
-       {  720, 576, 8,16},   /* 0x0e */
-       { 1280, 960, 8,16},   /* 0x0f */
-       {  800, 480, 8,16},   /* 0x10 */
-       { 1024, 576, 8,16},   /* 0x11 */
-       { 1280, 720, 8,16},   /* 0x12 */
-       {  856, 480, 8,16},   /* 0x13 */
-       { 1280, 768, 8,16},   /* 0x14 */
-       { 1400,1050, 8,16},   /* 0x15 */
-       { 1152, 864, 8,16},   /* 0x16 */
-       {  848, 480, 8,16},   /* 0x17 */
-       { 1360, 768, 8,16},   /* 0x18 */
-       { 1024, 600, 8,16},   /* 0x19 */
-       { 1152, 768, 8,16},   /* 0x1a */
-       {  768, 576, 8,16},   /* 0x1b */
-       { 1360,1024, 8,16},   /* 0x1c */
-       { 1680,1050, 8,16},   /* 0x1d */
-       { 1280, 800, 8,16},   /* 0x1e */
-       { 1920,1080, 8,16},   /* 0x1f */
-       {  960, 540, 8,16},   /* 0x20 */
-       {  960, 600, 8,16}    /* 0x21 */
+static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = {
+       {320, 200, 8, 8},       /* 0x00 */
+       {320, 240, 8, 8},       /* 0x01 */
+       {320, 400, 8, 8},       /* 0x02 */
+       {400, 300, 8, 8},       /* 0x03 */
+       {512, 384, 8, 8},       /* 0x04 */
+       {640, 400, 8, 16},      /* 0x05 */
+       {640, 480, 8, 16},      /* 0x06 */
+       {800, 600, 8, 16},      /* 0x07 */
+       {1024, 768, 8, 16},     /* 0x08 */
+       {1280, 1024, 8, 16},    /* 0x09 */
+       {1600, 1200, 8, 16},    /* 0x0a */
+       {1920, 1440, 8, 16},    /* 0x0b */
+       {2048, 1536, 8, 16},    /* 0x0c */
+       {720, 480, 8, 16},      /* 0x0d */
+       {720, 576, 8, 16},      /* 0x0e */
+       {1280, 960, 8, 16},     /* 0x0f */
+       {800, 480, 8, 16},      /* 0x10 */
+       {1024, 576, 8, 16},     /* 0x11 */
+       {1280, 720, 8, 16},     /* 0x12 */
+       {856, 480, 8, 16},      /* 0x13 */
+       {1280, 768, 8, 16},     /* 0x14 */
+       {1400, 1050, 8, 16},    /* 0x15 */
+       {1152, 864, 8, 16},     /* 0x16 */
+       {848, 480, 8, 16},      /* 0x17 */
+       {1360, 768, 8, 16},     /* 0x18 */
+       {1024, 600, 8, 16},     /* 0x19 */
+       {1152, 768, 8, 16},     /* 0x1a */
+       {768, 576, 8, 16},      /* 0x1b */
+       {1360, 1024, 8, 16},    /* 0x1c */
+       {1680, 1050, 8, 16},    /* 0x1d */
+       {1280, 800, 8, 16},     /* 0x1e */
+       {1920, 1080, 8, 16},    /* 0x1f */
+       {960, 540, 8, 16},      /* 0x20 */
+       {960, 600, 8, 16}       /* 0x21 */
 };
 
-static const struct SiS_StandTable SiSUSB_StandTable[] =
-{
+static const struct SiS_StandTable SiSUSB_StandTable[] = {
        /* MD_3_400 - mode 0x03 - 400 */
        {
-               0x50,0x18,0x10,0x1000,
-               { 0x00,0x03,0x00,0x02 },
-               0x67,
-               { 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-                 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
-                 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
-                 0xff },
-               { 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-                 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-                 0x0c,0x00,0x0f,0x08 },
-               { 0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, 0xff }
-       },
+        0x50, 0x18, 0x10, 0x1000,
+        {0x00, 0x03, 0x00, 0x02},
+        0x67,
+        {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+         0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+         0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
+         0xff},
+        {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+         0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+         0x0c, 0x00, 0x0f, 0x08},
+        {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff}
+        },
        /* Generic for VGA and higher */
        {
-               0x00,0x00,0x00,0x0000,
-               { 0x01,0x0f,0x00,0x0e },
-               0x23,
-               { 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
-                 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
-                 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
-                 0xff },
-               { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-                 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
-                 0x01,0x00,0x00,0x00 },
-               { 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, 0xff }
-       }
+        0x00, 0x00, 0x00, 0x0000,
+        {0x01, 0x0f, 0x00, 0x0e},
+        0x23,
+        {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+         0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3,
+         0xff},
+        {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+         0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+         0x01, 0x00, 0x00, 0x00},
+        {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff}
+        }
 };
 
-static const struct SiS_Ext SiSUSB_EModeIDTable[] =
-{
-       {0x2e,0x0a1b,0x0101,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */
-       {0x2f,0x0a1b,0x0100,SIS_RI_640x400,  0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */
-       {0x30,0x2a1b,0x0103,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */
-       {0x31,0x4a1b,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */
-       {0x32,0x4a1b,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */
-       {0x33,0x4a1d,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */
-       {0x34,0x6a1d,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */
-       {0x35,0x4a1f,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x32 */
-       {0x36,0x6a1f,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x32 */
-       {0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x8 */
-       {0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x8 */
-       {0x41,0x9a1d,0x010e,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x16 */
-       {0x44,0x0a1d,0x0111,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x16 */
-       {0x47,0x2a1d,0x0114,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x16 */
-       {0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x16 */
-       {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x16 */
-       {0x50,0x9a1b,0x0132,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x8  */
-       {0x51,0xba1b,0x0133,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x8  */
-       {0x52,0xba1b,0x0134,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x8  */
-       {0x56,0x9a1d,0x0135,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x16 */
-       {0x57,0xba1d,0x0136,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x16 */
-       {0x58,0xba1d,0x0137,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x16 */
-       {0x59,0x9a1b,0x0138,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x8  */
-       {0x5c,0xba1f,0x0000,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x32 */
-       {0x5d,0x0a1d,0x0139,SIS_RI_640x400,  0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x16 */
-       {0x5e,0x0a1f,0x0000,SIS_RI_640x400,  0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x32 */
-       {0x62,0x0a3f,0x013a,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x32 */
-       {0x63,0x2a3f,0x013b,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x32 */
-       {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x32 */
-       {0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x32 */
-       {0x70,0x6a1b,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x8 */
-       {0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x8 */
-       {0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x16 */
-       {0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x16 */
-       {0x76,0x6a1f,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x32 */
-       {0x77,0x4a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x32 */
-       {0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x32 */
-       {0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x8 */
-       {0x7a,0x6a1d,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x16 */
-       {0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x8 */
-       {0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x16 */
-       {0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x32 */
-       {0x39,0x6a1b,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x28,-1}, /* 848x480 */
-       {0x3b,0x6a3d,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x28,-1},
-       {0x3e,0x6a7f,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x28,-1},
-       {0x3f,0x6a1b,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x2a,-1}, /* 856x480 */
-       {0x42,0x6a3d,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x2a,-1},
-       {0x45,0x6a7f,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x2a,-1},
-       {0x4f,0x9a1f,0x0000,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x32 */
-       {0x53,0x9a1f,0x0000,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x32 */
-       {0x54,0xba1f,0x0000,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x32 */
-       {0x5f,0x6a1b,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x2c,-1}, /* 768x576 */
-       {0x60,0x6a1d,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x2c,-1},
-       {0x61,0x6a3f,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x2c,-1},
-       {0x1d,0x6a1b,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x2d,-1}, /* 960x540 */
-       {0x1e,0x6a3d,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x2d,-1},
-       {0x1f,0x6a7f,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x2d,-1},
-       {0x20,0x6a1b,0x0000,SIS_RI_960x600,  0x00,0x00,0x00,0x00,0x2e,-1}, /* 960x600 */
-       {0x21,0x6a3d,0x0000,SIS_RI_960x600,  0x00,0x00,0x00,0x00,0x2e,-1},
-       {0x22,0x6a7f,0x0000,SIS_RI_960x600,  0x00,0x00,0x00,0x00,0x2e,-1},
-       {0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1152x864 */
-       {0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1},
-       {0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1},
-       {0xff,0x0000,0x0000,0,               0x00,0x00,0x00,0x00,0x00,-1}
+static const struct SiS_Ext SiSUSB_EModeIDTable[] = {
+       {0x2e, 0x0a1b, 0x0101, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2},        /* 640x480x8 */
+       {0x2f, 0x0a1b, 0x0100, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x05, 0x10, 0},        /* 640x400x8 */
+       {0x30, 0x2a1b, 0x0103, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3},        /* 800x600x8 */
+       {0x31, 0x4a1b, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1},       /* 720x480x8 */
+       {0x32, 0x4a1b, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1},       /* 720x576x8 */
+       {0x33, 0x4a1d, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1},       /* 720x480x16 */
+       {0x34, 0x6a1d, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1},       /* 720x576x16 */
+       {0x35, 0x4a1f, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1},       /* 720x480x32 */
+       {0x36, 0x6a1f, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1},       /* 720x576x32 */
+       {0x38, 0x0a1b, 0x0105, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4},       /* 1024x768x8 */
+       {0x3a, 0x0e3b, 0x0107, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8},      /* 1280x1024x8 */
+       {0x41, 0x9a1d, 0x010e, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0},        /* 320x200x16 */
+       {0x44, 0x0a1d, 0x0111, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2},        /* 640x480x16 */
+       {0x47, 0x2a1d, 0x0114, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3},        /* 800x600x16 */
+       {0x4a, 0x0a3d, 0x0117, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4},       /* 1024x768x16 */
+       {0x4d, 0x0e7d, 0x011a, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8},      /* 1280x1024x16 */
+       {0x50, 0x9a1b, 0x0132, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2},        /* 320x240x8  */
+       {0x51, 0xba1b, 0x0133, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3},        /* 400x300x8  */
+       {0x52, 0xba1b, 0x0134, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4},        /* 512x384x8  */
+       {0x56, 0x9a1d, 0x0135, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2},        /* 320x240x16 */
+       {0x57, 0xba1d, 0x0136, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3},        /* 400x300x16 */
+       {0x58, 0xba1d, 0x0137, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4},        /* 512x384x16 */
+       {0x59, 0x9a1b, 0x0138, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0},        /* 320x200x8  */
+       {0x5c, 0xba1f, 0x0000, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4},        /* 512x384x32 */
+       {0x5d, 0x0a1d, 0x0139, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0},        /* 640x400x16 */
+       {0x5e, 0x0a1f, 0x0000, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0},        /* 640x400x32 */
+       {0x62, 0x0a3f, 0x013a, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2},        /* 640x480x32 */
+       {0x63, 0x2a3f, 0x013b, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3},        /* 800x600x32 */
+       {0x64, 0x0a7f, 0x013c, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4},       /* 1024x768x32 */
+       {0x65, 0x0eff, 0x013d, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8},      /* 1280x1024x32 */
+       {0x70, 0x6a1b, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1},       /* 800x480x8 */
+       {0x71, 0x4a1b, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1},      /* 1024x576x8 */
+       {0x74, 0x4a1d, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1},      /* 1024x576x16 */
+       {0x75, 0x0a3d, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5},       /* 1280x720x16 */
+       {0x76, 0x6a1f, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1},       /* 800x480x32 */
+       {0x77, 0x4a1f, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1},      /* 1024x576x32 */
+       {0x78, 0x0a3f, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5},       /* 1280x720x32 */
+       {0x79, 0x0a3b, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5},       /* 1280x720x8 */
+       {0x7a, 0x6a1d, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1},       /* 800x480x16 */
+       {0x23, 0x0e3b, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6},       /* 1280x768x8 */
+       {0x24, 0x0e7d, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6},       /* 1280x768x16 */
+       {0x25, 0x0eff, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6},       /* 1280x768x32 */
+       {0x39, 0x6a1b, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, -1},       /* 848x480 */
+       {0x3b, 0x6a3d, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28,
+        -1},
+       {0x3e, 0x6a7f, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28,
+        -1},
+       {0x3f, 0x6a1b, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, -1},       /* 856x480 */
+       {0x42, 0x6a3d, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a,
+        -1},
+       {0x45, 0x6a7f, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a,
+        -1},
+       {0x4f, 0x9a1f, 0x0000, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0},        /* 320x200x32 */
+       {0x53, 0x9a1f, 0x0000, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2},        /* 320x240x32 */
+       {0x54, 0xba1f, 0x0000, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3},        /* 400x300x32 */
+       {0x5f, 0x6a1b, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, -1},       /* 768x576 */
+       {0x60, 0x6a1d, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c,
+        -1},
+       {0x61, 0x6a3f, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c,
+        -1},
+       {0x1d, 0x6a1b, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, -1},       /* 960x540 */
+       {0x1e, 0x6a3d, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d,
+        -1},
+       {0x1f, 0x6a7f, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d,
+        -1},
+       {0x20, 0x6a1b, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, -1},       /* 960x600 */
+       {0x21, 0x6a3d, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e,
+        -1},
+       {0x22, 0x6a7f, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e,
+        -1},
+       {0x29, 0x4e1b, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, -1},      /* 1152x864 */
+       {0x2a, 0x4e3d, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33,
+        -1},
+       {0x2b, 0x4e7f, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33,
+        -1},
+       {0xff, 0x0000, 0x0000, 0, 0x00, 0x00, 0x00, 0x00, 0x00, -1}
 };
 
-static const struct SiS_Ext2 SiSUSB_RefIndex[] =
-{
-       {0x085f,0x0d,0x03,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */
-       {0x0067,0x0e,0x04,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */
-       {0x0067,0x0f,0x08,0x48,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */
-       {0x0067,0x10,0x07,0x8b,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */
-       {0x0047,0x11,0x0a,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */
-       {0x0047,0x12,0x0d,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */
-       {0x0047,0x13,0x13,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */
-       {0x0107,0x14,0x1c,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */
-       {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */
-       {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */
-       {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */
-       {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */
-       {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */
-       {0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */
-       {0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */
-       {0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */
-       {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */
-       {0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */
-       {0x006f,0x3d,0x6f,0x06,0x14,0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */
-       {0x0087,0x15,0x06,0x00,0x06,0x38,1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */
-       {0xc877,0x16,0x0b,0x06,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */
-       {0xc067,0x17,0x0f,0x49,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */
-       {0x0067,0x18,0x11,0x00,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */
-       {0x0047,0x19,0x16,0x8c,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */
-       {0x0107,0x1a,0x1b,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */
-       {0x0107,0x1b,0x1f,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */
-       {0x407f,0x00,0x00,0x00,0x00,0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */
-       {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */
-       {0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */
-       {0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */
-       {0x0077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */
-       {0x0047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */
-       {0x0047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */
-       {0x0077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */
-       {0x0047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */
-       {0x0047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */
-       {0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */
-       {0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */
-       {0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */
-       {0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */
-       {0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi  */
-       {0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz   */
-       {0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi  */
-       {0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz   */
-       {0x006f,0x4d,0x71,0x06,0x15,0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz   */
-       {0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */
-       {0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */
-       {0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30, 0x00, 0x00}, /* 0x2f */
-       {0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x30 */
-       {0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x31 */
-       {0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x32 */
-       {0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz  */
-       {0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz  */
-       {0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz  */
-       {0xffff,0x00,0x00,0x00,0x00,0x00,   0,   0,    0, 0x00, 0x00}
+static const struct SiS_Ext2 SiSUSB_RefIndex[] = {
+       {0x085f, 0x0d, 0x03, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},     /* 0x0 */
+       {0x0067, 0x0e, 0x04, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},     /* 0x1 */
+       {0x0067, 0x0f, 0x08, 0x48, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},     /* 0x2 */
+       {0x0067, 0x10, 0x07, 0x8b, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},     /* 0x3 */
+       {0x0047, 0x11, 0x0a, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},     /* 0x4 */
+       {0x0047, 0x12, 0x0d, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},     /* 0x5 */
+       {0x0047, 0x13, 0x13, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00},     /* 0x6 */
+       {0x0107, 0x14, 0x1c, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00},     /* 0x7 */
+       {0xc85f, 0x05, 0x00, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},     /* 0x8 */
+       {0xc067, 0x06, 0x02, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},     /* 0x9 */
+       {0xc067, 0x07, 0x02, 0x47, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},     /* 0xa */
+       {0xc067, 0x08, 0x03, 0x8a, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},     /* 0xb */
+       {0xc047, 0x09, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},     /* 0xc */
+       {0xc047, 0x0a, 0x09, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},     /* 0xd */
+       {0xc047, 0x0b, 0x0e, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},     /* 0xe */
+       {0xc047, 0x0c, 0x15, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},     /* 0xf */
+       {0x487f, 0x04, 0x00, 0x00, 0x00, 0x2f, 640, 400, 0x30, 0x55, 0x6e},     /* 0x10 */
+       {0xc06f, 0x3c, 0x01, 0x06, 0x13, 0x31, 720, 480, 0x30, 0x00, 0x00},     /* 0x11 */
+       {0x006f, 0x3d, 0x6f, 0x06, 0x14, 0x32, 720, 576, 0x30, 0x00, 0x00},     /* 0x12 (6f was 03) */
+       {0x0087, 0x15, 0x06, 0x00, 0x06, 0x38, 1024, 768, 0x30, 0x00, 0x00},    /* 0x13 */
+       {0xc877, 0x16, 0x0b, 0x06, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},    /* 0x14 */
+       {0xc067, 0x17, 0x0f, 0x49, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},    /* 0x15 */
+       {0x0067, 0x18, 0x11, 0x00, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},    /* 0x16 */
+       {0x0047, 0x19, 0x16, 0x8c, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},    /* 0x17 */
+       {0x0107, 0x1a, 0x1b, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00},    /* 0x18 */
+       {0x0107, 0x1b, 0x1f, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00},    /* 0x19 */
+       {0x407f, 0x00, 0x00, 0x00, 0x00, 0x41, 320, 200, 0x30, 0x56, 0x4e},     /* 0x1a */
+       {0xc07f, 0x01, 0x00, 0x04, 0x04, 0x50, 320, 240, 0x30, 0x00, 0x00},     /* 0x1b */
+       {0x007f, 0x02, 0x04, 0x05, 0x05, 0x51, 400, 300, 0x30, 0x00, 0x00},     /* 0x1c */
+       {0xc077, 0x03, 0x0b, 0x06, 0x06, 0x52, 512, 384, 0x30, 0x00, 0x00},     /* 0x1d */
+       {0x0077, 0x32, 0x40, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00},     /* 0x1e */
+       {0x0047, 0x33, 0x07, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00},     /* 0x1f */
+       {0x0047, 0x34, 0x0a, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00},     /* 0x20 */
+       {0x0077, 0x35, 0x0b, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00},    /* 0x21 */
+       {0x0047, 0x36, 0x11, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00},    /* 0x22 */
+       {0x0047, 0x37, 0x16, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00},    /* 0x23 */
+       {0x1137, 0x38, 0x19, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00},    /* 0x24 */
+       {0x1107, 0x39, 0x1e, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00},    /* 0x25 */
+       {0x1307, 0x3a, 0x20, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00},    /* 0x26 */
+       {0x0077, 0x42, 0x5b, 0x08, 0x11, 0x23, 1280, 768, 0x30, 0x00, 0x00},    /* 0x27 */
+       {0x0087, 0x45, 0x57, 0x00, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00},     /* 0x28 38Hzi  */
+       {0xc067, 0x46, 0x55, 0x0b, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00},     /* 0x29 848x480-60Hz   */
+       {0x0087, 0x47, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00},     /* 0x2a 856x480-38Hzi  */
+       {0xc067, 0x48, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00},     /* 0x2b 856x480-60Hz   */
+       {0x006f, 0x4d, 0x71, 0x06, 0x15, 0x5f, 768, 576, 0x30, 0x00, 0x00},     /* 0x2c 768x576-56Hz   */
+       {0x0067, 0x52, 0x6a, 0x00, 0x1c, 0x1d, 960, 540, 0x30, 0x00, 0x00},     /* 0x2d 960x540 60Hz */
+       {0x0077, 0x53, 0x6b, 0x0b, 0x1d, 0x20, 960, 600, 0x30, 0x00, 0x00},     /* 0x2e 960x600 60Hz */
+       {0x0087, 0x1c, 0x11, 0x00, 0x07, 0x3a, 1280, 1024, 0x30, 0x00, 0x00},   /* 0x2f */
+       {0x0137, 0x1d, 0x19, 0x07, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00},   /* 0x30 */
+       {0x0107, 0x1e, 0x1e, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00},   /* 0x31 */
+       {0x0207, 0x1f, 0x20, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00},   /* 0x32 */
+       {0x0127, 0x54, 0x6d, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00},    /* 0x33 1152x864-60Hz  */
+       {0x0127, 0x44, 0x19, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00},    /* 0x34 1152x864-75Hz  */
+       {0x0127, 0x4a, 0x1e, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00},    /* 0x35 1152x864-85Hz  */
+       {0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x00, 0x00}
 };
 
-static const struct SiS_CRT1Table SiSUSB_CRT1Table[] =
-{
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
-   0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
-   0x00}}, /* 0x0 */
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
-   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
-   0x00}}, /* 0x1 */
- {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0,
-   0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05,
-   0x01}}, /* 0x2 */
- {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
-   0x01}}, /* 0x3 */
- {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05,
-   0x00}}, /* 0x4 */
- {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
-   0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
-   0x00}}, /* 0x5 */
- {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e,
-   0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01,
-   0x00}}, /* 0x6 */
- {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f,
-   0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01,
-   0x00}}, /* 0x7 */
- {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f,
-   0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
-   0x00}}, /* 0x8 */
- {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f,
-   0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
-   0x61}}, /* 0x9 */
- {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e,
-   0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05,
-   0x61}}, /* 0xa */
- {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e,
-   0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05,
-   0x61}}, /* 0xb */
- {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f,
-   0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01,
-   0x00}}, /* 0xc */
- {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
-   0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05,
-   0x01}}, /* 0xd */
- {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0,
-   0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06,
-   0x01}}, /* 0xe */
- {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0,
-   0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06,
-   0x01}}, /* 0xf */
- {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0,
-   0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06,
-   0x01}}, /* 0x10 */
- {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0,
-   0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06,
-   0x01}}, /* 0x11 */
- {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0,
-   0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06,
-   0x61}}, /* 0x12 */
- {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0,
-   0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06,
-   0x61}}, /* 0x13 */
- {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0,
-   0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06,
-   0x61}}, /* 0x14 */
- {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f,
-   0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02,
-   0x00}}, /* 0x15 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-   0x01}}, /* 0x16 */
- {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-   0x01}}, /* 0x17 */
- {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5,
-   0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02,
-   0x01}}, /* 0x18 */
- {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5,
-   0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02,
-   0x01}}, /* 0x19 */
- {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5,
-   0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02,
-   0x62}}, /* 0x1a */
- {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5,
-   0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02,
-   0x62}}, /* 0x1b */
- {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba,
-   0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03,
-   0x00}}, /* 0x1c */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a,
-   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
-   0x01}}, /* 0x1d */
- {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a,
-   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
-   0x01}}, /* 0x1e */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a,
-   0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07,
-   0x01}}, /* 0x1f */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x20 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x21 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x22 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x23 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x24 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x25 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x26 */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-   0x00}}, /* 0x27 */
- {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05,
-   0x63}}, /* 0x28 */
- {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05,
-   0x63}}, /* 0x29 */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-   0x00}}, /* 0x2a */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-   0x00}}, /* 0x2b */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-   0x00}}, /* 0x2c */
- {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba,
-   0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05,
-   0x44}}, /* 0x2d */
- {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba,
-   0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05,
-   0x44}}, /* 0x2e */
- {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba,
-   0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05,
-   0x44}}, /* 0x2f */
- {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba,
-   0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05,
-   0x44}}, /* 0x30 */
- {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba,
-   0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05,
-   0x00}}, /* 0x31 */
- {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,
-   0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
-   0x01}}, /* 0x32 */
- {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba,
-   0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06,
-   0x01}}, /* 0x33 */
- {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba,
-   0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06,
-   0x01}}, /* 0x34 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1,
-   0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02,
-   0x01}}, /* 0x35 */
- {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1,
-   0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
-   0x01}}, /* 0x36 */
- {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1,
-   0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
-   0x01}}, /* 0x37 */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4,
-   0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
-   0x01}}, /* 0x38 */
- {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4,
-   0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
-   0x01}}, /* 0x39 */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4,
-   0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07,
-   0x01}}, /* 0x3a */
- {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff,
-   0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07,
-   0x01}}, /* 0x3b */
- {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e,
-   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
-   0x00}}, /* 0x3c */
- {{0x6d,0x59,0x59,0x91,0x60,0x89,0x53,0xf0,
-   0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05,
-   0x41}}, /* 0x3d */
- {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15,
-   0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02,
-   0x00}}, /* 0x3e */
- {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e,
-   0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02,
-   0x00}}, /* 0x3f */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1,
-   0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02,
-   0x01}},  /* 0x40 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-   0x01}},  /* 0x41 */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5,
-   0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07,
-   0x01}},  /* 0x42 */
- {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10,
-   0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03,
-   0x00}},  /* 0x43 */
- {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef,
-   0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07,
-   0x01}},  /* 0x44 */
- {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15,
-   0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
-   0x00}},  /* 0x45 */
- {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E,
-   0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06,
-   0x00}},  /* 0x46 */
- {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15,
-   0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
-   0x00}},  /* 0x47 */
- {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E,
-   0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02,
-   0x00}},  /* 0x48 */
- {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd,
-   0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03,
-   0x01}},  /* 0x49 */
- {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff,
-   0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03,
-   0x01}},  /* 0x4a */
- {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10,
-   0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03,
-   0x00}},  /* 0x4b */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff,
-   0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07,
-   0x01}},  /* 0x4c */
- {{0x75,0x5f,0x5f,0x99,0x66,0x90,0x53,0xf0,
-   0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05,
-   0x41}},
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
-   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
-   0x00}},  /* 0x4e */
- {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff,
-   0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07,
-   0x21}},  /* 0x4f */
- {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10,
-   0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c,
-   0x20}},  /* 0x50 */
- {{0x0e,0xef,0xef,0x92,0xfe,0x03,0x30,0xf0,
-   0x1e,0x83,0x1b,0x1c,0x31,0x00,0x01,0x00,
-   0x61}},  /* 0x51 */
- {{0x85,0x77,0x77,0x89,0x7d,0x01,0x31,0xf0,
-   0x1e,0x84,0x1b,0x1c,0x32,0x00,0x00,0x02,
-   0x41}},  /* 0x52 */
- {{0x87,0x77,0x77,0x8b,0x81,0x0b,0x68,0xf0,
-   0x5a,0x80,0x57,0x57,0x69,0x00,0x00,0x02,
-   0x01}},  /* 0x53 */
- {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff,
-   0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07,
-   0x41}}   /* 0x54 */
+static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = {
+       {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f,
+         0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00,
+         0x00}},               /* 0x0 */
+       {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e,
+         0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00,
+         0x00}},               /* 0x1 */
+       {{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0,
+         0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05,
+         0x01}},               /* 0x2 */
+       {{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5,
+         0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01,
+         0x01}},               /* 0x3 */
+       {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+         0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05,
+         0x00}},               /* 0x4 */
+       {{0x5f, 0x4f, 0x4f, 0x83, 0x55, 0x81, 0x0b, 0x3e,
+         0xe9, 0x8b, 0xdf, 0xe8, 0x0c, 0x00, 0x00, 0x05,
+         0x00}},               /* 0x5 */
+       {{0x63, 0x4f, 0x4f, 0x87, 0x56, 0x9b, 0x06, 0x3e,
+         0xe8, 0x8a, 0xdf, 0xe7, 0x07, 0x00, 0x00, 0x01,
+         0x00}},               /* 0x6 */
+       {{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f,
+         0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01,
+         0x00}},               /* 0x7 */
+       {{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f,
+         0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05,
+         0x00}},               /* 0x8 */
+       {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f,
+         0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05,
+         0x61}},               /* 0x9 */
+       {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e,
+         0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05,
+         0x61}},               /* 0xa */
+       {{0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e,
+         0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x00, 0x00, 0x05,
+         0x61}},               /* 0xb */
+       {{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f,
+         0xe6, 0x8a, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x01,
+         0x00}},               /* 0xc */
+       {{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0,
+         0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05,
+         0x01}},               /* 0xd */
+       {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0,
+         0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06,
+         0x01}},               /* 0xe */
+       {{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0,
+         0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06,
+         0x01}},               /* 0xf */
+       {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0,
+         0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06,
+         0x01}},               /* 0x10 */
+       {{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0,
+         0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06,
+         0x01}},               /* 0x11 */
+       {{0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0,
+         0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06,
+         0x61}},               /* 0x12 */
+       {{0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0,
+         0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06,
+         0x61}},               /* 0x13 */
+       {{0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0,
+         0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06,
+         0x61}},               /* 0x14 */
+       {{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f,
+         0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02,
+         0x00}},               /* 0x15 */
+       {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5,
+         0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+         0x01}},               /* 0x16 */
+       {{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5,
+         0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+         0x01}},               /* 0x17 */
+       {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5,
+         0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02,
+         0x01}},               /* 0x18 */
+       {{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5,
+         0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02,
+         0x01}},               /* 0x19 */
+       {{0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5,
+         0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02,
+         0x62}},               /* 0x1a */
+       {{0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5,
+         0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02,
+         0x62}},               /* 0x1b */
+       {{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba,
+         0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03,
+         0x00}},               /* 0x1c */
+       {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a,
+         0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07,
+         0x01}},               /* 0x1d */
+       {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a,
+         0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07,
+         0x01}},               /* 0x1e */
+       {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a,
+         0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07,
+         0x01}},               /* 0x1f */
+       {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+         0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+         0x00}},               /* 0x20 */
+       {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+         0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+         0x00}},               /* 0x21 */
+       {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+         0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+         0x00}},               /* 0x22 */
+       {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+         0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+         0x00}},               /* 0x23 */
+       {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+         0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+         0x00}},               /* 0x24 */
+       {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+         0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+         0x00}},               /* 0x25 */
+       {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+         0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+         0x00}},               /* 0x26 */
+       {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+         0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+         0x00}},               /* 0x27 */
+       {{0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f,
+         0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05,
+         0x63}},               /* 0x28 */
+       {{0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f,
+         0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05,
+         0x63}},               /* 0x29 */
+       {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+         0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+         0x00}},               /* 0x2a */
+       {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+         0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+         0x00}},               /* 0x2b */
+       {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+         0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+         0x00}},               /* 0x2c */
+       {{0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba,
+         0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05,
+         0x44}},               /* 0x2d */
+       {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba,
+         0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05,
+         0x44}},               /* 0x2e */
+       {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba,
+         0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05,
+         0x44}},               /* 0x2f */
+       {{0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba,
+         0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05,
+         0x44}},               /* 0x30 */
+       {{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba,
+         0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05,
+         0x00}},               /* 0x31 */
+       {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba,
+         0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06,
+         0x01}},               /* 0x32 */
+       {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba,
+         0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06,
+         0x01}},               /* 0x33 */
+       {{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba,
+         0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06,
+         0x01}},               /* 0x34 */
+       {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1,
+         0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02,
+         0x01}},               /* 0x35 */
+       {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1,
+         0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02,
+         0x01}},               /* 0x36 */
+       {{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x95, 0x26, 0xf1,
+         0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02,
+         0x01}},               /* 0x37 */
+       {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4,
+         0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07,
+         0x01}},               /* 0x38 */
+       {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4,
+         0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07,
+         0x01}},               /* 0x39 */
+       {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4,
+         0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07,
+         0x01}},               /* 0x3a */
+       {{0xdc, 0x9f, 0x9f, 0x80, 0xaf, 0x9d, 0xe6, 0xff,
+         0xc0, 0x83, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07,
+         0x01}},               /* 0x3b */
+       {{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e,
+         0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05,
+         0x00}},               /* 0x3c */
+       {{0x6d, 0x59, 0x59, 0x91, 0x60, 0x89, 0x53, 0xf0,
+         0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05,
+         0x41}},               /* 0x3d */
+       {{0x86, 0x6a, 0x6a, 0x8a, 0x74, 0x06, 0x8c, 0x15,
+         0x4f, 0x83, 0xef, 0xef, 0x8d, 0x30, 0x00, 0x02,
+         0x00}},               /* 0x3e */
+       {{0x81, 0x6a, 0x6a, 0x85, 0x70, 0x00, 0x0f, 0x3e,
+         0xeb, 0x8e, 0xdf, 0xdf, 0x10, 0x00, 0x00, 0x02,
+         0x00}},               /* 0x3f */
+       {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x1e, 0xf1,
+         0xae, 0x85, 0x57, 0x57, 0x1f, 0x30, 0x00, 0x02,
+         0x01}},               /* 0x40 */
+       {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5,
+         0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+         0x01}},               /* 0x41 */
+       {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x20, 0xf5,
+         0x03, 0x88, 0xff, 0xff, 0x21, 0x10, 0x00, 0x07,
+         0x01}},               /* 0x42 */
+       {{0xe6, 0xae, 0xae, 0x8a, 0xbd, 0x90, 0x3d, 0x10,
+         0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x00, 0x03,
+         0x00}},               /* 0x43 */
+       {{0xc3, 0x8f, 0x8f, 0x87, 0x9b, 0x0b, 0x82, 0xef,
+         0x60, 0x83, 0x5f, 0x5f, 0x83, 0x10, 0x00, 0x07,
+         0x01}},               /* 0x44 */
+       {{0x86, 0x69, 0x69, 0x8A, 0x74, 0x06, 0x8C, 0x15,
+         0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02,
+         0x00}},               /* 0x45 */
+       {{0x83, 0x69, 0x69, 0x87, 0x6f, 0x1d, 0x03, 0x3E,
+         0xE5, 0x8d, 0xDF, 0xe4, 0x04, 0x00, 0x00, 0x06,
+         0x00}},               /* 0x46 */
+       {{0x86, 0x6A, 0x6A, 0x8A, 0x74, 0x06, 0x8C, 0x15,
+         0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02,
+         0x00}},               /* 0x47 */
+       {{0x81, 0x6A, 0x6A, 0x85, 0x70, 0x00, 0x0F, 0x3E,
+         0xEB, 0x8E, 0xDF, 0xDF, 0x10, 0x00, 0x00, 0x02,
+         0x00}},               /* 0x48 */
+       {{0xdd, 0xa9, 0xa9, 0x81, 0xb4, 0x97, 0x26, 0xfd,
+         0x01, 0x8d, 0xff, 0x00, 0x27, 0x10, 0x00, 0x03,
+         0x01}},               /* 0x49 */
+       {{0xd9, 0x8f, 0x8f, 0x9d, 0xba, 0x0a, 0x8a, 0xff,
+         0x60, 0x8b, 0x5f, 0x5f, 0x8b, 0x10, 0x00, 0x03,
+         0x01}},               /* 0x4a */
+       {{0xea, 0xae, 0xae, 0x8e, 0xba, 0x82, 0x40, 0x10,
+         0x1b, 0x87, 0x19, 0x1a, 0x41, 0x0f, 0x00, 0x03,
+         0x00}},               /* 0x4b */
+       {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0xf1, 0xff,
+         0xc0, 0x83, 0xbf, 0xbf, 0xf2, 0x10, 0x00, 0x07,
+         0x01}},               /* 0x4c */
+       {{0x75, 0x5f, 0x5f, 0x99, 0x66, 0x90, 0x53, 0xf0,
+         0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05,
+         0x41}},
+       {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e,
+         0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00,
+         0x00}},               /* 0x4e */
+       {{0xcd, 0x9f, 0x9f, 0x91, 0xab, 0x1c, 0x3a, 0xff,
+         0x20, 0x83, 0x1f, 0x1f, 0x3b, 0x10, 0x00, 0x07,
+         0x21}},               /* 0x4f */
+       {{0x15, 0xd1, 0xd1, 0x99, 0xe2, 0x19, 0x3d, 0x10,
+         0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x01, 0x0c,
+         0x20}},               /* 0x50 */
+       {{0x0e, 0xef, 0xef, 0x92, 0xfe, 0x03, 0x30, 0xf0,
+         0x1e, 0x83, 0x1b, 0x1c, 0x31, 0x00, 0x01, 0x00,
+         0x61}},               /* 0x51 */
+       {{0x85, 0x77, 0x77, 0x89, 0x7d, 0x01, 0x31, 0xf0,
+         0x1e, 0x84, 0x1b, 0x1c, 0x32, 0x00, 0x00, 0x02,
+         0x41}},               /* 0x52 */
+       {{0x87, 0x77, 0x77, 0x8b, 0x81, 0x0b, 0x68, 0xf0,
+         0x5a, 0x80, 0x57, 0x57, 0x69, 0x00, 0x00, 0x02,
+         0x01}},               /* 0x53 */
+       {{0xcd, 0x8f, 0x8f, 0x91, 0x9b, 0x1b, 0x7a, 0xff,
+         0x64, 0x8c, 0x5f, 0x62, 0x7b, 0x10, 0x00, 0x07,
+         0x41}}                /* 0x54 */
 };
 
-static const struct SiS_VCLKData SiSUSB_VCLKData[] =
-{
-       { 0x1b,0xe1, 25}, /* 0x00 */
-       { 0x4e,0xe4, 28}, /* 0x01 */
-       { 0x57,0xe4, 31}, /* 0x02 */
-       { 0xc3,0xc8, 36}, /* 0x03 */
-       { 0x42,0xe2, 40}, /* 0x04 */
-       { 0xfe,0xcd, 43}, /* 0x05 */
-       { 0x5d,0xc4, 44}, /* 0x06 */
-       { 0x52,0xe2, 49}, /* 0x07 */
-       { 0x53,0xe2, 50}, /* 0x08 */
-       { 0x74,0x67, 52}, /* 0x09 */
-       { 0x6d,0x66, 56}, /* 0x0a */
-       { 0x5a,0x64, 65}, /* 0x0b */
-       { 0x46,0x44, 67}, /* 0x0c */
-       { 0xb1,0x46, 68}, /* 0x0d */
-       { 0xd3,0x4a, 72}, /* 0x0e */
-       { 0x29,0x61, 75}, /* 0x0f */
-       { 0x6e,0x46, 76}, /* 0x10 */
-       { 0x2b,0x61, 78}, /* 0x11 */
-       { 0x31,0x42, 79}, /* 0x12 */
-       { 0xab,0x44, 83}, /* 0x13 */
-       { 0x46,0x25, 84}, /* 0x14 */
-       { 0x78,0x29, 86}, /* 0x15 */
-       { 0x62,0x44, 94}, /* 0x16 */
-       { 0x2b,0x41,104}, /* 0x17 */
-       { 0x3a,0x23,105}, /* 0x18 */
-       { 0x70,0x44,108}, /* 0x19 */
-       { 0x3c,0x23,109}, /* 0x1a */
-       { 0x5e,0x43,113}, /* 0x1b */
-       { 0xbc,0x44,116}, /* 0x1c */
-       { 0xe0,0x46,132}, /* 0x1d */
-       { 0x54,0x42,135}, /* 0x1e */
-       { 0xea,0x2a,139}, /* 0x1f */
-       { 0x41,0x22,157}, /* 0x20 */
-       { 0x70,0x24,162}, /* 0x21 */
-       { 0x30,0x21,175}, /* 0x22 */
-       { 0x4e,0x22,189}, /* 0x23 */
-       { 0xde,0x26,194}, /* 0x24 */
-       { 0x62,0x06,202}, /* 0x25 */
-       { 0x3f,0x03,229}, /* 0x26 */
-       { 0xb8,0x06,234}, /* 0x27 */
-       { 0x34,0x02,253}, /* 0x28 */
-       { 0x58,0x04,255}, /* 0x29 */
-       { 0x24,0x01,265}, /* 0x2a */
-       { 0x9b,0x02,267}, /* 0x2b */
-       { 0x70,0x05,270}, /* 0x2c */
-       { 0x25,0x01,272}, /* 0x2d */
-       { 0x9c,0x02,277}, /* 0x2e */
-       { 0x27,0x01,286}, /* 0x2f */
-       { 0x3c,0x02,291}, /* 0x30 */
-       { 0xef,0x0a,292}, /* 0x31 */
-       { 0xf6,0x0a,310}, /* 0x32 */
-       { 0x95,0x01,315}, /* 0x33 */
-       { 0xf0,0x09,324}, /* 0x34 */
-       { 0xfe,0x0a,331}, /* 0x35 */
-       { 0xf3,0x09,332}, /* 0x36 */
-       { 0xea,0x08,340}, /* 0x37 */
-       { 0xe8,0x07,376}, /* 0x38 */
-       { 0xde,0x06,389}, /* 0x39 */
-       { 0x52,0x2a, 54}, /* 0x3a 301 TV */
-       { 0x52,0x6a, 27}, /* 0x3b 301 TV */
-       { 0x62,0x24, 70}, /* 0x3c 301 TV */
-       { 0x62,0x64, 70}, /* 0x3d 301 TV */
-       { 0xa8,0x4c, 30}, /* 0x3e 301 TV */
-       { 0x20,0x26, 33}, /* 0x3f 301 TV */
-       { 0x31,0xc2, 39}, /* 0x40 */
-       { 0x60,0x36, 30}, /* 0x41 Chrontel */
-       { 0x40,0x4a, 28}, /* 0x42 Chrontel */
-       { 0x9f,0x46, 44}, /* 0x43 Chrontel */
-       { 0x97,0x2c, 26}, /* 0x44 */
-       { 0x44,0xe4, 25}, /* 0x45 Chrontel */
-       { 0x7e,0x32, 47}, /* 0x46 Chrontel */
-       { 0x8a,0x24, 31}, /* 0x47 Chrontel */
-       { 0x97,0x2c, 26}, /* 0x48 Chrontel */
-       { 0xce,0x3c, 39}, /* 0x49 */
-       { 0x52,0x4a, 36}, /* 0x4a Chrontel */
-       { 0x34,0x61, 95}, /* 0x4b */
-       { 0x78,0x27,108}, /* 0x4c - was 102 */
-       { 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */
-       { 0x41,0x4e, 21}, /* 0x4e */
-       { 0xa1,0x4a, 29}, /* 0x4f Chrontel */
-       { 0x19,0x42, 42}, /* 0x50 */
-       { 0x54,0x46, 58}, /* 0x51 Chrontel */
-       { 0x25,0x42, 61}, /* 0x52 */
-       { 0x44,0x44, 66}, /* 0x53 Chrontel */
-       { 0x3a,0x62, 70}, /* 0x54 Chrontel */
-       { 0x62,0xc6, 34}, /* 0x55 848x480-60 */
-       { 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */
-       { 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */
-       { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */
-       { 0x52,0x07,149}, /* 0x59 1280x960-85 */
-       { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */
-       { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */
-       { 0x45,0x25, 83}, /* 0x5c 1280x800  */
-       { 0x70,0x0a,147}, /* 0x5d 1680x1050 */
-       { 0x70,0x24,162}, /* 0x5e 1600x1200 */
-       { 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */
-       { 0x63,0x46, 68}, /* 0x60 1280x768_2 */
-       { 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */
-       {    0,   0,  0}, /* 0x62 - custom (will be filled out at run-time) */
-       { 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */
-       { 0x70,0x28, 90}, /* 0x64 1152x864@60 */
-       { 0x41,0xc4, 32}, /* 0x65 848x480@60 */
-       { 0x5c,0xc6, 32}, /* 0x66 856x480@60 */
-       { 0x76,0xe7, 27}, /* 0x67 720x480@60 */
-       { 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */
-       { 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */
-       { 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */
-       { 0xe3,0x56, 41}, /* 0x6b 960x600@60 */
-       { 0x45,0x25, 83}, /* 0x6c 1280x800 */
-       { 0x70,0x28, 90}, /* 0x6d 1152x864@60 */
-       { 0x15,0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */
-       { 0x5f,0xc6, 33}, /* 0x6f 720x576@60 */
-       { 0x37,0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */
-       { 0x2b,0xc2, 35}  /* 0x71 768@576@60 */
+static const struct SiS_VCLKData SiSUSB_VCLKData[] = {
+       {0x1b, 0xe1, 25},       /* 0x00 */
+       {0x4e, 0xe4, 28},       /* 0x01 */
+       {0x57, 0xe4, 31},       /* 0x02 */
+       {0xc3, 0xc8, 36},       /* 0x03 */
+       {0x42, 0xe2, 40},       /* 0x04 */
+       {0xfe, 0xcd, 43},       /* 0x05 */
+       {0x5d, 0xc4, 44},       /* 0x06 */
+       {0x52, 0xe2, 49},       /* 0x07 */
+       {0x53, 0xe2, 50},       /* 0x08 */
+       {0x74, 0x67, 52},       /* 0x09 */
+       {0x6d, 0x66, 56},       /* 0x0a */
+       {0x5a, 0x64, 65},       /* 0x0b */
+       {0x46, 0x44, 67},       /* 0x0c */
+       {0xb1, 0x46, 68},       /* 0x0d */
+       {0xd3, 0x4a, 72},       /* 0x0e */
+       {0x29, 0x61, 75},       /* 0x0f */
+       {0x6e, 0x46, 76},       /* 0x10 */
+       {0x2b, 0x61, 78},       /* 0x11 */
+       {0x31, 0x42, 79},       /* 0x12 */
+       {0xab, 0x44, 83},       /* 0x13 */
+       {0x46, 0x25, 84},       /* 0x14 */
+       {0x78, 0x29, 86},       /* 0x15 */
+       {0x62, 0x44, 94},       /* 0x16 */
+       {0x2b, 0x41, 104},      /* 0x17 */
+       {0x3a, 0x23, 105},      /* 0x18 */
+       {0x70, 0x44, 108},      /* 0x19 */
+       {0x3c, 0x23, 109},      /* 0x1a */
+       {0x5e, 0x43, 113},      /* 0x1b */
+       {0xbc, 0x44, 116},      /* 0x1c */
+       {0xe0, 0x46, 132},      /* 0x1d */
+       {0x54, 0x42, 135},      /* 0x1e */
+       {0xea, 0x2a, 139},      /* 0x1f */
+       {0x41, 0x22, 157},      /* 0x20 */
+       {0x70, 0x24, 162},      /* 0x21 */
+       {0x30, 0x21, 175},      /* 0x22 */
+       {0x4e, 0x22, 189},      /* 0x23 */
+       {0xde, 0x26, 194},      /* 0x24 */
+       {0x62, 0x06, 202},      /* 0x25 */
+       {0x3f, 0x03, 229},      /* 0x26 */
+       {0xb8, 0x06, 234},      /* 0x27 */
+       {0x34, 0x02, 253},      /* 0x28 */
+       {0x58, 0x04, 255},      /* 0x29 */
+       {0x24, 0x01, 265},      /* 0x2a */
+       {0x9b, 0x02, 267},      /* 0x2b */
+       {0x70, 0x05, 270},      /* 0x2c */
+       {0x25, 0x01, 272},      /* 0x2d */
+       {0x9c, 0x02, 277},      /* 0x2e */
+       {0x27, 0x01, 286},      /* 0x2f */
+       {0x3c, 0x02, 291},      /* 0x30 */
+       {0xef, 0x0a, 292},      /* 0x31 */
+       {0xf6, 0x0a, 310},      /* 0x32 */
+       {0x95, 0x01, 315},      /* 0x33 */
+       {0xf0, 0x09, 324},      /* 0x34 */
+       {0xfe, 0x0a, 331},      /* 0x35 */
+       {0xf3, 0x09, 332},      /* 0x36 */
+       {0xea, 0x08, 340},      /* 0x37 */
+       {0xe8, 0x07, 376},      /* 0x38 */
+       {0xde, 0x06, 389},      /* 0x39 */
+       {0x52, 0x2a, 54},       /* 0x3a 301 TV */
+       {0x52, 0x6a, 27},       /* 0x3b 301 TV */
+       {0x62, 0x24, 70},       /* 0x3c 301 TV */
+       {0x62, 0x64, 70},       /* 0x3d 301 TV */
+       {0xa8, 0x4c, 30},       /* 0x3e 301 TV */
+       {0x20, 0x26, 33},       /* 0x3f 301 TV */
+       {0x31, 0xc2, 39},       /* 0x40 */
+       {0x60, 0x36, 30},       /* 0x41 Chrontel */
+       {0x40, 0x4a, 28},       /* 0x42 Chrontel */
+       {0x9f, 0x46, 44},       /* 0x43 Chrontel */
+       {0x97, 0x2c, 26},       /* 0x44 */
+       {0x44, 0xe4, 25},       /* 0x45 Chrontel */
+       {0x7e, 0x32, 47},       /* 0x46 Chrontel */
+       {0x8a, 0x24, 31},       /* 0x47 Chrontel */
+       {0x97, 0x2c, 26},       /* 0x48 Chrontel */
+       {0xce, 0x3c, 39},       /* 0x49 */
+       {0x52, 0x4a, 36},       /* 0x4a Chrontel */
+       {0x34, 0x61, 95},       /* 0x4b */
+       {0x78, 0x27, 108},      /* 0x4c - was 102 */
+       {0x66, 0x43, 123},      /* 0x4d Modes 0x26-0x28 (1400x1050) */
+       {0x41, 0x4e, 21},       /* 0x4e */
+       {0xa1, 0x4a, 29},       /* 0x4f Chrontel */
+       {0x19, 0x42, 42},       /* 0x50 */
+       {0x54, 0x46, 58},       /* 0x51 Chrontel */
+       {0x25, 0x42, 61},       /* 0x52 */
+       {0x44, 0x44, 66},       /* 0x53 Chrontel */
+       {0x3a, 0x62, 70},       /* 0x54 Chrontel */
+       {0x62, 0xc6, 34},       /* 0x55 848x480-60 */
+       {0x6a, 0xc6, 37},       /* 0x56 848x480-75 - TEMP */
+       {0xbf, 0xc8, 35},       /* 0x57 856x480-38i,60 */
+       {0x30, 0x23, 88},       /* 0x58 1360x768-62 (is 60Hz!) */
+       {0x52, 0x07, 149},      /* 0x59 1280x960-85 */
+       {0x56, 0x07, 156},      /* 0x5a 1400x1050-75 */
+       {0x70, 0x29, 81},       /* 0x5b 1280x768 LCD */
+       {0x45, 0x25, 83},       /* 0x5c 1280x800  */
+       {0x70, 0x0a, 147},      /* 0x5d 1680x1050 */
+       {0x70, 0x24, 162},      /* 0x5e 1600x1200 */
+       {0x5a, 0x64, 65},       /* 0x5f 1280x720 - temp */
+       {0x63, 0x46, 68},       /* 0x60 1280x768_2 */
+       {0x31, 0x42, 79},       /* 0x61 1280x768_3 - temp */
+       {0, 0, 0},              /* 0x62 - custom (will be filled out at run-time) */
+       {0x5a, 0x64, 65},       /* 0x63 1280x720 (LCD LVDS) */
+       {0x70, 0x28, 90},       /* 0x64 1152x864@60 */
+       {0x41, 0xc4, 32},       /* 0x65 848x480@60 */
+       {0x5c, 0xc6, 32},       /* 0x66 856x480@60 */
+       {0x76, 0xe7, 27},       /* 0x67 720x480@60 */
+       {0x5f, 0xc6, 33},       /* 0x68 720/768x576@60 */
+       {0x52, 0x27, 75},       /* 0x69 1920x1080i 60Hz interlaced */
+       {0x7c, 0x6b, 38},       /* 0x6a 960x540@60 */
+       {0xe3, 0x56, 41},       /* 0x6b 960x600@60 */
+       {0x45, 0x25, 83},       /* 0x6c 1280x800 */
+       {0x70, 0x28, 90},       /* 0x6d 1152x864@60 */
+       {0x15, 0xe1, 20},       /* 0x6e 640x400@60 (fake, not actually used) */
+       {0x5f, 0xc6, 33},       /* 0x6f 720x576@60 */
+       {0x37, 0x5a, 10},       /* 0x70 320x200@60 (fake, not actually used) */
+       {0x2b, 0xc2, 35}        /* 0x71 768@576@60 */
 };
 
-int            SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
-int            SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
+int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
+int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
 
-extern int     sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
-extern int     sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data);
-extern int     sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
-                                       u8 index, u8 data);
-extern int     sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port,
-                                       u8 index, u8 *data);
-extern int     sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port,
-                                       u8 idx, u8 myand, u8 myor);
-extern int     sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
-                                       u8 index, u8 myor);
-extern int     sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
-                                       u8 idx, u8 myand);
+extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
+extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 * data);
+extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
+                           u8 index, u8 data);
+extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port,
+                           u8 index, u8 * data);
+extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port,
+                                u8 idx, u8 myand, u8 myor);
+extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
+                             u8 index, u8 myor);
+extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
+                              u8 idx, u8 myand);
 
 void sisusb_delete(struct kref *kref);
 int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data);
-int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data);
+int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 * data);
 int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
-                      u32 dest, int length, size_t *bytes_written);
+                      u32 dest, int length, size_t * bytes_written);
 int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init);
 int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
-                        u8 *arg, int cmapsz, int ch512, int dorecalc,
+                        u8 * arg, int cmapsz, int ch512, int dorecalc,
                         struct vc_data *c, int fh, int uplock);
 void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location);
 int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last);
@@ -839,4 +839,3 @@ void sisusb_console_exit(struct sisusb_usb_data *sisusb);
 void sisusb_init_concode(void);
 
 #endif
-
index f325ecb..1c4240e 100644 (file)
@@ -44,7 +44,7 @@
  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Author:     Thomas Winischhofer <thomas@winischhofer.net>
+ * Author:     Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
 #define _SISUSB_STRUCT_H_
 
 struct SiS_St {
-       unsigned char   St_ModeID;
-       unsigned short  St_ModeFlag;
-       unsigned char   St_StTableIndex;
-       unsigned char   St_CRT2CRTC;
-       unsigned char   St_ResInfo;
-       unsigned char   VB_StTVFlickerIndex;
-       unsigned char   VB_StTVEdgeIndex;
-       unsigned char   VB_StTVYFilterIndex;
-       unsigned char   St_PDC;
+       unsigned char St_ModeID;
+       unsigned short St_ModeFlag;
+       unsigned char St_StTableIndex;
+       unsigned char St_CRT2CRTC;
+       unsigned char St_ResInfo;
+       unsigned char VB_StTVFlickerIndex;
+       unsigned char VB_StTVEdgeIndex;
+       unsigned char VB_StTVYFilterIndex;
+       unsigned char St_PDC;
 };
 
-struct SiS_StandTable
-{
-       unsigned char   CRT_COLS;
-       unsigned char   ROWS;
-       unsigned char   CHAR_HEIGHT;
-       unsigned short  CRT_LEN;
-       unsigned char   SR[4];
-       unsigned char   MISC;
-       unsigned char   CRTC[0x19];
-       unsigned char   ATTR[0x14];
-       unsigned char   GRC[9];
+struct SiS_StandTable {
+       unsigned char CRT_COLS;
+       unsigned char ROWS;
+       unsigned char CHAR_HEIGHT;
+       unsigned short CRT_LEN;
+       unsigned char SR[4];
+       unsigned char MISC;
+       unsigned char CRTC[0x19];
+       unsigned char ATTR[0x14];
+       unsigned char GRC[9];
 };
 
 struct SiS_StResInfo_S {
-       unsigned short  HTotal;
-       unsigned short  VTotal;
+       unsigned short HTotal;
+       unsigned short VTotal;
 };
 
-struct SiS_Ext
-{
-       unsigned char   Ext_ModeID;
-       unsigned short  Ext_ModeFlag;
-       unsigned short  Ext_VESAID;
-       unsigned char   Ext_RESINFO;
-       unsigned char   VB_ExtTVFlickerIndex;
-       unsigned char   VB_ExtTVEdgeIndex;
-       unsigned char   VB_ExtTVYFilterIndex;
-       unsigned char   VB_ExtTVYFilterIndexROM661;
-       unsigned char   REFindex;
-       char            ROMMODEIDX661;
+struct SiS_Ext {
+       unsigned char Ext_ModeID;
+       unsigned short Ext_ModeFlag;
+       unsigned short Ext_VESAID;
+       unsigned char Ext_RESINFO;
+       unsigned char VB_ExtTVFlickerIndex;
+       unsigned char VB_ExtTVEdgeIndex;
+       unsigned char VB_ExtTVYFilterIndex;
+       unsigned char VB_ExtTVYFilterIndexROM661;
+       unsigned char REFindex;
+       char ROMMODEIDX661;
 };
 
-struct SiS_Ext2
-{
-       unsigned short  Ext_InfoFlag;
-       unsigned char   Ext_CRT1CRTC;
-       unsigned char   Ext_CRTVCLK;
-       unsigned char   Ext_CRT2CRTC;
-       unsigned char   Ext_CRT2CRTC_NS;
-       unsigned char   ModeID;
-       unsigned short  XRes;
-       unsigned short  YRes;
-       unsigned char   Ext_PDC;
-       unsigned char   Ext_FakeCRT2CRTC;
-       unsigned char   Ext_FakeCRT2Clk;
+struct SiS_Ext2 {
+       unsigned short Ext_InfoFlag;
+       unsigned char Ext_CRT1CRTC;
+       unsigned char Ext_CRTVCLK;
+       unsigned char Ext_CRT2CRTC;
+       unsigned char Ext_CRT2CRTC_NS;
+       unsigned char ModeID;
+       unsigned short XRes;
+       unsigned short YRes;
+       unsigned char Ext_PDC;
+       unsigned char Ext_FakeCRT2CRTC;
+       unsigned char Ext_FakeCRT2Clk;
 };
 
-struct SiS_CRT1Table
-{
-       unsigned char   CR[17];
+struct SiS_CRT1Table {
+       unsigned char CR[17];
 };
 
-struct SiS_VCLKData
-{
-       unsigned char   SR2B,SR2C;
-       unsigned short  CLOCK;
+struct SiS_VCLKData {
+       unsigned char SR2B, SR2C;
+       unsigned short CLOCK;
 };
 
-struct SiS_ModeResInfo
-{
-       unsigned short  HTotal;
-       unsigned short  VTotal;
-       unsigned char   XChar;
-       unsigned char   YChar;
+struct SiS_ModeResInfo {
+       unsigned short HTotal;
+       unsigned short VTotal;
+       unsigned char XChar;
+       unsigned char YChar;
 };
 
-struct SiS_Private
-{
+struct SiS_Private {
        void *sisusb;
 
        unsigned long IOAddress;
@@ -151,19 +144,18 @@ struct SiS_Private
        unsigned long SiS_P3da;
        unsigned long SiS_Part1Port;
 
-       unsigned char   SiS_MyCR63;
-       unsigned short  SiS_CRT1Mode;
-       unsigned short  SiS_ModeType;
-       unsigned short  SiS_SetFlag;
-
-       const struct SiS_StandTable     *SiS_StandTable;
-       const struct SiS_St             *SiS_SModeIDTable;
-       const struct SiS_Ext            *SiS_EModeIDTable;
-       const struct SiS_Ext2           *SiS_RefIndex;
-       const struct SiS_CRT1Table      *SiS_CRT1Table;
-       const struct SiS_VCLKData       *SiS_VCLKData;
-       const struct SiS_ModeResInfo    *SiS_ModeResInfo;
+       unsigned char SiS_MyCR63;
+       unsigned short SiS_CRT1Mode;
+       unsigned short SiS_ModeType;
+       unsigned short SiS_SetFlag;
+
+       const struct SiS_StandTable *SiS_StandTable;
+       const struct SiS_St *SiS_SModeIDTable;
+       const struct SiS_Ext *SiS_EModeIDTable;
+       const struct SiS_Ext2 *SiS_RefIndex;
+       const struct SiS_CRT1Table *SiS_CRT1Table;
+       const struct SiS_VCLKData *SiS_VCLKData;
+       const struct SiS_ModeResInfo *SiS_ModeResInfo;
 };
 
 #endif
-
index c03dfd7..f06e4e2 100644 (file)
@@ -172,6 +172,10 @@ static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp,
 
 #define MON_RING_EMPTY(rp)     ((rp)->b_cnt == 0)
 
+static unsigned char xfer_to_pipe[4] = {
+       PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
+};
+
 static struct class *mon_bin_class;
 static dev_t mon_bin_dev0;
 static struct cdev mon_bin_cdev;
@@ -354,13 +358,9 @@ static inline char mon_bin_get_setup(unsigned char *setupb,
     const struct urb *urb, char ev_type)
 {
 
-       if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+       if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S')
                return '-';
 
-       if (urb->dev->bus->uses_dma &&
-           (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
-               return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
-       }
        if (urb->setup_packet == NULL)
                return 'Z';
 
@@ -386,13 +386,15 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp,
 }
 
 static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
-    char ev_type)
+    char ev_type, int status)
 {
+       const struct usb_endpoint_descriptor *epd = &urb->ep->desc;
        unsigned long flags;
        struct timeval ts;
        unsigned int urb_length;
        unsigned int offset;
        unsigned int length;
+       unsigned char dir;
        struct mon_bin_hdr *ep;
        char data_tag = 0;
 
@@ -410,16 +412,19 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
        if (length >= rp->b_size/5)
                length = rp->b_size/5;
 
-       if (usb_pipein(urb->pipe)) {
+       if (usb_urb_dir_in(urb)) {
                if (ev_type == 'S') {
                        length = 0;
                        data_tag = '<';
                }
+               /* Cannot rely on endpoint number in case of control ep.0 */
+               dir = USB_DIR_IN;
        } else {
                if (ev_type == 'C') {
                        length = 0;
                        data_tag = '>';
                }
+               dir = 0;
        }
 
        if (rp->mmap_active)
@@ -440,15 +445,14 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
         */
        memset(ep, 0, PKT_SIZE);
        ep->type = ev_type;
-       ep->xfer_type = usb_pipetype(urb->pipe);
-       /* We use the fact that usb_pipein() returns 0x80 */
-       ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
-       ep->devnum = usb_pipedevice(urb->pipe);
+       ep->xfer_type = xfer_to_pipe[usb_endpoint_type(epd)];
+       ep->epnum = dir | usb_endpoint_num(epd);
+       ep->devnum = urb->dev->devnum;
        ep->busnum = urb->dev->bus->busnum;
        ep->id = (unsigned long) urb;
        ep->ts_sec = ts.tv_sec;
        ep->ts_usec = ts.tv_usec;
-       ep->status = urb->status;
+       ep->status = status;
        ep->len_urb = urb_length;
        ep->len_cap = length;
 
@@ -471,13 +475,13 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
 static void mon_bin_submit(void *data, struct urb *urb)
 {
        struct mon_reader_bin *rp = data;
-       mon_bin_event(rp, urb, 'S');
+       mon_bin_event(rp, urb, 'S', -EINPROGRESS);
 }
 
-static void mon_bin_complete(void *data, struct urb *urb)
+static void mon_bin_complete(void *data, struct urb *urb, int status)
 {
        struct mon_reader_bin *rp = data;
-       mon_bin_event(rp, urb, 'C');
+       mon_bin_event(rp, urb, 'C', status);
 }
 
 static void mon_bin_error(void *data, struct urb *urb, int error)
@@ -500,10 +504,10 @@ static void mon_bin_error(void *data, struct urb *urb, int error)
 
        memset(ep, 0, PKT_SIZE);
        ep->type = 'E';
-       ep->xfer_type = usb_pipetype(urb->pipe);
-       /* We use the fact that usb_pipein() returns 0x80 */
-       ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
-       ep->devnum = usb_pipedevice(urb->pipe);
+       ep->xfer_type = xfer_to_pipe[usb_endpoint_type(&urb->ep->desc)];
+       ep->epnum = usb_urb_dir_in(urb) ? USB_DIR_IN : 0;
+       ep->epnum |= usb_endpoint_num(&urb->ep->desc);
+       ep->devnum = urb->dev->devnum;
        ep->busnum = urb->dev->bus->busnum;
        ep->id = (unsigned long) urb;
        ep->status = error;
index ce61d8b..b371ffd 100644 (file)
@@ -129,7 +129,8 @@ static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error)
 
 /*
  */
-static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
+static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb,
+               int status)
 {
        unsigned long flags;
        struct list_head *pos;
@@ -139,28 +140,18 @@ static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
        mbus->cnt_events++;
        list_for_each (pos, &mbus->r_list) {
                r = list_entry(pos, struct mon_reader, r_link);
-               r->rnf_complete(r->r_data, urb);
+               r->rnf_complete(r->r_data, urb, status);
        }
        spin_unlock_irqrestore(&mbus->lock, flags);
 }
 
-static void mon_complete(struct usb_bus *ubus, struct urb *urb)
+static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status)
 {
        struct mon_bus *mbus;
 
-       mbus = ubus->mon_bus;
-       if (mbus == NULL) {
-               /*
-                * This should not happen.
-                * At this point we do not even know the bus number...
-                */
-               printk(KERN_ERR TAG ": Null mon bus in URB, pipe 0x%x\n",
-                   urb->pipe);
-               return;
-       }
-
-       mon_bus_complete(mbus, urb);
-       mon_bus_complete(&mon_bus0, urb);
+       if ((mbus = ubus->mon_bus) != NULL)
+               mon_bus_complete(mbus, urb, status);
+       mon_bus_complete(&mon_bus0, urb, status);
 }
 
 /* int (*unlink_urb) (struct urb *urb, int status); */
@@ -170,7 +161,7 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb)
  */
 static void mon_stop(struct mon_bus *mbus)
 {
-       struct usb_bus *ubus = mbus->u_bus;
+       struct usb_bus *ubus;
        struct list_head *p;
 
        if (mbus == &mon_bus0) {
index 8f27a9e..ebb04ac 100644 (file)
@@ -50,10 +50,13 @@ struct mon_iso_desc {
 struct mon_event_text {
        struct list_head e_link;
        int type;               /* submit, complete, etc. */
-       unsigned int pipe;      /* Pipe */
        unsigned long id;       /* From pointer, most of the time */
        unsigned int tstamp;
        int busnum;
+       char devnum;
+       char epnum;
+       char is_in;
+       char xfertype;
        int length;             /* Depends on type: xfer length or act length */
        int status;
        int interval;
@@ -121,13 +124,9 @@ static inline char mon_text_get_setup(struct mon_event_text *ep,
     struct urb *urb, char ev_type, struct mon_bus *mbus)
 {
 
-       if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+       if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S')
                return '-';
 
-       if (urb->dev->bus->uses_dma &&
-           (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
-               return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX);
-       }
        if (urb->setup_packet == NULL)
                return 'Z';     /* '0' would be not as pretty. */
 
@@ -138,14 +137,12 @@ static inline char mon_text_get_setup(struct mon_event_text *ep,
 static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
     int len, char ev_type, struct mon_bus *mbus)
 {
-       int pipe = urb->pipe;
-
        if (len <= 0)
                return 'L';
        if (len >= DATA_MAX)
                len = DATA_MAX;
 
-       if (usb_pipein(pipe)) {
+       if (ep->is_in) {
                if (ev_type != 'C')
                        return '<';
        } else {
@@ -186,7 +183,7 @@ static inline unsigned int mon_get_timestamp(void)
 }
 
 static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
-    char ev_type)
+    char ev_type, int status)
 {
        struct mon_event_text *ep;
        unsigned int stamp;
@@ -203,24 +200,28 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
        }
 
        ep->type = ev_type;
-       ep->pipe = urb->pipe;
        ep->id = (unsigned long) urb;
        ep->busnum = urb->dev->bus->busnum;
+       ep->devnum = urb->dev->devnum;
+       ep->epnum = usb_endpoint_num(&urb->ep->desc);
+       ep->xfertype = usb_endpoint_type(&urb->ep->desc);
+       ep->is_in = usb_urb_dir_in(urb);
        ep->tstamp = stamp;
        ep->length = (ev_type == 'S') ?
            urb->transfer_buffer_length : urb->actual_length;
        /* Collecting status makes debugging sense for submits, too */
-       ep->status = urb->status;
+       ep->status = status;
 
-       if (usb_pipeint(urb->pipe)) {
+       if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
                ep->interval = urb->interval;
-       } else if (usb_pipeisoc(urb->pipe)) {
+       } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
                ep->interval = urb->interval;
                ep->start_frame = urb->start_frame;
                ep->error_count = urb->error_count;
        }
        ep->numdesc = urb->number_of_packets;
-       if (usb_pipeisoc(urb->pipe) && urb->number_of_packets > 0) {
+       if (ep->xfertype == USB_ENDPOINT_XFER_ISOC &&
+                       urb->number_of_packets > 0) {
                if ((ndesc = urb->number_of_packets) > ISODESC_MAX)
                        ndesc = ISODESC_MAX;
                fp = urb->iso_frame_desc;
@@ -247,13 +248,13 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
 static void mon_text_submit(void *data, struct urb *urb)
 {
        struct mon_reader_text *rp = data;
-       mon_text_event(rp, urb, 'S');
+       mon_text_event(rp, urb, 'S', -EINPROGRESS);
 }
 
-static void mon_text_complete(void *data, struct urb *urb)
+static void mon_text_complete(void *data, struct urb *urb, int status)
 {
        struct mon_reader_text *rp = data;
-       mon_text_event(rp, urb, 'C');
+       mon_text_event(rp, urb, 'C', status);
 }
 
 static void mon_text_error(void *data, struct urb *urb, int error)
@@ -268,9 +269,12 @@ static void mon_text_error(void *data, struct urb *urb, int error)
        }
 
        ep->type = 'E';
-       ep->pipe = urb->pipe;
        ep->id = (unsigned long) urb;
        ep->busnum = 0;
+       ep->devnum = urb->dev->devnum;
+       ep->epnum = usb_endpoint_num(&urb->ep->desc);
+       ep->xfertype = usb_endpoint_type(&urb->ep->desc);
+       ep->is_in = usb_urb_dir_in(urb);
        ep->tstamp = 0;
        ep->length = 0;
        ep->status = error;
@@ -413,10 +417,10 @@ static ssize_t mon_text_read_u(struct file *file, char __user *buf,
        mon_text_read_head_u(rp, &ptr, ep);
        if (ep->type == 'E') {
                mon_text_read_statset(rp, &ptr, ep);
-       } else if (usb_pipeisoc(ep->pipe)) {
+       } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
                mon_text_read_isostat(rp, &ptr, ep);
                mon_text_read_isodesc(rp, &ptr, ep);
-       } else if (usb_pipeint(ep->pipe)) {
+       } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
                mon_text_read_intstat(rp, &ptr, ep);
        } else {
                mon_text_read_statset(rp, &ptr, ep);
@@ -468,18 +472,17 @@ static void mon_text_read_head_t(struct mon_reader_text *rp,
 {
        char udir, utype;
 
-       udir = usb_pipein(ep->pipe) ? 'i' : 'o';
-       switch (usb_pipetype(ep->pipe)) {
-       case PIPE_ISOCHRONOUS:  utype = 'Z'; break;
-       case PIPE_INTERRUPT:    utype = 'I'; break;
-       case PIPE_CONTROL:      utype = 'C'; break;
+       udir = (ep->is_in ? 'i' : 'o');
+       switch (ep->xfertype) {
+       case USB_ENDPOINT_XFER_ISOC:    utype = 'Z'; break;
+       case USB_ENDPOINT_XFER_INT:     utype = 'I'; break;
+       case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break;
        default: /* PIPE_BULK */  utype = 'B';
        }
        p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
            "%lx %u %c %c%c:%03u:%02u",
            ep->id, ep->tstamp, ep->type,
-           utype, udir,
-           usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+           utype, udir, ep->devnum, ep->epnum);
 }
 
 static void mon_text_read_head_u(struct mon_reader_text *rp,
@@ -487,18 +490,17 @@ static void mon_text_read_head_u(struct mon_reader_text *rp,
 {
        char udir, utype;
 
-       udir = usb_pipein(ep->pipe) ? 'i' : 'o';
-       switch (usb_pipetype(ep->pipe)) {
-       case PIPE_ISOCHRONOUS:  utype = 'Z'; break;
-       case PIPE_INTERRUPT:    utype = 'I'; break;
-       case PIPE_CONTROL:      utype = 'C'; break;
+       udir = (ep->is_in ? 'i' : 'o');
+       switch (ep->xfertype) {
+       case USB_ENDPOINT_XFER_ISOC:    utype = 'Z'; break;
+       case USB_ENDPOINT_XFER_INT:     utype = 'I'; break;
+       case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break;
        default: /* PIPE_BULK */  utype = 'B';
        }
        p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
            "%lx %u %c %c%c:%d:%03u:%u",
            ep->id, ep->tstamp, ep->type,
-           utype, udir,
-           ep->busnum, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+           utype, udir, ep->busnum, ep->devnum, ep->epnum);
 }
 
 static void mon_text_read_statset(struct mon_reader_text *rp,
index f68ad6d..f5d84ff 100644 (file)
@@ -46,7 +46,7 @@ struct mon_reader {
 
        void (*rnf_submit)(void *data, struct urb *urb);
        void (*rnf_error)(void *data, struct urb *urb, int error);
-       void (*rnf_complete)(void *data, struct urb *urb);
+       void (*rnf_complete)(void *data, struct urb *urb, int status);
 };
 
 void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
index 43d6db6..99fefed 100644 (file)
@@ -92,6 +92,16 @@ config USB_SERIAL_BELKIN
          To compile this driver as a module, choose M here: the
          module will be called belkin_sa.
 
+config USB_SERIAL_CH341
+       tristate "USB Winchiphead CH341 Single Port Serial Driver"
+       depends on USB_SERIAL
+       help
+         Say Y here if you want to use a Winchiphead CH341 single port
+         USB to serial adapter.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ch341.
+
 config USB_SERIAL_WHITEHEAT
        tristate "USB ConnectTech WhiteHEAT Serial Driver"
        depends on USB_SERIAL
index 07a976e..d6fb384 100644 (file)
@@ -15,6 +15,7 @@ obj-$(CONFIG_USB_SERIAL_AIRCABLE)             += aircable.o
 obj-$(CONFIG_USB_SERIAL_AIRPRIME)              += airprime.o
 obj-$(CONFIG_USB_SERIAL_ARK3116)               += ark3116.o
 obj-$(CONFIG_USB_SERIAL_BELKIN)                        += belkin_sa.o
+obj-$(CONFIG_USB_SERIAL_CH341)                 += ch341.o
 obj-$(CONFIG_USB_SERIAL_CP2101)                        += cp2101.o
 obj-$(CONFIG_USB_SERIAL_CYBERJACK)             += cyberjack.o
 obj-$(CONFIG_USB_SERIAL_CYPRESS_M8)            += cypress_m8.o
index c9fd486..2a8e537 100644 (file)
@@ -172,11 +172,6 @@ static void ark3116_set_termios(struct usb_serial_port *port,
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
-       if (!port->tty || !port->tty->termios) {
-               dbg("%s - no tty structures", __FUNCTION__);
-               return;
-       }
-
        spin_lock_irqsave(&priv->lock, flags);
        if (!priv->termios_initialized) {
                *(port->tty->termios) = tty_std_termios;
index a47a24f..0b14aea 100644 (file)
@@ -36,6 +36,16 @@ static int usb_serial_device_match (struct device *dev, struct device_driver *dr
        return 0;
 }
 
+static ssize_t show_port_number(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct usb_serial_port *port = to_usb_serial_port(dev);
+
+       return sprintf(buf, "%d\n", port->number - port->serial->minor);
+}
+
+static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL);
+
 static int usb_serial_device_probe (struct device *dev)
 {
        struct usb_serial_driver *driver;
@@ -62,6 +72,10 @@ static int usb_serial_device_probe (struct device *dev)
                        goto exit;
        }
 
+       retval = device_create_file(dev, &dev_attr_port_number);
+       if (retval)
+               goto exit;
+
        minor = port->number;
        tty_register_device (usb_serial_tty_driver, minor, dev);
        dev_info(&port->serial->dev->dev, 
@@ -84,6 +98,8 @@ static int usb_serial_device_remove (struct device *dev)
                return -ENODEV;
        }
 
+       device_remove_file(&port->dev, &dev_attr_port_number);
+
        driver = port->serial->type;
        if (driver->port_remove) {
                if (!try_module_get(driver->driver.owner)) {
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
new file mode 100644 (file)
index 0000000..6b252ce
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2007, Frank A Kingswood <frank@kingswood-consulting.co.uk>
+ *
+ * ch341.c implements a serial port driver for the Winchiphead CH341.
+ *
+ * The CH341 device can be used to implement an RS232 asynchronous
+ * serial port, an IEEE-1284 parallel printer port or a memory-like
+ * interface. In all cases the CH341 supports an I2C interface as well.
+ * This driver only supports the asynchronous serial interface.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/serial.h>
+
+#define DEFAULT_BAUD_RATE 2400
+#define DEFAULT_TIMEOUT   1000
+
+static int debug;
+
+static struct usb_device_id id_table [] = {
+       { USB_DEVICE(0x4348, 0x5523) },
+       { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+struct ch341_private {
+       unsigned baud_rate;
+       u8 dtr;
+       u8 rts;
+};
+
+static int ch341_control_out(struct usb_device *dev, u8 request,
+                            u16 value, u16 index)
+{
+       int r;
+       dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40,
+               (int)request, (int)value, (int)index);
+
+       r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
+                           USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+                           value, index, NULL, 0, DEFAULT_TIMEOUT);
+
+       return r;
+}
+
+static int ch341_control_in(struct usb_device *dev,
+                           u8 request, u16 value, u16 index,
+                           char *buf, unsigned bufsize)
+{
+       int r;
+       dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40,
+               (int)request, (int)value, (int)index, buf, (int)bufsize);
+
+       r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
+                           USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                           value, index, buf, bufsize, DEFAULT_TIMEOUT);
+       return r;
+}
+
+static int ch341_set_baudrate(struct usb_device *dev,
+                             struct ch341_private *priv)
+{
+       short a, b;
+       int r;
+
+       dbg("ch341_set_baudrate(%d)", priv->baud_rate);
+       switch (priv->baud_rate) {
+       case 2400:
+               a = 0xd901;
+               b = 0x0038;
+               break;
+       case 4800:
+               a = 0x6402;
+               b = 0x001f;
+               break;
+       case 9600:
+               a = 0xb202;
+               b = 0x0013;
+               break;
+       case 19200:
+               a = 0xd902;
+               b = 0x000d;
+               break;
+       case 38400:
+               a = 0x6403;
+               b = 0x000a;
+               break;
+       case 115200:
+               a = 0xcc03;
+               b = 0x0008;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       r = ch341_control_out(dev, 0x9a, 0x1312, a);
+       if (!r)
+               r = ch341_control_out(dev, 0x9a, 0x0f2c, b);
+
+       return r;
+}
+
+static int ch341_set_handshake(struct usb_device *dev,
+                              struct ch341_private *priv)
+{
+       dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts);
+       return ch341_control_out(dev, 0xa4,
+               ~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0);
+}
+
+static int ch341_get_status(struct usb_device *dev)
+{
+       char *buffer;
+       int r;
+       const unsigned size = 8;
+
+       dbg("ch341_get_status()");
+
+       buffer = kmalloc(size, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size);
+       if ( r < 0)
+               goto out;
+
+       /* Not having the datasheet for the CH341, we ignore the bytes returned
+        * from the device. Return error if the device did not respond in time.
+        */
+       r = 0;
+
+out:   kfree(buffer);
+       return r;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
+{
+       char *buffer;
+       int r;
+       const unsigned size = 8;
+
+       dbg("ch341_configure()");
+
+       buffer = kmalloc(size, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       /* expect two bytes 0x27 0x00 */
+       r = ch341_control_in(dev, 0x5f, 0, 0, buffer, size);
+       if (r < 0)
+               goto out;
+
+       r = ch341_control_out(dev, 0xa1, 0, 0);
+       if (r < 0)
+               goto out;
+
+       r = ch341_set_baudrate(dev, priv);
+       if (r < 0)
+               goto out;
+
+       /* expect two bytes 0x56 0x00 */
+       r = ch341_control_in(dev, 0x95, 0x2518, 0, buffer, size);
+       if (r < 0)
+               goto out;
+
+       r = ch341_control_out(dev, 0x9a, 0x2518, 0x0050);
+       if (r < 0)
+               goto out;
+
+       /* expect 0xff 0xee */
+       r = ch341_get_status(dev);
+       if (r < 0)
+               goto out;
+
+       r = ch341_control_out(dev, 0xa1, 0x501f, 0xd90a);
+       if (r < 0)
+               goto out;
+
+       r = ch341_set_baudrate(dev, priv);
+       if (r < 0)
+               goto out;
+
+       r = ch341_set_handshake(dev, priv);
+       if (r < 0)
+               goto out;
+
+       /* expect 0x9f 0xee */
+       r = ch341_get_status(dev);
+
+out:   kfree(buffer);
+       return r;
+}
+
+/* allocate private data */
+static int ch341_attach(struct usb_serial *serial)
+{
+       struct ch341_private *priv;
+       int r;
+
+       dbg("ch341_attach()");
+
+       /* private data */
+       priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->baud_rate = DEFAULT_BAUD_RATE;
+       priv->dtr = 1;
+       priv->rts = 1;
+
+       r = ch341_configure(serial->dev, priv);
+       if (r < 0)
+               goto error;
+
+       usb_set_serial_port_data(serial->port[0], priv);
+       return 0;
+
+error: kfree(priv);
+       return r;
+}
+
+/* open this device, set default parameters */
+static int ch341_open(struct usb_serial_port *port, struct file *filp)
+{
+       struct usb_serial *serial = port->serial;
+       struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]);
+       int r;
+
+       dbg("ch341_open()");
+
+       priv->baud_rate = DEFAULT_BAUD_RATE;
+       priv->dtr = 1;
+       priv->rts = 1;
+
+       r = ch341_configure(serial->dev, priv);
+       if (r)
+               goto out;
+
+       r = ch341_set_handshake(serial->dev, priv);
+       if (r)
+               goto out;
+
+       r = ch341_set_baudrate(serial->dev, priv);
+       if (r)
+               goto out;
+
+       r = usb_serial_generic_open(port, filp);
+
+out:   return r;
+}
+
+/* Old_termios contains the original termios settings and
+ * tty->termios contains the new setting to be used.
+ */
+static void ch341_set_termios(struct usb_serial_port *port,
+                             struct ktermios *old_termios)
+{
+       struct ch341_private *priv = usb_get_serial_port_data(port);
+       struct tty_struct *tty = port->tty;
+       unsigned baud_rate;
+
+       dbg("ch341_set_termios()");
+
+       if (!tty || !tty->termios)
+               return;
+
+       baud_rate = tty_get_baud_rate(tty);
+
+       switch (baud_rate) {
+       case 2400:
+       case 4800:
+       case 9600:
+       case 19200:
+       case 38400:
+       case 115200:
+               priv->baud_rate = baud_rate;
+               break;
+       default:
+               dbg("Rate %d not supported, using %d",
+                       baud_rate, DEFAULT_BAUD_RATE);
+               priv->baud_rate = DEFAULT_BAUD_RATE;
+       }
+
+       ch341_set_baudrate(port->serial->dev, priv);
+
+       /* Unimplemented:
+        * (cflag & CSIZE) : data bits [5, 8]
+        * (cflag & PARENB) : parity {NONE, EVEN, ODD}
+        * (cflag & CSTOPB) : stop bits [1, 2]
+        */
+}
+
+static struct usb_driver ch341_driver = {
+       .name           = "ch341",
+       .probe          = usb_serial_probe,
+       .disconnect     = usb_serial_disconnect,
+       .id_table       = id_table,
+       .no_dynamic_id  = 1,
+};
+
+static struct usb_serial_driver ch341_device = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "ch341-uart",
+       },
+       .id_table         = id_table,
+       .usb_driver       = &ch341_driver,
+       .num_interrupt_in = NUM_DONT_CARE,
+       .num_bulk_in      = 1,
+       .num_bulk_out     = 1,
+       .num_ports        = 1,
+       .open             = ch341_open,
+       .set_termios      = ch341_set_termios,
+       .attach           = ch341_attach,
+};
+
+static int __init ch341_init(void)
+{
+       int retval;
+
+       retval = usb_serial_register(&ch341_device);
+       if (retval)
+               return retval;
+       retval = usb_register(&ch341_driver);
+       if (retval)
+               usb_serial_deregister(&ch341_device);
+       return retval;
+}
+
+static void __exit ch341_exit(void)
+{
+       usb_deregister(&ch341_driver);
+       usb_serial_deregister(&ch341_device);
+}
+
+module_init(ch341_init);
+module_exit(ch341_exit);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+/* EOF ch341.c */
index 33f6ee5..eb7df18 100644 (file)
@@ -53,6 +53,7 @@ static void cp2101_shutdown(struct usb_serial*);
 static int debug;
 
 static struct usb_device_id id_table [] = {
+       { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
        { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
        { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
        { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
@@ -521,7 +522,7 @@ static void cp2101_set_termios (struct usb_serial_port *port,
 
        dbg("%s - port %d", __FUNCTION__, port->number);
 
-       if ((!port->tty) || (!port->tty->termios)) {
+       if (!port->tty || !port->tty->termios) {
                dbg("%s - no tty structures", __FUNCTION__);
                return;
        }
index 2d04585..e4c248c 100644 (file)
@@ -1169,7 +1169,9 @@ static void remove_sysfs_attrs(struct usb_serial_port *port)
        /* XXX see create_sysfs_attrs */
        if (priv->chip_type != SIO) {
                device_remove_file(&port->dev, &dev_attr_event_char);
-               if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) {
+               if (priv->chip_type == FT232BM ||
+                   priv->chip_type == FT2232C ||
+                   priv->chip_type == FT232RL) {
                        device_remove_file(&port->dev, &dev_attr_latency_timer);
                }
        }
@@ -2102,6 +2104,7 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
        case FT8U232AM:
        case FT232BM:
        case FT2232C:
+       case FT232RL:
                /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
                   format as the data returned from the in point */
                if ((ret = usb_control_msg(port->serial->dev,
index 4092f6d..b5194dc 100644 (file)
@@ -24,26 +24,6 @@ static struct usb_device_id id_table [] = {
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static int funsoft_ioctl(struct usb_serial_port *port, struct file *file,
-                        unsigned int cmd, unsigned long arg)
-{
-       struct ktermios t;
-
-       dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd);
-
-       if (cmd == TCSETSF) {
-               if (user_termios_to_kernel_termios(&t, (struct termios __user *)arg))
-                       return -EFAULT;
-
-               dbg("%s - iflag:%x oflag:%x cflag:%x lflag:%x", __FUNCTION__,
-                   t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag);
-
-               if (!(t.c_lflag & ICANON))
-                       return -EINVAL;
-       }
-       return -ENOIOCTLCMD;
-}
-
 static struct usb_driver funsoft_driver = {
        .name =         "funsoft",
        .probe =        usb_serial_probe,
@@ -63,7 +43,6 @@ static struct usb_serial_driver funsoft_device = {
        .num_bulk_in =          NUM_DONT_CARE,
        .num_bulk_out =         NUM_DONT_CARE,
        .num_ports =            1,
-       .ioctl =                funsoft_ioctl,
 };
 
 static int __init funsoft_init(void)
index 6a3a704..e836ad0 100644 (file)
@@ -256,6 +256,7 @@ static struct usb_device_id ipaq_id_table [] = {
        { USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */
        { USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */
        { USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH USB Modem */
+       { USB_DEVICE(0x04DD, 0x91AC) }, /* SHARP WS011SH USB Modem */
        { USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */
        { USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */
        { USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */
@@ -646,11 +647,13 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
        kfree(port->bulk_out_buffer);
        port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
        if (port->bulk_in_buffer == NULL) {
+               port->bulk_out_buffer = NULL; /* prevent double free */
                goto enomem;
        }
        port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
        if (port->bulk_out_buffer == NULL) {
                kfree(port->bulk_in_buffer);
+               port->bulk_in_buffer = NULL;
                goto enomem;
        }
        port->read_urb->transfer_buffer = port->bulk_in_buffer;
index 5a4127e..90e3216 100644 (file)
@@ -728,24 +728,32 @@ static void klsi_105_set_termios (struct usb_serial_port *port,
 #endif
                }
                
-               switch(cflag & CBAUD) {
-               case B0: /* handled below */
+               switch(tty_get_baud_rate(port->tty)) {
+               case 0: /* handled below */
                        break;
-               case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200;
+               case 1200:
+                       priv->cfg.baudrate = kl5kusb105a_sio_b1200;
                        break;
-               case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400;
+               case 2400:
+                       priv->cfg.baudrate = kl5kusb105a_sio_b2400;
                        break;
-               case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800;
+               case 4800:
+                       priv->cfg.baudrate = kl5kusb105a_sio_b4800;
                        break;
-               case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+               case 9600:
+                       priv->cfg.baudrate = kl5kusb105a_sio_b9600;
                        break;
-               case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200;
+               case 19200:
+                       priv->cfg.baudrate = kl5kusb105a_sio_b19200;
                        break;
-               case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400;
+               case 38400:
+                       priv->cfg.baudrate = kl5kusb105a_sio_b38400;
                        break;
-               case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600;
+               case 57600:
+                       priv->cfg.baudrate = kl5kusb105a_sio_b57600;
                        break;
-               case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200;
+               case 115200:
+                       priv->cfg.baudrate = kl5kusb105a_sio_b115200;
                        break;
                default:
                        err("KLSI USB->Serial converter:"
index 02a86db..6f22419 100644 (file)
@@ -82,6 +82,7 @@ static int  kobil_tiocmset(struct usb_serial_port *port, struct file *file,
                           unsigned int set, unsigned int clear);
 static void kobil_read_int_callback( struct urb *urb );
 static void kobil_write_callback( struct urb *purb );
+static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old);
 
 
 static struct usb_device_id id_table [] = {
@@ -119,6 +120,7 @@ static struct usb_serial_driver kobil_device = {
        .attach =               kobil_startup,
        .shutdown =             kobil_shutdown,
        .ioctl =                kobil_ioctl,
+       .set_termios =          kobil_set_termios,
        .tiocmget =             kobil_tiocmget,
        .tiocmset =             kobil_tiocmset,
        .open =                 kobil_open,
@@ -137,7 +139,6 @@ struct kobil_private {
        int cur_pos; // index of the next char to send in buf
        __u16 device_type;
        int line_state;
-       struct ktermios internal_termios;
 };
 
 
@@ -216,7 +217,7 @@ static void kobil_shutdown (struct usb_serial *serial)
 
 static int kobil_open (struct usb_serial_port *port, struct file *filp)
 {
-       int i, result = 0;
+       int result = 0;
        struct kobil_private *priv;
        unsigned char *transfer_buffer;
        int transfer_buffer_length = 8;
@@ -242,16 +243,6 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
        port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
        port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D)
        
-       // set up internal termios structure 
-       priv->internal_termios.c_iflag = port->tty->termios->c_iflag;
-       priv->internal_termios.c_oflag = port->tty->termios->c_oflag;
-       priv->internal_termios.c_cflag = port->tty->termios->c_cflag;
-       priv->internal_termios.c_lflag = port->tty->termios->c_lflag;
-
-       for (i=0; i<NCCS; i++) {
-               priv->internal_termios.c_cc[i] = port->tty->termios->c_cc[i];
-       }
-       
        // allocate memory for transfer buffer
        transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
        if (! transfer_buffer) {
@@ -607,102 +598,79 @@ static int  kobil_tiocmset(struct usb_serial_port *port, struct file *file,
        return (result < 0) ? result : 0;
 }
 
-
-static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
-                       unsigned int cmd, unsigned long arg)
+static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old)
 {
        struct kobil_private * priv;
        int result;
        unsigned short urb_val = 0;
-       unsigned char *transfer_buffer;
-       int transfer_buffer_length = 8;
-       char *settings;
-       void __user *user_arg = (void __user *)arg;
+       int c_cflag = port->tty->termios->c_cflag;
+       speed_t speed;
+       void * settings;
 
        priv = usb_get_serial_port_data(port);
-       if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) {
+       if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
                // This device doesn't support ioctl calls
-               return 0;
-       }
-
-       switch (cmd) {
-       case TCGETS:   // 0x5401
-               if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) {
-                       dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
-                       return -EFAULT;
-               }
-               if (kernel_termios_to_user_termios((struct ktermios __user *)arg,
-                                                  &priv->internal_termios))
-                       return -EFAULT;
-               return 0;
-
-       case TCSETS:   // 0x5402
-               if (!(port->tty->termios)) {
-                       dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number);
-                       return -ENOTTY;
-               }
-               if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) {
-                       dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
-                       return -EFAULT;
-               }
-               if (user_termios_to_kernel_termios(&priv->internal_termios,
-                                                  (struct ktermios __user *)arg))
-                       return -EFAULT;
-               
-               settings = kzalloc(50, GFP_KERNEL);
-               if (! settings) {
-                       return -ENOBUFS;
-               }
+               return;
 
-               switch (priv->internal_termios.c_cflag & CBAUD) {
-               case B1200:
+       switch (speed = tty_get_baud_rate(port->tty)) {
+               case 1200:
                        urb_val = SUSBCR_SBR_1200;
-                       strcat(settings, "1200 ");
                        break;
-               case B9600:
+               case 9600:
                default:
                        urb_val = SUSBCR_SBR_9600;
-                       strcat(settings, "9600 ");
                        break;
-               }
+       }
+       urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
+
+       settings = kzalloc(50, GFP_KERNEL);
+       if (! settings)
+               return;
 
-               urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
-               strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit ");
+       sprintf(settings, "%d ", speed);
 
-               if (priv->internal_termios.c_cflag & PARENB) {
-                       if  (priv->internal_termios.c_cflag & PARODD) {
-                               urb_val |= SUSBCR_SPASB_OddParity;
-                               strcat(settings, "Odd Parity");
-                       } else {
-                               urb_val |= SUSBCR_SPASB_EvenParity;
-                               strcat(settings, "Even Parity");
-                       }
+       if (c_cflag & PARENB) {
+               if  (c_cflag & PARODD) {
+                       urb_val |= SUSBCR_SPASB_OddParity;
+                       strcat(settings, "Odd Parity");
                } else {
-                       urb_val |= SUSBCR_SPASB_NoParity;
-                       strcat(settings, "No Parity");
+                       urb_val |= SUSBCR_SPASB_EvenParity;
+                       strcat(settings, "Even Parity");
                }
-               dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings );
+       } else {
+               urb_val |= SUSBCR_SPASB_NoParity;
+               strcat(settings, "No Parity");
+       }
 
-               result = usb_control_msg( port->serial->dev, 
-                                         usb_rcvctrlpipe(port->serial->dev, 0 ), 
-                                         SUSBCRequest_SetBaudRateParityAndStopBits,
-                                         USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
-                                         urb_val,
-                                         0,
-                                         settings,
-                                         0,
-                                         KOBIL_TIMEOUT
-                       );
+       result = usb_control_msg( port->serial->dev,
+                                 usb_rcvctrlpipe(port->serial->dev, 0 ),
+                                 SUSBCRequest_SetBaudRateParityAndStopBits,
+                                 USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+                                 urb_val,
+                                 0,
+                                 settings,
+                                 0,
+                                 KOBIL_TIMEOUT
+               );
+       kfree(settings);
+}
 
-               dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result);
-               kfree(settings);
+static int kobil_ioctl(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+       struct kobil_private * priv = usb_get_serial_port_data(port);
+       unsigned char *transfer_buffer;
+       int transfer_buffer_length = 8;
+       int result;
+
+       if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
+               // This device doesn't support ioctl calls
                return 0;
 
+       switch (cmd) {
        case TCFLSH:   // 0x540B
                transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL);
-               if (! transfer_buffer) {
+               if (! transfer_buffer)
                        return -ENOBUFS;
-               }
 
                result = usb_control_msg( port->serial->dev, 
                                          usb_rcvctrlpipe(port->serial->dev, 0 ), 
@@ -716,15 +684,13 @@ static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
                        );
                
                dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result);
-
                kfree(transfer_buffer);
-               return ((result < 0) ? -EFAULT : 0);
-
+               return (result < 0) ? -EFAULT : 0;
+       default:
+               return -ENOIOCTLCMD;
        }
-       return -ENOIOCTLCMD;
 }
 
-
 static int __init kobil_init (void)
 {
        int retval;
index e08c9bb..0dc99f7 100644 (file)
@@ -206,20 +206,20 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value
                }
        } else {
                switch (value) {
-                       case 300: break;
-                       case 600: break;
-                       case 1200: break;
-                       case 2400: break;
-                       case 4800: break;
-                       case 9600: break;
-                       case 19200: break;
-                       case 38400: break;
-                       case 57600: break;
-                       case 115200: break;
-                       default:
-                               err("MCT USB-RS232: unsupported baudrate request 0x%x,"
-                                   " using default of B9600", value);
-                               value = 9600;
+               case 300: break;
+               case 600: break;
+               case 1200: break;
+               case 2400: break;
+               case 4800: break;
+               case 9600: break;
+               case 19200: break;
+               case 38400: break;
+               case 57600: break;
+               case 115200: break;
+               default:
+                       err("MCT USB-RS232: unsupported baudrate request 0x%x,"
+                           " using default of B9600", value);
+                       value = 9600;
                }
                return 115200/value;
        }
index 64f3f66..d198611 100644 (file)
@@ -1144,7 +1144,7 @@ static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
        if (size == 0)
                return NULL;
 
-       pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
+       pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
        if (pb == NULL)
                return NULL;
 
index f9f85f5..1da57fd 100644 (file)
@@ -73,6 +73,7 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
        { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
        { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
+       { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
        { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
        { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
        { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
index f9a71d0..c39bace 100644 (file)
@@ -59,6 +59,7 @@
 #define SIEMENS_PRODUCT_ID_SX1 0x0001
 #define SIEMENS_PRODUCT_ID_X65 0x0003
 #define SIEMENS_PRODUCT_ID_X75 0x0004
+#define SIEMENS_PRODUCT_ID_EF81        0x0005
 
 #define SYNTECH_VENDOR_ID      0x0745
 #define SYNTECH_PRODUCT_ID     0x0001
index 51669b7..4e6dcc1 100644 (file)
@@ -90,18 +90,12 @@ MODULE_AUTHOR (DRIVER_AUTHOR);
 MODULE_DESCRIPTION (DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-#if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT)
-#error "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT"
-#endif
-
-#if ! defined(CONFIG_USBD_SAFE_SERIAL_VENDOR)
 static __u16 vendor;           // no default
 static __u16 product;          // no default
 module_param(vendor, ushort, 0);
 MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)");
 module_param(product, ushort, 0);
 MODULE_PARM_DESC(product, "User specified USB idProduct (required)");
-#endif
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
@@ -145,11 +139,6 @@ static struct usb_device_id id_table[] = {
        {MY_USB_DEVICE (0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},  // Collie 
        {MY_USB_DEVICE (0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},  // Collie 
        {MY_USB_DEVICE (0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},  // Sharp tmp
-#if defined(CONFIG_USB_SAFE_SERIAL_VENDOR)
-       {MY_USB_DEVICE
-        (CONFIG_USB_SAFE_SERIAL_VENDOR, CONFIG_USB_SAFE_SERIAL_PRODUCT, CDC_DEVICE_CLASS,
-         LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
-#endif
        // extra null entry for module 
        // vendor/produc parameters
        {MY_USB_DEVICE (0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
index 9bf01a5..4b1bd7d 100644 (file)
@@ -578,6 +578,17 @@ static void kill_traffic(struct usb_serial_port *port)
 {
        usb_kill_urb(port->read_urb);
        usb_kill_urb(port->write_urb);
+       /*
+        * This is tricky.
+        * Some drivers submit the read_urb in the
+        * handler for the write_urb or vice versa
+        * this order determines the order in which
+        * usb_kill_urb() must be used to reliably
+        * kill the URBs. As it is unknown here,
+        * both orders must be used in turn.
+        * The call below is not redundant.
+        */
+       usb_kill_urb(port->read_urb);
        usb_kill_urb(port->interrupt_in_urb);
        usb_kill_urb(port->interrupt_out_urb);
 }
@@ -651,16 +662,14 @@ exit:
 
 static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
 {
-       struct list_head *p;
        const struct usb_device_id *id;
-       struct usb_serial_driver *t;
+       struct usb_serial_driver *drv;
 
        /* Check if the usb id matches a known device */
-       list_for_each(p, &usb_serial_driver_list) {
-               t = list_entry(p, struct usb_serial_driver, driver_list);
-               id = get_iface_id(t, iface);
+       list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
+               id = get_iface_id(drv, iface);
                if (id)
-                       return t;
+                       return drv;
        }
 
        return NULL;
@@ -800,9 +809,6 @@ int usb_serial_probe(struct usb_interface *interface,
        /* END HORRIBLE HACK FOR PL2303 */
 #endif
 
-       /* found all that we need */
-       dev_info(&interface->dev, "%s converter detected\n", type->description);
-
 #ifdef CONFIG_USB_SERIAL_GENERIC
        if (type == &usb_serial_generic_device) {
                num_ports = num_bulk_out;
@@ -836,6 +842,24 @@ int usb_serial_probe(struct usb_interface *interface,
        serial->num_interrupt_in = num_interrupt_in;
        serial->num_interrupt_out = num_interrupt_out;
 
+       /* check that the device meets the driver's requirements */
+       if ((type->num_interrupt_in != NUM_DONT_CARE &&
+                               type->num_interrupt_in != num_interrupt_in)
+                       || (type->num_interrupt_out != NUM_DONT_CARE &&
+                               type->num_interrupt_out != num_interrupt_out)
+                       || (type->num_bulk_in != NUM_DONT_CARE &&
+                               type->num_bulk_in != num_bulk_in)
+                       || (type->num_bulk_out != NUM_DONT_CARE &&
+                               type->num_bulk_out != num_bulk_out)) {
+               dbg("wrong number of endpoints");
+               kfree(serial);
+               return -EIO;
+       }
+
+       /* found all that we need */
+       dev_info(&interface->dev, "%s converter detected\n",
+                       type->description);
+
        /* create our ports, we need as many as the max endpoints */
        /* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
        max_endpoints = max(num_bulk_in, num_bulk_out);
index 30e08c0..7ee087f 100644 (file)
@@ -46,7 +46,6 @@ static int  visor_probe               (struct usb_serial *serial, const struct usb_device_id
 static int  visor_calc_num_ports(struct usb_serial *serial);
 static void visor_shutdown     (struct usb_serial *serial);
 static int  visor_ioctl                (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
-static void visor_set_termios  (struct usb_serial_port *port, struct ktermios *old_termios);
 static void visor_write_bulk_callback  (struct urb *urb);
 static void visor_read_bulk_callback   (struct urb *urb);
 static void visor_read_int_callback    (struct urb *urb);
@@ -203,7 +202,6 @@ static struct usb_serial_driver handspring_device = {
        .calc_num_ports =       visor_calc_num_ports,
        .shutdown =             visor_shutdown,
        .ioctl =                visor_ioctl,
-       .set_termios =          visor_set_termios,
        .write =                visor_write,
        .write_room =           visor_write_room,
        .chars_in_buffer =      visor_chars_in_buffer,
@@ -234,7 +232,6 @@ static struct usb_serial_driver clie_5_device = {
        .calc_num_ports =       visor_calc_num_ports,
        .shutdown =             visor_shutdown,
        .ioctl =                visor_ioctl,
-       .set_termios =          visor_set_termios,
        .write =                visor_write,
        .write_room =           visor_write_room,
        .chars_in_buffer =      visor_chars_in_buffer,
@@ -262,7 +259,6 @@ static struct usb_serial_driver clie_3_5_device = {
        .unthrottle =           visor_unthrottle,
        .attach =               clie_3_5_startup,
        .ioctl =                visor_ioctl,
-       .set_termios =          visor_set_termios,
        .write =                visor_write,
        .write_room =           visor_write_room,
        .chars_in_buffer =      visor_chars_in_buffer,
@@ -936,66 +932,6 @@ static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsign
        return -ENOIOCTLCMD;
 }
 
-
-/* This function is all nice and good, but we don't change anything based on it :) */
-static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
-{
-       unsigned int cflag;
-
-       dbg("%s - port %d", __FUNCTION__, port->number);
-
-       if ((!port->tty) || (!port->tty->termios)) {
-               dbg("%s - no tty structures", __FUNCTION__);
-               return;
-       }
-
-       cflag = port->tty->termios->c_cflag;
-
-       /* get the byte size */
-       switch (cflag & CSIZE) {
-               case CS5:       dbg("%s - data bits = 5", __FUNCTION__);   break;
-               case CS6:       dbg("%s - data bits = 6", __FUNCTION__);   break;
-               case CS7:       dbg("%s - data bits = 7", __FUNCTION__);   break;
-               default:
-               case CS8:       dbg("%s - data bits = 8", __FUNCTION__);   break;
-       }
-       
-       /* determine the parity */
-       if (cflag & PARENB)
-               if (cflag & PARODD)
-                       dbg("%s - parity = odd", __FUNCTION__);
-               else
-                       dbg("%s - parity = even", __FUNCTION__);
-       else
-               dbg("%s - parity = none", __FUNCTION__);
-
-       /* figure out the stop bits requested */
-       if (cflag & CSTOPB)
-               dbg("%s - stop bits = 2", __FUNCTION__);
-       else
-               dbg("%s - stop bits = 1", __FUNCTION__);
-
-       
-       /* figure out the flow control settings */
-       if (cflag & CRTSCTS)
-               dbg("%s - RTS/CTS is enabled", __FUNCTION__);
-       else
-               dbg("%s - RTS/CTS is disabled", __FUNCTION__);
-       
-       /* determine software flow control */
-       if (I_IXOFF(port->tty))
-               dbg("%s - XON/XOFF is enabled, XON = %2x, XOFF = %2x",
-                   __FUNCTION__, START_CHAR(port->tty), STOP_CHAR(port->tty));
-       else
-               dbg("%s - XON/XOFF is disabled", __FUNCTION__);
-
-       /* get the baud rate wanted */
-       dbg("%s - baud rate = %d", __FUNCTION__, tty_get_baud_rate(port->tty));
-
-       return;
-}
-
-
 static int __init visor_init (void)
 {
        int i, retval;
index 3a41740..ee5b42a 100644 (file)
@@ -90,3 +90,17 @@ int usb_stor_ucr61s2b_init(struct us_data *us)
 
        return (res ? -1 : 0);
 }
+
+/* This places the HUAWEI E220 devices in multi-port mode */
+int usb_stor_huawei_e220_init(struct us_data *us)
+{
+       int result;
+
+       us->iobuf[0] = 0x1;
+       result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+                                     USB_REQ_SET_FEATURE,
+                                     USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+                                     0x01, 0x0, us->iobuf, 0x1, 1000);
+       US_DEBUGP("usb_control_msg performing result is %d\n", result);
+       return (result ? 0 : -1);
+}
index e2967a4..ad3ffd4 100644 (file)
@@ -47,3 +47,6 @@ int usb_stor_euscsi_init(struct us_data *us);
 /* This function is required to activate all four slots on the UCR-61S2B
  * flash reader */
 int usb_stor_ucr61s2b_init(struct us_data *us);
+
+/* This places the HUAWEI E220 devices in multi-port mode */
+int usb_stor_huawei_e220_init(struct us_data *us);
index 5e27297..17ca4d7 100644 (file)
@@ -190,9 +190,6 @@ static int usbat_check_status(struct us_data *us)
        unsigned char *reply = us->iobuf;
        int rc;
 
-       if (!us)
-               return USB_STOR_TRANSPORT_ERROR;
-
        rc = usbat_get_status(us, reply);
        if (rc != USB_STOR_XFER_GOOD)
                return USB_STOR_TRANSPORT_FAILED;
index c6b78ba..9b656ec 100644 (file)
@@ -198,7 +198,7 @@ UNUSUAL_DEV(  0x0421, 0x044e, 0x0100, 0x0100,
                US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
 
 /* Reported by Bardur Arantsson <bardur@scientician.net> */
-UNUSUAL_DEV(  0x0421, 0x047c, 0x0370, 0x0370,
+UNUSUAL_DEV(  0x0421, 0x047c, 0x0370, 0x0610,
                "Nokia",
                "6131",
                US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -341,6 +341,13 @@ UNUSUAL_DEV(  0x04b0, 0x040d, 0x0100, 0x0100,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_FIX_CAPACITY),
 
+/* Reported by Graber and Mike Pagano <mpagano-kernel@mpagano.com> */
+UNUSUAL_DEV(  0x04b0, 0x040f, 0x0200, 0x0200,
+       "NIKON",
+       "NIKON DSC D200",
+       US_SC_DEVICE, US_PR_DEVICE, NULL,
+       US_FL_FIX_CAPACITY),
+
 /* Reported by Emil Larsson <emil@swip.net> */
 UNUSUAL_DEV(  0x04b0, 0x0411, 0x0100, 0x0101,
                "NIKON",
@@ -355,6 +362,20 @@ UNUSUAL_DEV(  0x04b0, 0x0413, 0x0110, 0x0110,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_FIX_CAPACITY),
 
+/* Reported by Paul Check <paul@openstreet.com> */
+UNUSUAL_DEV(  0x04b0, 0x0415, 0x0100, 0x0100,
+               "NIKON",
+               "NIKON DSC D2Xs",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_FIX_CAPACITY),
+
+/* Reported by Shan Destromp (shansan@gmail.com) */
+UNUSUAL_DEV(  0x04b0, 0x0417, 0x0100, 0x0100,
+               "NIKON",
+               "NIKON DSC D40X",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_FIX_CAPACITY),
+
 /* BENQ DC5330
  * Reported by Manuel Fombuena <mfombuena@ya.com> and
  * Frank Copeland <fjc@thingy.apana.org.au> */
@@ -1463,6 +1484,17 @@ UNUSUAL_DEV(  0x1210, 0x0003, 0x0100, 0x0100,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_IGNORE_RESIDUE ),
 
+/* Reported by fangxiaozhi <fangxiaozhi60675@huawei.com>
+ * and by linlei <linlei83@huawei.com>
+ * Patch reworked by Johann Wilhelm <johann.wilhelm@student.tugraz.at>
+ * This brings the HUAWEI E220 devices into multi-port mode
+ */
+UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0x0000,
+               "HUAWEI MOBILE",
+               "Mass Storage",
+               US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+               0),
+
 /* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */
 UNUSUAL_DEV(  0x132b, 0x000b, 0x0001, 0x0001,
                "Minolta",
index 5918166..3451e8d 100644 (file)
@@ -960,6 +960,10 @@ static int storage_probe(struct usb_interface *intf,
                return -ENOMEM;
        }
 
+       /*
+        * Allow 16-byte CDBs and thus > 2TB
+        */
+       host->max_cmd_len = 16;
        us = host_to_us(host);
        memset(us, 0, sizeof(struct us_data));
        mutex_init(&(us->dev_mutex));
index 8de11de..c815a40 100644 (file)
@@ -125,6 +125,7 @@ static int skel_open(struct inode *inode, struct file *file)
 
        /* save our object in the file's private structure */
        file->private_data = dev;
+       mutex_unlock(&dev->io_mutex);
 
 exit:
        return retval;
index 4f33a58..c5c8f16 100644 (file)
@@ -52,6 +52,7 @@ struct ep_device;
  * @ep_dev: ep_device for sysfs info
  * @extra: descriptors following this endpoint in the configuration
  * @extralen: how many bytes of "extra" are valid
+ * @enabled: URBs may be submitted to this endpoint
  *
  * USB requests are always queued to a given endpoint, identified by a
  * descriptor within an active interface in a given USB configuration.
@@ -64,6 +65,7 @@ struct usb_host_endpoint {
 
        unsigned char *extra;   /* Extra descriptors */
        int extralen;
+       int enabled;
 };
 
 /* host-side wrapper for one interface setting's parsed descriptors */
@@ -344,6 +346,11 @@ struct usb_tt;
  *
  * Usbcore drivers should not set usbdev->state directly.  Instead use
  * usb_set_device_state().
+ *
+ * @authorized: (user space) policy determines if we authorize this
+ *              device to be used or not. By default, wired USB
+ *              devices are authorized. WUSB devices are not, until we
+ *              authorize them from user space. FIXME -- complete doc
  */
 struct usb_device {
        int             devnum;         /* Address on USB bus */
@@ -376,8 +383,11 @@ struct usb_device {
        u8 portnum;                     /* Parent port number (origin 1) */
        u8 level;                       /* Number of USB hub ancestors */
 
+       unsigned can_submit:1;          /* URBs may be submitted */
        unsigned discon_suspended:1;    /* Disconnected while suspended */
        unsigned have_langid:1;         /* whether string_langid is valid */
+       unsigned authorized:1;          /* Policy has determined we can use it */
+       unsigned wusb:1;                /* Device is Wireless USB */
        int string_langid;              /* language ID for strings */
 
        /* static strings from the device */
@@ -405,6 +415,7 @@ struct usb_device {
 
        int pm_usage_cnt;               /* usage counter for autosuspend */
        u32 quirks;                     /* quirks of the whole device */
+       atomic_t urbnum;                /* number of URBs submitted for the whole device */
 
 #ifdef CONFIG_PM
        struct delayed_work autosuspend; /* for delayed autosuspends */
@@ -419,6 +430,7 @@ struct usb_device {
        unsigned persist_enabled:1;     /* USB_PERSIST enabled for this dev */
        unsigned autosuspend_disabled:1; /* autosuspend and autoresume */
        unsigned autoresume_disabled:1;  /*  disabled by the user */
+       unsigned skip_sys_resume:1;     /* skip the next system resume */
 #endif
 };
 #define        to_usb_device(d) container_of(d, struct usb_device, dev)
@@ -555,6 +567,29 @@ static inline int usb_make_path (struct usb_device *dev, char *buf,
 /*-------------------------------------------------------------------------*/
 
 /**
+ * usb_endpoint_num - get the endpoint's number
+ * @epd: endpoint to be checked
+ *
+ * Returns @epd's number: 0 to 15.
+ */
+static inline int usb_endpoint_num(const struct usb_endpoint_descriptor *epd)
+{
+       return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+}
+
+/**
+ * usb_endpoint_type - get the endpoint's transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns one of USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT} according
+ * to @epd's transfer type.
+ */
+static inline int usb_endpoint_type(const struct usb_endpoint_descriptor *epd)
+{
+       return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+}
+
+/**
  * usb_endpoint_dir_in - check if the endpoint has IN direction
  * @epd: endpoint to be checked
  *
@@ -996,6 +1031,8 @@ extern int usb_disabled(void);
 
 /*
  * urb->transfer_flags:
+ *
+ * Note: URB_DIR_IN/OUT is automatically set in usb_submit_urb().
  */
 #define URB_SHORT_NOT_OK       0x0001  /* report short reads as errors */
 #define URB_ISO_ASAP           0x0002  /* iso-only, urb->start_frame
@@ -1008,6 +1045,10 @@ extern int usb_disabled(void);
                                         * needed */
 #define URB_FREE_BUFFER                0x0100  /* Free transfer buffer with the URB */
 
+#define URB_DIR_IN             0x0200  /* Transfer from device to host */
+#define URB_DIR_OUT            0
+#define URB_DIR_MASK           URB_DIR_IN
+
 struct usb_iso_packet_descriptor {
        unsigned int offset;
        unsigned int length;            /* expected length */
@@ -1037,6 +1078,8 @@ typedef void (*usb_complete_t)(struct urb *);
  * @urb_list: For use by current owner of the URB.
  * @anchor_list: membership in the list of an anchor
  * @anchor: to anchor URBs to a common mooring
+ * @ep: Points to the endpoint's data structure.  Will eventually
+ *     replace @pipe.
  * @pipe: Holds endpoint number, direction, type, and more.
  *     Create these values with the eight macros available;
  *     usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is "ctrl"
@@ -1201,10 +1244,10 @@ 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 */
        void *hcpriv;                   /* private data for host controller */
        atomic_t use_count;             /* concurrent submissions counter */
        u8 reject;                      /* submissions will fail */
+       int unlinked;                   /* unlink error code */
 
        /* public: documented fields in the urb that can be used by drivers */
        struct list_head urb_list;      /* list head for use by the urb's
@@ -1212,6 +1255,7 @@ struct urb
        struct list_head anchor_list;   /* the URB may be anchored by the driver */
        struct usb_anchor *anchor;
        struct usb_device *dev;         /* (in) pointer to associated device */
+       struct usb_host_endpoint *ep;   /* (internal) pointer to endpoint struct */
        unsigned int pipe;              /* (in) pipe information */
        int status;                     /* (return) non-ISO status */
        unsigned int transfer_flags;    /* (in) URB_SHORT_NOT_OK | ...*/
@@ -1257,7 +1301,6 @@ static inline void usb_fill_control_urb (struct urb *urb,
                                         usb_complete_t complete_fn,
                                         void *context)
 {
-       spin_lock_init(&urb->lock);
        urb->dev = dev;
        urb->pipe = pipe;
        urb->setup_packet = setup_packet;
@@ -1288,7 +1331,6 @@ static inline void usb_fill_bulk_urb (struct urb *urb,
                                      usb_complete_t complete_fn,
                                      void *context)
 {
-       spin_lock_init(&urb->lock);
        urb->dev = dev;
        urb->pipe = pipe;
        urb->transfer_buffer = transfer_buffer;
@@ -1324,7 +1366,6 @@ static inline void usb_fill_int_urb (struct urb *urb,
                                     void *context,
                                     int interval)
 {
-       spin_lock_init(&urb->lock);
        urb->dev = dev;
        urb->pipe = pipe;
        urb->transfer_buffer = transfer_buffer;
@@ -1352,6 +1393,30 @@ extern void usb_unanchor_urb(struct urb *urb);
 extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
                                         unsigned int timeout);
 
+/**
+ * usb_urb_dir_in - check if an URB describes an IN transfer
+ * @urb: URB to be checked
+ *
+ * Returns 1 if @urb describes an IN transfer (device-to-host),
+ * otherwise 0.
+ */
+static inline int usb_urb_dir_in(struct urb *urb)
+{
+       return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN;
+}
+
+/**
+ * usb_urb_dir_out - check if an URB describes an OUT transfer
+ * @urb: URB to be checked
+ *
+ * Returns 1 if @urb describes an OUT transfer (host-to-device),
+ * otherwise 0.
+ */
+static inline int usb_urb_dir_out(struct urb *urb)
+{
+       return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_OUT;
+}
+
 void *usb_buffer_alloc (struct usb_device *dev, size_t size,
        gfp_t mem_flags, dma_addr_t *dma);
 void usb_buffer_free (struct usb_device *dev, size_t size,
@@ -1364,13 +1429,13 @@ void usb_buffer_unmap (struct urb *urb);
 #endif
 
 struct scatterlist;
-int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
+int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
                      struct scatterlist *sg, int nents);
 #if 0
-void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
                           struct scatterlist *sg, int n_hw_ents);
 #endif
-void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
                         struct scatterlist *sg, int n_hw_ents);
 
 /*-------------------------------------------------------------------*
similarity index 92%
rename from include/linux/usb_gadget.h
rename to include/linux/usb/gadget.h
index 4f59b2a..46705e9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * <linux/usb_gadget.h>
+ * <linux/usb/gadget.h>
  *
  * We call the USB code inside a Linux-based peripheral device a "gadget"
  * driver, except for the hardware-specific bus glue.  One USB host can
@@ -22,10 +22,10 @@ struct usb_ep;
 /**
  * struct usb_request - describes one i/o request
  * @buf: Buffer used for data.  Always provide this; some controllers
- *     only use PIO, or don't use DMA for some endpoints.
+ *     only use PIO, or don't use DMA for some endpoints.
  * @dma: DMA address corresponding to 'buf'.  If you don't set this
- *     field, and the usb controller needs one, it is responsible
- *     for mapping and unmapping the buffer.
+ *     field, and the usb controller needs one, it is responsible
+ *     for mapping and unmapping the buffer.
  * @length: Length of that data
  * @no_interrupt: If true, hints that no completion irq is needed.
  *     Helpful sometimes with deep request queues that are handled
@@ -45,16 +45,16 @@ struct usb_ep;
  * @context: For use by the completion callback
  * @list: For use by the gadget driver.
  * @status: Reports completion code, zero or a negative errno.
- *     Normally, faults block the transfer queue from advancing until
- *     the completion callback returns.
- *     Code "-ESHUTDOWN" indicates completion caused by device disconnect,
- *     or when the driver disabled the endpoint.
+ *     Normally, faults block the transfer queue from advancing until
+ *     the completion callback returns.
+ *     Code "-ESHUTDOWN" indicates completion caused by device disconnect,
+ *     or when the driver disabled the endpoint.
  * @actual: Reports bytes transferred to/from the buffer.  For reads (OUT
- *     transfers) this may be less than the requested length.  If the
- *     short_not_ok flag is set, short reads are treated as errors
- *     even when status otherwise indicates successful completion.
- *     Note that for writes (IN transfers) some data bytes may still
- *     reside in a device-side FIFO when the request is reported as
+ *     transfers) this may be less than the requested length.  If the
+ *     short_not_ok flag is set, short reads are treated as errors
+ *     even when status otherwise indicates successful completion.
+ *     Note that for writes (IN transfers) some data bytes may still
+ *     reside in a device-side FIFO when the request is reported as
  *     complete.
  *
  * These are allocated/freed through the endpoint they're used with.  The
@@ -128,7 +128,7 @@ struct usb_ep_ops {
  *     value can sometimes be reduced (hardware allowing), according to
  *      the endpoint descriptor used to configure the endpoint.
  * @driver_data:for use by the gadget driver.  all other fields are
- *     read-only to gadget drivers.
+ *     read-only to gadget drivers.
  *
  * the bus controller driver lists all the general purpose endpoints in
  * gadget->ep_list.  the control endpoint (gadget->ep0) is not in that list,
@@ -148,10 +148,10 @@ struct usb_ep {
 /**
  * usb_ep_enable - configure endpoint, making it usable
  * @ep:the endpoint being configured.  may not be the endpoint named "ep0".
- *     drivers discover endpoints through the ep_list of a usb_gadget.
+ *     drivers discover endpoints through the ep_list of a usb_gadget.
  * @desc:descriptor for desired behavior.  caller guarantees this pointer
- *     remains valid until the endpoint is disabled; the data byte order
- *     is little-endian (usb-standard).
+ *     remains valid until the endpoint is disabled; the data byte order
+ *     is little-endian (usb-standard).
  *
  * when configurations are set, or when interface settings change, the driver
  * will enable or disable the relevant endpoints.  while it is enabled, an
@@ -232,7 +232,7 @@ usb_ep_free_request (struct usb_ep *ep, struct usb_request *req)
  * @ep:the endpoint associated with the request
  * @req:the request being submitted
  * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't
- *     pre-allocate all necessary memory with the request.
+ *     pre-allocate all necessary memory with the request.
  *
  * This tells the device controller to perform the specified request through
  * that endpoint (reading or writing a buffer).  When the request completes,
@@ -415,7 +415,7 @@ struct usb_gadget_ops {
  * struct usb_gadget - represents a usb slave device
  * @ops: Function pointers used to access hardware-specific operations.
  * @ep0: Endpoint zero, used when reading or writing responses to
- *     driver setup() requests
+ *     driver setup() requests
  * @ep_list: List of other endpoints supported by the device.
  * @speed: Speed of current connection to USB host.
  * @is_dualspeed: True if the controller supports both high and full speed
@@ -432,7 +432,7 @@ struct usb_gadget_ops {
  * @b_hnp_enable: OTG device feature flag, indicating that the A-Host
  *     enabled HNP support.
  * @name: Identifies the controller hardware type.  Used in diagnostics
- *     and sometimes configuration.
+ *     and sometimes configuration.
  * @dev: Driver model state for this abstract device.
  *
  * Gadgets have a mostly-portable "gadget driver" implementing device
@@ -480,6 +480,39 @@ static inline void *get_gadget_data (struct usb_gadget *gadget)
 
 
 /**
+ * gadget_is_dualspeed - return true iff the hardware handles high speed
+ * @gadget: controller that might support both high and full speeds
+ */
+static inline int gadget_is_dualspeed(struct usb_gadget *g)
+{
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+       /* runtime test would check "g->is_dualspeed" ... that might be
+        * useful to work around hardware bugs, but is mostly pointless
+        */
+       return 1;
+#else
+       return 0;
+#endif
+}
+
+/**
+ * gadget_is_otg - return true iff the hardware is OTG-ready
+ * @gadget: controller that might have a Mini-AB connector
+ *
+ * This is a runtime test, since kernels with a USB-OTG stack sometimes
+ * run on boards which only have a Mini-B (or Mini-A) connector.
+ */
+static inline int gadget_is_otg(struct usb_gadget *g)
+{
+#ifdef CONFIG_USB_OTG
+       return g->is_otg;
+#else
+       return 0;
+#endif
+}
+
+
+/**
  * usb_gadget_frame_number - returns the current frame number
  * @gadget: controller that reports the frame number
  *
@@ -655,23 +688,23 @@ usb_gadget_disconnect (struct usb_gadget *gadget)
  * @function: String describing the gadget's function
  * @speed: Highest speed the driver handles.
  * @bind: Invoked when the driver is bound to a gadget, usually
- *     after registering the driver.
- *     At that point, ep0 is fully initialized, and ep_list holds
- *     the currently-available endpoints.
- *     Called in a context that permits sleeping.
+ *     after registering the driver.
+ *     At that point, ep0 is fully initialized, and ep_list holds
+ *     the currently-available endpoints.
+ *     Called in a context that permits sleeping.
  * @setup: Invoked for ep0 control requests that aren't handled by
- *     the hardware level driver. Most calls must be handled by
- *     the gadget driver, including descriptor and configuration
- *     management.  The 16 bit members of the setup data are in
- *     USB byte order. Called in_interrupt; this may not sleep.  Driver
+ *     the hardware level driver. Most calls must be handled by
+ *     the gadget driver, including descriptor and configuration
+ *     management.  The 16 bit members of the setup data are in
+ *     USB byte order. Called in_interrupt; this may not sleep.  Driver
  *     queues a response to ep0, or returns negative to stall.
  * @disconnect: Invoked after all transfers have been stopped,
- *     when the host is disconnected.  May be called in_interrupt; this
- *     may not sleep.  Some devices can't detect disconnect, so this might
+ *     when the host is disconnected.  May be called in_interrupt; this
+ *     may not sleep.  Some devices can't detect disconnect, so this might
  *     not be called except as part of controller shutdown.
  * @unbind: Invoked when the driver is unbound from a gadget,
- *     usually from rmmod (after a disconnect is reported).
- *     Called in a context that permits sleeping.
+ *     usually from rmmod (after a disconnect is reported).
+ *     Called in a context that permits sleeping.
  * @suspend: Invoked on USB suspend.  May be called in_interrupt.
  * @resume: Invoked on USB resume.  May be called in_interrupt.
  * @driver: Driver model state for this driver.
index 8da374c..2692ec9 100644 (file)
@@ -4,11 +4,8 @@
  * belong here.
  */
 
-/* device must not be autosuspended */
-#define USB_QUIRK_NO_AUTOSUSPEND       0x00000001
-
 /* string descriptors must not be fetched using a 255-byte read */
-#define USB_QUIRK_STRING_FETCH_255     0x00000002
+#define USB_QUIRK_STRING_FETCH_255     0x00000001
 
 /* device can't resume correctly so reset it instead */
-#define USB_QUIRK_RESET_RESUME         0x00000004
+#define USB_QUIRK_RESET_RESUME         0x00000002
index e8b8928..488ce12 100644 (file)
@@ -141,7 +141,7 @@ struct usb_serial {
 };
 #define to_usb_serial(d) container_of(d, struct usb_serial, kref)
 
-#define NUM_DONT_CARE  (-1)
+#define NUM_DONT_CARE  99
 
 /* get and set the serial private data pointer helper functions */
 static inline void *usb_get_serial_data (struct usb_serial *serial)
@@ -160,12 +160,18 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data)
  *     in the syslog messages when a device is inserted or removed.
  * @id_table: pointer to a list of usb_device_id structures that define all
  *     of the devices this structure can support.
- * @num_interrupt_in: the number of interrupt in endpoints this device will
- *     have.
- * @num_interrupt_out: the number of interrupt out endpoints this device will
- *     have.
- * @num_bulk_in: the number of bulk in endpoints this device will have.
- * @num_bulk_out: the number of bulk out endpoints this device will have.
+ * @num_interrupt_in: If a device doesn't have this many interrupt-in
+ *     endpoints, it won't be sent to the driver's attach() method.
+ *     (But it might still be sent to the probe() method.)
+ * @num_interrupt_out: If a device doesn't have this many interrupt-out
+ *     endpoints, it won't be sent to the driver's attach() method.
+ *     (But it might still be sent to the probe() method.)
+ * @num_bulk_in: If a device doesn't have this many bulk-in
+ *     endpoints, it won't be sent to the driver's attach() method.
+ *     (But it might still be sent to the probe() method.)
+ * @num_bulk_out: If a device doesn't have this many bulk-out
+ *     endpoints, it won't be sent to the driver's attach() method.
+ *     (But it might still be sent to the probe() method.)
  * @num_ports: the number of different ports this device will have.
  * @calc_num_ports: pointer to a function to determine how many ports this
  *     device has dynamically.  It will be called after the probe()
diff --git a/include/linux/usb_sl811.h b/include/linux/usb_sl811.h
deleted file mode 100644 (file)
index 4f2d012..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-
-/*
- * board initialization should put one of these into dev->platform_data
- * and place the sl811hs onto platform_bus named "sl811-hcd".
- */
-
-struct sl811_platform_data {
-       unsigned        can_wakeup:1;
-
-       /* given port_power, msec/2 after power on till power good */
-       u8              potpg;
-
-       /* mA/2 power supplied on this port (max = default = 250) */
-       u8              power;
-
-       /* sl811 relies on an external source of VBUS current */
-       void            (*port_power)(struct device *dev, int is_on);
-
-       /* pulse sl811 nRST (probably with a GPIO) */
-       void            (*reset)(struct device *dev);
-
-       // some boards need something like these:
-       // int          (*check_overcurrent)(struct device *dev);
-       // void         (*clock_enable)(struct device *dev, int is_on);
-};
-