ether.c
来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 2,360 行 · 第 1/5 页
C
2,360 行
}}static int eth_open (struct net_device *net){ struct eth_dev *dev = netdev_priv(net); DEBUG (dev, "%s\n", __FUNCTION__); if (netif_carrier_ok (dev->net)) eth_start (dev, GFP_KERNEL); return 0;}static int eth_stop (struct net_device *net){ struct eth_dev *dev = netdev_priv(net); VDEBUG (dev, "%s\n", __FUNCTION__); netif_stop_queue (net); DEBUG (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n", dev->stats.rx_packets, dev->stats.tx_packets, dev->stats.rx_errors, dev->stats.tx_errors ); /* ensure there are no more active requests */ if (dev->config) { usb_ep_disable (dev->in_ep); usb_ep_disable (dev->out_ep); if (netif_carrier_ok (dev->net)) { DEBUG (dev, "host still using in/out endpoints\n"); // FIXME idiom may leave toggle wrong here usb_ep_enable (dev->in_ep, dev->in); usb_ep_enable (dev->out_ep, dev->out); } if (dev->status_ep) { usb_ep_disable (dev->status_ep); usb_ep_enable (dev->status_ep, dev->status); } } if (rndis_active(dev)) { rndis_set_param_medium (dev->rndis_config, NDIS_MEDIUM_802_3, 0); (void) rndis_signal_disconnect (dev->rndis_config); } return 0;}/*-------------------------------------------------------------------------*/static struct usb_request *eth_req_alloc (struct usb_ep *ep, unsigned size, gfp_t gfp_flags){ struct usb_request *req; req = usb_ep_alloc_request (ep, gfp_flags); if (!req) return NULL; req->buf = kmalloc (size, gfp_flags); if (!req->buf) { usb_ep_free_request (ep, req); req = NULL; } return req;}static voideth_req_free (struct usb_ep *ep, struct usb_request *req){ kfree (req->buf); usb_ep_free_request (ep, req);}static void /* __init_or_exit */eth_unbind (struct usb_gadget *gadget){ struct eth_dev *dev = get_gadget_data (gadget); DEBUG (dev, "unbind\n"); 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); dev->req = NULL; } if (dev->stat_req) { eth_req_free (dev->status_ep, dev->stat_req); dev->stat_req = NULL; } unregister_netdev (dev->net); free_netdev(dev->net); /* assuming we used keventd, it must quiesce too */ flush_scheduled_work (); set_gadget_data (gadget, NULL);}static u8 __devinit nibble (unsigned char c){ if (likely (isdigit (c))) return c - '0'; c = toupper (c); if (likely (isxdigit (c))) return 10 + c - 'A'; return 0;}static int __devinit get_ether_addr(const char *str, u8 *dev_addr){ if (str) { unsigned i; for (i = 0; i < 6; i++) { unsigned char num; if((*str == '.') || (*str == ':')) str++; num = nibble(*str++) << 4; num |= (nibble(*str++)); dev_addr [i] = num; } if (is_valid_ether_addr (dev_addr)) return 0; } random_ether_addr(dev_addr); return 1;}static int __deviniteth_bind (struct usb_gadget *gadget){ struct eth_dev *dev; struct net_device *net; u8 cdc = 1, zlp = 1, rndis = 1; struct usb_ep *in_ep, *out_ep, *status_ep = NULL; int status = -ENOMEM; int gcnum; /* these flags are only ever cleared; compiler take note */ /* Because most host side USB stacks handle CDC Ethernet, that * standard protocol is _strongly_ preferred for interop purposes. * (By everyone except Microsoft.) */ if (gadget_is_pxa (gadget)) { /* pxa doesn't support altsettings */ cdc = 0; } else if (gadget_is_musbhdrc(gadget)) { /* reduce tx dma overhead by avoiding special cases */ zlp = 0; } else if (gadget_is_sh(gadget)) { /* sh doesn't support multiple interfaces or configs */ cdc = 0; rndis = 0; } else if (gadget_is_sa1100 (gadget)) { /* hardware can't write zlps */ zlp = 0; /* sa1100 CAN do CDC, without status endpoint ... we use * non-CDC to be compatible with ARM Linux-2.4 "usb-eth". */ cdc = 0; } gcnum = usb_gadget_controller_number (gadget); if (gcnum >= 0) device_desc.bcdDevice = cpu_to_le16 (0x0200 + gcnum); else { /* can't assume CDC works. don't want to default to * anything less functional on CDC-capable hardware, * so we fail in this case. */ dev_err (&gadget->dev, "controller '%s' not recognized\n", gadget->name); return -ENODEV; } snprintf (manufacturer, sizeof manufacturer, "%s %s/%s", init_utsname()->sysname, init_utsname()->release, gadget->name); /* 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 * the second configuration if it's CDC Ethernet, and need some help * to choose the right configuration otherwise. */ if (rndis) { device_desc.idVendor = __constant_cpu_to_le16(RNDIS_VENDOR_NUM); device_desc.idProduct = __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. (That may be improved by * supporting one submode of the "SAFE" variant of MDLM.) */ } else if (!cdc) { 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 */ if (idVendor) { if (!idProduct) { dev_err (&gadget->dev, "idVendor needs idProduct!\n"); return -ENODEV; } device_desc.idVendor = cpu_to_le16(idVendor); device_desc.idProduct = cpu_to_le16(idProduct); if (bcdDevice) device_desc.bcdDevice = cpu_to_le16(bcdDevice); } if (iManufacturer) strlcpy (manufacturer, iManufacturer, sizeof manufacturer); if (iProduct) strlcpy (product_desc, iProduct, sizeof product_desc); if (iSerialNumber) { device_desc.iSerialNumber = STRING_SERIALNUMBER, strlcpy(serial_number, iSerialNumber, sizeof serial_number); } /* 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: dev_err (&gadget->dev, "can't autoconfigure on %s\n", gadget->name); return -ENODEV; } in_ep->driver_data = in_ep; /* claim */ out_ep = usb_ep_autoconfig (gadget, &fs_sink_desc); if (!out_ep) goto autoconf_fail; out_ep->driver_data = out_ep; /* claim */ /* CDC Ethernet control interface doesn't require a status endpoint. * Since some hosts expect one, try to allocate one anyway. */ if (cdc || rndis) { status_ep = usb_ep_autoconfig (gadget, &fs_status_desc); if (status_ep) { status_ep->driver_data = status_ep; /* claim */ } else if (rndis) { dev_err (&gadget->dev, "can't run RNDIS on %s\n", gadget->name); return -ENODEV; /* pxa25x only does CDC subset; often used with RNDIS */ } else if (cdc) { control_intf.bNumEndpoints = 0; /* FIXME remove endpoint from descriptor list */ } } /* one config: cdc, else minimal subset */ if (!cdc) { eth_config.bNumInterfaces = 1; eth_config.iConfiguration = STRING_SUBSET; /* use functions to set these up, in case we're built to work * with multiple controllers and must override CDC Ethernet. */ fs_subset_descriptors(); hs_subset_descriptors(); } device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; usb_gadget_set_selfpowered (gadget); /* For now RNDIS is always a second config */ if (rndis) device_desc.bNumConfigurations = 2; if (rndis) dev_qualifier.bNumConfigurations = 2; else if (!cdc) dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC; /* assumes ep0 uses the same value for both speeds ... */ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; /* and that all endpoints are dual-speed */ hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; if (status_ep) hs_status_desc.bEndpointAddress = fs_status_desc.bEndpointAddress; if (gadget->is_otg) { otg_descriptor.bmAttributes |= USB_OTG_HNP, eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; eth_config.bMaxPower = 4; rndis_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; rndis_config.bMaxPower = 4; } net = alloc_etherdev (sizeof *dev); if (!net) return status; dev = netdev_priv(net); spin_lock_init (&dev->lock); spin_lock_init (&dev->req_lock); INIT_WORK (&dev->work, eth_work); INIT_LIST_HEAD (&dev->tx_reqs); INIT_LIST_HEAD (&dev->rx_reqs); /* network device setup */ dev->net = net; SET_MODULE_OWNER (net); strcpy (net->name, "usb%d"); dev->cdc = cdc; dev->zlp = zlp; dev->in_ep = in_ep; dev->out_ep = out_ep; dev->status_ep = status_ep; /* Module params for these addresses should come from ID proms. * The host side address is used with CDC and RNDIS, and commonly * ends up in a persistent config database. It's not clear if * host side code for the SAFE thing cares -- its original BLAN * thing didn't, Sharp never assigned those addresses on Zaurii. */ if (get_ether_addr(dev_addr, net->dev_addr)) dev_warn(&gadget->dev, "using random %s ethernet address\n", "self"); if (get_ether_addr(host_addr, dev->host_mac)) dev_warn(&gadget->dev, "using random %s ethernet address\n", "host"); snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X", dev->host_mac [0], dev->host_mac [1], dev->host_mac [2], dev->host_mac [3], dev->host_mac [4], dev->host_mac [5]); if (rndis) { status = rndis_init(); if (status < 0) { dev_err (&gadget->dev, "can't init RNDIS, %d\n", status); goto fail; } } net->change_mtu = eth_change_mtu; net->get_stats = eth_get_stats; net->hard_start_xmit = eth_start_xmit; net->open = eth_open; net->stop = eth_stop; // watchdog_timeo, tx_timeout ... // set_multicast_list 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->complete = eth_setup_complete; /* ... and maybe likewise for status transfer */ if (dev->status_ep) { 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; } /* finish hookup to lower layer ... */ dev->gadget = gadget; set_gadget_data (gadget, dev); gadget->ep0->driver_data = dev; /* two kinds of host-initiated state changes: * - iff DATA transfer is active, carrier is "on" * - tx queueing enabled if open *and* carrier is "on" */ netif_stop_queue (dev->net); netif_carrier_off (dev->net); SET_NETDEV_DEV (dev->net, &gadget->dev); status = register_netdev (dev->net); if (status < 0) goto fail1; INFO (dev, "%s, version: " DRIVER_VERSION "\n", driver_desc); INFO (dev, "using %s, OUT %s IN %s%s%s\n", gadget->name, out_ep->name, in_ep->name, status_ep ? " STATUS " : "", status_ep ? status_ep->name : "" ); INFO (dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n", net->dev_addr [0], net->dev_addr [1], net->dev_addr [2], net->dev_addr [3], net->dev_addr [4], net->dev_addr [5]); if (cdc || rndis) INFO (dev, "HOST MAC %02x:%02x:%02x:%02x:%02x:%02x\n", dev->host_mac [0], dev->host_mac [1], dev->host_mac [2], dev->host_mac [3], dev->host_mac [4], dev->host_mac [5]); if (rndis) { u32 vendorID = 0; /* FIXME RNDIS vendor id == "vendor NIC code" == ? */ dev->rndis_config = rndis_register (rndis_control_ack); if (dev->rndis_config < 0) {fail0: unregister_netdev (dev->net); status = -ENODEV; goto fail; } /* these set up a lot of the OIDs that RNDIS needs */ rndis_set_host_mac (dev->rndis_config, dev->host_mac); if (rndis_set_param_dev (dev->rndis_config, dev->net, &dev->stats, &dev->cdc_filter)) goto fail0; if (rndis_set_param_vendor (dev->rndis_config, vendorID, manufacturer)) goto fail0; if (rndis_set_param_medium (dev->rndis_config, NDIS_MEDIUM_802_3, 0)) goto fail0; INFO (dev, "RNDIS ready\n"); } return status;fail1: dev_dbg(&gadget->dev, "register_netdev failed, %d\n", status);fail: eth_unbind (gadget); return status;}/*-------------------------------------------------------------------------*/static voideth_suspend (struct usb_gadget *gadget){ struct eth_dev *dev = get_gadget_data (gadget); DEBUG (dev, "suspend\n"); dev->suspended = 1;}static voideth_resume (struct usb_gadget *gadget){ struct eth_dev *dev = get_gadget_data (gadget); DEBUG (dev, "resume\n"); dev-
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?