From: Ragner Magalhaes <[EMAIL PROTECTED]>

This patch adds some features that let the ether gadget
to work as a usb_function module.

Signed-off-by: Felipe Balbi <[EMAIL PROTECTED]>
Signed-off-by: Ragner Magalhaes <[EMAIL PROTECTED]>
---

 drivers/usb/gadget/ether.c |   98 +++++++++++++++++++++-----------------------
 1 files changed, 47 insertions(+), 51 deletions(-)

diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 325bf7c..5a6cfd7 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -48,6 +48,7 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
 #include <linux/usb_gadget.h>
+#include <linux/usb/composite.h>
 
 #include <linux/random.h>
 #include <linux/netdevice.h>
@@ -117,6 +118,7 @@ static const char driver_desc [] = DRIVER_DESC;
 struct eth_dev {
        spinlock_t              lock;
        struct usb_gadget       *gadget;
+       struct usb_function     *f;
        struct usb_request      *req;           /* for control responses */
        struct usb_request      *stat_req;      /* for cdc & rndis status */
 
@@ -144,6 +146,8 @@ struct eth_dev {
        u8                      host_mac [ETH_ALEN];
 };
 
+static struct usb_function eth_driver;
+
 /* This version autoconfigures as much as possible at run-time.
  *
  * It also ASSUMES a self-powered device, without remote wakeup,
@@ -416,14 +420,15 @@ static inline int BITRATE(struct usb_gadget *g)
 
 #define STRING_MANUFACTURER            1
 #define STRING_PRODUCT                 2
-#define STRING_ETHADDR                 3
-#define STRING_DATA                    4
-#define STRING_CONTROL                 5
+#define STRING_SERIALNUMBER            3
+#define STRING_CDC                     4
+#define STRING_RNDIS                   5
+
 #define STRING_RNDIS_CONTROL           6
-#define STRING_CDC                     7
+#define STRING_DATA                    7
 #define STRING_SUBSET                  8
-#define STRING_RNDIS                   9
-#define STRING_SERIALNUMBER            10
+#define STRING_CONTROL                 9
+#define STRING_ETHADDR                 10
 
 /* holds our biggest descriptor (or RNDIS response) */
 #define USB_BUFSIZ     256
@@ -981,7 +986,7 @@ static struct usb_gadget_strings    stringtab = {
  * complications: class descriptors, and an altsetting.
  */
 static int
-config_buf (enum usb_device_speed speed,
+config_buf (struct eth_dev *dev,
        u8 *buf, u8 type,
        unsigned index, int is_otg)
 {
@@ -989,7 +994,7 @@ config_buf (enum usb_device_speed speed,
        const struct usb_config_descriptor      *config;
        const struct usb_descriptor_header      **function;
 #ifdef CONFIG_USB_GADGET_DUALSPEED
-       int                             hs = (speed == USB_SPEED_HIGH);
+       int     hs = (dev->gadget->speed == USB_SPEED_HIGH);
 
        if (type == USB_DT_OTHER_SPEED_CONFIG)
                hs = !hs;
@@ -1016,9 +1021,16 @@ config_buf (enum usb_device_speed speed,
        }
 
        /* for now, don't advertise srp-only devices */
-       if (!is_otg)
+       if (!is_otg || is_composite())
                function++;
 
+       if (is_composite()) {
+               dev->f->config[index] = config;
+               buf += dev->req->length;
+               len = USB_BUFSIZ - dev->req->length;
+               return usb_descriptor_fillbuf(buf, len, function);
+       }
+
        len = usb_gadget_config_buf (config, buf, USB_BUFSIZ, function);
        if (len < 0)
                return len;
@@ -1369,7 +1381,7 @@ static void rndis_command_complete (struct usb_ep *ep, 
struct usb_request *req)
 static int
 eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 {
-       struct eth_dev          *dev = get_gadget_data (gadget);
+       struct eth_dev          *dev = get_usb_function_data (gadget);
        struct usb_request      *req = dev->req;
        int                     value = -EOPNOTSUPP;
        u16                     wIndex = le16_to_cpu(ctrl->wIndex);
@@ -1380,6 +1392,8 @@ eth_setup (struct usb_gadget *gadget, const struct 
usb_ctrlrequest *ctrl)
         * while config change events may enable network traffic.
         */
        req->complete = eth_setup_complete;
+       if (is_composite())
+               gadget->ep0->driver_data = dev;
        switch (ctrl->bRequest) {
 
        case USB_REQ_GET_DESCRIPTOR:
@@ -1405,7 +1419,7 @@ eth_setup (struct usb_gadget *gadget, const struct 
usb_ctrlrequest *ctrl)
                        // FALLTHROUGH
 #endif /* CONFIG_USB_GADGET_DUALSPEED */
                case USB_DT_CONFIG:
-                       value = config_buf (gadget->speed, req->buf,
+                       value = config_buf (dev, req->buf,
                                        wValue >> 8,
                                        wValue & 0xff,
                                        gadget->is_otg);
@@ -1520,9 +1534,10 @@ done_set_intf:
 
                /* for CDC, iff carrier is on, data interface is active. */
                if (rndis_active(dev) || wIndex != 1)
-                       *(u8 *)req->buf = 0;
+                       *(u8 *)req->buf = INTRF_FUNC2COMPOSITE(dev->f,0);
                else
-                       *(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0;
+                       *(u8 *)req->buf = INTRF_FUNC2COMPOSITE(dev->f,
+                                       netif_carrier_ok (dev->net) ? 1 : 0);
                value = min (wLength, (u16) 1);
                break;
 
@@ -1598,19 +1613,6 @@ done_set_intf:
                        wValue, wIndex, wLength);
        }
 
-       /* respond with data transfer before status phase? */
-       if (value >= 0) {
-               req->length = value;
-               req->zero = value < wLength
-                               && (value % gadget->ep0->maxpacket) == 0;
-               value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
-               if (value < 0) {
-                       DEBUG (dev, "ep_queue --> %d\n", value);
-                       req->status = 0;
-                       eth_setup_complete (gadget->ep0, req);
-               }
-       }
-
        /* host either stalls (value < 0) or reports success */
        return value;
 }
@@ -1618,7 +1620,7 @@ done_set_intf:
 static void
 eth_disconnect (struct usb_gadget *gadget)
 {
-       struct eth_dev          *dev = get_gadget_data (gadget);
+       struct eth_dev          *dev = get_usb_function_data (gadget);
        unsigned long           flags;
 
        spin_lock_irqsave (&dev->lock, flags);
@@ -2217,17 +2219,19 @@ eth_req_free (struct usb_ep *ep, struct usb_request 
*req)
 static void /* __init_or_exit */
 eth_unbind (struct usb_gadget *gadget)
 {
-       struct eth_dev          *dev = get_gadget_data (gadget);
+       struct eth_dev          *dev = get_usb_function_data (gadget);
 
        DEBUG (dev, "unbind\n");
+
+       if (is_composite())
+               eth_reset_config (dev);
+
        rndis_deregister (dev->rndis_config);
        rndis_exit ();
 
        /* we've already been disconnected ... no i/o is active */
-       if (dev->req) {
-               eth_req_free (gadget->ep0, dev->req);
+       if (dev->req)
                dev->req = NULL;
-       }
        if (dev->stat_req) {
                eth_req_free (dev->status_ep, dev->stat_req);
                dev->stat_req = NULL;
@@ -2238,7 +2242,6 @@ eth_unbind (struct usb_gadget *gadget)
 
        /* assuming we used keventd, it must quiesce too */
        flush_scheduled_work ();
-       set_gadget_data (gadget, NULL);
 }
 
 static u8 __devinit nibble (unsigned char c)
@@ -2376,7 +2379,6 @@ eth_bind (struct usb_gadget *gadget)
        }
 
        /* all we really need is bulk IN/OUT */
-       usb_ep_autoconfig_reset (gadget);
        in_ep = usb_ep_autoconfig (gadget, &fs_source_desc);
        if (!in_ep) {
 autoconf_fail:
@@ -2520,9 +2522,7 @@ autoconf_fail:
        SET_ETHTOOL_OPS(net, &ops);
 
        /* preallocate control message data and buffer */
-       dev->req = eth_req_alloc (gadget->ep0, USB_BUFSIZ, GFP_KERNEL);
-       if (!dev->req)
-               goto fail;
+       dev->req = get_usb_gadget_request (gadget);
        dev->req->complete = eth_setup_complete;
 
        /* ... and maybe likewise for status transfer */
@@ -2531,7 +2531,6 @@ autoconf_fail:
                dev->stat_req = eth_req_alloc (dev->status_ep,
                                        STATUS_BYTECOUNT, GFP_KERNEL);
                if (!dev->stat_req) {
-                       eth_req_free (gadget->ep0, dev->req);
                        goto fail;
                }
                dev->stat_req->context = NULL;
@@ -2540,8 +2539,10 @@ autoconf_fail:
 
        /* finish hookup to lower layer ... */
        dev->gadget = gadget;
-       set_gadget_data (gadget, dev);
-       gadget->ep0->driver_data = dev;
+       dev->f = get_usb_function(gadget);
+       set_usb_function_data (dev->f, dev);
+
+       dev->f->num_conf = rndis ? 2 : 1;
 
        /* two kinds of host-initiated state changes:
         *  - iff DATA transfer is active, carrier is "on"
@@ -2614,7 +2615,7 @@ fail:
 static void
 eth_suspend (struct usb_gadget *gadget)
 {
-       struct eth_dev          *dev = get_gadget_data (gadget);
+       struct eth_dev          *dev = get_usb_function_data (gadget);
 
        DEBUG (dev, "suspend\n");
        dev->suspended = 1;
@@ -2623,7 +2624,7 @@ eth_suspend (struct usb_gadget *gadget)
 static void
 eth_resume (struct usb_gadget *gadget)
 {
-       struct eth_dev          *dev = get_gadget_data (gadget);
+       struct eth_dev          *dev = get_usb_function_data (gadget);
 
        DEBUG (dev, "resume\n");
        dev->suspended = 0;
@@ -2631,10 +2632,10 @@ eth_resume (struct usb_gadget *gadget)
 
 /*-------------------------------------------------------------------------*/
 
-static struct usb_gadget_driver eth_driver = {
-       .speed          = DEVSPEED,
+static struct usb_function eth_driver = {
+       .name           = (char *) shortname,
+       .strings        = &stringtab,
 
-       .function       = (char *) driver_desc,
        .bind           = eth_bind,
        .unbind         = eth_unbind,
 
@@ -2643,11 +2644,6 @@ static struct usb_gadget_driver eth_driver = {
 
        .suspend        = eth_suspend,
        .resume         = eth_resume,
-
-       .driver = {
-               .name           = (char *) shortname,
-               .owner          = THIS_MODULE,
-       },
 };
 
 MODULE_DESCRIPTION (DRIVER_DESC);
@@ -2657,13 +2653,13 @@ MODULE_LICENSE ("GPL");
 
 static int __init init (void)
 {
-       return usb_gadget_register_driver (&eth_driver);
+       return usb_func_register(&eth_driver);
 }
 module_init (init);
 
 static void __exit cleanup (void)
 {
-       usb_gadget_unregister_driver (&eth_driver);
+       usb_func_unregister(&eth_driver);
 }
 module_exit (cleanup);
 

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
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