X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fusb%2Fgadget%2Fether.c;h=4137d76c42afb29a95a29b66a49798e54322af64;hb=12d0b8f5f07b76d7447d60f7528d578233553909;hp=700d5fbfb2ffa4f77faf24fea40bae5b5e32b486;hpb=6297872cd5de4705b6318778261b1f3f64a34c11;p=u-boot diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 700d5fbfb2..4137d76c42 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -9,31 +9,34 @@ */ #include -#include +#include +#include #include #include #include #include #include +#include #include +#include #include #include "gadget_chips.h" #include "rndis.h" +#include +#include +#include +#include + #define USB_NET_NAME "usb_ether" #define atomic_read extern struct platform_data brd; -#define spin_lock(x) -#define spin_unlock(x) unsigned packet_received, packet_sent; -#define GFP_ATOMIC ((gfp_t) 0) -#define GFP_KERNEL ((gfp_t) 0) - /* * Ethernet gadget driver -- with CDC and non-CDC options * Builds on hardware support for a full duplex link. @@ -73,13 +76,11 @@ unsigned packet_received, packet_sent; #define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ #define ETH_DATA_LEN 1500 /* Max. octets in payload */ #define ETH_FRAME_LEN PKTSIZE_ALIGN /* Max. octets in frame sans FCS */ -#define ETH_FCS_LEN 4 /* Octets in the FCS */ #define DRIVER_DESC "Ethernet Gadget" /* Based on linux 2.6.27 version */ #define DRIVER_VERSION "May Day 2005" -static const char shortname[] = "ether"; static const char driver_desc[] = DRIVER_DESC; #define RX_EXTRA 20 /* guard against rx overflows */ @@ -104,6 +105,9 @@ struct eth_dev { struct usb_gadget *gadget; struct usb_request *req; /* for control responses */ struct usb_request *stat_req; /* for cdc & rndis status */ +#ifdef CONFIG_DM_USB + struct udevice *usb_udev; +#endif u8 config; struct usb_ep *in_ep, *out_ep, *status_ep; @@ -112,7 +116,11 @@ struct eth_dev { struct usb_request *tx_req, *rx_req; +#ifndef CONFIG_DM_ETH struct eth_device *net; +#else + struct udevice *net; +#endif struct net_device_stats stats; unsigned int tx_qlen; @@ -137,9 +145,18 @@ struct eth_dev { */ /*-------------------------------------------------------------------------*/ -static struct eth_dev l_ethdev; -static struct eth_device l_netdev; -static struct usb_gadget_driver eth_driver; +struct ether_priv { + struct eth_dev ethdev; +#ifndef CONFIG_DM_ETH + struct eth_device netdev; +#else + struct udevice *netdev; +#endif + struct usb_gadget_driver eth_driver; +}; + +struct ether_priv eth_priv; +struct ether_priv *l_priv = ð_priv; /*-------------------------------------------------------------------------*/ @@ -259,7 +276,7 @@ static inline int BITRATE(struct usb_gadget *g) #if defined(CONFIG_USBNET_MANUFACTURER) static char *iManufacturer = CONFIG_USBNET_MANUFACTURER; #else -static char *iManufacturer = "U-boot"; +static char *iManufacturer = "U-Boot"; #endif /* These probably need to be configurable. */ @@ -490,6 +507,7 @@ static const struct usb_cdc_mdlm_desc mdlm_desc = { * can't really use its struct. All we do here is say that we're using * the submode of "SAFE" which directly matches the CDC Subset. */ +#ifdef CONFIG_USB_ETH_SUBSET static const u8 mdlm_detail_desc[] = { 6, USB_DT_CS_INTERFACE, @@ -499,6 +517,7 @@ static const u8 mdlm_detail_desc[] = { 0, /* network control capabilities (none) */ 0, /* network data capabilities ("raw" encapsulation) */ }; +#endif #endif @@ -635,6 +654,7 @@ fs_source_desc = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(64), }; static struct usb_endpoint_descriptor @@ -644,6 +664,7 @@ fs_sink_desc = { .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(64), }; static const struct usb_descriptor_header *fs_eth_function[11] = { @@ -855,30 +876,6 @@ DEFINE_CACHE_ALIGN_BUFFER(u8, control_req, USB_BUFSIZ); DEFINE_CACHE_ALIGN_BUFFER(u8, status_req, STATUS_BYTECOUNT); #endif - -/** - * strlcpy - Copy a %NUL terminated string into a sized buffer - * @dest: Where to copy the string to - * @src: Where to copy the string from - * @size: size of destination buffer - * - * Compatible with *BSD: the result is always a valid - * NUL-terminated string that fits in the buffer (unless, - * of course, the buffer size is zero). It does not pad - * out the result like strncpy() does. - */ -size_t strlcpy(char *dest, const char *src, size_t size) -{ - size_t ret = strlen(src); - - if (size) { - size_t len = (ret >= size) ? size - 1 : ret; - memcpy(dest, src, len); - dest[len] = '\0'; - } - return ret; -} - /*============================================================================*/ /* @@ -1160,7 +1157,7 @@ static void eth_status_complete(struct usb_ep *ep, struct usb_request *req) event->bNotificationType, value); if (event->bNotificationType == USB_CDC_NOTIFY_SPEED_CHANGE) { - l_ethdev.network_started = 1; + dev->network_started = 1; printf("USB network up!\n"); } } @@ -1276,6 +1273,7 @@ eth_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) switch (wValue >> 8) { case USB_DT_DEVICE: + device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; value = min(wLength, (u16) sizeof device_desc); memcpy(req->buf, &device_desc, value); break; @@ -1347,7 +1345,7 @@ eth_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) * that network is working. So we signalize it * here. */ - l_ethdev.network_started = 1; + dev->network_started = 1; debug("USB network up!\n"); goto done_set_intf; } @@ -1534,6 +1532,8 @@ static int rx_submit(struct eth_dev *dev, struct usb_request *req, */ debug("%s\n", __func__); + if (!req) + return -EINVAL; size = (ETHER_HDR_SIZE + dev->mtu + RX_EXTRA); size += dev->out_ep->maxpacket - 1; @@ -1547,7 +1547,7 @@ static int rx_submit(struct eth_dev *dev, struct usb_request *req, * RNDIS headers involve variable numbers of LE32 values. */ - req->buf = (u8 *) NetRxPackets[0]; + req->buf = (u8 *)net_rx_packets[0]; req->length = size; req->complete = rx_complete; @@ -1670,13 +1670,13 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) if (!eth_is_promisc (dev)) { u8 *dest = skb->data; - if (is_multicast_ether_addr(dest)) { + if (is_multicast_ethaddr(dest)) { u16 type; /* ignores USB_CDC_PACKET_TYPE_MULTICAST and host * SET_ETHERNET_MULTICAST_FILTERS requests */ - if (is_broadcast_ether_addr(dest)) + if (is_broadcast_ethaddr(dest)) type = USB_CDC_PACKET_TYPE_BROADCAST; else type = USB_CDC_PACKET_TYPE_ALL_MULTICAST; @@ -1845,10 +1845,10 @@ static void rndis_control_ack_complete(struct usb_ep *ep, debug("rndis control ack complete --> %d, %d/%d\n", req->status, req->actual, req->length); - if (!l_ethdev.network_started) { + if (!dev->network_started) { if (rndis_get_state(dev->rndis_config) == RNDIS_DATA_INITIALIZED) { - l_ethdev.network_started = 1; + dev->network_started = 1; printf("USB RNDIS network up!\n"); } } @@ -1861,9 +1861,14 @@ static void rndis_control_ack_complete(struct usb_ep *ep, static char rndis_resp_buf[8] __attribute__((aligned(sizeof(__le32)))); +#ifndef CONFIG_DM_ETH static int rndis_control_ack(struct eth_device *net) +#else +static int rndis_control_ack(struct udevice *net) +#endif { - struct eth_dev *dev = &l_ethdev; + struct ether_priv *priv = (struct ether_priv *)net->priv; + struct eth_dev *dev = &priv->ethdev; int length; struct usb_request *resp = dev->stat_req; @@ -1932,7 +1937,7 @@ static int eth_stop(struct eth_dev *dev) /* Wait until host receives OID_GEN_MEDIA_CONNECT_STATUS */ ts = get_timer(0); while (get_timer(ts) < timeout) - usb_gadget_handle_interrupts(); + usb_gadget_handle_interrupts(0); #endif rndis_uninit(dev->rndis_config); @@ -1967,7 +1972,7 @@ static int is_eth_addr_valid(char *str) } /* Now check the contents. */ - return is_valid_ether_addr(ea); + return is_valid_ethaddr(ea); } return 0; } @@ -1996,7 +2001,7 @@ static int get_ether_addr(const char *str, u8 *dev_addr) num |= (nibble(*str++)); dev_addr[i] = num; } - if (is_valid_ether_addr(dev_addr)) + if (is_valid_ethaddr(dev_addr)) return 0; } return 1; @@ -2004,12 +2009,15 @@ static int get_ether_addr(const char *str, u8 *dev_addr) static int eth_bind(struct usb_gadget *gadget) { - struct eth_dev *dev = &l_ethdev; + struct eth_dev *dev = &l_priv->ethdev; u8 cdc = 1, zlp = 1, rndis = 1; struct usb_ep *in_ep, *out_ep, *status_ep = NULL; int status = -ENOMEM; int gcnum; u8 tmp[7]; +#ifdef CONFIG_DM_ETH + struct eth_pdata *pdata = dev_get_platdata(l_priv->netdev); +#endif /* these flags are only ever cleared; compiler take note */ #ifndef CONFIG_USB_ETH_CDC @@ -2158,7 +2166,6 @@ autoconf_fail: hs_subset_descriptors(); } - device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; usb_gadget_set_selfpowered(gadget); /* For now RNDIS is always a second config */ @@ -2198,7 +2205,11 @@ autoconf_fail: /* network device setup */ - dev->net = &l_netdev; +#ifndef CONFIG_DM_ETH + dev->net = &l_priv->netdev; +#else + dev->net = l_priv->netdev; +#endif dev->cdc = cdc; dev->zlp = zlp; @@ -2207,6 +2218,7 @@ autoconf_fail: dev->out_ep = out_ep; dev->status_ep = status_ep; + memset(tmp, 0, sizeof(tmp)); /* * Module params for these addresses should come from ID proms. * The host side address is used with CDC and RNDIS, and commonly @@ -2214,10 +2226,13 @@ autoconf_fail: * host side code for the SAFE thing cares -- its original BLAN * thing didn't, Sharp never assigned those addresses on Zaurii. */ +#ifndef CONFIG_DM_ETH get_ether_addr(dev_addr, dev->net->enetaddr); - - memset(tmp, 0, sizeof(tmp)); memcpy(tmp, dev->net->enetaddr, sizeof(dev->net->enetaddr)); +#else + get_ether_addr(dev_addr, pdata->enetaddr); + memcpy(tmp, pdata->enetaddr, sizeof(pdata->enetaddr)); +#endif get_ether_addr(host_addr, dev->host_mac); @@ -2278,10 +2293,11 @@ autoconf_fail: status_ep ? " STATUS " : "", status_ep ? status_ep->name : "" ); - printf("MAC %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->net->enetaddr[0], dev->net->enetaddr[1], - dev->net->enetaddr[2], dev->net->enetaddr[3], - dev->net->enetaddr[4], dev->net->enetaddr[5]); +#ifndef CONFIG_DM_ETH + printf("MAC %pM\n", dev->net->enetaddr); +#else + printf("MAC %pM\n", pdata->enetaddr); +#endif if (cdc || rndis) printf("HOST MAC %02x:%02x:%02x:%02x:%02x:%02x\n", @@ -2326,17 +2342,39 @@ fail: /*-------------------------------------------------------------------------*/ -static int usb_eth_init(struct eth_device *netdev, bd_t *bd) +#ifdef CONFIG_DM_USB +int dm_usb_init(struct eth_dev *e_dev) { - struct eth_dev *dev = &l_ethdev; + struct udevice *dev = NULL; + int ret; + + ret = uclass_first_device(UCLASS_USB_DEV_GENERIC, &dev); + if (!dev || ret) { + error("No USB device found\n"); + return -ENODEV; + } + + e_dev->usb_udev = dev; + + return ret; +} +#endif + +static int _usb_eth_init(struct ether_priv *priv) +{ + struct eth_dev *dev = &priv->ethdev; struct usb_gadget *gadget; unsigned long ts; unsigned long timeout = USB_CONNECT_TIMEOUT; - if (!netdev) { - error("received NULL ptr"); - goto fail; +#ifdef CONFIG_DM_USB + if (dm_usb_init(dev)) { + error("USB ether not found\n"); + return -ENODEV; } +#else + board_usb_init(0, USB_INIT_DEVICE); +#endif /* Configure default mac-addresses for the USB ethernet device */ #ifdef CONFIG_USBNET_DEV_ADDR @@ -2363,7 +2401,15 @@ static int usb_eth_init(struct eth_device *netdev, bd_t *bd) goto fail; } - if (usb_gadget_register_driver(ð_driver) < 0) + priv->eth_driver.speed = DEVSPEED; + priv->eth_driver.bind = eth_bind; + priv->eth_driver.unbind = eth_unbind; + priv->eth_driver.setup = eth_setup; + priv->eth_driver.reset = eth_disconnect; + priv->eth_driver.disconnect = eth_disconnect; + priv->eth_driver.suspend = eth_suspend; + priv->eth_driver.resume = eth_resume; + if (usb_gadget_register_driver(&priv->eth_driver) < 0) goto fail; dev->network_started = 0; @@ -2378,13 +2424,13 @@ static int usb_eth_init(struct eth_device *netdev, bd_t *bd) timeout = simple_strtoul(getenv("cdc_connect_timeout"), NULL, 10) * CONFIG_SYS_HZ; ts = get_timer(0); - while (!l_ethdev.network_started) { + while (!dev->network_started) { /* Handle control-c and timeouts */ if (ctrlc() || (get_timer(ts) > timeout)) { error("The remote end did not respond in time."); goto fail; } - usb_gadget_handle_interrupts(); + usb_gadget_handle_interrupts(0); } packet_received = 0; @@ -2394,11 +2440,11 @@ fail: return -1; } -static int usb_eth_send(struct eth_device *netdev, void *packet, int length) +static int _usb_eth_send(struct ether_priv *priv, void *packet, int length) { int retval; void *rndis_pkt = NULL; - struct eth_dev *dev = &l_ethdev; + struct eth_dev *dev = &priv->ethdev; struct usb_request *req = dev->tx_req; unsigned long ts; unsigned long timeout = USB_CONNECT_TIMEOUT; @@ -2452,7 +2498,7 @@ static int usb_eth_send(struct eth_device *netdev, void *packet, int length) printf("timeout sending packets to usb ethernet\n"); return -1; } - usb_gadget_handle_interrupts(); + usb_gadget_handle_interrupts(0); } if (rndis_pkt) free(rndis_pkt); @@ -2463,33 +2509,16 @@ drop: return -ENOMEM; } -static int usb_eth_recv(struct eth_device *netdev) +static int _usb_eth_recv(struct ether_priv *priv) { - struct eth_dev *dev = &l_ethdev; - - usb_gadget_handle_interrupts(); + usb_gadget_handle_interrupts(0); - if (packet_received) { - debug("%s: packet received\n", __func__); - if (dev->rx_req) { - NetReceive(NetRxPackets[0], dev->rx_req->length); - packet_received = 0; - - rx_submit(dev, dev->rx_req, 0); - } else - error("dev->rx_req invalid"); - } return 0; } -void usb_eth_halt(struct eth_device *netdev) +void _usb_eth_halt(struct ether_priv *priv) { - struct eth_dev *dev = &l_ethdev; - - if (!netdev) { - error("received NULL ptr"); - return; - } + struct eth_dev *dev = &priv->ethdev; /* If the gadget not registered, simple return */ if (!dev->gadget) @@ -2512,29 +2541,68 @@ void usb_eth_halt(struct eth_device *netdev) /* Clear pending interrupt */ if (dev->network_started) { - usb_gadget_handle_interrupts(); + usb_gadget_handle_interrupts(0); dev->network_started = 0; } - usb_gadget_unregister_driver(ð_driver); + usb_gadget_unregister_driver(&priv->eth_driver); +#ifndef CONFIG_DM_USB + board_usb_cleanup(0, USB_INIT_DEVICE); +#endif } -static struct usb_gadget_driver eth_driver = { - .speed = DEVSPEED, +#ifndef CONFIG_DM_ETH +static int usb_eth_init(struct eth_device *netdev, bd_t *bd) +{ + struct ether_priv *priv = (struct ether_priv *)netdev->priv; - .bind = eth_bind, - .unbind = eth_unbind, + return _usb_eth_init(priv); +} - .setup = eth_setup, - .disconnect = eth_disconnect, +static int usb_eth_send(struct eth_device *netdev, void *packet, int length) +{ + struct ether_priv *priv = (struct ether_priv *)netdev->priv; - .suspend = eth_suspend, - .resume = eth_resume, -}; + return _usb_eth_send(priv, packet, length); +} + +static int usb_eth_recv(struct eth_device *netdev) +{ + struct ether_priv *priv = (struct ether_priv *)netdev->priv; + struct eth_dev *dev = &priv->ethdev; + int ret; + + ret = _usb_eth_recv(priv); + if (ret) { + error("error packet receive\n"); + return ret; + } + + if (!packet_received) + return 0; + + if (dev->rx_req) { + net_process_received_packet(net_rx_packets[0], + dev->rx_req->length); + } else { + error("dev->rx_req invalid"); + } + packet_received = 0; + rx_submit(dev, dev->rx_req, 0); + + return 0; +} + +void usb_eth_halt(struct eth_device *netdev) +{ + struct ether_priv *priv = (struct ether_priv *)netdev->priv; + + _usb_eth_halt(priv); +} int usb_eth_initialize(bd_t *bi) { - struct eth_device *netdev = &l_netdev; + struct eth_device *netdev = &l_priv->netdev; strlcpy(netdev->name, USB_NET_NAME, sizeof(netdev->name)); @@ -2542,6 +2610,7 @@ int usb_eth_initialize(bd_t *bi) netdev->send = usb_eth_send; netdev->recv = usb_eth_recv; netdev->halt = usb_eth_halt; + netdev->priv = l_priv; #ifdef CONFIG_MCAST_TFTP #error not supported @@ -2549,3 +2618,114 @@ int usb_eth_initialize(bd_t *bi) eth_register(netdev); return 0; } +#else +static int usb_eth_start(struct udevice *dev) +{ + struct ether_priv *priv = dev_get_priv(dev); + + return _usb_eth_init(priv); +} + +static int usb_eth_send(struct udevice *dev, void *packet, int length) +{ + struct ether_priv *priv = dev_get_priv(dev); + + return _usb_eth_send(priv, packet, length); +} + +static int usb_eth_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct ether_priv *priv = dev_get_priv(dev); + struct eth_dev *ethdev = &priv->ethdev; + int ret; + + ret = _usb_eth_recv(priv); + if (ret) { + error("error packet receive\n"); + return ret; + } + + if (packet_received) { + if (ethdev->rx_req) { + *packetp = (uchar *)net_rx_packets[0]; + return ethdev->rx_req->length; + } else { + error("dev->rx_req invalid"); + return -EFAULT; + } + } + + return -EAGAIN; +} + +static int usb_eth_free_pkt(struct udevice *dev, uchar *packet, + int length) +{ + struct ether_priv *priv = dev_get_priv(dev); + struct eth_dev *ethdev = &priv->ethdev; + + packet_received = 0; + + return rx_submit(ethdev, ethdev->rx_req, 0); +} + +static void usb_eth_stop(struct udevice *dev) +{ + struct ether_priv *priv = dev_get_priv(dev); + + _usb_eth_halt(priv); +} + +static int usb_eth_probe(struct udevice *dev) +{ + struct ether_priv *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + + priv->netdev = dev; + l_priv = priv; + + get_ether_addr(CONFIG_USBNET_DEVADDR, pdata->enetaddr); + eth_setenv_enetaddr("usbnet_devaddr", pdata->enetaddr); + + return 0; +} + +static const struct eth_ops usb_eth_ops = { + .start = usb_eth_start, + .send = usb_eth_send, + .recv = usb_eth_recv, + .free_pkt = usb_eth_free_pkt, + .stop = usb_eth_stop, +}; + +int usb_ether_init(void) +{ + struct udevice *dev; + struct udevice *usb_dev; + int ret; + + ret = uclass_first_device(UCLASS_USB_DEV_GENERIC, &usb_dev); + if (!usb_dev || ret) { + error("No USB device found\n"); + return ret; + } + + ret = device_bind_driver(usb_dev, "usb_ether", "usb_ether", &dev); + if (!dev || ret) { + error("usb - not able to bind usb_ether device\n"); + return ret; + } + + return 0; +} + +U_BOOT_DRIVER(eth_usb) = { + .name = "usb_ether", + .id = UCLASS_ETH, + .probe = usb_eth_probe, + .ops = &usb_eth_ops, + .priv_auto_alloc_size = sizeof(struct ether_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; +#endif /* CONFIG_DM_ETH */