📄 cdc_ether.c
字号:
usb_set_intfdata(info->data, NULL); usb_driver_release_interface(driver, info->data); info->data = NULL; } /* and vice versa (just in case) */ else if (intf == info->data && info->control) { /* ensure immediate exit from usbnet_disconnect */ usb_set_intfdata(info->control, NULL); usb_driver_release_interface(driver, info->control); info->control = NULL; }}EXPORT_SYMBOL_GPL(usbnet_cdc_unbind);/*------------------------------------------------------------------------- * * Communications Device Class, Ethernet Control model * * Takes two interfaces. The DATA interface is inactive till an altsetting * is selected. Configuration data includes class descriptors. There's * an optional status endpoint on the control interface. * * This should interop with whatever the 2.4 "CDCEther.c" driver * (by Brad Hards) talked with, with more functionality. * *-------------------------------------------------------------------------*/static void dumpspeed(struct usbnet *dev, __le32 *speeds){ if (netif_msg_timer(dev)) devinfo(dev, "link speeds: %u kbps up, %u kbps down", __le32_to_cpu(speeds[0]) / 1000, __le32_to_cpu(speeds[1]) / 1000);}static void cdc_status(struct usbnet *dev, struct urb *urb){ struct usb_cdc_notification *event; if (urb->actual_length < sizeof *event) return; /* SPEED_CHANGE can get split into two 8-byte packets */ if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) { dumpspeed(dev, (__le32 *) urb->transfer_buffer); return; } event = urb->transfer_buffer; switch (event->bNotificationType) { case USB_CDC_NOTIFY_NETWORK_CONNECTION: if (netif_msg_timer(dev)) devdbg(dev, "CDC: carrier %s", event->wValue ? "on" : "off"); if (event->wValue) netif_carrier_on(dev->net); else netif_carrier_off(dev->net); break; case USB_CDC_NOTIFY_SPEED_CHANGE: /* tx/rx rates */ if (netif_msg_timer(dev)) devdbg(dev, "CDC: speed change (len %d)", urb->actual_length); if (urb->actual_length != (sizeof *event + 8)) set_bit(EVENT_STS_SPLIT, &dev->flags); else dumpspeed(dev, (__le32 *) &event[1]); break; /* USB_CDC_NOTIFY_RESPONSE_AVAILABLE can happen too (e.g. RNDIS), * but there are no standard formats for the response data. */ default: deverr(dev, "CDC: unexpected notification %02x!", event->bNotificationType); break; }}static u8 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 inline intget_ethernet_addr(struct usbnet *dev, struct usb_cdc_ether_desc *e){ int tmp, i; unsigned char buf [13]; tmp = usb_string(dev->udev, e->iMACAddress, buf, sizeof buf); if (tmp != 12) { dev_dbg(&dev->udev->dev, "bad MAC string %d fetch, %d\n", e->iMACAddress, tmp); if (tmp >= 0) tmp = -EINVAL; return tmp; } for (i = tmp = 0; i < 6; i++, tmp += 2) dev->net->dev_addr [i] = (nibble(buf [tmp]) << 4) + nibble(buf [tmp + 1]); return 0;}static int cdc_bind(struct usbnet *dev, struct usb_interface *intf){ int status; struct cdc_state *info = (void *) &dev->data; status = usbnet_generic_cdc_bind(dev, intf); if (status < 0) return status; status = get_ethernet_addr(dev, info->ether); if (status < 0) { usb_set_intfdata(info->data, NULL); usb_driver_release_interface(driver_of(intf), info->data); return status; } /* FIXME cdc-ether has some multicast code too, though it complains * in routine cases. info->ether describes the multicast support. * Implement that here, manipulating the cdc filter as needed. */ return 0;}static const struct driver_info cdc_info = { .description = "CDC Ethernet Device", .flags = FLAG_ETHER, // .check_connect = cdc_check_connect, .bind = cdc_bind, .unbind = usbnet_cdc_unbind, .status = cdc_status,};/*-------------------------------------------------------------------------*/static const struct usb_device_id products [] = {/* * BLACKLIST !! * * First blacklist any products that are egregiously nonconformant * with the CDC Ethernet specs. Minor braindamage we cope with; when * they're not even trying, needing a separate driver is only the first * of the differences to show up. */#define ZAURUS_MASTER_INTERFACE \ .bInterfaceClass = USB_CLASS_COMM, \ .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \ .bInterfaceProtocol = USB_CDC_PROTO_NONE/* SA-1100 based Sharp Zaurus ("collie"), or compatible; * wire-incompatible with true CDC Ethernet implementations. * (And, it seems, needlessly so...) */{ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x04DD, .idProduct = 0x8004, ZAURUS_MASTER_INTERFACE, .driver_info = 0,},/* PXA-25x based Sharp Zaurii. Note that it seems some of these * (later models especially) may have shipped only with firmware * advertising false "CDC MDLM" compatibility ... but we're not * clear which models did that, so for now let's assume the worst. */{ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x04DD, .idProduct = 0x8005, /* A-300 */ ZAURUS_MASTER_INTERFACE, .driver_info = 0,}, { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x04DD, .idProduct = 0x8006, /* B-500/SL-5600 */ ZAURUS_MASTER_INTERFACE, .driver_info = 0,}, { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x04DD, .idProduct = 0x8007, /* C-700 */ ZAURUS_MASTER_INTERFACE, .driver_info = 0,}, { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x04DD, .idProduct = 0x9031, /* C-750 C-760 */ ZAURUS_MASTER_INTERFACE, .driver_info = 0,}, { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x04DD, .idProduct = 0x9032, /* SL-6000 */ ZAURUS_MASTER_INTERFACE, .driver_info = 0,}, { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x04DD, /* reported with some C860 units */ .idProduct = 0x9050, /* C-860 */ ZAURUS_MASTER_INTERFACE, .driver_info = 0,},/* Olympus has some models with a Zaurus-compatible option. * R-1000 uses a FreeScale i.MXL cpu (ARMv4T) */{ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | USB_DEVICE_ID_MATCH_DEVICE, .idVendor = 0x07B4, .idProduct = 0x0F02, /* R-1000 */ ZAURUS_MASTER_INTERFACE, .driver_info = 0,},/* * WHITELIST!!! * * CDC Ether uses two interfaces, not necessarily consecutive. * We match the main interface, ignoring the optional device * class so we could handle devices that aren't exclusively * CDC ether. * * NOTE: this match must come AFTER entries blacklisting devices * because of bugs/quirks in a given product (like Zaurus, above). */{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), .driver_info = (unsigned long) &cdc_info,}, { }, // END};MODULE_DEVICE_TABLE(usb, products);static struct usb_driver cdc_driver = { .name = "cdc_ether", .id_table = products, .probe = usbnet_probe, .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume,};static int __init cdc_init(void){ BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) < sizeof(struct cdc_state))); return usb_register(&cdc_driver);}module_init(cdc_init);static void __exit cdc_exit(void){ usb_deregister(&cdc_driver);}module_exit(cdc_exit);MODULE_AUTHOR("David Brownell");MODULE_DESCRIPTION("USB CDC Ethernet devices");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -