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/
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel