ChangeSet 1.2181.4.56, 2005/03/24 14:29:06-08:00, [EMAIL PROTECTED]

[PATCH] USB: pxa25x udc updates, mostly PM

This has various updates to the PXA 21x/25x/26x UDC driver.

    - Implement the "new" pullup() and vbus_session() methods, and
      use them to keep the UDC 48 MHz clock off much of the time.

        * Reworked that ugly Lubbock VBUS IRQ code.  Claim both IRQs,
          enable only one at a time; clock the UDC only when VBUS is
          present.  (And get rid of rude runtime messages.)

        * Implement driver model suspend() and resume() calls.  When
          this device suspends, it clocks off the UDC.  On boards that
          support it (including Zaurus clamshells, but not Lubbock)
          the D+ pullup is disabled, so the host won't see the device.

    - Hmm, the "latest" errata defined some "Must Be One" bits.  OK.

    - Change the LED support for debugging.  It stopped compiling for
      Lubbock a while back.  This switches to the standard LED calls
      (so it can work on non-Lubbock hardware), removes the EP0 calls
      (not very useful any more), and for Lubbock now initializes the
      hex leds (U-Boot doesn't enable them, BLOB did).

    - "sparse" updates, and get rid of a warning that's pointless
      unless someone's working on DMA support;

Tested on Lubbock (VBUS sensing but no pullup) and some Zaurus
clamshells (pullup but no VBUS).

Signed-off-by: David Brownell <[EMAIL PROTECTED]>
Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>


 drivers/usb/gadget/pxa2xx_udc.c |  279 ++++++++++++++++++++++++++--------------
 drivers/usb/gadget/pxa2xx_udc.h |   29 ++--
 2 files changed, 199 insertions(+), 109 deletions(-)


diff -Nru a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
--- a/drivers/usb/gadget/pxa2xx_udc.c   2005-03-30 13:34:28 -08:00
+++ b/drivers/usb/gadget/pxa2xx_udc.c   2005-03-30 13:34:28 -08:00
@@ -310,7 +310,7 @@
        /* flush fifo (mostly for IN buffers) */
        pxa2xx_ep_fifo_flush (_ep);
 
-       ep->desc = 0;
+       ep->desc = NULL;
        ep->stopped = 1;
 
        DBG(DBG_VERBOSE, "%s disabled\n", _ep->name);
@@ -334,7 +334,7 @@
 
        req = kmalloc (sizeof *req, gfp_flags);
        if (!req)
-               return 0;
+               return NULL;
 
        memset (req, 0, sizeof *req);
        INIT_LIST_HEAD (&req->queue);
@@ -369,7 +369,11 @@
 
        retval = kmalloc (bytes, gfp_flags & ~(__GFP_DMA|__GFP_HIGHMEM));
        if (retval)
+#ifdef USE_DMA
                *dma = virt_to_bus (retval);
+#else
+               *dma = (dma_addr_t)~0;
+#endif
        return retval;
 }
 
@@ -411,7 +415,6 @@
 static inline void ep0_idle (struct pxa2xx_udc *dev)
 {
        dev->ep0state = EP0_IDLE;
-       LED_EP0_OFF;
 }
 
 static int
@@ -930,7 +933,7 @@
                        case EP0_IN_DATA_PHASE:
                                dev->stats.write.ops++;
                                if (write_ep0_fifo(ep, req))
-                                       req = 0;
+                                       req = NULL;
                                break;
 
                        case EP0_OUT_DATA_PHASE:
@@ -940,7 +943,8 @@
                                        DBG(DBG_VERBOSE, "ep0 config ack%s\n",
                                                dev->has_cfr ?  "" : " raced");
                                        if (dev->has_cfr)
-                                               UDCCFR = UDCCFR_AREN|UDCCFR_ACM;
+                                               UDCCFR = UDCCFR_AREN|UDCCFR_ACM
+                                                       |UDCCFR_MB1;
                                        done(ep, req, 0);
                                        dev->ep0state = EP0_END_XFER;
                                        local_irq_restore (flags);
@@ -952,7 +956,7 @@
                                                && read_ep0_fifo(ep, req))) {
                                        ep0_idle(dev);
                                        done(ep, req, 0);
-                                       req = 0;
+                                       req = NULL;
                                }
                                break;
 
@@ -970,10 +974,10 @@
                } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0
                                && (*ep->reg_udccs & UDCCS_BI_TFS) != 0
                                && write_fifo(ep, req)) {
-                       req = 0;
+                       req = NULL;
                } else if ((*ep->reg_udccs & UDCCS_BO_RFS) != 0
                                && read_fifo(ep, req)) {
-                       req = 0;
+                       req = NULL;
                }
 
                if (likely (req && ep->desc) && ep->dma < 0)
@@ -1094,7 +1098,6 @@
                start_watchdog(ep->dev);
                ep->dev->req_pending = 0;
                ep->dev->ep0state = EP0_STALL;
-               LED_EP0_OFF;
 
        /* and bulk/intr endpoints like dropping stalls too */
        } else {
@@ -1194,13 +1197,71 @@
        return 0;
 }
 
+static void stop_activity(struct pxa2xx_udc *, struct usb_gadget_driver *);
+static void udc_enable (struct pxa2xx_udc *);
+static void udc_disable(struct pxa2xx_udc *);
+
+/* We disable the UDC -- and its 48 MHz clock -- whenever it's not
+ * in active use.  
+ */
+static int pullup(struct pxa2xx_udc *udc, int is_active)
+{
+       is_active = is_active && udc->vbus && udc->pullup;
+       DMSG("%s\n", is_active ? "active" : "inactive");
+       if (is_active)
+               udc_enable(udc);
+       else {
+               if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
+                       DMSG("disconnect %s\n", udc->driver
+                               ? udc->driver->driver.name
+                               : "(no driver)");
+                       stop_activity(udc, udc->driver);
+               }
+               udc_disable(udc);
+       }
+       return 0;
+}
+
+/* VBUS reporting logically comes from a transceiver */
+static int pxa2xx_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
+{
+       struct pxa2xx_udc       *udc;
+
+       udc = container_of(_gadget, struct pxa2xx_udc, gadget);
+       udc->vbus = is_active = (is_active != 0);
+       DMSG("vbus %s\n", is_active ? "supplied" : "inactive");
+       pullup(udc, is_active);
+       return 0;
+}
+
+/* drivers may have software control over D+ pullup */
+static int pxa2xx_udc_pullup(struct usb_gadget *_gadget, int is_active)
+{
+       struct pxa2xx_udc       *udc;
+
+       udc = container_of(_gadget, struct pxa2xx_udc, gadget);
+
+       /* not all boards support pullup control */
+       if (!udc->mach->udc_command)
+               return -EOPNOTSUPP;
+
+       is_active = (is_active != 0);
+       udc->pullup = is_active;
+       pullup(udc, is_active);
+       return 0;
+}
+
 static const struct usb_gadget_ops pxa2xx_udc_ops = {
-       .get_frame       = pxa2xx_udc_get_frame,
-       .wakeup          = pxa2xx_udc_wakeup,
-       // current versions must always be self-powered
+       .get_frame      = pxa2xx_udc_get_frame,
+       .wakeup         = pxa2xx_udc_wakeup,
+       .vbus_session   = pxa2xx_udc_vbus_session,
+       .pullup         = pxa2xx_udc_pullup,
+
+       // .vbus_draw ... boards may consume current from VBUS, up to
+       // 100-500mA based on config.  the 500uA suspend ceiling means
+       // that exclusively vbus-powered PXA designs violate USB specs.
 };
 
-
 /*-------------------------------------------------------------------------*/
 
 #ifdef CONFIG_USB_GADGET_DEBUG_FILES
@@ -1427,7 +1488,7 @@
                if (i != 0)
                        list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
 
-               ep->desc = 0;
+               ep->desc = NULL;
                ep->stopped = 0;
                INIT_LIST_HEAD (&ep->queue);
                ep->pio_irqs = ep->dma_irqs = 0;
@@ -1446,6 +1507,7 @@
 #ifdef CONFIG_ARCH_PXA
         /* Enable clock for USB device */
        pxa_set_cken(CKEN11_USB, 1);
+       udelay(5);
 #endif
 
        /* try to clear these bits before we enable the udc */
@@ -1469,7 +1531,7 @@
                /* pxa255 (a0+) can avoid a set_config race that could
                 * prevent gadget drivers from configuring correctly
                 */
-               UDCCFR = UDCCFR_ACM;
+               UDCCFR = UDCCFR_ACM | UDCCFR_MB1;
        } else {
                /* "USB test mode" for pxa250 errata 40-42 (stepping a0, a1)
                 * which could result in missing packets and interrupts.
@@ -1498,18 +1560,13 @@
        }
 #endif
 
-       /* caller must be able to sleep in order to cope
-        * with startup transients.
-        */
-       msleep(100);
-
        /* enable suspend/resume and reset irqs */
        udc_clear_mask_UDCCR(UDCCR_SRM | UDCCR_REM);
 
        /* enable ep0 irqs */
        UICR0 &= ~UICR0_IM0;
 
-       /* if hardware supports it, connect to usb and wait for host */
+       /* if hardware supports it, pullup D+ and wait for reset */
        let_usb_appear();
 }
 
@@ -1540,6 +1597,7 @@
        /* first hook up the driver ... */
        dev->driver = driver;
        dev->gadget.dev.driver = &driver->driver;
+       dev->pullup = 1;
 
        device_add (&dev->gadget.dev);
        retval = driver->bind(&dev->gadget);
@@ -1548,18 +1606,17 @@
                                driver->driver.name, retval);
                device_del (&dev->gadget.dev);
 
-               dev->driver = 0;
-               dev->gadget.dev.driver = 0;
+               dev->driver = NULL;
+               dev->gadget.dev.driver = NULL;
                return retval;
        }
        device_create_file(dev->dev, &dev_attr_function);
 
        /* ... then enable host detection and ep0; and we're ready
         * for set_configuration as well as eventual disconnect.
-        * NOTE:  this shouldn't power up until later.
         */
        DMSG("registered gadget driver '%s'\n", driver->driver.name);
-       udc_enable(dev);
+       pullup(dev, 1);
        dump_state(dev);
        return 0;
 }
@@ -1572,7 +1629,7 @@
 
        /* don't disconnect drivers more than once */
        if (dev->gadget.speed == USB_SPEED_UNKNOWN)
-               driver = 0;
+               driver = NULL;
        dev->gadget.speed = USB_SPEED_UNKNOWN;
 
        /* prevent new request submissions, kill any outstanding requests  */
@@ -1603,12 +1660,12 @@
                return -EINVAL;
 
        local_irq_disable();
-       udc_disable(dev);
+       pullup(dev, 0);
        stop_activity(dev, driver);
        local_irq_enable();
 
        driver->unbind(&dev->gadget);
-       dev->driver = 0;
+       dev->driver = NULL;
 
        device_del (&dev->gadget.dev);
        device_remove_file(dev->dev, &dev_attr_function);
@@ -1624,61 +1681,41 @@
 
 #ifdef CONFIG_ARCH_LUBBOCK
 
-/* Lubbock can report connect or disconnect irqs.  Likely more hardware
- * could support it as a timer callback.
- *
- * FIXME for better power management, keep the hardware powered down
- * until a host is powering the link.  means scheduling work later
- * in some task that can udc_enable().
+/* Lubbock has separate connect and disconnect irqs.  More typical designs
+ * use one GPIO as the VBUS IRQ, and another to control the D+ pullup.
  */
 
-#define        enable_disconnect_irq() \
-       if (machine_is_lubbock()) { enable_irq(LUBBOCK_USB_DISC_IRQ); }
-#define        disable_disconnect_irq() \
-       if (machine_is_lubbock()) { disable_irq(LUBBOCK_USB_DISC_IRQ); }
-
 static irqreturn_t
-usb_connection_irq(int irq, void *_dev, struct pt_regs *r)
+lubbock_vbus_irq(int irq, void *_dev, struct pt_regs *r)
 {
        struct pxa2xx_udc       *dev = _dev;
+       int                     vbus;
 
        dev->stats.irqs++;
        HEX_DISPLAY(dev->stats.irqs);
-
-       if (!is_usb_connected()) {
-               LED_CONNECTED_OFF;
-               disable_disconnect_irq();
-               /* report disconnect just once */
-               if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
-                       DMSG("disconnect %s\n",
-                               dev->driver ? dev->driver->driver.name : 0);
-                       stop_activity(dev, dev->driver);
-
-                       // udc_disable (dev);
-                       // no more udc irqs
-                       // maybe "ACTION=disconnect /sbin/hotplug gadget".
-               }
-       } else if (dev->gadget.speed == USB_SPEED_UNKNOWN) {
+       switch (irq) {
+       case LUBBOCK_USB_IRQ:
                LED_CONNECTED_ON;
-
-               DMSG("?? connect irq ??\n");
-
-               // if there's no driver bound, ignore; else
-               // udc_enable (dev);
-               // UDC irqs drive the rest.
-               // maybe "ACTION=connect /sbin/hotplug gadget".
+               vbus = 1;
+               disable_irq(LUBBOCK_USB_IRQ);
+               enable_irq(LUBBOCK_USB_DISC_IRQ);
+               break;
+       case LUBBOCK_USB_DISC_IRQ:
+               LED_CONNECTED_OFF;
+               vbus = 0;
+               disable_irq(LUBBOCK_USB_DISC_IRQ);
+               enable_irq(LUBBOCK_USB_IRQ);
+               break;
+       default:
+               return IRQ_NONE;
        }
+
+       pxa2xx_udc_vbus_session(&dev->gadget, vbus);
        return IRQ_HANDLED;
 }
 
 #endif
 
-#ifndef        enable_disconnect_irq
-#warning USB disconnect() is not yet reported.
-#define        enable_disconnect_irq()         do {} while (0)
-#define        disable_disconnect_irq()        do {} while (0)
-#endif
-
 
 /*-------------------------------------------------------------------------*/
 
@@ -1720,7 +1757,7 @@
        } u;
 
        if (list_empty(&ep->queue))
-               req = 0;
+               req = NULL;
        else
                req = list_entry(ep->queue.next, struct pxa2xx_request, queue);
 
@@ -1764,14 +1801,11 @@
                                goto bad_setup;
 
 got_setup:
-                       le16_to_cpus (&u.r.wValue);
-                       le16_to_cpus (&u.r.wIndex);
-                       le16_to_cpus (&u.r.wLength);
-
-                       LED_EP0_ON;
                        DBG(DBG_VERBOSE, "SETUP %02x.%02x v%04x i%04x l%04x\n",
                                u.r.bRequestType, u.r.bRequest,
-                               u.r.wValue, u.r.wIndex, u.r.wLength);
+                               le16_to_cpu(u.r.wValue),
+                               le16_to_cpu(u.r.wIndex),
+                               le16_to_cpu(u.r.wLength));
 
                        /* cope with automagic for some standard requests. */
                        dev->req_std = (u.r.bRequestType & USB_TYPE_MASK)
@@ -1803,7 +1837,8 @@
                                         *  - ep reset doesn't include halt(?).
                                         */
                                        DMSG("broken set_interface (%d/%d)\n",
-                                               u.r.wIndex, u.r.wValue);
+                                               le16_to_cpu(u.r.wIndex),
+                                               le16_to_cpu(u.r.wValue));
                                        goto config_change;
                                }
                                break;
@@ -1847,7 +1882,6 @@
                                ep0start(dev, UDCCS0_FST|UDCCS0_FTF, "stall");
                                start_watchdog(dev);
                                dev->ep0state = EP0_STALL;
-                               LED_EP0_OFF;
 
                        /* deferred i/o == no response yet */
                        } else if (dev->req_pending) {
@@ -1948,7 +1982,7 @@
                        req = list_entry(ep->queue.next,
                                        struct pxa2xx_request, queue);
                else
-                       req = 0;
+                       req = NULL;
 
                // TODO check FST handling
 
@@ -2050,8 +2084,6 @@
 
                        if ((UDCCR & UDCCR_UDA) == 0) {
                                DBG(DBG_VERBOSE, "USB reset start\n");
-                               if (dev->gadget.speed != USB_SPEED_UNKNOWN)
-                                       disable_disconnect_irq();
 
                                /* reset driver and endpoints,
                                 * in case that's not yet done
@@ -2059,12 +2091,11 @@
                                stop_activity (dev, dev->driver);
 
                        } else {
-                               INFO("USB reset\n");
+                               DBG(DBG_VERBOSE, "USB reset end\n");
                                dev->gadget.speed = USB_SPEED_FULL;
                                LED_CONNECTED_ON;
                                memset(&dev->stats, 0, sizeof dev->stats);
                                /* driver and endpoints are still reset */
-                               enable_disconnect_irq();
                        }
 
                } else {
@@ -2478,6 +2509,8 @@
        udc_disable(dev);
        udc_reinit(dev);
 
+       dev->vbus = is_usb_connected();
+
        /* irq setup after old hardware state is cleaned up */
        retval = request_irq(IRQ_USB, pxa2xx_udc_irq,
                        SA_INTERRUPT, driver_name, dev);
@@ -2490,18 +2523,32 @@
 
 #ifdef CONFIG_ARCH_LUBBOCK
        if (machine_is_lubbock()) {
-               disable_irq(LUBBOCK_USB_DISC_IRQ);
                retval = request_irq(LUBBOCK_USB_DISC_IRQ,
-                               usb_connection_irq,
-                               SA_INTERRUPT /* OOPSING | SA_SAMPLE_RANDOM */,
+                               lubbock_vbus_irq,
+                               SA_INTERRUPT | SA_SAMPLE_RANDOM,
                                driver_name, dev);
                if (retval != 0) {
-                       enable_irq(LUBBOCK_USB_DISC_IRQ);
                        printk(KERN_ERR "%s: can't get irq %i, err %d\n",
                                driver_name, LUBBOCK_USB_DISC_IRQ, retval);
+lubbock_fail0:
+                       free_irq(IRQ_USB, dev);
                        return -EBUSY;
                }
-               dev->got_disc = 1;
+               retval = request_irq(LUBBOCK_USB_IRQ,
+                               lubbock_vbus_irq,
+                               SA_INTERRUPT | SA_SAMPLE_RANDOM,
+                               driver_name, dev);
+               if (retval != 0) {
+                       printk(KERN_ERR "%s: can't get irq %i, err %d\n",
+                               driver_name, LUBBOCK_USB_IRQ, retval);
+                       free_irq(LUBBOCK_USB_DISC_IRQ, dev);
+                       goto lubbock_fail0;
+               }
+#ifdef DEBUG
+               /* with U-Boot (but not BLOB), hex is off by default */
+               HEX_DISPLAY(dev->stats.irqs);
+               LUB_DISC_BLNK_LED &= 0xff;
+#endif
        }
 #endif
        create_proc_files();
@@ -2510,7 +2557,7 @@
 }
 static int __exit pxa2xx_udc_remove(struct device *_dev)
 {
-       struct pxa2xx_udc *dev = _dev->driver_data;
+       struct pxa2xx_udc *dev = dev_get_drvdata(_dev);
 
        udc_disable(dev);
        remove_proc_files();
@@ -2520,26 +2567,66 @@
                free_irq(IRQ_USB, dev);
                dev->got_irq = 0;
        }
-       if (machine_is_lubbock() && dev->got_disc) {
+       if (machine_is_lubbock()) {
                free_irq(LUBBOCK_USB_DISC_IRQ, dev);
-               dev->got_disc = 0;
+               free_irq(LUBBOCK_USB_IRQ, dev);
        }
-       dev_set_drvdata(_dev, 0);
-       the_controller = 0;
+       dev_set_drvdata(_dev, NULL);
+       the_controller = NULL;
        return 0;
 }
 
 /*-------------------------------------------------------------------------*/
 
+#ifdef CONFIG_PM
+
+/* USB suspend (controlled by the host) and system suspend (controlled
+ * by the PXA) don't necessarily work well together.  If USB is active,
+ * the 48 MHz clock is required; so the system can't enter 33 MHz idle
+ * mode, or any deeper PM saving state.
+ *
+ * For now, we punt and forcibly disconnect from the USB host when PXA
+ * enters any suspend state.  While we're disconnected, we always disable
+ * the 48MHz USB clock ... allowing PXA sleep and/or 33 MHz idle states. 
+ * Boards without software pullup control shouldn't use those states.
+ * VBUS IRQs should probably be ignored so that the PXA device just acts
+ * "dead" to USB hosts until system resume.
+ */
+static int pxa2xx_udc_suspend(struct device *dev, u32 state, u32 level)
+{
+       struct pxa2xx_udc       *udc = dev_get_drvdata(dev);
+
+       if (level == SUSPEND_POWER_DOWN) {
+               if (!udc->mach->udc_command)
+                       WARN("USB host won't detect disconnect!\n");
+               pullup(udc, 0);
+       }
+       return 0;
+}
+
+static int pxa2xx_udc_resume(struct device *dev, u32 level)
+{
+       struct pxa2xx_udc       *udc = dev_get_drvdata(dev);
+
+       if (level == RESUME_POWER_ON)
+               pullup(udc, 1);
+       return 0;
+}
+
+#else
+#define        pxa2xx_udc_suspend      NULL
+#define        pxa2xx_udc_resume       NULL
+#endif
+
+/*-------------------------------------------------------------------------*/
+
 static struct device_driver udc_driver = {
        .name           = "pxa2xx-udc",
        .bus            = &platform_bus_type,
        .probe          = pxa2xx_udc_probe,
        .remove         = __exit_p(pxa2xx_udc_remove),
-
-       // FIXME power management support
-       // .suspend = ... disable UDC
-       // .resume = ... re-enable UDC
+       .suspend        = pxa2xx_udc_suspend,
+       .resume         = pxa2xx_udc_resume,
 };
 
 static int __init udc_init(void)
diff -Nru a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
--- a/drivers/usb/gadget/pxa2xx_udc.h   2005-03-30 13:34:28 -08:00
+++ b/drivers/usb/gadget/pxa2xx_udc.h   2005-03-30 13:34:28 -08:00
@@ -40,6 +40,9 @@
 #define UDCCFR_AREN    (1 << 7)        /* ACK response enable (now) */
 #define UDCCFR_ACM     (1 << 2)        /* ACK control mode (wait for AREN) */
 
+/* latest pxa255 errata define new "must be one" bits in UDCCFR */
+#define        UDCCFR_MB1      (0xff & ~(UDCCFR_AREN|UDCCFR_ACM))
+
 /*-------------------------------------------------------------------------*/
 
 struct pxa2xx_udc;
@@ -120,7 +123,8 @@
        enum ep0_state                          ep0state;
        struct udc_stats                        stats;
        unsigned                                got_irq : 1,
-                                               got_disc : 1,
+                                               vbus : 1,
+                                               pullup : 1,
                                                has_cfr : 1,
                                                req_pending : 1,
                                                req_std : 1,
@@ -143,14 +147,7 @@
 
 #ifdef DEBUG
 #define HEX_DISPLAY(n) if (machine_is_lubbock()) { LUB_HEXLED = (n); }
-
-#define LED_CONNECTED_ON       if (machine_is_lubbock()) { \
-       DISCRETE_LED_ON(D26); }
-#define LED_CONNECTED_OFF      if(machine_is_lubbock()) { \
-       DISCRETE_LED_OFF(D26); LUB_HEXLED = 0; }
-#define LED_EP0_ON     if (machine_is_lubbock()) { DISCRETE_LED_ON(D25); }
-#define LED_EP0_OFF    if (machine_is_lubbock()) { DISCRETE_LED_OFF(D25); }
-#endif /* DEBUG */
+#endif
 
 #endif
 
@@ -161,13 +158,19 @@
 #define HEX_DISPLAY(n)         do {} while(0)
 #endif
 
+#ifdef DEBUG
+#include <asm/leds.h>
+
+#define LED_CONNECTED_ON       leds_event(led_green_on)
+#define LED_CONNECTED_OFF      do { \
+                                       leds_event(led_green_off); \
+                                       HEX_DISPLAY(0); \
+                               } while(0)
+#endif
+
 #ifndef LED_CONNECTED_ON
 #define LED_CONNECTED_ON       do {} while(0)
 #define LED_CONNECTED_OFF      do {} while(0)
-#endif
-#ifndef LED_EP0_ON
-#define LED_EP0_ON             do {} while (0)
-#define LED_EP0_OFF            do {} while (0)
 #endif
 
 /*-------------------------------------------------------------------------*/



-------------------------------------------------------
This SF.net email is sponsored by Demarc:
A global provider of Threat Management Solutions.
Download our HomeAdmin security software for free today!
http://www.demarc.com/info/Sentarus/hamr30
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to