Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Thu, 8 Feb 2007 03:23:21 +0000 (19:23 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Thu, 8 Feb 2007 03:23:21 +0000 (19:23 -0800)
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6: (70 commits)
  USB: remove duplicate device id from zc0301
  USB: remove duplicate device id from usb_storage
  USB: remove duplicate device id from keyspan
  USB: remove duplicate device id from ftdi_sio
  USB: remove duplicate device id from visor
  USB: a bit more coding style cleanup
  usbcore: trivial whitespace fixes
  usb-storage: use first bulk endpoints, not last
  EHCI: fix interrupt-driven remote wakeup
  USB: switch ehci-hcd to new polling scheme
  USB: autosuspend for usb printer driver
  USB Input: Added kernel module to support all GTCO CalComp USB InterWrite School products
  USB: Sierra Wireless auto set D0
  USB: usb ethernet gadget recognizes HUSB2DEV
  USB: list atmel husb2_udc gadget controller
  USB: gadgetfs AIO tweaks
  USB: gadgetfs behaves better on userspace init bug
  USB: gadgetfs race fix
  USB: gadgetfs simplifications
  USB: gadgetfs cleanups
  ...

140 files changed:
Documentation/usb/proc_usb_info.txt
Documentation/usb/usbmon.txt
arch/powerpc/Kconfig
drivers/i2c/chips/isp1301_omap.c
drivers/media/video/zc0301/zc0301_sensor.h
drivers/usb/atm/speedtch.c
drivers/usb/class/usblp.c
drivers/usb/core/Kconfig
drivers/usb/core/buffer.c
drivers/usb/core/devices.c
drivers/usb/core/devio.c
drivers/usb/core/driver.c
drivers/usb/core/file.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/sysfs.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/at91_udc.h
drivers/usb/gadget/config.c
drivers/usb/gadget/epautoconf.c
drivers/usb/gadget/ether.c
drivers/usb/gadget/file_storage.c
drivers/usb/gadget/gadget_chips.h
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/net2280.c
drivers/usb/gadget/omap_udc.c
drivers/usb/gadget/pxa2xx_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-dbg.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-ps3.c [new file with mode: 0644]
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/ehci.h
drivers/usb/host/ohci-at91.c
drivers/usb/host/ohci-au1xxx.c
drivers/usb/host/ohci-ep93xx.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-lh7a404.c
drivers/usb/host/ohci-omap.c
drivers/usb/host/ohci-pci.c
drivers/usb/host/ohci-pnx4008.c
drivers/usb/host/ohci-pnx8550.c
drivers/usb/host/ohci-ppc-of.c [new file with mode: 0644]
drivers/usb/host/ohci-ppc-soc.c
drivers/usb/host/ohci-ps3.c [new file with mode: 0644]
drivers/usb/host/ohci-pxa27x.c
drivers/usb/host/ohci-s3c2410.c
drivers/usb/host/ohci-sa1111.c
drivers/usb/host/ohci.h
drivers/usb/host/uhci-debug.c
drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-hcd.h
drivers/usb/host/uhci-q.c
drivers/usb/image/mdc800.c
drivers/usb/input/Kconfig
drivers/usb/input/Makefile
drivers/usb/input/gtco.c [new file with mode: 0644]
drivers/usb/input/hid-core.c
drivers/usb/misc/idmouse.c
drivers/usb/misc/rio500.c
drivers/usb/mon/Makefile
drivers/usb/mon/mon_bin.c [new file with mode: 0644]
drivers/usb/mon/mon_dma.c
drivers/usb/mon/mon_main.c
drivers/usb/mon/mon_text.c
drivers/usb/mon/usb_mon.h
drivers/usb/net/Kconfig
drivers/usb/net/cdc_ether.c
drivers/usb/net/kaweth.c
drivers/usb/net/rndis_host.c
drivers/usb/serial/aircable.c
drivers/usb/serial/airprime.c
drivers/usb/serial/ark3116.c
drivers/usb/serial/belkin_sa.c
drivers/usb/serial/bus.c
drivers/usb/serial/cp2101.c
drivers/usb/serial/cyberjack.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/empeg.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio.h
drivers/usb/serial/funsoft.c
drivers/usb/serial/garmin_gps.c
drivers/usb/serial/generic.c
drivers/usb/serial/hp4x.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_edgeport.h
drivers/usb/serial/io_tables.h
drivers/usb/serial/io_ti.c
drivers/usb/serial/io_usbvend.h
drivers/usb/serial/ipaq.c
drivers/usb/serial/ipw.c
drivers/usb/serial/ir-usb.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/keyspan.h
drivers/usb/serial/keyspan_pda.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/serial/kobil_sct.c
drivers/usb/serial/mct_u232.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/navman.c
drivers/usb/serial/omninet.c
drivers/usb/serial/option.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/safe_serial.c
drivers/usb/serial/sierra.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/visor.c
drivers/usb/serial/visor.h
drivers/usb/serial/whiteheat.c
drivers/usb/storage/onetouch.c
drivers/usb/storage/scsiglue.c
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/usb.c
include/linux/Kbuild
include/linux/hid.h
include/linux/usb.h
include/linux/usb/Kbuild [new file with mode: 0644]
include/linux/usb/ch9.h [new file with mode: 0644]
include/linux/usb/serial.h
include/linux/usb_ch9.h [deleted file]
include/linux/usb_gadgetfs.h

index 22c5331..077e903 100644 (file)
@@ -213,15 +213,16 @@ C:* #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
 
 Interface descriptor info (can be multiple per Config):
 
-I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
-|   |      |      |       |             |      |       |__Driver name
-|   |      |      |       |             |      |          or "(none)"
-|   |      |      |       |             |      |__InterfaceProtocol
-|   |      |      |       |             |__InterfaceSubClass
-|   |      |      |       |__InterfaceClass
-|   |      |      |__NumberOfEndpoints
-|   |      |__AlternateSettingNumber
-|   |__InterfaceNumber
+I:* If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
+| | |      |      |       |             |      |       |__Driver name
+| | |      |      |       |             |      |          or "(none)"
+| | |      |      |       |             |      |__InterfaceProtocol
+| | |      |      |       |             |__InterfaceSubClass
+| | |      |      |       |__InterfaceClass
+| | |      |      |__NumberOfEndpoints
+| | |      |__AlternateSettingNumber
+| | |__InterfaceNumber
+| |__ "*" indicates the active altsetting (others are " ")
 |__Interface info tag
 
     A given interface may have one or more "alternate" settings.
@@ -277,7 +278,7 @@ of the USB devices on a system's root hub.  (See more below
 on how to do this.)
 
 The Interface lines can be used to determine what driver is
-being used for each device.
+being used for each device, and which altsetting it activated.
 
 The Configuration lines could be used to list maximum power
 (in milliamps) that a system's USB devices are using.
index e65ec82..0f6808a 100644 (file)
@@ -77,7 +77,7 @@ that the file size is not excessive for your favourite editor.
 
 The '1t' type data consists of a stream of events, such as URB submission,
 URB callback, submission error. Every event is a text line, which consists
-of whitespace separated words. The number of position of words may depend
+of whitespace separated words. The number or position of words may depend
 on the event type, but there is a set of words, common for all types.
 
 Here is the list of words, from left to right:
@@ -170,4 +170,152 @@ dd65f0e8 4128379808 C Bo:005:02 0 31 >
 
 * Raw binary format and API
 
-TBD
+The overall architecture of the API is about the same as the one above,
+only the events are delivered in binary format. Each event is sent in
+the following structure (its name is made up, so that we can refer to it):
+
+struct usbmon_packet {
+       u64 id;                 /*  0: URB ID - from submission to callback */
+       unsigned char type;     /*  8: Same as text; extensible. */
+       unsigned char xfer_type; /*    ISO (0), Intr, Control, Bulk (3) */
+       unsigned char epnum;    /*     Endpoint number and transfer direction */
+       unsigned char devnum;   /*     Device address */
+       u16 busnum;             /* 12: Bus number */
+       char flag_setup;        /* 14: Same as text */
+       char flag_data;         /* 15: Same as text; Binary zero is OK. */
+       s64 ts_sec;             /* 16: gettimeofday */
+       s32 ts_usec;            /* 24: gettimeofday */
+       int status;             /* 28: */
+       unsigned int length;    /* 32: Length of data (submitted or actual) */
+       unsigned int len_cap;   /* 36: Delivered length */
+       unsigned char setup[8]; /* 40: Only for Control 'S' */
+};                             /* 48 bytes total */
+
+These events can be received from a character device by reading with read(2),
+with an ioctl(2), or by accessing the buffer with mmap.
+
+The character device is usually called /dev/usbmonN, where N is the USB bus
+number. Number zero (/dev/usbmon0) is special and means "all buses".
+However, this feature is not implemented yet. Note that specific naming
+policy is set by your Linux distribution.
+
+If you create /dev/usbmon0 by hand, make sure that it is owned by root
+and has mode 0600. Otherwise, unpriviledged users will be able to snoop
+keyboard traffic.
+
+The following ioctl calls are available, with MON_IOC_MAGIC 0x92:
+
+ MON_IOCQ_URB_LEN, defined as _IO(MON_IOC_MAGIC, 1)
+
+This call returns the length of data in the next event. Note that majority of
+events contain no data, so if this call returns zero, it does not mean that
+no events are available.
+
+ MON_IOCG_STATS, defined as _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
+
+The argument is a pointer to the following structure:
+
+struct mon_bin_stats {
+       u32 queued;
+       u32 dropped;
+};
+
+The member "queued" refers to the number of events currently queued in the
+buffer (and not to the number of events processed since the last reset).
+
+The member "dropped" is the number of events lost since the last call
+to MON_IOCG_STATS.
+
+ MON_IOCT_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 4)
+
+This call sets the buffer size. The argument is the size in bytes.
+The size may be rounded down to the next chunk (or page). If the requested
+size is out of [unspecified] bounds for this kernel, the call fails with
+-EINVAL.
+
+ MON_IOCQ_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 5)
+
+This call returns the current size of the buffer in bytes.
+
+ MON_IOCX_GET, defined as _IOW(MON_IOC_MAGIC, 6, struct mon_get_arg)
+
+This call waits for events to arrive if none were in the kernel buffer,
+then returns the first event. Its argument is a pointer to the following
+structure:
+
+struct mon_get_arg {
+       struct usbmon_packet *hdr;
+       void *data;
+       size_t alloc;           /* Length of data (can be zero) */
+};
+
+Before the call, hdr, data, and alloc should be filled. Upon return, the area
+pointed by hdr contains the next event structure, and the data buffer contains
+the data, if any. The event is removed from the kernel buffer.
+
+ MON_IOCX_MFETCH, defined as _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg)
+
+This ioctl is primarily used when the application accesses the buffer
+with mmap(2). Its argument is a pointer to the following structure:
+
+struct mon_mfetch_arg {
+       uint32_t *offvec;       /* Vector of events fetched */
+       uint32_t nfetch;        /* Number of events to fetch (out: fetched) */
+       uint32_t nflush;        /* Number of events to flush */
+};
+
+The ioctl operates in 3 stages.
+
+First, it removes and discards up to nflush events from the kernel buffer.
+The actual number of events discarded is returned in nflush.
+
+Second, it waits for an event to be present in the buffer, unless the pseudo-
+device is open with O_NONBLOCK.
+
+Third, it extracts up to nfetch offsets into the mmap buffer, and stores
+them into the offvec. The actual number of event offsets is stored into
+the nfetch.
+
+ MON_IOCH_MFLUSH, defined as _IO(MON_IOC_MAGIC, 8)
+
+This call removes a number of events from the kernel buffer. Its argument
+is the number of events to remove. If the buffer contains fewer events
+than requested, all events present are removed, and no error is reported.
+This works when no events are available too.
+
+ FIONBIO
+
+The ioctl FIONBIO may be implemented in the future, if there's a need.
+
+In addition to ioctl(2) and read(2), the special file of binary API can
+be polled with select(2) and poll(2). But lseek(2) does not work.
+
+* Memory-mapped access of the kernel buffer for the binary API
+
+The basic idea is simple:
+
+To prepare, map the buffer by getting the current size, then using mmap(2).
+Then, execute a loop similar to the one written in pseudo-code below:
+
+   struct mon_mfetch_arg fetch;
+   struct usbmon_packet *hdr;
+   int nflush = 0;
+   for (;;) {
+      fetch.offvec = vec; // Has N 32-bit words
+      fetch.nfetch = N;   // Or less than N
+      fetch.nflush = nflush;
+      ioctl(fd, MON_IOCX_MFETCH, &fetch);   // Process errors, too
+      nflush = fetch.nfetch;       // This many packets to flush when done
+      for (i = 0; i < nflush; i++) {
+         hdr = (struct ubsmon_packet *) &mmap_area[vec[i]];
+         if (hdr->type == '@')     // Filler packet
+            continue;
+         caddr_t data = &mmap_area[vec[i]] + 64;
+         process_packet(hdr, data);
+      }
+   }
+
+Thus, the main idea is to execute only one ioctl per N events.
+
+Although the buffer is circular, the returned headers and data do not cross
+the end of the buffer, so the above pseudo-code does not need any gathering.
index d6abe49..c1e01b2 100644 (file)
@@ -529,6 +529,11 @@ config PPC_PS3
        bool "Sony PS3 (incomplete)"
        depends on PPC_MULTIPLATFORM && PPC64
        select PPC_CELL
+       select USB_ARCH_HAS_OHCI
+       select USB_OHCI_LITTLE_ENDIAN
+       select USB_OHCI_BIG_ENDIAN_MMIO
+       select USB_ARCH_HAS_EHCI
+       select USB_EHCI_BIG_ENDIAN_MMIO
        help
          This option enables support for the Sony PS3 game console
          and other platforms using the PS3 hypervisor.
index ccdf3e9..9fafadb 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb.h>
 #include <linux/usb/otg.h>
index 4363a91..3daf049 100644 (file)
@@ -75,7 +75,6 @@ static const struct usb_device_id zc0301_id_table[] =  {                      \
        { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
        { ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */           \
        { ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */           \
-       { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
        { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), },                         \
        { ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */    \
        { ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */           \
index 8ed6c75..638b800 100644 (file)
@@ -36,7 +36,7 @@
 #include <linux/stat.h>
 #include <linux/timer.h>
 #include <linux/types.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/workqueue.h>
 
 #include "usbatm.h"
index 6377db1..63e50a1 100644 (file)
@@ -398,6 +398,9 @@ static int usblp_open(struct inode *inode, struct file *file)
        retval = 0;
 #endif
 
+       retval = usb_autopm_get_interface(intf);
+       if (retval < 0)
+               goto out;
        usblp->used = 1;
        file->private_data = usblp;
 
@@ -442,6 +445,7 @@ static int usblp_release(struct inode *inode, struct file *file)
        usblp->used = 0;
        if (usblp->present) {
                usblp_unlink_urbs(usblp);
+               usb_autopm_put_interface(usblp->intf);
        } else          /* finish cleanup from disconnect */
                usblp_cleanup (usblp);
        mutex_unlock (&usblp_mutex);
@@ -1203,14 +1207,9 @@ static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
 {
        struct usblp *usblp = usb_get_intfdata (intf);
 
-       /* this races against normal access and open */
-       mutex_lock (&usblp_mutex);
-       mutex_lock (&usblp->mut);
        /* we take no more IO */
        usblp->sleeping = 1;
        usblp_unlink_urbs(usblp);
-       mutex_unlock (&usblp->mut);
-       mutex_unlock (&usblp_mutex);
 
        return 0;
 }
@@ -1220,15 +1219,9 @@ static int usblp_resume (struct usb_interface *intf)
        struct usblp *usblp = usb_get_intfdata (intf);
        int r;
 
-       mutex_lock (&usblp_mutex);
-       mutex_lock (&usblp->mut);
-
        usblp->sleeping = 0;
        r = handle_bidir (usblp);
 
-       mutex_unlock (&usblp->mut);
-       mutex_unlock (&usblp_mutex);
-
        return r;
 }
 
@@ -1251,6 +1244,7 @@ static struct usb_driver usblp_driver = {
        .suspend =      usblp_suspend,
        .resume =       usblp_resume,
        .id_table =     usblp_ids,
+       .supports_autosuspend = 1,
 };
 
 static int __init usblp_init(void)
index 3e66b2a..2fc0f88 100644 (file)
@@ -33,19 +33,6 @@ config USB_DEVICEFS
 
          Most users want to say Y here.
 
-config USB_BANDWIDTH
-       bool "Enforce USB bandwidth allocation (EXPERIMENTAL)"
-       depends on USB && EXPERIMENTAL
-       help
-         If you say Y here, the USB subsystem enforces USB bandwidth
-         allocation and will prevent some device opens from succeeding
-         if they would cause USB bandwidth usage to go above 90% of
-         the bus bandwidth.
-
-         If you say N here, these conditions will cause warning messages
-         about USB bandwidth usage to be logged and some devices or
-         drivers may not work correctly.
-
 config USB_DYNAMIC_MINORS
        bool "Dynamic USB minor allocation (EXPERIMENTAL)"
        depends on USB && EXPERIMENTAL
index c3915dc..ead2475 100644 (file)
@@ -49,9 +49,9 @@ static const size_t   pool_max [HCD_BUFFER_POOLS] = {
  *
  * Call hcd_buffer_destroy() to clean up after using those pools.
  */
-int hcd_buffer_create (struct usb_hcd *hcd)
+int hcd_buffer_create(struct usb_hcd *hcd)
 {
-       char            name [16];
+       char            name[16];
        int             i, size;
 
        if (!hcd->self.controller->dma_mask)
@@ -60,11 +60,11 @@ int hcd_buffer_create (struct usb_hcd *hcd)
        for (i = 0; i < HCD_BUFFER_POOLS; i++) { 
                if (!(size = pool_max [i]))
                        continue;
-               snprintf (name, sizeof name, "buffer-%d", size);
-               hcd->pool [i] = dma_pool_create (name, hcd->self.controller,
+               snprintf(name, sizeof name, "buffer-%d", size);
+               hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
                                size, size, 0);
                if (!hcd->pool [i]) {
-                       hcd_buffer_destroy (hcd);
+                       hcd_buffer_destroy(hcd);
                        return -ENOMEM;
                }
        }
@@ -79,14 +79,14 @@ int hcd_buffer_create (struct usb_hcd *hcd)
  *
  * This frees the buffer pools created by hcd_buffer_create().
  */
-void hcd_buffer_destroy (struct usb_hcd *hcd)
+void hcd_buffer_destroy(struct usb_hcd *hcd)
 {
        int             i;
 
        for (i = 0; i < HCD_BUFFER_POOLS; i++) { 
-               struct dma_pool         *pool = hcd->pool [i];
+               struct dma_pool         *pool = hcd->pool[i];
                if (pool) {
-                       dma_pool_destroy (pool);
+                       dma_pool_destroy(pool);
                        hcd->pool[i] = NULL;
                }
        }
@@ -97,8 +97,8 @@ void hcd_buffer_destroy (struct usb_hcd *hcd)
  * better sharing and to leverage mm/slab.c intelligence.
  */
 
-void *hcd_buffer_alloc (
-       struct usb_bus          *bus,
+void *hcd_buffer_alloc(
+       struct usb_bus  *bus,
        size_t                  size,
        gfp_t                   mem_flags,
        dma_addr_t              *dma
@@ -110,18 +110,18 @@ void *hcd_buffer_alloc (
        /* some USB hosts just use PIO */
        if (!bus->controller->dma_mask) {
                *dma = ~(dma_addr_t) 0;
-               return kmalloc (size, mem_flags);
+               return kmalloc(size, mem_flags);
        }
 
        for (i = 0; i < HCD_BUFFER_POOLS; i++) {
                if (size <= pool_max [i])
-                       return dma_pool_alloc (hcd->pool [i], mem_flags, dma);
+                       return dma_pool_alloc(hcd->pool [i], mem_flags, dma);
        }
-       return dma_alloc_coherent (hcd->self.controller, size, dma, 0);
+       return dma_alloc_coherent(hcd->self.controller, size, dma, 0);
 }
 
-void hcd_buffer_free (
-       struct usb_bus          *bus,
+void hcd_buffer_free(
+       struct usb_bus  *bus,
        size_t                  size,
        void                    *addr,
        dma_addr_t              dma
@@ -134,15 +134,15 @@ void hcd_buffer_free (
                return;
 
        if (!bus->controller->dma_mask) {
-               kfree (addr);
+               kfree(addr);
                return;
        }
 
        for (i = 0; i < HCD_BUFFER_POOLS; i++) {
                if (size <= pool_max [i]) {
-                       dma_pool_free (hcd->pool [i], addr, dma);
+                       dma_pool_free(hcd->pool [i], addr, dma);
                        return;
                }
        }
-       dma_free_coherent (hcd->self.controller, size, addr, dma);
+       dma_free_coherent(hcd->self.controller, size, addr, dma);
 }
index ea398e5..a47c30b 100644 (file)
@@ -104,7 +104,7 @@ static const char *format_config =
   
 static const char *format_iface =
 /* I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
-  "I:  If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
+  "I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
 
 static const char *format_endpt =
 /* E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
@@ -164,10 +164,10 @@ static const char *class_decode(const int class)
        for (ix = 0; clas_info[ix].class != -1; ix++)
                if (clas_info[ix].class == class)
                        break;
-       return (clas_info[ix].class_name);
+       return clas_info[ix].class_name;
 }
 
-static char *usb_dump_endpoint_descriptor (
+static char *usb_dump_endpoint_descriptor(
        int speed,
        char *start,
        char *end,
@@ -212,9 +212,9 @@ static char *usb_dump_endpoint_descriptor (
                break;
        case USB_ENDPOINT_XFER_INT:
                type = "Int.";
-               if (speed == USB_SPEED_HIGH) {
+               if (speed == USB_SPEED_HIGH)
                        interval = 1 << (desc->bInterval - 1);
-               else
+               else
                        interval = desc->bInterval;
                break;
        default:        /* "can't happen" */
@@ -242,15 +242,19 @@ static char *usb_dump_interface_descriptor(char *start, char *end,
 {
        const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc;
        const char *driver_name = "";
+       int active = 0;
 
        if (start > end)
                return start;
        down_read(&usb_bus_type.subsys.rwsem);
-       if (iface)
+       if (iface) {
                driver_name = (iface->dev.driver
                                ? iface->dev.driver->name
                                : "(none)");
+               active = (desc == &iface->cur_altsetting->desc);
+       }
        start += sprintf(start, format_iface,
+                        active ? '*' : ' ',    /* mark active altsetting */
                         desc->bInterfaceNumber,
                         desc->bAlternateSetting,
                         desc->bNumEndpoints,
@@ -343,7 +347,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb
 
        if (start > end)
                return start;
-       start += sprintf (start, format_device1,
+       start += sprintf(start, format_device1,
                          bcdUSB >> 8, bcdUSB & 0xff,
                          desc->bDeviceClass,
                          class_decode (desc->bDeviceClass),
@@ -363,7 +367,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb
 /*
  * Dump the different strings that this device holds.
  */
-static char *usb_dump_device_strings (char *start, char *end, struct usb_device *dev)
+static char *usb_dump_device_strings(char *start, char *end, struct usb_device *dev)
 {
        if (start > end)
                return start;
@@ -395,7 +399,7 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev)
        if (start > end)
                return start;
        
-       start = usb_dump_device_strings (start, end, dev);
+       start = usb_dump_device_strings(start, end, dev);
 
        for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
                if (start > end)
index 4b3a6ab..2087766 100644 (file)
@@ -522,19 +522,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
 
 static struct usb_device *usbdev_lookup_minor(int minor)
 {
-       struct class_device *class_dev;
-       struct usb_device *dev = NULL;
+       struct device *device;
+       struct usb_device *udev = NULL;
 
        down(&usb_device_class->sem);
-       list_for_each_entry(class_dev, &usb_device_class->children, node) {
-               if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
-                       dev = class_dev->class_data;
+       list_for_each_entry(device, &usb_device_class->devices, node) {
+               if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
+                       udev = device->platform_data;
                        break;
                }
        }
        up(&usb_device_class->sem);
 
-       return dev;
+       return udev;
 };
 
 /*
@@ -570,6 +570,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
        ps->dev = dev;
        ps->file = file;
        spin_lock_init(&ps->lock);
+       INIT_LIST_HEAD(&ps->list);
        INIT_LIST_HEAD(&ps->async_pending);
        INIT_LIST_HEAD(&ps->async_completed);
        init_waitqueue_head(&ps->wait);
@@ -1596,19 +1597,19 @@ static int usbdev_add(struct usb_device *dev)
 {
        int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
 
-       dev->class_dev = class_device_create(usb_device_class, NULL,
-                               MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
+       dev->usbfs_dev = device_create(usb_device_class, &dev->dev,
+                               MKDEV(USB_DEVICE_MAJOR, minor),
                                "usbdev%d.%d", dev->bus->busnum, dev->devnum);
-       if (IS_ERR(dev->class_dev))
-               return PTR_ERR(dev->class_dev);
+       if (IS_ERR(dev->usbfs_dev))
+               return PTR_ERR(dev->usbfs_dev);
 
-       dev->class_dev->class_data = dev;
+       dev->usbfs_dev->platform_data = dev;
        return 0;
 }
 
 static void usbdev_remove(struct usb_device *dev)
 {
-       class_device_unregister(dev->class_dev);
+       device_unregister(dev->usbfs_dev);
 }
 
 static int usbdev_notify(struct notifier_block *self, unsigned long action,
index d505926..600d1bc 100644 (file)
 #include "hcd.h"
 #include "usb.h"
 
-static int usb_match_one_id(struct usb_interface *interface,
-                           const struct usb_device_id *id);
-
-struct usb_dynid {
-       struct list_head node;
-       struct usb_device_id id;
-};
-
 #ifdef CONFIG_HOTPLUG
 
 /*
  * Adds a new dynamic USBdevice ID to this driver,
  * and cause the driver to probe for all devices again.
  */
-static ssize_t store_new_id(struct device_driver *driver,
-                           const char *buf, size_t count)
+ssize_t usb_store_new_id(struct usb_dynids *dynids,
+                        struct device_driver *driver,
+                        const char *buf, size_t count)
 {
-       struct usb_driver *usb_drv = to_usb_driver(driver);
        struct usb_dynid *dynid;
        u32 idVendor = 0;
        u32 idProduct = 0;
@@ -65,9 +57,9 @@ static ssize_t store_new_id(struct device_driver *driver,
        dynid->id.idProduct = idProduct;
        dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
 
-       spin_lock(&usb_drv->dynids.lock);
-       list_add_tail(&usb_drv->dynids.list, &dynid->node);
-       spin_unlock(&usb_drv->dynids.lock);
+       spin_lock(&dynids->lock);
+       list_add_tail(&dynids->list, &dynid->node);
+       spin_unlock(&dynids->lock);
 
        if (get_driver(driver)) {
                retval = driver_attach(driver);
@@ -78,6 +70,15 @@ static ssize_t store_new_id(struct device_driver *driver,
                return retval;
        return count;
 }
+EXPORT_SYMBOL_GPL(usb_store_new_id);
+
+static ssize_t store_new_id(struct device_driver *driver,
+                           const char *buf, size_t count)
+{
+       struct usb_driver *usb_drv = to_usb_driver(driver);
+
+       return usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+}
 static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
 
 static int usb_create_newid_file(struct usb_driver *usb_drv)
@@ -365,8 +366,8 @@ void usb_driver_release_interface(struct usb_driver *driver,
 EXPORT_SYMBOL(usb_driver_release_interface);
 
 /* returns 0 if no match, 1 if match */
-static int usb_match_one_id(struct usb_interface *interface,
-                           const struct usb_device_id *id)
+int usb_match_one_id(struct usb_interface *interface,
+                    const struct usb_device_id *id)
 {
        struct usb_host_interface *intf;
        struct usb_device *dev;
@@ -432,6 +433,8 @@ static int usb_match_one_id(struct usb_interface *interface,
 
        return 1;
 }
+EXPORT_SYMBOL_GPL(usb_match_one_id);
+
 /**
  * usb_match_id - find first usb_device_id matching device or interface
  * @interface: the interface of interest
index f794f07..01c857a 100644 (file)
@@ -194,14 +194,13 @@ int usb_register_dev(struct usb_interface *intf,
                ++temp;
        else
                temp = name;
-       intf->class_dev = class_device_create(usb_class->class, NULL,
-                                             MKDEV(USB_MAJOR, minor),
-                                             &intf->dev, "%s", temp);
-       if (IS_ERR(intf->class_dev)) {
+       intf->usb_dev = device_create(usb_class->class, &intf->dev,
+                                     MKDEV(USB_MAJOR, minor), "%s", temp);
+       if (IS_ERR(intf->usb_dev)) {
                spin_lock (&minor_lock);
                usb_minors[intf->minor] = NULL;
                spin_unlock (&minor_lock);
-               retval = PTR_ERR(intf->class_dev);
+               retval = PTR_ERR(intf->usb_dev);
        }
 exit:
        return retval;
@@ -242,8 +241,8 @@ void usb_deregister_dev(struct usb_interface *intf,
        spin_unlock (&minor_lock);
 
        snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
-       class_device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
-       intf->class_dev = NULL;
+       device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
+       intf->usb_dev = NULL;
        intf->minor = -1;
        destroy_usb_class();
 }
index ebb20ff..b531a4f 100644 (file)
@@ -25,6 +25,20 @@ static inline const char *plural(int n)
        return (n == 1 ? "" : "s");
 }
 
+static int is_rndis(struct usb_interface_descriptor *desc)
+{
+       return desc->bInterfaceClass == USB_CLASS_COMM
+               && desc->bInterfaceSubClass == 2
+               && desc->bInterfaceProtocol == 0xff;
+}
+
+static int is_activesync(struct usb_interface_descriptor *desc)
+{
+       return desc->bInterfaceClass == USB_CLASS_MISC
+               && desc->bInterfaceSubClass == 1
+               && desc->bInterfaceProtocol == 1;
+}
+
 static int choose_configuration(struct usb_device *udev)
 {
        int i;
@@ -87,14 +101,12 @@ static int choose_configuration(struct usb_device *udev)
                        continue;
                }
 
-               /* If the first config's first interface is COMM/2/0xff
-                * (MSFT RNDIS), rule it out unless Linux has host-side
-                * RNDIS support. */
-               if (i == 0 && desc
-                               && desc->bInterfaceClass == USB_CLASS_COMM
-                               && desc->bInterfaceSubClass == 2
-                               && desc->bInterfaceProtocol == 0xff) {
-#ifndef CONFIG_USB_NET_RNDIS_HOST
+               /* When the first config's first interface is one of Microsoft's
+                * pet nonstandard Ethernet-over-USB protocols, ignore it unless
+                * this kernel has enabled the necessary host side driver.
+                */
+               if (i == 0 && desc && (is_rndis(desc) || is_activesync(desc))) {
+#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
                        continue;
 #else
                        best = c;
index 10064af..b26c19e 100644 (file)
@@ -45,8 +45,6 @@
 #include "hub.h"
 
 
-// #define USB_BANDWIDTH_MESSAGES
-
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -891,136 +889,6 @@ long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
 }
 EXPORT_SYMBOL (usb_calc_bus_time);
 
-/*
- * usb_check_bandwidth():
- *
- * old_alloc is from host_controller->bandwidth_allocated in microseconds;
- * bustime is from calc_bus_time(), but converted to microseconds.
- *
- * returns <bustime in us> if successful,
- * or -ENOSPC if bandwidth request fails.
- *
- * FIXME:
- * This initial implementation does not use Endpoint.bInterval
- * in managing bandwidth allocation.
- * It probably needs to be expanded to use Endpoint.bInterval.
- * This can be done as a later enhancement (correction).
- *
- * This will also probably require some kind of
- * frame allocation tracking...meaning, for example,
- * that if multiple drivers request interrupts every 10 USB frames,
- * they don't all have to be allocated at
- * frame numbers N, N+10, N+20, etc.  Some of them could be at
- * N+11, N+21, N+31, etc., and others at
- * N+12, N+22, N+32, etc.
- *
- * Similarly for isochronous transfers...
- *
- * Individual HCDs can schedule more directly ... this logic
- * is not correct for high speed transfers.
- */
-int usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
-{
-       unsigned int    pipe = urb->pipe;
-       long            bustime;
-       int             is_in = usb_pipein (pipe);
-       int             is_iso = usb_pipeisoc (pipe);
-       int             old_alloc = dev->bus->bandwidth_allocated;
-       int             new_alloc;
-
-
-       bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso,
-                       usb_maxpacket (dev, pipe, !is_in)));
-       if (is_iso)
-               bustime /= urb->number_of_packets;
-
-       new_alloc = old_alloc + (int) bustime;
-       if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) {
-#ifdef DEBUG
-               char    *mode = 
-#ifdef CONFIG_USB_BANDWIDTH
-                       "";
-#else
-                       "would have ";
-#endif
-               dev_dbg (&dev->dev, "usb_check_bandwidth %sFAILED: %d + %ld = %d usec\n",
-                       mode, old_alloc, bustime, new_alloc);
-#endif
-#ifdef CONFIG_USB_BANDWIDTH
-               bustime = -ENOSPC;      /* report error */
-#endif
-       }
-
-       return bustime;
-}
-EXPORT_SYMBOL (usb_check_bandwidth);
-
-
-/**
- * usb_claim_bandwidth - records bandwidth for a periodic transfer
- * @dev: source/target of request
- * @urb: request (urb->dev == dev)
- * @bustime: bandwidth consumed, in (average) microseconds per frame
- * @isoc: true iff the request is isochronous
- *
- * Bus bandwidth reservations are recorded purely for diagnostic purposes.
- * HCDs are expected not to overcommit periodic bandwidth, and to record such
- * reservations whenever endpoints are added to the periodic schedule.
- *
- * FIXME averaging per-frame is suboptimal.  Better to sum over the HCD's
- * entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable
- * for EHCI (256/512/1024 frames, default 1024) and have the bus expose how
- * large its periodic schedule is.
- */
-void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc)
-{
-       dev->bus->bandwidth_allocated += bustime;
-       if (isoc)
-               dev->bus->bandwidth_isoc_reqs++;
-       else
-               dev->bus->bandwidth_int_reqs++;
-       urb->bandwidth = bustime;
-
-#ifdef USB_BANDWIDTH_MESSAGES
-       dev_dbg (&dev->dev, "bandwidth alloc increased by %d (%s) to %d for %d requesters\n",
-               bustime,
-               isoc ? "ISOC" : "INTR",
-               dev->bus->bandwidth_allocated,
-               dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
-}
-EXPORT_SYMBOL (usb_claim_bandwidth);
-
-
-/**
- * usb_release_bandwidth - reverses effect of usb_claim_bandwidth()
- * @dev: source/target of request
- * @urb: request (urb->dev == dev)
- * @isoc: true iff the request is isochronous
- *
- * This records that previously allocated bandwidth has been released.
- * Bandwidth is released when endpoints are removed from the host controller's
- * periodic schedule.
- */
-void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc)
-{
-       dev->bus->bandwidth_allocated -= urb->bandwidth;
-       if (isoc)
-               dev->bus->bandwidth_isoc_reqs--;
-       else
-               dev->bus->bandwidth_int_reqs--;
-
-#ifdef USB_BANDWIDTH_MESSAGES
-       dev_dbg (&dev->dev, "bandwidth alloc reduced by %d (%s) to %d for %d requesters\n",
-               urb->bandwidth,
-               isoc ? "ISOC" : "INTR",
-               dev->bus->bandwidth_allocated,
-               dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
-       urb->bandwidth = 0;
-}
-EXPORT_SYMBOL (usb_release_bandwidth);
-
 
 /*-------------------------------------------------------------------------*/
 
@@ -1034,11 +902,6 @@ static void urb_unlink (struct urb *urb)
 {
        unsigned long           flags;
 
-       /* Release any periodic transfer bandwidth */
-       if (urb->bandwidth)
-               usb_release_bandwidth (urb->dev, urb,
-                       usb_pipeisoc (urb->pipe));
-
        /* clear all state linking urb to this dev (and hcd) */
 
        spin_lock_irqsave (&hcd_data_lock, flags);
index 8f8df0d..2a269ca 100644 (file)
@@ -308,10 +308,6 @@ extern void usb_destroy_configuration(struct usb_device *dev);
 #define NS_TO_US(ns)   ((ns + 500L) / 1000L)
                        /* convert & round nanoseconds to microseconds */
 
-extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb,
-               int bustime, int isoc);
-extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb,
-               int isoc);
 
 /*
  * Full/low speed bandwidth allocation constants/support.
@@ -324,8 +320,6 @@ extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb,
 #define FRAME_TIME_MAX_BITS_ALLOC      (90L * FRAME_TIME_BITS / 100L)
 #define FRAME_TIME_MAX_USECS_ALLOC     (90L * FRAME_TIME_USECS / 100L)
 
-extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
-
 /*
  * Ceiling [nano/micro]seconds (typical) for that many bytes at high speed
  * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
index 1988224..590ec82 100644 (file)
@@ -87,9 +87,6 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
 
 static struct task_struct *khubd_task;
 
-/* multithreaded probe logic */
-static int multithread_probe = 0;
-
 /* cycle leds on hubs that aren't blinking for attention */
 static int blinkenlights = 0;
 module_param (blinkenlights, bool, S_IRUGO);
@@ -1256,9 +1253,28 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
 static int __usb_port_suspend(struct usb_device *, int port1);
 #endif
 
-static int __usb_new_device(void *void_data)
+/**
+ * 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)
 {
-       struct usb_device *udev = void_data;
        int err;
 
        /* Lock ourself into memory in order to keep a probe sequence
@@ -1375,44 +1391,6 @@ fail:
        goto exit;
 }
 
-/**
- * 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.
- *
- * The return value for this function depends on if the
- * multithread_probe variable is set or not.  If it's set, it will
- * return a if the probe thread was successfully created or not.  If the
- * variable is not set, it will return if the device is configured
- * properly or not.  interfaces, in sysfs); 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)
-{
-       struct task_struct *probe_task;
-       int ret = 0;
-
-       if (multithread_probe) {
-               probe_task = kthread_run(__usb_new_device, udev,
-                                        "usb-probe-%s", udev->devnum);
-               if (IS_ERR(probe_task))
-                       ret = PTR_ERR(probe_task);
-       } else
-               ret = __usb_new_device(udev);
-
-       return ret;
-}
-
 static int hub_port_status(struct usb_hub *hub, int port1,
                               u16 *status, u16 *change)
 {
index 149aa8b..8aca357 100644 (file)
@@ -1545,11 +1545,7 @@ int usb_driver_set_configuration(struct usb_device *udev, int config)
        INIT_WORK(&req->work, driver_set_config_work);
 
        usb_get_dev(udev);
-       if (!schedule_work(&req->work)) {
-               usb_put_dev(udev);
-               kfree(req);
-               return -EINVAL;
-       }
+       schedule_work(&req->work);
        return 0;
 }
 EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
index 55d8f57..4eaa0ee 100644 (file)
 
 /* Active configuration fields */
 #define usb_actconfig_show(field, multiplier, format_string)           \
-static ssize_t  show_##field (struct device *dev,                      \
+static ssize_t  show_##field(struct device *dev,                       \
                struct device_attribute *attr, char *buf)               \
 {                                                                      \
        struct usb_device *udev;                                        \
        struct usb_host_config *actconfig;                              \
                                                                        \
-       udev = to_usb_device (dev);                                     \
+       udev = to_usb_device(dev);                                      \
        actconfig = udev->actconfig;                                    \
        if (actconfig)                                                  \
-               return sprintf (buf, format_string,                     \
+               return sprintf(buf, format_string,                      \
                                actconfig->desc.field * multiplier);    \
        else                                                            \
                return 0;                                               \
@@ -35,9 +35,9 @@ static ssize_t  show_##field (struct device *dev,                     \
 usb_actconfig_show(field, multiplier, format_string)                   \
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 
-usb_actconfig_attr (bNumInterfaces, 1, "%2d\n")
-usb_actconfig_attr (bmAttributes, 1, "%2x\n")
-usb_actconfig_attr (bMaxPower, 2, "%3dmA\n")
+usb_actconfig_attr(bNumInterfaces, 1, "%2d\n")
+usb_actconfig_attr(bmAttributes, 1, "%2x\n")
+usb_actconfig_attr(bMaxPower, 2, "%3dmA\n")
 
 static ssize_t show_configuration_string(struct device *dev,
                struct device_attribute *attr, char *buf)
@@ -45,7 +45,7 @@ static ssize_t show_configuration_string(struct device *dev,
        struct usb_device *udev;
        struct usb_host_config *actconfig;
 
-       udev = to_usb_device (dev);
+       udev = to_usb_device(dev);
        actconfig = udev->actconfig;
        if ((!actconfig) || (!actconfig->string))
                return 0;
@@ -57,16 +57,16 @@ static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
 usb_actconfig_show(bConfigurationValue, 1, "%u\n");
 
 static ssize_t
-set_bConfigurationValue (struct device *dev, struct device_attribute *attr,
+set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
                const char *buf, size_t count)
 {
-       struct usb_device       *udev = to_usb_device (dev);
+       struct usb_device       *udev = to_usb_device(dev);
        int                     config, value;
 
-       if (sscanf (buf, "%u", &config) != 1 || config > 255)
+       if (sscanf(buf, "%u", &config) != 1 || config > 255)
                return -EINVAL;
        usb_lock_device(udev);
-       value = usb_set_configuration (udev, config);
+       value = usb_set_configuration(udev, config);
        usb_unlock_device(udev);
        return (value < 0) ? value : count;
 }
@@ -81,7 +81,7 @@ static ssize_t  show_##name(struct device *dev,                               \
 {                                                                      \
        struct usb_device *udev;                                        \
                                                                        \
-       udev = to_usb_device (dev);                                     \
+       udev = to_usb_device(dev);                                      \
        return sprintf(buf, "%s\n", udev->name);                        \
 }                                                                      \
 static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
@@ -91,12 +91,12 @@ usb_string_attr(manufacturer);
 usb_string_attr(serial);
 
 static ssize_t
-show_speed (struct device *dev, struct device_attribute *attr, char *buf)
+show_speed(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct usb_device *udev;
        char *speed;
 
-       udev = to_usb_device (dev);
+       udev = to_usb_device(dev);
 
        switch (udev->speed) {
        case USB_SPEED_LOW:
@@ -112,22 +112,22 @@ show_speed (struct device *dev, struct device_attribute *attr, char *buf)
        default:
                speed = "unknown";
        }
-       return sprintf (buf, "%s\n", speed);
+       return sprintf(buf, "%s\n", speed);
 }
 static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);
 
 static ssize_t
-show_devnum (struct device *dev, struct device_attribute *attr, char *buf)
+show_devnum(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct usb_device *udev;
 
-       udev = to_usb_device (dev);
-       return sprintf (buf, "%d\n", udev->devnum);
+       udev = to_usb_device(dev);
+       return sprintf(buf, "%d\n", udev->devnum);
 }
 static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL);
 
 static ssize_t
-show_version (struct device *dev, struct device_attribute *attr, char *buf)
+show_version(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct usb_device *udev;
        u16 bcdUSB;
@@ -139,25 +139,25 @@ show_version (struct device *dev, struct device_attribute *attr, char *buf)
 static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
 
 static ssize_t
-show_maxchild (struct device *dev, struct device_attribute *attr, char *buf)
+show_maxchild(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct usb_device *udev;
 
-       udev = to_usb_device (dev);
-       return sprintf (buf, "%d\n", udev->maxchild);
+       udev = to_usb_device(dev);
+       return sprintf(buf, "%d\n", udev->maxchild);
 }
 static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL);
 
 /* Descriptor fields */
 #define usb_descriptor_attr_le16(field, format_string)                 \
 static ssize_t                                                         \
-show_##field (struct device *dev, struct device_attribute *attr,       \
+show_##field(struct device *dev, struct device_attribute *attr,        \
                char *buf)                                              \
 {                                                                      \
        struct usb_device *udev;                                        \
                                                                        \
-       udev = to_usb_device (dev);                                     \
-       return sprintf (buf, format_string,                             \
+       udev = to_usb_device(dev);                                      \
+       return sprintf(buf, format_string,                              \
                        le16_to_cpu(udev->descriptor.field));           \
 }                                                                      \
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
@@ -168,21 +168,21 @@ usb_descriptor_attr_le16(bcdDevice, "%04x\n")
 
 #define usb_descriptor_attr(field, format_string)                      \
 static ssize_t                                                         \
-show_##field (struct device *dev, struct device_attribute *attr,       \
+show_##field(struct device *dev, struct device_attribute *attr,        \
                char *buf)                                              \
 {                                                                      \
        struct usb_device *udev;                                        \
                                                                        \
-       udev = to_usb_device (dev);                                     \
-       return sprintf (buf, format_string, udev->descriptor.field);    \
+       udev = to_usb_device(dev);                                      \
+       return sprintf(buf, format_string, udev->descriptor.field);     \
 }                                                                      \
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 
-usb_descriptor_attr (bDeviceClass, "%02x\n")
-usb_descriptor_attr (bDeviceSubClass, "%02x\n")
-usb_descriptor_attr (bDeviceProtocol, "%02x\n")
-usb_descriptor_attr (bNumConfigurations, "%d\n")
-usb_descriptor_attr (bMaxPacketSize0, "%d\n")
+usb_descriptor_attr(bDeviceClass, "%02x\n")
+usb_descriptor_attr(bDeviceSubClass, "%02x\n")
+usb_descriptor_attr(bDeviceProtocol, "%02x\n")
+usb_descriptor_attr(bNumConfigurations, "%d\n")
+usb_descriptor_attr(bMaxPacketSize0, "%d\n")
 
 static struct attribute *dev_attrs[] = {
        /* current configuration's attributes */
@@ -220,17 +220,17 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
                return retval;
 
        if (udev->manufacturer) {
-               retval = device_create_file (dev, &dev_attr_manufacturer);
+               retval = device_create_file(dev, &dev_attr_manufacturer);
                if (retval)
                        goto error;
        }
        if (udev->product) {
-               retval = device_create_file (dev, &dev_attr_product);
+               retval = device_create_file(dev, &dev_attr_product);
                if (retval)
                        goto error;
        }
        if (udev->serial) {
-               retval = device_create_file (dev, &dev_attr_serial);
+               retval = device_create_file(dev, &dev_attr_serial);
                if (retval)
                        goto error;
        }
@@ -246,7 +246,7 @@ error:
        return retval;
 }
 
-void usb_remove_sysfs_dev_files (struct usb_device *udev)
+void usb_remove_sysfs_dev_files(struct usb_device *udev)
 {
        struct device *dev = &udev->dev;
 
@@ -264,22 +264,22 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev)
 /* Interface fields */
 #define usb_intf_attr(field, format_string)                            \
 static ssize_t                                                         \
-show_##field (struct device *dev, struct device_attribute *attr,       \
+show_##field(struct device *dev, struct device_attribute *attr,        \
                char *buf)                                              \
 {                                                                      \
-       struct usb_interface *intf = to_usb_interface (dev);            \
+       struct usb_interface *intf = to_usb_interface(dev);             \
                                                                        \
-       return sprintf (buf, format_string,                             \
+       return sprintf(buf, format_string,                              \
                        intf->cur_altsetting->desc.field);              \
 }                                                                      \
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 
-usb_intf_attr (bInterfaceNumber, "%02x\n")
-usb_intf_attr (bAlternateSetting, "%2d\n")
-usb_intf_attr (bNumEndpoints, "%02x\n")
-usb_intf_attr (bInterfaceClass, "%02x\n")
-usb_intf_attr (bInterfaceSubClass, "%02x\n")
-usb_intf_attr (bInterfaceProtocol, "%02x\n")
+usb_intf_attr(bInterfaceNumber, "%02x\n")
+usb_intf_attr(bAlternateSetting, "%2d\n")
+usb_intf_attr(bNumEndpoints, "%02x\n")
+usb_intf_attr(bInterfaceClass, "%02x\n")
+usb_intf_attr(bInterfaceSubClass, "%02x\n")
+usb_intf_attr(bInterfaceProtocol, "%02x\n")
 
 static ssize_t show_interface_string(struct device *dev,
                struct device_attribute *attr, char *buf)
@@ -288,8 +288,8 @@ static ssize_t show_interface_string(struct device *dev,
        struct usb_device *udev;
        int len;
 
-       intf = to_usb_interface (dev);
-       udev = interface_to_usbdev (intf);
+       intf = to_usb_interface(dev);
+       udev = interface_to_usbdev(intf);
        len = snprintf(buf, 256, "%s", intf->cur_altsetting->string);
        if (len < 0)
                return 0;
@@ -384,7 +384,7 @@ error:
        return retval;
 }
 
-void usb_remove_sysfs_intf_files (struct usb_interface *intf)
+void usb_remove_sysfs_intf_files(struct usb_interface *intf)
 {
        usb_remove_intf_ep_files(intf);
        sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
index 9801d08..94ea972 100644 (file)
@@ -235,16 +235,15 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 
        urb->status = -EINPROGRESS;
        urb->actual_length = 0;
-       urb->bandwidth = 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);
+       temp = usb_pipetype(pipe);
+       is_out = usb_pipeout(pipe);
 
-       if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED)
+       if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
                return -ENODEV;
 
        /* FIXME there should be a sharable lock protecting us against
@@ -253,11 +252,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
         * checks get made.)
         */
 
-       max = usb_maxpacket (dev, pipe, is_out);
+       max = usb_maxpacket(dev, pipe, is_out);
        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_pipeendpoint(pipe), is_out ? "out" : "in",
                        __FUNCTION__, max);
                return -EMSGSIZE;
        }
@@ -279,11 +278,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                if (urb->number_of_packets <= 0)                    
                        return -EINVAL;
                for (n = 0; n < urb->number_of_packets; n++) {
-                       len = urb->iso_frame_desc [n].length;
+                       len = urb->iso_frame_desc[n].length;
                        if (len < 0 || len > max) 
                                return -EMSGSIZE;
-                       urb->iso_frame_desc [n].status = -EXDEV;
-                       urb->iso_frame_desc [n].actual_length = 0;
+                       urb->iso_frame_desc[n].status = -EXDEV;
+                       urb->iso_frame_desc[n].actual_length = 0;
                }
        }
 
@@ -322,7 +321,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 
        /* fail if submitter gave bogus flags */
        if (urb->transfer_flags != orig_flags) {
-               err ("BOGUS urb flags, %x --> %x",
+               err("BOGUS urb flags, %x --> %x",
                        orig_flags, urb->transfer_flags);
                return -EINVAL;
        }
@@ -373,7 +372,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                urb->interval = temp;
        }
 
-       return usb_hcd_submit_urb (urb, mem_flags);
+       return usb_hcd_submit_urb(urb, mem_flags);
 }
 
 /*-------------------------------------------------------------------*/
index 02426d0..3db721c 100644 (file)
@@ -233,7 +233,7 @@ static void usb_autosuspend_work(struct work_struct *work)
  * @parent: hub to which device is connected; null to allocate a root hub
  * @bus: bus used to access the device
  * @port1: one-based index of port; ignored for root hubs
- * Context: !in_interrupt ()
+ * Context: !in_interrupt()
  *
  * Only hub drivers (including virtual root hub drivers for host
  * controllers) should ever call this.
@@ -277,22 +277,22 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
         * as stable:  bus->busnum changes easily from modprobe order,
         * cardbus or pci hotplugging, and so on.
         */
-       if (unlikely (!parent)) {
-               dev->devpath [0] = '0';
+       if (unlikely(!parent)) {
+               dev->devpath[0] = '0';
 
                dev->dev.parent = bus->controller;
-               sprintf (&dev->dev.bus_id[0], "usb%d", bus->busnum);
+               sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
        } else {
                /* match any labeling on the hubs; it's one-based */
-               if (parent->devpath [0] == '0')
-                       snprintf (dev->devpath, sizeof dev->devpath,
+               if (parent->devpath[0] == '0')
+                       snprintf(dev->devpath, sizeof dev->devpath,
                                "%d", port1);
                else
-                       snprintf (dev->devpath, sizeof dev->devpath,
+                       snprintf(dev->devpath, sizeof dev->devpath,
                                "%s.%d", parent->devpath, port1);
 
                dev->dev.parent = &parent->dev;
-               sprintf (&dev->dev.bus_id[0], "%d-%s",
+               sprintf(&dev->dev.bus_id[0], "%d-%s",
                        bus->busnum, dev->devpath);
 
                /* hub driver sets up TT records */
@@ -463,7 +463,7 @@ static struct usb_device *match_device(struct usb_device *dev,
        /* see if this device matches */
        if ((vendor_id == le16_to_cpu(dev->descriptor.idVendor)) &&
            (product_id == le16_to_cpu(dev->descriptor.idProduct))) {
-               dev_dbg (&dev->dev, "matched this device!\n");
+               dev_dbg(&dev->dev, "matched this device!\n");
                ret_dev = usb_get_dev(dev);
                goto exit;
        }
@@ -535,7 +535,7 @@ exit:
  */
 int usb_get_current_frame_number(struct usb_device *dev)
 {
-       return usb_hcd_get_frame_number (dev);
+       return usb_hcd_get_frame_number(dev);
 }
 
 /*-------------------------------------------------------------------*/
@@ -593,7 +593,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
  *
  * When the buffer is no longer used, free it with usb_buffer_free().
  */
-void *usb_buffer_alloc (
+void *usb_buffer_alloc(
        struct usb_device *dev,
        size_t size,
        gfp_t mem_flags,
@@ -602,7 +602,7 @@ void *usb_buffer_alloc (
 {
        if (!dev || !dev->bus)
                return NULL;
-       return hcd_buffer_alloc (dev->bus, size, mem_flags, dma);
+       return hcd_buffer_alloc(dev->bus, size, mem_flags, dma);
 }
 
 /**
@@ -616,7 +616,7 @@ void *usb_buffer_alloc (
  * been allocated using usb_buffer_alloc(), and the parameters must match
  * those provided in that allocation request. 
  */
-void usb_buffer_free (
+void usb_buffer_free(
        struct usb_device *dev,
        size_t size,
        void *addr,
@@ -627,7 +627,7 @@ void usb_buffer_free (
                return;
        if (!addr)
                return;
-       hcd_buffer_free (dev->bus, size, addr, dma);
+       hcd_buffer_free(dev->bus, size, addr, dma);
 }
 
 /**
@@ -647,7 +647,7 @@ void usb_buffer_free (
  * Reverse the effect of this call with usb_buffer_unmap().
  */
 #if 0
-struct urb *usb_buffer_map (struct urb *urb)
+struct urb *usb_buffer_map(struct urb *urb)
 {
        struct usb_bus          *bus;
        struct device           *controller;
@@ -659,14 +659,14 @@ struct urb *usb_buffer_map (struct urb *urb)
                return NULL;
 
        if (controller->dma_mask) {
-               urb->transfer_dma = dma_map_single (controller,
+               urb->transfer_dma = dma_map_single(controller,
                        urb->transfer_buffer, urb->transfer_buffer_length,
-                       usb_pipein (urb->pipe)
+                       usb_pipein(urb->pipe)
                                ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-               if (usb_pipecontrol (urb->pipe))
-                       urb->setup_dma = dma_map_single (controller,
+               if (usb_pipecontrol(urb->pipe))
+                       urb->setup_dma = dma_map_single(controller,
                                        urb->setup_packet,
-                                       sizeof (struct usb_ctrlrequest),
+                                       sizeof(struct usb_ctrlrequest),
                                        DMA_TO_DEVICE);
        // FIXME generic api broken like pci, can't report errors
        // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
@@ -689,7 +689,7 @@ struct urb *usb_buffer_map (struct urb *urb)
  * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s)
  * @urb: urb whose transfer_buffer/setup_packet will be synchronized
  */
-void usb_buffer_dmasync (struct urb *urb)
+void usb_buffer_dmasync(struct urb *urb)
 {
        struct usb_bus          *bus;
        struct device           *controller;
@@ -702,14 +702,14 @@ void usb_buffer_dmasync (struct urb *urb)
                return;
 
        if (controller->dma_mask) {
-               dma_sync_single (controller,
+               dma_sync_single(controller,
                        urb->transfer_dma, urb->transfer_buffer_length,
-                       usb_pipein (urb->pipe)
+                       usb_pipein(urb->pipe)
                                ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-               if (usb_pipecontrol (urb->pipe))
-                       dma_sync_single (controller,
+               if (usb_pipecontrol(urb->pipe))
+                       dma_sync_single(controller,
                                        urb->setup_dma,
-                                       sizeof (struct usb_ctrlrequest),
+                                       sizeof(struct usb_ctrlrequest),
                                        DMA_TO_DEVICE);
        }
 }
@@ -722,7 +722,7 @@ void usb_buffer_dmasync (struct urb *urb)
  * Reverses the effect of usb_buffer_map().
  */
 #if 0
-void usb_buffer_unmap (struct urb *urb)
+void usb_buffer_unmap(struct urb *urb)
 {
        struct usb_bus          *bus;
        struct device           *controller;
@@ -735,14 +735,14 @@ void usb_buffer_unmap (struct urb *urb)
                return;
 
        if (controller->dma_mask) {
-               dma_unmap_single (controller,
+               dma_unmap_single(controller,
                        urb->transfer_dma, urb->transfer_buffer_length,
-                       usb_pipein (urb->pipe)
+                       usb_pipein(urb->pipe)
                                ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-               if (usb_pipecontrol (urb->pipe))
-                       dma_unmap_single (controller,
+               if (usb_pipecontrol(urb->pipe))
+                       dma_unmap_single(controller,
                                        urb->setup_dma,
-                                       sizeof (struct usb_ctrlrequest),
+                                       sizeof(struct usb_ctrlrequest),
                                        DMA_TO_DEVICE);
        }
        urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP
@@ -783,15 +783,15 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
        struct device           *controller;
 
        if (!dev
-                       || usb_pipecontrol (pipe)
+                       || usb_pipecontrol(pipe)
                        || !(bus = dev->bus)
                        || !(controller = bus->controller)
                        || !controller->dma_mask)
                return -1;
 
        // 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);
+       return dma_map_sg(controller, sg, nents,
+                       usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /* XXX DISABLED, no users currently.  If you wish to re-enable this
@@ -823,8 +823,8 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
                        || !controller->dma_mask)
                return;
 
-       dma_sync_sg (controller, sg, n_hw_ents,
-                       usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+       dma_sync_sg(controller, sg, n_hw_ents,
+                       usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 #endif
 
@@ -849,8 +849,8 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
                        || !controller->dma_mask)
                return;
 
-       dma_unmap_sg (controller, sg, n_hw_ents,
-                       usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+       dma_unmap_sg(controller, sg, n_hw_ents,
+                       usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /* format to disable USB on kernel command line is: nousb */
@@ -871,7 +871,7 @@ static int __init usb_init(void)
 {
        int retval;
        if (nousb) {
-               pr_info ("%s: USB support disabled\n", usbcore_name);
+               pr_info("%s: USB support disabled\n", usbcore_name);
                return 0;
        }
 
@@ -971,19 +971,19 @@ EXPORT_SYMBOL(__usb_get_extra_descriptor);
 EXPORT_SYMBOL(usb_find_device);
 EXPORT_SYMBOL(usb_get_current_frame_number);
 
-EXPORT_SYMBOL (usb_buffer_alloc);
-EXPORT_SYMBOL (usb_buffer_free);
+EXPORT_SYMBOL(usb_buffer_alloc);
+EXPORT_SYMBOL(usb_buffer_free);
 
 #if 0
-EXPORT_SYMBOL (usb_buffer_map);
-EXPORT_SYMBOL (usb_buffer_dmasync);
-EXPORT_SYMBOL (usb_buffer_unmap);
+EXPORT_SYMBOL(usb_buffer_map);
+EXPORT_SYMBOL(usb_buffer_dmasync);
+EXPORT_SYMBOL(usb_buffer_unmap);
 #endif
 
-EXPORT_SYMBOL (usb_buffer_map_sg);
+EXPORT_SYMBOL(usb_buffer_map_sg);
 #if 0
-EXPORT_SYMBOL (usb_buffer_dmasync_sg);
+EXPORT_SYMBOL(usb_buffer_dmasync_sg);
 #endif
-EXPORT_SYMBOL (usb_buffer_unmap_sg);
+EXPORT_SYMBOL(usb_buffer_unmap_sg);
 
 MODULE_LICENSE("GPL");
index 812c733..f390501 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
 #include <linux/clk.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/byteorder.h>
@@ -1807,16 +1807,13 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg)
                        || !wake
                        || at91_suspend_entering_slow_clock()) {
                pullup(udc, 0);
-               disable_irq_wake(udc->udp_irq);
+               wake = 0;
        } else
                enable_irq_wake(udc->udp_irq);
 
-       if (udc->board.vbus_pin > 0) {
-               if (wake)
-                       enable_irq_wake(udc->board.vbus_pin);
-               else
-                       disable_irq_wake(udc->board.vbus_pin);
-       }
+       udc->active_suspend = wake;
+       if (udc->board.vbus_pin > 0 && wake)
+               enable_irq_wake(udc->board.vbus_pin);
        return 0;
 }
 
@@ -1824,8 +1821,14 @@ static int at91udc_resume(struct platform_device *pdev)
 {
        struct at91_udc *udc = platform_get_drvdata(pdev);
 
+       if (udc->board.vbus_pin > 0 && udc->active_suspend)
+               disable_irq_wake(udc->board.vbus_pin);
+
        /* maybe reconnect to host; if so, clocks on */
-       pullup(udc, 1);
+       if (udc->active_suspend)
+               disable_irq_wake(udc->udp_irq);
+       else
+               pullup(udc, 1);
        return 0;
 }
 #else
index 677089b..7e34e2f 100644 (file)
@@ -136,6 +136,7 @@ struct at91_udc {
        unsigned                        wait_for_addr_ack:1;
        unsigned                        wait_for_config_ack:1;
        unsigned                        selfpowered:1;
+       unsigned                        active_suspend:1;
        u8                              addr;
        struct at91_udc_data            board;
        struct clk                      *iclk, *fclk;
index 83b4866..d18901b 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/string.h>
 #include <linux/device.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 
index 53d5845..f28af06 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/ctype.h>
 #include <linux/string.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include "gadget_chips.h"
index d15bf22..22e3c94 100644 (file)
@@ -47,7 +47,7 @@
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
 #include <linux/usb_gadget.h>
 
  *
  * There's some hardware that can't talk CDC.  We make that hardware
  * implement a "minimalist" vendor-agnostic CDC core:  same framing, but
- * link-level setup only requires activating the configuration.
- * Linux supports it, but other host operating systems may not.
- * (This is a subset of CDC Ethernet.)
+ * link-level setup only requires activating the configuration.  Only the
+ * endpoint descriptors, and product/vendor IDs, are relevant; no control
+ * operations are available.  Linux supports it, but other host operating
+ * systems may not.  (This is a subset of CDC Ethernet.)
+ *
+ * It turns out that if you add a few descriptors to that "CDC Subset",
+ * (Windows) host side drivers from MCCI can treat it as one submode of
+ * a proprietary scheme called "SAFE" ... without needing to know about
+ * specific product/vendor IDs.  So we do that, making it easier to use
+ * those MS-Windows drivers.  Those added descriptors make it resemble a
+ * CDC MDLM device, but they don't change device behavior at all.  (See
+ * MCCI Engineering report 950198 "SAFE Networking Functions".)
  *
  * A third option is also in use.  Rather than CDC Ethernet, or something
  * simpler, Microsoft pushes their own approach: RNDIS.  The published
@@ -254,6 +263,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 #define DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_S3C2410
+#define DEV_CONFIG_CDC
+#endif
+
 #ifdef CONFIG_USB_GADGET_AT91
 #define DEV_CONFIG_CDC
 #endif
@@ -266,6 +279,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 #define DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_HUSB2DEV
+#define DEV_CONFIG_CDC
+#endif
+
 
 /* For CDC-incapable hardware, choose the simple cdc subset.
  * Anything that talks bulk (without notable bugs) can do this.
@@ -283,9 +300,6 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 #define        DEV_CONFIG_SUBSET
 #endif
 
-#ifdef CONFIG_USB_GADGET_S3C2410
-#define DEV_CONFIG_CDC
-#endif
 
 /*-------------------------------------------------------------------------*/
 
@@ -487,8 +501,17 @@ rndis_config = {
  * endpoint.  Both have a "data" interface and two bulk endpoints.
  * There are also differences in how control requests are handled.
  *
- * RNDIS shares a lot with CDC-Ethernet, since it's a variant of
- * the CDC-ACM (modem) spec.
+ * RNDIS shares a lot with CDC-Ethernet, since it's a variant of the
+ * CDC-ACM (modem) spec.  Unfortunately MSFT's RNDIS driver is buggy; it
+ * may hang or oops.  Since bugfixes (or accurate specs, letting Linux
+ * work around those bugs) are unlikely to ever come from MSFT, you may
+ * wish to avoid using RNDIS.
+ *
+ * MCCI offers an alternative to RNDIS if you need to connect to Windows
+ * but have hardware that can't support CDC Ethernet.   We add descriptors
+ * to present the CDC Subset as a (nonconformant) CDC MDLM variant called
+ * "SAFE".  That borrows from both CDC Ethernet and CDC MDLM.  You can
+ * get those drivers from MCCI, or bundled with various products.
  */
 
 #ifdef DEV_CONFIG_CDC
@@ -522,8 +545,6 @@ rndis_control_intf = {
 };
 #endif
 
-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
-
 static const struct usb_cdc_header_desc header_desc = {
        .bLength =              sizeof header_desc,
        .bDescriptorType =      USB_DT_CS_INTERFACE,
@@ -532,6 +553,8 @@ static const struct usb_cdc_header_desc header_desc = {
        .bcdCDC =               __constant_cpu_to_le16 (0x0110),
 };
 
+#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+
 static const struct usb_cdc_union_desc union_desc = {
        .bLength =              sizeof union_desc,
        .bDescriptorType =      USB_DT_CS_INTERFACE,
@@ -564,7 +587,40 @@ static const struct usb_cdc_acm_descriptor acm_descriptor = {
 
 #endif
 
-#ifdef DEV_CONFIG_CDC
+#ifndef DEV_CONFIG_CDC
+
+/* "SAFE" loosely follows CDC WMC MDLM, violating the spec in various
+ * ways:  data endpoints live in the control interface, there's no data
+ * interface, and it's not used to talk to a cell phone radio.
+ */
+
+static const struct usb_cdc_mdlm_desc mdlm_desc = {
+       .bLength =              sizeof mdlm_desc,
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_MDLM_TYPE,
+
+       .bcdVersion =           __constant_cpu_to_le16(0x0100),
+       .bGUID = {
+               0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
+               0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
+       },
+};
+
+/* since "usb_cdc_mdlm_detail_desc" is a variable length structure, we
+ * can't really use its struct.  All we do here is say that we're using
+ * the submode of "SAFE" which directly matches the CDC Subset.
+ */
+static const u8 mdlm_detail_desc[] = {
+       6,
+       USB_DT_CS_INTERFACE,
+       USB_CDC_MDLM_DETAIL_TYPE,
+
+       0,      /* "SAFE" */
+       0,      /* network control capabilities (none) */
+       0,      /* network data capabilities ("raw" encapsulation) */
+};
+
+#endif
 
 static const struct usb_cdc_ether_desc ether_desc = {
        .bLength =              sizeof ether_desc,
@@ -579,7 +635,6 @@ static const struct usb_cdc_ether_desc ether_desc = {
        .bNumberPowerFilters =  0,
 };
 
-#endif
 
 #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
 
@@ -672,6 +727,9 @@ rndis_data_intf = {
 /*
  * "Simple" CDC-subset option is a simple vendor-neutral model that most
  * full speed controllers can handle:  one interface, two bulk endpoints.
+ *
+ * To assist host side drivers, we fancy it up a bit, and add descriptors
+ * so some host side drivers will understand it as a "SAFE" variant.
  */
 
 static const struct usb_interface_descriptor
@@ -682,8 +740,8 @@ subset_data_intf = {
        .bInterfaceNumber =     0,
        .bAlternateSetting =    0,
        .bNumEndpoints =        2,
-       .bInterfaceClass =      USB_CLASS_VENDOR_SPEC,
-       .bInterfaceSubClass =   0,
+       .bInterfaceClass =      USB_CLASS_COMM,
+       .bInterfaceSubClass =   USB_CDC_SUBCLASS_MDLM,
        .bInterfaceProtocol =   0,
        .iInterface =           STRING_DATA,
 };
@@ -731,10 +789,15 @@ static const struct usb_descriptor_header *fs_eth_function [11] = {
 static inline void __init fs_subset_descriptors(void)
 {
 #ifdef DEV_CONFIG_SUBSET
+       /* behavior is "CDC Subset"; extra descriptors say "SAFE" */
        fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
-       fs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
-       fs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
-       fs_eth_function[4] = NULL;
+       fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+       fs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+       fs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+       fs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+       fs_eth_function[6] = (struct usb_descriptor_header *) &fs_source_desc;
+       fs_eth_function[7] = (struct usb_descriptor_header *) &fs_sink_desc;
+       fs_eth_function[8] = NULL;
 #else
        fs_eth_function[1] = NULL;
 #endif
@@ -828,10 +891,15 @@ static const struct usb_descriptor_header *hs_eth_function [11] = {
 static inline void __init hs_subset_descriptors(void)
 {
 #ifdef DEV_CONFIG_SUBSET
+       /* behavior is "CDC Subset"; extra descriptors say "SAFE" */
        hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
-       hs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
-       hs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
-       hs_eth_function[4] = NULL;
+       hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+       hs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+       hs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+       hs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+       hs_eth_function[6] = (struct usb_descriptor_header *) &hs_source_desc;
+       hs_eth_function[7] = (struct usb_descriptor_header *) &hs_sink_desc;
+       hs_eth_function[8] = NULL;
 #else
        hs_eth_function[1] = NULL;
 #endif
@@ -878,10 +946,8 @@ static char                                manufacturer [50];
 static char                            product_desc [40] = DRIVER_DESC;
 static char                            serial_number [20];
 
-#ifdef DEV_CONFIG_CDC
 /* address that the host will use ... usually assigned at random */
 static char                            ethaddr [2 * ETH_ALEN + 1];
-#endif
 
 /* static strings, in UTF-8 */
 static struct usb_string               strings [] = {
@@ -889,9 +955,9 @@ static struct usb_string            strings [] = {
        { STRING_PRODUCT,       product_desc, },
        { STRING_SERIALNUMBER,  serial_number, },
        { STRING_DATA,          "Ethernet Data", },
+       { STRING_ETHADDR,       ethaddr, },
 #ifdef DEV_CONFIG_CDC
        { STRING_CDC,           "CDC Ethernet", },
-       { STRING_ETHADDR,       ethaddr, },
        { STRING_CONTROL,       "CDC Communications Control", },
 #endif
 #ifdef DEV_CONFIG_SUBSET
@@ -986,10 +1052,10 @@ set_ether_config (struct eth_dev *dev, gfp_t gfp_flags)
        }
 #endif
 
-       dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
+       dev->in = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
        dev->in_ep->driver_data = dev;
 
-       dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
+       dev->out = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
        dev->out_ep->driver_data = dev;
 
        /* With CDC,  the host isn't allowed to use these two data
@@ -2278,10 +2344,10 @@ eth_bind (struct usb_gadget *gadget)
                        "RNDIS/%s", driver_desc);
 
        /* CDC subset ... recognized by Linux since 2.4.10, but Windows
-        * drivers aren't widely available.
+        * drivers aren't widely available.  (That may be improved by
+        * supporting one submode of the "SAFE" variant of MDLM.)
         */
        } else if (!cdc) {
-               device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
                device_desc.idVendor =
                        __constant_cpu_to_le16(SIMPLE_VENDOR_NUM);
                device_desc.idProduct =
@@ -2352,6 +2418,10 @@ autoconf_fail:
        if (!cdc) {
                eth_config.bNumInterfaces = 1;
                eth_config.iConfiguration = STRING_SUBSET;
+
+               /* use functions to set these up, in case we're built to work
+                * with multiple controllers and must override CDC Ethernet.
+                */
                fs_subset_descriptors();
                hs_subset_descriptors();
        }
@@ -2415,22 +2485,20 @@ autoconf_fail:
 
        /* Module params for these addresses should come from ID proms.
         * The host side address is used with CDC and RNDIS, and commonly
-        * ends up in a persistent config database.
+        * ends up in a persistent config database.  It's not clear if
+        * host side code for the SAFE thing cares -- its original BLAN
+        * thing didn't, Sharp never assigned those addresses on Zaurii.
         */
        if (get_ether_addr(dev_addr, net->dev_addr))
                dev_warn(&gadget->dev,
                        "using random %s ethernet address\n", "self");
-       if (cdc || rndis) {
-               if (get_ether_addr(host_addr, dev->host_mac))
-                       dev_warn(&gadget->dev,
-                               "using random %s ethernet address\n", "host");
-#ifdef DEV_CONFIG_CDC
-               snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
-                       dev->host_mac [0], dev->host_mac [1],
-                       dev->host_mac [2], dev->host_mac [3],
-                       dev->host_mac [4], dev->host_mac [5]);
-#endif
-       }
+       if (get_ether_addr(host_addr, dev->host_mac))
+               dev_warn(&gadget->dev,
+                       "using random %s ethernet address\n", "host");
+       snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
+               dev->host_mac [0], dev->host_mac [1],
+               dev->host_mac [2], dev->host_mac [3],
+               dev->host_mac [4], dev->host_mac [5]);
 
        if (rndis) {
                status = rndis_init();
index 72f2ae9..f04a29a 100644 (file)
 #include <linux/freezer.h>
 #include <linux/utsname.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include "gadget_chips.h"
@@ -1148,7 +1148,7 @@ static int ep0_queue(struct fsg_dev *fsg)
 
 static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
 {
-       struct fsg_dev          *fsg = (struct fsg_dev *) ep->driver_data;
+       struct fsg_dev          *fsg = ep->driver_data;
 
        if (req->actual > 0)
                dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
@@ -1170,8 +1170,8 @@ static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
 
 static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
 {
-       struct fsg_dev          *fsg = (struct fsg_dev *) ep->driver_data;
-       struct fsg_buffhd       *bh = (struct fsg_buffhd *) req->context;
+       struct fsg_dev          *fsg = ep->driver_data;
+       struct fsg_buffhd       *bh = req->context;
 
        if (req->status || req->actual != req->length)
                DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
@@ -1190,8 +1190,8 @@ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
 
 static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
 {
-       struct fsg_dev          *fsg = (struct fsg_dev *) ep->driver_data;
-       struct fsg_buffhd       *bh = (struct fsg_buffhd *) req->context;
+       struct fsg_dev          *fsg = ep->driver_data;
+       struct fsg_buffhd       *bh = req->context;
 
        dump_msg(fsg, "bulk-out", req->buf, req->actual);
        if (req->status || req->actual != bh->bulk_out_intended_length)
@@ -1214,8 +1214,8 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
 #ifdef CONFIG_USB_FILE_STORAGE_TEST
 static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
 {
-       struct fsg_dev          *fsg = (struct fsg_dev *) ep->driver_data;
-       struct fsg_buffhd       *bh = (struct fsg_buffhd *) req->context;
+       struct fsg_dev          *fsg = ep->driver_data;
+       struct fsg_buffhd       *bh = req->context;
 
        if (req->status || req->actual != req->length)
                DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
@@ -2577,7 +2577,7 @@ static int send_status(struct fsg_dev *fsg)
        }
 
        if (transport_is_bbb()) {
-               struct bulk_cs_wrap     *csw = (struct bulk_cs_wrap *) bh->buf;
+               struct bulk_cs_wrap     *csw = bh->buf;
 
                /* Store and send the Bulk-only CSW */
                csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG);
@@ -2596,8 +2596,7 @@ static int send_status(struct fsg_dev *fsg)
                return 0;
 
        } else {                        // USB_PR_CBI
-               struct interrupt_data   *buf = (struct interrupt_data *)
-                                               bh->buf;
+               struct interrupt_data   *buf = bh->buf;
 
                /* Store and send the Interrupt data.  UFI sends the ASC
                 * and ASCQ bytes.  Everything else sends a Type (which
@@ -2982,7 +2981,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
 static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
 {
        struct usb_request      *req = bh->outreq;
-       struct bulk_cb_wrap     *cbw = (struct bulk_cb_wrap *) req->buf;
+       struct bulk_cb_wrap     *cbw = req->buf;
 
        /* Was this a real packet? */
        if (req->status)
@@ -3428,7 +3427,7 @@ static void handle_exception(struct fsg_dev *fsg)
 
 static int fsg_main_thread(void *fsg_)
 {
-       struct fsg_dev          *fsg = (struct fsg_dev *) fsg_;
+       struct fsg_dev          *fsg = fsg_;
 
        /* Allow the thread to be killed by a signal, but set the signal mask
         * to block everything but INT, TERM, KILL, and USR1. */
@@ -3600,7 +3599,7 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *
 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 = (struct fsg_dev *) dev_get_drvdata(dev);
+       struct fsg_dev  *fsg = dev_get_drvdata(dev);
        char            *p;
        ssize_t         rc;
 
@@ -3629,7 +3628,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
 {
        ssize_t         rc = count;
        struct lun      *curlun = dev_to_lun(dev);
-       struct fsg_dev  *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+       struct fsg_dev  *fsg = dev_get_drvdata(dev);
        int             i;
 
        if (sscanf(buf, "%d", &i) != 1)
@@ -3652,7 +3651,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
 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 = (struct fsg_dev *) dev_get_drvdata(dev);
+       struct fsg_dev  *fsg = dev_get_drvdata(dev);
        int             rc = 0;
 
        if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) {
@@ -3700,7 +3699,7 @@ static void fsg_release(struct kref *ref)
 
 static void lun_release(struct device *dev)
 {
-       struct fsg_dev  *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+       struct fsg_dev  *fsg = dev_get_drvdata(dev);
 
        kref_put(&fsg->ref, fsg_release);
 }
index aa80f09..2e3d662 100644 (file)
 #define        gadget_is_pxa27x(g)     0
 #endif
 
+#ifdef CONFIG_USB_GADGET_HUSB2DEV
+#define gadget_is_husb2dev(g)  !strcmp("husb2_udc", (g)->name)
+#else
+#define gadget_is_husb2dev(g)  0
+#endif
+
 #ifdef CONFIG_USB_GADGET_S3C2410
 #define gadget_is_s3c2410(g)    !strcmp("s3c2410_udc", (g)->name)
 #else
@@ -169,5 +175,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
                return 0x16;
        else if (gadget_is_mpc8272(gadget))
                return 0x17;
+       else if (gadget_is_husb2dev(gadget))
+               return 0x18;
        return -ENOENT;
 }
index f1a6796..d08a8d0 100644 (file)
@@ -35,7 +35,7 @@
 #include <sound/initval.h>
 #include <sound/rawmidi.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb/audio.h>
 #include <linux/usb/midi.h>
index d0ef1d6..e873cf4 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
 #include <linux/device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/byteorder.h>
index 3fb1044..34296e7 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 
-// #define     DEBUG                   /* data to help fault diagnosis */
+// #define     DEBUG                   /* data to help fault diagnosis */
 // #define     VERBOSE         /* extra debug messages (success too) */
 
 #include <linux/init.h>
  *   may serve as a source of device events, used to handle all control
  *   requests other than basic enumeration.
  *
- * - Then either immediately, or after a SET_CONFIGURATION control request,
- *   ep_config() is called when each /dev/gadget/ep* file is configured
- *   (by writing endpoint descriptors).  Afterwards these files are used
- *   to write() IN data or to read() OUT data.  To halt the endpoint, a
- *   "wrong direction" request is issued (like reading an IN endpoint).
+ * - Then, after a SET_CONFIGURATION control request, ep_config() is
+ *   called when each /dev/gadget/ep* file is configured (by writing
+ *   endpoint descriptors).  Afterwards these files are used to write()
+ *   IN data or to read() OUT data.  To halt the endpoint, a "wrong
+ *   direction" request is issued (like reading an IN endpoint).
  *
  * Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe
  * not possible on all hardware.  For example, precise fault handling with
@@ -98,16 +98,16 @@ enum ep0_state {
         * must always write descriptors to initialize the device, then
         * the device becomes UNCONNECTED until enumeration.
         */
-       STATE_OPENED,
+       STATE_DEV_OPENED,
 
        /* From then on, ep0 fd is in either of two basic modes:
         * - (UN)CONNECTED: read usb_gadgetfs_event(s) from it
         * - SETUP: read/write will transfer control data and succeed;
         *   or if "wrong direction", performs protocol stall
         */
-       STATE_UNCONNECTED,
-       STATE_CONNECTED,
-       STATE_SETUP,
+       STATE_DEV_UNCONNECTED,
+       STATE_DEV_CONNECTED,
+       STATE_DEV_SETUP,
 
        /* UNBOUND means the driver closed ep0, so the device won't be
         * accessible again (DEV_DISABLED) until all fds are closed.
@@ -121,7 +121,7 @@ enum ep0_state {
 struct dev_data {
        spinlock_t                      lock;
        atomic_t                        count;
-       enum ep0_state                  state;
+       enum ep0_state                  state;          /* P: lock */
        struct usb_gadgetfs_event       event [N_EVENT];
        unsigned                        ev_next;
        struct fasync_struct            *fasync;
@@ -188,7 +188,6 @@ static struct dev_data *dev_new (void)
 enum ep_state {
        STATE_EP_DISABLED = 0,
        STATE_EP_READY,
-       STATE_EP_DEFER_ENABLE,
        STATE_EP_ENABLED,
        STATE_EP_UNBOUND,
 };
@@ -313,18 +312,10 @@ nonblock:
 
        if ((val = down_interruptible (&epdata->lock)) < 0)
                return val;
-newstate:
+
        switch (epdata->state) {
        case STATE_EP_ENABLED:
                break;
-       case STATE_EP_DEFER_ENABLE:
-               DBG (epdata->dev, "%s wait for host\n", epdata->name);
-               if ((val = wait_event_interruptible (epdata->wait, 
-                               epdata->state != STATE_EP_DEFER_ENABLE
-                               || epdata->dev->state == STATE_DEV_UNBOUND
-                               )) < 0)
-                       goto fail;
-               goto newstate;
        // case STATE_EP_DISABLED:              /* "can't happen" */
        // case STATE_EP_READY:                 /* "can't happen" */
        default:                                /* error! */
@@ -333,7 +324,6 @@ newstate:
                // FALLTHROUGH
        case STATE_EP_UNBOUND:                  /* clean disconnect */
                val = -ENODEV;
-fail:
                up (&epdata->lock);
        }
        return val;
@@ -565,29 +555,28 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb)
        ssize_t                 len, total;
        int                     i;
 
-       /* we "retry" to get the right mm context for this: */
-
-       /* copy stuff into user buffers */
-       total = priv->actual;
-       len = 0;
-       for (i=0; i < priv->nr_segs; i++) {
-               ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
-
-               if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
-                       if (len == 0)
-                               len = -EFAULT;
-                       break;
-               }
-
-               total -= this;
-               len += this;
-               if (total == 0)
-                       break;
-       }
-       kfree(priv->buf);
-       kfree(priv);
-       aio_put_req(iocb);
-       return len;
+       /* we "retry" to get the right mm context for this: */
+
+       /* copy stuff into user buffers */
+       total = priv->actual;
+       len = 0;
+       for (i=0; i < priv->nr_segs; i++) {
+               ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
+
+               if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
+                       if (len == 0)
+                               len = -EFAULT;
+                       break;
+               }
+
+               total -= this;
+               len += this;
+               if (total == 0)
+                       break;
+       }
+       kfree(priv->buf);
+       kfree(priv);
+       return len;
 }
 
 static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
@@ -600,18 +589,17 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
        spin_lock(&epdata->dev->lock);
        priv->req = NULL;
        priv->epdata = NULL;
-       if (priv->iv == NULL
-                       || unlikely(req->actual == 0)
-                       || unlikely(kiocbIsCancelled(iocb))) {
+
+       /* if this was a write or a read returning no data then we
+        * don't need to copy anything to userspace, so we can
+        * complete the aio request immediately.
+        */
+       if (priv->iv == NULL || unlikely(req->actual == 0)) {
                kfree(req->buf);
                kfree(priv);
                iocb->private = NULL;
                /* aio_complete() reports bytes-transferred _and_ faults */
-               if (unlikely(kiocbIsCancelled(iocb)))
-                       aio_put_req(iocb);
-               else
-                       aio_complete(iocb,
-                               req->actual ? req->actual : req->status,
+               aio_complete(iocb, req->actual ? req->actual : req->status,
                                req->status);
        } else {
                /* retry() won't report both; so we hide some faults */
@@ -636,7 +624,7 @@ ep_aio_rwtail(
        size_t          len,
        struct ep_data  *epdata,
        const struct iovec *iv,
-       unsigned long   nr_segs
+       unsigned long   nr_segs
 )
 {
        struct kiocb_priv       *priv;
@@ -852,9 +840,9 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                break;
 #endif
        default:
-               DBG (data->dev, "unconnected, %s init deferred\n",
+               DBG(data->dev, "unconnected, %s init abandoned\n",
                                data->name);
-               data->state = STATE_EP_DEFER_ENABLE;
+               value = -EINVAL;
        }
        if (value == 0) {
                fd->f_op = &ep_io_operations;
@@ -943,22 +931,24 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req)
 static void ep0_complete (struct usb_ep *ep, struct usb_request *req)
 {
        struct dev_data         *dev = ep->driver_data;
+       unsigned long           flags;
        int                     free = 1;
 
        /* for control OUT, data must still get to userspace */
+       spin_lock_irqsave(&dev->lock, flags);
        if (!dev->setup_in) {
                dev->setup_out_error = (req->status != 0);
                if (!dev->setup_out_error)
                        free = 0;
                dev->setup_out_ready = 1;
                ep0_readable (dev);
-       } else if (dev->state == STATE_SETUP)
-               dev->state = STATE_CONNECTED;
+       }
 
        /* clean up as appropriate */
        if (free && req->buf != &dev->rbuf)
                clean_req (ep, req);
        req->complete = epio_complete;
+       spin_unlock_irqrestore(&dev->lock, flags);
 }
 
 static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
@@ -998,13 +988,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
        }
 
        /* control DATA stage */
-       if ((state = dev->state) == STATE_SETUP) {
+       if ((state = dev->state) == STATE_DEV_SETUP) {
 
                if (dev->setup_in) {            /* stall IN */
                        VDEBUG(dev, "ep0in stall\n");
                        (void) usb_ep_set_halt (dev->gadget->ep0);
                        retval = -EL2HLT;
-                       dev->state = STATE_CONNECTED;
+                       dev->state = STATE_DEV_CONNECTED;
 
                } else if (len == 0) {          /* ack SET_CONFIGURATION etc */
                        struct usb_ep           *ep = dev->gadget->ep0;
@@ -1012,7 +1002,7 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
 
                        if ((retval = setup_req (ep, req, 0)) == 0)
                                retval = usb_ep_queue (ep, req, GFP_ATOMIC);
-                       dev->state = STATE_CONNECTED;
+                       dev->state = STATE_DEV_CONNECTED;
 
                        /* assume that was SET_CONFIGURATION */
                        if (dev->current_config) {
@@ -1040,6 +1030,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
                        spin_lock_irq (&dev->lock);
                        if (retval)
                                goto done;
+
+                       if (dev->state != STATE_DEV_SETUP) {
+                               retval = -ECANCELED;
+                               goto done;
+                       }
+                       dev->state = STATE_DEV_CONNECTED;
+
                        if (dev->setup_out_error)
                                retval = -EIO;
                        else {
@@ -1066,39 +1063,36 @@ scan:
        /* return queued events right away */
        if (dev->ev_next != 0) {
                unsigned                i, n;
-               int                     tmp = dev->ev_next;
 
-               len = min (len, tmp * sizeof (struct usb_gadgetfs_event));
                n = len / sizeof (struct usb_gadgetfs_event);
+               if (dev->ev_next < n)
+                       n = dev->ev_next;
 
-               /* ep0 can't deliver events when STATE_SETUP */
+               /* ep0 i/o has special semantics during STATE_DEV_SETUP */
                for (i = 0; i < n; i++) {
                        if (dev->event [i].type == GADGETFS_SETUP) {
-                               len = i + 1;
-                               len *= sizeof (struct usb_gadgetfs_event);
-                               n = 0;
+                               dev->state = STATE_DEV_SETUP;
+                               n = i + 1;
                                break;
                        }
                }
                spin_unlock_irq (&dev->lock);
+               len = n * sizeof (struct usb_gadgetfs_event);
                if (copy_to_user (buf, &dev->event, len))
                        retval = -EFAULT;
                else
                        retval = len;
                if (len > 0) {
-                       len /= sizeof (struct usb_gadgetfs_event);
-
                        /* NOTE this doesn't guard against broken drivers;
                         * concurrent ep0 readers may lose events.
                         */
                        spin_lock_irq (&dev->lock);
-                       dev->ev_next -= len;
-                       if (dev->ev_next != 0)
-                               memmove (&dev->event, &dev->event [len],
+                       if (dev->ev_next > n) {
+                               memmove(&dev->event[0], &dev->event[n],
                                        sizeof (struct usb_gadgetfs_event)
-                                               * (tmp - len));
-                       if (n == 0)
-                               dev->state = STATE_SETUP;
+                                               * (dev->ev_next - n));
+                       }
+                       dev->ev_next -= n;
                        spin_unlock_irq (&dev->lock);
                }
                return retval;
@@ -1113,8 +1107,8 @@ scan:
                DBG (dev, "fail %s, state %d\n", __FUNCTION__, state);
                retval = -ESRCH;
                break;
-       case STATE_UNCONNECTED:
-       case STATE_CONNECTED:
+       case STATE_DEV_UNCONNECTED:
+       case STATE_DEV_CONNECTED:
                spin_unlock_irq (&dev->lock);
                DBG (dev, "%s wait\n", __FUNCTION__);
 
@@ -1141,7 +1135,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
        switch (type) {
        /* these events purge the queue */
        case GADGETFS_DISCONNECT:
-               if (dev->state == STATE_SETUP)
+               if (dev->state == STATE_DEV_SETUP)
                        dev->setup_abort = 1;
                // FALL THROUGH
        case GADGETFS_CONNECT:
@@ -1153,7 +1147,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
                for (i = 0; i != dev->ev_next; i++) {
                        if (dev->event [i].type != type)
                                continue;
-                       DBG (dev, "discard old event %d\n", type);
+                       DBG(dev, "discard old event[%d] %d\n", i, type);
                        dev->ev_next--;
                        if (i == dev->ev_next)
                                break;
@@ -1166,9 +1160,9 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
        default:
                BUG ();
        }
+       VDEBUG(dev, "event[%d] = %d\n", dev->ev_next, type);
        event = &dev->event [dev->ev_next++];
        BUG_ON (dev->ev_next > N_EVENT);
-       VDEBUG (dev, "ev %d, next %d\n", type, dev->ev_next);
        memset (event, 0, sizeof *event);
        event->type = type;
        return event;
@@ -1188,12 +1182,13 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                retval = -EIDRM;
 
        /* data and/or status stage for control request */
-       } else if (dev->state == STATE_SETUP) {
+       } else if (dev->state == STATE_DEV_SETUP) {
 
                /* IN DATA+STATUS caller makes len <= wLength */
                if (dev->setup_in) {
                        retval = setup_req (dev->gadget->ep0, dev->req, len);
                        if (retval == 0) {
+                               dev->state = STATE_DEV_CONNECTED;
                                spin_unlock_irq (&dev->lock);
                                if (copy_from_user (dev->req->buf, buf, len))
                                        retval = -EFAULT;
@@ -1219,7 +1214,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                        VDEBUG(dev, "ep0out stall\n");
                        (void) usb_ep_set_halt (dev->gadget->ep0);
                        retval = -EL2HLT;
-                       dev->state = STATE_CONNECTED;
+                       dev->state = STATE_DEV_CONNECTED;
                } else {
                        DBG(dev, "bogus ep0out stall!\n");
                }
@@ -1261,7 +1256,9 @@ dev_release (struct inode *inode, struct file *fd)
        put_dev (dev);
 
        /* other endpoints were all decoupled from this device */
+       spin_lock_irq(&dev->lock);
        dev->state = STATE_DEV_DISABLED;
+       spin_unlock_irq(&dev->lock);
        return 0;
 }
 
@@ -1282,7 +1279,7 @@ ep0_poll (struct file *fd, poll_table *wait)
                goto out;
        }
 
-       if (dev->state == STATE_SETUP) {
+       if (dev->state == STATE_DEV_SETUP) {
                if (dev->setup_in || dev->setup_can_stall)
                        mask = POLLOUT;
        } else {
@@ -1392,52 +1389,29 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 
        spin_lock (&dev->lock);
        dev->setup_abort = 0;
-       if (dev->state == STATE_UNCONNECTED) {
-               struct usb_ep   *ep;
-               struct ep_data  *data;
-
-               dev->state = STATE_CONNECTED;
-               dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
-
+       if (dev->state == STATE_DEV_UNCONNECTED) {
 #ifdef CONFIG_USB_GADGET_DUALSPEED
                if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == 0) {
+                       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;
+
                INFO (dev, "connected\n");
                event = next_event (dev, GADGETFS_CONNECT);
                event->u.speed = gadget->speed;
                ep0_readable (dev);
 
-               list_for_each_entry (ep, &gadget->ep_list, ep_list) {
-                       data = ep->driver_data;
-                       /* ... down_trylock (&data->lock) ... */
-                       if (data->state != STATE_EP_DEFER_ENABLE)
-                               continue;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-                       if (gadget->speed == USB_SPEED_HIGH)
-                               value = usb_ep_enable (ep, &data->hs_desc);
-                       else
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
-                               value = usb_ep_enable (ep, &data->desc);
-                       if (value) {
-                               ERROR (dev, "deferred %s enable --> %d\n",
-                                       data->name, value);
-                               continue;
-                       }
-                       data->state = STATE_EP_ENABLED;
-                       wake_up (&data->wait);
-                       DBG (dev, "woke up %s waiters\n", data->name);
-               }
-
        /* host may have given up waiting for response.  we can miss control
         * requests handled lower down (device/endpoint status and features);
         * then ep0_{read,write} will report the wrong status. controller
         * driver will have aborted pending i/o.
         */
-       } else if (dev->state == STATE_SETUP)
+       } else if (dev->state == STATE_DEV_SETUP)
                dev->setup_abort = 1;
 
        req->buf = dev->rbuf;
@@ -1583,7 +1557,7 @@ delegate:
        }
 
        /* proceed with data transfer and status phases? */
-       if (value >= 0 && dev->state != STATE_SETUP) {
+       if (value >= 0 && dev->state != STATE_DEV_SETUP) {
                req->length = value;
                req->zero = value < w_length;
                value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
@@ -1747,7 +1721,9 @@ gadgetfs_bind (struct usb_gadget *gadget)
                goto enomem;
 
        INFO (dev, "bound to %s driver\n", gadget->name);
-       dev->state = STATE_UNCONNECTED;
+       spin_lock_irq(&dev->lock);
+       dev->state = STATE_DEV_UNCONNECTED;
+       spin_unlock_irq(&dev->lock);
        get_dev (dev);
        return 0;
 
@@ -1762,11 +1738,9 @@ gadgetfs_disconnect (struct usb_gadget *gadget)
        struct dev_data         *dev = get_gadget_data (gadget);
 
        spin_lock (&dev->lock);
-       if (dev->state == STATE_UNCONNECTED) {
-               DBG (dev, "already unconnected\n");
+       if (dev->state == STATE_DEV_UNCONNECTED)
                goto exit;
-       }
-       dev->state = STATE_UNCONNECTED;
+       dev->state = STATE_DEV_UNCONNECTED;
 
        INFO (dev, "disconnected\n");
        next_event (dev, GADGETFS_DISCONNECT);
@@ -1783,9 +1757,9 @@ gadgetfs_suspend (struct usb_gadget *gadget)
        INFO (dev, "suspended from state %d\n", dev->state);
        spin_lock (&dev->lock);
        switch (dev->state) {
-       case STATE_SETUP:               // VERY odd... host died??
-       case STATE_CONNECTED:
-       case STATE_UNCONNECTED:
+       case STATE_DEV_SETUP:           // VERY odd... host died??
+       case STATE_DEV_CONNECTED:
+       case STATE_DEV_UNCONNECTED:
                next_event (dev, GADGETFS_SUSPEND);
                ep0_readable (dev);
                /* FALLTHROUGH */
@@ -1808,7 +1782,7 @@ static struct usb_gadget_driver gadgetfs_driver = {
        .disconnect     = gadgetfs_disconnect,
        .suspend        = gadgetfs_suspend,
 
-       .driver         = {
+       .driver = {
                .name           = (char *) shortname,
        },
 };
@@ -1829,7 +1803,7 @@ static struct usb_gadget_driver probe_driver = {
        .unbind         = gadgetfs_nop,
        .setup          = (void *)gadgetfs_nop,
        .disconnect     = gadgetfs_nop,
-       .driver         = {
+       .driver = {
                .name           = "nop",
        },
 };
@@ -1849,19 +1823,16 @@ static struct usb_gadget_driver probe_driver = {
  * . full/low speed config ... all wTotalLength bytes (with interface,
  *     class, altsetting, endpoint, and other descriptors)
  * . high speed config ... all descriptors, for high speed operation;
- *     this one's optional except for high-speed hardware
+ *     this one's optional except for high-speed hardware
  * . device descriptor
  *
- * Endpoints are not yet enabled. Drivers may want to immediately
- * initialize them, using the /dev/gadget/ep* files that are available
- * as soon as the kernel sees the configuration, or they can wait
- * until device configuration and interface altsetting changes create
+ * Endpoints are not yet enabled. Drivers must wait until device
+ * configuration and interface altsetting changes create
  * the need to configure (or unconfigure) them.
  *
  * After initialization, the device stays active for as long as that
- * $CHIP file is open.  Events may then be read from that descriptor,
- * such as configuration notifications.  More complex drivers will handle
- * some control requests in user space.
+ * $CHIP file is open.  Events must then be read from that descriptor,
+ * such as configuration notifications.
  */
 
 static int is_valid_config (struct usb_config_descriptor *config)
@@ -1884,9 +1855,6 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
        u32                     tag;
        char                    *kbuf;
 
-       if (dev->state != STATE_OPENED)
-               return -EEXIST;
-
        if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4))
                return -EINVAL;
 
@@ -1978,13 +1946,15 @@ dev_open (struct inode *inode, struct file *fd)
        struct dev_data         *dev = inode->i_private;
        int                     value = -EBUSY;
 
+       spin_lock_irq(&dev->lock);
        if (dev->state == STATE_DEV_DISABLED) {
                dev->ev_next = 0;
-               dev->state = STATE_OPENED;
+               dev->state = STATE_DEV_OPENED;
                fd->private_data = dev;
                get_dev (dev);
                value = 0;
        }
+       spin_unlock_irq(&dev->lock);
        return value;
 }
 
index e3bb785..b3fe197 100644 (file)
@@ -49,7 +49,7 @@
 #include <asm/unaligned.h>
 #include <asm/hardware.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 /*
index 569eb8c..7617ff7 100644 (file)
@@ -63,7 +63,7 @@
 #include <linux/interrupt.h>
 #include <linux/moduleparam.h>
 #include <linux/device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/byteorder.h>
index cdcfd42..1401043 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/mm.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
index b78de96..0d22536 100644 (file)
@@ -56,7 +56,7 @@
 #include <asm/arch/pxa-regs.h>
 #endif
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/arch/udc.h>
index f8a3ec6..6c742a9 100644 (file)
@@ -43,7 +43,7 @@
 #include <asm/unaligned.h>
 #include <asm/uaccess.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
 #include <linux/usb_gadget.h>
 
index b173576..3459ea6 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/device.h>
 #include <linux/init.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/unaligned.h>
index 40710ea..ebe04e0 100644 (file)
@@ -84,7 +84,7 @@
 #include <asm/system.h>
 #include <asm/unaligned.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include "gadget_chips.h"
index cc60759..6271187 100644 (file)
@@ -67,6 +67,11 @@ config USB_EHCI_TT_NEWSCHED
 
          If unsure, say N.
 
+config USB_EHCI_BIG_ENDIAN_MMIO
+       bool
+       depends on USB_EHCI_HCD
+       default n
+
 config USB_ISP116X_HCD
        tristate "ISP116X HCD support"
        depends on USB
@@ -101,21 +106,48 @@ config USB_OHCI_HCD_PPC_SOC
        bool "OHCI support for on-chip PPC USB controller"
        depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
        default y
-       select USB_OHCI_BIG_ENDIAN
+       select USB_OHCI_BIG_ENDIAN_DESC
+       select USB_OHCI_BIG_ENDIAN_MMIO
        ---help---
          Enables support for the USB controller on the MPC52xx or
          STB03xxx processor chip.  If unsure, say Y.
 
+config USB_OHCI_HCD_PPC_OF
+       bool "OHCI support for PPC USB controller on OF platform bus"
+       depends on USB_OHCI_HCD && PPC_OF
+       default y
+       ---help---
+         Enables support for the USB controller PowerPC present on the
+         OpenFirmware platform bus.
+
+config USB_OHCI_HCD_PPC_OF_BE
+       bool "Support big endian HC"
+       depends on USB_OHCI_HCD_PPC_OF
+       default y
+       select USB_OHCI_BIG_ENDIAN_DESC
+       select USB_OHCI_BIG_ENDIAN_MMIO
+
+config USB_OHCI_HCD_PPC_OF_LE
+       bool "Support little endian HC"
+       depends on USB_OHCI_HCD_PPC_OF
+       default n
+       select USB_OHCI_LITTLE_ENDIAN
+
 config USB_OHCI_HCD_PCI
        bool "OHCI support for PCI-bus USB controllers"
-       depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx)
+       depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF)
        default y
        select USB_OHCI_LITTLE_ENDIAN
        ---help---
          Enables support for PCI-bus plug-in USB controller cards.
          If unsure, say Y.
 
-config USB_OHCI_BIG_ENDIAN
+config USB_OHCI_BIG_ENDIAN_DESC
+       bool
+       depends on USB_OHCI_HCD
+       default n
+
+config USB_OHCI_BIG_ENDIAN_MMIO
        bool
        depends on USB_OHCI_HCD
        default n
index 56349d2..246afea 100644 (file)
@@ -43,7 +43,7 @@
  */
 static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
 {
-       u32     params = readl (&ehci->caps->hcs_params);
+       u32     params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
        ehci_dbg (ehci,
                "%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n",
@@ -87,7 +87,7 @@ static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}
  * */
 static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
 {
-       u32     params = readl (&ehci->caps->hcc_params);
+       u32     params = ehci_readl(ehci, &ehci->caps->hcc_params);
 
        if (HCC_ISOC_CACHE (params)) {
                ehci_dbg (ehci,
@@ -653,7 +653,7 @@ show_registers (struct class_device *class_dev, char *buf)
        }
 
        /* Capability Registers */
-       i = HC_VERSION(readl (&ehci->caps->hc_capbase));
+       i = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
        temp = scnprintf (next, size,
                "bus %s, device %s (driver " DRIVER_VERSION ")\n"
                "%s\n"
@@ -673,7 +673,7 @@ show_registers (struct class_device *class_dev, char *buf)
                unsigned        count = 256/4;
 
                pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
-               offset = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
+               offset = HCC_EXT_CAPS (ehci_readl(ehci, &ehci->caps->hcc_params));
                while (offset && count--) {
                        pci_read_config_dword (pdev, offset, &cap);
                        switch (cap & 0xff) {
@@ -704,50 +704,50 @@ show_registers (struct class_device *class_dev, char *buf)
 #endif
 
        // FIXME interpret both types of params
-       i = readl (&ehci->caps->hcs_params);
+       i = ehci_readl(ehci, &ehci->caps->hcs_params);
        temp = scnprintf (next, size, "structural params 0x%08x\n", i);
        size -= temp;
        next += temp;
 
-       i = readl (&ehci->caps->hcc_params);
+       i = ehci_readl(ehci, &ehci->caps->hcc_params);
        temp = scnprintf (next, size, "capability params 0x%08x\n", i);
        size -= temp;
        next += temp;
 
        /* Operational Registers */
        temp = dbg_status_buf (scratch, sizeof scratch, label,
-                       readl (&ehci->regs->status));
+                       ehci_readl(ehci, &ehci->regs->status));
        temp = scnprintf (next, size, fmt, temp, scratch);
        size -= temp;
        next += temp;
 
        temp = dbg_command_buf (scratch, sizeof scratch, label,
-                       readl (&ehci->regs->command));
+                       ehci_readl(ehci, &ehci->regs->command));
        temp = scnprintf (next, size, fmt, temp, scratch);
        size -= temp;
        next += temp;
 
        temp = dbg_intr_buf (scratch, sizeof scratch, label,
-                       readl (&ehci->regs->intr_enable));
+                       ehci_readl(ehci, &ehci->regs->intr_enable));
        temp = scnprintf (next, size, fmt, temp, scratch);
        size -= temp;
        next += temp;
 
        temp = scnprintf (next, size, "uframe %04x\n",
-                       readl (&ehci->regs->frame_index));
+                       ehci_readl(ehci, &ehci->regs->frame_index));
        size -= temp;
        next += temp;
 
        for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
                temp = dbg_port_buf (scratch, sizeof scratch, label, i,
-                               readl (&ehci->regs->port_status [i - 1]));
+                               ehci_readl(ehci, &ehci->regs->port_status [i - 1]));
                temp = scnprintf (next, size, fmt, temp, scratch);
                size -= temp;
                next += temp;
                if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
                        temp = scnprintf (next, size,
                                        "    debug control %08x\n",
-                                       readl (&ehci->debug->control));
+                                       ehci_readl(ehci, &ehci->debug->control));
                        size -= temp;
                        next += temp;
                }
index 1a915e9..a524805 100644 (file)
@@ -177,7 +177,7 @@ static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
        case FSL_USB2_PHY_NONE:
                break;
        }
-       writel(portsc, &ehci->regs->port_status[port_offset]);
+       ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
 }
 
 static void mpc83xx_usb_setup(struct usb_hcd *hcd)
@@ -214,7 +214,7 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
        }
 
        /* put controller in host mode. */
-       writel(0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
+       ehci_writel(ehci, 0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
        out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
        out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
        out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
@@ -238,12 +238,12 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
        /* EHCI registers start at offset 0x100 */
        ehci->caps = hcd->regs + 0x100;
        ehci->regs = hcd->regs + 0x100 +
-           HC_LENGTH(readl(&ehci->caps->hc_capbase));
+           HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
        dbg_hcs_params(ehci, "reset");
        dbg_hcc_params(ehci, "reset");
 
        /* cache this readonly data; minimize chip reads */
-       ehci->hcs_params = readl(&ehci->caps->hcs_params);
+       ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
        retval = ehci_halt(ehci);
        if (retval)
index 025d333..185721d 100644 (file)
@@ -157,12 +157,13 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");
  * before driver shutdown. But it also seems to be caused by bugs in cardbus
  * bridge shutdown:  shutting down the bridge before the devices using it.
  */
-static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
+static int handshake (struct ehci_hcd *ehci, void __iomem *ptr,
+                     u32 mask, u32 done, int usec)
 {
        u32     result;
 
        do {
-               result = readl (ptr);
+               result = ehci_readl(ehci, ptr);
                if (result == ~(u32)0)          /* card removed */
                        return -ENODEV;
                result &= mask;
@@ -177,18 +178,19 @@ static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
 /* force HC to halt state from unknown (EHCI spec section 2.3) */
 static int ehci_halt (struct ehci_hcd *ehci)
 {
-       u32     temp = readl (&ehci->regs->status);
+       u32     temp = ehci_readl(ehci, &ehci->regs->status);
 
        /* disable any irqs left enabled by previous code */
-       writel (0, &ehci->regs->intr_enable);
+       ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 
        if ((temp & STS_HALT) != 0)
                return 0;
 
-       temp = readl (&ehci->regs->command);
+       temp = ehci_readl(ehci, &ehci->regs->command);
        temp &= ~CMD_RUN;
-       writel (temp, &ehci->regs->command);
-       return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125);
+       ehci_writel(ehci, temp, &ehci->regs->command);
+       return handshake (ehci, &ehci->regs->status,
+                         STS_HALT, STS_HALT, 16 * 125);
 }
 
 /* put TDI/ARC silicon into EHCI mode */
@@ -198,23 +200,24 @@ static void tdi_reset (struct ehci_hcd *ehci)
        u32             tmp;
 
        reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68);
-       tmp = readl (reg_ptr);
+       tmp = ehci_readl(ehci, reg_ptr);
        tmp |= 0x3;
-       writel (tmp, reg_ptr);
+       ehci_writel(ehci, tmp, reg_ptr);
 }
 
 /* reset a non-running (STS_HALT == 1) controller */
 static int ehci_reset (struct ehci_hcd *ehci)
 {
        int     retval;
-       u32     command = readl (&ehci->regs->command);
+       u32     command = ehci_readl(ehci, &ehci->regs->command);
 
        command |= CMD_RESET;
        dbg_cmd (ehci, "reset", command);
-       writel (command, &ehci->regs->command);
+       ehci_writel(ehci, command, &ehci->regs->command);
        ehci_to_hcd(ehci)->state = HC_STATE_HALT;
        ehci->next_statechange = jiffies;
-       retval = handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000);
+       retval = handshake (ehci, &ehci->regs->command,
+                           CMD_RESET, 0, 250 * 1000);
 
        if (retval)
                return retval;
@@ -236,21 +239,21 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
 #endif
 
        /* wait for any schedule enables/disables to take effect */
-       temp = readl (&ehci->regs->command) << 10;
+       temp = ehci_readl(ehci, &ehci->regs->command) << 10;
        temp &= STS_ASS | STS_PSS;
-       if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+       if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
                                temp, 16 * 125) != 0) {
                ehci_to_hcd(ehci)->state = HC_STATE_HALT;
                return;
        }
 
        /* then disable anything that's still active */
-       temp = readl (&ehci->regs->command);
+       temp = ehci_readl(ehci, &ehci->regs->command);
        temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
-       writel (temp, &ehci->regs->command);
+       ehci_writel(ehci, temp, &ehci->regs->command);
 
        /* hardware can take 16 microframes to turn off ... */
-       if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+       if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
                                0, 16 * 125) != 0) {
                ehci_to_hcd(ehci)->state = HC_STATE_HALT;
                return;
@@ -277,11 +280,11 @@ static void ehci_watchdog (unsigned long param)
 
        /* lost IAA irqs wedge things badly; seen with a vt8235 */
        if (ehci->reclaim) {
-               u32             status = readl (&ehci->regs->status);
+               u32             status = ehci_readl(ehci, &ehci->regs->status);
                if (status & STS_IAA) {
                        ehci_vdbg (ehci, "lost IAA\n");
                        COUNT (ehci->stats.lost_iaa);
-                       writel (STS_IAA, &ehci->regs->status);
+                       ehci_writel(ehci, STS_IAA, &ehci->regs->status);
                        ehci->reclaim_ready = 1;
                }
        }
@@ -309,7 +312,7 @@ ehci_shutdown (struct usb_hcd *hcd)
        (void) ehci_halt (ehci);
 
        /* make BIOS/etc use companion controller during reboot */
-       writel (0, &ehci->regs->configured_flag);
+       ehci_writel(ehci, 0, &ehci->regs->configured_flag);
 }
 
 static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
@@ -379,12 +382,13 @@ static void ehci_stop (struct usb_hcd *hcd)
                ehci_quiesce (ehci);
 
        ehci_reset (ehci);
-       writel (0, &ehci->regs->intr_enable);
+       ehci_writel(ehci, 0, &ehci->regs->intr_enable);
        spin_unlock_irq(&ehci->lock);
 
        /* let companion controllers work when we aren't */
-       writel (0, &ehci->regs->configured_flag);
+       ehci_writel(ehci, 0, &ehci->regs->configured_flag);
 
+       remove_companion_file(ehci);
        remove_debug_files (ehci);
 
        /* root hub is shut down separately (first, when possible) */
@@ -402,7 +406,8 @@ static void ehci_stop (struct usb_hcd *hcd)
                ehci->stats.complete, ehci->stats.unlink);
 #endif
 
-       dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
+       dbg_status (ehci, "ehci_stop completed",
+                   ehci_readl(ehci, &ehci->regs->status));
 }
 
 /* one-time init, only for memory state */
@@ -428,7 +433,7 @@ static int ehci_init(struct usb_hcd *hcd)
                return retval;
 
        /* controllers may cache some of the periodic schedule ... */
-       hcc_params = readl(&ehci->caps->hcc_params);
+       hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
        if (HCC_ISOC_CACHE(hcc_params))         // full frame cache
                ehci->i_thresh = 8;
        else                                    // N microframes cached
@@ -496,13 +501,16 @@ static int ehci_run (struct usb_hcd *hcd)
        u32                     temp;
        u32                     hcc_params;
 
+       hcd->uses_new_polling = 1;
+       hcd->poll_rh = 0;
+
        /* EHCI spec section 4.1 */
        if ((retval = ehci_reset(ehci)) != 0) {
                ehci_mem_cleanup(ehci);
                return retval;
        }
-       writel(ehci->periodic_dma, &ehci->regs->frame_list);
-       writel((u32)ehci->async->qh_dma, &ehci->regs->async_next);
+       ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+       ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
 
        /*
         * hcc_params controls whether ehci->regs->segment must (!!!)
@@ -516,9 +524,9 @@ static int ehci_run (struct usb_hcd *hcd)
         * Scsi_Host.highmem_io, and so forth.  It's readonly to all
         * host side drivers though.
         */
-       hcc_params = readl(&ehci->caps->hcc_params);
+       hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
        if (HCC_64BIT_ADDR(hcc_params)) {
-               writel(0, &ehci->regs->segment);
+               ehci_writel(ehci, 0, &ehci->regs->segment);
 #if 0
 // this is deeply broken on almost all architectures
                if (!dma_set_mask(hcd->self.controller, DMA_64BIT_MASK))
@@ -531,7 +539,7 @@ static int ehci_run (struct usb_hcd *hcd)
        // root hub will detect new devices (why?); NEC doesn't
        ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
        ehci->command |= CMD_RUN;
-       writel (ehci->command, &ehci->regs->command);
+       ehci_writel(ehci, ehci->command, &ehci->regs->command);
        dbg_cmd (ehci, "init", ehci->command);
 
        /*
@@ -541,23 +549,25 @@ static int ehci_run (struct usb_hcd *hcd)
         * and there's no companion controller unless maybe for USB OTG.)
         */
        hcd->state = HC_STATE_RUNNING;
-       writel (FLAG_CF, &ehci->regs->configured_flag);
-       readl (&ehci->regs->command);   /* unblock posted writes */
+       ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+       ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
 
-       temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
+       temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
        ehci_info (ehci,
                "USB %x.%x started, EHCI %x.%02x, driver %s%s\n",
                ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
                temp >> 8, temp & 0xff, DRIVER_VERSION,
                ignore_oc ? ", overcurrent ignored" : "");
 
-       writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
+       ehci_writel(ehci, INTR_MASK,
+                   &ehci->regs->intr_enable); /* Turn On Interrupts */
 
        /* GRR this is run-once init(), being done every time the HC starts.
         * So long as they're part of class devices, we can't do it init()
         * since the class device isn't created that early.
         */
        create_debug_files(ehci);
+       create_companion_file(ehci);
 
        return 0;
 }
@@ -567,12 +577,12 @@ static int ehci_run (struct usb_hcd *hcd)
 static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
-       u32                     status;
+       u32                     status, pcd_status = 0;
        int                     bh;
 
        spin_lock (&ehci->lock);
 
-       status = readl (&ehci->regs->status);
+       status = ehci_readl(ehci, &ehci->regs->status);
 
        /* e.g. cardbus physical eject */
        if (status == ~(u32) 0) {
@@ -587,8 +597,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
        }
 
        /* clear (just) interrupts */
-       writel (status, &ehci->regs->status);
-       readl (&ehci->regs->command);   /* unblock posted write */
+       ehci_writel(ehci, status, &ehci->regs->status);
+       ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */
        bh = 0;
 
 #ifdef EHCI_VERBOSE_DEBUG
@@ -617,13 +627,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
        /* remote wakeup [4.3.1] */
        if (status & STS_PCD) {
                unsigned        i = HCS_N_PORTS (ehci->hcs_params);
+               pcd_status = status;
 
                /* resume root hub? */
-               if (!(readl(&ehci->regs->command) & CMD_RUN))
+               if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN))
                        usb_hcd_resume_root_hub(hcd);
 
                while (i--) {
-                       int pstatus = readl (&ehci->regs->port_status [i]);
+                       int pstatus = ehci_readl(ehci,
+                                                &ehci->regs->port_status [i]);
 
                        if (pstatus & PORT_OWNER)
                                continue;
@@ -643,14 +655,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
        /* PCI errors [4.15.2.4] */
        if (unlikely ((status & STS_FATAL) != 0)) {
                /* bogus "fatal" IRQs appear on some chips... why?  */
-               status = readl (&ehci->regs->status);
-               dbg_cmd (ehci, "fatal", readl (&ehci->regs->command));
+               status = ehci_readl(ehci, &ehci->regs->status);
+               dbg_cmd (ehci, "fatal", ehci_readl(ehci,
+                                                  &ehci->regs->command));
                dbg_status (ehci, "fatal", status);
                if (status & STS_HALT) {
                        ehci_err (ehci, "fatal error\n");
 dead:
                        ehci_reset (ehci);
-                       writel (0, &ehci->regs->configured_flag);
+                       ehci_writel(ehci, 0, &ehci->regs->configured_flag);
                        /* generic layer kills/unlinks all urbs, then
                         * uses ehci_stop to clean up the rest
                         */
@@ -661,6 +674,8 @@ dead:
        if (bh)
                ehci_work (ehci);
        spin_unlock (&ehci->lock);
+       if (pcd_status & STS_PCD)
+               usb_hcd_poll_rh_status(hcd);
        return IRQ_HANDLED;
 }
 
@@ -873,7 +888,8 @@ done:
 static int ehci_get_frame (struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
-       return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size;
+       return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) %
+               ehci->periodic_size;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -899,7 +915,13 @@ MODULE_LICENSE ("GPL");
 #define        PLATFORM_DRIVER         ehci_hcd_au1xxx_driver
 #endif
 
-#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER)
+#ifdef CONFIG_PPC_PS3
+#include "ehci-ps3.c"
+#define        PS3_SYSTEM_BUS_DRIVER   ps3_ehci_sb_driver
+#endif
+
+#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
+    !defined(PS3_SYSTEM_BUS_DRIVER)
 #error "missing bus glue for ehci-hcd"
 #endif
 
@@ -924,6 +946,20 @@ static int __init ehci_hcd_init(void)
 #ifdef PLATFORM_DRIVER
                platform_driver_unregister(&PLATFORM_DRIVER);
 #endif
+               return retval;
+       }
+#endif
+
+#ifdef PS3_SYSTEM_BUS_DRIVER
+       retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+       if (retval < 0) {
+#ifdef PLATFORM_DRIVER
+               platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+#ifdef PCI_DRIVER
+               pci_unregister_driver(&PCI_DRIVER);
+#endif
+               return retval;
        }
 #endif
 
@@ -939,6 +975,9 @@ static void __exit ehci_hcd_cleanup(void)
 #ifdef PCI_DRIVER
        pci_unregister_driver(&PCI_DRIVER);
 #endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+       ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+#endif
 }
 module_exit(ehci_hcd_cleanup);
 
index bfe5f30..0d83c6d 100644 (file)
@@ -47,7 +47,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
                ehci_quiesce (ehci);
                hcd->state = HC_STATE_QUIESCING;
        }
-       ehci->command = readl (&ehci->regs->command);
+       ehci->command = ehci_readl(ehci, &ehci->regs->command);
        if (ehci->reclaim)
                ehci->reclaim_ready = 1;
        ehci_work(ehci);
@@ -60,7 +60,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
        ehci->bus_suspended = 0;
        while (port--) {
                u32 __iomem     *reg = &ehci->regs->port_status [port];
-               u32             t1 = readl (reg) & ~PORT_RWC_BITS;
+               u32             t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
                u32             t2 = t1;
 
                /* keep track of which ports we suspend */
@@ -79,7 +79,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
                if (t1 != t2) {
                        ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
                                port + 1, t1, t2);
-                       writel (t2, reg);
+                       ehci_writel(ehci, t2, reg);
                }
        }
 
@@ -92,8 +92,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
        mask = INTR_MASK;
        if (!device_may_wakeup(&hcd->self.root_hub->dev))
                mask &= ~STS_PCD;
-       writel(mask, &ehci->regs->intr_enable);
-       readl(&ehci->regs->intr_enable);
+       ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+       ehci_readl(ehci, &ehci->regs->intr_enable);
 
        ehci->next_statechange = jiffies + msecs_to_jiffies(10);
        spin_unlock_irq (&ehci->lock);
@@ -118,26 +118,26 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
         * the last user of the controller, not reset/pm hardware keeping
         * state we gave to it.
         */
-       temp = readl(&ehci->regs->intr_enable);
+       temp = ehci_readl(ehci, &ehci->regs->intr_enable);
        ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss");
 
        /* at least some APM implementations will try to deliver
         * IRQs right away, so delay them until we're ready.
         */
-       writel(0, &ehci->regs->intr_enable);
+       ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 
        /* re-init operational registers */
-       writel(0, &ehci->regs->segment);
-       writel(ehci->periodic_dma, &ehci->regs->frame_list);
-       writel((u32) ehci->async->qh_dma, &ehci->regs->async_next);
+       ehci_writel(ehci, 0, &ehci->regs->segment);
+       ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+       ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next);
 
        /* restore CMD_RUN, framelist size, and irq threshold */
-       writel (ehci->command, &ehci->regs->command);
+       ehci_writel(ehci, ehci->command, &ehci->regs->command);
 
        /* manually resume the ports we suspended during bus_suspend() */
        i = HCS_N_PORTS (ehci->hcs_params);
        while (i--) {
-               temp = readl (&ehci->regs->port_status [i]);
+               temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
                temp &= ~(PORT_RWC_BITS
                        | PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
                if (test_bit(i, &ehci->bus_suspended) &&
@@ -145,20 +145,20 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
                        ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
                        temp |= PORT_RESUME;
                }
-               writel (temp, &ehci->regs->port_status [i]);
+               ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
        }
        i = HCS_N_PORTS (ehci->hcs_params);
        mdelay (20);
        while (i--) {
-               temp = readl (&ehci->regs->port_status [i]);
+               temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
                if (test_bit(i, &ehci->bus_suspended) &&
                                (temp & PORT_SUSPEND)) {
                        temp &= ~(PORT_RWC_BITS | PORT_RESUME);
-                       writel (temp, &ehci->regs->port_status [i]);
+                       ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
                        ehci_vdbg (ehci, "resumed port %d\n", i + 1);
                }
        }
-       (void) readl (&ehci->regs->command);
+       (void) ehci_readl(ehci, &ehci->regs->command);
 
        /* maybe re-activate the schedule(s) */
        temp = 0;
@@ -168,14 +168,14 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
                temp |= CMD_PSE;
        if (temp) {
                ehci->command |= temp;
-               writel (ehci->command, &ehci->regs->command);
+               ehci_writel(ehci, ehci->command, &ehci->regs->command);
        }
 
        ehci->next_statechange = jiffies + msecs_to_jiffies(5);
        hcd->state = HC_STATE_RUNNING;
 
        /* Now we can safely re-enable irqs */
-       writel(INTR_MASK, &ehci->regs->intr_enable);
+       ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
 
        spin_unlock_irq (&ehci->lock);
        return 0;
@@ -188,11 +188,109 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
 
 #endif /* CONFIG_PM */
 
+/*-------------------------------------------------------------------------*/
+
+/* Display the ports dedicated to the companion controller */
+static ssize_t show_companion(struct class_device *class_dev, char *buf)
+{
+       struct ehci_hcd         *ehci;
+       int                     nports, index, n;
+       int                     count = PAGE_SIZE;
+       char                    *ptr = buf;
+
+       ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+       nports = HCS_N_PORTS(ehci->hcs_params);
+
+       for (index = 0; index < nports; ++index) {
+               if (test_bit(index, &ehci->companion_ports)) {
+                       n = scnprintf(ptr, count, "%d\n", index + 1);
+                       ptr += n;
+                       count -= n;
+               }
+       }
+       return ptr - buf;
+}
+
+/*
+ * Dedicate or undedicate a port to the companion controller.
+ * Syntax is "[-]portnum", where a leading '-' sign means
+ * return control of the port to the EHCI controller.
+ */
+static ssize_t store_companion(struct class_device *class_dev,
+               const char *buf, size_t count)
+{
+       struct ehci_hcd         *ehci;
+       int                     portnum, new_owner, try;
+       u32 __iomem             *status_reg;
+       u32                     port_status;
+
+       ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+       new_owner = PORT_OWNER;         /* Owned by companion */
+       if (sscanf(buf, "%d", &portnum) != 1)
+               return -EINVAL;
+       if (portnum < 0) {
+               portnum = - portnum;
+               new_owner = 0;          /* Owned by EHCI */
+       }
+       if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
+               return -ENOENT;
+       status_reg = &ehci->regs->port_status[--portnum];
+       if (new_owner)
+               set_bit(portnum, &ehci->companion_ports);
+       else
+               clear_bit(portnum, &ehci->companion_ports);
+
+       /*
+        * The controller won't set the OWNER bit if the port is
+        * enabled, so this loop will sometimes require at least two
+        * iterations: one to disable the port and one to set OWNER.
+        */
+
+       for (try = 4; try > 0; --try) {
+               spin_lock_irq(&ehci->lock);
+               port_status = ehci_readl(ehci, status_reg);
+               if ((port_status & PORT_OWNER) == new_owner
+                               || (port_status & (PORT_OWNER | PORT_CONNECT))
+                                       == 0)
+                       try = 0;
+               else {
+                       port_status ^= PORT_OWNER;
+                       port_status &= ~(PORT_PE | PORT_RWC_BITS);
+                       ehci_writel(ehci, port_status, status_reg);
+               }
+               spin_unlock_irq(&ehci->lock);
+               if (try > 1)
+                       msleep(5);
+       }
+       return count;
+}
+static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion);
+
+static inline void create_companion_file(struct ehci_hcd *ehci)
+{
+       int     i;
+
+       /* with integrated TT there is no companion! */
+       if (!ehci_is_TDI(ehci))
+               i = class_device_create_file(ehci_to_hcd(ehci)->self.class_dev,
+                               &class_device_attr_companion);
+}
+
+static inline void remove_companion_file(struct ehci_hcd *ehci)
+{
+       /* with integrated TT there is no companion! */
+       if (!ehci_is_TDI(ehci))
+               class_device_remove_file(ehci_to_hcd(ehci)->self.class_dev,
+                               &class_device_attr_companion);
+}
+
+
 /*-------------------------------------------------------------------------*/
 
 static int check_reset_complete (
        struct ehci_hcd *ehci,
        int             index,
+       u32 __iomem     *status_reg,
        int             port_status
 ) {
        if (!(port_status & PORT_CONNECT)) {
@@ -217,7 +315,7 @@ static int check_reset_complete (
                // what happens if HCS_N_CC(params) == 0 ?
                port_status |= PORT_OWNER;
                port_status &= ~PORT_RWC_BITS;
-               writel (port_status, &ehci->regs->port_status [index]);
+               ehci_writel(ehci, port_status, status_reg);
 
        } else
                ehci_dbg (ehci, "port %d high speed\n", index + 1);
@@ -268,22 +366,21 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
        /* port N changes (bit N)? */
        spin_lock_irqsave (&ehci->lock, flags);
        for (i = 0; i < ports; i++) {
-               temp = readl (&ehci->regs->port_status [i]);
-               if (temp & PORT_OWNER) {
-                       /* don't report this in GetPortStatus */
-                       if (temp & PORT_CSC) {
-                               temp &= ~PORT_RWC_BITS;
-                               temp |= PORT_CSC;
-                               writel (temp, &ehci->regs->port_status [i]);
-                       }
-                       continue;
-               }
+               temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
+
+               /*
+                * Return status information even for ports with OWNER set.
+                * Otherwise khubd wouldn't see the disconnect event when a
+                * high-speed device is switched over to the companion
+                * controller by the user.
+                */
+
                if (!(temp & PORT_CONNECT))
                        ehci->reset_done [i] = 0;
                if ((temp & mask) != 0
                                || ((temp & PORT_RESUME) != 0
-                                       && time_after (jiffies,
-                                               ehci->reset_done [i]))) {
+                                       && time_after_eq(jiffies,
+                                               ehci->reset_done[i]))) {
                        if (i < 7)
                            buf [0] |= 1 << (i + 1);
                        else
@@ -345,6 +442,7 @@ static int ehci_hub_control (
 ) {
        struct ehci_hcd *ehci = hcd_to_ehci (hcd);
        int             ports = HCS_N_PORTS (ehci->hcs_params);
+       u32 __iomem     *status_reg = &ehci->regs->port_status[wIndex - 1];
        u32             temp, status;
        unsigned long   flags;
        int             retval = 0;
@@ -373,18 +471,22 @@ static int ehci_hub_control (
                if (!wIndex || wIndex > ports)
                        goto error;
                wIndex--;
-               temp = readl (&ehci->regs->port_status [wIndex]);
-               if (temp & PORT_OWNER)
-                       break;
+               temp = ehci_readl(ehci, status_reg);
+
+               /*
+                * Even if OWNER is set, so the port is owned by the
+                * companion controller, khubd needs to be able to clear
+                * the port-change status bits (especially
+                * USB_PORT_FEAT_C_CONNECTION).
+                */
 
                switch (wValue) {
                case USB_PORT_FEAT_ENABLE:
-                       writel (temp & ~PORT_PE,
-                               &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, temp & ~PORT_PE, status_reg);
                        break;
                case USB_PORT_FEAT_C_ENABLE:
-                       writel((temp & ~PORT_RWC_BITS) | PORT_PEC,
-                               &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC,
+                                       status_reg);
                        break;
                case USB_PORT_FEAT_SUSPEND:
                        if (temp & PORT_RESET)
@@ -396,8 +498,8 @@ static int ehci_hub_control (
                                        goto error;
                                /* resume signaling for 20 msec */
                                temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
-                               writel (temp | PORT_RESUME,
-                                       &ehci->regs->port_status [wIndex]);
+                               ehci_writel(ehci, temp | PORT_RESUME,
+                                               status_reg);
                                ehci->reset_done [wIndex] = jiffies
                                                + msecs_to_jiffies (20);
                        }
@@ -407,16 +509,17 @@ static int ehci_hub_control (
                        break;
                case USB_PORT_FEAT_POWER:
                        if (HCS_PPC (ehci->hcs_params))
-                               writel (temp & ~(PORT_RWC_BITS | PORT_POWER),
-                                       &ehci->regs->port_status [wIndex]);
+                               ehci_writel(ehci,
+                                         temp & ~(PORT_RWC_BITS | PORT_POWER),
+                                         status_reg);
                        break;
                case USB_PORT_FEAT_C_CONNECTION:
-                       writel((temp & ~PORT_RWC_BITS) | PORT_CSC,
-                               &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC,
+                                       status_reg);
                        break;
                case USB_PORT_FEAT_C_OVER_CURRENT:
-                       writel((temp & ~PORT_RWC_BITS) | PORT_OCC,
-                               &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC,
+                                       status_reg);
                        break;
                case USB_PORT_FEAT_C_RESET:
                        /* GetPortStatus clears reset */
@@ -424,7 +527,7 @@ static int ehci_hub_control (
                default:
                        goto error;
                }
-               readl (&ehci->regs->command);   /* unblock posted write */
+               ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */
                break;
        case GetHubDescriptor:
                ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
@@ -440,7 +543,7 @@ static int ehci_hub_control (
                        goto error;
                wIndex--;
                status = 0;
-               temp = readl (&ehci->regs->port_status [wIndex]);
+               temp = ehci_readl(ehci, status_reg);
 
                // wPortChange bits
                if (temp & PORT_CSC)
@@ -451,42 +554,55 @@ static int ehci_hub_control (
                        status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
 
                /* whoever resumes must GetPortStatus to complete it!! */
-               if ((temp & PORT_RESUME)
-                               && time_after (jiffies,
-                                       ehci->reset_done [wIndex])) {
-                       status |= 1 << USB_PORT_FEAT_C_SUSPEND;
-                       ehci->reset_done [wIndex] = 0;
+               if (temp & PORT_RESUME) {
 
-                       /* stop resume signaling */
-                       temp = readl (&ehci->regs->port_status [wIndex]);
-                       writel (temp & ~(PORT_RWC_BITS | PORT_RESUME),
-                               &ehci->regs->port_status [wIndex]);
-                       retval = handshake (
-                                       &ehci->regs->port_status [wIndex],
-                                       PORT_RESUME, 0, 2000 /* 2msec */);
-                       if (retval != 0) {
-                               ehci_err (ehci, "port %d resume error %d\n",
-                                       wIndex + 1, retval);
-                               goto error;
+                       /* Remote Wakeup received? */
+                       if (!ehci->reset_done[wIndex]) {
+                               /* resume signaling for 20 msec */
+                               ehci->reset_done[wIndex] = jiffies
+                                               + msecs_to_jiffies(20);
+                               /* check the port again */
+                               mod_timer(&ehci_to_hcd(ehci)->rh_timer,
+                                               ehci->reset_done[wIndex]);
+                       }
+
+                       /* resume completed? */
+                       else if (time_after_eq(jiffies,
+                                       ehci->reset_done[wIndex])) {
+                               status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+                               ehci->reset_done[wIndex] = 0;
+
+                               /* stop resume signaling */
+                               temp = ehci_readl(ehci, status_reg);
+                               ehci_writel(ehci,
+                                       temp & ~(PORT_RWC_BITS | PORT_RESUME),
+                                       status_reg);
+                               retval = handshake(ehci, status_reg,
+                                          PORT_RESUME, 0, 2000 /* 2msec */);
+                               if (retval != 0) {
+                                       ehci_err(ehci,
+                                               "port %d resume error %d\n",
+                                               wIndex + 1, retval);
+                                       goto error;
+                               }
+                               temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
                        }
-                       temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
                }
 
                /* whoever resets must GetPortStatus to complete it!! */
                if ((temp & PORT_RESET)
-                               && time_after (jiffies,
-                                       ehci->reset_done [wIndex])) {
+                               && time_after_eq(jiffies,
+                                       ehci->reset_done[wIndex])) {
                        status |= 1 << USB_PORT_FEAT_C_RESET;
                        ehci->reset_done [wIndex] = 0;
 
                        /* force reset to complete */
-                       writel (temp & ~(PORT_RWC_BITS | PORT_RESET),
-                                       &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET),
+                                       status_reg);
                        /* REVISIT:  some hardware needs 550+ usec to clear
                         * this bit; seems too long to spin routinely...
                         */
-                       retval = handshake (
-                                       &ehci->regs->port_status [wIndex],
+                       retval = handshake(ehci, status_reg,
                                        PORT_RESET, 0, 750);
                        if (retval != 0) {
                                ehci_err (ehci, "port %d reset error %d\n",
@@ -495,28 +611,41 @@ static int ehci_hub_control (
                        }
 
                        /* see what we found out */
-                       temp = check_reset_complete (ehci, wIndex,
-                               readl (&ehci->regs->port_status [wIndex]));
+                       temp = check_reset_complete (ehci, wIndex, status_reg,
+                                       ehci_readl(ehci, status_reg));
                }
 
-               // don't show wPortStatus if it's owned by a companion hc
-               if (!(temp & PORT_OWNER)) {
-                       if (temp & PORT_CONNECT) {
-                               status |= 1 << USB_PORT_FEAT_CONNECTION;
-                               // status may be from integrated TT
-                               status |= ehci_port_speed(ehci, temp);
-                       }
-                       if (temp & PORT_PE)
-                               status |= 1 << USB_PORT_FEAT_ENABLE;
-                       if (temp & (PORT_SUSPEND|PORT_RESUME))
-                               status |= 1 << USB_PORT_FEAT_SUSPEND;
-                       if (temp & PORT_OC)
-                               status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
-                       if (temp & PORT_RESET)
-                               status |= 1 << USB_PORT_FEAT_RESET;
-                       if (temp & PORT_POWER)
-                               status |= 1 << USB_PORT_FEAT_POWER;
+               /* transfer dedicated ports to the companion hc */
+               if ((temp & PORT_CONNECT) &&
+                               test_bit(wIndex, &ehci->companion_ports)) {
+                       temp &= ~PORT_RWC_BITS;
+                       temp |= PORT_OWNER;
+                       ehci_writel(ehci, temp, status_reg);
+                       ehci_dbg(ehci, "port %d --> companion\n", wIndex + 1);
+                       temp = ehci_readl(ehci, status_reg);
+               }
+
+               /*
+                * Even if OWNER is set, there's no harm letting khubd
+                * see the wPortStatus values (they should all be 0 except
+                * for PORT_POWER anyway).
+                */
+
+               if (temp & PORT_CONNECT) {
+                       status |= 1 << USB_PORT_FEAT_CONNECTION;
+                       // status may be from integrated TT
+                       status |= ehci_port_speed(ehci, temp);
                }
+               if (temp & PORT_PE)
+                       status |= 1 << USB_PORT_FEAT_ENABLE;
+               if (temp & (PORT_SUSPEND|PORT_RESUME))
+                       status |= 1 << USB_PORT_FEAT_SUSPEND;
+               if (temp & PORT_OC)
+                       status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
+               if (temp & PORT_RESET)
+                       status |= 1 << USB_PORT_FEAT_RESET;
+               if (temp & PORT_POWER)
+                       status |= 1 << USB_PORT_FEAT_POWER;
 
 #ifndef        EHCI_VERBOSE_DEBUG
        if (status & ~0xffff)   /* only if wPortChange is interesting */
@@ -541,7 +670,7 @@ static int ehci_hub_control (
                if (!wIndex || wIndex > ports)
                        goto error;
                wIndex--;
-               temp = readl (&ehci->regs->port_status [wIndex]);
+               temp = ehci_readl(ehci, status_reg);
                if (temp & PORT_OWNER)
                        break;
 
@@ -555,13 +684,12 @@ static int ehci_hub_control (
                                goto error;
                        if (device_may_wakeup(&hcd->self.root_hub->dev))
                                temp |= PORT_WAKE_BITS;
-                       writel (temp | PORT_SUSPEND,
-                               &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
                        break;
                case USB_PORT_FEAT_POWER:
                        if (HCS_PPC (ehci->hcs_params))
-                               writel (temp | PORT_POWER,
-                                       &ehci->regs->port_status [wIndex]);
+                               ehci_writel(ehci, temp | PORT_POWER,
+                                               status_reg);
                        break;
                case USB_PORT_FEAT_RESET:
                        if (temp & PORT_RESUME)
@@ -589,7 +717,7 @@ static int ehci_hub_control (
                                ehci->reset_done [wIndex] = jiffies
                                                + msecs_to_jiffies (50);
                        }
-                       writel (temp, &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, temp, status_reg);
                        break;
 
                /* For downstream facing ports (these):  one hub port is put
@@ -604,13 +732,13 @@ static int ehci_hub_control (
                        ehci_quiesce(ehci);
                        ehci_halt(ehci);
                        temp |= selector << 16;
-                       writel (temp, &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, temp, status_reg);
                        break;
 
                default:
                        goto error;
                }
-               readl (&ehci->regs->command);   /* unblock posted writes */
+               ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
                break;
 
        default:
index 4bc7970..12edc72 100644 (file)
@@ -38,7 +38,7 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
                if ((temp & (3 << 13)) == (1 << 13)) {
                        temp &= 0x1fff;
                        ehci->debug = ehci_to_hcd(ehci)->regs + temp;
-                       temp = readl(&ehci->debug->control);
+                       temp = ehci_readl(ehci, &ehci->debug->control);
                        ehci_info(ehci, "debug port %d%s\n",
                                HCS_DEBUG_PORT(ehci->hcs_params),
                                (temp & DBGP_ENABLED)
@@ -71,8 +71,24 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
        u32                     temp;
        int                     retval;
 
+       switch (pdev->vendor) {
+       case PCI_VENDOR_ID_TOSHIBA_2:
+               /* celleb's companion chip */
+               if (pdev->device == 0x01b5) {
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+                       ehci->big_endian_mmio = 1;
+#else
+                       ehci_warn(ehci,
+                                 "unsupported big endian Toshiba quirk\n");
+#endif
+               }
+               break;
+       }
+
        ehci->caps = hcd->regs;
-       ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+       ehci->regs = hcd->regs +
+               HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+
        dbg_hcs_params(ehci, "reset");
        dbg_hcc_params(ehci, "reset");
 
@@ -101,7 +117,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
        }
 
        /* cache this readonly data; minimize chip reads */
-       ehci->hcs_params = readl(&ehci->caps->hcs_params);
+       ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
        retval = ehci_halt(ehci);
        if (retval)
@@ -235,8 +251,8 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
                rc = -EINVAL;
                goto bail;
        }
-       writel (0, &ehci->regs->intr_enable);
-       (void)readl(&ehci->regs->intr_enable);
+       ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+       (void)ehci_readl(ehci, &ehci->regs->intr_enable);
 
        /* make sure snapshot being resumed re-enumerates everything */
        if (message.event == PM_EVENT_PRETHAW) {
@@ -270,13 +286,13 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
        /* If CF is still set, we maintained PCI Vaux power.
         * Just undo the effect of ehci_pci_suspend().
         */
-       if (readl(&ehci->regs->configured_flag) == FLAG_CF) {
+       if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
                int     mask = INTR_MASK;
 
                if (!device_may_wakeup(&hcd->self.root_hub->dev))
                        mask &= ~STS_PCD;
-               writel(mask, &ehci->regs->intr_enable);
-               readl(&ehci->regs->intr_enable);
+               ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+               ehci_readl(ehci, &ehci->regs->intr_enable);
                return 0;
        }
 
@@ -300,9 +316,9 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
        /* here we "know" root ports should always stay powered */
        ehci_port_power(ehci, 1);
 
-       writel(ehci->command, &ehci->regs->command);
-       writel(FLAG_CF, &ehci->regs->configured_flag);
-       readl(&ehci->regs->command);    /* unblock posted writes */
+       ehci_writel(ehci, ehci->command, &ehci->regs->command);
+       ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+       ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
 
        hcd->state = HC_STATE_SUSPENDED;
        return 0;
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
new file mode 100644 (file)
index 0000000..371f194
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ *  PS3 EHCI Host Controller driver
+ *
+ *  Copyright (C) 2006 Sony Computer Entertainment Inc.
+ *  Copyright 2006 Sony Corp.
+ *
+ *  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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <asm/ps3.h>
+
+static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
+{
+       int result;
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+       ehci->big_endian_mmio = 1;
+
+       ehci->caps = hcd->regs;
+       ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
+               &ehci->caps->hc_capbase));
+
+       dbg_hcs_params(ehci, "reset");
+       dbg_hcc_params(ehci, "reset");
+
+       ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+       result = ehci_halt(ehci);
+
+       if (result)
+               return result;
+
+       result = ehci_init(hcd);
+
+       if (result)
+               return result;
+
+       ehci_port_power(ehci, 0);
+
+       return result;
+}
+
+static const struct hc_driver ps3_ehci_hc_driver = {
+       .description            = hcd_name,
+       .product_desc           = "PS3 EHCI Host Controller",
+       .hcd_priv_size          = sizeof(struct ehci_hcd),
+       .irq                    = ehci_irq,
+       .flags                  = HCD_MEMORY | HCD_USB2,
+       .reset                  = ps3_ehci_hc_reset,
+       .start                  = ehci_run,
+       .stop                   = ehci_stop,
+       .shutdown               = ehci_shutdown,
+       .urb_enqueue            = ehci_urb_enqueue,
+       .urb_dequeue            = ehci_urb_dequeue,
+       .endpoint_disable       = ehci_endpoint_disable,
+       .get_frame_number       = ehci_get_frame,
+       .hub_status_data        = ehci_hub_status_data,
+       .hub_control            = ehci_hub_control,
+#if defined(CONFIG_PM)
+       .bus_suspend            = ehci_bus_suspend,
+       .bus_resume             = ehci_bus_resume,
+#endif
+};
+
+#if !defined(DEBUG)
+#undef dev_dbg
+static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+       const struct device *_dev, const char *fmt, ...) {return 0;}
+#endif
+
+
+static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
+{
+       int result;
+       struct usb_hcd *hcd;
+       unsigned int virq;
+       static u64 dummy_mask = DMA_32BIT_MASK;
+
+       if (usb_disabled()) {
+               result = -ENODEV;
+               goto fail_start;
+       }
+
+       result = ps3_mmio_region_create(dev->m_region);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
+                       __func__, __LINE__);
+               result = -EPERM;
+               goto fail_mmio;
+       }
+
+       dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+               __LINE__, dev->m_region->lpar_addr);
+
+       result = ps3_alloc_io_irq(dev->interrupt_id, &virq);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
+                       __func__, __LINE__, virq);
+               result = -EPERM;
+               goto fail_irq;
+       }
+
+       dev->core.power.power_state = PMSG_ON;
+       dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
+
+       hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev->core.bus_id);
+
+       if (!hcd) {
+               dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
+                       __LINE__);
+               result = -ENOMEM;
+               goto fail_create_hcd;
+       }
+
+       hcd->rsrc_start = dev->m_region->lpar_addr;
+       hcd->rsrc_len = dev->m_region->len;
+       hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
+
+       if (!hcd->regs) {
+               dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
+                       __LINE__);
+               result = -EPERM;
+               goto fail_ioremap;
+       }
+
+       dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
+               (unsigned long)hcd->rsrc_start);
+       dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len   %lxh\n", __func__, __LINE__,
+               (unsigned long)hcd->rsrc_len);
+       dev_dbg(&dev->core, "%s:%d: hcd->regs       %lxh\n", __func__, __LINE__,
+               (unsigned long)hcd->regs);
+       dev_dbg(&dev->core, "%s:%d: virq            %lu\n", __func__, __LINE__,
+               (unsigned long)virq);
+
+       ps3_system_bus_set_driver_data(dev, hcd);
+
+       result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
+                       __func__, __LINE__, result);
+               goto fail_add_hcd;
+       }
+
+       return result;
+
+fail_add_hcd:
+       iounmap(hcd->regs);
+fail_ioremap:
+       usb_put_hcd(hcd);
+fail_create_hcd:
+       ps3_free_io_irq(virq);
+fail_irq:
+       ps3_free_mmio_region(dev->m_region);
+fail_mmio:
+fail_start:
+       return result;
+}
+
+static int ps3_ehci_sb_remove(struct ps3_system_bus_device *dev)
+{
+       struct usb_hcd *hcd =
+               (struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+
+       usb_put_hcd(hcd);
+       ps3_system_bus_set_driver_data(dev, NULL);
+
+       return 0;
+}
+
+MODULE_ALIAS("ps3-ehci");
+
+static struct ps3_system_bus_driver ps3_ehci_sb_driver = {
+       .match_id = PS3_MATCH_ID_EHCI,
+       .core = {
+               .name = "ps3-ehci-driver",
+       },
+       .probe = ps3_ehci_sb_probe,
+       .remove = ps3_ehci_sb_remove,
+};
index 62e46dc..e7fbbd0 100644 (file)
@@ -789,13 +789,14 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
        head = ehci->async;
        timer_action_done (ehci, TIMER_ASYNC_OFF);
        if (!head->qh_next.qh) {
-               u32     cmd = readl (&ehci->regs->command);
+               u32     cmd = ehci_readl(ehci, &ehci->regs->command);
 
                if (!(cmd & CMD_ASE)) {
                        /* in case a clear of CMD_ASE didn't take yet */
-                       (void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
+                       (void)handshake(ehci, &ehci->regs->status,
+                                       STS_ASS, 0, 150);
                        cmd |= CMD_ASE | CMD_RUN;
-                       writel (cmd, &ehci->regs->command);
+                       ehci_writel(ehci, cmd, &ehci->regs->command);
                        ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
                        /* posted write need not be known to HC yet ... */
                }
@@ -1007,7 +1008,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
 
 static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
-       int             cmd = readl (&ehci->regs->command);
+       int             cmd = ehci_readl(ehci, &ehci->regs->command);
        struct ehci_qh  *prev;
 
 #ifdef DEBUG
@@ -1025,7 +1026,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
                if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
                                && !ehci->reclaim) {
                        /* ... and CMD_IAAD clear */
-                       writel (cmd & ~CMD_ASE, &ehci->regs->command);
+                       ehci_writel(ehci, cmd & ~CMD_ASE,
+                                   &ehci->regs->command);
                        wmb ();
                        // handshake later, if we need to
                        timer_action_done (ehci, TIMER_ASYNC_OFF);
@@ -1054,8 +1056,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
        ehci->reclaim_ready = 0;
        cmd |= CMD_IAAD;
-       writel (cmd, &ehci->regs->command);
-       (void) readl (&ehci->regs->command);
+       ehci_writel(ehci, cmd, &ehci->regs->command);
+       (void)ehci_readl(ehci, &ehci->regs->command);
        timer_action (ehci, TIMER_IAA_WATCHDOG);
 }
 
index 65c402a..7b5ae71 100644 (file)
@@ -433,20 +433,20 @@ static int enable_periodic (struct ehci_hcd *ehci)
        /* did clearing PSE did take effect yet?
         * takes effect only at frame boundaries...
         */
-       status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125);
+       status = handshake(ehci, &ehci->regs->status, STS_PSS, 0, 9 * 125);
        if (status != 0) {
                ehci_to_hcd(ehci)->state = HC_STATE_HALT;
                return status;
        }
 
-       cmd = readl (&ehci->regs->command) | CMD_PSE;
-       writel (cmd, &ehci->regs->command);
+       cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
+       ehci_writel(ehci, cmd, &ehci->regs->command);
        /* posted write ... PSS happens later */
        ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
 
        /* make sure ehci_work scans these */
-       ehci->next_uframe = readl (&ehci->regs->frame_index)
-                               % (ehci->periodic_size << 3);
+       ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
+               % (ehci->periodic_size << 3);
        return 0;
 }
 
@@ -458,14 +458,14 @@ static int disable_periodic (struct ehci_hcd *ehci)
        /* did setting PSE not take effect yet?
         * takes effect only at frame boundaries...
         */
-       status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
+       status = handshake(ehci, &ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
        if (status != 0) {
                ehci_to_hcd(ehci)->state = HC_STATE_HALT;
                return status;
        }
 
-       cmd = readl (&ehci->regs->command) & ~CMD_PSE;
-       writel (cmd, &ehci->regs->command);
+       cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
+       ehci_writel(ehci, cmd, &ehci->regs->command);
        /* posted write ... */
 
        ehci->next_uframe = -1;
@@ -1336,7 +1336,7 @@ iso_stream_schedule (
                goto fail;
        }
 
-       now = readl (&ehci->regs->frame_index) % mod;
+       now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
 
        /* when's the last uframe this urb could start? */
        max = now + mod;
@@ -2088,7 +2088,7 @@ scan_periodic (struct ehci_hcd *ehci)
         */
        now_uframe = ehci->next_uframe;
        if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
-               clock = readl (&ehci->regs->frame_index);
+               clock = ehci_readl(ehci, &ehci->regs->frame_index);
        else
                clock = now_uframe + mod - 1;
        clock %= mod;
@@ -2213,7 +2213,7 @@ restart:
                        if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
                                break;
                        ehci->next_uframe = now_uframe;
-                       now = readl (&ehci->regs->frame_index) % mod;
+                       now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
                        if (now_uframe == now)
                                break;
 
index 74dbc6c..ec0da03 100644 (file)
@@ -74,7 +74,11 @@ struct ehci_hcd {                    /* one per controller */
 
        /* per root hub port */
        unsigned long           reset_done [EHCI_MAX_ROOT_PORTS];
-       unsigned long           bus_suspended;
+       /* bit vectors (one bit per port) */
+       unsigned long           bus_suspended;          /* which ports were
+                       already suspended at the start of a bus suspend */
+       unsigned long           companion_ports;        /* which ports are
+                       dedicated to the companion controller */
 
        /* per-HC memory pools (could be per-bus, but ...) */
        struct dma_pool         *qh_pool;       /* qh per active urb */
@@ -92,6 +96,7 @@ struct ehci_hcd {                     /* one per controller */
        unsigned                is_tdi_rh_tt:1; /* TDI roothub with TT */
        unsigned                no_selective_suspend:1;
        unsigned                has_fsl_port_bug:1; /* FreeScale */
+       unsigned                big_endian_mmio:1;
 
        u8                      sbrn;           /* packed release number */
 
@@ -651,6 +656,45 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
 #define        ehci_has_fsl_portno_bug(e)              (0)
 #endif
 
+/*
+ * While most USB host controllers implement their registers in
+ * little-endian format, a minority (celleb companion chip) implement
+ * them in big endian format.
+ *
+ * This attempts to support either format at compile time without a
+ * runtime penalty, or both formats with the additional overhead
+ * of checking a flag bit.
+ */
+
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+#define ehci_big_endian_mmio(e)                ((e)->big_endian_mmio)
+#else
+#define ehci_big_endian_mmio(e)                0
+#endif
+
+static inline unsigned int ehci_readl (const struct ehci_hcd *ehci,
+                                      __u32 __iomem * regs)
+{
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+       return ehci_big_endian_mmio(ehci) ?
+               readl_be((__force u32 *)regs) :
+               readl((__force u32 *)regs);
+#else
+       return readl((__force u32 *)regs);
+#endif
+}
+
+static inline void ehci_writel (const struct ehci_hcd *ehci,
+                               const unsigned int val, __u32 __iomem *regs)
+{
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+       ehci_big_endian_mmio(ehci) ?
+               writel_be(val, (__force u32 *)regs) :
+               writel(val, (__force u32 *)regs);
+#else
+       writel(val, (__force u32 *)regs);
+#endif
+}
 
 /*-------------------------------------------------------------------------*/
 
index cc40551..9303464 100644 (file)
@@ -170,7 +170,6 @@ static int usb_hcd_at91_remove(struct usb_hcd *hcd,
        at91_stop_hc(pdev);
        iounmap(hcd->regs);
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-       disable_irq_wake(hcd->irq);
 
        clk_put(fclk);
        clk_put(iclk);
@@ -271,8 +270,6 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
 
        if (device_may_wakeup(&pdev->dev))
                enable_irq_wake(hcd->irq);
-       else
-               disable_irq_wake(hcd->irq);
 
        /*
         * The integrated transceivers seem unable to notice disconnect,
@@ -293,6 +290,11 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
 
 static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
 {
+       struct usb_hcd  *hcd = platform_get_drvdata(pdev);
+
+       if (device_may_wakeup(&pdev->dev))
+               disable_irq_wake(hcd->irq);
+
        if (!clocked) {
                clk_enable(iclk);
                clk_enable(fclk);
@@ -320,18 +322,3 @@ static struct platform_driver ohci_hcd_at91_driver = {
        },
 };
 
-static int __init ohci_hcd_at91_init (void)
-{
-       if (usb_disabled())
-               return -ENODEV;
-
-       return platform_driver_register(&ohci_hcd_at91_driver);
-}
-
-static void __exit ohci_hcd_at91_cleanup (void)
-{
-       platform_driver_unregister(&ohci_hcd_at91_driver);
-}
-
-module_init (ohci_hcd_at91_init);
-module_exit (ohci_hcd_at91_cleanup);
index e70b243..663a060 100644 (file)
@@ -345,19 +345,3 @@ static struct platform_driver ohci_hcd_au1xxx_driver = {
        },
 };
 
-static int __init ohci_hcd_au1xxx_init (void)
-{
-       pr_debug (DRIVER_INFO " (Au1xxx)");
-       pr_debug ("block sizes: ed %d td %d\n",
-               sizeof (struct ed), sizeof (struct td));
-
-       return platform_driver_register(&ohci_hcd_au1xxx_driver);
-}
-
-static void __exit ohci_hcd_au1xxx_cleanup (void)
-{
-       platform_driver_unregister(&ohci_hcd_au1xxx_driver);
-}
-
-module_init (ohci_hcd_au1xxx_init);
-module_exit (ohci_hcd_au1xxx_cleanup);
index 3348b07..44c60fb 100644 (file)
@@ -214,15 +214,3 @@ static struct platform_driver ohci_hcd_ep93xx_driver = {
        },
 };
 
-static int __init ohci_hcd_ep93xx_init(void)
-{
-       return platform_driver_register(&ohci_hcd_ep93xx_driver);
-}
-
-static void __exit ohci_hcd_ep93xx_cleanup(void)
-{
-       platform_driver_unregister(&ohci_hcd_ep93xx_driver);
-}
-
-module_init(ohci_hcd_ep93xx_init);
-module_exit(ohci_hcd_ep93xx_cleanup);
index c1c1d87..fa6a7ce 100644 (file)
@@ -855,63 +855,167 @@ MODULE_LICENSE ("GPL");
 
 #ifdef CONFIG_PCI
 #include "ohci-pci.c"
+#define PCI_DRIVER             ohci_pci_driver
 #endif
 
 #ifdef CONFIG_SA1111
 #include "ohci-sa1111.c"
+#define SA1111_DRIVER          ohci_hcd_sa1111_driver
 #endif
 
 #ifdef CONFIG_ARCH_S3C2410
 #include "ohci-s3c2410.c"
+#define PLATFORM_DRIVER                ohci_hcd_s3c2410_driver
 #endif
 
 #ifdef CONFIG_ARCH_OMAP
 #include "ohci-omap.c"
+#define PLATFORM_DRIVER                ohci_hcd_omap_driver
 #endif
 
 #ifdef CONFIG_ARCH_LH7A404
 #include "ohci-lh7a404.c"
+#define PLATFORM_DRIVER                ohci_hcd_lh7a404_driver
 #endif
 
 #ifdef CONFIG_PXA27x
 #include "ohci-pxa27x.c"
+#define PLATFORM_DRIVER                ohci_hcd_pxa27x_driver
 #endif
 
 #ifdef CONFIG_ARCH_EP93XX
 #include "ohci-ep93xx.c"
+#define PLATFORM_DRIVER                ohci_hcd_ep93xx_driver
 #endif
 
 #ifdef CONFIG_SOC_AU1X00
 #include "ohci-au1xxx.c"
+#define PLATFORM_DRIVER                ohci_hcd_au1xxx_driver
 #endif
 
 #ifdef CONFIG_PNX8550
 #include "ohci-pnx8550.c"
+#define PLATFORM_DRIVER                ohci_hcd_pnx8550_driver
 #endif
 
 #ifdef CONFIG_USB_OHCI_HCD_PPC_SOC
 #include "ohci-ppc-soc.c"
+#define PLATFORM_DRIVER                ohci_hcd_ppc_soc_driver
 #endif
 
 #ifdef CONFIG_ARCH_AT91
 #include "ohci-at91.c"
+#define PLATFORM_DRIVER                ohci_hcd_at91_driver
 #endif
 
 #ifdef CONFIG_ARCH_PNX4008
 #include "ohci-pnx4008.c"
+#define PLATFORM_DRIVER                usb_hcd_pnx4008_driver
 #endif
 
-#if !(defined(CONFIG_PCI) \
-      || defined(CONFIG_SA1111) \
-      || defined(CONFIG_ARCH_S3C2410) \
-      || defined(CONFIG_ARCH_OMAP) \
-      || defined (CONFIG_ARCH_LH7A404) \
-      || defined (CONFIG_PXA27x) \
-      || defined (CONFIG_ARCH_EP93XX) \
-      || defined (CONFIG_SOC_AU1X00) \
-      || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
-      || defined (CONFIG_ARCH_AT91) \
-      || defined (CONFIG_ARCH_PNX4008) \
-       )
+
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF
+#include "ohci-ppc-of.c"
+#define OF_PLATFORM_DRIVER     ohci_hcd_ppc_of_driver
+#endif
+
+#ifdef CONFIG_PPC_PS3
+#include "ohci-ps3.c"
+#define PS3_SYSTEM_BUS_DRIVER  ps3_ohci_sb_driver
+#endif
+
+#if    !defined(PCI_DRIVER) &&         \
+       !defined(PLATFORM_DRIVER) &&    \
+       !defined(OF_PLATFORM_DRIVER) && \
+       !defined(SA1111_DRIVER) &&      \
+       !defined(PS3_SYSTEM_BUS_DRIVER)
 #error "missing bus glue for ohci-hcd"
 #endif
+
+static int __init ohci_hcd_mod_init(void)
+{
+       int retval = 0;
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       printk (KERN_DEBUG "%s: " DRIVER_INFO "\n", hcd_name);
+       pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
+               sizeof (struct ed), sizeof (struct td));
+
+#ifdef PS3_SYSTEM_BUS_DRIVER
+       retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+       if (retval < 0)
+               goto error_ps3;
+#endif
+
+#ifdef PLATFORM_DRIVER
+       retval = platform_driver_register(&PLATFORM_DRIVER);
+       if (retval < 0)
+               goto error_platform;
+#endif
+
+#ifdef OF_PLATFORM_DRIVER
+       retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
+       if (retval < 0)
+               goto error_of_platform;
+#endif
+
+#ifdef SA1111_DRIVER
+       retval = sa1111_driver_register(&SA1111_DRIVER);
+       if (retval < 0)
+               goto error_sa1111;
+#endif
+
+#ifdef PCI_DRIVER
+       retval = pci_register_driver(&PCI_DRIVER);
+       if (retval < 0)
+               goto error_pci;
+#endif
+
+       return retval;
+
+       /* Error path */
+#ifdef PCI_DRIVER
+ error_pci:
+#endif
+#ifdef SA1111_DRIVER
+       sa1111_driver_unregister(&SA1111_DRIVER);
+ error_sa1111:
+#endif
+#ifdef OF_PLATFORM_DRIVER
+       of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+ error_of_platform:
+#endif
+#ifdef PLATFORM_DRIVER
+       platform_driver_unregister(&PLATFORM_DRIVER);
+ error_platform:
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+       ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+ error_ps3:
+#endif
+       return retval;
+}
+module_init(ohci_hcd_mod_init);
+
+static void __exit ohci_hcd_mod_exit(void)
+{
+#ifdef PCI_DRIVER
+       pci_unregister_driver(&PCI_DRIVER);
+#endif
+#ifdef SA1111_DRIVER
+       sa1111_driver_unregister(&SA1111_DRIVER);
+#endif
+#ifdef OF_PLATFORM_DRIVER
+       of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+#endif
+#ifdef PLATFORM_DRIVER
+       platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+       ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+#endif
+}
+module_exit(ohci_hcd_mod_exit);
+
index e9807cf..4a043ab 100644 (file)
@@ -251,19 +251,3 @@ static struct platform_driver ohci_hcd_lh7a404_driver = {
        },
 };
 
-static int __init ohci_hcd_lh7a404_init (void)
-{
-       pr_debug (DRIVER_INFO " (LH7A404)");
-       pr_debug ("block sizes: ed %d td %d\n",
-               sizeof (struct ed), sizeof (struct td));
-
-       return platform_driver_register(&ohci_hcd_lh7a404_driver);
-}
-
-static void __exit ohci_hcd_lh7a404_cleanup (void)
-{
-       platform_driver_unregister(&ohci_hcd_lh7a404_driver);
-}
-
-module_init (ohci_hcd_lh7a404_init);
-module_exit (ohci_hcd_lh7a404_cleanup);
index 27be1f9..5cfa3d1 100644 (file)
@@ -544,22 +544,3 @@ static struct platform_driver ohci_hcd_omap_driver = {
        },
 };
 
-static int __init ohci_hcd_omap_init (void)
-{
-       printk (KERN_DEBUG "%s: " DRIVER_INFO " (OMAP)\n", hcd_name);
-       if (usb_disabled())
-               return -ENODEV;
-
-       pr_debug("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
-               sizeof (struct ed), sizeof (struct td));
-
-       return platform_driver_register(&ohci_hcd_omap_driver);
-}
-
-static void __exit ohci_hcd_omap_cleanup (void)
-{
-       platform_driver_unregister(&ohci_hcd_omap_driver);
-}
-
-module_init (ohci_hcd_omap_init);
-module_exit (ohci_hcd_omap_cleanup);
index 596e0b4..b331ac4 100644 (file)
 
 /*-------------------------------------------------------------------------*/
 
-static int
-ohci_pci_reset (struct usb_hcd *hcd)
+/* AMD 756, for most chips (early revs), corrupts register
+ * values on read ... so enable the vendor workaround.
+ */
+static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd)
 {
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
 
-       ohci_hcd_init (ohci);
-       return ohci_init (ohci);
+       ohci->flags = OHCI_QUIRK_AMD756;
+       ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
+
+       /* also erratum 10 (suspend/resume issues) */
+       device_init_wakeup(&hcd->self.root_hub->dev, 0);
+
+       return 0;
 }
 
-static int __devinit
-ohci_pci_start (struct usb_hcd *hcd)
+/* Apple's OHCI driver has a lot of bizarre workarounds
+ * for this chip.  Evidently control and bulk lists
+ * can get confused.  (B&W G3 models, and ...)
+ */
+static int __devinit ohci_quirk_opti(struct usb_hcd *hcd)
 {
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
-       int             ret;
 
-       /* REVISIT this whole block should move to reset(), which handles
-        * all the other one-time init.
+       ohci_dbg (ohci, "WARNING: OPTi workarounds unavailable\n");
+
+       return 0;
+}
+
+/* Check for NSC87560. We have to look at the bridge (fn1) to
+ * identify the USB (fn2). This quirk might apply to more or
+ * even all NSC stuff.
+ */
+static int __devinit ohci_quirk_ns(struct usb_hcd *hcd)
+{
+       struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+       struct pci_dev  *b;
+
+       b  = pci_get_slot (pdev->bus, PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
+       if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
+           && b->vendor == PCI_VENDOR_ID_NS) {
+               struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+               ohci->flags |= OHCI_QUIRK_SUPERIO;
+               ohci_dbg (ohci, "Using NSC SuperIO setup\n");
+       }
+       pci_dev_put(b);
+
+       return 0;
+}
+
+/* Check for Compaq's ZFMicro chipset, which needs short
+ * delays before control or bulk queues get re-activated
+ * in finish_unlinks()
+ */
+static int __devinit 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");
+
+       return 0;
+}
+
+/* Check for Toshiba SCC OHCI which has big endian registers
+ * and little endian in memory data structures
+ */
+static int __devinit ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+       /* That chip is only present in the southbridge of some
+        * cell based platforms which are supposed to select
+        * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO. We verify here if
+        * that was the case though.
+        */
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+       ohci->flags |= OHCI_QUIRK_BE_MMIO;
+       ohci_dbg (ohci, "enabled big endian Toshiba quirk\n");
+       return 0;
+#else
+       ohci_err (ohci, "unsupported big endian Toshiba quirk\n");
+       return -ENXIO;
+#endif
+}
+
+/* List of quirks for OHCI */
+static const struct pci_device_id ohci_pci_quirks[] = {
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x740c),
+               .driver_data = (unsigned long)ohci_quirk_amd756,
+       },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_OPTI, 0xc861),
+               .driver_data = (unsigned long)ohci_quirk_opti,
+       },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_ANY_ID),
+               .driver_data = (unsigned long)ohci_quirk_ns,
+       },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xa0f8),
+               .driver_data = (unsigned long)ohci_quirk_zfmicro,
+       },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6),
+               .driver_data = (unsigned long)ohci_quirk_toshiba_scc,
+       },
+       /* FIXME for some of the early AMD 760 southbridges, OHCI
+        * won't work at all.  blacklist them.
         */
+
+       {},
+};
+
+static int ohci_pci_reset (struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+       int ret = 0;
+
        if (hcd->self.controller) {
                struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+               const struct pci_device_id *quirk_id;
 
-               /* AMD 756, for most chips (early revs), corrupts register
-                * values on read ... so enable the vendor workaround.
-                */
-               if (pdev->vendor == PCI_VENDOR_ID_AMD
-                               && pdev->device == 0x740c) {
-                       ohci->flags = OHCI_QUIRK_AMD756;
-                       ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
-                       /* also erratum 10 (suspend/resume issues) */
-                       device_init_wakeup(&hcd->self.root_hub->dev, 0);
+               quirk_id = pci_match_id(ohci_pci_quirks, pdev);
+               if (quirk_id != NULL) {
+                       int (*quirk)(struct usb_hcd *ohci);
+                       quirk = (void *)quirk_id->driver_data;
+                       ret = quirk(hcd);
                }
+       }
+       if (ret == 0) {
+               ohci_hcd_init (ohci);
+               return ohci_init (ohci);
+       }
+       return ret;
+}
 
-               /* FIXME for some of the early AMD 760 southbridges, OHCI
-                * won't work at all.  blacklist them.
-                */
-
-               /* Apple's OHCI driver has a lot of bizarre workarounds
-                * for this chip.  Evidently control and bulk lists
-                * can get confused.  (B&W G3 models, and ...)
-                */
-               else if (pdev->vendor == PCI_VENDOR_ID_OPTI
-                               && pdev->device == 0xc861) {
-                       ohci_dbg (ohci,
-                               "WARNING: OPTi workarounds unavailable\n");
-               }
 
-               /* Check for NSC87560. We have to look at the bridge (fn1) to
-                * identify the USB (fn2). This quirk might apply to more or
-                * even all NSC stuff.
-                */
-               else if (pdev->vendor == PCI_VENDOR_ID_NS) {
-                       struct pci_dev  *b;
-
-                       b  = pci_get_slot (pdev->bus,
-                                       PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
-                       if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
-                                       && b->vendor == PCI_VENDOR_ID_NS) {
-                               ohci->flags |= OHCI_QUIRK_SUPERIO;
-                               ohci_dbg (ohci, "Using NSC SuperIO setup\n");
-                       }
-                       pci_dev_put(b);
-               }
+static int __devinit ohci_pci_start (struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+       int             ret;
 
-               /* Check for Compaq's ZFMicro chipset, which needs short
-                * delays before control or bulk queues get re-activated
-                * in finish_unlinks()
-                */
-               else if (pdev->vendor == PCI_VENDOR_ID_COMPAQ
-                               && pdev->device  == 0xa0f8) {
-                       ohci->flags |= OHCI_QUIRK_ZFMICRO;
-                       ohci_dbg (ohci,
-                               "enabled Compaq ZFMicro chipset quirk\n");
-               }
+#ifdef CONFIG_PM /* avoid warnings about unused pdev */
+       if (hcd->self.controller) {
+               struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
 
                /* RWC may not be set for add-in PCI cards, since boot
                 * firmware probably ignored them.  This transfers PCI
@@ -101,16 +176,14 @@ ohci_pci_start (struct usb_hcd *hcd)
                if (device_may_wakeup(&pdev->dev))
                        ohci->hc_control |= OHCI_CTRL_RWC;
        }
+#endif /* CONFIG_PM */
 
-       /* NOTE: there may have already been a first reset, to
-        * keep bios/smm irqs from making trouble
-        */
-       if ((ret = ohci_run (ohci)) < 0) {
+       ret = ohci_run (ohci);
+       if (ret < 0) {
                ohci_err (ohci, "can't start\n");
                ohci_stop (hcd);
-               return ret;
        }
-       return 0;
+       return ret;
 }
 
 #ifdef CONFIG_PM
@@ -238,23 +311,3 @@ static struct pci_driver ohci_pci_driver = {
        .shutdown =     usb_hcd_pci_shutdown,
 };
 
-
-static int __init ohci_hcd_pci_init (void)
-{
-       printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name);
-       if (usb_disabled())
-               return -ENODEV;
-
-       pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
-               sizeof (struct ed), sizeof (struct td));
-       return pci_register_driver (&ohci_pci_driver);
-}
-module_init (ohci_hcd_pci_init);
-
-/*-------------------------------------------------------------------------*/
-
-static void __exit ohci_hcd_pci_cleanup (void)
-{
-       pci_unregister_driver (&ohci_pci_driver);
-}
-module_exit (ohci_hcd_pci_cleanup);
index 3a8cbfb..893b172 100644 (file)
@@ -465,15 +465,3 @@ static struct platform_driver usb_hcd_pnx4008_driver = {
        .remove = usb_hcd_pnx4008_remove,
 };
 
-static int __init usb_hcd_pnx4008_init(void)
-{
-       return platform_driver_register(&usb_hcd_pnx4008_driver);
-}
-
-static void __exit usb_hcd_pnx4008_cleanup(void)
-{
-       return platform_driver_unregister(&usb_hcd_pnx4008_driver);
-}
-
-module_init(usb_hcd_pnx4008_init);
-module_exit(usb_hcd_pnx4008_cleanup);
index 6922b91..de45eb0 100644 (file)
@@ -240,19 +240,3 @@ static struct platform_driver ohci_hcd_pnx8550_driver = {
        .remove         = ohci_hcd_pnx8550_drv_remove,
 };
 
-static int __init ohci_hcd_pnx8550_init (void)
-{
-       pr_debug (DRIVER_INFO " (pnx8550)");
-       pr_debug ("block sizes: ed %d td %d\n",
-               sizeof (struct ed), sizeof (struct td));
-
-       return platform_driver_register(&ohci_hcd_pnx8550_driver);
-}
-
-static void __exit ohci_hcd_pnx8550_cleanup (void)
-{
-       platform_driver_unregister(&ohci_hcd_pnx8550_driver);
-}
-
-module_init (ohci_hcd_pnx8550_init);
-module_exit (ohci_hcd_pnx8550_cleanup);
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
new file mode 100644 (file)
index 0000000..08e237c
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ * (C) Copyright 2006 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Bus glue for OHCI HC on the of_platform bus
+ *
+ * Modified for of_platform bus from ohci-sa1111.c
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/signal.h>
+
+#include <asm/of_platform.h>
+#include <asm/prom.h>
+
+
+static int __devinit
+ohci_ppc_of_start(struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+       int             ret;
+
+       if ((ret = ohci_init(ohci)) < 0)
+               return ret;
+
+       if ((ret = ohci_run(ohci)) < 0) {
+               err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
+               ohci_stop(hcd);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct hc_driver ohci_ppc_of_hc_driver = {
+       .description =          hcd_name,
+       .product_desc =         "OF OHCI",
+       .hcd_priv_size =        sizeof(struct ohci_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq =                  ohci_irq,
+       .flags =                HCD_USB11 | HCD_MEMORY,
+
+       /*
+        * basic lifecycle operations
+        */
+       .start =                ohci_ppc_of_start,
+       .stop =                 ohci_stop,
+       .shutdown =             ohci_shutdown,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue =          ohci_urb_enqueue,
+       .urb_dequeue =          ohci_urb_dequeue,
+       .endpoint_disable =     ohci_endpoint_disable,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number =     ohci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data =      ohci_hub_status_data,
+       .hub_control =          ohci_hub_control,
+       .hub_irq_enable =       ohci_rhsc_enable,
+#ifdef CONFIG_PM
+       .bus_suspend =          ohci_bus_suspend,
+       .bus_resume =           ohci_bus_resume,
+#endif
+       .start_port_reset =     ohci_start_port_reset,
+};
+
+
+static int __devinit
+ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+       struct device_node *dn = op->node;
+       struct usb_hcd *hcd;
+       struct ohci_hcd *ohci;
+       struct resource res;
+       int irq;
+
+       int rv;
+       int is_bigendian;
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       is_bigendian =
+               device_is_compatible(dn, "ohci-bigendian") ||
+               device_is_compatible(dn, "ohci-be");
+
+       dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
+
+       rv = of_address_to_resource(dn, 0, &res);
+       if (rv)
+               return rv;
+
+       hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
+       if (!hcd)
+               return -ENOMEM;
+
+       hcd->rsrc_start = res.start;
+       hcd->rsrc_len = res.end - res.start + 1;
+
+       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+               printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
+               rv = -EBUSY;
+               goto err_rmr;
+       }
+
+       irq = irq_of_parse_and_map(dn, 0);
+       if (irq == NO_IRQ) {
+               printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+               rv = -EBUSY;
+               goto err_irq;
+       }
+
+       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       if (!hcd->regs) {
+               printk(KERN_ERR __FILE__ ": ioremap failed\n");
+               rv = -ENOMEM;
+               goto err_ioremap;
+       }
+
+       ohci = hcd_to_ohci(hcd);
+       if (is_bigendian)
+               ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+
+       ohci_hcd_init(ohci);
+
+       rv = usb_add_hcd(hcd, irq, 0);
+       if (rv == 0)
+               return 0;
+
+       iounmap(hcd->regs);
+err_ioremap:
+       irq_dispose_mapping(irq);
+err_irq:
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_rmr:
+       usb_put_hcd(hcd);
+
+       return rv;
+}
+
+static int ohci_hcd_ppc_of_remove(struct of_device *op)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+       dev_set_drvdata(&op->dev, NULL);
+
+       dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
+
+       usb_remove_hcd(hcd);
+
+       iounmap(hcd->regs);
+       irq_dispose_mapping(hcd->irq);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+       usb_put_hcd(hcd);
+
+       return 0;
+}
+
+static int ohci_hcd_ppc_of_shutdown(struct of_device *op)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+
+        if (hcd->driver->shutdown)
+                hcd->driver->shutdown(hcd);
+
+       return 0;
+}
+
+
+static struct of_device_id ohci_hcd_ppc_of_match[] = {
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
+       {
+               .name = "usb",
+               .compatible = "ohci-bigendian",
+       },
+       {
+               .name = "usb",
+               .compatible = "ohci-be",
+       },
+#endif
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE
+       {
+               .name = "usb",
+               .compatible = "ohci-littledian",
+       },
+       {
+               .name = "usb",
+               .compatible = "ohci-le",
+       },
+#endif
+       {},
+};
+MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
+
+#if    !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
+       !defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
+#error "No endianess selected for ppc-of-ohci"
+#endif
+
+
+static struct of_platform_driver ohci_hcd_ppc_of_driver = {
+       .name           = "ppc-of-ohci",
+       .match_table    = ohci_hcd_ppc_of_match,
+       .probe          = ohci_hcd_ppc_of_probe,
+       .remove         = ohci_hcd_ppc_of_remove,
+       .shutdown       = ohci_hcd_ppc_of_shutdown,
+#ifdef CONFIG_PM
+       /*.suspend      = ohci_hcd_ppc_soc_drv_suspend,*/
+       /*.resume       = ohci_hcd_ppc_soc_drv_resume,*/
+#endif
+       .driver         = {
+               .name   = "ppc-of-ohci",
+               .owner  = THIS_MODULE,
+       },
+};
+
index e1a7eb8..1a2e177 100644 (file)
@@ -72,7 +72,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
        }
 
        ohci = hcd_to_ohci(hcd);
-       ohci->flags |= OHCI_BIG_ENDIAN;
+       ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
        ohci_hcd_init(ohci);
 
        retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
@@ -208,19 +208,3 @@ static struct platform_driver ohci_hcd_ppc_soc_driver = {
        },
 };
 
-static int __init ohci_hcd_ppc_soc_init(void)
-{
-       pr_debug(DRIVER_INFO " (PPC SOC)\n");
-       pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed),
-                                                       sizeof(struct td));
-
-       return platform_driver_register(&ohci_hcd_ppc_soc_driver);
-}
-
-static void __exit ohci_hcd_ppc_soc_cleanup(void)
-{
-       platform_driver_unregister(&ohci_hcd_ppc_soc_driver);
-}
-
-module_init(ohci_hcd_ppc_soc_init);
-module_exit(ohci_hcd_ppc_soc_cleanup);
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
new file mode 100644 (file)
index 0000000..69d948b
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ *  PS3 OHCI Host Controller driver
+ *
+ *  Copyright (C) 2006 Sony Computer Entertainment Inc.
+ *  Copyright 2006 Sony Corp.
+ *
+ *  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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <asm/ps3.h>
+
+static int ps3_ohci_hc_reset(struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+       ohci->flags |= OHCI_QUIRK_BE_MMIO;
+       ohci_hcd_init(ohci);
+       return ohci_init(ohci);
+}
+
+static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd)
+{
+       int result;
+       struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+       /* Handle root hub init quirk in spider south bridge. */
+       /* Also set PwrOn2PwrGood to 0x7f (254ms). */
+
+       ohci_writel(ohci, 0x7f000000 | RH_A_PSM | RH_A_OCPM,
+               &ohci->regs->roothub.a);
+       ohci_writel(ohci, 0x00060000, &ohci->regs->roothub.b);
+
+       result = ohci_run(ohci);
+
+       if (result < 0) {
+               err("can't start %s", hcd->self.bus_name);
+               ohci_stop(hcd);
+       }
+
+       return result;
+}
+
+static const struct hc_driver ps3_ohci_hc_driver = {
+       .description            = hcd_name,
+       .product_desc           = "PS3 OHCI Host Controller",
+       .hcd_priv_size          = sizeof(struct ohci_hcd),
+       .irq                    = ohci_irq,
+       .flags                  = HCD_MEMORY | HCD_USB11,
+       .reset                  = ps3_ohci_hc_reset,
+       .start                  = ps3_ohci_hc_start,
+       .stop                   = ohci_stop,
+       .shutdown               = ohci_shutdown,
+       .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,
+       .start_port_reset       = ohci_start_port_reset,
+#if defined(CONFIG_PM)
+       .bus_suspend            = ohci_bus_suspend,
+       .bus_resume             = ohci_bus_resume,
+#endif
+};
+
+/* redefine dev_dbg to do a syntax check */
+
+#if !defined(DEBUG)
+#undef dev_dbg
+static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+       const struct device *_dev, const char *fmt, ...) {return 0;}
+#endif
+
+static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
+{
+       int result;
+       struct usb_hcd *hcd;
+       unsigned int virq;
+       static u64 dummy_mask = DMA_32BIT_MASK;
+
+       if (usb_disabled()) {
+               result = -ENODEV;
+               goto fail_start;
+       }
+
+       result = ps3_mmio_region_create(dev->m_region);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
+                       __func__, __LINE__);
+               result = -EPERM;
+               goto fail_mmio;
+       }
+
+       dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+               __LINE__, dev->m_region->lpar_addr);
+
+       result = ps3_alloc_io_irq(dev->interrupt_id, &virq);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
+                       __func__, __LINE__, virq);
+               result = -EPERM;
+               goto fail_irq;
+       }
+
+       dev->core.power.power_state = PMSG_ON;
+       dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
+
+       hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev->core.bus_id);
+
+       if (!hcd) {
+               dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
+                       __LINE__);
+               result = -ENOMEM;
+               goto fail_create_hcd;
+       }
+
+       hcd->rsrc_start = dev->m_region->lpar_addr;
+       hcd->rsrc_len = dev->m_region->len;
+       hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
+
+       if (!hcd->regs) {
+               dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
+                       __LINE__);
+               result = -EPERM;
+               goto fail_ioremap;
+       }
+
+       dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
+               (unsigned long)hcd->rsrc_start);
+       dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len   %lxh\n", __func__, __LINE__,
+               (unsigned long)hcd->rsrc_len);
+       dev_dbg(&dev->core, "%s:%d: hcd->regs       %lxh\n", __func__, __LINE__,
+               (unsigned long)hcd->regs);
+       dev_dbg(&dev->core, "%s:%d: virq            %lu\n", __func__, __LINE__,
+               (unsigned long)virq);
+
+       ps3_system_bus_set_driver_data(dev, hcd);
+
+       result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
+                       __func__, __LINE__, result);
+               goto fail_add_hcd;
+       }
+
+       return result;
+
+fail_add_hcd:
+       iounmap(hcd->regs);
+fail_ioremap:
+       usb_put_hcd(hcd);
+fail_create_hcd:
+       ps3_free_io_irq(virq);
+fail_irq:
+       ps3_free_mmio_region(dev->m_region);
+fail_mmio:
+fail_start:
+       return result;
+}
+
+static int ps3_ohci_sb_remove (struct ps3_system_bus_device *dev)
+{
+       struct usb_hcd *hcd =
+               (struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+
+       usb_put_hcd(hcd);
+       ps3_system_bus_set_driver_data(dev, NULL);
+
+       return 0;
+}
+
+MODULE_ALIAS("ps3-ohci");
+
+static struct ps3_system_bus_driver ps3_ohci_sb_driver = {
+       .match_id = PS3_MATCH_ID_OHCI,
+       .core = {
+               .name = "ps3-ohci-driver",
+       },
+       .probe = ps3_ohci_sb_probe,
+       .remove = ps3_ohci_sb_remove,
+};
index 3bbea84..f1563dc 100644 (file)
@@ -369,19 +369,3 @@ static struct platform_driver ohci_hcd_pxa27x_driver = {
        },
 };
 
-static int __init ohci_hcd_pxa27x_init (void)
-{
-       pr_debug (DRIVER_INFO " (pxa27x)");
-       pr_debug ("block sizes: ed %d td %d\n",
-               sizeof (struct ed), sizeof (struct td));
-
-       return platform_driver_register(&ohci_hcd_pxa27x_driver);
-}
-
-static void __exit ohci_hcd_pxa27x_cleanup (void)
-{
-       platform_driver_unregister(&ohci_hcd_pxa27x_driver);
-}
-
-module_init (ohci_hcd_pxa27x_init);
-module_exit (ohci_hcd_pxa27x_cleanup);
index b350d45..6829814 100644 (file)
@@ -501,15 +501,3 @@ static struct platform_driver ohci_hcd_s3c2410_driver = {
        },
 };
 
-static int __init ohci_hcd_s3c2410_init (void)
-{
-       return platform_driver_register(&ohci_hcd_s3c2410_driver);
-}
-
-static void __exit ohci_hcd_s3c2410_cleanup (void)
-{
-       platform_driver_unregister(&ohci_hcd_s3c2410_driver);
-}
-
-module_init (ohci_hcd_s3c2410_init);
-module_exit (ohci_hcd_s3c2410_cleanup);
index fe0090e..0f48f2d 100644 (file)
@@ -269,19 +269,3 @@ static struct sa1111_driver ohci_hcd_sa1111_driver = {
        .remove         = ohci_hcd_sa1111_drv_remove,
 };
 
-static int __init ohci_hcd_sa1111_init (void)
-{
-       dbg (DRIVER_INFO " (SA-1111)");
-       dbg ("block sizes: ed %d td %d",
-               sizeof (struct ed), sizeof (struct td));
-
-       return sa1111_driver_register(&ohci_hcd_sa1111_driver);
-}
-
-static void __exit ohci_hcd_sa1111_cleanup (void)
-{
-       sa1111_driver_unregister(&ohci_hcd_sa1111_driver);
-}
-
-module_init (ohci_hcd_sa1111_init);
-module_exit (ohci_hcd_sa1111_cleanup);
index 405257f..0dafcda 100644 (file)
@@ -394,8 +394,9 @@ struct ohci_hcd {
 #define        OHCI_QUIRK_AMD756       0x01                    /* erratum #4 */
 #define        OHCI_QUIRK_SUPERIO      0x02                    /* natsemi */
 #define        OHCI_QUIRK_INITRESET    0x04                    /* SiS, OPTi, ... */
-#define        OHCI_BIG_ENDIAN         0x08                    /* big endian HC */
-#define        OHCI_QUIRK_ZFMICRO      0x10                    /* Compaq ZFMicro chipset*/
+#define        OHCI_QUIRK_BE_DESC      0x08                    /* BE descriptors */
+#define        OHCI_QUIRK_BE_MMIO      0x10                    /* BE registers */
+#define        OHCI_QUIRK_ZFMICRO      0x20                    /* Compaq ZFMicro chipset*/
        // there are also chip quirks/bugs in init logic
 
 };
@@ -439,117 +440,164 @@ static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci)
  * a minority (notably the IBM STB04XXX and the Motorola MPC5200
  * processors) implement them in big endian format.
  *
+ * In addition some more exotic implementations like the Toshiba
+ * Spider (aka SCC) cell southbridge are "mixed" endian, that is,
+ * they have a different endianness for registers vs. in-memory
+ * descriptors.
+ *
  * This attempts to support either format at compile time without a
  * runtime penalty, or both formats with the additional overhead
  * of checking a flag bit.
+ *
+ * That leads to some tricky Kconfig rules howevber. There are
+ * different defaults based on some arch/ppc platforms, though
+ * the basic rules are:
+ *
+ * Controller type              Kconfig options needed
+ * ---------------              ----------------------
+ * little endian                CONFIG_USB_OHCI_LITTLE_ENDIAN
+ *
+ * fully big endian             CONFIG_USB_OHCI_BIG_ENDIAN_DESC _and_
+ *                              CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ *
+ * mixed endian                 CONFIG_USB_OHCI_LITTLE_ENDIAN _and_
+ *                              CONFIG_USB_OHCI_BIG_ENDIAN_{MMIO,DESC}
+ *
+ * (If you have a mixed endian controller, you -must- also define
+ * CONFIG_USB_OHCI_LITTLE_ENDIAN or things will not work when building
+ * both your mixed endian and a fully big endian controller support in
+ * the same kernel image).
  */
 
-#ifdef CONFIG_USB_OHCI_BIG_ENDIAN
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_DESC
+#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
+#define big_endian_desc(ohci)  (ohci->flags & OHCI_QUIRK_BE_DESC)
+#else
+#define big_endian_desc(ohci)  1               /* only big endian */
+#endif
+#else
+#define big_endian_desc(ohci)  0               /* only little endian */
+#endif
 
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
 #ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
-#define big_endian(ohci)       (ohci->flags & OHCI_BIG_ENDIAN) /* either */
+#define big_endian_mmio(ohci)  (ohci->flags & OHCI_QUIRK_BE_MMIO)
 #else
-#define big_endian(ohci)       1               /* only big endian */
+#define big_endian_mmio(ohci)  1               /* only big endian */
+#endif
+#else
+#define big_endian_mmio(ohci)  0               /* only little endian */
 #endif
 
 /*
  * Big-endian read/write functions are arch-specific.
  * Other arches can be added if/when they're needed.
+ *
+ * REVISIT: arch/powerpc now has readl/writel_be, so the
+ * definition below can die once the STB04xxx support is
+ * finally ported over.
  */
-#if defined(CONFIG_PPC)
+#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE)
 #define readl_be(addr)         in_be32((__force unsigned *)addr)
 #define writel_be(val, addr)   out_be32((__force unsigned *)addr, val)
 #endif
 
-static inline unsigned int ohci_readl (const struct ohci_hcd *ohci,
-                                                       __hc32 __iomem * regs)
+static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci,
+                                       __hc32 __iomem * regs)
 {
-       return big_endian(ohci) ? readl_be (regs) : readl ((__force u32 *)regs);
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+       return big_endian_mmio(ohci) ?
+               readl_be ((__force u32 *)regs) :
+               readl ((__force u32 *)regs);
+#else
+       return readl ((__force u32 *)regs);
+#endif
 }
 
-static inline void ohci_writel (const struct ohci_hcd *ohci,
-                               const unsigned int val, __hc32 __iomem *regs)
+static inline void _ohci_writel (const struct ohci_hcd *ohci,
+                                const unsigned int val, __hc32 __iomem *regs)
 {
-       big_endian(ohci) ? writel_be (val, regs) :
-                          writel (val, (__force u32 *)regs);
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+       big_endian_mmio(ohci) ?
+               writel_be (val, (__force u32 *)regs) :
+               writel (val, (__force u32 *)regs);
+#else
+               writel (val, (__force u32 *)regs);
+#endif
 }
 
-#else  /* !CONFIG_USB_OHCI_BIG_ENDIAN */
-
-#define big_endian(ohci)       0               /* only little endian */
-
 #ifdef CONFIG_ARCH_LH7A404
-       /* Marc Singer: at the time this code was written, the LH7A404
-        * had a problem reading the USB host registers.  This
-        * implementation of the ohci_readl function performs the read
-        * twice as a work-around.
-        */
-static inline unsigned int
-ohci_readl (const struct ohci_hcd *ohci, const __hc32 *regs)
-{
-       *(volatile __force unsigned int*) regs;
-       return *(volatile __force unsigned int*) regs;
-}
+/* Marc Singer: at the time this code was written, the LH7A404
+ * had a problem reading the USB host registers.  This
+ * implementation of the ohci_readl function performs the read
+ * twice as a work-around.
+ */
+#define ohci_readl(o,r)                (_ohci_readl(o,r),_ohci_readl(o,r))
+#define ohci_writel(o,v,r)     _ohci_writel(o,v,r)
 #else
-       /* Standard version of ohci_readl uses standard, platform
-        * specific implementation. */
-static inline unsigned int
-ohci_readl (const struct ohci_hcd *ohci, __hc32 __iomem * regs)
-{
-       return readl(regs);
-}
+#define ohci_readl(o,r)                _ohci_readl(o,r)
+#define ohci_writel(o,v,r)     _ohci_writel(o,v,r)
 #endif
 
-static inline void ohci_writel (const struct ohci_hcd *ohci,
-                               const unsigned int val, __hc32 __iomem *regs)
-{
-       writel (val, regs);
-}
-
-#endif /* !CONFIG_USB_OHCI_BIG_ENDIAN */
 
 /*-------------------------------------------------------------------------*/
 
 /* cpu to ohci */
 static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x)
 {
-       return big_endian(ohci) ? (__force __hc16)cpu_to_be16(x) : (__force __hc16)cpu_to_le16(x);
+       return big_endian_desc(ohci) ?
+               (__force __hc16)cpu_to_be16(x) :
+               (__force __hc16)cpu_to_le16(x);
 }
 
 static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x)
 {
-       return big_endian(ohci) ? cpu_to_be16p(x) : cpu_to_le16p(x);
+       return big_endian_desc(ohci) ?
+               cpu_to_be16p(x) :
+               cpu_to_le16p(x);
 }
 
 static inline __hc32 cpu_to_hc32 (const struct ohci_hcd *ohci, const u32 x)
 {
-       return big_endian(ohci) ? (__force __hc32)cpu_to_be32(x) : (__force __hc32)cpu_to_le32(x);
+       return big_endian_desc(ohci) ?
+               (__force __hc32)cpu_to_be32(x) :
+               (__force __hc32)cpu_to_le32(x);
 }
 
 static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x)
 {
-       return big_endian(ohci) ? cpu_to_be32p(x) : cpu_to_le32p(x);
+       return big_endian_desc(ohci) ?
+               cpu_to_be32p(x) :
+               cpu_to_le32p(x);
 }
 
 /* ohci to cpu */
 static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x)
 {
-       return big_endian(ohci) ? be16_to_cpu((__force __be16)x) : le16_to_cpu((__force __le16)x);
+       return big_endian_desc(ohci) ?
+               be16_to_cpu((__force __be16)x) :
+               le16_to_cpu((__force __le16)x);
 }
 
 static inline u16 hc16_to_cpup (const struct ohci_hcd *ohci, const __hc16 *x)
 {
-       return big_endian(ohci) ? be16_to_cpup((__force __be16 *)x) : le16_to_cpup((__force __le16 *)x);
+       return big_endian_desc(ohci) ?
+               be16_to_cpup((__force __be16 *)x) :
+               le16_to_cpup((__force __le16 *)x);
 }
 
 static inline u32 hc32_to_cpu (const struct ohci_hcd *ohci, const __hc32 x)
 {
-       return big_endian(ohci) ? be32_to_cpu((__force __be32)x) : le32_to_cpu((__force __le32)x);
+       return big_endian_desc(ohci) ?
+               be32_to_cpu((__force __be32)x) :
+               le32_to_cpu((__force __le32)x);
 }
 
 static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
 {
-       return big_endian(ohci) ? be32_to_cpup((__force __be32 *)x) : le32_to_cpup((__force __le32 *)x);
+       return big_endian_desc(ohci) ?
+               be32_to_cpup((__force __be32 *)x) :
+               le32_to_cpup((__force __le32 *)x);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -557,6 +605,9 @@ 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
@@ -568,7 +619,7 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
 static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
 {
        u32 tmp;
-       if (big_endian(ohci)) {
+       if (big_endian_desc(ohci)) {
                tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
                tmp >>= OHCI_BE_FRAME_NO_SHIFT;
        } else
@@ -580,7 +631,7 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
 static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci,
                                  const struct td *td, int index)
 {
-       return (__hc16 *)(big_endian(ohci) ?
+       return (__hc16 *)(big_endian_desc(ohci) ?
                        &td->hwPSW[index ^ 1] : &td->hwPSW[index]);
 }
 
index e345f15..5d6c06b 100644 (file)
@@ -168,9 +168,13 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
                        space, "", qh, qtype,
                        le32_to_cpu(qh->link), le32_to_cpu(element));
        if (qh->type == USB_ENDPOINT_XFER_ISOC)
-               out += sprintf(out, "%*s    period %d frame %x desc [%p]\n",
-                               space, "", qh->period, qh->iso_frame,
-                               qh->iso_packet_desc);
+               out += sprintf(out, "%*s    period %d phase %d load %d us, "
+                               "frame %x desc [%p]\n",
+                               space, "", qh->period, qh->phase, qh->load,
+                               qh->iso_frame, qh->iso_packet_desc);
+       else if (qh->type == USB_ENDPOINT_XFER_INT)
+               out += sprintf(out, "%*s    period %d phase %d load %d us\n",
+                               space, "", qh->period, qh->phase, qh->load);
 
        if (element & UHCI_PTR_QH)
                out += sprintf(out, "%*s  Element points to QH (bug?)\n", space, "");
@@ -208,7 +212,7 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
                                        space, "", nurbs);
        }
 
-       if (qh->udev) {
+       if (qh->dummy_td) {
                out += sprintf(out, "%*s  Dummy TD\n", space, "");
                out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0);
        }
@@ -347,31 +351,80 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
        struct uhci_qh *qh;
        struct uhci_td *td;
        struct list_head *tmp, *head;
+       int nframes, nerrs;
 
        out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
        out += sprintf(out, "HC status\n");
        out += uhci_show_status(uhci, out, len - (out - buf));
+
+       out += sprintf(out, "Periodic load table\n");
+       for (i = 0; i < MAX_PHASE; ++i) {
+               out += sprintf(out, "\t%d", uhci->load[i]);
+               if (i % 8 == 7)
+                       *out++ = '\n';
+       }
+       out += sprintf(out, "Total: %d, #INT: %d, #ISO: %d\n",
+                       uhci->total_load,
+                       uhci_to_hcd(uhci)->self.bandwidth_int_reqs,
+                       uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs);
        if (debug <= 1)
                return out - buf;
 
        out += sprintf(out, "Frame List\n");
+       nframes = 10;
+       nerrs = 0;
        for (i = 0; i < UHCI_NUMFRAMES; ++i) {
+               __le32 link, qh_dma;
+
+               j = 0;
                td = uhci->frame_cpu[i];
+               link = uhci->frame[i];
                if (!td)
-                       continue;
+                       goto check_link;
 
-               out += sprintf(out, "- Frame %d\n", i); \
-               if (td->dma_handle != (dma_addr_t)uhci->frame[i])
-                       out += sprintf(out, "    frame list does not match td->dma_handle!\n");
+               if (nframes > 0) {
+                       out += sprintf(out, "- Frame %d -> (%08x)\n",
+                                       i, le32_to_cpu(link));
+                       j = 1;
+               }
 
                head = &td->fl_list;
                tmp = head;
                do {
                        td = list_entry(tmp, struct uhci_td, fl_list);
                        tmp = tmp->next;
-                       out += uhci_show_td(td, out, len - (out - buf), 4);
+                       if (cpu_to_le32(td->dma_handle) != link) {
+                               if (nframes > 0)
+                                       out += sprintf(out, "    link does "
+                                               "not match list entry!\n");
+                               else
+                                       ++nerrs;
+                       }
+                       if (nframes > 0)
+                               out += uhci_show_td(td, out,
+                                               len - (out - buf), 4);
+                       link = td->link;
                } while (tmp != head);
+
+check_link:
+               qh_dma = uhci_frame_skel_link(uhci, i);
+               if (link != qh_dma) {
+                       if (nframes > 0) {
+                               if (!j) {
+                                       out += sprintf(out,
+                                               "- Frame %d -> (%08x)\n",
+                                               i, le32_to_cpu(link));
+                                       j = 1;
+                               }
+                               out += sprintf(out, "   link does not match "
+                                       "QH (%08x)!\n", le32_to_cpu(qh_dma));
+                       } else
+                               ++nerrs;
+               }
+               nframes -= j;
        }
+       if (nerrs > 0)
+               out += sprintf(out, "Skipped %d bad links\n", nerrs);
 
        out += sprintf(out, "Skeleton QHs\n");
 
index e0d4c23..49b9d39 100644 (file)
@@ -92,6 +92,34 @@ static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state);
 static void wakeup_rh(struct uhci_hcd *uhci);
 static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
 
+/*
+ * Calculate the link pointer DMA value for the first Skeleton QH in a frame.
+ */
+static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
+{
+       int skelnum;
+
+       /*
+        * The interrupt queues will be interleaved as evenly as possible.
+        * There's not much to be done about period-1 interrupts; they have
+        * to occur in every frame.  But we can schedule period-2 interrupts
+        * in odd-numbered frames, period-4 interrupts in frames congruent
+        * to 2 (mod 4), and so on.  This way each frame only has two
+        * interrupt QHs, which will help spread out bandwidth utilization.
+        *
+        * ffs (Find First bit Set) does exactly what we need:
+        * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[8],
+        * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
+        * ffs >= 7 => not on any high-period queue, so use
+        *      skel_int1_qh = skelqh[9].
+        * Add in UHCI_NUMFRAMES to insure at least one bit is set.
+        */
+       skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES);
+       if (skelnum <= 1)
+               skelnum = 9;
+       return UHCI_PTR_QH | cpu_to_le32(uhci->skelqh[skelnum]->dma_handle);
+}
+
 #include "uhci-debug.c"
 #include "uhci-q.c"
 #include "uhci-hub.c"
@@ -631,32 +659,11 @@ static int uhci_start(struct usb_hcd *hcd)
        /*
         * Fill the frame list: make all entries point to the proper
         * interrupt queue.
-        *
-        * The interrupt queues will be interleaved as evenly as possible.
-        * There's not much to be done about period-1 interrupts; they have
-        * to occur in every frame.  But we can schedule period-2 interrupts
-        * in odd-numbered frames, period-4 interrupts in frames congruent
-        * to 2 (mod 4), and so on.  This way each frame only has two
-        * interrupt QHs, which will help spread out bandwidth utilization.
         */
        for (i = 0; i < UHCI_NUMFRAMES; i++) {
-               int irq;
-
-               /*
-                * ffs (Find First bit Set) does exactly what we need:
-                * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[8],
-                * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
-                * ffs >= 7 => not on any high-period queue, so use
-                *      skel_int1_qh = skelqh[9].
-                * Add UHCI_NUMFRAMES to insure at least one bit is set.
-                */
-               irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES);
-               if (irq <= 1)
-                       irq = 9;
 
                /* Only place we don't use the frame list routines */
-               uhci->frame[i] = UHCI_PTR_QH |
-                               cpu_to_le32(uhci->skelqh[irq]->dma_handle);
+               uhci->frame[i] = uhci_frame_skel_link(uhci, i);
        }
 
        /*
index 108e3de..74469b5 100644 (file)
@@ -83,6 +83,7 @@
 #define UHCI_MAX_SOF_NUMBER    2047    /* in an SOF packet */
 #define CAN_SCHEDULE_FRAMES    1000    /* how far in the future frames
                                         * can be scheduled */
+#define MAX_PHASE              32      /* Periodic scheduling length */
 
 /* When no queues need Full-Speed Bandwidth Reclamation,
  * delay this long before turning FSBR off */
@@ -141,6 +142,8 @@ struct uhci_qh {
        unsigned long advance_jiffies;  /* Time of last queue advance */
        unsigned int unlink_frame;      /* When the QH was unlinked */
        unsigned int period;            /* For Interrupt and Isochronous QHs */
+       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 */
 
@@ -153,6 +156,8 @@ struct uhci_qh {
        unsigned int needs_fixup:1;     /* Must fix the TD toggle values */
        unsigned int is_stopped:1;      /* Queue was stopped by error/unlink */
        unsigned int wait_expired:1;    /* QH_WAIT_TIMEOUT has expired */
+       unsigned int bandwidth_reserved:1;      /* Periodic bandwidth has
+                                                * been allocated */
 } __attribute__((aligned(16)));
 
 /*
@@ -414,6 +419,9 @@ struct uhci_hcd {
 
        wait_queue_head_t waitqh;               /* endpoint_disable waiters */
        int num_waiting;                        /* Number of waiters */
+
+       int total_load;                         /* Sum of array values */
+       short load[MAX_PHASE];                  /* Periodic allocations */
 };
 
 /* Convert between a usb_hcd pointer and the corresponding uhci_hcd */
index 30b8845..2cbb239 100644 (file)
@@ -248,16 +248,26 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
        INIT_LIST_HEAD(&qh->node);
 
        if (udev) {             /* Normal QH */
-               qh->dummy_td = uhci_alloc_td(uhci);
-               if (!qh->dummy_td) {
-                       dma_pool_free(uhci->qh_pool, qh, dma_handle);
-                       return NULL;
+               qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+               if (qh->type != USB_ENDPOINT_XFER_ISOC) {
+                       qh->dummy_td = uhci_alloc_td(uhci);
+                       if (!qh->dummy_td) {
+                               dma_pool_free(uhci->qh_pool, qh, dma_handle);
+                               return NULL;
+                       }
                }
                qh->state = QH_STATE_IDLE;
                qh->hep = hep;
                qh->udev = udev;
                hep->hcpriv = qh;
-               qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+               if (qh->type == USB_ENDPOINT_XFER_INT ||
+                               qh->type == USB_ENDPOINT_XFER_ISOC)
+                       qh->load = usb_calc_bus_time(udev->speed,
+                                       usb_endpoint_dir_in(&hep->desc),
+                                       qh->type == USB_ENDPOINT_XFER_ISOC,
+                                       le16_to_cpu(hep->desc.wMaxPacketSize))
+                               / 1000 + 1;
 
        } else {                /* Skeleton QH */
                qh->state = QH_STATE_ACTIVE;
@@ -275,7 +285,8 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
        list_del(&qh->node);
        if (qh->udev) {
                qh->hep->hcpriv = NULL;
-               uhci_free_td(uhci, qh->dummy_td);
+               if (qh->dummy_td)
+                       uhci_free_td(uhci, qh->dummy_td);
        }
        dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
 }
@@ -327,7 +338,7 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh,
                goto done;
        qh->element = UHCI_PTR_TERM;
 
-       /* Control pipes have to worry about toggles */
+       /* Control pipes don't have to worry about toggles */
        if (qh->type == USB_ENDPOINT_XFER_CONTROL)
                goto done;
 
@@ -493,6 +504,121 @@ static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh)
                wake_up_all(&uhci->waitqh);
 }
 
+/*
+ * Find the highest existing bandwidth load for a given phase and period.
+ */
+static int uhci_highest_load(struct uhci_hcd *uhci, int phase, int period)
+{
+       int highest_load = uhci->load[phase];
+
+       for (phase += period; phase < MAX_PHASE; phase += period)
+               highest_load = max_t(int, highest_load, uhci->load[phase]);
+       return highest_load;
+}
+
+/*
+ * Set qh->phase to the optimal phase for a periodic transfer and
+ * check whether the bandwidth requirement is acceptable.
+ */
+static int uhci_check_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+       int minimax_load;
+
+       /* Find the optimal phase (unless it is already set) and get
+        * its load value. */
+       if (qh->phase >= 0)
+               minimax_load = uhci_highest_load(uhci, qh->phase, qh->period);
+       else {
+               int phase, load;
+               int max_phase = min_t(int, MAX_PHASE, qh->period);
+
+               qh->phase = 0;
+               minimax_load = uhci_highest_load(uhci, qh->phase, qh->period);
+               for (phase = 1; phase < max_phase; ++phase) {
+                       load = uhci_highest_load(uhci, phase, qh->period);
+                       if (load < minimax_load) {
+                               minimax_load = load;
+                               qh->phase = phase;
+                       }
+               }
+       }
+
+       /* Maximum allowable periodic bandwidth is 90%, or 900 us per frame */
+       if (minimax_load + qh->load > 900) {
+               dev_dbg(uhci_dev(uhci), "bandwidth allocation failed: "
+                               "period %d, phase %d, %d + %d us\n",
+                               qh->period, qh->phase, minimax_load, qh->load);
+               return -ENOSPC;
+       }
+       return 0;
+}
+
+/*
+ * Reserve a periodic QH's bandwidth in the schedule
+ */
+static void uhci_reserve_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+       int i;
+       int load = qh->load;
+       char *p = "??";
+
+       for (i = qh->phase; i < MAX_PHASE; i += qh->period) {
+               uhci->load[i] += load;
+               uhci->total_load += load;
+       }
+       uhci_to_hcd(uhci)->self.bandwidth_allocated =
+                       uhci->total_load / MAX_PHASE;
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_INT:
+               ++uhci_to_hcd(uhci)->self.bandwidth_int_reqs;
+               p = "INT";
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               ++uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs;
+               p = "ISO";
+               break;
+       }
+       qh->bandwidth_reserved = 1;
+       dev_dbg(uhci_dev(uhci),
+                       "%s dev %d ep%02x-%s, period %d, phase %d, %d us\n",
+                       "reserve", qh->udev->devnum,
+                       qh->hep->desc.bEndpointAddress, p,
+                       qh->period, qh->phase, load);
+}
+
+/*
+ * Release a periodic QH's bandwidth reservation
+ */
+static void uhci_release_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+       int i;
+       int load = qh->load;
+       char *p = "??";
+
+       for (i = qh->phase; i < MAX_PHASE; i += qh->period) {
+               uhci->load[i] -= load;
+               uhci->total_load -= load;
+       }
+       uhci_to_hcd(uhci)->self.bandwidth_allocated =
+                       uhci->total_load / MAX_PHASE;
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_INT:
+               --uhci_to_hcd(uhci)->self.bandwidth_int_reqs;
+               p = "INT";
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               --uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs;
+               p = "ISO";
+               break;
+       }
+       qh->bandwidth_reserved = 0;
+       dev_dbg(uhci_dev(uhci),
+                       "%s dev %d ep%02x-%s, period %d, phase %d, %d us\n",
+                       "release", qh->udev->devnum,
+                       qh->hep->desc.bEndpointAddress, p,
+                       qh->period, qh->phase, load);
+}
+
 static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci,
                struct urb *urb)
 {
@@ -796,7 +922,6 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
        wmb();
        qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
        qh->dummy_td = td;
-       qh->period = urb->interval;
 
        usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
                        usb_pipeout(urb->pipe), toggle);
@@ -827,28 +952,42 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
 static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
                struct uhci_qh *qh)
 {
-       int exponent;
+       int ret;
 
        /* USB 1.1 interrupt transfers only involve one packet per interval.
         * Drivers can submit URBs of any length, but longer ones will need
         * multiple intervals to complete.
         */
 
-       /* Figure out which power-of-two queue to use */
-       for (exponent = 7; exponent >= 0; --exponent) {
-               if ((1 << exponent) <= urb->interval)
-                       break;
-       }
-       if (exponent < 0)
-               return -EINVAL;
-       urb->interval = 1 << exponent;
+       if (!qh->bandwidth_reserved) {
+               int exponent;
 
-       if (qh->period == 0)
+               /* Figure out which power-of-two queue to use */
+               for (exponent = 7; exponent >= 0; --exponent) {
+                       if ((1 << exponent) <= urb->interval)
+                               break;
+               }
+               if (exponent < 0)
+                       return -EINVAL;
+               qh->period = 1 << exponent;
                qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)];
-       else if (qh->period != urb->interval)
-               return -EINVAL;         /* Can't change the period */
 
-       return uhci_submit_common(uhci, urb, qh);
+               /* For now, interrupt phase is fixed by the layout
+                * of the QH lists. */
+               qh->phase = (qh->period / 2) & (MAX_PHASE - 1);
+               ret = uhci_check_bandwidth(uhci, qh);
+               if (ret)
+                       return ret;
+       } else if (qh->period > urb->interval)
+               return -EINVAL;         /* Can't decrease the period */
+
+       ret = uhci_submit_common(uhci, urb, qh);
+       if (ret == 0) {
+               urb->interval = qh->period;
+               if (!qh->bandwidth_reserved)
+                       uhci_reserve_bandwidth(uhci, qh);
+       }
+       return ret;
 }
 
 /*
@@ -995,15 +1134,32 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
                return -EFBIG;
 
        /* Check the period and figure out the starting frame number */
-       if (qh->period == 0) {
+       if (!qh->bandwidth_reserved) {
+               qh->period = urb->interval;
                if (urb->transfer_flags & URB_ISO_ASAP) {
+                       qh->phase = -1;         /* Find the best phase */
+                       i = uhci_check_bandwidth(uhci, qh);
+                       if (i)
+                               return i;
+
+                       /* Allow a little time to allocate the TDs */
                        uhci_get_current_frame_number(uhci);
-                       urb->start_frame = uhci->frame_number + 10;
+                       frame = uhci->frame_number + 10;
+
+                       /* Move forward to the first frame having the
+                        * correct phase */
+                       urb->start_frame = frame + ((qh->phase - frame) &
+                                       (qh->period - 1));
                } else {
                        i = urb->start_frame - uhci->last_iso_frame;
                        if (i <= 0 || i >= UHCI_NUMFRAMES)
                                return -EINVAL;
+                       qh->phase = urb->start_frame & (qh->period - 1);
+                       i = uhci_check_bandwidth(uhci, qh);
+                       if (i)
+                               return i;
                }
+
        } else if (qh->period != urb->interval) {
                return -EINVAL;         /* Can't change the period */
 
@@ -1049,9 +1205,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
        /* Set the interrupt-on-completion flag on the last packet. */
        td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
 
-       qh->skel = uhci->skel_iso_qh;
-       qh->period = urb->interval;
-
        /* Add the TDs to the frame list */
        frame = urb->start_frame;
        list_for_each_entry(td, &urbp->td_list, list) {
@@ -1065,6 +1218,9 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
                qh->iso_status = 0;
        }
 
+       qh->skel = uhci->skel_iso_qh;
+       if (!qh->bandwidth_reserved)
+               uhci_reserve_bandwidth(uhci, qh);
        return 0;
 }
 
@@ -1119,7 +1275,6 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
        unsigned long flags;
        struct urb_priv *urbp;
        struct uhci_qh *qh;
-       int bustime;
 
        spin_lock_irqsave(&uhci->lock, flags);
 
@@ -1149,35 +1304,11 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
                ret = uhci_submit_bulk(uhci, urb, qh);
                break;
        case USB_ENDPOINT_XFER_INT:
-               if (list_empty(&qh->queue)) {
-                       bustime = usb_check_bandwidth(urb->dev, urb);
-                       if (bustime < 0)
-                               ret = bustime;
-                       else {
-                               ret = uhci_submit_interrupt(uhci, urb, qh);
-                               if (ret == 0)
-                                       usb_claim_bandwidth(urb->dev, urb, bustime, 0);
-                       }
-               } else {        /* inherit from parent */
-                       struct urb_priv *eurbp;
-
-                       eurbp = list_entry(qh->queue.prev, struct urb_priv,
-                                       node);
-                       urb->bandwidth = eurbp->urb->bandwidth;
-                       ret = uhci_submit_interrupt(uhci, urb, qh);
-               }
+               ret = uhci_submit_interrupt(uhci, urb, qh);
                break;
        case USB_ENDPOINT_XFER_ISOC:
                urb->error_count = 0;
-               bustime = usb_check_bandwidth(urb->dev, urb);
-               if (bustime < 0) {
-                       ret = bustime;
-                       break;
-               }
-
                ret = uhci_submit_isochronous(uhci, urb, qh);
-               if (ret == 0)
-                       usb_claim_bandwidth(urb->dev, urb, bustime, 1);
                break;
        }
        if (ret != 0)
@@ -1274,24 +1405,6 @@ __acquires(uhci->lock)
 
        uhci_free_urb_priv(uhci, urbp);
 
-       switch (qh->type) {
-       case USB_ENDPOINT_XFER_ISOC:
-               /* Release bandwidth for Interrupt or Isoc. transfers */
-               if (urb->bandwidth)
-                       usb_release_bandwidth(urb->dev, urb, 1);
-               break;
-       case USB_ENDPOINT_XFER_INT:
-               /* Release bandwidth for Interrupt or Isoc. transfers */
-               /* Make sure we don't release if we have a queued URB */
-               if (list_empty(&qh->queue) && urb->bandwidth)
-                       usb_release_bandwidth(urb->dev, urb, 0);
-               else
-                       /* bandwidth was passed on to queued URB, */
-                       /* so don't let usb_unlink_urb() release it */
-                       urb->bandwidth = 0;
-               break;
-       }
-
        spin_unlock(&uhci->lock);
        usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
        spin_lock(&uhci->lock);
@@ -1300,9 +1413,8 @@ __acquires(uhci->lock)
         * reserved bandwidth. */
        if (list_empty(&qh->queue)) {
                uhci_unlink_qh(uhci, qh);
-
-               /* Bandwidth stuff not yet implemented */
-               qh->period = 0;
+               if (qh->bandwidth_reserved)
+                       uhci_release_bandwidth(uhci, qh);
        }
 }
 
index 63a84bb..d308afd 100644 (file)
@@ -565,11 +565,15 @@ static void mdc800_usb_disconnect (struct usb_interface *intf)
 
                usb_deregister_dev(intf, &mdc800_class);
 
+               /* must be under lock to make sure no URB
+                  is submitted after usb_kill_urb() */
+               mutex_lock(&mdc800->io_lock);
                mdc800->state=NOT_CONNECTED;
 
                usb_kill_urb(mdc800->irq_urb);
                usb_kill_urb(mdc800->write_urb);
                usb_kill_urb(mdc800->download_urb);
+               mutex_unlock(&mdc800->io_lock);
 
                mdc800->dev = NULL;
                usb_set_intfdata(intf, NULL);
index aa6a620..2e71d3c 100644 (file)
@@ -352,3 +352,15 @@ config USB_APPLETOUCH
 
          To compile this driver as a module, choose M here: the
          module will be called appletouch.
+
+config USB_GTCO
+        tristate "GTCO CalComp/InterWrite USB Support"
+        depends on USB && INPUT
+        ---help---
+          Say Y here if you want to use the USB version of the GTCO
+          CalComp/InterWrite Tablet.  Make sure to say Y to "Mouse support"
+          (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+          (CONFIG_INPUT_EVDEV) as well.
+
+          To compile this driver as a module, choose M here: the
+          module will be called gtco.
index a06024e..a9d206c 100644 (file)
@@ -48,6 +48,7 @@ obj-$(CONFIG_USB_ACECAD)      += acecad.o
 obj-$(CONFIG_USB_YEALINK)      += yealink.o
 obj-$(CONFIG_USB_XPAD)         += xpad.o
 obj-$(CONFIG_USB_APPLETOUCH)   += appletouch.o
+obj-$(CONFIG_USB_GTCO)         += gtco.o
 
 ifeq ($(CONFIG_USB_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/usb/input/gtco.c b/drivers/usb/input/gtco.c
new file mode 100644 (file)
index 0000000..203cdc1
--- /dev/null
@@ -0,0 +1,1104 @@
+/*    -*- linux-c -*-
+
+GTCO digitizer USB driver
+
+Use the err(), dbg() and info() macros from usb.h for system logging
+
+TO CHECK:  Is pressure done right on report 5?
+
+Copyright (C) 2006  GTCO CalComp
+
+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; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of GTCO-CalComp not be used in advertising
+or publicity pertaining to distribution of the software without specific,
+written prior permission. GTCO-CalComp makes no representations about the
+suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+
+GTCO-CALCOMP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL GTCO-CALCOMP BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+GTCO CalComp, Inc.
+7125 Riverwood Drive
+Columbia, MD 21046
+
+Jeremy Roberson jroberson@gtcocalcomp.com
+Scott Hill shill@gtcocalcomp.com
+*/
+
+
+
+/*#define DEBUG*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+
+#include <linux/version.h>
+#include <linux/usb/input.h>
+
+/* Version with a Major number of 2 is for kernel inclusion only. */
+#define  GTCO_VERSION   "2.00.0006"
+
+
+/*   MACROS  */
+
+#define VENDOR_ID_GTCO       0x078C
+#define PID_400               0x400
+#define PID_401               0x401
+#define PID_1000              0x1000
+#define PID_1001              0x1001
+#define PID_1002              0x1002
+
+/* Max size of a single report */
+#define REPORT_MAX_SIZE       10
+
+
+/* Bitmask whether pen is in range */
+#define MASK_INRANGE 0x20
+#define MASK_BUTTON  0x01F
+
+#define  PATHLENGTH     64
+
+/* DATA STRUCTURES */
+
+/* Device table */
+static struct usb_device_id gtco_usbid_table [] = {
+       { USB_DEVICE(VENDOR_ID_GTCO, PID_400) },
+       { USB_DEVICE(VENDOR_ID_GTCO, PID_401) },
+       { USB_DEVICE(VENDOR_ID_GTCO, PID_1000) },
+       { USB_DEVICE(VENDOR_ID_GTCO, PID_1001) },
+       { USB_DEVICE(VENDOR_ID_GTCO, PID_1002) },
+       { }
+};
+MODULE_DEVICE_TABLE (usb, gtco_usbid_table);
+
+
+/* Structure to hold all of our device specific stuff */
+struct gtco {
+
+       struct input_dev  *inputdevice; /* input device struct pointer  */
+       struct usb_device *usbdev; /* the usb device for this device */
+       struct urb        *urbinfo;      /* urb for incoming reports      */
+       dma_addr_t        buf_dma;  /* dma addr of the data buffer*/
+       unsigned char *   buffer;   /* databuffer for reports */
+
+       char  usbpath[PATHLENGTH];
+       int   openCount;
+
+       /* Information pulled from Report Descriptor */
+       u32  usage;
+       u32  min_X;
+       u32  max_X;
+       u32  min_Y;
+       u32  max_Y;
+       s8   mintilt_X;
+       s8   maxtilt_X;
+       s8   mintilt_Y;
+       s8   maxtilt_Y;
+       u32  maxpressure;
+       u32  minpressure;
+};
+
+
+
+/*   Code for parsing the HID REPORT DESCRIPTOR          */
+
+/* From HID1.11 spec */
+struct hid_descriptor
+{
+       struct usb_descriptor_header header;
+       __le16   bcdHID;
+       u8       bCountryCode;
+       u8       bNumDescriptors;
+       u8       bDescriptorType;
+       __le16   wDescriptorLength;
+} __attribute__ ((packed));
+
+
+#define HID_DESCRIPTOR_SIZE   9
+#define HID_DEVICE_TYPE       33
+#define REPORT_DEVICE_TYPE    34
+
+
+#define PREF_TAG(x)     ((x)>>4)
+#define PREF_TYPE(x)    ((x>>2)&0x03)
+#define PREF_SIZE(x)    ((x)&0x03)
+
+#define TYPE_MAIN       0
+#define TYPE_GLOBAL     1
+#define TYPE_LOCAL      2
+#define TYPE_RESERVED   3
+
+#define TAG_MAIN_INPUT        0x8
+#define TAG_MAIN_OUTPUT       0x9
+#define TAG_MAIN_FEATURE      0xB
+#define TAG_MAIN_COL_START    0xA
+#define TAG_MAIN_COL_END      0xC
+
+#define TAG_GLOB_USAGE        0
+#define TAG_GLOB_LOG_MIN      1
+#define TAG_GLOB_LOG_MAX      2
+#define TAG_GLOB_PHYS_MIN     3
+#define TAG_GLOB_PHYS_MAX     4
+#define TAG_GLOB_UNIT_EXP     5
+#define TAG_GLOB_UNIT         6
+#define TAG_GLOB_REPORT_SZ    7
+#define TAG_GLOB_REPORT_ID    8
+#define TAG_GLOB_REPORT_CNT   9
+#define TAG_GLOB_PUSH         10
+#define TAG_GLOB_POP          11
+
+#define TAG_GLOB_MAX          12
+
+#define DIGITIZER_USAGE_TIP_PRESSURE   0x30
+#define DIGITIZER_USAGE_TILT_X         0x3D
+#define DIGITIZER_USAGE_TILT_Y         0x3E
+
+
+/*
+ *
+ *   This is an abbreviated parser for the HID Report Descriptor.  We
+ *   know what devices we are talking to, so this is by no means meant
+ *   to be generic.  We can make some safe assumptions:
+ *
+ *   - We know there are no LONG tags, all short
+ *   - We know that we have no MAIN Feature and MAIN Output items
+ *   - We know what the IRQ reports are supposed to look like.
+ *
+ *   The main purpose of this is to use the HID report desc to figure
+ *   out the mins and maxs of the fields in the IRQ reports.  The IRQ
+ *   reports for 400/401 change slightly if the max X is bigger than 64K.
+ *
+ */
+static void parse_hid_report_descriptor(struct gtco *device, char * report,
+                                       int length)
+{
+       int   x,i=0;
+
+       /* Tag primitive vars */
+       __u8   prefix;
+       __u8   size;
+       __u8   tag;
+       __u8   type;
+       __u8   data   = 0;
+       __u16  data16 = 0;
+       __u32  data32 = 0;
+
+
+       /* For parsing logic */
+       int   inputnum = 0;
+       __u32 usage = 0;
+
+       /* Global Values, indexed by TAG */
+       __u32 globalval[TAG_GLOB_MAX];
+       __u32 oldval[TAG_GLOB_MAX];
+
+       /* Debug stuff */
+       char  maintype='x';
+       char  globtype[12];
+       int   indent=0;
+       char  indentstr[10]="";
+
+
+
+       dbg("======>>>>>>PARSE<<<<<<======");
+
+       /* Walk  this report and pull out the info we need */
+       while (i<length){
+               prefix=report[i];
+
+               /* Skip over prefix */
+               i++;
+
+               /* Determine data size and save the data in the proper variable */
+               size = PREF_SIZE(prefix);
+               switch(size){
+               case 1:
+                       data = report[i];
+                       break;
+               case 2:
+                       data16 = le16_to_cpu(get_unaligned((__le16*)(&(report[i]))));
+                       break;
+               case 3:
+                       size = 4;
+                       data32 = le32_to_cpu(get_unaligned((__le32*)(&(report[i]))));
+               }
+
+               /* Skip size of data */
+               i+=size;
+
+               /* What we do depends on the tag type */
+               tag  = PREF_TAG(prefix);
+               type = PREF_TYPE(prefix);
+               switch(type){
+               case TYPE_MAIN:
+                       strcpy(globtype,"");
+                       switch(tag){
+
+                       case TAG_MAIN_INPUT:
+                               /*
+                                * The INPUT MAIN tag signifies this is
+                                * information from a report.  We need to
+                                * figure out what it is and store the
+                                * min/max values
+                                */
+
+                               maintype='I';
+                               if (data==2){
+                                       strcpy(globtype,"Variable");
+                               }
+                               if (data==3){
+                                       strcpy(globtype,"Var|Const");
+                               }
+
+                               dbg("::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits",
+                                   globalval[TAG_GLOB_REPORT_ID],inputnum,
+                                   globalval[TAG_GLOB_LOG_MAX],globalval[TAG_GLOB_LOG_MAX],
+                                   globalval[TAG_GLOB_LOG_MIN],globalval[TAG_GLOB_LOG_MIN],
+                                   (globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]));
+
+
+                               /*
+                                 We can assume that the first two input items
+                                 are always the X and Y coordinates.  After
+                                 that, we look for everything else by
+                                 local usage value
+                                */
+                               switch (inputnum){
+                               case 0:  /* X coord */
+                                       dbg("GER: X Usage: 0x%x",usage);
+                                       if (device->max_X == 0){
+                                               device->max_X = globalval[TAG_GLOB_LOG_MAX];
+                                               device->min_X = globalval[TAG_GLOB_LOG_MIN];
+                                       }
+
+                                       break;
+                               case 1:  /* Y coord */
+                                       dbg("GER: Y Usage: 0x%x",usage);
+                                       if (device->max_Y == 0){
+                                               device->max_Y = globalval[TAG_GLOB_LOG_MAX];
+                                               device->min_Y = globalval[TAG_GLOB_LOG_MIN];
+                                       }
+                                       break;
+                               default:
+                                       /* Tilt X */
+                                       if (usage == DIGITIZER_USAGE_TILT_X){
+                                               if (device->maxtilt_X == 0){
+                                                       device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX];
+                                                       device->mintilt_X = globalval[TAG_GLOB_LOG_MIN];
+                                               }
+                                       }
+
+                                       /* Tilt Y */
+                                       if (usage == DIGITIZER_USAGE_TILT_Y){
+                                               if (device->maxtilt_Y == 0){
+                                                       device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX];
+                                                       device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN];
+                                               }
+                                       }
+
+
+                                       /* Pressure */
+                                       if (usage == DIGITIZER_USAGE_TIP_PRESSURE){
+                                               if (device->maxpressure == 0){
+                                                       device->maxpressure = globalval[TAG_GLOB_LOG_MAX];
+                                                       device->minpressure = globalval[TAG_GLOB_LOG_MIN];
+                                               }
+                                       }
+
+                                       break;
+                               }
+
+                               inputnum++;
+
+
+                               break;
+                       case TAG_MAIN_OUTPUT:
+                               maintype='O';
+                               break;
+                       case TAG_MAIN_FEATURE:
+                               maintype='F';
+                               break;
+                       case TAG_MAIN_COL_START:
+                               maintype='S';
+
+                               if (data==0){
+                                       dbg("======>>>>>> Physical");
+                                       strcpy(globtype,"Physical");
+                               }else{
+                                       dbg("======>>>>>>");
+                               }
+
+                               /* Indent the debug output */
+                               indent++;
+                               for (x=0;x<indent;x++){
+                                       indentstr[x]='-';
+                               }
+                               indentstr[x]=0;
+
+                               /* Save global tags */
+                               for (x=0;x<TAG_GLOB_MAX;x++){
+                                       oldval[x] = globalval[x];
+                               }
+
+                               break;
+                       case TAG_MAIN_COL_END:
+                               dbg("<<<<<<======");
+                               maintype='E';
+                               indent--;
+                               for (x=0;x<indent;x++){
+                                       indentstr[x]='-';
+                               }
+                               indentstr[x]=0;
+
+                               /* Copy global tags back */
+                               for (x=0;x<TAG_GLOB_MAX;x++){
+                                       globalval[x] = oldval[x];
+                               }
+
+                               break;
+                       }
+
+                       switch (size){
+                       case 1:
+                               dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+                                   indentstr,tag,maintype,size,globtype,data);
+                               break;
+                       case 2:
+                               dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+                                   indentstr,tag,maintype,size,globtype, data16);
+                               break;
+                       case 4:
+                               dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+                                   indentstr,tag,maintype,size,globtype,data32);
+                               break;
+                       }
+                       break;
+               case TYPE_GLOBAL:
+                       switch(tag){
+                       case TAG_GLOB_USAGE:
+                               /*
+                                * First time we hit the global usage tag,
+                                * it should tell us the type of device
+                                */
+                               if (device->usage == 0){
+                                       device->usage = data;
+                               }
+                               strcpy(globtype,"USAGE");
+                               break;
+                       case TAG_GLOB_LOG_MIN   :
+                               strcpy(globtype,"LOG_MIN");
+                               break;
+                       case TAG_GLOB_LOG_MAX   :
+                               strcpy(globtype,"LOG_MAX");
+                               break;
+                       case TAG_GLOB_PHYS_MIN  :
+                               strcpy(globtype,"PHYS_MIN");
+                               break;
+                       case TAG_GLOB_PHYS_MAX  :
+                               strcpy(globtype,"PHYS_MAX");
+                               break;
+                       case TAG_GLOB_UNIT_EXP  :
+                               strcpy(globtype,"EXP");
+                               break;
+                       case TAG_GLOB_UNIT      :
+                               strcpy(globtype,"UNIT");
+                               break;
+                       case TAG_GLOB_REPORT_SZ :
+                               strcpy(globtype,"REPORT_SZ");
+                               break;
+                       case TAG_GLOB_REPORT_ID :
+                               strcpy(globtype,"REPORT_ID");
+                               /* New report, restart numbering */
+                               inputnum=0;
+                               break;
+                       case TAG_GLOB_REPORT_CNT:
+                               strcpy(globtype,"REPORT_CNT");
+                               break;
+                       case TAG_GLOB_PUSH :
+                               strcpy(globtype,"PUSH");
+                               break;
+                       case TAG_GLOB_POP:
+                               strcpy(globtype,"POP");
+                               break;
+                       }
+
+
+                       /* Check to make sure we have a good tag number
+                          so we don't overflow array */
+                       if (tag < TAG_GLOB_MAX){
+                               switch (size){
+                               case 1:
+                                       dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data);
+                                       globalval[tag]=data;
+                                       break;
+                               case 2:
+                                       dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data16);
+                                       globalval[tag]=data16;
+                                       break;
+                               case 4:
+                                       dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data32);
+                                       globalval[tag]=data32;
+                                       break;
+                               }
+                       }else{
+                               dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ",
+                                   indentstr,tag,size);
+                       }
+
+
+                       break;
+
+               case TYPE_LOCAL:
+                       switch(tag){
+                       case TAG_GLOB_USAGE:
+                               strcpy(globtype,"USAGE");
+                               /* Always 1 byte */
+                               usage = data;
+                               break;
+                       case TAG_GLOB_LOG_MIN   :
+                               strcpy(globtype,"MIN");
+                               break;
+                       case TAG_GLOB_LOG_MAX   :
+                               strcpy(globtype,"MAX");
+                               break;
+                       default:
+                               strcpy(globtype,"UNKNOWN");
+                       }
+
+                       switch (size){
+                       case 1:
+                               dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+                                   indentstr,tag,globtype,size,data);
+                               break;
+                       case 2:
+                               dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+                                   indentstr,tag,globtype,size,data16);
+                               break;
+                       case 4:
+                               dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+                                   indentstr,tag,globtype,size,data32);
+                               break;
+                       }
+
+                       break;
+               }
+
+       }
+
+}
+
+
+
+/*   INPUT DRIVER Routines                               */
+
+
+/*
+ *    Called when opening the input device.  This will submit the URB to
+ *    the usb system so we start getting reports
+ */
+static int gtco_input_open(struct input_dev *inputdev)
+{
+       struct gtco *device;
+       device = inputdev->private;
+
+       device->urbinfo->dev = device->usbdev;
+       if (usb_submit_urb(device->urbinfo, GFP_KERNEL)) {
+               return -EIO;
+       }
+       return 0;
+}
+
+/**
+    Called when closing the input device.  This will unlink the URB
+*/
+static void gtco_input_close(struct input_dev *inputdev)
+{
+       struct gtco *device = inputdev->private;
+
+       usb_kill_urb(device->urbinfo);
+
+}
+
+
+/*
+ *  Setup input device capabilities.  Tell the input system what this
+ *  device is capable of generating.
+ *
+ *  This information is based on what is read from the HID report and
+ *  placed in the struct gtco structure
+ *
+ */
+static void  gtco_setup_caps(struct input_dev  *inputdev)
+{
+       struct gtco *device = inputdev->private;
+
+
+       /* Which events */
+       inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
+
+
+       /* Misc event menu block */
+       inputdev->mscbit[0] = BIT(MSC_SCAN)|BIT(MSC_SERIAL)|BIT(MSC_RAW) ;
+
+
+       /* Absolute values based on HID report info */
+       input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X,
+                            0, 0);
+       input_set_abs_params(inputdev, ABS_Y, device->min_Y, device->max_Y,
+                            0, 0);
+
+       /* Proximity */
+       input_set_abs_params(inputdev, ABS_DISTANCE, 0, 1, 0, 0);
+
+       /* Tilt & pressure */
+       input_set_abs_params(inputdev, ABS_TILT_X, device->mintilt_X,
+                            device->maxtilt_X, 0, 0);
+       input_set_abs_params(inputdev, ABS_TILT_Y, device->mintilt_Y,
+                            device->maxtilt_Y, 0, 0);
+       input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure,
+                            device->maxpressure, 0, 0);
+
+
+       /* Transducer */
+       input_set_abs_params(inputdev, ABS_MISC, 0,0xFF, 0, 0);
+
+}
+
+
+
+/*   USB Routines  */
+
+
+/*
+ * URB callback routine.  Called when we get IRQ reports from the
+ *  digitizer.
+ *
+ *  This bridges the USB and input device worlds.  It generates events
+ *  on the input device based on the USB reports.
+ */
+static void gtco_urb_callback(struct urb *urbinfo)
+{
+
+
+       struct gtco     *device = urbinfo->context;
+       struct input_dev  *inputdev;
+       int               rc;
+       u32               val = 0;
+       s8                valsigned = 0;
+       char              le_buffer[2];
+
+       inputdev = device->inputdevice;
+
+
+       /* Was callback OK? */
+       if ((urbinfo->status == -ECONNRESET ) ||
+           (urbinfo->status == -ENOENT ) ||
+           (urbinfo->status == -ESHUTDOWN )){
+
+               /* Shutdown is occurring. Return and don't queue up any more */
+               return;
+       }
+
+       if (urbinfo->status != 0 ) {
+               /* Some unknown error.  Hopefully temporary.  Just go and */
+               /* requeue an URB */
+               goto resubmit;
+       }
+
+       /*
+        * Good URB, now process
+        */
+
+       /* PID dependent when we interpret the report */
+       if ((inputdev->id.product == PID_1000 )||
+           (inputdev->id.product == PID_1001 )||
+           (inputdev->id.product == PID_1002 ))
+       {
+
+               /*
+                * Switch on the report ID
+                * Conveniently, the reports have more information, the higher
+                * the report number.  We can just fall through the case
+                * statements if we start with the highest number report
+                */
+               switch(device->buffer[0]){
+               case 5:
+                       /* Pressure is 9 bits */
+                       val =  ((u16)(device->buffer[8]) << 1);
+                       val |= (u16)(device->buffer[7] >> 7);
+                       input_report_abs(inputdev, ABS_PRESSURE,
+                                        device->buffer[8]);
+
+                       /* Mask out the Y tilt value used for pressure */
+                       device->buffer[7] = (u8)((device->buffer[7]) & 0x7F);
+
+
+                       /* Fall thru */
+               case 4:
+                       /* Tilt */
+
+                       /* Sign extend these 7 bit numbers.  */
+                       if (device->buffer[6] & 0x40)
+                               device->buffer[6] |= 0x80;
+
+                       if (device->buffer[7] & 0x40)
+                               device->buffer[7] |= 0x80;
+
+
+                       valsigned = (device->buffer[6]);
+                       input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned);
+
+                       valsigned = (device->buffer[7]);
+                       input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned);
+
+                       /* Fall thru */
+
+               case 2:
+               case 3:
+                       /* Convert buttons, only 5 bits possible */
+                       val = (device->buffer[5])&MASK_BUTTON;
+
+                       /* We don't apply any meaning to the bitmask,
+                          just report */
+                       input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+
+                       /*  Fall thru */
+               case 1:
+
+                       /* All reports have X and Y coords in the same place */
+                       val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[1])));
+                       input_report_abs(inputdev, ABS_X, val);
+
+                       val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[3])));
+                       input_report_abs(inputdev, ABS_Y, val);
+
+
+                       /* Ditto for proximity bit */
+                       if (device->buffer[5]& MASK_INRANGE){
+                               val = 1;
+                       }else{
+                               val=0;
+                       }
+                       input_report_abs(inputdev, ABS_DISTANCE, val);
+
+
+                       /* Report 1 is an exception to how we handle buttons */
+                       /* Buttons are an index, not a bitmask */
+                       if (device->buffer[0] == 1){
+
+                               /* Convert buttons, 5 bit index */
+                               /* Report value of index set as one,
+                                  the rest as 0 */
+                               val = device->buffer[5]& MASK_BUTTON;
+                               dbg("======>>>>>>REPORT 1: val 0x%X(%d)",
+                                   val,val);
+
+                               /*
+                                * We don't apply any meaning to the button
+                                * index, just report it
+                                */
+                               input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+
+
+                       }
+
+                       break;
+               case 7:
+                       /* Menu blocks */
+                       input_event(inputdev, EV_MSC, MSC_SCAN,
+                                   device->buffer[1]);
+
+
+                       break;
+
+               }
+
+
+       }
+       /* Other pid class */
+       if ((inputdev->id.product == PID_400 )||
+           (inputdev->id.product == PID_401 ))
+       {
+
+               /* Report 2 */
+               if (device->buffer[0] == 2){
+                       /* Menu blocks */
+                       input_event(inputdev, EV_MSC, MSC_SCAN,
+                                   device->buffer[1]);
+               }
+
+               /*  Report 1 */
+               if (device->buffer[0] == 1){
+                       char buttonbyte;
+
+
+                       /*  IF X max > 64K, we still a bit from the y report */
+                       if (device->max_X > 0x10000){
+
+                               val = (u16)(((u16)(device->buffer[2]<<8))|((u8)(device->buffer[1])));
+                               val |= (u32)(((u8)device->buffer[3]&0x1)<< 16);
+
+                               input_report_abs(inputdev, ABS_X, val);
+
+                               le_buffer[0]  = (u8)((u8)(device->buffer[3])>>1);
+                               le_buffer[0] |= (u8)((device->buffer[3]&0x1)<<7);
+
+                               le_buffer[1]  = (u8)(device->buffer[4]>>1);
+                               le_buffer[1] |= (u8)((device->buffer[5]&0x1)<<7);
+
+                               val = le16_to_cpu(get_unaligned((__le16 *)(le_buffer)));
+
+                               input_report_abs(inputdev, ABS_Y, val);
+
+
+                               /*
+                                * Shift the button byte right by one to
+                                * make it look like the standard report
+                                */
+                               buttonbyte = (device->buffer[5])>>1;
+                       }else{
+
+                               val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[1]))));
+                               input_report_abs(inputdev, ABS_X, val);
+
+                               val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[3]))));
+                               input_report_abs(inputdev, ABS_Y, val);
+
+                               buttonbyte = device->buffer[5];
+
+                       }
+
+
+                       /* BUTTONS and PROXIMITY */
+                       if (buttonbyte& MASK_INRANGE){
+                               val = 1;
+                       }else{
+                               val=0;
+                       }
+                       input_report_abs(inputdev, ABS_DISTANCE, val);
+
+                       /* Convert buttons, only 4 bits possible */
+                       val = buttonbyte&0x0F;
+#ifdef USE_BUTTONS
+                       for ( i=0;i<5;i++){
+                               input_report_key(inputdev, BTN_DIGI+i,val&(1<<i));
+                       }
+#else
+                       /* We don't apply any meaning to the bitmask, just report */
+                       input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+#endif
+                       /* TRANSDUCER */
+                       input_report_abs(inputdev, ABS_MISC, device->buffer[6]);
+
+               }
+       }
+
+       /* Everybody gets report ID's */
+       input_event(inputdev, EV_MSC, MSC_RAW,  device->buffer[0]);
+
+       /* Sync it up */
+       input_sync(inputdev);
+
+ resubmit:
+       rc = usb_submit_urb(urbinfo, GFP_ATOMIC);
+       if (rc != 0) {
+               err("usb_submit_urb failed rc=0x%x",rc);
+       }
+
+}
+
+/*
+ *  The probe routine.  This is called when the kernel find the matching USB
+ *   vendor/product.  We do the following:
+ *
+ *    - Allocate mem for a local structure to manage the device
+ *    - Request a HID Report Descriptor from the device and parse it to
+ *      find out the device parameters
+ *    - Create an input device and assign it attributes
+ *   - Allocate an URB so the device can talk to us when the input
+ *      queue is open
+ */
+static int gtco_probe(struct usb_interface *usbinterface,
+                     const struct usb_device_id *id)
+{
+
+       struct gtco             *device = NULL;
+       char                    path[PATHLENGTH];
+       struct input_dev        *inputdev;
+       struct hid_descriptor   *hid_desc;
+       char                    *report;
+       int                     result=0, retry;
+       struct usb_endpoint_descriptor *endpoint;
+
+       /* Allocate memory for device structure */
+       device = kzalloc(sizeof(struct gtco), GFP_KERNEL);
+       if (device == NULL) {
+               err("No more memory");
+               return -ENOMEM;
+       }
+
+
+       device->inputdevice = input_allocate_device();
+       if (!device->inputdevice){
+               kfree(device);
+               err("No more memory");
+               return -ENOMEM;
+       }
+
+       /* Get pointer to the input device */
+       inputdev = device->inputdevice;
+
+       /* Save interface information */
+       device->usbdev     = usb_get_dev(interface_to_usbdev(usbinterface));
+
+
+       /* Allocate some data for incoming reports */
+       device->buffer = usb_buffer_alloc(device->usbdev, REPORT_MAX_SIZE,
+                                          GFP_KERNEL, &(device->buf_dma));
+       if (!device->buffer){
+               input_free_device(device->inputdevice);
+               kfree(device);
+               err("No more memory");
+               return -ENOMEM;
+       }
+
+       /* Allocate URB for reports */
+       device->urbinfo = usb_alloc_urb(0, GFP_KERNEL);
+       if (!device->urbinfo) {
+               usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+                               device->buffer, device->buf_dma);
+               input_free_device(device->inputdevice);
+               kfree(device);
+               err("No more memory");
+               return -ENOMEM;
+       }
+
+
+       /*
+        * The endpoint is always altsetting 0, we know this since we know
+        * this device only has one interrupt endpoint
+        */
+       endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+       /* Some debug */
+       dbg("gtco # interfaces: %d",usbinterface->num_altsetting);
+       dbg("num endpoints:     %d",usbinterface->cur_altsetting->desc.bNumEndpoints);
+       dbg("interface class:   %d",usbinterface->cur_altsetting->desc.bInterfaceClass);
+       dbg("endpoint: attribute:0x%x type:0x%x",endpoint->bmAttributes,endpoint->bDescriptorType);
+       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
+               dbg("endpoint: we have interrupt endpoint\n");
+
+       dbg("endpoint extra len:%d ",usbinterface->altsetting[0].extralen);
+
+
+
+       /*
+        * Find the HID descriptor so we can find out the size of the
+        * HID report descriptor
+        */
+       if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
+                                    HID_DEVICE_TYPE,&hid_desc) != 0){
+               err("Can't retrieve exta USB descriptor to get hid report descriptor length");
+               usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+                               device->buffer, device->buf_dma);
+               input_free_device(device->inputdevice);
+               kfree(device);
+               return -EIO;
+       }
+
+       dbg("Extra descriptor success: type:%d  len:%d",
+           hid_desc->bDescriptorType,  hid_desc->wDescriptorLength);
+
+       if (!(report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL))) {
+               usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+                               device->buffer, device->buf_dma);
+
+               input_free_device(device->inputdevice);
+               kfree(device);
+               err("No more memory");
+               return -ENOMEM;
+       }
+
+       /* Couple of tries to get reply */
+       for (retry=0;retry<3;retry++) {
+               result = usb_control_msg(device->usbdev,
+                                        usb_rcvctrlpipe(device->usbdev, 0),
+                                        USB_REQ_GET_DESCRIPTOR,
+                                        USB_RECIP_INTERFACE | USB_DIR_IN,
+                                        (REPORT_DEVICE_TYPE << 8),
+                                        0, /* interface */
+                                        report,
+                                        hid_desc->wDescriptorLength,
+                                        5000); /* 5 secs */
+
+               if (result == hid_desc->wDescriptorLength)
+                       break;
+       }
+
+       /* If we didn't get the report, fail */
+       dbg("usb_control_msg result: :%d", result);
+       if (result != hid_desc->wDescriptorLength){
+               kfree(report);
+               usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+                               device->buffer, device->buf_dma);
+               input_free_device(device->inputdevice);
+               kfree(device);
+               err("Failed to get HID Report Descriptor of size: %d",
+                   hid_desc->wDescriptorLength);
+               return -EIO;
+       }
+
+
+       /* Now we parse the report */
+       parse_hid_report_descriptor(device,report,result);
+
+       /* Now we delete it */
+       kfree(report);
+
+       /* Create a device file node */
+       usb_make_path(device->usbdev, path, PATHLENGTH);
+       sprintf(device->usbpath, "%s/input0", path);
+
+
+       /* Set Input device functions */
+       inputdev->open     = gtco_input_open;
+       inputdev->close    = gtco_input_close;
+
+       /* Set input device information */
+       inputdev->name     = "GTCO_CalComp";
+       inputdev->phys     = device->usbpath;
+       inputdev->private  = device;
+
+
+       /* Now set up all the input device capabilities */
+       gtco_setup_caps(inputdev);
+
+       /* Set input device required ID information */
+       usb_to_input_id(device->usbdev, &device->inputdevice->id);
+       inputdev->cdev.dev = &usbinterface->dev;
+
+       /* Setup the URB, it will be posted later on open of input device */
+       endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+       usb_fill_int_urb(device->urbinfo,
+                        device->usbdev,
+                        usb_rcvintpipe(device->usbdev,
+                                       endpoint->bEndpointAddress),
+                        device->buffer,
+                        REPORT_MAX_SIZE,
+                        gtco_urb_callback,
+                        device,
+                        endpoint->bInterval);
+
+       device->urbinfo->transfer_dma = device->buf_dma;
+       device->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+
+       /* Save device pointer in USB interface device */
+       usb_set_intfdata(usbinterface, device);
+
+       /* All done, now register the input device */
+       input_register_device(inputdev);
+
+       info( "gtco driver created usb:  %s\n",  path);
+       return 0;
+
+}
+
+/*
+ *  This function is a standard USB function called when the USB device
+ *  is disconnected.  We will get rid of the URV, de-register the input
+ *  device, and free up allocated memory
+ */
+static void gtco_disconnect(struct usb_interface *interface)
+{
+
+       /* Grab private device ptr */
+       struct gtco    *device = usb_get_intfdata (interface);
+       struct input_dev *inputdev;
+
+       inputdev = device->inputdevice;
+
+       /* Now reverse all the registration stuff */
+       if (device) {
+               input_unregister_device(inputdev);
+               usb_kill_urb(device->urbinfo);
+               usb_free_urb(device->urbinfo);
+               usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+                               device->buffer, device->buf_dma);
+               kfree(device);
+       }
+
+       info("gtco driver disconnected");
+}
+
+
+/*   STANDARD MODULE LOAD ROUTINES  */
+
+static struct usb_driver gtco_driverinfo_table = {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
+       .owner      = THIS_MODULE,
+#endif
+       .name       = "gtco",
+       .id_table   = gtco_usbid_table,
+       .probe      = gtco_probe,
+       .disconnect = gtco_disconnect,
+};
+/*
+ *  Register this module with the USB subsystem
+ */
+static int __init gtco_init(void)
+{
+       int rc;
+       rc = usb_register(&gtco_driverinfo_table);
+       if (rc) {
+               err("usb_register() failed rc=0x%x", rc);
+       }
+       printk("GTCO usb driver version: %s",GTCO_VERSION);
+       return rc;
+}
+
+/*
+ *   Deregister this module with the USB subsystem
+ */
+static void __exit gtco_exit(void)
+{
+       usb_deregister(&gtco_driverinfo_table);
+}
+
+module_init (gtco_init);
+module_exit (gtco_exit);
+
+MODULE_LICENSE("GPL");
index e07a304..84983d1 100644 (file)
@@ -768,6 +768,9 @@ void usbhid_init_reports(struct hid_device *hid)
 #define USB_VENDOR_ID_PANTHERLORD      0x0810
 #define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK    0x0001
 
+#define USB_VENDOR_ID_SONY                     0x054c
+#define USB_DEVICE_ID_SONY_PS3_CONTROLLER      0x0268
+
 /*
  * Alphabetically sorted blacklist by quirk type.
  */
@@ -949,6 +952,8 @@ static const struct hid_blacklist {
 
        { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
 
+       { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER },
+
        { 0, 0 }
 };
 
@@ -1013,6 +1018,32 @@ static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize)
        }
 }
 
+/*
+ * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
+ * to "operational".  Without this, the ps3 controller will not report any
+ * events.
+ */
+static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
+{
+       int result;
+       char *buf = kmalloc(18, GFP_KERNEL);
+
+       if (!buf)
+               return;
+
+       result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                                HID_REQ_GET_REPORT,
+                                USB_DIR_IN | USB_TYPE_CLASS |
+                                USB_RECIP_INTERFACE,
+                                (3 << 8) | 0xf2, ifnum, buf, 17,
+                                USB_CTRL_GET_TIMEOUT);
+
+       if (result < 0)
+               err("%s failed: %d\n", __func__, result);
+
+       kfree(buf);
+}
+
 static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 {
        struct usb_host_interface *interface = intf->cur_altsetting;
@@ -1303,6 +1334,10 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
        if ((hid->claimed & HID_CLAIMED_INPUT))
                hid_ff_init(hid);
 
+       if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
+               hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
+                       intf->cur_altsetting->desc.bInterfaceNumber);
+
        printk(KERN_INFO);
 
        if (hid->claimed & HID_CLAIMED_INPUT)
index c941853..15c70bd 100644 (file)
@@ -269,7 +269,7 @@ static int idmouse_release(struct inode *inode, struct file *file)
        /* prevent a race condition with open() */
        mutex_lock(&disconnect_mutex);
 
-       dev = (struct usb_idmouse *) file->private_data;
+       dev = file->private_data;
 
        if (dev == NULL) {
                mutex_unlock(&disconnect_mutex);
@@ -304,17 +304,15 @@ static int idmouse_release(struct inode *inode, struct file *file)
 static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count,
                                loff_t * ppos)
 {
-       struct usb_idmouse *dev;
+       struct usb_idmouse *dev = file->private_data;
        int result;
 
-       dev = (struct usb_idmouse *) file->private_data;
-
        /* lock this object */
-       down (&dev->sem);
+       down(&dev->sem);
 
        /* verify that the device wasn't unplugged */
        if (!dev->present) {
-               up (&dev->sem);
+               up(&dev->sem);
                return -ENODEV;
        }
 
index 384fa37..fdf6847 100644 (file)
@@ -69,7 +69,7 @@ struct rio_usb_data {
         char *obuf, *ibuf;              /* transfer buffers */
         char bulk_in_ep, bulk_out_ep;   /* Endpoint assignments */
         wait_queue_head_t wait_q;       /* for timeouts */
-       struct semaphore lock;          /* general race avoidance */
+       struct mutex lock;          /* general race avoidance */
 };
 
 static struct rio_usb_data rio_instance;
@@ -78,17 +78,17 @@ static int open_rio(struct inode *inode, struct file *file)
 {
        struct rio_usb_data *rio = &rio_instance;
 
-       down(&(rio->lock));
+       mutex_lock(&(rio->lock));
 
        if (rio->isopen || !rio->present) {
-               up(&(rio->lock));
+               mutex_unlock(&(rio->lock));
                return -EBUSY;
        }
        rio->isopen = 1;
 
        init_waitqueue_head(&rio->wait_q);
 
-       up(&(rio->lock));
+       mutex_unlock(&(rio->lock));
 
        info("Rio opened.");
 
@@ -117,7 +117,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
        int retries;
        int retval=0;
 
-       down(&(rio->lock));
+       mutex_lock(&(rio->lock));
         /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
              rio->present == 0 ||
@@ -257,7 +257,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
 
 
 err_out:
-       up(&(rio->lock));
+       mutex_unlock(&(rio->lock));
        return retval;
 }
 
@@ -275,14 +275,17 @@ write_rio(struct file *file, const char __user *buffer,
        int result = 0;
        int maxretry;
        int errn = 0;
+       int intr;
 
-       down(&(rio->lock));
+       intr = mutex_lock_interruptible(&(rio->lock));
+       if (intr)
+               return -EINTR;
         /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
              rio->present == 0 ||
              rio->rio_dev == NULL )
        {
-               up(&(rio->lock));
+               mutex_unlock(&(rio->lock));
                return -ENODEV;
        }
 
@@ -305,7 +308,7 @@ write_rio(struct file *file, const char __user *buffer,
                                goto error;
                        }
                        if (signal_pending(current)) {
-                               up(&(rio->lock));
+                               mutex_unlock(&(rio->lock));
                                return bytes_written ? bytes_written : -EINTR;
                        }
 
@@ -341,12 +344,12 @@ write_rio(struct file *file, const char __user *buffer,
                buffer += copy_size;
        } while (count > 0);
 
-       up(&(rio->lock));
+       mutex_unlock(&(rio->lock));
 
        return bytes_written ? bytes_written : -EIO;
 
 error:
-       up(&(rio->lock));
+       mutex_unlock(&(rio->lock));
        return errn;
 }
 
@@ -361,14 +364,17 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
        int result;
        int maxretry = 10;
        char *ibuf;
+       int intr;
 
-       down(&(rio->lock));
+       intr = mutex_lock_interruptible(&(rio->lock));
+       if (intr)
+               return -EINTR;
        /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
              rio->present == 0 ||
              rio->rio_dev == NULL )
        {
-               up(&(rio->lock));
+               mutex_unlock(&(rio->lock));
                return -ENODEV;
        }
 
@@ -379,11 +385,11 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
 
        while (count > 0) {
                if (signal_pending(current)) {
-                       up(&(rio->lock));
+                       mutex_unlock(&(rio->lock));
                        return read_count ? read_count : -EINTR;
                }
                if (!rio->rio_dev) {
-                       up(&(rio->lock));
+                       mutex_unlock(&(rio->lock));
                        return -ENODEV;
                }
                this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
@@ -400,7 +406,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
                        count = this_read = partial;
                } else if (result == -ETIMEDOUT || result == 15) {      /* FIXME: 15 ??? */
                        if (!maxretry--) {
-                               up(&(rio->lock));
+                               mutex_unlock(&(rio->lock));
                                err("read_rio: maxretry timeout");
                                return -ETIME;
                        }
@@ -409,18 +415,18 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
                        finish_wait(&rio->wait_q, &wait);
                        continue;
                } else if (result != -EREMOTEIO) {
-                       up(&(rio->lock));
+                       mutex_unlock(&(rio->lock));
                        err("Read Whoops - result:%u partial:%u this_read:%u",
                             result, partial, this_read);
                        return -EIO;
                } else {
-                       up(&(rio->lock));
+                       mutex_unlock(&(rio->lock));
                        return (0);
                }
 
                if (this_read) {
                        if (copy_to_user(buffer, ibuf, this_read)) {
-                               up(&(rio->lock));
+                               mutex_unlock(&(rio->lock));
                                return -EFAULT;
                        }
                        count -= this_read;
@@ -428,7 +434,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
                        buffer += this_read;
                }
        }
-       up(&(rio->lock));
+       mutex_unlock(&(rio->lock));
        return read_count;
 }
 
@@ -480,7 +486,7 @@ static int probe_rio(struct usb_interface *intf,
        }
        dbg("probe_rio: ibuf address:%p", rio->ibuf);
 
-       init_MUTEX(&(rio->lock));
+       mutex_init(&(rio->lock));
 
        usb_set_intfdata (intf, rio);
        rio->present = 1;
@@ -496,12 +502,12 @@ static void disconnect_rio(struct usb_interface *intf)
        if (rio) {
                usb_deregister_dev(intf, &usb_rio_class);
 
-               down(&(rio->lock));
+               mutex_lock(&(rio->lock));
                if (rio->isopen) {
                        rio->isopen = 0;
                        /* better let it finish - the release will do whats needed */
                        rio->rio_dev = NULL;
-                       up(&(rio->lock));
+                       mutex_unlock(&(rio->lock));
                        return;
                }
                kfree(rio->ibuf);
@@ -510,7 +516,7 @@ static void disconnect_rio(struct usb_interface *intf)
                info("USB Rio disconnected.");
 
                rio->present = 0;
-               up(&(rio->lock));
+               mutex_unlock(&(rio->lock));
        }
 }
 
index 3cf3ea3..90c5953 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for USB Core files and filesystem
 #
 
-usbmon-objs    := mon_main.o mon_stat.o mon_text.o mon_dma.o
+usbmon-objs    := mon_main.o mon_stat.o mon_text.o mon_bin.o mon_dma.o
 
 # This does not use CONFIG_USB_MON because we want this to use a tristate.
 obj-$(CONFIG_USB)      += usbmon.o
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
new file mode 100644 (file)
index 0000000..c01dfe6
--- /dev/null
@@ -0,0 +1,1172 @@
+/*
+ * The USB Monitor, inspired by Dave Harding's USBMon.
+ *
+ * This is a binary format reader.
+ *
+ * Copyright (C) 2006 Paolo Abeni (paolo.abeni@email.it)
+ * Copyright (C) 2006 Pete Zaitcev (zaitcev@redhat.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/usb.h>
+#include <linux/poll.h>
+#include <linux/compat.h>
+#include <linux/mm.h>
+
+#include <asm/uaccess.h>
+
+#include "usb_mon.h"
+
+/*
+ * Defined by USB 2.0 clause 9.3, table 9.2.
+ */
+#define SETUP_LEN  8
+
+/* ioctl macros */
+#define MON_IOC_MAGIC 0x92
+
+#define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1)
+/* #2 used to be MON_IOCX_URB, removed before it got into Linus tree */
+#define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
+#define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4)
+#define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5)
+#define MON_IOCX_GET   _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get)
+#define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch)
+#define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8)
+#ifdef CONFIG_COMPAT
+#define MON_IOCX_GET32 _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get32)
+#define MON_IOCX_MFETCH32 _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch32)
+#endif
+
+/*
+ * Some architectures have enormous basic pages (16KB for ia64, 64KB for ppc).
+ * But it's all right. Just use a simple way to make sure the chunk is never
+ * smaller than a page.
+ *
+ * N.B. An application does not know our chunk size.
+ *
+ * Woops, get_zeroed_page() returns a single page. I guess we're stuck with
+ * page-sized chunks for the time being.
+ */
+#define CHUNK_SIZE   PAGE_SIZE
+#define CHUNK_ALIGN(x)   (((x)+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1))
+
+/*
+ * The magic limit was calculated so that it allows the monitoring
+ * application to pick data once in two ticks. This way, another application,
+ * which presumably drives the bus, gets to hog CPU, yet we collect our data.
+ * If HZ is 100, a 480 mbit/s bus drives 614 KB every jiffy. USB has an
+ * enormous overhead built into the bus protocol, so we need about 1000 KB.
+ *
+ * This is still too much for most cases, where we just snoop a few
+ * descriptor fetches for enumeration. So, the default is a "reasonable"
+ * amount for systems with HZ=250 and incomplete bus saturation.
+ *
+ * XXX What about multi-megabyte URBs which take minutes to transfer?
+ */
+#define BUFF_MAX  CHUNK_ALIGN(1200*1024)
+#define BUFF_DFL   CHUNK_ALIGN(300*1024)
+#define BUFF_MIN     CHUNK_ALIGN(8*1024)
+
+/*
+ * The per-event API header (2 per URB).
+ *
+ * This structure is seen in userland as defined by the documentation.
+ */
+struct mon_bin_hdr {
+       u64 id;                 /* URB ID - from submission to callback */
+       unsigned char type;     /* Same as in text API; extensible. */
+       unsigned char xfer_type;        /* ISO, Intr, Control, Bulk */
+       unsigned char epnum;    /* Endpoint number and transfer direction */
+       unsigned char devnum;   /* Device address */
+       unsigned short busnum;  /* Bus number */
+       char flag_setup;
+       char flag_data;
+       s64 ts_sec;             /* gettimeofday */
+       s32 ts_usec;            /* gettimeofday */
+       int status;
+       unsigned int len_urb;   /* Length of data (submitted or actual) */
+       unsigned int len_cap;   /* Delivered length */
+       unsigned char setup[SETUP_LEN]; /* Only for Control S-type */
+};
+
+/* per file statistic */
+struct mon_bin_stats {
+       u32 queued;
+       u32 dropped;
+};
+
+struct mon_bin_get {
+       struct mon_bin_hdr __user *hdr; /* Only 48 bytes, not 64. */
+       void __user *data;
+       size_t alloc;           /* Length of data (can be zero) */
+};
+
+struct mon_bin_mfetch {
+       u32 __user *offvec;     /* Vector of events fetched */
+       u32 nfetch;             /* Number of events to fetch (out: fetched) */
+       u32 nflush;             /* Number of events to flush */
+};
+
+#ifdef CONFIG_COMPAT
+struct mon_bin_get32 {
+       u32 hdr32;
+       u32 data32;
+       u32 alloc32;
+};
+
+struct mon_bin_mfetch32 {
+        u32 offvec32;
+        u32 nfetch32;
+        u32 nflush32;
+};
+#endif
+
+/* Having these two values same prevents wrapping of the mon_bin_hdr */
+#define PKT_ALIGN   64
+#define PKT_SIZE    64
+
+/* max number of USB bus supported */
+#define MON_BIN_MAX_MINOR 128
+
+/*
+ * The buffer: map of used pages.
+ */
+struct mon_pgmap {
+       struct page *pg;
+       unsigned char *ptr;     /* XXX just use page_to_virt everywhere? */
+};
+
+/*
+ * This gets associated with an open file struct.
+ */
+struct mon_reader_bin {
+       /* The buffer: one per open. */
+       spinlock_t b_lock;              /* Protect b_cnt, b_in */
+       unsigned int b_size;            /* Current size of the buffer - bytes */
+       unsigned int b_cnt;             /* Bytes used */
+       unsigned int b_in, b_out;       /* Offsets into buffer - bytes */
+       unsigned int b_read;            /* Amount of read data in curr. pkt. */
+       struct mon_pgmap *b_vec;        /* The map array */
+       wait_queue_head_t b_wait;       /* Wait for data here */
+
+       struct mutex fetch_lock;        /* Protect b_read, b_out */
+       int mmap_active;
+
+       /* A list of these is needed for "bus 0". Some time later. */
+       struct mon_reader r;
+
+       /* Stats */
+       unsigned int cnt_lost;
+};
+
+static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp,
+    unsigned int offset)
+{
+       return (struct mon_bin_hdr *)
+           (rp->b_vec[offset / CHUNK_SIZE].ptr + offset % CHUNK_SIZE);
+}
+
+#define MON_RING_EMPTY(rp)     ((rp)->b_cnt == 0)
+
+static dev_t mon_bin_dev0;
+static struct cdev mon_bin_cdev;
+
+static void mon_buff_area_fill(const struct mon_reader_bin *rp,
+    unsigned int offset, unsigned int size);
+static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp);
+static int mon_alloc_buff(struct mon_pgmap *map, int npages);
+static void mon_free_buff(struct mon_pgmap *map, int npages);
+
+/*
+ * This is a "chunked memcpy". It does not manipulate any counters.
+ * But it returns the new offset for repeated application.
+ */
+unsigned int mon_copy_to_buff(const struct mon_reader_bin *this,
+    unsigned int off, const unsigned char *from, unsigned int length)
+{
+       unsigned int step_len;
+       unsigned char *buf;
+       unsigned int in_page;
+
+       while (length) {
+               /*
+                * Determine step_len.
+                */
+               step_len = length;
+               in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1));
+               if (in_page < step_len)
+                       step_len = in_page;
+
+               /*
+                * Copy data and advance pointers.
+                */
+               buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE;
+               memcpy(buf, from, step_len);
+               if ((off += step_len) >= this->b_size) off = 0;
+               from += step_len;
+               length -= step_len;
+       }
+       return off;
+}
+
+/*
+ * This is a little worse than the above because it's "chunked copy_to_user".
+ * The return value is an error code, not an offset.
+ */
+static int copy_from_buf(const struct mon_reader_bin *this, unsigned int off,
+    char __user *to, int length)
+{
+       unsigned int step_len;
+       unsigned char *buf;
+       unsigned int in_page;
+
+       while (length) {
+               /*
+                * Determine step_len.
+                */
+               step_len = length;
+               in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1));
+               if (in_page < step_len)
+                       step_len = in_page;
+
+               /*
+                * Copy data and advance pointers.
+                */
+               buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE;
+               if (copy_to_user(to, buf, step_len))
+                       return -EINVAL;
+               if ((off += step_len) >= this->b_size) off = 0;
+               to += step_len;
+               length -= step_len;
+       }
+       return 0;
+}
+
+/*
+ * Allocate an (aligned) area in the buffer.
+ * This is called under b_lock.
+ * Returns ~0 on failure.
+ */
+static unsigned int mon_buff_area_alloc(struct mon_reader_bin *rp,
+    unsigned int size)
+{
+       unsigned int offset;
+
+       size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+       if (rp->b_cnt + size > rp->b_size)
+               return ~0;
+       offset = rp->b_in;
+       rp->b_cnt += size;
+       if ((rp->b_in += size) >= rp->b_size)
+               rp->b_in -= rp->b_size;
+       return offset;
+}
+
+/*
+ * This is the same thing as mon_buff_area_alloc, only it does not allow
+ * buffers to wrap. This is needed by applications which pass references
+ * into mmap-ed buffers up their stacks (libpcap can do that).
+ *
+ * Currently, we always have the header stuck with the data, although
+ * it is not strictly speaking necessary.
+ *
+ * When a buffer would wrap, we place a filler packet to mark the space.
+ */
+static unsigned int mon_buff_area_alloc_contiguous(struct mon_reader_bin *rp,
+    unsigned int size)
+{
+       unsigned int offset;
+       unsigned int fill_size;
+
+       size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+       if (rp->b_cnt + size > rp->b_size)
+               return ~0;
+       if (rp->b_in + size > rp->b_size) {
+               /*
+                * This would wrap. Find if we still have space after
+                * skipping to the end of the buffer. If we do, place
+                * a filler packet and allocate a new packet.
+                */
+               fill_size = rp->b_size - rp->b_in;
+               if (rp->b_cnt + size + fill_size > rp->b_size)
+                       return ~0;
+               mon_buff_area_fill(rp, rp->b_in, fill_size);
+
+               offset = 0;
+               rp->b_in = size;
+               rp->b_cnt += size + fill_size;
+       } else if (rp->b_in + size == rp->b_size) {
+               offset = rp->b_in;
+               rp->b_in = 0;
+               rp->b_cnt += size;
+       } else {
+               offset = rp->b_in;
+               rp->b_in += size;
+               rp->b_cnt += size;
+       }
+       return offset;
+}
+
+/*
+ * Return a few (kilo-)bytes to the head of the buffer.
+ * This is used if a DMA fetch fails.
+ */
+static void mon_buff_area_shrink(struct mon_reader_bin *rp, unsigned int size)
+{
+
+       size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+       rp->b_cnt -= size;
+       if (rp->b_in < size)
+               rp->b_in += rp->b_size;
+       rp->b_in -= size;
+}
+
+/*
+ * This has to be called under both b_lock and fetch_lock, because
+ * it accesses both b_cnt and b_out.
+ */
+static void mon_buff_area_free(struct mon_reader_bin *rp, unsigned int size)
+{
+
+       size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+       rp->b_cnt -= size;
+       if ((rp->b_out += size) >= rp->b_size)
+               rp->b_out -= rp->b_size;
+}
+
+static void mon_buff_area_fill(const struct mon_reader_bin *rp,
+    unsigned int offset, unsigned int size)
+{
+       struct mon_bin_hdr *ep;
+
+       ep = MON_OFF2HDR(rp, offset);
+       memset(ep, 0, PKT_SIZE);
+       ep->type = '@';
+       ep->len_cap = size - PKT_SIZE;
+}
+
+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')
+               return '-';
+
+       if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)
+               return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
+       if (urb->setup_packet == NULL)
+               return 'Z';
+
+       memcpy(setupb, urb->setup_packet, SETUP_LEN);
+       return 0;
+}
+
+static char mon_bin_get_data(const struct mon_reader_bin *rp,
+    unsigned int offset, struct urb *urb, unsigned int length)
+{
+
+       if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) {
+               mon_dmapeek_vec(rp, offset, urb->transfer_dma, length);
+               return 0;
+       }
+
+       if (urb->transfer_buffer == NULL)
+               return 'Z';
+
+       mon_copy_to_buff(rp, offset, urb->transfer_buffer, length);
+       return 0;
+}
+
+static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
+    char ev_type)
+{
+       unsigned long flags;
+       struct timeval ts;
+       unsigned int urb_length;
+       unsigned int offset;
+       unsigned int length;
+       struct mon_bin_hdr *ep;
+       char data_tag = 0;
+
+       do_gettimeofday(&ts);
+
+       spin_lock_irqsave(&rp->b_lock, flags);
+
+       /*
+        * Find the maximum allowable length, then allocate space.
+        */
+       urb_length = (ev_type == 'S') ?
+           urb->transfer_buffer_length : urb->actual_length;
+       length = urb_length;
+
+       if (length >= rp->b_size/5)
+               length = rp->b_size/5;
+
+       if (usb_pipein(urb->pipe)) {
+               if (ev_type == 'S') {
+                       length = 0;
+                       data_tag = '<';
+               }
+       } else {
+               if (ev_type == 'C') {
+                       length = 0;
+                       data_tag = '>';
+               }
+       }
+
+       if (rp->mmap_active)
+               offset = mon_buff_area_alloc_contiguous(rp, length + PKT_SIZE);
+       else
+               offset = mon_buff_area_alloc(rp, length + PKT_SIZE);
+       if (offset == ~0) {
+               rp->cnt_lost++;
+               spin_unlock_irqrestore(&rp->b_lock, flags);
+               return;
+       }
+
+       ep = MON_OFF2HDR(rp, offset);
+       if ((offset += PKT_SIZE) >= rp->b_size) offset = 0;
+
+       /*
+        * Fill the allocated area.
+        */
+       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->busnum = rp->r.m_bus->u_bus->busnum;
+       ep->id = (unsigned long) urb;
+       ep->ts_sec = ts.tv_sec;
+       ep->ts_usec = ts.tv_usec;
+       ep->status = urb->status;
+       ep->len_urb = urb_length;
+       ep->len_cap = length;
+
+       ep->flag_setup = mon_bin_get_setup(ep->setup, urb, ev_type);
+       if (length != 0) {
+               ep->flag_data = mon_bin_get_data(rp, offset, urb, length);
+               if (ep->flag_data != 0) {       /* Yes, it's 0x00, not '0' */
+                       ep->len_cap = 0;
+                       mon_buff_area_shrink(rp, length);
+               }
+       } else {
+               ep->flag_data = data_tag;
+       }
+
+       spin_unlock_irqrestore(&rp->b_lock, flags);
+
+       wake_up(&rp->b_wait);
+}
+
+static void mon_bin_submit(void *data, struct urb *urb)
+{
+       struct mon_reader_bin *rp = data;
+       mon_bin_event(rp, urb, 'S');
+}
+
+static void mon_bin_complete(void *data, struct urb *urb)
+{
+       struct mon_reader_bin *rp = data;
+       mon_bin_event(rp, urb, 'C');
+}
+
+static void mon_bin_error(void *data, struct urb *urb, int error)
+{
+       struct mon_reader_bin *rp = data;
+       unsigned long flags;
+       unsigned int offset;
+       struct mon_bin_hdr *ep;
+
+       spin_lock_irqsave(&rp->b_lock, flags);
+
+       offset = mon_buff_area_alloc(rp, PKT_SIZE);
+       if (offset == ~0) {
+               /* Not incrementing cnt_lost. Just because. */
+               spin_unlock_irqrestore(&rp->b_lock, flags);
+               return;
+       }
+
+       ep = MON_OFF2HDR(rp, offset);
+
+       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->busnum = rp->r.m_bus->u_bus->busnum;
+       ep->id = (unsigned long) urb;
+       ep->status = error;
+
+       ep->flag_setup = '-';
+       ep->flag_data = 'E';
+
+       spin_unlock_irqrestore(&rp->b_lock, flags);
+
+       wake_up(&rp->b_wait);
+}
+
+static int mon_bin_open(struct inode *inode, struct file *file)
+{
+       struct mon_bus *mbus;
+       struct usb_bus *ubus;
+       struct mon_reader_bin *rp;
+       size_t size;
+       int rc;
+
+       mutex_lock(&mon_lock);
+       if ((mbus = mon_bus_lookup(iminor(inode))) == NULL) {
+               mutex_unlock(&mon_lock);
+               return -ENODEV;
+       }
+       if ((ubus = mbus->u_bus) == NULL) {
+               printk(KERN_ERR TAG ": consistency error on open\n");
+               mutex_unlock(&mon_lock);
+               return -ENODEV;
+       }
+
+       rp = kzalloc(sizeof(struct mon_reader_bin), GFP_KERNEL);
+       if (rp == NULL) {
+               rc = -ENOMEM;
+               goto err_alloc;
+       }
+       spin_lock_init(&rp->b_lock);
+       init_waitqueue_head(&rp->b_wait);
+       mutex_init(&rp->fetch_lock);
+
+       rp->b_size = BUFF_DFL;
+
+       size = sizeof(struct mon_pgmap) * (rp->b_size/CHUNK_SIZE);
+       if ((rp->b_vec = kzalloc(size, GFP_KERNEL)) == NULL) {
+               rc = -ENOMEM;
+               goto err_allocvec;
+       }
+
+       if ((rc = mon_alloc_buff(rp->b_vec, rp->b_size/CHUNK_SIZE)) < 0)
+               goto err_allocbuff;
+
+       rp->r.m_bus = mbus;
+       rp->r.r_data = rp;
+       rp->r.rnf_submit = mon_bin_submit;
+       rp->r.rnf_error = mon_bin_error;
+       rp->r.rnf_complete = mon_bin_complete;
+
+       mon_reader_add(mbus, &rp->r);
+
+       file->private_data = rp;
+       mutex_unlock(&mon_lock);
+       return 0;
+
+err_allocbuff:
+       kfree(rp->b_vec);
+err_allocvec:
+       kfree(rp);
+err_alloc:
+       mutex_unlock(&mon_lock);
+       return rc;
+}
+
+/*
+ * Extract an event from buffer and copy it to user space.
+ * Wait if there is no event ready.
+ * Returns zero or error.
+ */
+static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp,
+    struct mon_bin_hdr __user *hdr, void __user *data, unsigned int nbytes)
+{
+       unsigned long flags;
+       struct mon_bin_hdr *ep;
+       size_t step_len;
+       unsigned int offset;
+       int rc;
+
+       mutex_lock(&rp->fetch_lock);
+
+       if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+               mutex_unlock(&rp->fetch_lock);
+               return rc;
+       }
+
+       ep = MON_OFF2HDR(rp, rp->b_out);
+
+       if (copy_to_user(hdr, ep, sizeof(struct mon_bin_hdr))) {
+               mutex_unlock(&rp->fetch_lock);
+               return -EFAULT;
+       }
+
+       step_len = min(ep->len_cap, nbytes);
+       if ((offset = rp->b_out + PKT_SIZE) >= rp->b_size) offset = 0;
+
+       if (copy_from_buf(rp, offset, data, step_len)) {
+               mutex_unlock(&rp->fetch_lock);
+               return -EFAULT;
+       }
+
+       spin_lock_irqsave(&rp->b_lock, flags);
+       mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+       spin_unlock_irqrestore(&rp->b_lock, flags);
+       rp->b_read = 0;
+
+       mutex_unlock(&rp->fetch_lock);
+       return 0;
+}
+
+static int mon_bin_release(struct inode *inode, struct file *file)
+{
+       struct mon_reader_bin *rp = file->private_data;
+       struct mon_bus* mbus = rp->r.m_bus;
+
+       mutex_lock(&mon_lock);
+
+       if (mbus->nreaders <= 0) {
+               printk(KERN_ERR TAG ": consistency error on close\n");
+               mutex_unlock(&mon_lock);
+               return 0;
+       }
+       mon_reader_del(mbus, &rp->r);
+
+       mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE);
+       kfree(rp->b_vec);
+       kfree(rp);
+
+       mutex_unlock(&mon_lock);
+       return 0;
+}
+
+static ssize_t mon_bin_read(struct file *file, char __user *buf,
+    size_t nbytes, loff_t *ppos)
+{
+       struct mon_reader_bin *rp = file->private_data;
+       unsigned long flags;
+       struct mon_bin_hdr *ep;
+       unsigned int offset;
+       size_t step_len;
+       char *ptr;
+       ssize_t done = 0;
+       int rc;
+
+       mutex_lock(&rp->fetch_lock);
+
+       if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+               mutex_unlock(&rp->fetch_lock);
+               return rc;
+       }
+
+       ep = MON_OFF2HDR(rp, rp->b_out);
+
+       if (rp->b_read < sizeof(struct mon_bin_hdr)) {
+               step_len = min(nbytes, sizeof(struct mon_bin_hdr) - rp->b_read);
+               ptr = ((char *)ep) + rp->b_read;
+               if (step_len && copy_to_user(buf, ptr, step_len)) {
+                       mutex_unlock(&rp->fetch_lock);
+                       return -EFAULT;
+               }
+               nbytes -= step_len;
+               buf += step_len;
+               rp->b_read += step_len;
+               done += step_len;
+       }
+
+       if (rp->b_read >= sizeof(struct mon_bin_hdr)) {
+               step_len = min(nbytes, (size_t)ep->len_cap);
+               offset = rp->b_out + PKT_SIZE;
+               offset += rp->b_read - sizeof(struct mon_bin_hdr);
+               if (offset >= rp->b_size)
+                       offset -= rp->b_size;
+               if (copy_from_buf(rp, offset, buf, step_len)) {
+                       mutex_unlock(&rp->fetch_lock);
+                       return -EFAULT;
+               }
+               nbytes -= step_len;
+               buf += step_len;
+               rp->b_read += step_len;
+               done += step_len;
+       }
+
+       /*
+        * Check if whole packet was read, and if so, jump to the next one.
+        */
+       if (rp->b_read >= sizeof(struct mon_bin_hdr) + ep->len_cap) {
+               spin_lock_irqsave(&rp->b_lock, flags);
+               mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+               spin_unlock_irqrestore(&rp->b_lock, flags);
+               rp->b_read = 0;
+       }
+
+       mutex_unlock(&rp->fetch_lock);
+       return done;
+}
+
+/*
+ * Remove at most nevents from chunked buffer.
+ * Returns the number of removed events.
+ */
+static int mon_bin_flush(struct mon_reader_bin *rp, unsigned nevents)
+{
+       unsigned long flags;
+       struct mon_bin_hdr *ep;
+       int i;
+
+       mutex_lock(&rp->fetch_lock);
+       spin_lock_irqsave(&rp->b_lock, flags);
+       for (i = 0; i < nevents; ++i) {
+               if (MON_RING_EMPTY(rp))
+                       break;
+
+               ep = MON_OFF2HDR(rp, rp->b_out);
+               mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+       }
+       spin_unlock_irqrestore(&rp->b_lock, flags);
+       rp->b_read = 0;
+       mutex_unlock(&rp->fetch_lock);
+       return i;
+}
+
+/*
+ * Fetch at most max event offsets into the buffer and put them into vec.
+ * The events are usually freed later with mon_bin_flush.
+ * Return the effective number of events fetched.
+ */
+static int mon_bin_fetch(struct file *file, struct mon_reader_bin *rp,
+    u32 __user *vec, unsigned int max)
+{
+       unsigned int cur_out;
+       unsigned int bytes, avail;
+       unsigned int size;
+       unsigned int nevents;
+       struct mon_bin_hdr *ep;
+       unsigned long flags;
+       int rc;
+
+       mutex_lock(&rp->fetch_lock);
+
+       if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+               mutex_unlock(&rp->fetch_lock);
+               return rc;
+       }
+
+       spin_lock_irqsave(&rp->b_lock, flags);
+       avail = rp->b_cnt;
+       spin_unlock_irqrestore(&rp->b_lock, flags);
+
+       cur_out = rp->b_out;
+       nevents = 0;
+       bytes = 0;
+       while (bytes < avail) {
+               if (nevents >= max)
+                       break;
+
+               ep = MON_OFF2HDR(rp, cur_out);
+               if (put_user(cur_out, &vec[nevents])) {
+                       mutex_unlock(&rp->fetch_lock);
+                       return -EFAULT;
+               }
+
+               nevents++;
+               size = ep->len_cap + PKT_SIZE;
+               size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+               if ((cur_out += size) >= rp->b_size)
+                       cur_out -= rp->b_size;
+               bytes += size;
+       }
+
+       mutex_unlock(&rp->fetch_lock);
+       return nevents;
+}
+
+/*
+ * Count events. This is almost the same as the above mon_bin_fetch,
+ * only we do not store offsets into user vector, and we have no limit.
+ */
+static int mon_bin_queued(struct mon_reader_bin *rp)
+{
+       unsigned int cur_out;
+       unsigned int bytes, avail;
+       unsigned int size;
+       unsigned int nevents;
+       struct mon_bin_hdr *ep;
+       unsigned long flags;
+
+       mutex_lock(&rp->fetch_lock);
+
+       spin_lock_irqsave(&rp->b_lock, flags);
+       avail = rp->b_cnt;
+       spin_unlock_irqrestore(&rp->b_lock, flags);
+
+       cur_out = rp->b_out;
+       nevents = 0;
+       bytes = 0;
+       while (bytes < avail) {
+               ep = MON_OFF2HDR(rp, cur_out);
+
+               nevents++;
+               size = ep->len_cap + PKT_SIZE;
+               size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+               if ((cur_out += size) >= rp->b_size)
+                       cur_out -= rp->b_size;
+               bytes += size;
+       }
+
+       mutex_unlock(&rp->fetch_lock);
+       return nevents;
+}
+
+/*
+ */
+static int mon_bin_ioctl(struct inode *inode, struct file *file,
+    unsigned int cmd, unsigned long arg)
+{
+       struct mon_reader_bin *rp = file->private_data;
+       // struct mon_bus* mbus = rp->r.m_bus;
+       int ret = 0;
+       struct mon_bin_hdr *ep;
+       unsigned long flags;
+
+       switch (cmd) {
+
+       case MON_IOCQ_URB_LEN:
+               /*
+                * N.B. This only returns the size of data, without the header.
+                */
+               spin_lock_irqsave(&rp->b_lock, flags);
+               if (!MON_RING_EMPTY(rp)) {
+                       ep = MON_OFF2HDR(rp, rp->b_out);
+                       ret = ep->len_cap;
+               }
+               spin_unlock_irqrestore(&rp->b_lock, flags);
+               break;
+
+       case MON_IOCQ_RING_SIZE:
+               ret = rp->b_size;
+               break;
+
+       case MON_IOCT_RING_SIZE:
+               /*
+                * Changing the buffer size will flush it's contents; the new
+                * buffer is allocated before releasing the old one to be sure
+                * the device will stay functional also in case of memory
+                * pressure.
+                */
+               {
+               int size;
+               struct mon_pgmap *vec;
+
+               if (arg < BUFF_MIN || arg > BUFF_MAX)
+                       return -EINVAL;
+
+               size = CHUNK_ALIGN(arg);
+               if ((vec = kzalloc(sizeof(struct mon_pgmap) * (size/CHUNK_SIZE),
+                   GFP_KERNEL)) == NULL) {
+                       ret = -ENOMEM;
+                       break;
+               }
+
+               ret = mon_alloc_buff(vec, size/CHUNK_SIZE);
+               if (ret < 0) {
+                       kfree(vec);
+                       break;
+               }
+
+               mutex_lock(&rp->fetch_lock);
+               spin_lock_irqsave(&rp->b_lock, flags);
+               mon_free_buff(rp->b_vec, size/CHUNK_SIZE);
+               kfree(rp->b_vec);
+               rp->b_vec  = vec;
+               rp->b_size = size;
+               rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0;
+               rp->cnt_lost = 0;
+               spin_unlock_irqrestore(&rp->b_lock, flags);
+               mutex_unlock(&rp->fetch_lock);
+               }
+               break;
+
+       case MON_IOCH_MFLUSH:
+               ret = mon_bin_flush(rp, arg);
+               break;
+
+       case MON_IOCX_GET:
+               {
+               struct mon_bin_get getb;
+
+               if (copy_from_user(&getb, (void __user *)arg,
+                                           sizeof(struct mon_bin_get)))
+                       return -EFAULT;
+
+               if (getb.alloc > 0x10000000)    /* Want to cast to u32 */
+                       return -EINVAL;
+               ret = mon_bin_get_event(file, rp,
+                         getb.hdr, getb.data, (unsigned int)getb.alloc);
+               }
+               break;
+
+#ifdef CONFIG_COMPAT
+       case MON_IOCX_GET32: {
+               struct mon_bin_get32 getb;
+
+               if (copy_from_user(&getb, (void __user *)arg,
+                                           sizeof(struct mon_bin_get32)))
+                       return -EFAULT;
+
+               ret = mon_bin_get_event(file, rp,
+                   compat_ptr(getb.hdr32), compat_ptr(getb.data32),
+                   getb.alloc32);
+               }
+               break;
+#endif
+
+       case MON_IOCX_MFETCH:
+               {
+               struct mon_bin_mfetch mfetch;
+               struct mon_bin_mfetch __user *uptr;
+
+               uptr = (struct mon_bin_mfetch __user *)arg;
+
+               if (copy_from_user(&mfetch, uptr, sizeof(mfetch)))
+                       return -EFAULT;
+
+               if (mfetch.nflush) {
+                       ret = mon_bin_flush(rp, mfetch.nflush);
+                       if (ret < 0)
+                               return ret;
+                       if (put_user(ret, &uptr->nflush))
+                               return -EFAULT;
+               }
+               ret = mon_bin_fetch(file, rp, mfetch.offvec, mfetch.nfetch);
+               if (ret < 0)
+                       return ret;
+               if (put_user(ret, &uptr->nfetch))
+                       return -EFAULT;
+               ret = 0;
+               }
+               break;
+
+#ifdef CONFIG_COMPAT
+       case MON_IOCX_MFETCH32:
+               {
+               struct mon_bin_mfetch32 mfetch;
+               struct mon_bin_mfetch32 __user *uptr;
+
+               uptr = (struct mon_bin_mfetch32 __user *) compat_ptr(arg);
+
+               if (copy_from_user(&mfetch, uptr, sizeof(mfetch)))
+                       return -EFAULT;
+
+               if (mfetch.nflush32) {
+                       ret = mon_bin_flush(rp, mfetch.nflush32);
+                       if (ret < 0)
+                               return ret;
+                       if (put_user(ret, &uptr->nflush32))
+                               return -EFAULT;
+               }
+               ret = mon_bin_fetch(file, rp, compat_ptr(mfetch.offvec32),
+                   mfetch.nfetch32);
+               if (ret < 0)
+                       return ret;
+               if (put_user(ret, &uptr->nfetch32))
+                       return -EFAULT;
+               ret = 0;
+               }
+               break;
+#endif
+
+       case MON_IOCG_STATS: {
+               struct mon_bin_stats __user *sp;
+               unsigned int nevents;
+               unsigned int ndropped;
+
+               spin_lock_irqsave(&rp->b_lock, flags);
+               ndropped = rp->cnt_lost;
+               rp->cnt_lost = 0;
+               spin_unlock_irqrestore(&rp->b_lock, flags);
+               nevents = mon_bin_queued(rp);
+
+               sp = (struct mon_bin_stats __user *)arg;
+               if (put_user(rp->cnt_lost, &sp->dropped))
+                       return -EFAULT;
+               if (put_user(nevents, &sp->queued))
+                       return -EFAULT;
+
+               }
+               break;
+
+       default:
+               return -ENOTTY;
+       }
+
+       return ret;
+}
+
+static unsigned int
+mon_bin_poll(struct file *file, struct poll_table_struct *wait)
+{
+       struct mon_reader_bin *rp = file->private_data;
+       unsigned int mask = 0;
+       unsigned long flags;
+
+       if (file->f_mode & FMODE_READ)
+               poll_wait(file, &rp->b_wait, wait);
+
+       spin_lock_irqsave(&rp->b_lock, flags);
+       if (!MON_RING_EMPTY(rp))
+               mask |= POLLIN | POLLRDNORM;    /* readable */
+       spin_unlock_irqrestore(&rp->b_lock, flags);
+       return mask;
+}
+
+/*
+ * open and close: just keep track of how many times the device is
+ * mapped, to use the proper memory allocation function.
+ */
+static void mon_bin_vma_open(struct vm_area_struct *vma)
+{
+       struct mon_reader_bin *rp = vma->vm_private_data;
+       rp->mmap_active++;
+}
+
+static void mon_bin_vma_close(struct vm_area_struct *vma)
+{
+       struct mon_reader_bin *rp = vma->vm_private_data;
+       rp->mmap_active--;
+}
+
+/*
+ * Map ring pages to user space.
+ */
+struct page *mon_bin_vma_nopage(struct vm_area_struct *vma,
+                                unsigned long address, int *type)
+{
+       struct mon_reader_bin *rp = vma->vm_private_data;
+       unsigned long offset, chunk_idx;
+       struct page *pageptr;
+
+       offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
+       if (offset >= rp->b_size)
+               return NOPAGE_SIGBUS;
+       chunk_idx = offset / CHUNK_SIZE;
+       pageptr = rp->b_vec[chunk_idx].pg;
+       get_page(pageptr);
+       if (type)
+               *type = VM_FAULT_MINOR;
+       return pageptr;
+}
+
+struct vm_operations_struct mon_bin_vm_ops = {
+       .open =     mon_bin_vma_open,
+       .close =    mon_bin_vma_close,
+       .nopage =   mon_bin_vma_nopage,
+};
+
+int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       /* don't do anything here: "nopage" will set up page table entries */
+       vma->vm_ops = &mon_bin_vm_ops;
+       vma->vm_flags |= VM_RESERVED;
+       vma->vm_private_data = filp->private_data;
+       mon_bin_vma_open(vma);
+       return 0;
+}
+
+struct file_operations mon_fops_binary = {
+       .owner =        THIS_MODULE,
+       .open =         mon_bin_open,
+       .llseek =       no_llseek,
+       .read =         mon_bin_read,
+       /* .write =     mon_text_write, */
+       .poll =         mon_bin_poll,
+       .ioctl =        mon_bin_ioctl,
+       .release =      mon_bin_release,
+};
+
+static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp)
+{
+       DECLARE_WAITQUEUE(waita, current);
+       unsigned long flags;
+
+       add_wait_queue(&rp->b_wait, &waita);
+       set_current_state(TASK_INTERRUPTIBLE);
+
+       spin_lock_irqsave(&rp->b_lock, flags);
+       while (MON_RING_EMPTY(rp)) {
+               spin_unlock_irqrestore(&rp->b_lock, flags);
+
+               if (file->f_flags & O_NONBLOCK) {
+                       set_current_state(TASK_RUNNING);
+                       remove_wait_queue(&rp->b_wait, &waita);
+                       return -EWOULDBLOCK; /* Same as EAGAIN in Linux */
+               }
+               schedule();
+               if (signal_pending(current)) {
+                       remove_wait_queue(&rp->b_wait, &waita);
+                       return -EINTR;
+               }
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               spin_lock_irqsave(&rp->b_lock, flags);
+       }
+       spin_unlock_irqrestore(&rp->b_lock, flags);
+
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&rp->b_wait, &waita);
+       return 0;
+}
+
+static int mon_alloc_buff(struct mon_pgmap *map, int npages)
+{
+       int n;
+       unsigned long vaddr;
+
+       for (n = 0; n < npages; n++) {
+               vaddr = get_zeroed_page(GFP_KERNEL);
+               if (vaddr == 0) {
+                       while (n-- != 0)
+                               free_page((unsigned long) map[n].ptr);
+                       return -ENOMEM;
+               }
+               map[n].ptr = (unsigned char *) vaddr;
+               map[n].pg = virt_to_page(vaddr);
+       }
+       return 0;
+}
+
+static void mon_free_buff(struct mon_pgmap *map, int npages)
+{
+       int n;
+
+       for (n = 0; n < npages; n++)
+               free_page((unsigned long) map[n].ptr);
+}
+
+int __init mon_bin_init(void)
+{
+       int rc;
+
+       rc = alloc_chrdev_region(&mon_bin_dev0, 0, MON_BIN_MAX_MINOR, "usbmon");
+       if (rc < 0)
+               goto err_dev;
+
+       cdev_init(&mon_bin_cdev, &mon_fops_binary);
+       mon_bin_cdev.owner = THIS_MODULE;
+
+       rc = cdev_add(&mon_bin_cdev, mon_bin_dev0, MON_BIN_MAX_MINOR);
+       if (rc < 0)
+               goto err_add;
+
+       return 0;
+
+err_add:
+       unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
+err_dev:
+       return rc;
+}
+
+void __exit mon_bin_exit(void)
+{
+       cdev_del(&mon_bin_cdev);
+       unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
+}
index ddcfc01..140cc80 100644 (file)
@@ -48,6 +48,36 @@ char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
        local_irq_restore(flags);
        return 0;
 }
+
+void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+    unsigned int offset, dma_addr_t dma_addr, unsigned int length)
+{
+       unsigned long flags;
+       unsigned int step_len;
+       struct page *pg;
+       unsigned char *map;
+       unsigned long page_off, page_len;
+
+       local_irq_save(flags);
+       while (length) {
+               /* compute number of bytes we are going to copy in this page */
+               step_len = length;
+               page_off = dma_addr & (PAGE_SIZE-1);
+               page_len = PAGE_SIZE - page_off;
+               if (page_len < step_len)
+                       step_len = page_len;
+
+               /* copy data and advance pointers */
+               pg = phys_to_page(dma_addr);
+               map = kmap_atomic(pg, KM_IRQ0);
+               offset = mon_copy_to_buff(rp, offset, map + page_off, step_len);
+               kunmap_atomic(map, KM_IRQ0);
+               dma_addr += step_len;
+               length -= step_len;
+       }
+       local_irq_restore(flags);
+}
+
 #endif /* __i386__ */
 
 #ifndef MON_HAS_UNMAP
@@ -55,4 +85,11 @@ char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
 {
        return 'D';
 }
-#endif
+
+void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+    unsigned int offset, dma_addr_t dma_addr, unsigned int length)
+{
+       ;
+}
+
+#endif /* MON_HAS_UNMAP */
index 394bbf2..c9739e7 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/usb.h>
-#include <linux/debugfs.h>
 #include <linux/smp_lock.h>
 #include <linux/notifier.h>
 #include <linux/mutex.h>
@@ -22,11 +21,10 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb);
 static void mon_stop(struct mon_bus *mbus);
 static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
 static void mon_bus_drop(struct kref *r);
-static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus);
+static void mon_bus_init(struct usb_bus *ubus);
 
 DEFINE_MUTEX(mon_lock);
 
-static struct dentry *mon_dir;         /* /dbg/usbmon */
 static LIST_HEAD(mon_buses);           /* All buses we know: struct mon_bus */
 
 /*
@@ -200,7 +198,7 @@ static void mon_stop(struct mon_bus *mbus)
  */
 static void mon_bus_add(struct usb_bus *ubus)
 {
-       mon_bus_init(mon_dir, ubus);
+       mon_bus_init(ubus);
 }
 
 /*
@@ -212,8 +210,8 @@ static void mon_bus_remove(struct usb_bus *ubus)
 
        mutex_lock(&mon_lock);
        list_del(&mbus->bus_link);
-       debugfs_remove(mbus->dent_t);
-       debugfs_remove(mbus->dent_s);
+       if (mbus->text_inited)
+               mon_text_del(mbus);
 
        mon_dissolve(mbus, ubus);
        kref_put(&mbus->ref, mon_bus_drop);
@@ -281,13 +279,9 @@ static void mon_bus_drop(struct kref *r)
  *  - refcount USB bus struct
  *  - link
  */
-static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
+static void mon_bus_init(struct usb_bus *ubus)
 {
-       struct dentry *d;
        struct mon_bus *mbus;
-       enum { NAMESZ = 10 };
-       char name[NAMESZ];
-       int rc;
 
        if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
                goto err_alloc;
@@ -303,57 +297,54 @@ static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
        ubus->mon_bus = mbus;
        mbus->uses_dma = ubus->uses_dma;
 
-       rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
-       if (rc <= 0 || rc >= NAMESZ)
-               goto err_print_t;
-       d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_text);
-       if (d == NULL)
-               goto err_create_t;
-       mbus->dent_t = d;
-
-       rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
-       if (rc <= 0 || rc >= NAMESZ)
-               goto err_print_s;
-       d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_stat);
-       if (d == NULL)
-               goto err_create_s;
-       mbus->dent_s = d;
+       mbus->text_inited = mon_text_add(mbus, ubus);
+       // mon_bin_add(...)
 
        mutex_lock(&mon_lock);
        list_add_tail(&mbus->bus_link, &mon_buses);
        mutex_unlock(&mon_lock);
        return;
 
-err_create_s:
-err_print_s:
-       debugfs_remove(mbus->dent_t);
-err_create_t:
-err_print_t:
-       kfree(mbus);
 err_alloc:
        return;
 }
 
+/*
+ * Search a USB bus by number. Notice that USB bus numbers start from one,
+ * which we may later use to identify "all" with zero.
+ *
+ * This function must be called with mon_lock held.
+ *
+ * This is obviously inefficient and may be revised in the future.
+ */
+struct mon_bus *mon_bus_lookup(unsigned int num)
+{
+       struct list_head *p;
+       struct mon_bus *mbus;
+
+       list_for_each (p, &mon_buses) {
+               mbus = list_entry(p, struct mon_bus, bus_link);
+               if (mbus->u_bus->busnum == num) {
+                       return mbus;
+               }
+       }
+       return NULL;
+}
+
 static int __init mon_init(void)
 {
        struct usb_bus *ubus;
-       struct dentry *mondir;
+       int rc;
 
-       mondir = debugfs_create_dir("usbmon", NULL);
-       if (IS_ERR(mondir)) {
-               printk(KERN_NOTICE TAG ": debugfs is not available\n");
-               return -ENODEV;
-       }
-       if (mondir == NULL) {
-               printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
-               return -ENODEV;
-       }
-       mon_dir = mondir;
+       if ((rc = mon_text_init()) != 0)
+               goto err_text;
+       if ((rc = mon_bin_init()) != 0)
+               goto err_bin;
 
        if (usb_mon_register(&mon_ops_0) != 0) {
                printk(KERN_NOTICE TAG ": unable to register with the core\n");
-               debugfs_remove(mondir);
-               return -ENODEV;
+               rc = -ENODEV;
+               goto err_reg;
        }
        // MOD_INC_USE_COUNT(which_module?);
 
@@ -361,10 +352,17 @@ static int __init mon_init(void)
 
        mutex_lock(&usb_bus_list_lock);
        list_for_each_entry (ubus, &usb_bus_list, bus_list) {
-               mon_bus_init(mondir, ubus);
+               mon_bus_init(ubus);
        }
        mutex_unlock(&usb_bus_list_lock);
        return 0;
+
+err_reg:
+       mon_bin_exit();
+err_bin:
+       mon_text_exit();
+err_text:
+       return rc;
 }
 
 static void __exit mon_exit(void)
@@ -381,8 +379,8 @@ static void __exit mon_exit(void)
                mbus = list_entry(p, struct mon_bus, bus_link);
                list_del(p);
 
-               debugfs_remove(mbus->dent_t);
-               debugfs_remove(mbus->dent_s);
+               if (mbus->text_inited)
+                       mon_text_del(mbus);
 
                /*
                 * This never happens, because the open/close paths in
@@ -401,7 +399,8 @@ static void __exit mon_exit(void)
        }
        mutex_unlock(&mon_lock);
 
-       debugfs_remove(mon_dir);
+       mon_text_exit();
+       mon_bin_exit();
 }
 
 module_init(mon_init);
index 05cf2c9..d38a127 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/usb.h>
 #include <linux/time.h>
 #include <linux/mutex.h>
+#include <linux/debugfs.h>
 #include <asm/uaccess.h>
 
 #include "usb_mon.h"
@@ -63,6 +64,8 @@ struct mon_reader_text {
        char slab_name[SLAB_NAME_SZ];
 };
 
+static struct dentry *mon_dir;         /* Usually /sys/kernel/debug/usbmon */
+
 static void mon_text_ctor(void *, struct kmem_cache *, unsigned long);
 
 /*
@@ -436,7 +439,7 @@ static int mon_text_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-const struct file_operations mon_fops_text = {
+static const struct file_operations mon_fops_text = {
        .owner =        THIS_MODULE,
        .open =         mon_text_open,
        .llseek =       no_llseek,
@@ -447,6 +450,47 @@ const struct file_operations mon_fops_text = {
        .release =      mon_text_release,
 };
 
+int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
+{
+       struct dentry *d;
+       enum { NAMESZ = 10 };
+       char name[NAMESZ];
+       int rc;
+
+       rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
+       if (rc <= 0 || rc >= NAMESZ)
+               goto err_print_t;
+       d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text);
+       if (d == NULL)
+               goto err_create_t;
+       mbus->dent_t = d;
+
+       /* XXX The stats do not belong to here (text API), but oh well... */
+       rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
+       if (rc <= 0 || rc >= NAMESZ)
+               goto err_print_s;
+       d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_stat);
+       if (d == NULL)
+               goto err_create_s;
+       mbus->dent_s = d;
+
+       return 1;
+
+err_create_s:
+err_print_s:
+       debugfs_remove(mbus->dent_t);
+       mbus->dent_t = NULL;
+err_create_t:
+err_print_t:
+       return 0;
+}
+
+void mon_text_del(struct mon_bus *mbus)
+{
+       debugfs_remove(mbus->dent_t);
+       debugfs_remove(mbus->dent_s);
+}
+
 /*
  * Slab interface: constructor.
  */
@@ -459,3 +503,24 @@ static void mon_text_ctor(void *mem, struct kmem_cache *slab, unsigned long sfla
        memset(mem, 0xe5, sizeof(struct mon_event_text));
 }
 
+int __init mon_text_init(void)
+{
+       struct dentry *mondir;
+
+       mondir = debugfs_create_dir("usbmon", NULL);
+       if (IS_ERR(mondir)) {
+               printk(KERN_NOTICE TAG ": debugfs is not available\n");
+               return -ENODEV;
+       }
+       if (mondir == NULL) {
+               printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
+               return -ENODEV;
+       }
+       mon_dir = mondir;
+       return 0;
+}
+
+void __exit mon_text_exit(void)
+{
+       debugfs_remove(mon_dir);
+}
index ab9d02d..4f949ce 100644 (file)
 struct mon_bus {
        struct list_head bus_link;
        spinlock_t lock;
+       struct usb_bus *u_bus;
+
+       int text_inited;
        struct dentry *dent_s;          /* Debugging file */
        struct dentry *dent_t;          /* Text interface file */
-       struct usb_bus *u_bus;
        int uses_dma;
 
        /* Ref */
@@ -48,13 +50,35 @@ struct mon_reader {
 void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
 void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
 
+struct mon_bus *mon_bus_lookup(unsigned int num);
+
+int /*bool*/ mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus);
+void mon_text_del(struct mon_bus *mbus);
+// void mon_bin_add(struct mon_bus *);
+
+int __init mon_text_init(void);
+void __exit mon_text_exit(void);
+int __init mon_bin_init(void);
+void __exit mon_bin_exit(void);
+
 /*
- */
+ * DMA interface.
+ *
+ * XXX The vectored side needs a serious re-thinking. Abstracting vectors,
+ * like in Paolo's original patch, produces a double pkmap. We need an idea.
+*/
 extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len);
 
+struct mon_reader_bin;
+extern void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+    unsigned int offset, dma_addr_t dma_addr, unsigned int len);
+extern unsigned int mon_copy_to_buff(const struct mon_reader_bin *rp,
+    unsigned int offset, const unsigned char *from, unsigned int len);
+
+/*
+ */
 extern struct mutex mon_lock;
 
-extern const struct file_operations mon_fops_text;
 extern const struct file_operations mon_fops_stat;
 
 #endif /* __USB_MON_H */
index e081836..a2b94ef 100644 (file)
@@ -222,13 +222,15 @@ config USB_NET_MCS7830
          adapters marketed under the DeLOCK brand.
 
 config USB_NET_RNDIS_HOST
-       tristate "Host for RNDIS devices (EXPERIMENTAL)"
+       tristate "Host for RNDIS and ActiveSync devices (EXPERIMENTAL)"
        depends on USB_USBNET && EXPERIMENTAL
        select USB_NET_CDCETHER
        help
          This option enables hosting "Remote NDIS" USB networking links,
          as encouraged by Microsoft (instead of CDC Ethernet!) for use in
-         various devices that may only support this protocol.
+         various devices that may only support this protocol.  A variant
+         of this protocol (with even less public documentation) seems to
+         be at the root of Microsoft's "ActiveSync" too.
 
          Avoid using this protocol unless you have no better options.
          The protocol specification is incomplete, and is controlled by
index 44a9154..e5cdafa 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * CDC Ethernet based networking peripherals
  * Copyright (C) 2003-2005 by David Brownell
+ * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync)
  *
  * 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
 #include "usbnet.h"
 
 
+#if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
+
+static int is_rndis(struct usb_interface_descriptor *desc)
+{
+       return desc->bInterfaceClass == USB_CLASS_COMM
+               && desc->bInterfaceSubClass == 2
+               && desc->bInterfaceProtocol == 0xff;
+}
+
+static int is_activesync(struct usb_interface_descriptor *desc)
+{
+       return desc->bInterfaceClass == USB_CLASS_MISC
+               && desc->bInterfaceSubClass == 1
+               && desc->bInterfaceProtocol == 1;
+}
+
+#else
+
+#define is_rndis(desc)         0
+#define is_activesync(desc)    0
+
+#endif
+
 /*
  * probes control interface, claims data interface, collects the bulk
  * endpoints, activates data interface (if needed), maybe sets MTU.
@@ -71,7 +95,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
        /* this assumes that if there's a non-RNDIS vendor variant
         * of cdc-acm, it'll fail RNDIS requests cleanly.
         */
-       rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff);
+       rndis = is_rndis(&intf->cur_altsetting->desc)
+               || is_activesync(&intf->cur_altsetting->desc);
 
        memset(info, 0, sizeof *info);
        info->control = intf;
@@ -99,6 +124,23 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
                                goto bad_desc;
                        }
                        break;
+               case USB_CDC_ACM_TYPE:
+                       /* paranoia:  disambiguate a "real" vendor-specific
+                        * modem interface from an RNDIS non-modem.
+                        */
+                       if (rndis) {
+                               struct usb_cdc_acm_descriptor *d;
+
+                               d = (void *) buf;
+                               if (d->bmCapabilities) {
+                                       dev_dbg(&intf->dev,
+                                               "ACM capabilities %02x, "
+                                               "not really RNDIS?\n",
+                                               d->bmCapabilities);
+                                       goto bad_desc;
+                               }
+                       }
+                       break;
                case USB_CDC_UNION_TYPE:
                        if (info->u) {
                                dev_dbg(&intf->dev, "extra CDC union\n");
@@ -171,7 +213,21 @@ next_desc:
                buf += buf [0];
        }
 
-       if (!info->header || !info->u || (!rndis && !info->ether)) {
+       /* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors,
+        * so we'll hard-wire the interfaces and not check for descriptors.
+        */
+       if (is_activesync(&intf->cur_altsetting->desc) && !info->u) {
+               info->control = usb_ifnum_to_if(dev->udev, 0);
+               info->data = usb_ifnum_to_if(dev->udev, 1);
+               if (!info->control || !info->data) {
+                       dev_dbg(&intf->dev,
+                               "activesync: master #0/%p slave #1/%p\n",
+                               info->control,
+                               info->data);
+                       goto bad_desc;
+               }
+
+       } else if (!info->header || !info->u || (!rndis && !info->ether)) {
                dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
                        info->header ? "" : "header ",
                        info->u ? "" : "union ",
index fa78326..36a9891 100644 (file)
@@ -179,6 +179,7 @@ static struct usb_driver kaweth_driver = {
        .suspend =      kaweth_suspend,
        .resume =       kaweth_resume,
        .id_table =     usb_klsi_table,
+       .supports_autosuspend = 1,
 };
 
 typedef __u8 eth_addr_t[6];
@@ -225,6 +226,7 @@ struct kaweth_device
        struct delayed_work lowmem_work;
 
        struct usb_device *dev;
+       struct usb_interface *intf;
        struct net_device *net;
        wait_queue_head_t term_wait;
 
@@ -662,9 +664,14 @@ static int kaweth_open(struct net_device *net)
 
        dbg("Opening network device.");
 
+       res = usb_autopm_get_interface(kaweth->intf);
+       if (res) {
+               err("Interface cannot be resumed.");
+               return -EIO;
+       }
        res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
        if (res)
-               return -EIO;
+               goto err_out;
 
        usb_fill_int_urb(
                kaweth->irq_urb,
@@ -681,7 +688,7 @@ static int kaweth_open(struct net_device *net)
        res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL);
        if (res) {
                usb_kill_urb(kaweth->rx_urb);
-               return -EIO;
+               goto err_out;
        }
        kaweth->opened = 1;
 
@@ -689,10 +696,14 @@ static int kaweth_open(struct net_device *net)
 
        kaweth_async_set_rx_mode(kaweth);
        return 0;
+
+err_out:
+       usb_autopm_enable(kaweth->intf);
+       return -EIO;
 }
 
 /****************************************************************
- *     kaweth_close
+ *     kaweth_kill_urbs
  ****************************************************************/
 static void kaweth_kill_urbs(struct kaweth_device *kaweth)
 {
@@ -724,17 +735,29 @@ static int kaweth_close(struct net_device *net)
 
        kaweth->status &= ~KAWETH_STATUS_CLOSING;
 
+       usb_autopm_enable(kaweth->intf);
+
        return 0;
 }
 
 static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
+       struct kaweth_device *kaweth = netdev_priv(dev);
 
        strlcpy(info->driver, driver_name, sizeof(info->driver));
+       usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info));
+}
+
+static u32 kaweth_get_link(struct net_device *dev)
+{
+       struct kaweth_device *kaweth = netdev_priv(dev);
+
+       return kaweth->linkstate;
 }
 
 static struct ethtool_ops ops = {
-       .get_drvinfo = kaweth_get_drvinfo
+       .get_drvinfo    = kaweth_get_drvinfo,
+       .get_link       = kaweth_get_link
 };
 
 /****************************************************************
@@ -908,6 +931,7 @@ static int kaweth_suspend(struct usb_interface *intf, pm_message_t message)
        struct kaweth_device *kaweth = usb_get_intfdata(intf);
        unsigned long flags;
 
+       dbg("Suspending device");
        spin_lock_irqsave(&kaweth->device_lock, flags);
        kaweth->status |= KAWETH_STATUS_SUSPENDING;
        spin_unlock_irqrestore(&kaweth->device_lock, flags);
@@ -924,6 +948,7 @@ static int kaweth_resume(struct usb_interface *intf)
        struct kaweth_device *kaweth = usb_get_intfdata(intf);
        unsigned long flags;
 
+       dbg("Resuming device");
        spin_lock_irqsave(&kaweth->device_lock, flags);
        kaweth->status &= ~KAWETH_STATUS_SUSPENDING;
        spin_unlock_irqrestore(&kaweth->device_lock, flags);
@@ -1086,6 +1111,8 @@ err_fw:
 
        dbg("Initializing net device.");
 
+       kaweth->intf = intf;
+
        kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!kaweth->tx_urb)
                goto err_free_netdev;
@@ -1265,7 +1292,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev,
 {
         struct urb *urb;
         int retv;
-        int length;
+        int length = 0; /* shut up GCC */
 
         urb = usb_alloc_urb(0, GFP_NOIO);
         if (!urb)
index a322a16..be888d2 100644 (file)
@@ -49,6 +49,8 @@
  *    - In some cases, MS-Windows will emit undocumented requests; this
  *     matters more to peripheral implementations than host ones.
  *
+ * Moreover there's a no-open-specs variant of RNDIS called "ActiveSync".
+ *
  * For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in
  * favor of such non-proprietary alternatives as CDC Ethernet or the newer (and
  * currently rare) "Ethernet Emulation Model" (EEM).
@@ -61,6 +63,9 @@
  *  - control-in:  GET_ENCAPSULATED
  *
  * We'll try to ignore the RESPONSE_AVAILABLE notifications.
+ *
+ * REVISIT some RNDIS implementations seem to have curious issues still
+ * to be resolved.
  */
 struct rndis_msg_hdr {
        __le32  msg_type;                       /* RNDIS_MSG_* */
@@ -71,8 +76,14 @@ struct rndis_msg_hdr {
        // ... and more
 } __attribute__ ((packed));
 
-/* RNDIS defines this (absurdly huge) control timeout */
-#define        RNDIS_CONTROL_TIMEOUT_MS        (10 * 1000)
+/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */
+#define        CONTROL_BUFFER_SIZE             1025
+
+/* RNDIS defines an (absurdly huge) 10 second control timeout,
+ * but ActiveSync seems to use a more usual 5 second timeout
+ * (which matches the USB 2.0 spec).
+ */
+#define        RNDIS_CONTROL_TIMEOUT_MS        (5 * 1000)
 
 
 #define ccpu2 __constant_cpu_to_le32
@@ -270,6 +281,7 @@ static void rndis_status(struct usbnet *dev, struct urb *urb)
 static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
 {
        struct cdc_state        *info = (void *) &dev->data;
+       int                     master_ifnum;
        int                     retval;
        unsigned                count;
        __le32                  rsp;
@@ -279,7 +291,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
         * disconnect(): either serialize, or dispatch responses on xid
         */
 
-       /* Issue the request; don't bother byteswapping our xid */
+       /* Issue the request; xid is unique, don't bother byteswapping it */
        if (likely(buf->msg_type != RNDIS_MSG_HALT
                        && buf->msg_type != RNDIS_MSG_RESET)) {
                xid = dev->xid++;
@@ -287,11 +299,12 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
                        xid = dev->xid++;
                buf->request_id = (__force __le32) xid;
        }
+       master_ifnum = info->control->cur_altsetting->desc.bInterfaceNumber;
        retval = usb_control_msg(dev->udev,
                usb_sndctrlpipe(dev->udev, 0),
                USB_CDC_SEND_ENCAPSULATED_COMMAND,
                USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-               0, info->u->bMasterInterface0,
+               0, master_ifnum,
                buf, le32_to_cpu(buf->msg_len),
                RNDIS_CONTROL_TIMEOUT_MS);
        if (unlikely(retval < 0 || xid == 0))
@@ -306,13 +319,13 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
         */
        rsp = buf->msg_type | RNDIS_MSG_COMPLETION;
        for (count = 0; count < 10; count++) {
-               memset(buf, 0, 1024);
+               memset(buf, 0, CONTROL_BUFFER_SIZE);
                retval = usb_control_msg(dev->udev,
                        usb_rcvctrlpipe(dev->udev, 0),
                        USB_CDC_GET_ENCAPSULATED_RESPONSE,
                        USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       0, info->u->bMasterInterface0,
-                       buf, 1024,
+                       0, master_ifnum,
+                       buf, CONTROL_BUFFER_SIZE,
                        RNDIS_CONTROL_TIMEOUT_MS);
                if (likely(retval >= 8)) {
                        msg_len = le32_to_cpu(buf->msg_len);
@@ -350,7 +363,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
                                        usb_sndctrlpipe(dev->udev, 0),
                                        USB_CDC_SEND_ENCAPSULATED_COMMAND,
                                        USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                                       0, info->u->bMasterInterface0,
+                                       0, master_ifnum,
                                        msg, sizeof *msg,
                                        RNDIS_CONTROL_TIMEOUT_MS);
                                if (unlikely(retval < 0))
@@ -393,38 +406,64 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
        u32                     tmp;
 
        /* we can't rely on i/o from stack working, or stack allocation */
-       u.buf = kmalloc(1024, GFP_KERNEL);
+       u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
        if (!u.buf)
                return -ENOMEM;
        retval = usbnet_generic_cdc_bind(dev, intf);
        if (retval < 0)
                goto fail;
 
-       net->hard_header_len += sizeof (struct rndis_data_hdr);
-
-       /* initialize; max transfer is 16KB at full speed */
        u.init->msg_type = RNDIS_MSG_INIT;
        u.init->msg_len = ccpu2(sizeof *u.init);
        u.init->major_version = ccpu2(1);
        u.init->minor_version = ccpu2(0);
-       u.init->max_transfer_size = ccpu2(net->mtu + net->hard_header_len);
 
+       /* max transfer (in spec) is 0x4000 at full speed, but for
+        * TX we'll stick to one Ethernet packet plus RNDIS framing.
+        * For RX we handle drivers that zero-pad to end-of-packet.
+        * Don't let userspace change these settings.
+        */
+       net->hard_header_len += sizeof (struct rndis_data_hdr);
+       dev->hard_mtu = net->mtu + net->hard_header_len;
+
+       dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1);
+       dev->rx_urb_size &= ~(dev->maxpacket - 1);
+       u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size);
+
+       net->change_mtu = NULL;
        retval = rndis_command(dev, u.header);
        if (unlikely(retval < 0)) {
                /* it might not even be an RNDIS device!! */
                dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
+               goto fail_and_release;
+       }
+       tmp = le32_to_cpu(u.init_c->max_transfer_size);
+       if (tmp < dev->hard_mtu) {
+               dev_err(&intf->dev,
+                       "dev can't take %u byte packets (max %u)\n",
+                       dev->hard_mtu, tmp);
                goto fail_and_release;
        }
-       dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size);
+
        /* REVISIT:  peripheral "alignment" request is ignored ... */
-       dev_dbg(&intf->dev, "hard mtu %u, align %d\n", dev->hard_mtu,
+       dev_dbg(&intf->dev,
+               "hard mtu %u (%u from dev), rx buflen %Zu, align %d\n",
+               dev->hard_mtu, tmp, dev->rx_urb_size,
                1 << le32_to_cpu(u.init_c->packet_alignment));
 
-       /* get designated host ethernet address */
-       memset(u.get, 0, sizeof *u.get);
+       /* Get designated host ethernet address.
+        *
+        * Adding a payload exactly the same size as the expected response
+        * payload is an evident requirement MSFT added for ActiveSync.
+        * This undocumented (and nonsensical) issue was found by sniffing
+        * protocol requests from the ActiveSync 4.1 Windows driver.
+        */
+       memset(u.get, 0, sizeof *u.get + 48);
        u.get->msg_type = RNDIS_MSG_QUERY;
-       u.get->msg_len = ccpu2(sizeof *u.get);
+       u.get->msg_len = ccpu2(sizeof *u.get + 48);
        u.get->oid = OID_802_3_PERMANENT_ADDRESS;
+       u.get->len = ccpu2(48);
+       u.get->offset = ccpu2(20);
 
        retval = rndis_command(dev, u.header);
        if (unlikely(retval < 0)) {
@@ -432,7 +471,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
                goto fail_and_release;
        }
        tmp = le32_to_cpu(u.get_c->offset);
-       if (unlikely((tmp + 8) > (1024 - ETH_ALEN)
+       if (unlikely((tmp + 8) > (CONTROL_BUFFER_SIZE - ETH_ALEN)
                        || u.get_c->len != ccpu2(ETH_ALEN))) {
                dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n",
                        tmp, le32_to_cpu(u.get_c->len));
@@ -598,6 +637,10 @@ static const struct usb_device_id  products [] = {
        /* RNDIS is MSFT's un-official variant of CDC ACM */
        USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
        .driver_info = (unsigned long) &rndis_info,
+}, {
+       /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */
+       USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1),
+       .driver_info = (unsigned long) &rndis_info,
 },
        { },            // END
 };
index 86bcf63..11dad42 100644 (file)
@@ -572,8 +572,20 @@ static void aircable_unthrottle(struct usb_serial_port *port)
                schedule_work(&priv->rx_work);
 }
 
+static struct usb_driver aircable_driver = {
+       .name =         "aircable",
+       .probe =        usb_serial_probe,
+       .disconnect =   usb_serial_disconnect,
+       .id_table =     id_table,
+       .no_dynamic_id =        1,
+};
+
 static struct usb_serial_driver aircable_device = {
-       .description =          "aircable",
+       .driver = {
+               .owner =        THIS_MODULE,
+               .name =         "aircable",
+       },
+       .usb_driver =           &aircable_driver,
        .id_table =             id_table,
        .num_ports =            1,
        .attach =               aircable_attach,
@@ -587,13 +599,6 @@ static struct usb_serial_driver aircable_device = {
        .unthrottle =           aircable_unthrottle,
 };
 
-static struct usb_driver aircable_driver = {
-       .name =         "aircable",
-       .probe =        usb_serial_probe,
-       .disconnect =   usb_serial_disconnect,
-       .id_table =     id_table,
-};
-
 static int __init aircable_init (void)
 {
        int retval;
index f2ca76a..0af42e3 100644 (file)
@@ -277,6 +277,7 @@ static struct usb_serial_driver airprime_device = {
                .owner =        THIS_MODULE,
                .name =         "airprime",
        },
+       .usb_driver =           &airprime_driver,
        .id_table =             id_table,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
index 5261cd2..edd6857 100644 (file)
@@ -444,6 +444,7 @@ static struct usb_driver ark3116_driver = {
        .probe =        usb_serial_probe,
        .disconnect =   usb_serial_disconnect,
        .id_table =     id_table,
+       .no_dynamic_id =        1,
 };
 
 static struct usb_serial_driver ark3116_device = {
@@ -452,6 +453,7 @@ static struct usb_serial_driver ark3116_device = {
                .name =         "ark3116",
        },
        .id_table =             id_table,
+       .usb_driver =           &ark3116_driver,
        .num_interrupt_in =     1,
        .num_bulk_in =          1,
        .num_bulk_out =         1,
index 38b4dae..3b800d2 100644 (file)
@@ -126,6 +126,7 @@ static struct usb_serial_driver belkin_device = {
                .name =         "belkin",
        },
        .description =          "Belkin / Peracom / GoHubs USB Serial Adapter",
+       .usb_driver =           &belkin_driver,
        .id_table =             id_table_combined,
        .num_interrupt_in =     1,
        .num_bulk_in =          1,
index 6542f22..c08a384 100644 (file)
@@ -103,11 +103,52 @@ exit:
        return retval;
 }
 
+#ifdef CONFIG_HOTPLUG
+static ssize_t store_new_id(struct device_driver *driver,
+                           const char *buf, size_t count)
+{
+       struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
+       ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+
+       if (retval >= 0 && usb_drv->usb_driver != NULL)
+               retval = usb_store_new_id(&usb_drv->usb_driver->dynids,
+                                         &usb_drv->usb_driver->drvwrap.driver,
+                                         buf, count);
+       return retval;
+}
+
+static struct driver_attribute drv_attrs[] = {
+       __ATTR(new_id, S_IWUSR, NULL, store_new_id),
+       __ATTR_NULL,
+};
+
+static void free_dynids(struct usb_serial_driver *drv)
+{
+       struct usb_dynid *dynid, *n;
+
+       spin_lock(&drv->dynids.lock);
+       list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
+               list_del(&dynid->node);
+               kfree(dynid);
+       }
+       spin_unlock(&drv->dynids.lock);
+}
+
+#else
+static struct driver_attribute drv_attrs[] = {
+       __ATTR_NULL,
+};
+static inline void free_dynids(struct usb_driver *drv)
+{
+}
+#endif
+
 struct bus_type usb_serial_bus_type = {
        .name =         "usb-serial",
        .match =        usb_serial_device_match,
        .probe =        usb_serial_device_probe,
        .remove =       usb_serial_device_remove,
+       .drv_attrs =    drv_attrs,
 };
 
 int usb_serial_bus_register(struct usb_serial_driver *driver)
@@ -115,6 +156,9 @@ int usb_serial_bus_register(struct usb_serial_driver *driver)
        int retval;
 
        driver->driver.bus = &usb_serial_bus_type;
+       spin_lock_init(&driver->dynids.lock);
+       INIT_LIST_HEAD(&driver->dynids.list);
+
        retval = driver_register(&driver->driver);
 
        return retval;
@@ -122,6 +166,7 @@ int usb_serial_bus_register(struct usb_serial_driver *driver)
 
 void usb_serial_bus_deregister(struct usb_serial_driver *driver)
 {
+       free_dynids(driver);
        driver_unregister(&driver->driver);
 }
 
index 7ebaffd..06b4fff 100644 (file)
@@ -89,6 +89,7 @@ static struct usb_serial_driver cp2101_device = {
                .owner =        THIS_MODULE,
                .name =         "cp2101",
        },
+       .usb_driver             = &cp2101_driver,
        .id_table               = id_table,
        .num_interrupt_in       = 0,
        .num_bulk_in            = 0,
index a63c328..4167753 100644 (file)
@@ -88,6 +88,7 @@ static struct usb_serial_driver cyberjack_device = {
                .name =         "cyberjack",
        },
        .description =          "Reiner SCT Cyberjack USB card reader",
+       .usb_driver =           &cyberjack_driver,
        .id_table =             id_table,
        .num_interrupt_in =     1,
        .num_bulk_in =          1,
@@ -98,7 +99,7 @@ static struct usb_serial_driver cyberjack_device = {
        .open =                 cyberjack_open,
        .close =                cyberjack_close,
        .write =                cyberjack_write,
-       .write_room =   cyberjack_write_room,
+       .write_room =           cyberjack_write_room,
        .read_int_callback =    cyberjack_read_int_callback,
        .read_bulk_callback =   cyberjack_read_bulk_callback,
        .write_bulk_callback =  cyberjack_write_bulk_callback,
index 6bc1f40..57b8e27 100644 (file)
@@ -193,6 +193,7 @@ static struct usb_serial_driver cypress_earthmate_device = {
                .name =                 "earthmate",
        },
        .description =                  "DeLorme Earthmate USB",
+       .usb_driver =                   &cypress_driver,
        .id_table =                     id_table_earthmate,
        .num_interrupt_in =             1,
        .num_interrupt_out =            1,
@@ -222,6 +223,7 @@ static struct usb_serial_driver cypress_hidcom_device = {
                .name =                 "cyphidcom",
        },
        .description =                  "HID->COM RS232 Adapter",
+       .usb_driver =                   &cypress_driver,
        .id_table =                     id_table_cyphidcomrs232,
        .num_interrupt_in =             1,
        .num_interrupt_out =            1,
@@ -251,6 +253,7 @@ static struct usb_serial_driver cypress_ca42v2_device = {
                 .name =                        "nokiaca42v2",
        },
        .description =                  "Nokia CA-42 V2 Adapter",
+       .usb_driver =                   &cypress_driver,
        .id_table =                     id_table_nokiaca42v2,
        .num_interrupt_in =             1,
        .num_interrupt_out =            1,
index efd9ce3..0b0fb51 100644 (file)
@@ -509,6 +509,7 @@ static struct usb_serial_driver digi_acceleport_2_device = {
                .name =                 "digi_2",
        },
        .description =                  "Digi 2 port USB adapter",
+       .usb_driver =                   &digi_driver,
        .id_table =                     id_table_2,
        .num_interrupt_in =             0,
        .num_bulk_in =                  4,
@@ -538,6 +539,7 @@ static struct usb_serial_driver digi_acceleport_4_device = {
                .name =                 "digi_4",
        },
        .description =                  "Digi 4 port USB adapter",
+       .usb_driver =                   &digi_driver,
        .id_table =                     id_table_4,
        .num_interrupt_in =             0,
        .num_bulk_in =                  5,
index 92beeb1..4703c8f 100644 (file)
@@ -117,6 +117,7 @@ static struct usb_serial_driver empeg_device = {
                .name =         "empeg",
        },
        .id_table =             id_table,
+       .usb_driver =           &empeg_driver,
        .num_interrupt_in =     0,
        .num_bulk_in =          1,
        .num_bulk_out =         1,
index 6986e75..4695952 100644 (file)
@@ -464,7 +464,6 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
        { USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) },
-       { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
        { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) },
@@ -615,6 +614,7 @@ static struct usb_serial_driver ftdi_sio_device = {
                .name =         "ftdi_sio",
        },
        .description =          "FTDI USB Serial Device",
+       .usb_driver =           &ftdi_driver ,
        .id_table =             id_table_combined,
        .num_interrupt_in =     0,
        .num_bulk_in =          1,
index 40dd394..7eff1c0 100644 (file)
  * USB-TTY activ, USB-TTY passiv.  Some PIDs are used by several devices
  * and I'm not entirely sure which are used by which.
  */
-#define FTDI_4N_GALAXY_DE_0_PID        0x8372
 #define FTDI_4N_GALAXY_DE_1_PID        0xF3C0
 #define FTDI_4N_GALAXY_DE_2_PID        0xF3C1
 
index 2bebd63..4092f6d 100644 (file)
@@ -58,6 +58,7 @@ static struct usb_serial_driver funsoft_device = {
                .name =         "funsoft",
        },
        .id_table =             id_table,
+       .usb_driver =           &funsoft_driver,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
        .num_bulk_out =         NUM_DONT_CARE,
index 6530d39..74660a3 100644 (file)
@@ -1566,6 +1566,7 @@ static struct usb_serial_driver garmin_device = {
                .name        = "garmin_gps",
        },
        .description         = "Garmin GPS usb/tty",
+       .usb_driver          = &garmin_driver,
        .id_table            = id_table,
        .num_interrupt_in    = 1,
        .num_bulk_in         = 1,
index 3604293..601e064 100644 (file)
 #include <linux/usb/serial.h>
 #include <asm/uaccess.h>
 
+static int generic_probe(struct usb_interface *interface,
+                        const struct usb_device_id *id);
+
+
 static int debug;
 
 #ifdef CONFIG_USB_SERIAL_GENERIC
@@ -34,6 +38,21 @@ MODULE_PARM_DESC(product, "User specified USB idProduct");
 
 static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */
 
+/* we want to look at all devices, as the vendor/product id can change
+ * depending on the command line argument */
+static struct usb_device_id generic_serial_ids[] = {
+       {.driver_info = 42},
+       {}
+};
+
+static struct usb_driver generic_driver = {
+       .name =         "usbserial_generic",
+       .probe =        generic_probe,
+       .disconnect =   usb_serial_disconnect,
+       .id_table =     generic_serial_ids,
+       .no_dynamic_id =        1,
+};
+
 /* All of the device info needed for the Generic Serial Converter */
 struct usb_serial_driver usb_serial_generic_device = {
        .driver = {
@@ -41,6 +60,7 @@ struct usb_serial_driver usb_serial_generic_device = {
                .name =         "generic",
        },
        .id_table =             generic_device_ids,
+       .usb_driver =           &generic_driver,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
        .num_bulk_out =         NUM_DONT_CARE,
@@ -48,13 +68,6 @@ struct usb_serial_driver usb_serial_generic_device = {
        .shutdown =             usb_serial_generic_shutdown,
 };
 
-/* we want to look at all devices, as the vendor/product id can change
- * depending on the command line argument */
-static struct usb_device_id generic_serial_ids[] = {
-       {.driver_info = 42},
-       {}
-};
-
 static int generic_probe(struct usb_interface *interface,
                               const struct usb_device_id *id)
 {
@@ -65,14 +78,6 @@ static int generic_probe(struct usb_interface *interface,
                return usb_serial_probe(interface, id);
        return -ENODEV;
 }
-
-static struct usb_driver generic_driver = {
-       .name =         "usbserial_generic",
-       .probe =        generic_probe,
-       .disconnect =   usb_serial_disconnect,
-       .id_table =     generic_serial_ids,
-       .no_dynamic_id =        1,
-};
 #endif
 
 int usb_serial_generic_register (int _debug)
index ebcac70..6c6ebae 100644 (file)
@@ -49,6 +49,7 @@ static struct usb_serial_driver hp49gp_device = {
                .name =         "hp4X",
        },
        .id_table =             id_table,
+       .usb_driver =           &hp49gp_driver,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
        .num_bulk_out =         NUM_DONT_CARE,
index f623d58..6a26a2e 100644 (file)
@@ -146,6 +146,8 @@ struct edgeport_serial {
        struct edge_manuf_descriptor    manuf_descriptor;       /* the manufacturer descriptor */
        struct edge_boot_descriptor     boot_descriptor;        /* the boot firmware descriptor */
        struct edgeport_product_info    product_info;           /* Product Info */
+       struct edge_compatibility_descriptor epic_descriptor;   /* Edgeport compatible descriptor */
+       int                     is_epic;                        /* flag if EPiC device or not */
 
        __u8                    interrupt_in_endpoint;          /* the interrupt endpoint handle */
        unsigned char *         interrupt_in_buffer;            /* the buffer we use for the interrupt endpoint */
@@ -240,14 +242,6 @@ static void edge_shutdown          (struct usb_serial *serial);
 
 #include "io_tables.h" /* all of the devices that this driver supports */
 
-static struct usb_driver io_driver = {
-       .name =         "io_edgeport",
-       .probe =        usb_serial_probe,
-       .disconnect =   usb_serial_disconnect,
-       .id_table =     id_table_combined,
-       .no_dynamic_id =        1,
-};
-
 /* function prototypes for all of our local functions */
 static void  process_rcvd_data         (struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength);
 static void process_rcvd_status                (struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3);
@@ -397,6 +391,7 @@ static int get_string (struct usb_device *dev, int Id, char *string, int buflen)
        unicode_to_ascii(string, buflen, pStringDesc->wData, pStringDesc->bLength/2);
 
        kfree(pStringDesc);
+       dbg("%s - USB String %s", __FUNCTION__, string);
        return strlen(string);
 }
 
@@ -434,6 +429,34 @@ static int get_string_desc (struct usb_device *dev, int Id, struct usb_string_de
 }
 #endif
 
+static void dump_product_info(struct edgeport_product_info *product_info)
+{
+       // Dump Product Info structure
+       dbg("**Product Information:");
+       dbg("  ProductId             %x", product_info->ProductId );
+       dbg("  NumPorts              %d", product_info->NumPorts );
+       dbg("  ProdInfoVer           %d", product_info->ProdInfoVer );
+       dbg("  IsServer              %d", product_info->IsServer);
+       dbg("  IsRS232               %d", product_info->IsRS232 );
+       dbg("  IsRS422               %d", product_info->IsRS422 );
+       dbg("  IsRS485               %d", product_info->IsRS485 );
+       dbg("  RomSize               %d", product_info->RomSize );
+       dbg("  RamSize               %d", product_info->RamSize );
+       dbg("  CpuRev                %x", product_info->CpuRev  );
+       dbg("  BoardRev              %x", product_info->BoardRev);
+       dbg("  BootMajorVersion      %d.%d.%d", product_info->BootMajorVersion,
+           product_info->BootMinorVersion,
+           le16_to_cpu(product_info->BootBuildNumber));
+       dbg("  FirmwareMajorVersion  %d.%d.%d", product_info->FirmwareMajorVersion,
+           product_info->FirmwareMinorVersion,
+           le16_to_cpu(product_info->FirmwareBuildNumber));
+       dbg("  ManufactureDescDate   %d/%d/%d", product_info->ManufactureDescDate[0],
+           product_info->ManufactureDescDate[1],
+           product_info->ManufactureDescDate[2]+1900);
+       dbg("  iDownloadFile         0x%x", product_info->iDownloadFile);
+       dbg("  EpicVer               %d", product_info->EpicVer);
+}
+
 static void get_product_info(struct edgeport_serial *edge_serial)
 {
        struct edgeport_product_info *product_info = &edge_serial->product_info;
@@ -495,30 +518,60 @@ static void get_product_info(struct edgeport_serial *edge_serial)
                        break;
        }
 
-       // Dump Product Info structure
-       dbg("**Product Information:");
-       dbg("  ProductId             %x", product_info->ProductId );
-       dbg("  NumPorts              %d", product_info->NumPorts );
-       dbg("  ProdInfoVer           %d", product_info->ProdInfoVer );
-       dbg("  IsServer              %d", product_info->IsServer);
-       dbg("  IsRS232               %d", product_info->IsRS232 );
-       dbg("  IsRS422               %d", product_info->IsRS422 );
-       dbg("  IsRS485               %d", product_info->IsRS485 );
-       dbg("  RomSize               %d", product_info->RomSize );
-       dbg("  RamSize               %d", product_info->RamSize );
-       dbg("  CpuRev                %x", product_info->CpuRev  );
-       dbg("  BoardRev              %x", product_info->BoardRev);
-       dbg("  BootMajorVersion      %d.%d.%d", product_info->BootMajorVersion,
-           product_info->BootMinorVersion,
-           le16_to_cpu(product_info->BootBuildNumber));
-       dbg("  FirmwareMajorVersion  %d.%d.%d", product_info->FirmwareMajorVersion,
-           product_info->FirmwareMinorVersion,
-           le16_to_cpu(product_info->FirmwareBuildNumber));
-       dbg("  ManufactureDescDate   %d/%d/%d", product_info->ManufactureDescDate[0],
-           product_info->ManufactureDescDate[1],
-           product_info->ManufactureDescDate[2]+1900);
-       dbg("  iDownloadFile         0x%x",     product_info->iDownloadFile);
+       dump_product_info(product_info);
+}
 
+static int get_epic_descriptor(struct edgeport_serial *ep)
+{
+       int result;
+       struct usb_serial *serial = ep->serial;
+       struct edgeport_product_info *product_info = &ep->product_info;
+       struct edge_compatibility_descriptor *epic = &ep->epic_descriptor;
+       struct edge_compatibility_bits *bits;
+
+       ep->is_epic = 0;
+       result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+                                USB_REQUEST_ION_GET_EPIC_DESC,
+                                0xC0, 0x00, 0x00,
+                                &ep->epic_descriptor,
+                                sizeof(struct edge_compatibility_descriptor),
+                                300);
+
+       dbg("%s result = %d", __FUNCTION__, result);
+
+       if (result > 0) {
+               ep->is_epic = 1;
+               memset(product_info, 0, sizeof(struct edgeport_product_info));
+
+               product_info->NumPorts                  = epic->NumPorts;
+               product_info->ProdInfoVer               = 0;
+               product_info->FirmwareMajorVersion      = epic->MajorVersion;
+               product_info->FirmwareMinorVersion      = epic->MinorVersion;
+               product_info->FirmwareBuildNumber       = epic->BuildNumber;
+               product_info->iDownloadFile             = epic->iDownloadFile;
+               product_info->EpicVer                   = epic->EpicVer;
+               product_info->Epic                      = epic->Supports;
+               product_info->ProductId                 = ION_DEVICE_ID_EDGEPORT_COMPATIBLE;
+               dump_product_info(product_info);
+
+               bits = &ep->epic_descriptor.Supports;
+               dbg("**EPIC descriptor:");
+               dbg("  VendEnableSuspend: %s", bits->VendEnableSuspend  ? "TRUE": "FALSE");
+               dbg("  IOSPOpen         : %s", bits->IOSPOpen           ? "TRUE": "FALSE" );
+               dbg("  IOSPClose        : %s", bits->IOSPClose          ? "TRUE": "FALSE" );
+               dbg("  IOSPChase        : %s", bits->IOSPChase          ? "TRUE": "FALSE" );
+               dbg("  IOSPSetRxFlow    : %s", bits->IOSPSetRxFlow      ? "TRUE": "FALSE" );
+               dbg("  IOSPSetTxFlow    : %s", bits->IOSPSetTxFlow      ? "TRUE": "FALSE" );
+               dbg("  IOSPSetXChar     : %s", bits->IOSPSetXChar       ? "TRUE": "FALSE" );
+               dbg("  IOSPRxCheck      : %s", bits->IOSPRxCheck        ? "TRUE": "FALSE" );
+               dbg("  IOSPSetClrBreak  : %s", bits->IOSPSetClrBreak    ? "TRUE": "FALSE" );
+               dbg("  IOSPWriteMCR     : %s", bits->IOSPWriteMCR       ? "TRUE": "FALSE" );
+               dbg("  IOSPWriteLCR     : %s", bits->IOSPWriteLCR       ? "TRUE": "FALSE" );
+               dbg("  IOSPSetBaudRate  : %s", bits->IOSPSetBaudRate    ? "TRUE": "FALSE" );
+               dbg("  TrueEdgeport     : %s", bits->TrueEdgeport       ? "TRUE": "FALSE" );
+       }
+
+       return result;
 }
 
 
@@ -1017,21 +1070,29 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
 
        edge_port->closePending = TRUE;
 
-       /* flush and chase */
-       edge_port->chaseResponsePending = TRUE;
-
-       dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
-       status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
-       if (status == 0) {
-               // block until chase finished
-               block_until_chase_response(edge_port);
-       } else {
-               edge_port->chaseResponsePending = FALSE;
+       if ((!edge_serial->is_epic) ||
+           ((edge_serial->is_epic) &&
+            (edge_serial->epic_descriptor.Supports.IOSPChase))) {
+               /* flush and chase */
+               edge_port->chaseResponsePending = TRUE;
+
+               dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
+               status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
+               if (status == 0) {
+                       // block until chase finished
+                       block_until_chase_response(edge_port);
+               } else {
+                       edge_port->chaseResponsePending = FALSE;
+               }
        }
 
-       /* close the port */
-       dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__);
-       send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
+       if ((!edge_serial->is_epic) ||
+           ((edge_serial->is_epic) &&
+            (edge_serial->epic_descriptor.Supports.IOSPClose))) {
+              /* close the port */
+               dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__);
+               send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
+       }
 
        //port->close = TRUE;
        edge_port->closePending = FALSE;
@@ -1694,29 +1755,38 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned
 static void edge_break (struct usb_serial_port *port, int break_state)
 {
        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+       struct edgeport_serial *edge_serial = usb_get_serial_data(port->serial);
        int status;
 
-       /* flush and chase */
-       edge_port->chaseResponsePending = TRUE;
-
-       dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
-       status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
-       if (status == 0) {
-               // block until chase finished
-               block_until_chase_response(edge_port);
-       } else {
-               edge_port->chaseResponsePending = FALSE;
+       if ((!edge_serial->is_epic) ||
+           ((edge_serial->is_epic) &&
+            (edge_serial->epic_descriptor.Supports.IOSPChase))) {
+               /* flush and chase */
+               edge_port->chaseResponsePending = TRUE;
+
+               dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
+               status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
+               if (status == 0) {
+                       // block until chase finished
+                       block_until_chase_response(edge_port);
+               } else {
+                       edge_port->chaseResponsePending = FALSE;
+               }
        }
 
-       if (break_state == -1) {
-               dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__);
-               status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0);
-       } else {
-               dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__);
-               status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0);
-       }
-       if (status) {
-               dbg("%s - error sending break set/clear command.", __FUNCTION__);
+       if ((!edge_serial->is_epic) ||
+           ((edge_serial->is_epic) &&
+            (edge_serial->epic_descriptor.Supports.IOSPSetClrBreak))) {
+               if (break_state == -1) {
+                       dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__);
+                       status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0);
+               } else {
+                       dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__);
+                       status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0);
+               }
+               if (status) {
+                       dbg("%s - error sending break set/clear command.", __FUNCTION__);
+               }
        }
 
        return;
@@ -2288,6 +2358,7 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer
  *****************************************************************************/
 static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate)
 {
+       struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
        unsigned char *cmdBuffer;
        unsigned char *currCmd;
        int cmdLen = 0;
@@ -2295,6 +2366,14 @@ static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRa
        int status;
        unsigned char number = edge_port->port->number - edge_port->port->serial->minor;
 
+       if ((!edge_serial->is_epic) ||
+           ((edge_serial->is_epic) &&
+            (!edge_serial->epic_descriptor.Supports.IOSPSetBaudRate))) {
+               dbg("SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d",
+                   edge_port->port->number, baudRate);
+               return 0;
+       }
+
        dbg("%s - port = %d, baud = %d", __FUNCTION__, edge_port->port->number, baudRate);
 
        status = calc_baud_rate_divisor (baudRate, &divisor);
@@ -2374,6 +2453,7 @@ static int calc_baud_rate_divisor (int baudrate, int *divisor)
  *****************************************************************************/
 static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue)
 {
+       struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
        unsigned char *cmdBuffer;
        unsigned char *currCmd;
        unsigned long cmdLen = 0;
@@ -2381,6 +2461,22 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
 
        dbg("%s - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", __FUNCTION__, regValue);
 
+       if ((!edge_serial->is_epic) ||
+           ((edge_serial->is_epic) &&
+            (!edge_serial->epic_descriptor.Supports.IOSPWriteMCR) &&
+            (regNum == MCR))) {
+               dbg("SendCmdWriteUartReg - Not writting to MCR Register");
+               return 0;
+       }
+
+       if ((!edge_serial->is_epic) ||
+           ((edge_serial->is_epic) &&
+            (!edge_serial->epic_descriptor.Supports.IOSPWriteLCR) &&
+            (regNum == LCR))) {
+               dbg ("SendCmdWriteUartReg - Not writting to LCR Register");
+               return 0;
+       }
+
        // Alloc memory for the string of commands.
        cmdBuffer = kmalloc (0x10, GFP_ATOMIC);
        if (cmdBuffer == NULL ) {
@@ -2414,6 +2510,7 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
 #endif
 static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios)
 {
+       struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
        struct tty_struct *tty;
        int baud;
        unsigned cflag;
@@ -2494,8 +2591,12 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
                unsigned char stop_char  = STOP_CHAR(tty);
                unsigned char start_char = START_CHAR(tty);
 
-               send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XON_CHAR, start_char);
-               send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char);
+               if ((!edge_serial->is_epic) ||
+                   ((edge_serial->is_epic) &&
+                    (edge_serial->epic_descriptor.Supports.IOSPSetXChar))) {
+                       send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XON_CHAR, start_char);
+                       send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char);
+               }
 
                /* if we are implementing INBOUND XON/XOFF */
                if (I_IXOFF(tty)) {
@@ -2515,8 +2616,14 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
        }
 
        /* Set flow control to the configured value */
-       send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow);
-       send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_TX_FLOW, txFlow);
+       if ((!edge_serial->is_epic) ||
+           ((edge_serial->is_epic) &&
+            (edge_serial->epic_descriptor.Supports.IOSPSetRxFlow)))
+               send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow);
+       if ((!edge_serial->is_epic) ||
+           ((edge_serial->is_epic) &&
+            (edge_serial->epic_descriptor.Supports.IOSPSetTxFlow)))
+               send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_TX_FLOW, txFlow);
 
 
        edge_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
@@ -2728,6 +2835,13 @@ static int edge_startup (struct usb_serial *serial)
        struct edgeport_port *edge_port;
        struct usb_device *dev;
        int i, j;
+       int response;
+       int interrupt_in_found;
+       int bulk_in_found;
+       int bulk_out_found;
+       static __u32 descriptor[3] = {  EDGE_COMPATIBILITY_MASK0,
+                                       EDGE_COMPATIBILITY_MASK1,
+                                       EDGE_COMPATIBILITY_MASK2 };
 
        dev = serial->dev;
 
@@ -2750,38 +2864,50 @@ static int edge_startup (struct usb_serial *serial)
 
        dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name);
 
-       /* get the manufacturing descriptor for this device */
-       get_manufacturing_desc (edge_serial);
+       /* Read the epic descriptor */
+       if (get_epic_descriptor(edge_serial) <= 0) {
+               /* memcpy descriptor to Supports structures */
+               memcpy(&edge_serial->epic_descriptor.Supports, descriptor,
+                      sizeof(struct edge_compatibility_bits));
+
+               /* get the manufacturing descriptor for this device */
+               get_manufacturing_desc (edge_serial);
 
-       /* get the boot descriptor */
-       get_boot_desc (edge_serial);
+               /* get the boot descriptor */
+               get_boot_desc (edge_serial);
 
-       get_product_info(edge_serial);
+               get_product_info(edge_serial);
+       }
 
        /* set the number of ports from the manufacturing description */
        /* serial->num_ports = serial->product_info.NumPorts; */
-       if (edge_serial->product_info.NumPorts != serial->num_ports) {
-               warn("%s - Device Reported %d serial ports vs core "
-                    "thinking we have %d ports, email greg@kroah.com this info.",
-                    __FUNCTION__, edge_serial->product_info.NumPorts, 
-                    serial->num_ports);
+       if ((!edge_serial->is_epic) &&
+           (edge_serial->product_info.NumPorts != serial->num_ports)) {
+               dev_warn(&serial->dev->dev, "Device Reported %d serial ports "
+                        "vs. core thinking we have %d ports, email "
+                        "greg@kroah.com this information.",
+                        edge_serial->product_info.NumPorts,
+                        serial->num_ports);
        }
 
        dbg("%s - time 1 %ld", __FUNCTION__, jiffies);
 
-       /* now load the application firmware into this device */
-       load_application_firmware (edge_serial);
+       /* If not an EPiC device */
+       if (!edge_serial->is_epic) {
+               /* now load the application firmware into this device */
+               load_application_firmware (edge_serial);
 
-       dbg("%s - time 2 %ld", __FUNCTION__, jiffies);
+               dbg("%s - time 2 %ld", __FUNCTION__, jiffies);
 
-       /* Check current Edgeport EEPROM and update if necessary */
-       update_edgeport_E2PROM (edge_serial);
-       
-       dbg("%s - time 3 %ld", __FUNCTION__, jiffies);
+               /* Check current Edgeport EEPROM and update if necessary */
+               update_edgeport_E2PROM (edge_serial);
 
-       /* set the configuration to use #1 */
-//     dbg("set_configuration 1");
-//     usb_set_configuration (dev, 1);
+               dbg("%s - time 3 %ld", __FUNCTION__, jiffies);
+
+               /* set the configuration to use #1 */
+//             dbg("set_configuration 1");
+//             usb_set_configuration (dev, 1);
+       }
 
        /* we set up the pointers to the endpoints in the edge_open function, 
         * as the structures aren't created yet. */
@@ -2804,8 +2930,101 @@ static int edge_startup (struct usb_serial *serial)
                edge_port->port = serial->port[i];
                usb_set_serial_port_data(serial->port[i], edge_port);
        }
-       
-       return 0;
+
+       response = 0;
+
+       if (edge_serial->is_epic) {
+               /* EPIC thing, set up our interrupt polling now and our read urb, so
+                * that the device knows it really is connected. */
+               interrupt_in_found = bulk_in_found = bulk_out_found = FALSE;
+               for (i = 0; i < serial->interface->altsetting[0].desc.bNumEndpoints; ++i) {
+                       struct usb_endpoint_descriptor *endpoint;
+                       int buffer_size;
+
+                       endpoint = &serial->interface->altsetting[0].endpoint[i].desc;
+                       buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+                       if ((!interrupt_in_found) &&
+                           (usb_endpoint_is_int_in(endpoint))) {
+                               /* we found a interrupt in endpoint */
+                               dbg("found interrupt in");
+
+                               /* not set up yet, so do it now */
+                               edge_serial->interrupt_read_urb = usb_alloc_urb(0, GFP_KERNEL);
+                               if (!edge_serial->interrupt_read_urb) {
+                                       err("out of memory");
+                                       return -ENOMEM;
+                               }
+                               edge_serial->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+                               if (!edge_serial->interrupt_in_buffer) {
+                                       err("out of memory");
+                                       usb_free_urb(edge_serial->interrupt_read_urb);
+                                       return -ENOMEM;
+                               }
+                               edge_serial->interrupt_in_endpoint = endpoint->bEndpointAddress;
+
+                               /* set up our interrupt urb */
+                               usb_fill_int_urb(edge_serial->interrupt_read_urb,
+                                                dev,
+                                                usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+                                                edge_serial->interrupt_in_buffer,
+                                                buffer_size,
+                                                edge_interrupt_callback,
+                                                edge_serial,
+                                                endpoint->bInterval);
+
+                               interrupt_in_found = TRUE;
+                       }
+
+                       if ((!bulk_in_found) &&
+                           (usb_endpoint_is_bulk_in(endpoint))) {
+                               /* we found a bulk in endpoint */
+                               dbg("found bulk in");
+
+                               /* not set up yet, so do it now */
+                               edge_serial->read_urb = usb_alloc_urb(0, GFP_KERNEL);
+                               if (!edge_serial->read_urb) {
+                                       err("out of memory");
+                                       return -ENOMEM;
+                               }
+                               edge_serial->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+                               if (!edge_serial->bulk_in_buffer) {
+                                       err ("out of memory");
+                                       usb_free_urb(edge_serial->read_urb);
+                                       return -ENOMEM;
+                               }
+                               edge_serial->bulk_in_endpoint = endpoint->bEndpointAddress;
+
+                               /* set up our bulk in urb */
+                               usb_fill_bulk_urb(edge_serial->read_urb, dev,
+                                                 usb_rcvbulkpipe(dev, endpoint->bEndpointAddress),
+                                                 edge_serial->bulk_in_buffer,
+                                                 endpoint->wMaxPacketSize,
+                                                 edge_bulk_in_callback,
+                                                 edge_serial);
+                               bulk_in_found = TRUE;
+                       }
+
+                       if ((!bulk_out_found) &&
+                           (usb_endpoint_is_bulk_out(endpoint))) {
+                               /* we found a bulk out endpoint */
+                               dbg("found bulk out");
+                               edge_serial->bulk_out_endpoint = endpoint->bEndpointAddress;
+                               bulk_out_found = TRUE;
+                       }
+               }
+
+               if ((!interrupt_in_found) || (!bulk_in_found) || (!bulk_out_found)) {
+                       err ("Error - the proper endpoints were not found!");
+                       return -ENODEV;
+               }
+
+               /* start interrupt read for this edgeport this interrupt will
+                * continue as long as the edgeport is connected */
+               response = usb_submit_urb(edge_serial->interrupt_read_urb, GFP_KERNEL);
+               if (response)
+                       err("%s - Error %d submitting control urb", __FUNCTION__, response);
+       }
+       return response;
 }
 
 
@@ -2815,6 +3034,7 @@ static int edge_startup (struct usb_serial *serial)
  ****************************************************************************/
 static void edge_shutdown (struct usb_serial *serial)
 {
+       struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
        int i;
 
        dbg("%s", __FUNCTION__);
@@ -2824,7 +3044,18 @@ static void edge_shutdown (struct usb_serial *serial)
                kfree (usb_get_serial_port_data(serial->port[i]));
                usb_set_serial_port_data(serial->port[i],  NULL);
        }
-       kfree (usb_get_serial_data(serial));
+       /* free up our endpoint stuff */
+       if (edge_serial->is_epic) {
+               usb_unlink_urb(edge_serial->interrupt_read_urb);
+               usb_free_urb(edge_serial->interrupt_read_urb);
+               kfree(edge_serial->interrupt_in_buffer);
+
+               usb_unlink_urb(edge_serial->read_urb);
+               usb_free_urb(edge_serial->read_urb);
+               kfree(edge_serial->bulk_in_buffer);
+       }
+
+       kfree(edge_serial);
        usb_set_serial_data(serial, NULL);
 }
 
@@ -2846,6 +3077,9 @@ static int __init edgeport_init(void)
        retval = usb_serial_register(&edgeport_8port_device);
        if (retval)
                goto failed_8port_device_register;
+       retval = usb_serial_register(&epic_device);
+       if (retval)
+               goto failed_epic_device_register;
        retval = usb_register(&io_driver);
        if (retval) 
                goto failed_usb_register;
@@ -2853,6 +3087,8 @@ static int __init edgeport_init(void)
        return 0;
 
 failed_usb_register:
+       usb_serial_deregister(&epic_device);
+failed_epic_device_register:
        usb_serial_deregister(&edgeport_8port_device);
 failed_8port_device_register:
        usb_serial_deregister(&edgeport_4port_device);
@@ -2873,6 +3109,7 @@ static void __exit edgeport_exit (void)
        usb_serial_deregister (&edgeport_2port_device);
        usb_serial_deregister (&edgeport_4port_device);
        usb_serial_deregister (&edgeport_8port_device);
+       usb_serial_deregister (&epic_device);
 }
 
 module_init(edgeport_init);
index 123fa8a..29a913a 100644 (file)
@@ -111,10 +111,12 @@ struct edgeport_product_info {
        __le16  FirmwareBuildNumber;            /*                              zzzz (LE format) */
 
        __u8    ManufactureDescDate[3];         /* MM/DD/YY when descriptor template was compiled */
-       __u8    Unused1[1];                     /* Available */
+       __u8    HardwareType;
 
        __u8    iDownloadFile;                  /* What to download to EPiC device */
-       __u8    Unused2[2];                     /* Available */
+       __u8    EpicVer;                        /* What version of EPiC spec this device supports */
+
+       struct edge_compatibility_bits Epic;
 };
 
 /*
index fad561c..6d30087 100644 (file)
@@ -47,6 +47,18 @@ static struct usb_device_id edgeport_8port_id_table [] = {
        { }
 };
 
+static struct usb_device_id Epic_port_id_table [] = {
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) },
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) },
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) },
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) },
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) },
+       { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) },
+       { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) },
+       { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) },
+       { }
+};
+
 /* Devices that this driver supports */
 static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) },
@@ -70,17 +82,34 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) },
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) },
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) },
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) },
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) },
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) },
+       { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) },
+       { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) },
+       { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) },
        { }                                                     /* Terminating entry */
 };
 
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
+static struct usb_driver io_driver = {
+       .name =         "io_edgeport",
+       .probe =        usb_serial_probe,
+       .disconnect =   usb_serial_disconnect,
+       .id_table =     id_table_combined,
+       .no_dynamic_id =        1,
+};
+
 static struct usb_serial_driver edgeport_2port_device = {
        .driver = {
                .owner          = THIS_MODULE,
                .name           = "edgeport_2",
        },
        .description            = "Edgeport 2 port adapter",
+       .usb_driver             = &io_driver,
        .id_table               = edgeport_2port_id_table,
        .num_interrupt_in       = 1,
        .num_bulk_in            = 1,
@@ -111,6 +140,7 @@ static struct usb_serial_driver edgeport_4port_device = {
                .name           = "edgeport_4",
        },
        .description            = "Edgeport 4 port adapter",
+       .usb_driver             = &io_driver,
        .id_table               = edgeport_4port_id_table,
        .num_interrupt_in       = 1,
        .num_bulk_in            = 1,
@@ -141,6 +171,7 @@ static struct usb_serial_driver edgeport_8port_device = {
                .name           = "edgeport_8",
        },
        .description            = "Edgeport 8 port adapter",
+       .usb_driver             = &io_driver,
        .id_table               = edgeport_8port_id_table,
        .num_interrupt_in       = 1,
        .num_bulk_in            = 1,
@@ -165,5 +196,35 @@ static struct usb_serial_driver edgeport_8port_device = {
        .write_bulk_callback    = edge_bulk_out_data_callback,
 };
 
+static struct usb_serial_driver epic_device = {
+       .driver = {
+               .owner          = THIS_MODULE,
+               .name           = "epic",
+       },
+       .description            = "EPiC device",
+       .id_table               = Epic_port_id_table,
+       .num_interrupt_in       = 1,
+       .num_bulk_in            = 1,
+       .num_bulk_out           = 1,
+       .num_ports              = 1,
+       .open                   = edge_open,
+       .close                  = edge_close,
+       .throttle               = edge_throttle,
+       .unthrottle             = edge_unthrottle,
+       .attach                 = edge_startup,
+       .shutdown               = edge_shutdown,
+       .ioctl                  = edge_ioctl,
+       .set_termios            = edge_set_termios,
+       .tiocmget               = edge_tiocmget,
+       .tiocmset               = edge_tiocmset,
+       .write                  = edge_write,
+       .write_room             = edge_write_room,
+       .chars_in_buffer        = edge_chars_in_buffer,
+       .break_ctl              = edge_break,
+       .read_int_callback      = edge_interrupt_callback,
+       .read_bulk_callback     = edge_bulk_in_callback,
+       .write_bulk_callback    = edge_bulk_out_data_callback,
+};
+
 #endif
 
index 980285c..544098d 100644 (file)
@@ -2979,6 +2979,7 @@ static struct usb_serial_driver edgeport_1port_device = {
                .name           = "edgeport_ti_1",
        },
        .description            = "Edgeport TI 1 port adapter",
+       .usb_driver             = &io_driver,
        .id_table               = edgeport_1port_id_table,
        .num_interrupt_in       = 1,
        .num_bulk_in            = 1,
@@ -3009,6 +3010,7 @@ static struct usb_serial_driver edgeport_2port_device = {
                .name           = "edgeport_ti_2",
        },
        .description            = "Edgeport TI 2 port adapter",
+       .usb_driver             = &io_driver,
        .id_table               = edgeport_2port_id_table,
        .num_interrupt_in       = 1,
        .num_bulk_in            = 2,
index f1804fd..e57fa11 100644 (file)
@@ -30,6 +30,7 @@
 
 #define        USB_VENDOR_ID_ION       0x1608          // Our VID
 #define        USB_VENDOR_ID_TI        0x0451          // TI VID
+#define USB_VENDOR_ID_AXIOHM   0x05D9          /* Axiohm VID */
 
 //
 // Definitions of USB product IDs (PID)
@@ -334,6 +335,10 @@ struct edge_compatibility_bits
 
 };
 
+#define EDGE_COMPATIBILITY_MASK0       0x0001
+#define EDGE_COMPATIBILITY_MASK1       0x3FFF
+#define EDGE_COMPATIBILITY_MASK2       0x0001
+
 struct edge_compatibility_descriptor
 {
        __u8    Length;                         // Descriptor Length (per USB spec)
index 42f757a..a408184 100644 (file)
@@ -563,6 +563,7 @@ static struct usb_serial_driver ipaq_device = {
                .name =         "ipaq",
        },
        .description =          "PocketPC PDA",
+       .usb_driver =           &ipaq_driver,
        .id_table =             ipaq_id_table,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          1,
index d3b9a35..1bc5860 100644 (file)
@@ -442,6 +442,7 @@ static struct usb_serial_driver ipw_device = {
                .name =         "ipw",
        },
        .description =          "IPWireless converter",
+       .usb_driver =           &usb_ipw_driver,
        .id_table =             usb_ipw_ids,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          1,
index 8fdf486..9d847f6 100644 (file)
@@ -138,6 +138,7 @@ static struct usb_serial_driver ir_device = {
                .name =         "ir-usb",
        },
        .description =          "IR Dongle",
+       .usb_driver =           &ir_driver,
        .id_table =             id_table,
        .num_interrupt_in =     1,
        .num_bulk_in =          1,
index 9d2fdfd..e6966f1 100644 (file)
@@ -1275,11 +1275,31 @@ static int keyspan_fake_startup (struct usb_serial *serial)
 }
 
 /* Helper functions used by keyspan_setup_urbs */
+static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
+                                                    int endpoint)
+{
+       struct usb_host_interface *iface_desc;
+       struct usb_endpoint_descriptor *ep;
+       int i;
+
+       iface_desc = serial->interface->cur_altsetting;
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+               ep = &iface_desc->endpoint[i].desc;
+               if (ep->bEndpointAddress == endpoint)
+                       return ep;
+       }
+       dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
+                "endpoint %x\n", endpoint);
+       return NULL;
+}
+
 static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
                                      int dir, void *ctx, char *buf, int len,
                                      void (*callback)(struct urb *))
 {
        struct urb *urb;
+       struct usb_endpoint_descriptor const *ep_desc;
+       char const *ep_type_name;
 
        if (endpoint == -1)
                return NULL;            /* endpoint not needed */
@@ -1291,11 +1311,32 @@ static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
                return NULL;
        }
 
-               /* Fill URB using supplied data. */
-       usb_fill_bulk_urb(urb, serial->dev,
-                     usb_sndbulkpipe(serial->dev, endpoint) | dir,
-                     buf, len, callback, ctx);
+       ep_desc = find_ep(serial, endpoint);
+       if (!ep_desc) {
+               /* leak the urb, something's wrong and the callers don't care */
+               return urb;
+       }
+       if (usb_endpoint_xfer_int(ep_desc)) {
+               ep_type_name = "INT";
+               usb_fill_int_urb(urb, serial->dev,
+                                usb_sndintpipe(serial->dev, endpoint) | dir,
+                                buf, len, callback, ctx,
+                                ep_desc->bInterval);
+       } else if (usb_endpoint_xfer_bulk(ep_desc)) {
+               ep_type_name = "BULK";
+               usb_fill_bulk_urb(urb, serial->dev,
+                                 usb_sndbulkpipe(serial->dev, endpoint) | dir,
+                                 buf, len, callback, ctx);
+       } else {
+               dev_warn(&serial->interface->dev,
+                        "unsupported endpoint type %x\n",
+                        ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+               usb_free_urb(urb);
+               return NULL;
+       }
 
+       dbg("%s - using urb %p for %s endpoint %x",
+           __func__, urb, ep_type_name, endpoint);
        return urb;
 }
 
index 6413d73..c6830cb 100644 (file)
@@ -229,7 +229,6 @@ struct ezusb_hex_record {
 #define        keyspan_usa28_product_id                0x010f
 #define        keyspan_usa28x_product_id               0x0110
 #define        keyspan_usa28xa_product_id              0x0115
-#define        keyspan_usa28xb_product_id              0x0110
 #define        keyspan_usa49w_product_id               0x010a
 #define        keyspan_usa49wlc_product_id             0x012a
 
@@ -511,7 +510,6 @@ static struct usb_device_id keyspan_ids_combined[] = {
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
-       { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)},
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
        { } /* Terminating entry */
@@ -559,7 +557,6 @@ static struct usb_device_id keyspan_2port_ids[] = {
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
-       { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
        { } /* Terminating entry */
 };
 
@@ -576,6 +573,7 @@ static struct usb_serial_driver keyspan_pre_device = {
                .name           = "keyspan_no_firm",
        },
        .description            = "Keyspan - (without firmware)",
+       .usb_driver             = &keyspan_driver,
        .id_table               = keyspan_pre_ids,
        .num_interrupt_in       = NUM_DONT_CARE,
        .num_bulk_in            = NUM_DONT_CARE,
@@ -590,6 +588,7 @@ static struct usb_serial_driver keyspan_1port_device = {
                .name           = "keyspan_1",
        },
        .description            = "Keyspan 1 port adapter",
+       .usb_driver             = &keyspan_driver,
        .id_table               = keyspan_1port_ids,
        .num_interrupt_in       = NUM_DONT_CARE,
        .num_bulk_in            = NUM_DONT_CARE,
@@ -617,6 +616,7 @@ static struct usb_serial_driver keyspan_2port_device = {
                .name           = "keyspan_2",
        },
        .description            = "Keyspan 2 port adapter",
+       .usb_driver             = &keyspan_driver,
        .id_table               = keyspan_2port_ids,
        .num_interrupt_in       = NUM_DONT_CARE,
        .num_bulk_in            = NUM_DONT_CARE,
@@ -644,6 +644,7 @@ static struct usb_serial_driver keyspan_4port_device = {
                .name           = "keyspan_4",
        },
        .description            = "Keyspan 4 port adapter",
+       .usb_driver             = &keyspan_driver,
        .id_table               = keyspan_4port_ids,
        .num_interrupt_in       = NUM_DONT_CARE,
        .num_bulk_in            = 5,
index 126b970..da514cb 100644 (file)
@@ -793,6 +793,7 @@ static struct usb_serial_driver keyspan_pda_fake_device = {
                .name =         "keyspan_pda_pre",
        },
        .description =          "Keyspan PDA - (prerenumeration)",
+       .usb_driver =           &keyspan_pda_driver,
        .id_table =             id_table_fake,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
@@ -809,6 +810,7 @@ static struct usb_serial_driver xircom_pgs_fake_device = {
                .name =         "xircom_no_firm",
        },
        .description =          "Xircom / Entregra PGS - (prerenumeration)",
+       .usb_driver =           &keyspan_pda_driver,
        .id_table =             id_table_fake_xircom,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
@@ -824,6 +826,7 @@ static struct usb_serial_driver keyspan_pda_device = {
                .name =         "keyspan_pda",
        },
        .description =          "Keyspan PDA",
+       .usb_driver =           &keyspan_pda_driver,
        .id_table =             id_table_std,
        .num_interrupt_in =     1,
        .num_bulk_in =          0,
index 5c4b06a..b2097c4 100644 (file)
@@ -124,6 +124,7 @@ static struct usb_serial_driver kl5kusb105d_device = {
                .name =         "kl5kusb105d",
        },
        .description =       "KL5KUSB105D / PalmConnect",
+       .usb_driver =        &kl5kusb105d_driver,
        .id_table =          id_table,
        .num_interrupt_in =  1,
        .num_bulk_in =       1,
index 62bea0c..0683b51 100644 (file)
@@ -110,6 +110,7 @@ static struct usb_serial_driver kobil_device = {
                .name =         "kobil",
        },
        .description =          "KOBIL USB smart card terminal",
+       .usb_driver =           &kobil_driver,
        .id_table =             id_table,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          0,
index 38b1d17..4cd839b 100644 (file)
@@ -137,6 +137,7 @@ static struct usb_serial_driver mct_u232_device = {
                .name =         "mct_u232",
        },
        .description =       "MCT U232",
+       .usb_driver =        &mct_u232_driver,
        .id_table =          id_table_combined,
        .num_interrupt_in =  2,
        .num_bulk_in =       0,
index e55f4ed..6109c67 100644 (file)
@@ -1605,12 +1605,21 @@ static void mos7720_shutdown(struct usb_serial *serial)
        usb_set_serial_data(serial, NULL);
 }
 
+static struct usb_driver usb_driver = {
+       .name =         "moschip7720",
+       .probe =        usb_serial_probe,
+       .disconnect =   usb_serial_disconnect,
+       .id_table =     moschip_port_id_table,
+       .no_dynamic_id =        1,
+};
+
 static struct usb_serial_driver moschip7720_2port_driver = {
        .driver = {
                .owner =        THIS_MODULE,
                .name =         "moschip7720",
        },
        .description            = "Moschip 2 port adapter",
+       .usb_driver             = &usb_driver,
        .id_table               = moschip_port_id_table,
        .num_interrupt_in       = 1,
        .num_bulk_in            = 2,
@@ -1631,13 +1640,6 @@ static struct usb_serial_driver moschip7720_2port_driver = {
        .read_bulk_callback     = mos7720_bulk_in_callback,
 };
 
-static struct usb_driver usb_driver = {
-       .name =         "moschip7720",
-       .probe =        usb_serial_probe,
-       .disconnect =   usb_serial_disconnect,
-       .id_table =     moschip_port_id_table,
-};
-
 static int __init moschip7720_init(void)
 {
        int retval;
index 83f6614..b2264a8 100644 (file)
@@ -2834,12 +2834,21 @@ static void mos7840_shutdown(struct usb_serial *serial)
 
 }
 
+static struct usb_driver io_driver = {
+       .name = "mos7840",
+       .probe = usb_serial_probe,
+       .disconnect = usb_serial_disconnect,
+       .id_table = moschip_id_table_combined,
+       .no_dynamic_id = 1,
+};
+
 static struct usb_serial_driver moschip7840_4port_device = {
        .driver = {
                   .owner = THIS_MODULE,
                   .name = "mos7840",
                   },
        .description = DRIVER_DESC,
+       .usb_driver = &io_driver,
        .id_table = moschip_port_id_table,
        .num_interrupt_in = 1,  //NUM_DONT_CARE,//1,
 #ifdef check
@@ -2869,13 +2878,6 @@ static struct usb_serial_driver moschip7840_4port_device = {
        .read_int_callback = mos7840_interrupt_callback,
 };
 
-static struct usb_driver io_driver = {
-       .name = "mos7840",
-       .probe = usb_serial_probe,
-       .disconnect = usb_serial_disconnect,
-       .id_table = moschip_id_table_combined,
-};
-
 /****************************************************************************
  * moschip7840_init
  *     This is called by the module subsystem, or on startup to initialize us
index 054abee..9070111 100644 (file)
@@ -119,6 +119,7 @@ static struct usb_serial_driver navman_device = {
                .name =         "navman",
        },
        .id_table =             id_table,
+       .usb_driver =           &navman_driver,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
        .num_bulk_out =         NUM_DONT_CARE,
index bc91d3b..0216ac1 100644 (file)
@@ -93,6 +93,7 @@ static struct usb_serial_driver zyxel_omninet_device = {
                .name =         "omninet",
        },
        .description =          "ZyXEL - omni.net lcd plus usb",
+       .usb_driver =           &omninet_driver,
        .id_table =             id_table,
        .num_interrupt_in =     1,
        .num_bulk_in =          1,
index 0fed43a..ced9f32 100644 (file)
@@ -135,6 +135,7 @@ static struct usb_serial_driver option_1port_device = {
                .name =         "option1",
        },
        .description       = "GSM modem (1-port)",
+       .usb_driver        = &option_driver,
        .id_table          = option_ids1,
        .num_interrupt_in  = NUM_DONT_CARE,
        .num_bulk_in       = NUM_DONT_CARE,
index 5dc2ac9..6c083d4 100644 (file)
@@ -1118,6 +1118,7 @@ static struct usb_serial_driver pl2303_device = {
                .name =         "pl2303",
        },
        .id_table =             id_table,
+       .usb_driver =           &pl2303_driver,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          1,
        .num_bulk_out =         1,
index 30b7ebc..5a03a3f 100644 (file)
@@ -402,6 +402,7 @@ static struct usb_serial_driver safe_device = {
                .name =         "safe_serial",
        },
        .id_table =             id_table,
+       .usb_driver =           &safe_driver,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
        .num_bulk_out =         NUM_DONT_CARE,
index 6d8e91e..ecedd83 100644 (file)
   Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
   Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
 
-  History:
 */
 
-#define DRIVER_VERSION "v.1.0.5"
+#define DRIVER_VERSION "v.1.0.6"
 #define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
 #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
 
 
 
 static struct usb_device_id id_table [] = {
+       { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
        { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+       { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
        { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
-       { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
        { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
-       { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
+       { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
        { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
+       { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
        { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
-       { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */
        { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
        { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
 
@@ -55,14 +55,15 @@ static struct usb_device_id id_table_1port [] = {
 };
 
 static struct usb_device_id id_table_3port [] = {
+       { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
        { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+       { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
        { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
-       { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
        { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
-       { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
+       { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
        { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
+       { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
        { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
-       { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */
        { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
        { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
        { }
@@ -81,7 +82,7 @@ static int debug;
 
 /* per port private data */
 #define N_IN_URB       4
-#define N_OUT_URB      1
+#define N_OUT_URB      4
 #define IN_BUFLEN      4096
 #define OUT_BUFLEN     128
 
@@ -396,6 +397,8 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
        struct usb_serial *serial = port->serial;
        int i, err;
        struct urb *urb;
+       int result;
+       __u16 set_mode_dzero = 0x0000;
 
        portdata = usb_get_serial_port_data(port);
 
@@ -442,6 +445,12 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
 
        port->tty->low_latency = 1;
 
+       /* set mode to D0 */
+       result = usb_control_msg(serial->dev,
+                                usb_rcvctrlpipe(serial->dev, 0),
+                                0x00, 0x40, set_mode_dzero, 0, NULL,
+                                0, USB_CTRL_SET_TIMEOUT);
+
        sierra_send_setup(port);
 
        return (0);
@@ -614,6 +623,7 @@ static struct usb_serial_driver sierra_1port_device = {
        },
        .description       = "Sierra USB modem (1 port)",
        .id_table          = id_table_1port,
+       .usb_driver        = &sierra_driver,
        .num_interrupt_in  = NUM_DONT_CARE,
        .num_bulk_in       = 1,
        .num_bulk_out      = 1,
@@ -642,6 +652,7 @@ static struct usb_serial_driver sierra_3port_device = {
        },
        .description       = "Sierra USB modem (3 port)",
        .id_table          = id_table_3port,
+       .usb_driver        = &sierra_driver,
        .num_interrupt_in  = NUM_DONT_CARE,
        .num_bulk_in       = 3,
        .num_bulk_out      = 3,
index 8318900..4203e2b 100644 (file)
@@ -262,6 +262,7 @@ static struct usb_serial_driver ti_1port_device = {
                .name           = "ti_usb_3410_5052_1",
        },
        .description            = "TI USB 3410 1 port adapter",
+       .usb_driver             = &ti_usb_driver,
        .id_table               = ti_id_table_3410,
        .num_interrupt_in       = 1,
        .num_bulk_in            = 1,
@@ -292,6 +293,7 @@ static struct usb_serial_driver ti_2port_device = {
                .name           = "ti_usb_3410_5052_2",
        },
        .description            = "TI USB 5052 2 port adapter",
+       .usb_driver             = &ti_usb_driver,
        .id_table               = ti_id_table_5052,
        .num_interrupt_in       = 1,
        .num_bulk_in            = 2,
index 716f680..6bf22a2 100644 (file)
@@ -59,14 +59,19 @@ static struct usb_driver usb_serial_driver = {
 
 static int debug;
 static struct usb_serial *serial_table[SERIAL_TTY_MINORS];     /* initially all NULL */
+static spinlock_t table_lock;
 static LIST_HEAD(usb_serial_driver_list);
 
 struct usb_serial *usb_serial_get_by_index(unsigned index)
 {
-       struct usb_serial *serial = serial_table[index];
+       struct usb_serial *serial;
+
+       spin_lock(&table_lock);
+       serial = serial_table[index];
 
        if (serial)
                kref_get(&serial->kref);
+       spin_unlock(&table_lock);
        return serial;
 }
 
@@ -78,6 +83,7 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
        dbg("%s %d", __FUNCTION__, num_ports);
 
        *minor = 0;
+       spin_lock(&table_lock);
        for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
                if (serial_table[i])
                        continue;
@@ -96,8 +102,10 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
                dbg("%s - minor base = %d", __FUNCTION__, *minor);
                for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
                        serial_table[i] = serial;
+               spin_unlock(&table_lock);
                return serial;
        }
+       spin_unlock(&table_lock);
        return NULL;
 }
 
@@ -110,9 +118,11 @@ static void return_serial(struct usb_serial *serial)
        if (serial == NULL)
                return;
 
+       spin_lock(&table_lock);
        for (i = 0; i < serial->num_ports; ++i) {
                serial_table[serial->minor + i] = NULL;
        }
+       spin_unlock(&table_lock);
 }
 
 static void destroy_serial(struct kref *kref)
@@ -271,7 +281,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
 static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count)
 {
        struct usb_serial_port *port = tty->driver_data;
-       int retval = -EINVAL;
+       int retval = -ENODEV;
 
        if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
                goto exit;
@@ -279,6 +289,7 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int
        dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
 
        if (!port->open_count) {
+               retval = -EINVAL;
                dbg("%s - port not opened", __FUNCTION__);
                goto exit;
        }
@@ -559,15 +570,20 @@ static void port_release(struct device *dev)
        port_free(port);
 }
 
-static void port_free(struct usb_serial_port *port)
+static void kill_traffic(struct usb_serial_port *port)
 {
        usb_kill_urb(port->read_urb);
-       usb_free_urb(port->read_urb);
        usb_kill_urb(port->write_urb);
-       usb_free_urb(port->write_urb);
        usb_kill_urb(port->interrupt_in_urb);
-       usb_free_urb(port->interrupt_in_urb);
        usb_kill_urb(port->interrupt_out_urb);
+}
+
+static void port_free(struct usb_serial_port *port)
+{
+       kill_traffic(port);
+       usb_free_urb(port->read_urb);
+       usb_free_urb(port->write_urb);
+       usb_free_urb(port->interrupt_in_urb);
        usb_free_urb(port->interrupt_out_urb);
        kfree(port->bulk_in_buffer);
        kfree(port->bulk_out_buffer);
@@ -596,6 +612,39 @@ static struct usb_serial * create_serial (struct usb_device *dev,
        return serial;
 }
 
+static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
+                                                   struct usb_serial_driver *drv)
+{
+       struct usb_dynid *dynid;
+
+       spin_lock(&drv->dynids.lock);
+       list_for_each_entry(dynid, &drv->dynids.list, node) {
+               if (usb_match_one_id(intf, &dynid->id)) {
+                       spin_unlock(&drv->dynids.lock);
+                       return &dynid->id;
+               }
+       }
+       spin_unlock(&drv->dynids.lock);
+       return NULL;
+}
+
+static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv,
+                                               struct usb_interface *intf)
+{
+       const struct usb_device_id *id;
+
+       id = usb_match_id(intf, drv->id_table);
+       if (id) {
+               dbg("static descriptor matches");
+               goto exit;
+       }
+       id = match_dynamic_id(intf, drv);
+       if (id)
+               dbg("dynamic descriptor matches");
+exit:
+       return id;
+}
+
 static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
 {
        struct list_head *p;
@@ -605,11 +654,9 @@ static struct usb_serial_driver *search_serial_device(struct usb_interface *ifac
        /* 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 = usb_match_id(iface, t->id_table);
-               if (id != NULL) {
-                       dbg("descriptor matches");
+               id = get_iface_id(t, iface);
+               if (id)
                        return t;
-               }
        }
 
        return NULL;
@@ -639,14 +686,17 @@ int usb_serial_probe(struct usb_interface *interface,
        int num_ports = 0;
        int max_endpoints;
 
+       lock_kernel(); /* guard against unloading a serial driver module */
        type = search_serial_device(interface);
        if (!type) {
+               unlock_kernel();
                dbg("none matched");
                return -ENODEV;
        }
 
        serial = create_serial (dev, interface, type);
        if (!serial) {
+               unlock_kernel();
                dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
                return -ENOMEM;
        }
@@ -656,16 +706,18 @@ int usb_serial_probe(struct usb_interface *interface,
                const struct usb_device_id *id;
 
                if (!try_module_get(type->driver.owner)) {
+                       unlock_kernel();
                        dev_err(&interface->dev, "module get failed, exiting\n");
                        kfree (serial);
                        return -EIO;
                }
 
-               id = usb_match_id(interface, type->id_table);
+               id = get_iface_id(type, interface);
                retval = type->probe(serial, id);
                module_put(type->driver.owner);
 
                if (retval) {
+                       unlock_kernel();
                        dbg ("sub driver rejected device");
                        kfree (serial);
                        return retval;
@@ -735,6 +787,7 @@ int usb_serial_probe(struct usb_interface *interface,
                 * properly during a later invocation of usb_serial_probe
                 */
                if (num_bulk_in == 0 || num_bulk_out == 0) {
+                       unlock_kernel();
                        dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
                        kfree (serial);
                        return -ENODEV;
@@ -750,6 +803,7 @@ int usb_serial_probe(struct usb_interface *interface,
        if (type == &usb_serial_generic_device) {
                num_ports = num_bulk_out;
                if (num_ports == 0) {
+                       unlock_kernel();
                        dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n");
                        kfree (serial);
                        return -EIO;
@@ -760,6 +814,7 @@ int usb_serial_probe(struct usb_interface *interface,
                /* if this device type has a calc_num_ports function, call it */
                if (type->calc_num_ports) {
                        if (!try_module_get(type->driver.owner)) {
+                               unlock_kernel();
                                dev_err(&interface->dev, "module get failed, exiting\n");
                                kfree (serial);
                                return -EIO;
@@ -771,12 +826,6 @@ int usb_serial_probe(struct usb_interface *interface,
                        num_ports = type->num_ports;
        }
 
-       if (get_free_serial (serial, num_ports, &minor) == NULL) {
-               dev_err(&interface->dev, "No more free serial devices\n");
-               kfree (serial);
-               return -ENOMEM;
-       }
-
        serial->minor = minor;
        serial->num_ports = num_ports;
        serial->num_bulk_in = num_bulk_in;
@@ -791,6 +840,8 @@ int usb_serial_probe(struct usb_interface *interface,
        max_endpoints = max(max_endpoints, num_interrupt_out);
        max_endpoints = max(max_endpoints, (int)serial->num_ports);
        serial->num_port_pointers = max_endpoints;
+       unlock_kernel();
+
        dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
        for (i = 0; i < max_endpoints; ++i) {
                port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
@@ -925,6 +976,11 @@ int usb_serial_probe(struct usb_interface *interface,
                }
        }
 
+       if (get_free_serial (serial, num_ports, &minor) == NULL) {
+               dev_err(&interface->dev, "No more free serial devices\n");
+               goto probe_error;
+       }
+
        /* register all of the individual ports with the driver core */
        for (i = 0; i < num_ports; ++i) {
                port = serial->port[i];
@@ -1002,8 +1058,11 @@ void usb_serial_disconnect(struct usb_interface *interface)
        if (serial) {
                for (i = 0; i < serial->num_ports; ++i) {
                        port = serial->port[i];
-                       if (port && port->tty)
-                               tty_hangup(port->tty);
+                       if (port) {
+                               if (port->tty)
+                                       tty_hangup(port->tty);
+                               kill_traffic(port);
+                       }
                }
                /* let the last holder of this object 
                 * cause it to be cleaned up */
@@ -1040,6 +1099,7 @@ static int __init usb_serial_init(void)
                return -ENOMEM;
 
        /* Initialize our global data */
+       spin_lock_init(&table_lock);
        for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
                serial_table[i] = NULL;
        }
@@ -1138,7 +1198,7 @@ static void fixup_generic(struct usb_serial_driver *device)
        set_to_generic_if_null(device, shutdown);
 }
 
-int usb_serial_register(struct usb_serial_driver *driver)
+int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */
 {
        int retval;
 
@@ -1162,7 +1222,7 @@ int usb_serial_register(struct usb_serial_driver *driver)
 }
 
 
-void usb_serial_deregister(struct usb_serial_driver *device)
+void usb_serial_deregister(struct usb_serial_driver *device) /* must be called with BKL held */
 {
        info("USB Serial deregistering driver %s", device->description);
        list_del(&device->driver_list);
index b09f060..2f59ff2 100644 (file)
@@ -90,8 +90,6 @@ static struct usb_device_id id_table [] = {
                .driver_info = (kernel_ulong_t)&palm_os_4_probe },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID),
                .driver_info = (kernel_ulong_t)&palm_os_4_probe },
-       { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID),
-               .driver_info = (kernel_ulong_t)&palm_os_4_probe },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID),
                .driver_info = (kernel_ulong_t)&palm_os_4_probe },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID),
@@ -151,7 +149,6 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) },
-       { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
@@ -189,6 +186,7 @@ static struct usb_serial_driver handspring_device = {
                .name =         "visor",
        },
        .description =          "Handspring Visor / Palm OS",
+       .usb_driver =           &visor_driver,
        .id_table =             id_table,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          2,
@@ -219,6 +217,7 @@ static struct usb_serial_driver clie_5_device = {
                .name =         "clie_5",
        },
        .description =          "Sony Clie 5.0",
+       .usb_driver =           &visor_driver,
        .id_table =             clie_id_5_table,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          2,
@@ -249,6 +248,7 @@ static struct usb_serial_driver clie_3_5_device = {
                .name =         "clie_3.5",
        },
        .description =          "Sony Clie 3.5",
+       .usb_driver =           &visor_driver,
        .id_table =             clie_id_3_5_table,
        .num_interrupt_in =     0,
        .num_bulk_in =          1,
index 765118d..4ce6f62 100644 (file)
@@ -32,7 +32,6 @@
 #define PALM_TUNGSTEN_T_ID             0x0060
 #define PALM_TREO_650                  0x0061
 #define PALM_TUNGSTEN_Z_ID             0x0031
-#define PALM_ZIRE31_ID                 0x0061
 #define PALM_ZIRE_ID                   0x0070
 #define PALM_M100_ID                   0x0080
 
index 5483d85..bf16e9e 100644 (file)
@@ -161,6 +161,7 @@ static struct usb_serial_driver whiteheat_fake_device = {
                .name =         "whiteheatnofirm",
        },
        .description =          "Connect Tech - WhiteHEAT - (prerenumeration)",
+       .usb_driver =           &whiteheat_driver,
        .id_table =             id_table_prerenumeration,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
@@ -176,6 +177,7 @@ static struct usb_serial_driver whiteheat_device = {
                .name =         "whiteheat",
        },
        .description =          "Connect Tech - WhiteHEAT",
+       .usb_driver =           &whiteheat_driver,
        .id_table =             id_table_std,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
index e565d3d..6d3dad3 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/usb_ch9.h>
 #include <linux/usb/input.h>
 #include "usb.h"
 #include "onetouch.h"
index e1072d5..70234f5 100644 (file)
@@ -110,23 +110,6 @@ static int slave_configure(struct scsi_device *sdev)
         * the end, scatter-gather buffers follow page boundaries. */
        blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
 
-       /* Set the SCSI level to at least 2.  We'll leave it at 3 if that's
-        * what is originally reported.  We need this to avoid confusing
-        * the SCSI layer with devices that report 0 or 1, but need 10-byte
-        * commands (ala ATAPI devices behind certain bridges, or devices
-        * which simply have broken INQUIRY data).
-        *
-        * NOTE: This means /dev/sg programs (ala cdrecord) will get the
-        * actual information.  This seems to be the preference for
-        * programs like that.
-        *
-        * NOTE: This also means that /proc/scsi/scsi and sysfs may report
-        * the actual value or the modified one, depending on where the
-        * data comes from.
-        */
-       if (sdev->scsi_level < SCSI_2)
-               sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2;
-
        /* Many devices have trouble transfering more than 32KB at a time,
         * while others have trouble with more than 64K. At this time we
         * are limiting both to 32K (64 sectores).
@@ -176,7 +159,9 @@ static int slave_configure(struct scsi_device *sdev)
                 * a Get-Max-LUN request, we won't lose much by setting the
                 * revision level down to 2.  The only devices that would be
                 * affected are those with sparse LUNs. */
-               sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2;
+               if (sdev->scsi_level > SCSI_2)
+                       sdev->sdev_target->scsi_level =
+                                       sdev->scsi_level = SCSI_2;
 
                /* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
                 * Hardware Error) when any low-level error occurs,
@@ -194,6 +179,16 @@ static int slave_configure(struct scsi_device *sdev)
                sdev->use_10_for_ms = 1;
        }
 
+       /* The CB and CBI transports have no way to pass LUN values
+        * other than the bits in the second byte of a CDB.  But those
+        * bits don't get set to the LUN value if the device reports
+        * scsi_level == 0 (UNKNOWN).  Hence such devices must necessarily
+        * be single-LUN.
+        */
+       if ((us->protocol == US_PR_CB || us->protocol == US_PR_CBI) &&
+                       sdev->scsi_level == SCSI_UNKNOWN)
+               us->max_lun = 0;
+
        /* Some devices choke when they receive a PREVENT-ALLOW MEDIUM
         * REMOVAL command, so suppress those commands. */
        if (us->flags & US_FL_NOT_LOCKABLE)
index b49f2a7..f49a62f 100644 (file)
@@ -573,7 +573,7 @@ UNUSUAL_DEV(  0x054c, 0x002b, 0x0100, 0x0110,
 #endif
 
 /* Submitted by Olaf Hering, <olh@suse.de> SuSE Bugzilla #49049 */
-UNUSUAL_DEV(  0x054c, 0x002c, 0x0501, 0x0501,
+UNUSUAL_DEV(  0x054c, 0x002c, 0x0501, 0x2000,
                "Sony",
                "USB Floppy Drive",
                US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -1325,13 +1325,6 @@ UNUSUAL_DEV(  0x0fce, 0xe031, 0x0000, 0x0000,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_FIX_CAPACITY ),
 
-/* Reported by Jan Mate <mate@fiit.stuba.sk> */
-UNUSUAL_DEV(  0x0fce, 0xe030, 0x0000, 0x0000,
-               "Sony Ericsson",
-               "P990i",
-               US_SC_DEVICE, US_PR_DEVICE, NULL,
-               US_FL_FIX_CAPACITY ),
-
 /* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
  * Tested on hardware version 1.10.
  * Entry is needed only for the initializer function override.
index 7064450..7e7ec29 100644 (file)
@@ -731,26 +731,27 @@ static int get_pipes(struct us_data *us)
        struct usb_endpoint_descriptor *ep_int = NULL;
 
        /*
-        * Find the endpoints we need.
+        * Find the first endpoint of each type we need.
         * We are expecting a minimum of 2 endpoints - in and out (bulk).
-        * An optional interrupt is OK (necessary for CBI protocol).
+        * An optional interrupt-in is OK (necessary for CBI protocol).
         * We will ignore any others.
         */
        for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
                ep = &altsetting->endpoint[i].desc;
 
-               /* Is it a BULK endpoint? */
                if (usb_endpoint_xfer_bulk(ep)) {
-                       /* BULK in or out? */
-                       if (usb_endpoint_dir_in(ep))
-                               ep_in = ep;
-                       else
-                               ep_out = ep;
+                       if (usb_endpoint_dir_in(ep)) {
+                               if (!ep_in)
+                                       ep_in = ep;
+                       } else {
+                               if (!ep_out)
+                                       ep_out = ep;
+                       }
                }
 
-               /* Is it an interrupt endpoint? */
-               else if (usb_endpoint_xfer_int(ep)) {
-                       ep_int = ep;
+               else if (usb_endpoint_is_int_in(ep)) {
+                       if (!ep_int)
+                               ep_int = ep;
                }
        }
 
index 157db77..683513e 100644 (file)
@@ -11,6 +11,7 @@ header-y += netfilter_arp/
 header-y += netfilter_bridge/
 header-y += netfilter_ipv4/
 header-y += netfilter_ipv6/
+header-y += usb/
 
 header-y += affs_hardblocks.h
 header-y += aio_abi.h
@@ -326,7 +327,6 @@ unifdef-y += udp.h
 unifdef-y += uinput.h
 unifdef-y += uio.h
 unifdef-y += unistd.h
-unifdef-y += usb_ch9.h
 unifdef-y += usbdevice_fs.h
 unifdef-y += user.h
 unifdef-y += utsname.h
index 93173fe..d26b08f 100644 (file)
@@ -266,6 +266,7 @@ struct hid_item {
 #define HID_QUIRK_BAD_RELATIVE_KEYS            0x00010000
 #define HID_QUIRK_SKIP_OUTPUT_REPORTS          0x00020000
 #define HID_QUIRK_IGNORE_MOUSE                 0x00040000
+#define HID_QUIRK_SONY_PS3_CONTROLLER          0x00080000
 
 /*
  * This is the global environment of the parser. This information is
index 733f38d..b5c226a 100644 (file)
@@ -2,7 +2,7 @@
 #define __LINUX_USB_H
 
 #include <linux/mod_devicetable.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 
 #define USB_MAJOR                      180
 #define USB_DEVICE_MAJOR               189
@@ -107,7 +107,8 @@ enum usb_interface_condition {
  * @needs_remote_wakeup: flag set when the driver requires remote-wakeup
  *     capability during autosuspend.
  * @dev: driver model's view of this device
- * @class_dev: driver model's class view of this device.
+ * @usb_dev: if an interface is bound to the USB major, this will point
+ *     to the sysfs representation for that device.
  * @pm_usage_cnt: PM usage counter for this interface; autosuspend is not
  *     allowed unless the counter is 0.
  *
@@ -152,7 +153,7 @@ struct usb_interface {
        unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
 
        struct device dev;              /* interface specific device info */
-       struct class_device *class_dev;
+       struct device *usb_dev;         /* pointer to the usb class's device, if any */
        int pm_usage_cnt;               /* usage counter for autosuspend */
 };
 #define        to_usb_interface(d) container_of(d, struct usb_interface, dev)
@@ -372,7 +373,7 @@ struct usb_device {
        char *serial;                   /* iSerialNumber string, if present */
 
        struct list_head filelist;
-       struct class_device *class_dev;
+       struct device *usbfs_dev;
        struct dentry *usbfs_dentry;    /* usbfs dentry entry for the device */
 
        /*
@@ -475,6 +476,8 @@ extern void usb_driver_release_interface(struct usb_driver *driver,
                        struct usb_interface *iface);
 const struct usb_device_id *usb_match_id(struct usb_interface *interface,
                                         const struct usb_device_id *id);
+extern int usb_match_one_id(struct usb_interface *interface,
+                           const struct usb_device_id *id);
 
 extern struct usb_interface *usb_find_interface(struct usb_driver *drv,
                int minor);
@@ -553,6 +556,18 @@ static inline int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *e
                USB_ENDPOINT_XFER_BULK);
 }
 
+/**
+ * usb_endpoint_xfer_control - check if the endpoint has control transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type control, otherwise it returns false.
+ */
+static inline int usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd)
+{
+       return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+               USB_ENDPOINT_XFER_CONTROL);
+}
+
 /**
  * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type
  * @epd: endpoint to be checked
@@ -723,11 +738,21 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor
 
 /* ----------------------------------------------------------------------- */
 
+/* Stuff for dynamic usb ids */
 struct usb_dynids {
        spinlock_t lock;
        struct list_head list;
 };
 
+struct usb_dynid {
+       struct list_head node;
+       struct usb_device_id id;
+};
+
+extern ssize_t usb_store_new_id(struct usb_dynids *dynids,
+                               struct device_driver *driver,
+                               const char *buf, size_t count);
+
 /**
  * struct usbdrv_wrap - wrapper for driver-model structure
  * @driver: The driver-model core driver structure.
@@ -1086,7 +1111,6 @@ struct urb
        struct kref kref;               /* reference count of the URB */
        spinlock_t lock;                /* lock for the URB */
        void *hcpriv;                   /* private data for host controller */
-       int bandwidth;                  /* bandwidth for INT/ISO request */
        atomic_t use_count;             /* concurrent submissions counter */
        u8 reject;                      /* submissions will fail */
 
diff --git a/include/linux/usb/Kbuild b/include/linux/usb/Kbuild
new file mode 100644 (file)
index 0000000..43f160c
--- /dev/null
@@ -0,0 +1,5 @@
+unifdef-y += audio.h
+unifdef-y += cdc.h
+unifdef-y += ch9.h
+unifdef-y += midi.h
+
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
new file mode 100644 (file)
index 0000000..ae78337
--- /dev/null
@@ -0,0 +1,563 @@
+/*
+ * This file holds USB constants and structures that are needed for USB
+ * device APIs.  These are used by the USB device model, which is defined
+ * in chapter 9 of the USB 2.0 specification.  Linux has several APIs in C
+ * that need these:
+ *
+ * - the master/host side Linux-USB kernel driver API;
+ * - the "usbfs" user space API; and
+ * - the Linux "gadget" slave/device/peripheral side driver API.
+ *
+ * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems
+ * act either as a USB master/host or as a USB slave/device.  That means
+ * the master and slave side APIs benefit from working well together.
+ *
+ * There's also "Wireless USB", using low power short range radios for
+ * peripheral interconnection but otherwise building on the USB framework.
+ */
+
+#ifndef __LINUX_USB_CH9_H
+#define __LINUX_USB_CH9_H
+
+#include <linux/types.h>       /* __u8 etc */
+
+/*-------------------------------------------------------------------------*/
+
+/* CONTROL REQUEST SUPPORT */
+
+/*
+ * USB directions
+ *
+ * This bit flag is used in endpoint descriptors' bEndpointAddress field.
+ * It's also one of three fields in control requests bRequestType.
+ */
+#define USB_DIR_OUT                    0               /* to device */
+#define USB_DIR_IN                     0x80            /* to host */
+
+/*
+ * USB types, the second of three bRequestType fields
+ */
+#define USB_TYPE_MASK                  (0x03 << 5)
+#define USB_TYPE_STANDARD              (0x00 << 5)
+#define USB_TYPE_CLASS                 (0x01 << 5)
+#define USB_TYPE_VENDOR                        (0x02 << 5)
+#define USB_TYPE_RESERVED              (0x03 << 5)
+
+/*
+ * USB recipients, the third of three bRequestType fields
+ */
+#define USB_RECIP_MASK                 0x1f
+#define USB_RECIP_DEVICE               0x00
+#define USB_RECIP_INTERFACE            0x01
+#define USB_RECIP_ENDPOINT             0x02
+#define USB_RECIP_OTHER                        0x03
+/* From Wireless USB 1.0 */
+#define USB_RECIP_PORT                         0x04
+#define USB_RECIP_RPIPE                0x05
+
+/*
+ * Standard requests, for the bRequest field of a SETUP packet.
+ *
+ * These are qualified by the bRequestType field, so that for example
+ * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved
+ * by a GET_STATUS request.
+ */
+#define USB_REQ_GET_STATUS             0x00
+#define USB_REQ_CLEAR_FEATURE          0x01
+#define USB_REQ_SET_FEATURE            0x03
+#define USB_REQ_SET_ADDRESS            0x05
+#define USB_REQ_GET_DESCRIPTOR         0x06
+#define USB_REQ_SET_DESCRIPTOR         0x07
+#define USB_REQ_GET_CONFIGURATION      0x08
+#define USB_REQ_SET_CONFIGURATION      0x09
+#define USB_REQ_GET_INTERFACE          0x0A
+#define USB_REQ_SET_INTERFACE          0x0B
+#define USB_REQ_SYNCH_FRAME            0x0C
+
+#define USB_REQ_SET_ENCRYPTION         0x0D    /* Wireless USB */
+#define USB_REQ_GET_ENCRYPTION         0x0E
+#define USB_REQ_RPIPE_ABORT            0x0E
+#define USB_REQ_SET_HANDSHAKE          0x0F
+#define USB_REQ_RPIPE_RESET            0x0F
+#define USB_REQ_GET_HANDSHAKE          0x10
+#define USB_REQ_SET_CONNECTION         0x11
+#define USB_REQ_SET_SECURITY_DATA      0x12
+#define USB_REQ_GET_SECURITY_DATA      0x13
+#define USB_REQ_SET_WUSB_DATA          0x14
+#define USB_REQ_LOOPBACK_DATA_WRITE    0x15
+#define USB_REQ_LOOPBACK_DATA_READ     0x16
+#define USB_REQ_SET_INTERFACE_DS       0x17
+
+/*
+ * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and
+ * are read as a bit array returned by USB_REQ_GET_STATUS.  (So there
+ * are at most sixteen features of each type.)
+ */
+#define USB_DEVICE_SELF_POWERED                0       /* (read only) */
+#define USB_DEVICE_REMOTE_WAKEUP       1       /* dev may initiate wakeup */
+#define USB_DEVICE_TEST_MODE           2       /* (wired high speed only) */
+#define USB_DEVICE_BATTERY             2       /* (wireless) */
+#define USB_DEVICE_B_HNP_ENABLE                3       /* (otg) dev may initiate HNP */
+#define USB_DEVICE_WUSB_DEVICE         3       /* (wireless)*/
+#define USB_DEVICE_A_HNP_SUPPORT       4       /* (otg) RH port supports HNP */
+#define USB_DEVICE_A_ALT_HNP_SUPPORT   5       /* (otg) other RH port does */
+#define USB_DEVICE_DEBUG_MODE          6       /* (special devices only) */
+
+#define USB_ENDPOINT_HALT              0       /* IN/OUT will STALL */
+
+
+/**
+ * struct usb_ctrlrequest - SETUP data for a USB device control request
+ * @bRequestType: matches the USB bmRequestType field
+ * @bRequest: matches the USB bRequest field
+ * @wValue: matches the USB wValue field (le16 byte order)
+ * @wIndex: matches the USB wIndex field (le16 byte order)
+ * @wLength: matches the USB wLength field (le16 byte order)
+ *
+ * This structure is used to send control requests to a USB device.  It matches
+ * the different fields of the USB 2.0 Spec section 9.3, table 9-2.  See the
+ * USB spec for a fuller description of the different fields, and what they are
+ * used for.
+ *
+ * Note that the driver for any interface can issue control requests.
+ * For most devices, interfaces don't coordinate with each other, so
+ * such requests may be made at any time.
+ */
+struct usb_ctrlrequest {
+       __u8 bRequestType;
+       __u8 bRequest;
+       __le16 wValue;
+       __le16 wIndex;
+       __le16 wLength;
+} __attribute__ ((packed));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or
+ * (rarely) accepted by SET_DESCRIPTOR.
+ *
+ * Note that all multi-byte values here are encoded in little endian
+ * byte order "on the wire".  But when exposed through Linux-USB APIs,
+ * they've been converted to cpu byte order.
+ */
+
+/*
+ * Descriptor types ... USB 2.0 spec table 9.5
+ */
+#define USB_DT_DEVICE                  0x01
+#define USB_DT_CONFIG                  0x02
+#define USB_DT_STRING                  0x03
+#define USB_DT_INTERFACE               0x04
+#define USB_DT_ENDPOINT                        0x05
+#define USB_DT_DEVICE_QUALIFIER                0x06
+#define USB_DT_OTHER_SPEED_CONFIG      0x07
+#define USB_DT_INTERFACE_POWER         0x08
+/* these are from a minor usb 2.0 revision (ECN) */
+#define USB_DT_OTG                     0x09
+#define USB_DT_DEBUG                   0x0a
+#define USB_DT_INTERFACE_ASSOCIATION   0x0b
+/* these are from the Wireless USB spec */
+#define USB_DT_SECURITY                        0x0c
+#define USB_DT_KEY                     0x0d
+#define USB_DT_ENCRYPTION_TYPE         0x0e
+#define USB_DT_BOS                     0x0f
+#define USB_DT_DEVICE_CAPABILITY       0x10
+#define USB_DT_WIRELESS_ENDPOINT_COMP  0x11
+#define USB_DT_WIRE_ADAPTER            0x21
+#define USB_DT_RPIPE                   0x22
+
+/* conventional codes for class-specific descriptors */
+#define USB_DT_CS_DEVICE               0x21
+#define USB_DT_CS_CONFIG               0x22
+#define USB_DT_CS_STRING               0x23
+#define USB_DT_CS_INTERFACE            0x24
+#define USB_DT_CS_ENDPOINT             0x25
+
+/* All standard descriptors have these 2 fields at the beginning */
+struct usb_descriptor_header {
+       __u8  bLength;
+       __u8  bDescriptorType;
+} __attribute__ ((packed));
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEVICE: Device descriptor */
+struct usb_device_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __le16 bcdUSB;
+       __u8  bDeviceClass;
+       __u8  bDeviceSubClass;
+       __u8  bDeviceProtocol;
+       __u8  bMaxPacketSize0;
+       __le16 idVendor;
+       __le16 idProduct;
+       __le16 bcdDevice;
+       __u8  iManufacturer;
+       __u8  iProduct;
+       __u8  iSerialNumber;
+       __u8  bNumConfigurations;
+} __attribute__ ((packed));
+
+#define USB_DT_DEVICE_SIZE             18
+
+
+/*
+ * Device and/or Interface Class codes
+ * as found in bDeviceClass or bInterfaceClass
+ * and defined by www.usb.org documents
+ */
+#define USB_CLASS_PER_INTERFACE                0       /* for DeviceClass */
+#define USB_CLASS_AUDIO                        1
+#define USB_CLASS_COMM                 2
+#define USB_CLASS_HID                  3
+#define USB_CLASS_PHYSICAL             5
+#define USB_CLASS_STILL_IMAGE          6
+#define USB_CLASS_PRINTER              7
+#define USB_CLASS_MASS_STORAGE         8
+#define USB_CLASS_HUB                  9
+#define USB_CLASS_CDC_DATA             0x0a
+#define USB_CLASS_CSCID                        0x0b    /* chip+ smart card */
+#define USB_CLASS_CONTENT_SEC          0x0d    /* content security */
+#define USB_CLASS_VIDEO                        0x0e
+#define USB_CLASS_WIRELESS_CONTROLLER  0xe0
+#define USB_CLASS_MISC                 0xef
+#define USB_CLASS_APP_SPEC             0xfe
+#define USB_CLASS_VENDOR_SPEC          0xff
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_CONFIG: Configuration descriptor information.
+ *
+ * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the
+ * descriptor type is different.  Highspeed-capable devices can look
+ * different depending on what speed they're currently running.  Only
+ * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG
+ * descriptors.
+ */
+struct usb_config_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __le16 wTotalLength;
+       __u8  bNumInterfaces;
+       __u8  bConfigurationValue;
+       __u8  iConfiguration;
+       __u8  bmAttributes;
+       __u8  bMaxPower;
+} __attribute__ ((packed));
+
+#define USB_DT_CONFIG_SIZE             9
+
+/* from config descriptor bmAttributes */
+#define USB_CONFIG_ATT_ONE             (1 << 7)        /* must be set */
+#define USB_CONFIG_ATT_SELFPOWER       (1 << 6)        /* self powered */
+#define USB_CONFIG_ATT_WAKEUP          (1 << 5)        /* can wakeup */
+#define USB_CONFIG_ATT_BATTERY         (1 << 4)        /* battery powered */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_STRING: String descriptor */
+struct usb_string_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __le16 wData[1];                /* UTF-16LE encoded */
+} __attribute__ ((packed));
+
+/* note that "string" zero is special, it holds language codes that
+ * the device supports, not Unicode characters.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_INTERFACE: Interface descriptor */
+struct usb_interface_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  bInterfaceNumber;
+       __u8  bAlternateSetting;
+       __u8  bNumEndpoints;
+       __u8  bInterfaceClass;
+       __u8  bInterfaceSubClass;
+       __u8  bInterfaceProtocol;
+       __u8  iInterface;
+} __attribute__ ((packed));
+
+#define USB_DT_INTERFACE_SIZE          9
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_ENDPOINT: Endpoint descriptor */
+struct usb_endpoint_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  bEndpointAddress;
+       __u8  bmAttributes;
+       __le16 wMaxPacketSize;
+       __u8  bInterval;
+
+       /* NOTE:  these two are _only_ in audio endpoints. */
+       /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
+       __u8  bRefresh;
+       __u8  bSynchAddress;
+} __attribute__ ((packed));
+
+#define USB_DT_ENDPOINT_SIZE           7
+#define USB_DT_ENDPOINT_AUDIO_SIZE     9       /* Audio extension */
+
+
+/*
+ * Endpoints
+ */
+#define USB_ENDPOINT_NUMBER_MASK       0x0f    /* in bEndpointAddress */
+#define USB_ENDPOINT_DIR_MASK          0x80
+
+#define USB_ENDPOINT_XFERTYPE_MASK     0x03    /* in bmAttributes */
+#define USB_ENDPOINT_XFER_CONTROL      0
+#define USB_ENDPOINT_XFER_ISOC         1
+#define USB_ENDPOINT_XFER_BULK         2
+#define USB_ENDPOINT_XFER_INT          3
+#define USB_ENDPOINT_MAX_ADJUSTABLE    0x80
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */
+struct usb_qualifier_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __le16 bcdUSB;
+       __u8  bDeviceClass;
+       __u8  bDeviceSubClass;
+       __u8  bDeviceProtocol;
+       __u8  bMaxPacketSize0;
+       __u8  bNumConfigurations;
+       __u8  bRESERVED;
+} __attribute__ ((packed));
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_OTG (from OTG 1.0a supplement) */
+struct usb_otg_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  bmAttributes;     /* support for HNP, SRP, etc */
+} __attribute__ ((packed));
+
+/* from usb_otg_descriptor.bmAttributes */
+#define USB_OTG_SRP            (1 << 0)
+#define USB_OTG_HNP            (1 << 1)        /* swap host/device roles */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEBUG:  for special highspeed devices, replacing serial console */
+struct usb_debug_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       /* bulk endpoints with 8 byte maxpacket */
+       __u8  bDebugInEndpoint;
+       __u8  bDebugOutEndpoint;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_INTERFACE_ASSOCIATION: groups interfaces */
+struct usb_interface_assoc_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  bFirstInterface;
+       __u8  bInterfaceCount;
+       __u8  bFunctionClass;
+       __u8  bFunctionSubClass;
+       __u8  bFunctionProtocol;
+       __u8  iFunction;
+} __attribute__ ((packed));
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_SECURITY:  group of wireless security descriptors, including
+ * encryption types available for setting up a CC/association.
+ */
+struct usb_security_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __le16 wTotalLength;
+       __u8  bNumEncryptionTypes;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_KEY:  used with {GET,SET}_SECURITY_DATA; only public keys
+ * may be retrieved.
+ */
+struct usb_key_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  tTKID[3];
+       __u8  bReserved;
+       __u8  bKeyData[0];
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_ENCRYPTION_TYPE:  bundled in DT_SECURITY groups */
+struct usb_encryption_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  bEncryptionType;
+#define        USB_ENC_TYPE_UNSECURE           0
+#define        USB_ENC_TYPE_WIRED              1       /* non-wireless mode */
+#define        USB_ENC_TYPE_CCM_1              2       /* aes128/cbc session */
+#define        USB_ENC_TYPE_RSA_1              3       /* rsa3072/sha1 auth */
+       __u8  bEncryptionValue;         /* use in SET_ENCRYPTION */
+       __u8  bAuthKeyIndex;
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_BOS:  group of wireless capabilities */
+struct usb_bos_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __le16 wTotalLength;
+       __u8  bNumDeviceCaps;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEVICE_CAPABILITY:  grouped with BOS */
+struct usb_dev_cap_header {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDevCapabilityType;
+};
+
+#define        USB_CAP_TYPE_WIRELESS_USB       1
+
+struct usb_wireless_cap_descriptor {   /* Ultra Wide Band */
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDevCapabilityType;
+
+       __u8  bmAttributes;
+#define        USB_WIRELESS_P2P_DRD            (1 << 1)
+#define        USB_WIRELESS_BEACON_MASK        (3 << 2)
+#define        USB_WIRELESS_BEACON_SELF        (1 << 2)
+#define        USB_WIRELESS_BEACON_DIRECTED    (2 << 2)
+#define        USB_WIRELESS_BEACON_NONE        (3 << 2)
+       __le16 wPHYRates;       /* bit rates, Mbps */
+#define        USB_WIRELESS_PHY_53             (1 << 0)        /* always set */
+#define        USB_WIRELESS_PHY_80             (1 << 1)
+#define        USB_WIRELESS_PHY_107            (1 << 2)        /* always set */
+#define        USB_WIRELESS_PHY_160            (1 << 3)
+#define        USB_WIRELESS_PHY_200            (1 << 4)        /* always set */
+#define        USB_WIRELESS_PHY_320            (1 << 5)
+#define        USB_WIRELESS_PHY_400            (1 << 6)
+#define        USB_WIRELESS_PHY_480            (1 << 7)
+       __u8  bmTFITXPowerInfo; /* TFI power levels */
+       __u8  bmFFITXPowerInfo; /* FFI power levels */
+       __le16 bmBandGroup;
+       __u8  bReserved;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_WIRELESS_ENDPOINT_COMP:  companion descriptor associated with
+ * each endpoint descriptor for a wireless device
+ */
+struct usb_wireless_ep_comp_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  bMaxBurst;
+       __u8  bMaxSequence;
+       __le16 wMaxStreamDelay;
+       __le16 wOverTheAirPacketSize;
+       __u8  bOverTheAirInterval;
+       __u8  bmCompAttributes;
+#define USB_ENDPOINT_SWITCH_MASK       0x03    /* in bmCompAttributes */
+#define USB_ENDPOINT_SWITCH_NO         0
+#define USB_ENDPOINT_SWITCH_SWITCH     1
+#define USB_ENDPOINT_SWITCH_SCALE      2
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_REQ_SET_HANDSHAKE is a four-way handshake used between a wireless
+ * host and a device for connection set up, mutual authentication, and
+ * exchanging short lived session keys.  The handshake depends on a CC.
+ */
+struct usb_handshake {
+       __u8 bMessageNumber;
+       __u8 bStatus;
+       __u8 tTKID[3];
+       __u8 bReserved;
+       __u8 CDID[16];
+       __u8 nonce[16];
+       __u8 MIC[8];
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_REQ_SET_CONNECTION modifies or revokes a connection context (CC).
+ * A CC may also be set up using non-wireless secure channels (including
+ * wired USB!), and some devices may support CCs with multiple hosts.
+ */
+struct usb_connection_context {
+       __u8 CHID[16];          /* persistent host id */
+       __u8 CDID[16];          /* device id (unique w/in host context) */
+       __u8 CK[16];            /* connection key */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB 2.0 defines three speeds, here's how Linux identifies them */
+
+enum usb_device_speed {
+       USB_SPEED_UNKNOWN = 0,                  /* enumerating */
+       USB_SPEED_LOW, USB_SPEED_FULL,          /* usb 1.1 */
+       USB_SPEED_HIGH,                         /* usb 2.0 */
+       USB_SPEED_VARIABLE,                     /* wireless (usb 2.5) */
+};
+
+enum usb_device_state {
+       /* NOTATTACHED isn't in the USB spec, and this state acts
+        * the same as ATTACHED ... but it's clearer this way.
+        */
+       USB_STATE_NOTATTACHED = 0,
+
+       /* chapter 9 and authentication (wireless) device states */
+       USB_STATE_ATTACHED,
+       USB_STATE_POWERED,                      /* wired */
+       USB_STATE_UNAUTHENTICATED,              /* auth */
+       USB_STATE_RECONNECTING,                 /* auth */
+       USB_STATE_DEFAULT,                      /* limited function */
+       USB_STATE_ADDRESS,
+       USB_STATE_CONFIGURED,                   /* most functions */
+
+       USB_STATE_SUSPENDED
+
+       /* NOTE:  there are actually four different SUSPENDED
+        * states, returning to POWERED, DEFAULT, ADDRESS, or
+        * CONFIGURED respectively when SOF tokens flow again.
+        */
+};
+
+#endif /* __LINUX_USB_CH9_H */
index 10f99e5..33dcd85 100644 (file)
@@ -179,6 +179,9 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data)
  *     memory structure allocation at this point in time.
  * @shutdown: pointer to the driver's shutdown function.  This will be
  *     called when the device is removed from the system.
+ * @usb_driver: pointer to the struct usb_driver that controls this
+ *     device.  This is necessary to allow dynamic ids to be added to
+ *     the driver from sysfs.
  *
  * This structure is defines a USB Serial driver.  It provides all of
  * the information that the USB serial core code needs.  If the function
@@ -202,6 +205,8 @@ struct usb_serial_driver {
 
        struct list_head        driver_list;
        struct device_driver    driver;
+       struct usb_driver       *usb_driver;
+       struct usb_dynids       dynids;
 
        int (*probe) (struct usb_serial *serial, const struct usb_device_id *id);
        int (*attach) (struct usb_serial *serial);
diff --git a/include/linux/usb_ch9.h b/include/linux/usb_ch9.h
deleted file mode 100644 (file)
index c720d10..0000000
+++ /dev/null
@@ -1,562 +0,0 @@
-/*
- * This file holds USB constants and structures that are needed for USB
- * device APIs.  These are used by the USB device model, which is defined
- * in chapter 9 of the USB 2.0 specification.  Linux has several APIs in C
- * that need these:
- *
- * - the master/host side Linux-USB kernel driver API;
- * - the "usbfs" user space API; and
- * - the Linux "gadget" slave/device/peripheral side driver API.
- *
- * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems
- * act either as a USB master/host or as a USB slave/device.  That means
- * the master and slave side APIs benefit from working well together.
- *
- * There's also "Wireless USB", using low power short range radios for
- * peripheral interconnection but otherwise building on the USB framework.
- */
-
-#ifndef __LINUX_USB_CH9_H
-#define __LINUX_USB_CH9_H
-
-#include <linux/types.h>       /* __u8 etc */
-
-/*-------------------------------------------------------------------------*/
-
-/* CONTROL REQUEST SUPPORT */
-
-/*
- * USB directions
- *
- * This bit flag is used in endpoint descriptors' bEndpointAddress field.
- * It's also one of three fields in control requests bRequestType.
- */
-#define USB_DIR_OUT                    0               /* to device */
-#define USB_DIR_IN                     0x80            /* to host */
-
-/*
- * USB types, the second of three bRequestType fields
- */
-#define USB_TYPE_MASK                  (0x03 << 5)
-#define USB_TYPE_STANDARD              (0x00 << 5)
-#define USB_TYPE_CLASS                 (0x01 << 5)
-#define USB_TYPE_VENDOR                        (0x02 << 5)
-#define USB_TYPE_RESERVED              (0x03 << 5)
-
-/*
- * USB recipients, the third of three bRequestType fields
- */
-#define USB_RECIP_MASK                 0x1f
-#define USB_RECIP_DEVICE               0x00
-#define USB_RECIP_INTERFACE            0x01
-#define USB_RECIP_ENDPOINT             0x02
-#define USB_RECIP_OTHER                        0x03
-/* From Wireless USB 1.0 */
-#define USB_RECIP_PORT                         0x04
-#define USB_RECIP_RPIPE                0x05
-
-/*
- * Standard requests, for the bRequest field of a SETUP packet.
- *
- * These are qualified by the bRequestType field, so that for example
- * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved
- * by a GET_STATUS request.
- */
-#define USB_REQ_GET_STATUS             0x00
-#define USB_REQ_CLEAR_FEATURE          0x01
-#define USB_REQ_SET_FEATURE            0x03
-#define USB_REQ_SET_ADDRESS            0x05
-#define USB_REQ_GET_DESCRIPTOR         0x06
-#define USB_REQ_SET_DESCRIPTOR         0x07
-#define USB_REQ_GET_CONFIGURATION      0x08
-#define USB_REQ_SET_CONFIGURATION      0x09
-#define USB_REQ_GET_INTERFACE          0x0A
-#define USB_REQ_SET_INTERFACE          0x0B
-#define USB_REQ_SYNCH_FRAME            0x0C
-
-#define USB_REQ_SET_ENCRYPTION         0x0D    /* Wireless USB */
-#define USB_REQ_GET_ENCRYPTION         0x0E
-#define USB_REQ_RPIPE_ABORT            0x0E
-#define USB_REQ_SET_HANDSHAKE          0x0F
-#define USB_REQ_RPIPE_RESET            0x0F
-#define USB_REQ_GET_HANDSHAKE          0x10
-#define USB_REQ_SET_CONNECTION         0x11
-#define USB_REQ_SET_SECURITY_DATA      0x12
-#define USB_REQ_GET_SECURITY_DATA      0x13
-#define USB_REQ_SET_WUSB_DATA          0x14
-#define USB_REQ_LOOPBACK_DATA_WRITE    0x15
-#define USB_REQ_LOOPBACK_DATA_READ     0x16
-#define USB_REQ_SET_INTERFACE_DS       0x17
-
-/*
- * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and
- * are read as a bit array returned by USB_REQ_GET_STATUS.  (So there
- * are at most sixteen features of each type.)
- */
-#define USB_DEVICE_SELF_POWERED                0       /* (read only) */
-#define USB_DEVICE_REMOTE_WAKEUP       1       /* dev may initiate wakeup */
-#define USB_DEVICE_TEST_MODE           2       /* (wired high speed only) */
-#define USB_DEVICE_BATTERY             2       /* (wireless) */
-#define USB_DEVICE_B_HNP_ENABLE                3       /* (otg) dev may initiate HNP */
-#define USB_DEVICE_WUSB_DEVICE         3       /* (wireless)*/
-#define USB_DEVICE_A_HNP_SUPPORT       4       /* (otg) RH port supports HNP */
-#define USB_DEVICE_A_ALT_HNP_SUPPORT   5       /* (otg) other RH port does */
-#define USB_DEVICE_DEBUG_MODE          6       /* (special devices only) */
-
-#define USB_ENDPOINT_HALT              0       /* IN/OUT will STALL */
-
-
-/**
- * struct usb_ctrlrequest - SETUP data for a USB device control request
- * @bRequestType: matches the USB bmRequestType field
- * @bRequest: matches the USB bRequest field
- * @wValue: matches the USB wValue field (le16 byte order)
- * @wIndex: matches the USB wIndex field (le16 byte order)
- * @wLength: matches the USB wLength field (le16 byte order)
- *
- * This structure is used to send control requests to a USB device.  It matches
- * the different fields of the USB 2.0 Spec section 9.3, table 9-2.  See the
- * USB spec for a fuller description of the different fields, and what they are
- * used for.
- *
- * Note that the driver for any interface can issue control requests.
- * For most devices, interfaces don't coordinate with each other, so
- * such requests may be made at any time.
- */
-struct usb_ctrlrequest {
-       __u8 bRequestType;
-       __u8 bRequest;
-       __le16 wValue;
-       __le16 wIndex;
-       __le16 wLength;
-} __attribute__ ((packed));
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or
- * (rarely) accepted by SET_DESCRIPTOR.
- *
- * Note that all multi-byte values here are encoded in little endian
- * byte order "on the wire".  But when exposed through Linux-USB APIs,
- * they've been converted to cpu byte order.
- */
-
-/*
- * Descriptor types ... USB 2.0 spec table 9.5
- */
-#define USB_DT_DEVICE                  0x01
-#define USB_DT_CONFIG                  0x02
-#define USB_DT_STRING                  0x03
-#define USB_DT_INTERFACE               0x04
-#define USB_DT_ENDPOINT                        0x05
-#define USB_DT_DEVICE_QUALIFIER                0x06
-#define USB_DT_OTHER_SPEED_CONFIG      0x07
-#define USB_DT_INTERFACE_POWER         0x08
-/* these are from a minor usb 2.0 revision (ECN) */
-#define USB_DT_OTG                     0x09
-#define USB_DT_DEBUG                   0x0a
-#define USB_DT_INTERFACE_ASSOCIATION   0x0b
-/* these are from the Wireless USB spec */
-#define USB_DT_SECURITY                        0x0c
-#define USB_DT_KEY                     0x0d
-#define USB_DT_ENCRYPTION_TYPE         0x0e
-#define USB_DT_BOS                     0x0f
-#define USB_DT_DEVICE_CAPABILITY       0x10
-#define USB_DT_WIRELESS_ENDPOINT_COMP  0x11
-#define USB_DT_WIRE_ADAPTER            0x21
-#define USB_DT_RPIPE                   0x22
-
-/* conventional codes for class-specific descriptors */
-#define USB_DT_CS_DEVICE               0x21
-#define USB_DT_CS_CONFIG               0x22
-#define USB_DT_CS_STRING               0x23
-#define USB_DT_CS_INTERFACE            0x24
-#define USB_DT_CS_ENDPOINT             0x25
-
-/* All standard descriptors have these 2 fields at the beginning */
-struct usb_descriptor_header {
-       __u8  bLength;
-       __u8  bDescriptorType;
-} __attribute__ ((packed));
-
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_DEVICE: Device descriptor */
-struct usb_device_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __le16 bcdUSB;
-       __u8  bDeviceClass;
-       __u8  bDeviceSubClass;
-       __u8  bDeviceProtocol;
-       __u8  bMaxPacketSize0;
-       __le16 idVendor;
-       __le16 idProduct;
-       __le16 bcdDevice;
-       __u8  iManufacturer;
-       __u8  iProduct;
-       __u8  iSerialNumber;
-       __u8  bNumConfigurations;
-} __attribute__ ((packed));
-
-#define USB_DT_DEVICE_SIZE             18
-
-
-/*
- * Device and/or Interface Class codes
- * as found in bDeviceClass or bInterfaceClass
- * and defined by www.usb.org documents
- */
-#define USB_CLASS_PER_INTERFACE                0       /* for DeviceClass */
-#define USB_CLASS_AUDIO                        1
-#define USB_CLASS_COMM                 2
-#define USB_CLASS_HID                  3
-#define USB_CLASS_PHYSICAL             5
-#define USB_CLASS_STILL_IMAGE          6
-#define USB_CLASS_PRINTER              7
-#define USB_CLASS_MASS_STORAGE         8
-#define USB_CLASS_HUB                  9
-#define USB_CLASS_CDC_DATA             0x0a
-#define USB_CLASS_CSCID                        0x0b    /* chip+ smart card */
-#define USB_CLASS_CONTENT_SEC          0x0d    /* content security */
-#define USB_CLASS_VIDEO                        0x0e
-#define USB_CLASS_WIRELESS_CONTROLLER  0xe0
-#define USB_CLASS_APP_SPEC             0xfe
-#define USB_CLASS_VENDOR_SPEC          0xff
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_CONFIG: Configuration descriptor information.
- *
- * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the
- * descriptor type is different.  Highspeed-capable devices can look
- * different depending on what speed they're currently running.  Only
- * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG
- * descriptors.
- */
-struct usb_config_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __le16 wTotalLength;
-       __u8  bNumInterfaces;
-       __u8  bConfigurationValue;
-       __u8  iConfiguration;
-       __u8  bmAttributes;
-       __u8  bMaxPower;
-} __attribute__ ((packed));
-
-#define USB_DT_CONFIG_SIZE             9
-
-/* from config descriptor bmAttributes */
-#define USB_CONFIG_ATT_ONE             (1 << 7)        /* must be set */
-#define USB_CONFIG_ATT_SELFPOWER       (1 << 6)        /* self powered */
-#define USB_CONFIG_ATT_WAKEUP          (1 << 5)        /* can wakeup */
-#define USB_CONFIG_ATT_BATTERY         (1 << 4)        /* battery powered */
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_STRING: String descriptor */
-struct usb_string_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __le16 wData[1];                /* UTF-16LE encoded */
-} __attribute__ ((packed));
-
-/* note that "string" zero is special, it holds language codes that
- * the device supports, not Unicode characters.
- */
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_INTERFACE: Interface descriptor */
-struct usb_interface_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __u8  bInterfaceNumber;
-       __u8  bAlternateSetting;
-       __u8  bNumEndpoints;
-       __u8  bInterfaceClass;
-       __u8  bInterfaceSubClass;
-       __u8  bInterfaceProtocol;
-       __u8  iInterface;
-} __attribute__ ((packed));
-
-#define USB_DT_INTERFACE_SIZE          9
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_ENDPOINT: Endpoint descriptor */
-struct usb_endpoint_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __u8  bEndpointAddress;
-       __u8  bmAttributes;
-       __le16 wMaxPacketSize;
-       __u8  bInterval;
-
-       /* NOTE:  these two are _only_ in audio endpoints. */
-       /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
-       __u8  bRefresh;
-       __u8  bSynchAddress;
-} __attribute__ ((packed));
-
-#define USB_DT_ENDPOINT_SIZE           7
-#define USB_DT_ENDPOINT_AUDIO_SIZE     9       /* Audio extension */
-
-
-/*
- * Endpoints
- */
-#define USB_ENDPOINT_NUMBER_MASK       0x0f    /* in bEndpointAddress */
-#define USB_ENDPOINT_DIR_MASK          0x80
-
-#define USB_ENDPOINT_XFERTYPE_MASK     0x03    /* in bmAttributes */
-#define USB_ENDPOINT_XFER_CONTROL      0
-#define USB_ENDPOINT_XFER_ISOC         1
-#define USB_ENDPOINT_XFER_BULK         2
-#define USB_ENDPOINT_XFER_INT          3
-#define USB_ENDPOINT_MAX_ADJUSTABLE    0x80
-
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */
-struct usb_qualifier_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __le16 bcdUSB;
-       __u8  bDeviceClass;
-       __u8  bDeviceSubClass;
-       __u8  bDeviceProtocol;
-       __u8  bMaxPacketSize0;
-       __u8  bNumConfigurations;
-       __u8  bRESERVED;
-} __attribute__ ((packed));
-
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_OTG (from OTG 1.0a supplement) */
-struct usb_otg_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __u8  bmAttributes;     /* support for HNP, SRP, etc */
-} __attribute__ ((packed));
-
-/* from usb_otg_descriptor.bmAttributes */
-#define USB_OTG_SRP            (1 << 0)
-#define USB_OTG_HNP            (1 << 1)        /* swap host/device roles */
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_DEBUG:  for special highspeed devices, replacing serial console */
-struct usb_debug_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       /* bulk endpoints with 8 byte maxpacket */
-       __u8  bDebugInEndpoint;
-       __u8  bDebugOutEndpoint;
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_INTERFACE_ASSOCIATION: groups interfaces */
-struct usb_interface_assoc_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __u8  bFirstInterface;
-       __u8  bInterfaceCount;
-       __u8  bFunctionClass;
-       __u8  bFunctionSubClass;
-       __u8  bFunctionProtocol;
-       __u8  iFunction;
-} __attribute__ ((packed));
-
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_SECURITY:  group of wireless security descriptors, including
- * encryption types available for setting up a CC/association.
- */
-struct usb_security_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __le16 wTotalLength;
-       __u8  bNumEncryptionTypes;
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_KEY:  used with {GET,SET}_SECURITY_DATA; only public keys
- * may be retrieved.
- */
-struct usb_key_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __u8  tTKID[3];
-       __u8  bReserved;
-       __u8  bKeyData[0];
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_ENCRYPTION_TYPE:  bundled in DT_SECURITY groups */
-struct usb_encryption_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __u8  bEncryptionType;
-#define        USB_ENC_TYPE_UNSECURE           0
-#define        USB_ENC_TYPE_WIRED              1       /* non-wireless mode */
-#define        USB_ENC_TYPE_CCM_1              2       /* aes128/cbc session */
-#define        USB_ENC_TYPE_RSA_1              3       /* rsa3072/sha1 auth */
-       __u8  bEncryptionValue;         /* use in SET_ENCRYPTION */
-       __u8  bAuthKeyIndex;
-};
-
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_BOS:  group of wireless capabilities */
-struct usb_bos_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __le16 wTotalLength;
-       __u8  bNumDeviceCaps;
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_DEVICE_CAPABILITY:  grouped with BOS */
-struct usb_dev_cap_header {
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDevCapabilityType;
-};
-
-#define        USB_CAP_TYPE_WIRELESS_USB       1
-
-struct usb_wireless_cap_descriptor {   /* Ultra Wide Band */
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDevCapabilityType;
-
-       __u8  bmAttributes;
-#define        USB_WIRELESS_P2P_DRD            (1 << 1)
-#define        USB_WIRELESS_BEACON_MASK        (3 << 2)
-#define        USB_WIRELESS_BEACON_SELF        (1 << 2)
-#define        USB_WIRELESS_BEACON_DIRECTED    (2 << 2)
-#define        USB_WIRELESS_BEACON_NONE        (3 << 2)
-       __le16 wPHYRates;       /* bit rates, Mbps */
-#define        USB_WIRELESS_PHY_53             (1 << 0)        /* always set */
-#define        USB_WIRELESS_PHY_80             (1 << 1)
-#define        USB_WIRELESS_PHY_107            (1 << 2)        /* always set */
-#define        USB_WIRELESS_PHY_160            (1 << 3)
-#define        USB_WIRELESS_PHY_200            (1 << 4)        /* always set */
-#define        USB_WIRELESS_PHY_320            (1 << 5)
-#define        USB_WIRELESS_PHY_400            (1 << 6)
-#define        USB_WIRELESS_PHY_480            (1 << 7)
-       __u8  bmTFITXPowerInfo; /* TFI power levels */
-       __u8  bmFFITXPowerInfo; /* FFI power levels */
-       __le16 bmBandGroup;
-       __u8  bReserved;
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_WIRELESS_ENDPOINT_COMP:  companion descriptor associated with
- * each endpoint descriptor for a wireless device
- */
-struct usb_wireless_ep_comp_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __u8  bMaxBurst;
-       __u8  bMaxSequence;
-       __le16 wMaxStreamDelay;
-       __le16 wOverTheAirPacketSize;
-       __u8  bOverTheAirInterval;
-       __u8  bmCompAttributes;
-#define USB_ENDPOINT_SWITCH_MASK       0x03    /* in bmCompAttributes */
-#define USB_ENDPOINT_SWITCH_NO         0
-#define USB_ENDPOINT_SWITCH_SWITCH     1
-#define USB_ENDPOINT_SWITCH_SCALE      2
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_REQ_SET_HANDSHAKE is a four-way handshake used between a wireless
- * host and a device for connection set up, mutual authentication, and
- * exchanging short lived session keys.  The handshake depends on a CC.
- */
-struct usb_handshake {
-       __u8 bMessageNumber;
-       __u8 bStatus;
-       __u8 tTKID[3];
-       __u8 bReserved;
-       __u8 CDID[16];
-       __u8 nonce[16];
-       __u8 MIC[8];
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_REQ_SET_CONNECTION modifies or revokes a connection context (CC).
- * A CC may also be set up using non-wireless secure channels (including
- * wired USB!), and some devices may support CCs with multiple hosts.
- */
-struct usb_connection_context {
-       __u8 CHID[16];          /* persistent host id */
-       __u8 CDID[16];          /* device id (unique w/in host context) */
-       __u8 CK[16];            /* connection key */
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* USB 2.0 defines three speeds, here's how Linux identifies them */
-
-enum usb_device_speed {
-       USB_SPEED_UNKNOWN = 0,                  /* enumerating */
-       USB_SPEED_LOW, USB_SPEED_FULL,          /* usb 1.1 */
-       USB_SPEED_HIGH,                         /* usb 2.0 */
-       USB_SPEED_VARIABLE,                     /* wireless (usb 2.5) */
-};
-
-enum usb_device_state {
-       /* NOTATTACHED isn't in the USB spec, and this state acts
-        * the same as ATTACHED ... but it's clearer this way.
-        */
-       USB_STATE_NOTATTACHED = 0,
-
-       /* chapter 9 and authentication (wireless) device states */
-       USB_STATE_ATTACHED,
-       USB_STATE_POWERED,                      /* wired */
-       USB_STATE_UNAUTHENTICATED,              /* auth */
-       USB_STATE_RECONNECTING,                 /* auth */
-       USB_STATE_DEFAULT,                      /* limited function */
-       USB_STATE_ADDRESS,
-       USB_STATE_CONFIGURED,                   /* most functions */
-
-       USB_STATE_SUSPENDED
-
-       /* NOTE:  there are actually four different SUSPENDED
-        * states, returning to POWERED, DEFAULT, ADDRESS, or
-        * CONFIGURED respectively when SOF tokens flow again.
-        */
-};
-
-#endif /* __LINUX_USB_CH9_H */
index b53d6ae..8086d5a 100644 (file)
@@ -2,7 +2,7 @@
 #include <asm/types.h>
 #include <asm/ioctl.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 
 /*
  * Filesystem based user-mode API to USB Gadget controller hardware