X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fgadget%2Fether.c;h=48ec722d3091d161e3877fa0f4ea9d69c934aeab;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=2891eeeef61b9365a65cbeaf3656b18db8977470;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 2891eeeef..48ec722d3 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -36,8 +36,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -63,6 +62,7 @@ /* * Ethernet gadget driver -- with CDC and non-CDC options + * Builds on hardware support for a full duplex link. * * CDC Ethernet is the standard USB solution for sending Ethernet frames * using USB. Real hardware tends to use the same framing protocol but look @@ -83,7 +83,7 @@ */ #define DRIVER_DESC "Ethernet Gadget" -#define DRIVER_VERSION "St Patrick's Day 2004" +#define DRIVER_VERSION "Equinox 2004" static const char shortname [] = "ether"; static const char driver_desc [] = DRIVER_DESC; @@ -118,6 +118,7 @@ struct eth_dev { unsigned zlp:1; unsigned cdc:1; unsigned rndis:1; + unsigned suspended:1; u16 cdc_filter; unsigned long todo; #define WORK_RX_MEMORY 0 @@ -221,6 +222,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_CDC #endif +#ifdef CONFIG_USB_GADGET_LH7A40X +#define DEV_CONFIG_CDC +#endif + #ifdef CONFIG_USB_GADGET_MQ11XX #define DEV_CONFIG_CDC #endif @@ -229,11 +234,19 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_CDC #endif +#ifdef CONFIG_USB_GADGET_N9604 +#define DEV_CONFIG_CDC +#endif + +#ifdef CONFIG_USB_GADGET_PXA27X +#define DEV_CONFIG_CDC +#endif + /* For CDC-incapable hardware, choose the simple cdc subset. * Anything that talks bulk (without notable bugs) can do this. */ -#ifdef CONFIG_USB_GADGET_PXA +#ifdef CONFIG_USB_GADGET_PXA2XX #define DEV_CONFIG_SUBSET #endif @@ -337,6 +350,9 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR); * * NOTE: Controllers like superh_udc should probably be able to use * an RNDIS-only configuration. + * + * FIXME define some higher-powered configurations to make it easier + * to recharge batteries ... */ #define DEV_CONFIG_VALUE 1 /* cdc or subset */ @@ -360,6 +376,14 @@ device_desc = { .bNumConfigurations = 1, }; +static struct usb_otg_descriptor +otg_descriptor = { + .bLength = sizeof otg_descriptor, + .bDescriptorType = USB_DT_OTG, + + .bmAttributes = USB_OTG_SRP, +}; + static struct usb_config_descriptor eth_config = { .bLength = sizeof eth_config, @@ -370,11 +394,11 @@ eth_config = { .bConfigurationValue = DEV_CONFIG_VALUE, .iConfiguration = STRING_CDC, .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = 1, + .bMaxPower = 50, }; #ifdef CONFIG_USB_ETH_RNDIS -static const struct usb_config_descriptor +static struct usb_config_descriptor rndis_config = { .bLength = sizeof rndis_config, .bDescriptorType = USB_DT_CONFIG, @@ -384,7 +408,7 @@ rndis_config = { .bConfigurationValue = DEV_RNDIS_CONFIG_VALUE, .iConfiguration = STRING_RNDIS, .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = 1, + .bMaxPower = 50, }; #endif @@ -670,7 +694,8 @@ fs_sink_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; -static const struct usb_descriptor_header *fs_eth_function [10] = { +static const struct usb_descriptor_header *fs_eth_function [11] = { + (struct usb_descriptor_header *) &otg_descriptor, #ifdef DEV_CONFIG_CDC /* "cdc" mode descriptors */ (struct usb_descriptor_header *) &control_intf, @@ -684,24 +709,25 @@ static const struct usb_descriptor_header *fs_eth_function [10] = { (struct usb_descriptor_header *) &data_intf, (struct usb_descriptor_header *) &fs_source_desc, (struct usb_descriptor_header *) &fs_sink_desc, - 0, + NULL, #endif /* DEV_CONFIG_CDC */ }; static inline void __init fs_subset_descriptors(void) { #ifdef DEV_CONFIG_SUBSET - fs_eth_function[0] = (struct usb_descriptor_header *) &subset_data_intf; - fs_eth_function[1] = (struct usb_descriptor_header *) &fs_source_desc; - fs_eth_function[2] = (struct usb_descriptor_header *) &fs_sink_desc; - fs_eth_function[3] = 0; + fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf; + fs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc; + fs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc; + fs_eth_function[4] = NULL; #else - fs_eth_function[0] = 0; + fs_eth_function[1] = NULL; #endif } #ifdef CONFIG_USB_ETH_RNDIS static const struct usb_descriptor_header *fs_rndis_function [] = { + (struct usb_descriptor_header *) &otg_descriptor, /* control interface matches ACM, not Ethernet */ (struct usb_descriptor_header *) &rndis_control_intf, (struct usb_descriptor_header *) &header_desc, @@ -713,7 +739,7 @@ static const struct usb_descriptor_header *fs_rndis_function [] = { (struct usb_descriptor_header *) &rndis_data_intf, (struct usb_descriptor_header *) &fs_source_desc, (struct usb_descriptor_header *) &fs_sink_desc, - 0, + NULL, }; #endif @@ -765,7 +791,8 @@ dev_qualifier = { .bNumConfigurations = 1, }; -static const struct usb_descriptor_header *hs_eth_function [10] = { +static const struct usb_descriptor_header *hs_eth_function [11] = { + (struct usb_descriptor_header *) &otg_descriptor, #ifdef DEV_CONFIG_CDC /* "cdc" mode descriptors */ (struct usb_descriptor_header *) &control_intf, @@ -779,24 +806,25 @@ static const struct usb_descriptor_header *hs_eth_function [10] = { (struct usb_descriptor_header *) &data_intf, (struct usb_descriptor_header *) &hs_source_desc, (struct usb_descriptor_header *) &hs_sink_desc, - 0, + NULL, #endif /* DEV_CONFIG_CDC */ }; static inline void __init hs_subset_descriptors(void) { #ifdef DEV_CONFIG_SUBSET - hs_eth_function[0] = (struct usb_descriptor_header *) &subset_data_intf; - hs_eth_function[1] = (struct usb_descriptor_header *) &fs_source_desc; - hs_eth_function[2] = (struct usb_descriptor_header *) &fs_sink_desc; - hs_eth_function[3] = 0; + hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf; + hs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc; + hs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc; + hs_eth_function[4] = NULL; #else - hs_eth_function[0] = 0; + hs_eth_function[1] = NULL; #endif } #ifdef CONFIG_USB_ETH_RNDIS static const struct usb_descriptor_header *hs_rndis_function [] = { + (struct usb_descriptor_header *) &otg_descriptor, /* control interface matches ACM, not Ethernet */ (struct usb_descriptor_header *) &rndis_control_intf, (struct usb_descriptor_header *) &header_desc, @@ -808,7 +836,7 @@ static const struct usb_descriptor_header *hs_rndis_function [] = { (struct usb_descriptor_header *) &rndis_data_intf, (struct usb_descriptor_header *) &hs_source_desc, (struct usb_descriptor_header *) &hs_sink_desc, - 0, + NULL, }; #endif @@ -831,7 +859,7 @@ static inline void __init hs_subset_descriptors(void) /* descriptors that are built on-demand */ -static char manufacturer [40]; +static char manufacturer [50]; static char product_desc [40] = DRIVER_DESC; #ifdef DEV_CONFIG_CDC @@ -839,7 +867,7 @@ static char product_desc [40] = DRIVER_DESC; static char ethaddr [2 * ETH_ALEN + 1]; #endif -/* static strings, in iso 8859/1 */ +/* static strings, in UTF-8 */ static struct usb_string strings [] = { { STRING_MANUFACTURER, manufacturer, }, { STRING_PRODUCT, product_desc, }, @@ -869,19 +897,21 @@ static struct usb_gadget_strings stringtab = { * complications: class descriptors, and an altsetting. */ static int -config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index) +config_buf (enum usb_device_speed speed, + u8 *buf, u8 type, + unsigned index, int is_otg) { - int len; + int len; + const struct usb_config_descriptor *config; + const struct usb_descriptor_header **function; #ifdef CONFIG_USB_GADGET_DUALSPEED int hs = (speed == USB_SPEED_HIGH); if (type == USB_DT_OTHER_SPEED_CONFIG) hs = !hs; -#define which_config(t) (hs ? & t ## _config : & t ## _config) -#define which_fn(t) (hs ? & hs_ ## t ## _function : & fs_ ## t ## _function) +#define which_fn(t) (hs ? hs_ ## t ## _function : fs_ ## t ## _function) #else -#define which_config(t) (& t ## _config) -#define which_fn(t) (& fs_ ## t ## _function) +#define which_fn(t) (fs_ ## t ## _function) #endif if (index >= device_desc.bNumConfigurations) @@ -891,15 +921,21 @@ config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index) /* list the RNDIS config first, to make Microsoft's drivers * happy. DOCSIS 1.0 needs this too. */ - if (device_desc.bNumConfigurations == 2 && index == 0) - len = usb_gadget_config_buf (which_config (rndis), buf, - USB_BUFSIZ, (const struct usb_descriptor_header **) - which_fn (rndis)); - else + if (device_desc.bNumConfigurations == 2 && index == 0) { + config = &rndis_config; + function = which_fn (rndis); + } else #endif - len = usb_gadget_config_buf (which_config (eth), buf, - USB_BUFSIZ, (const struct usb_descriptor_header **) - which_fn (eth)); + { + config = ð_config; + function = which_fn (eth); + } + + /* for now, don't advertise srp-only devices */ + if (!is_otg) + function++; + + len = usb_gadget_config_buf (config, buf, USB_BUFSIZ, function); if (len < 0) return len; ((struct usb_config_descriptor *) buf)->bDescriptorType = type; @@ -1050,8 +1086,8 @@ set_ether_config (struct eth_dev *dev, int gfp_flags) if (dev->status_ep) (void) usb_ep_disable (dev->status_ep); #endif - dev->status_ep = 0; - dev->status = 0; + dev->status_ep = NULL; + dev->status = NULL; #if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS) if (dev->rndis || !dev->cdc) { if (dev->in_ep) @@ -1060,10 +1096,10 @@ set_ether_config (struct eth_dev *dev, int gfp_flags) (void) usb_ep_disable (dev->out_ep); } #endif - dev->in_ep = 0; - dev->in = 0; - dev->out_ep = 0; - dev->out = 0; + dev->in_ep = NULL; + dev->in = NULL; + dev->out_ep = NULL; + dev->out = NULL; } else /* activate non-CDC configs right away @@ -1110,7 +1146,7 @@ static void eth_reset_config (struct eth_dev *dev) list_del (&req->list); usb_ep_free_request (dev->in_ep, req); } - dev->in_ep = 0; + dev->in_ep = NULL; } if (dev->out_ep) { usb_ep_disable (dev->out_ep); @@ -1120,12 +1156,12 @@ static void eth_reset_config (struct eth_dev *dev) list_del (&req->list); usb_ep_free_request (dev->out_ep, req); } - dev->out_ep = 0; + dev->out_ep = NULL; } if (dev->status_ep) { usb_ep_disable (dev->status_ep); - dev->status_ep = 0; + dev->status_ep = NULL; } dev->config = 0; } @@ -1169,13 +1205,20 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) result = -EINVAL; /* FALL THROUGH */ case 0: - return result; + break; } - if (result) - eth_reset_config (dev); - else { + if (result) { + if (number) + eth_reset_config (dev); + usb_gadget_vbus_draw(dev->gadget, + dev->gadget->is_otg ? 8 : 100); + } else { char *speed; + unsigned power; + + power = 2 * eth_config.bMaxPower; + usb_gadget_vbus_draw(dev->gadget, power); switch (gadget->speed) { case USB_SPEED_FULL: speed = "full"; break; @@ -1186,8 +1229,8 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags) } dev->config = number; - INFO (dev, "%s speed config #%d: %s, using %s\n", - speed, number, driver_desc, + INFO (dev, "%s speed config #%d: %d mA, %s, using %s\n", + speed, number, power, driver_desc, dev->rndis ? "RNDIS" : (dev->cdc @@ -1345,24 +1388,24 @@ static void eth_setup_complete (struct usb_ep *ep, struct usb_request *req) static void rndis_response_complete (struct usb_ep *ep, struct usb_request *req) { - struct eth_dev *dev = ep->driver_data; - if (req->status || req->actual != req->length) - DEBUG (dev, "rndis response complete --> %d, %d/%d\n", - req->status, req->actual, req->length); + DEBUG ((struct eth_dev *) ep->driver_data, + "rndis response complete --> %d, %d/%d\n", + req->status, req->actual, req->length); /* done sending after CDC_GET_ENCAPSULATED_RESPONSE */ - rndis_free_response (dev->rndis_config, req->buf); } static void rndis_command_complete (struct usb_ep *ep, struct usb_request *req) { struct eth_dev *dev = ep->driver_data; + int status; /* received RNDIS command from CDC_SEND_ENCAPSULATED_COMMAND */ spin_lock(&dev->lock); - if (rndis_msg_parser (dev->rndis_config, (u8 *) req->buf)) - ERROR(dev, "%s: rndis parse error\n", __FUNCTION__ ); + status = rndis_msg_parser (dev->rndis_config, (u8 *) req->buf); + if (status < 0) + ERROR(dev, "%s: rndis parse error %d\n", __FUNCTION__, status); spin_unlock(&dev->lock); } @@ -1387,6 +1430,7 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) /* descriptors just go into the pre-allocated ep0 buffer, * while config change events may enable network traffic. */ + req->complete = eth_setup_complete; switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: @@ -1414,7 +1458,8 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) case USB_DT_CONFIG: value = config_buf (gadget->speed, req->buf, ctrl->wValue >> 8, - ctrl->wValue & 0xff); + ctrl->wValue & 0xff, + gadget->is_otg); if (value >= 0) value = min (ctrl->wLength, (u16) value); break; @@ -1431,6 +1476,10 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) case USB_REQ_SET_CONFIGURATION: if (ctrl->bRequestType != 0) break; + if (gadget->a_hnp_support) + DEBUG (dev, "HNP available\n"); + else if (gadget->a_alt_hnp_support) + DEBUG (dev, "HNP needs a different root port\n"); spin_lock (&dev->lock); value = eth_set_config (dev, ctrl->wValue, GFP_ATOMIC); spin_unlock (&dev->lock); @@ -1580,6 +1629,7 @@ done_set_intf: if (buf) { memcpy (req->buf, buf, value); req->complete = rndis_response_complete; + rndis_free_response(dev->rndis_config, buf); } /* else stalls ... spec says to avoid that */ } @@ -1596,6 +1646,8 @@ done_set_intf: /* respond with data transfer before status phase? */ if (value >= 0) { req->length = value; + req->zero = value < ctrl->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); @@ -1633,7 +1685,7 @@ eth_disconnect (struct usb_gadget *gadget) static int eth_change_mtu (struct net_device *net, int new_mtu) { - struct eth_dev *dev = (struct eth_dev *) net->priv; + struct eth_dev *dev = netdev_priv(net); // FIXME if rndis, don't change while link's live @@ -1648,58 +1700,29 @@ static int eth_change_mtu (struct net_device *net, int new_mtu) static struct net_device_stats *eth_get_stats (struct net_device *net) { - return &((struct eth_dev *) net->priv)->stats; + return &((struct eth_dev *)netdev_priv(net))->stats; } -static int eth_ethtool_ioctl (struct net_device *net, void __user *useraddr) +static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p) { - struct eth_dev *dev = (struct eth_dev *) net->priv; - u32 cmd; - - if (get_user (cmd, (u32 __user *)useraddr)) - return -EFAULT; - switch (cmd) { - - case ETHTOOL_GDRVINFO: { /* get driver info */ - struct ethtool_drvinfo info; - - memset (&info, 0, sizeof info); - info.cmd = ETHTOOL_GDRVINFO; - strlcpy (info.driver, shortname, sizeof info.driver); - strlcpy (info.version, DRIVER_VERSION, sizeof info.version); - strlcpy (info.fw_version, dev->gadget->name, - sizeof info.fw_version); - strlcpy (info.bus_info, dev->gadget->dev.bus_id, - sizeof info.bus_info); - if (copy_to_user (useraddr, &info, sizeof (info))) - return -EFAULT; - return 0; - } - - case ETHTOOL_GLINK: { /* get link status */ - struct ethtool_value edata = { ETHTOOL_GLINK }; - - edata.data = (dev->gadget->speed != USB_SPEED_UNKNOWN); - if (copy_to_user (useraddr, &edata, sizeof (edata))) - return -EFAULT; - return 0; - } - - } - /* Note that the ethtool user space code requires EOPNOTSUPP */ - return -EOPNOTSUPP; + struct eth_dev *dev = netdev_priv(net); + strlcpy(p->driver, shortname, sizeof p->driver); + strlcpy(p->version, DRIVER_VERSION, sizeof p->version); + strlcpy(p->fw_version, dev->gadget->name, sizeof p->fw_version); + strlcpy (p->bus_info, dev->gadget->dev.bus_id, sizeof p->bus_info); } -static int eth_ioctl (struct net_device *net, struct ifreq *rq, int cmd) +static u32 eth_get_link(struct net_device *net) { - switch (cmd) { - case SIOCETHTOOL: - return eth_ethtool_ioctl(net, rq->ifr_data); - default: - return -EOPNOTSUPP; - } + struct eth_dev *dev = netdev_priv(net); + return dev->gadget->speed != USB_SPEED_UNKNOWN; } +static struct ethtool_ops ops = { + .get_drvinfo = eth_get_drvinfo, + .get_link = eth_get_link +}; + static void defer_kevent (struct eth_dev *dev, int flag) { if (test_and_set_bit (flag, &dev->todo)) @@ -1721,9 +1744,10 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags) /* Padding up to RX_EXTRA handles minor disagreements with host. * Normally we use the USB "terminate on short read" convention; - * so allow up to (N*maxpacket)-1, since that memory is normally - * already allocated. Major loss of synch means -EOVERFLOW; any - * obviously corrupted packets will automatically be discarded. + * so allow up to (N*maxpacket), since that memory is normally + * already allocated. Some hardware doesn't deal well with short + * reads (e.g. DMA must be N*maxpacket), so for now don't trim a + * byte off the end (to force hardware errors on overflow). * * RNDIS uses internal framing, and explicitly allows senders to * pad to end-of-packet. That's potentially nice for speed, @@ -1736,10 +1760,6 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags) size += sizeof (struct rndis_packet_msg_type); #endif size -= size % dev->out_ep->maxpacket; -#ifdef CONFIG_USB_ETH_RNDIS - if (!dev->rndis) -#endif - size--; if ((skb = alloc_skb (size, gfp_flags)) == 0) { DEBUG (dev, "no rx skb\n"); @@ -1797,7 +1817,7 @@ static void rx_complete (struct usb_ep *ep, struct usb_request *req) * use skb buffers. */ status = netif_rx (skb); - skb = 0; + skb = NULL; break; /* software-driven interface shutdown */ @@ -1831,7 +1851,7 @@ quiesce: clean: /* nobody reading rx_reqs, so no dev->lock */ list_add (&req->list, &dev->rx_reqs); - req = 0; + req = NULL; } if (req) rx_submit (dev, req, GFP_ATOMIC); @@ -1963,10 +1983,10 @@ static void tx_complete (struct usb_ep *ep, struct usb_request *req) static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) { - struct eth_dev *dev = (struct eth_dev *) net->priv; + struct eth_dev *dev = netdev_priv(net); int length = skb->len; int retval; - struct usb_request *req = 0; + struct usb_request *req = NULL; unsigned long flags; /* FIXME check dev->cdc_filter to decide whether to send this, @@ -2064,9 +2084,21 @@ static void rndis_send_media_state (struct eth_dev *dev, int connect) } } +static void +rndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req) +{ + if (req->status || req->actual != req->length) + DEBUG ((struct eth_dev *) ep->driver_data, + "rndis control ack complete --> %d, %d/%d\n", + req->status, req->actual, req->length); + + usb_ep_free_buffer(ep, req->buf, req->dma, 8); + usb_ep_free_request(ep, req); +} + static int rndis_control_ack (struct net_device *net) { - struct eth_dev *dev = (struct eth_dev *) net->priv; + struct eth_dev *dev = netdev_priv(net); u32 length; struct usb_request *resp; @@ -2095,7 +2127,7 @@ static int rndis_control_ack (struct net_device *net) * CDC_NOTIFY_RESPONSE_AVAILABLE should work too */ resp->length = 8; - resp->complete = rndis_response_complete; + resp->complete = rndis_control_ack_complete; *((u32 *) resp->buf) = __constant_cpu_to_le32 (1); *((u32 *) resp->buf + 1) = __constant_cpu_to_le32 (0); @@ -2103,7 +2135,7 @@ static int rndis_control_ack (struct net_device *net) length = usb_ep_queue (dev->status_ep, resp, GFP_ATOMIC); if (length < 0) { resp->status = 0; - rndis_response_complete (dev->status_ep, resp); + rndis_control_ack_complete (dev->status_ep, resp); } return 0; @@ -2133,7 +2165,7 @@ static void eth_start (struct eth_dev *dev, int gfp_flags) static int eth_open (struct net_device *net) { - struct eth_dev *dev = (struct eth_dev *) net->priv; + struct eth_dev *dev = netdev_priv(net); DEBUG (dev, "%s\n", __FUNCTION__); if (netif_carrier_ok (dev->net)) @@ -2143,7 +2175,7 @@ static int eth_open (struct net_device *net) static int eth_stop (struct net_device *net) { - struct eth_dev *dev = (struct eth_dev *) net->priv; + struct eth_dev *dev = netdev_priv(net); VDEBUG (dev, "%s\n", __FUNCTION__); netif_stop_queue (net); @@ -2154,7 +2186,7 @@ static int eth_stop (struct net_device *net) ); /* ensure there are no more active requests */ - if (dev->gadget->speed != USB_SPEED_UNKNOWN) { + if (dev->config) { usb_ep_disable (dev->in_ep); usb_ep_disable (dev->out_ep); if (netif_carrier_ok (dev->net)) { @@ -2199,7 +2231,7 @@ eth_unbind (struct usb_gadget *gadget) dev->req->buf, dev->req->dma, USB_BUFSIZ); usb_ep_free_request (gadget->ep0, dev->req); - dev->req = 0; + dev->req = NULL; } unregister_netdev (dev->net); @@ -2207,7 +2239,7 @@ eth_unbind (struct usb_gadget *gadget) /* assuming we used keventd, it must quiesce too */ flush_scheduled_work (); - set_gadget_data (gadget, 0); + set_gadget_data (gadget, NULL); } static u8 __init nibble (unsigned char c) @@ -2288,6 +2320,12 @@ eth_bind (struct usb_gadget *gadget) device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207); } else if (gadget_is_omap (gadget)) { device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208); + } else if (gadget_is_lh7a40x(gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0209); + } else if (gadget_is_n9604(gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0210); + } else if (gadget_is_pxa27x(gadget)) { + device_desc.bcdDevice = __constant_cpu_to_le16 (0x0211); } else { /* can't assume CDC works. don't want to default to * anything less functional on CDC-capable hardware, @@ -2298,21 +2336,10 @@ eth_bind (struct usb_gadget *gadget) gadget->name); return -ENODEV; } - snprintf (manufacturer, sizeof manufacturer, - UTS_SYSNAME " " UTS_RELEASE "/%s", + snprintf (manufacturer, sizeof manufacturer, "%s %s/%s", + system_utsname.sysname, system_utsname.release, gadget->name); - /* CDC subset ... recognized by Linux since 2.4.10, but Windows - * drivers aren't widely available. - */ - if (!cdc) { - device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC; - device_desc.idVendor = - __constant_cpu_to_le16(SIMPLE_VENDOR_NUM); - device_desc.idProduct = - __constant_cpu_to_le16(SIMPLE_PRODUCT_NUM); - } - /* If there's an RNDIS configuration, that's what Windows wants to * be using ... so use these product IDs here and in the "linux.inf" * needed to install MSFT drivers. Current Linux kernels will use @@ -2326,6 +2353,16 @@ eth_bind (struct usb_gadget *gadget) __constant_cpu_to_le16(RNDIS_PRODUCT_NUM); snprintf (product_desc, sizeof product_desc, "RNDIS/%s", driver_desc); + + /* CDC subset ... recognized by Linux since 2.4.10, but Windows + * drivers aren't widely available. + */ + } else if (!cdc) { + device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC; + device_desc.idVendor = + __constant_cpu_to_le16(SIMPLE_VENDOR_NUM); + device_desc.idProduct = + __constant_cpu_to_le16(SIMPLE_PRODUCT_NUM); } /* support optional vendor/distro customization */ @@ -2363,6 +2400,7 @@ autoconf_fail: EP_OUT_NAME = ep->name; ep->driver_data = ep; /* claim */ +#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) /* CDC Ethernet control interface doesn't require a status endpoint. * Since some hosts expect one, try to allocate one anyway. */ @@ -2376,13 +2414,12 @@ autoconf_fail: "can't run RNDIS on %s\n", gadget->name); return -ENODEV; -#ifdef DEV_CONFIG_CDC } else if (cdc) { control_intf.bNumEndpoints = 0; /* FIXME remove endpoint from descriptor list */ -#endif } } +#endif /* one config: cdc, else minimal subset */ if (!cdc) { @@ -2418,10 +2455,20 @@ autoconf_fail: device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; usb_gadget_set_selfpowered (gadget); + if (gadget->is_otg) { + otg_descriptor.bmAttributes |= USB_OTG_HNP, + eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + eth_config.bMaxPower = 4; +#ifdef CONFIG_USB_ETH_RNDIS + rndis_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + rndis_config.bMaxPower = 4; +#endif + } + net = alloc_etherdev (sizeof *dev); if (!net) return status; - dev = net->priv; + dev = netdev_priv(net); spin_lock_init (&dev->lock); INIT_WORK (&dev->work, eth_work, dev); INIT_LIST_HEAD (&dev->tx_reqs); @@ -2436,7 +2483,7 @@ autoconf_fail: /* Module params for these addresses should come from ID proms. * The host side address is used with CDC and RNDIS, and commonly - * end ups in a persistent config database. + * ends up in a persistent config database. */ get_ether_addr(dev_addr, net->dev_addr); if (cdc || rndis) { @@ -2465,7 +2512,7 @@ autoconf_fail: net->stop = eth_stop; // watchdog_timeo, tx_timeout ... // set_multicast_list - net->do_ioctl = eth_ioctl; + SET_ETHTOOL_OPS(net, &ops); /* preallocate control response and buffer */ dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL); @@ -2554,6 +2601,26 @@ fail: /*-------------------------------------------------------------------------*/ +static void +eth_suspend (struct usb_gadget *gadget) +{ + struct eth_dev *dev = get_gadget_data (gadget); + + DEBUG (dev, "suspend\n"); + dev->suspended = 1; +} + +static void +eth_resume (struct usb_gadget *gadget) +{ + struct eth_dev *dev = get_gadget_data (gadget); + + DEBUG (dev, "resume\n"); + dev->suspended = 0; +} + +/*-------------------------------------------------------------------------*/ + static struct usb_gadget_driver eth_driver = { #ifdef CONFIG_USB_GADGET_DUALSPEED .speed = USB_SPEED_HIGH, @@ -2567,6 +2634,9 @@ static struct usb_gadget_driver eth_driver = { .setup = eth_setup, .disconnect = eth_disconnect, + .suspend = eth_suspend, + .resume = eth_resume, + .driver = { .name = (char *) shortname, // .shutdown = ...