📄 cdcether.c
字号:
// Standard routines for kernel Ethernet Device ////////////////////////////////////////////////////////////////////////////////////////////////////////////static struct net_device_stats *CDCEther_netdev_stats( struct net_device *net ){ // Easy enough! return &((ether_dev_t *)net->priv)->stats;}static int CDCEther_open(struct net_device *net){ ether_dev_t *ether_dev = (ether_dev_t *)net->priv; int res; // Turn on the USB and let the packets flow!!! if ( (res = enable_net_traffic( ether_dev )) ) { err("%s can't enable_net_traffic() - %d", __FUNCTION__, res ); return -EIO; } /* Prep a receive URB */ FILL_BULK_URB( ðer_dev->rx_urb, ether_dev->usb, usb_rcvbulkpipe(ether_dev->usb, ether_dev->data_ep_in), ether_dev->rx_buff, ether_dev->wMaxSegmentSize, read_bulk_callback, ether_dev ); /* Put it out there so the device can send us stuff */ if ( (res = usb_submit_urb(ðer_dev->rx_urb)) ) { /* Hmm... Okay... */ warn( "%s failed rx_urb %d", __FUNCTION__, res ); } if (ether_dev->properties & HAVE_NOTIFICATION_ELEMENT) { /* Arm and submit the interrupt URB */ FILL_INT_URB( ðer_dev->intr_urb, ether_dev->usb, usb_rcvintpipe(ether_dev->usb, ether_dev->comm_ep_in), ether_dev->intr_buff, 8, /* Transfer buffer length */ intr_callback, ether_dev, ether_dev->intr_interval); if ( (res = usb_submit_urb(ðer_dev->intr_urb)) ) { warn("%s failed intr_urb %d", __FUNCTION__, res ); } } // Tell the kernel we are ready to start receiving from it netif_start_queue( net ); // We are up and running. ether_dev->flags |= CDC_ETHER_RUNNING; // Let's get ready to move frames!!! return 0;}static int CDCEther_close( struct net_device *net ){ ether_dev_t *ether_dev = net->priv; // We are no longer running. ether_dev->flags &= ~CDC_ETHER_RUNNING; // Tell the kernel to stop sending us stuff netif_stop_queue( net ); // If we are not already unplugged, turn off USB // traffic if ( !(ether_dev->flags & CDC_ETHER_UNPLUG) ) { disable_net_traffic( ether_dev ); } // We don't need the URBs anymore. usb_unlink_urb( ðer_dev->rx_urb ); usb_unlink_urb( ðer_dev->tx_urb ); usb_unlink_urb( ðer_dev->intr_urb ); usb_unlink_urb( ðer_dev->ctrl_urb ); // That's it. I'm done. return 0;}static int netdev_ethtool_ioctl(struct net_device *netdev, void *useraddr){ ether_dev_t *ether_dev = netdev->priv; u32 cmd; char tmp[40]; if (get_user(cmd, (u32 *)useraddr)) return -EFAULT; switch (cmd) { /* get driver info */ case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; strncpy(info.driver, SHORT_DRIVER_DESC, ETHTOOL_BUSINFO_LEN); strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN); sprintf(tmp, "usb%d:%d", ether_dev->usb->bus->busnum, ether_dev->usb->devnum); strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN); sprintf(tmp, "CDC %x.%x", ((ether_dev->bcdCDC & 0xff00)>>8), (ether_dev->bcdCDC & 0x00ff) ); strncpy(info.fw_version, tmp, ETHTOOL_BUSINFO_LEN); if (copy_to_user(useraddr, &info, sizeof(info))) return -EFAULT; return 0; } /* get link status */ case ETHTOOL_GLINK: { struct ethtool_value edata = {ETHTOOL_GLINK}; edata.data = netif_carrier_ok(netdev); if (copy_to_user(useraddr, &edata, sizeof(edata))) return -EFAULT; return 0; } } dbg("Got unsupported ioctl: %x", cmd); return -EOPNOTSUPP; /* the ethtool user space tool relies on this */}static int CDCEther_ioctl( struct net_device *net, struct ifreq *rq, int cmd ){ switch(cmd) { case SIOCETHTOOL: return netdev_ethtool_ioctl(net, (void *) rq->ifr_data); default: return -ENOTTY; /* per ioctl man page */ }}/* Multicast routines */static void CDC_SetEthernetPacketFilter (ether_dev_t *ether_dev){#if 0 struct usb_ctrlrequest *dr = ðer_dev->ctrl_dr; int res; dr->bRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE; dr->bRequest = SET_ETHERNET_PACKET_FILTER; dr->wValue = cpu_to_le16(ether_dev->mode_flags); dr->wIndex = cpu_to_le16((u16)ether_dev->comm_interface); dr->wLength = 0; FILL_CONTROL_URB(ðer_dev->ctrl_urb, ether_dev->usb, usb_sndctrlpipe(ether_dev->usb, 0), dr, NULL, NULL, setpktfilter_done, ether_dev); if ( (res = usb_submit_urb(ðer_dev->ctrl_urb)) ) { warn("%s failed submit ctrl_urb %d", __FUNCTION__, res); }#endif}static void CDCEther_set_multicast( struct net_device *net ){ ether_dev_t *ether_dev = net->priv; int i; __u8 *buff; // Tell the kernel to stop sending us frames while we get this // all set up. netif_stop_queue(net); /* Note: do not reorder, GCC is clever about common statements. */ if (net->flags & IFF_PROMISC) { /* Unconditionally log net taps. */ dbg( "%s: Promiscuous mode enabled", net->name); ether_dev->mode_flags = MODE_FLAG_PROMISCUOUS | MODE_FLAG_ALL_MULTICAST | MODE_FLAG_DIRECTED | MODE_FLAG_BROADCAST | MODE_FLAG_MULTICAST; } else if (net->mc_count > ether_dev->wNumberMCFilters) { /* Too many to filter perfectly -- accept all multicasts. */ dbg("%s: too many MC filters for hardware, using allmulti", net->name); ether_dev->mode_flags = MODE_FLAG_ALL_MULTICAST | MODE_FLAG_DIRECTED | MODE_FLAG_BROADCAST | MODE_FLAG_MULTICAST; } else if (net->flags & IFF_ALLMULTI) { /* Filter in software */ dbg("%s: using allmulti", net->name); ether_dev->mode_flags = MODE_FLAG_ALL_MULTICAST | MODE_FLAG_DIRECTED | MODE_FLAG_BROADCAST | MODE_FLAG_MULTICAST; } else { /* do multicast filtering in hardware */ struct dev_mc_list *mclist; dbg("%s: set multicast filters", net->name); ether_dev->mode_flags = MODE_FLAG_ALL_MULTICAST | MODE_FLAG_DIRECTED | MODE_FLAG_BROADCAST | MODE_FLAG_MULTICAST; buff = kmalloc(6 * net->mc_count, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); for (i = 0, mclist = net->mc_list; mclist && i < net->mc_count; i++, mclist = mclist->next) { memcpy(&mclist->dmi_addr, &buff[i * 6], 6); }#if 0 usb_control_msg(ether_dev->usb, usb_sndctrlpipe(ether_dev->usb, 0), SET_ETHERNET_MULTICAST_FILTER, /* request */ USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE, /* request type */ cpu_to_le16(net->mc_count), /* value */ cpu_to_le16((u16)ether_dev->comm_interface), /* index */ buff, (6* net->mc_count), /* size */ HZ); /* timeout */#endif kfree(buff); } CDC_SetEthernetPacketFilter(ether_dev); /* Tell the kernel to start giving frames to us again. */ netif_wake_queue(net);}//////////////////////////////////////////////////////////////////////////////// Routines used to parse out the Functional Descriptors ////////////////////////////////////////////////////////////////////////////////////////////////////* Header Descriptor - CDC Spec 5.2.3.1, Table 26 */static int parse_header_functional_descriptor( int *bFunctionLength, int bDescriptorType, int bDescriptorSubtype, unsigned char *data, ether_dev_t *ether_dev, int *requirements ){ /* Check to make sure we haven't seen one of these already. */ if ( (~*requirements) & REQ_HDR_FUNC_DESCR ) { err( "Multiple Header Functional Descriptors found." ); return -1; } /* Check for appropriate length */ if (*bFunctionLength != HEADER_FUNC_DESC_LEN) { dbg( "Invalid length in Header Functional Descriptor, working around it." ); /* This is a hack to get around a particular device (NO NAMES) * It has this function length set to the length of the * whole class-specific descriptor */ *bFunctionLength = HEADER_FUNC_DESC_LEN; } /* Nothing extremely useful here */ /* We'll keep it for posterity */ ether_dev->bcdCDC = data[0] + (data[1] << 8); dbg( "Found Header descriptor, CDC version %x.", ether_dev->bcdCDC); /* We've seen one of these */ *requirements &= ~REQ_HDR_FUNC_DESCR; /* Success */ return 0;}/* Union Descriptor - CDC Spec 5.2.3.8, Table 33 */static int parse_union_functional_descriptor( int *bFunctionLength, int bDescriptorType, int bDescriptorSubtype, unsigned char *data, ether_dev_t *ether_dev, int *requirements ){ /* Check to make sure we haven't seen one of these already. */ if ( (~*requirements) & REQ_UNION_FUNC_DESCR ) { err( "Multiple Union Functional Descriptors found." ); return -1; } /* Check for appropriate length */ if (*bFunctionLength != UNION_FUNC_DESC_LEN) { // It is NOT the size we expected. err( "Invalid length in Union Functional Descriptor." ); return -1; } /* Sanity check of sorts */ if (ether_dev->comm_interface != data[0]) { /* This tells us that we are chasing the wrong comm * interface or we are crazy or something else weird. */ if (ether_dev->comm_interface == data[1]) { dbg( "Probably broken Union descriptor, fudging data interface." ); /* We'll need this in a few microseconds, * so if the comm interface was the first slave, * then probably the master interface is the data one * Just hope for the best */ ether_dev->data_interface = data[0]; } else { err( "Union Functional Descriptor is broken beyond repair." ); return -1; } } else{ /* Descriptor is OK */ ether_dev->data_interface = data[1]; } /* We've seen one of these */ *requirements &= ~REQ_UNION_FUNC_DESCR; /* Success */ return 0;}/* Ethernet Descriptor - CDC Spec 5.2.3.16, Table 41 */static int parse_ethernet_functional_descriptor( int *bFunctionLength, int bDescriptorType, int bDescriptorSubtype, unsigned char *data, ether_dev_t *ether_dev, int *requirements ){ //* Check to make sure we haven't seen one of these already. */ if ( (~*requirements) & REQ_ETH_FUNC_DESCR ) { err( "Multiple Ethernet Functional Descriptors found." ); return -1; } /* Check for appropriate length */ if (*bFunctionLength != ETHERNET_FUNC_DESC_LEN) { err( "Invalid length in Ethernet Networking Functional Descriptor." ); return -1; } /* Lots of goodies from this one. They are all important. */ ether_dev->iMACAddress = data[0]; ether_dev->bmEthernetStatistics = data[1] + (data[2] << 8) + (data[3] << 16) + (data[4] << 24); ether_dev->wMaxSegmentSize = data[5] + (data[6] << 8); ether_dev->wNumberMCFilters = (data[7] + (data[8] << 8)); if (ether_dev->wNumberMCFilters & (1 << 15)) { ether_dev->properties |= PERFECT_FILTERING; dbg("Perfect filtering support"); } else { dbg("Imperfect filtering support - need sw hashing"); } if (0 == (ether_dev->wNumberMCFilters & (0x7f))) { ether_dev->properties |= NO_SET_MULTICAST; dbg("Can't use SetEthernetMulticastFilters request"); } if (ether_dev->wNumberMCFilters > multicast_filter_limit) { ether_dev->wNumberMCFilters = multicast_filter_limit; } ether_dev->bNumberPowerFilters = data[9]; /* We've seen one of these */ *requirements &= ~REQ_ETH_FUNC_DESCR; /* Success */ return 0;}static int parse_protocol_unit_functional_descriptor( int *bFunctionLength, int bDescriptorType, int bDescriptorSubtype, unsigned char *data, ether_dev_t *ether_dev, int *requirements ){ /* There should only be one type if we are sane */ if (bDescriptorType != CS_INTERFACE) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -