📄 ecos_usbeth.c
字号:
usbeth->tx_buffer[i+4], usbeth->tx_buffer[i+5], usbeth->tx_buffer[i+6], usbeth->tx_buffer[i+7]); } printk("--------------------------------------------------------------\n"); }#endif res = usb_submit_urb(&(usbeth->tx_urb)); if (0 == res) { netif_stop_queue(net); net->trans_start = jiffies; usbeth->stats.tx_packets++; usbeth->stats.tx_bytes += skb->len; } else { printk("ecos_usbeth: failed to start USB packet transmission, %d\n", res); usbeth->stats.tx_errors++; } spin_unlock(&usbeth->usb_lock); dev_kfree_skb(skb); return 0;}// set_rx_mode()// Invoked by the network stack to enable/disable promiscuous mode or// for multicasting. The latter is not yet supported on the target// side. The former involves a USB control message. The main call// is not allowed to block.static voidecos_usbeth_set_rx_mode_callback(struct urb* urb){ kfree(urb->setup_packet); usb_free_urb(urb);}static voidecos_usbeth_set_rx_mode(struct net_device* net){ ecos_usbeth* usbeth = (ecos_usbeth*) net->priv; __u16 promiscuous = net->flags & IFF_PROMISC; int res; if (promiscuous != usbeth->target_promiscuous) { devrequest* req; urb_t* urb; urb = usb_alloc_urb(0); if ((urb_t*)0 == urb) { return; } req = kmalloc(sizeof(devrequest), GFP_KERNEL); if ((devrequest*)0 == req) { usb_free_urb(urb); return; } req->requesttype = USB_TYPE_CLASS | USB_RECIP_DEVICE; req->request = ECOS_USBETH_CONTROL_SET_PROMISCUOUS_MODE; req->value = cpu_to_le16p(&promiscuous); req->index = 0; req->length = 0; FILL_CONTROL_URB(urb, usbeth->usb_dev, usb_sndctrlpipe(usbeth->usb_dev, 0), (unsigned char*) req, (void*) 0, 0, &ecos_usbeth_set_rx_mode_callback, (void*) usbeth); res = usb_submit_urb(urb); if (0 != res) { kfree(req); usb_free_urb(urb); } else { usbeth->target_promiscuous = promiscuous; } }}// netdev_stats()// Supply the current network statistics. These are held in// the stats field of the ecos_usbeth structurestatic struct net_device_stats*ecos_usbeth_netdev_stats(struct net_device* net){ ecos_usbeth* usbeth = (ecos_usbeth*) net->priv; return &(usbeth->stats);}// ioctl()// Currently none of the network ioctl()'s are supportedstatic intecos_usbeth_ioctl(struct net_device* net, struct ifreq* request, int command){ return -EINVAL;}// probe().// This is invoked by the generic USB code when a new device has// been detected and its configuration details have been extracted// and stored in the usbdev structure. The interface_id specifies// a specific USB interface, to cope with multifunction peripherals.//// FIXME; right now this code only copes with simple enumeration data.// OK, to be really honest it just looks for the vendor and device ids// in the simple test cases and ignores everything else.//// On success it should return a non-NULL pointer, which happens to be// a newly allocated ecos_usbeth structure. This will get passed to// the disconnect function. Filling in the ecos_usbeth structure will,// amongst other things, register this as a network device driver.// The MAC address is obtained from the peripheral via a control// request.static void*ecos_usbeth_probe(struct usb_device* usbdev, unsigned int interface_id){ struct net_device* net; ecos_usbeth* usbeth; int res; unsigned char MAC[6]; unsigned char dummy[1]; int tx_endpoint = -1; int rx_endpoint = -1; const ecos_usbeth_impl* impl; int found_impl = 0; // See if this is the correct driver for this USB peripheral. impl = ecos_usbeth_implementations; while (impl->name != NULL) { if ((usbdev->descriptor.idVendor != impl->vendor) || (usbdev->descriptor.idProduct != impl->id)) { found_impl = 1; break; } impl++; } if (! found_impl) { return (void*) 0; } // For now only support USB-ethernet peripherals consisting of a single // configuration, with a single interface, with two bulk endpoints. if ((1 != usbdev->descriptor.bNumConfigurations) || (1 != usbdev->config[0].bNumInterfaces) || (2 != usbdev->config[0].interface[0].altsetting->bNumEndpoints)) { return (void*) 0; } if ((0 == (usbdev->config[0].interface[0].altsetting->endpoint[0].bEndpointAddress & USB_DIR_IN)) && (0 != (usbdev->config[0].interface[0].altsetting->endpoint[1].bEndpointAddress & USB_DIR_IN))) { tx_endpoint = usbdev->config[0].interface[0].altsetting->endpoint[0].bEndpointAddress; rx_endpoint = usbdev->config[0].interface[0].altsetting->endpoint[1].bEndpointAddress & ~USB_DIR_IN; } if ((0 != (usbdev->config[0].interface[0].altsetting->endpoint[0].bEndpointAddress & USB_DIR_IN)) && (0 == (usbdev->config[0].interface[0].altsetting->endpoint[1].bEndpointAddress & USB_DIR_IN))) { tx_endpoint = usbdev->config[0].interface[0].altsetting->endpoint[1].bEndpointAddress; rx_endpoint = usbdev->config[0].interface[0].altsetting->endpoint[0].bEndpointAddress & ~USB_DIR_IN; } if (-1 == tx_endpoint) { return (void*) 0; } res = usb_set_configuration(usbdev, usbdev->config[0].bConfigurationValue); if (0 != res) { printk("ecos_usbeth: failed to set configuration, %d\n", res); return (void*) 0; } res = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), ECOS_USBETH_CONTROL_GET_MAC_ADDRESS, USB_TYPE_CLASS | USB_RECIP_DEVICE | USB_DIR_IN, 0, 0, (void*) MAC, 6, 5 * HZ); if (6 != res) { printk("ecos_usbeth: failed to get MAC address, %d\n", res); return (void*) 0; } res = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), // pipe ECOS_USBETH_CONTROL_SET_PROMISCUOUS_MODE, // request USB_TYPE_CLASS | USB_RECIP_DEVICE, // requesttype 0, // value 0, // index (void*) dummy, // data 0, // size 5 * HZ); // timeout if (0 != res) { printk("ecos_usbeth: failed to disable promiscous mode, %d\n", res); } usbeth = (ecos_usbeth*) kmalloc(sizeof(ecos_usbeth), GFP_KERNEL); if ((ecos_usbeth*)0 == usbeth) { printk("ecos_usbeth: failed to allocate memory for usbeth data structure\n"); return (void*) 0; } memset(usbeth, 0, sizeof(ecos_usbeth)); net = init_etherdev(0, 0); if ((struct net_device*) 0 == net) { kfree(usbeth); printk("ecos_usbeth: failed to allocate memory for net data structure\n"); return (void*) 0; } usbeth->usb_lock = SPIN_LOCK_UNLOCKED; usbeth->usb_dev = usbdev; FILL_BULK_URB(&(usbeth->tx_urb), usbdev, usb_sndbulkpipe(usbdev, tx_endpoint), usbeth->tx_buffer, ECOS_USBETH_MAXTU, &ecos_usbeth_tx_callback, (void*) usbeth); FILL_BULK_URB(&(usbeth->rx_urb), usbdev, usb_rcvbulkpipe(usbdev, rx_endpoint), usbeth->rx_buffer, ECOS_USBETH_MAXTU, &ecos_usbeth_rx_callback, (void*) usbeth); usbeth->net_dev = net; usbeth->target_promiscuous = 0; net->priv = (void*) usbeth; net->open = &ecos_usbeth_open; net->stop = &ecos_usbeth_close; net->do_ioctl = &ecos_usbeth_ioctl; net->hard_start_xmit = &ecos_usbeth_start_tx; net->set_multicast_list = &ecos_usbeth_set_rx_mode; net->get_stats = &ecos_usbeth_netdev_stats; net->mtu = 1500; // ECOS_USBETH_MAXTU - 2; memcpy(net->dev_addr, MAC, 6); printk("eCos-based USB ethernet peripheral active at %s\n", net->name); MOD_INC_USE_COUNT; return (void*) usbeth;}// disconnect().// Invoked after probe() has recognized a device but that device// has gone away. static voidecos_usbeth_disconnect(struct usb_device* usbdev, void* data){ ecos_usbeth* usbeth = (ecos_usbeth*) data; if (!usbeth) { printk("ecos_usbeth: warning, disconnecting unconnected device\n"); return; } if (0 != netif_running(usbeth->net_dev)) { ecos_usbeth_close(usbeth->net_dev); } unregister_netdev(usbeth->net_dev); if (-EINPROGRESS == usbeth->rx_urb.status) { usb_unlink_urb(&(usbeth->rx_urb)); } if (-EINPROGRESS == usbeth->tx_urb.status) { usb_unlink_urb(&(usbeth->tx_urb)); } kfree(usbeth); MOD_DEC_USE_COUNT;}static struct usb_driver ecos_usbeth_driver = { name: "ecos_usbeth", probe: ecos_usbeth_probe, disconnect: ecos_usbeth_disconnect,};// init()// Called when the module is loaded. It just registers the device with// the generic USB code. Nothing else can really be done until// the USB code detects that a device has been attached.int __initecos_usbeth_init(void){ printk("eCos USB-ethernet device driver\n"); return usb_register(&ecos_usbeth_driver);}// exit()// Called when the module is unloaded. disconnect() will be// invoked if appropriate.void __exitecos_usbeth_exit(void){ usb_deregister(&ecos_usbeth_driver);}module_init(ecos_usbeth_init);module_exit(ecos_usbeth_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -