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 (ð_driver); + return usb_func_register(ð_driver); } module_init (init); static void __exit cleanup (void) { - usb_gadget_unregister_driver (ð_driver); + usb_func_unregister(ð_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