Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / usb / gadget / zero.c
index 2e220d3..68e3d8f 100644 (file)
@@ -75,8 +75,7 @@
 #include <linux/timer.h>
 #include <linux/list.h>
 #include <linux/interrupt.h>
-#include <linux/uts.h>
-#include <linux/version.h>
+#include <linux/utsname.h>
 #include <linux/device.h>
 #include <linux/moduleparam.h>
 
@@ -130,6 +129,9 @@ struct zero_dev {
         */
        u8                      config;
        struct usb_ep           *in_ep, *out_ep;
+
+       /* autoresume timer */
+       struct timer_list       resume;
 };
 
 #define xprintk(d,level,fmt,args...) \
@@ -163,10 +165,16 @@ static unsigned buflen = 4096;
 static unsigned qlen = 32;
 static unsigned pattern = 0;
 
-module_param (buflen, uint, S_IRUGO|S_IWUSR);
-module_param (qlen, uint, S_IRUGO|S_IWUSR);
+module_param (buflen, uint, S_IRUGO);
+module_param (qlen, uint, S_IRUGO);
 module_param (pattern, uint, S_IRUGO|S_IWUSR);
 
+/*
+ * if it's nonzero, autoresume says how many seconds to wait
+ * before trying to wake up the host after suspend.
+ */
+static unsigned autoresume = 0;
+module_param (autoresume, uint, 0);
 
 /*
  * Normally the "loopback" configuration is second (index 1) so
@@ -185,8 +193,13 @@ module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
  * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
  * Instead:  allocate your own, using normal USB-IF procedures.
  */
+#ifndef        CONFIG_USB_ZERO_HNPTEST
 #define DRIVER_VENDOR_NUM      0x0525          /* NetChip */
 #define DRIVER_PRODUCT_NUM     0xa4a0          /* Linux-USB "Gadget Zero" */
+#else
+#define DRIVER_VENDOR_NUM      0x1a0a          /* OTG test device IDs */
+#define DRIVER_PRODUCT_NUM     0xbadd
+#endif
 
 /*-------------------------------------------------------------------------*/
 
@@ -224,7 +237,7 @@ device_desc = {
        .bNumConfigurations =   2,
 };
 
-static const struct usb_config_descriptor
+static struct usb_config_descriptor
 source_sink_config = {
        .bLength =              sizeof source_sink_config,
        .bDescriptorType =      USB_DT_CONFIG,
@@ -237,7 +250,7 @@ source_sink_config = {
        .bMaxPower =            1,      /* self-powered */
 };
 
-static const struct usb_config_descriptor
+static struct usb_config_descriptor
 loopback_config = {
        .bLength =              sizeof loopback_config,
        .bDescriptorType =      USB_DT_CONFIG,
@@ -250,6 +263,14 @@ loopback_config = {
        .bMaxPower =            1,      /* self-powered */
 };
 
+static struct usb_otg_descriptor
+otg_descriptor = {
+       .bLength =              sizeof otg_descriptor,
+       .bDescriptorType =      USB_DT_OTG,
+
+       .bmAttributes =         USB_OTG_SRP,
+};
+
 /* one interface in each configuration */
 
 static const struct usb_interface_descriptor
@@ -293,17 +314,19 @@ fs_sink_desc = {
 };
 
 static const struct usb_descriptor_header *fs_source_sink_function [] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
        (struct usb_descriptor_header *) &source_sink_intf,
        (struct usb_descriptor_header *) &fs_sink_desc,
        (struct usb_descriptor_header *) &fs_source_desc,
-       0,
+       NULL,
 };
 
 static const struct usb_descriptor_header *fs_loopback_function [] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
        (struct usb_descriptor_header *) &loopback_intf,
        (struct usb_descriptor_header *) &fs_sink_desc,
        (struct usb_descriptor_header *) &fs_source_desc,
-       0,
+       NULL,
 };
 
 #ifdef CONFIG_USB_GADGET_DUALSPEED
@@ -347,17 +370,19 @@ dev_qualifier = {
 };
 
 static const struct usb_descriptor_header *hs_source_sink_function [] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
        (struct usb_descriptor_header *) &source_sink_intf,
        (struct usb_descriptor_header *) &hs_source_desc,
        (struct usb_descriptor_header *) &hs_sink_desc,
-       0,
+       NULL,
 };
 
 static const struct usb_descriptor_header *hs_loopback_function [] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
        (struct usb_descriptor_header *) &loopback_intf,
        (struct usb_descriptor_header *) &hs_source_desc,
        (struct usb_descriptor_header *) &hs_sink_desc,
-       0,
+       NULL,
 };
 
 /* maxpacket and other transfer characteristics vary by speed. */
@@ -370,10 +395,10 @@ static const struct usb_descriptor_header *hs_loopback_function [] = {
 
 #endif /* !CONFIG_USB_GADGET_DUALSPEED */
 
-static char                            manufacturer [40];
+static char                            manufacturer [50];
 static char                            serial [40];
 
-/* static strings, in iso 8859/1 */
+/* static strings, in UTF-8 */
 static struct usb_string               strings [] = {
        { STRING_MANUFACTURER, manufacturer, },
        { STRING_PRODUCT, longname, },
@@ -435,6 +460,10 @@ config_buf (struct usb_gadget *gadget,
                        ? fs_source_sink_function
                        : fs_loopback_function;
 
+       /* for now, don't advertise srp-only devices */
+       if (!gadget->is_otg)
+               function++;
+
        len = usb_gadget_config_buf (is_source_sink
                                        ? &source_sink_config
                                        : &loopback_config,
@@ -459,7 +488,7 @@ alloc_ep_req (struct usb_ep *ep, unsigned length)
                                &req->dma, GFP_ATOMIC);
                if (!req->buf) {
                        usb_ep_free_request (ep, req);
-                       req = 0;
+                       req = NULL;
                }
        }
        return req;
@@ -476,7 +505,7 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
 
 /* optionally require specific source/sink data patterns  */
 
-static inline int
+static int
 check_read_data (
        struct zero_dev         *dev,
        struct usb_ep           *ep,
@@ -510,7 +539,7 @@ check_read_data (
        return 0;
 }
 
-static inline void
+static void
 reinit_write_data (
        struct zero_dev         *dev,
        struct usb_ep           *ep,
@@ -543,9 +572,10 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
        switch (status) {
 
        case 0:                         /* normal completion? */
-               if (ep == dev->out_ep)
+               if (ep == dev->out_ep) {
                        check_read_data (dev, ep, req);
-               else
+                       memset (req->buf, 0x55, req->length);
+               } else
                        reinit_write_data (dev, ep, req);
                break;
 
@@ -583,20 +613,22 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
 }
 
 static struct usb_request *
-source_sink_start_ep (struct usb_ep *ep, int gfp_flags)
+source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
 {
        struct usb_request      *req;
        int                     status;
 
        req = alloc_ep_req (ep, buflen);
        if (!req)
-               return 0;
+               return NULL;
 
        memset (req->buf, 0, req->length);
        req->complete = source_sink_complete;
 
        if (strcmp (ep->name, EP_IN_NAME) == 0)
                reinit_write_data (ep->driver_data, ep, req);
+       else
+               memset (req->buf, 0x55, req->length);
 
        status = usb_ep_queue (ep, req, gfp_flags);
        if (status) {
@@ -604,14 +636,14 @@ source_sink_start_ep (struct usb_ep *ep, int gfp_flags)
 
                ERROR (dev, "start %s --> %d\n", ep->name, status);
                free_ep_req (ep, req);
-               req = 0;
+               req = NULL;
        }
 
        return req;
 }
 
 static int
-set_source_sink_config (struct zero_dev *dev, int gfp_flags)
+set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
 {
        int                     result = 0;
        struct usb_ep           *ep;
@@ -715,7 +747,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
 }
 
 static int
-set_loopback_config (struct zero_dev *dev, int gfp_flags)
+set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags)
 {
        int                     result = 0;
        struct usb_ep           *ep;
@@ -795,13 +827,14 @@ static void zero_reset_config (struct zero_dev *dev)
         */
        if (dev->in_ep) {
                usb_ep_disable (dev->in_ep);
-               dev->in_ep = 0;
+               dev->in_ep = NULL;
        }
        if (dev->out_ep) {
                usb_ep_disable (dev->out_ep);
-               dev->out_ep = 0;
+               dev->out_ep = NULL;
        }
        dev->config = 0;
+       del_timer (&dev->resume);
 }
 
 /* change our operational config.  this code must agree with the code
@@ -815,7 +848,7 @@ static void zero_reset_config (struct zero_dev *dev)
  * by limiting configuration choices (like the pxa2xx).
  */
 static int
-zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags)
+zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
 {
        int                     result = 0;
        struct usb_gadget       *gadget = dev->gadget;
@@ -889,26 +922,30 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
        struct zero_dev         *dev = get_gadget_data (gadget);
        struct usb_request      *req = dev->req;
        int                     value = -EOPNOTSUPP;
+       u16                     w_index = le16_to_cpu(ctrl->wIndex);
+       u16                     w_value = le16_to_cpu(ctrl->wValue);
+       u16                     w_length = le16_to_cpu(ctrl->wLength);
 
        /* usually this stores reply data in the pre-allocated ep0 buffer,
         * but config change events will reconfigure hardware.
         */
+       req->zero = 0;
        switch (ctrl->bRequest) {
 
        case USB_REQ_GET_DESCRIPTOR:
                if (ctrl->bRequestType != USB_DIR_IN)
                        goto unknown;
-               switch (ctrl->wValue >> 8) {
+               switch (w_value >> 8) {
 
                case USB_DT_DEVICE:
-                       value = min (ctrl->wLength, (u16) sizeof device_desc);
+                       value = min (w_length, (u16) sizeof device_desc);
                        memcpy (req->buf, &device_desc, value);
                        break;
 #ifdef CONFIG_USB_GADGET_DUALSPEED
                case USB_DT_DEVICE_QUALIFIER:
                        if (!gadget->is_dualspeed)
                                break;
-                       value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
+                       value = min (w_length, (u16) sizeof dev_qualifier);
                        memcpy (req->buf, &dev_qualifier, value);
                        break;
 
@@ -919,21 +956,22 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 #endif /* CONFIG_USB_GADGET_DUALSPEED */
                case USB_DT_CONFIG:
                        value = config_buf (gadget, req->buf,
-                                       ctrl->wValue >> 8,
-                                       ctrl->wValue & 0xff);
+                                       w_value >> 8,
+                                       w_value & 0xff);
                        if (value >= 0)
-                               value = min (ctrl->wLength, (u16) value);
+                               value = min (w_length, (u16) value);
                        break;
 
                case USB_DT_STRING:
                        /* wIndex == language code.
                         * this driver only handles one language, you can
-                        * add others even if they don't use iso8859/1
+                        * add string tables for other languages, using
+                        * any UTF-8 characters
                         */
                        value = usb_gadget_get_string (&stringtab,
-                                       ctrl->wValue & 0xff, req->buf);
+                                       w_value & 0xff, req->buf);
                        if (value >= 0)
-                               value = min (ctrl->wLength, (u16) value);
+                               value = min (w_length, (u16) value);
                        break;
                }
                break;
@@ -942,15 +980,21 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
        case USB_REQ_SET_CONFIGURATION:
                if (ctrl->bRequestType != 0)
                        goto unknown;
+               if (gadget->a_hnp_support)
+                       DBG (dev, "HNP available\n");
+               else if (gadget->a_alt_hnp_support)
+                       DBG (dev, "HNP needs a different root port\n");
+               else
+                       VDBG (dev, "HNP inactive\n");
                spin_lock (&dev->lock);
-               value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC);
+               value = zero_set_config (dev, w_value, GFP_ATOMIC);
                spin_unlock (&dev->lock);
                break;
        case USB_REQ_GET_CONFIGURATION:
                if (ctrl->bRequestType != USB_DIR_IN)
                        goto unknown;
                *(u8 *)req->buf = dev->config;
-               value = min (ctrl->wLength, (u16) 1);
+               value = min (w_length, (u16) 1);
                break;
 
        /* until we add altsetting support, or other interfaces,
@@ -961,7 +1005,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                if (ctrl->bRequestType != USB_RECIP_INTERFACE)
                        goto unknown;
                spin_lock (&dev->lock);
-               if (dev->config && ctrl->wIndex == 0 && ctrl->wValue == 0) {
+               if (dev->config && w_index == 0 && w_value == 0) {
                        u8              config = dev->config;
 
                        /* resets interface configuration, forgets about
@@ -982,12 +1026,12 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                        goto unknown;
                if (!dev->config)
                        break;
-               if (ctrl->wIndex != 0) {
+               if (w_index != 0) {
                        value = -EDOM;
                        break;
                }
                *(u8 *)req->buf = 0;
-               value = min (ctrl->wLength, (u16) 1);
+               value = min (w_length, (u16) 1);
                break;
 
        /*
@@ -998,23 +1042,23 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
        case 0x5b:      /* control WRITE test -- fill the buffer */
                if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
                        goto unknown;
-               if (ctrl->wValue || ctrl->wIndex)
+               if (w_value || w_index)
                        break;
                /* just read that many bytes into the buffer */
-               if (ctrl->wLength > USB_BUFSIZ)
+               if (w_length > USB_BUFSIZ)
                        break;
-               value = ctrl->wLength;
+               value = w_length;
                break;
        case 0x5c:      /* control READ test -- return the buffer */
                if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
                        goto unknown;
-               if (ctrl->wValue || ctrl->wIndex)
+               if (w_value || w_index)
                        break;
                /* expect those bytes are still in the buffer; send back */
-               if (ctrl->wLength > USB_BUFSIZ
-                               || ctrl->wLength != req->length)
+               if (w_length > USB_BUFSIZ
+                               || w_length != req->length)
                        break;
-               value = ctrl->wLength;
+               value = w_length;
                break;
 
        default:
@@ -1022,12 +1066,13 @@ unknown:
                VDBG (dev,
                        "unknown control req%02x.%02x v%04x i%04x l%d\n",
                        ctrl->bRequestType, ctrl->bRequest,
-                       ctrl->wValue, ctrl->wIndex, ctrl->wLength);
+                       w_value, w_index, w_length);
        }
 
        /* respond with data transfer before status phase? */
        if (value >= 0) {
                req->length = value;
+               req->zero = value < w_length;
                value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
                if (value < 0) {
                        DBG (dev, "ep_queue --> %d\n", value);
@@ -1060,9 +1105,24 @@ zero_disconnect (struct usb_gadget *gadget)
         */
 }
 
+static void
+zero_autoresume (unsigned long _dev)
+{
+       struct zero_dev *dev = (struct zero_dev *) _dev;
+       int             status;
+
+       /* normally the host would be woken up for something
+        * more significant than just a timer firing...
+        */
+       if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
+               status = usb_gadget_wakeup (dev->gadget);
+               DBG (dev, "wakeup --> %d\n", status);
+       }
+}
+
 /*-------------------------------------------------------------------------*/
 
-static void
+static void __exit
 zero_unbind (struct usb_gadget *gadget)
 {
        struct zero_dev         *dev = get_gadget_data (gadget);
@@ -1070,17 +1130,27 @@ zero_unbind (struct usb_gadget *gadget)
        DBG (dev, "unbind\n");
 
        /* we've already been disconnected ... no i/o is active */
-       if (dev->req)
+       if (dev->req) {
+               dev->req->length = USB_BUFSIZ;
                free_ep_req (gadget->ep0, dev->req);
+       }
+       del_timer_sync (&dev->resume);
        kfree (dev);
-       set_gadget_data (gadget, 0);
+       set_gadget_data (gadget, NULL);
 }
 
-static int
+static int __init
 zero_bind (struct usb_gadget *gadget)
 {
        struct zero_dev         *dev;
        struct usb_ep           *ep;
+       int                     gcnum;
+
+       /* FIXME this can't yet work right with SH ... it has only
+        * one configuration, numbered one.
+        */
+       if (gadget_is_sh(gadget))
+               return -ENODEV;
 
        /* Bulk-only drivers like this one SHOULD be able to
         * autoconfigure on any sane usb controller driver,
@@ -1103,33 +1173,10 @@ autoconf_fail:
        EP_OUT_NAME = ep->name;
        ep->driver_data = ep;   /* claim */
 
-
-       /*
-        * DRIVER POLICY CHOICE:  you may want to do this differently.
-        * One thing to avoid is reusing a bcdDevice revision code
-        * with different host-visible configurations or behavior
-        * restrictions -- using ep1in/ep2out vs ep1out/ep3in, etc
-        */
-       if (gadget_is_net2280 (gadget)) {
-               device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201);
-       } else if (gadget_is_pxa (gadget)) {
-               device_desc.bcdDevice = __constant_cpu_to_le16 (0x0203);
-#if 0
-       } else if (gadget_is_sh(gadget)) {
-               device_desc.bcdDevice = __constant_cpu_to_le16 (0x0204);
-               /* SH has only one configuration; see "loopdefault" */
-               device_desc.bNumConfigurations = 1;
-               /* FIXME make 1 == default.bConfigurationValue */
-#endif
-       } else if (gadget_is_sa1100 (gadget)) {
-               device_desc.bcdDevice = __constant_cpu_to_le16 (0x0205);
-       } else if (gadget_is_goku (gadget)) {
-               device_desc.bcdDevice = __constant_cpu_to_le16 (0x0206);
-       } else if (gadget_is_mq11xx (gadget)) {
-               device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207);
-       } else if (gadget_is_omap (gadget)) {
-               device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208);
-       } else {
+       gcnum = usb_gadget_controller_number (gadget);
+       if (gcnum >= 0)
+               device_desc.bcdDevice = cpu_to_le16 (0x0200 + gcnum);
+       else {
                /* gadget zero is so simple (for now, no altsettings) that
                 * it SHOULD NOT have problems with bulk-capable hardware.
                 * so warn about unrcognized controllers, don't panic.
@@ -1144,10 +1191,9 @@ autoconf_fail:
 
 
        /* ok, we made sense of the hardware ... */
-       dev = kmalloc (sizeof *dev, SLAB_KERNEL);
+       dev = kzalloc(sizeof(*dev), SLAB_KERNEL);
        if (!dev)
                return -ENOMEM;
-       memset (dev, 0, sizeof *dev);
        spin_lock_init (&dev->lock);
        dev->gadget = gadget;
        set_gadget_data (gadget, dev);
@@ -1174,16 +1220,30 @@ autoconf_fail:
        hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
 #endif
 
+       if (gadget->is_otg) {
+               otg_descriptor.bmAttributes |= USB_OTG_HNP,
+               source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+               loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+
        usb_gadget_set_selfpowered (gadget);
 
+       init_timer (&dev->resume);
+       dev->resume.function = zero_autoresume;
+       dev->resume.data = (unsigned long) dev;
+       if (autoresume) {
+               source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+               loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+
        gadget->ep0->driver_data = dev;
 
        INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
        INFO (dev, "using %s, OUT %s IN %s\n", gadget->name,
                EP_OUT_NAME, EP_IN_NAME);
 
-       snprintf (manufacturer, sizeof manufacturer,
-               UTS_SYSNAME " " UTS_RELEASE " with %s",
+       snprintf (manufacturer, sizeof manufacturer, "%s %s with %s",
+               system_utsname.sysname, system_utsname.release,
                gadget->name);
 
        return 0;
@@ -1193,6 +1253,33 @@ enomem:
        return -ENOMEM;
 }
 
+/*-------------------------------------------------------------------------*/
+
+static void
+zero_suspend (struct usb_gadget *gadget)
+{
+       struct zero_dev         *dev = get_gadget_data (gadget);
+
+       if (gadget->speed == USB_SPEED_UNKNOWN)
+               return;
+
+       if (autoresume) {
+               mod_timer (&dev->resume, jiffies + (HZ * autoresume));
+               DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
+       } else
+               DBG (dev, "suspend\n");
+}
+
+static void
+zero_resume (struct usb_gadget *gadget)
+{
+       struct zero_dev         *dev = get_gadget_data (gadget);
+
+       DBG (dev, "resume\n");
+       del_timer (&dev->resume);
+}
+
+
 /*-------------------------------------------------------------------------*/
 
 static struct usb_gadget_driver zero_driver = {
@@ -1203,16 +1290,17 @@ static struct usb_gadget_driver zero_driver = {
 #endif
        .function       = (char *) longname,
        .bind           = zero_bind,
-       .unbind         = zero_unbind,
+       .unbind         = __exit_p(zero_unbind),
 
        .setup          = zero_setup,
        .disconnect     = zero_disconnect,
 
+       .suspend        = zero_suspend,
+       .resume         = zero_resume,
+
        .driver         = {
                .name           = (char *) shortname,
-               // .shutdown = ...
-               // .suspend = ...
-               // .resume = ...
+               .owner          = THIS_MODULE,
        },
 };