📄 cdcether.c
字号:
/* Too many to filter perfectly -- accept all multicasts. */ info("%s: set too many MC filters, 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 */ info("%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; info("%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); }#if 0 CDC_SetEthernetPacketFilter(ether_dev);#endif // Tell the kernel to start giving frames to us again. netif_wake_queue(net);}//////////////////////////////////////////////////////////////////////////////// Routines used to parse out the Functional Descriptors ///////////////////////////////////////////////////////////////////////////////////////////////////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; } // Is it the right size??? if (*bFunctionLength != 5) { info( "Invalid length in Header Functional Descriptor" ); // 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 = 5; } // 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; // It's all good. return 0;}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; } // Is it the right size? if (*bFunctionLength != 5) { // It is NOT the size we expected. err( "Unsupported 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]) { info( "Probably broken Union descriptor, fudging data interface" ); // We'll need this in a few microseconds, // so guess here, and 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 // We'll need this in a few microseconds! ether_dev->data_interface = data[1]; } // We've seen one of these now. *requirements &= ~REQ_UNION_FUNC_DESCR; // Done return 0;}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; } // Is it the right size? if (*bFunctionLength != 13) { 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)) & 0x00007FFF; if (ether_dev->wNumberMCFilters > multicast_filter_limit) { ether_dev->wNumberMCFilters = multicast_filter_limit; } ether_dev->bNumberPowerFilters = data[9]; // We've seen one of these now. *requirements &= ~REQ_ETH_FUNC_DESCR; // That's all she wrote. 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) { info( "Invalid bDescriptorType found." ); return -1; } // The Subtype tells the tale. switch (bDescriptorSubtype){ case 0x00: // Header Functional Descriptor return parse_header_functional_descriptor( bFunctionLength, bDescriptorType, bDescriptorSubtype, data, ether_dev, requirements ); break; case 0x06: // Union Functional Descriptor return parse_union_functional_descriptor( bFunctionLength, bDescriptorType, bDescriptorSubtype, data, ether_dev, requirements ); break; case 0x0F: // Ethernet Networking Functional Descriptor return parse_ethernet_functional_descriptor( bFunctionLength, bDescriptorType, bDescriptorSubtype, data, ether_dev, requirements ); break; default: // We don't support this at this time... // However that doesn't necessarily indicate an error. dbg( "Unexpected header type %x:", bDescriptorSubtype ); return 0; } // How did we get here??? return -1;}static int parse_ethernet_class_information( unsigned char *data, int length, ether_dev_t *ether_dev ){ int loc = 0; int rc; int bFunctionLength; int bDescriptorType; int bDescriptorSubtype; int requirements = REQUIREMENTS_TOTAL; // As long as there is something here, we will try to parse it while (loc < length) { // Length bFunctionLength = data[loc]; loc++; // Type bDescriptorType = data[loc]; loc++; // Subtype bDescriptorSubtype = data[loc]; loc++; // ship this off to be processed elsewhere. rc = parse_protocol_unit_functional_descriptor( &bFunctionLength, bDescriptorType, bDescriptorSubtype, &data[loc], ether_dev, &requirements ); // Did it process okay? if (rc) { // Something was hosed somewhere. // No need to continue; err("Bad descriptor parsing: %x", rc ); return -1; } // We have already taken three bytes. loc += (bFunctionLength - 3); } // Check to see if we got everything we need. if (requirements) { // We missed some of the requirements... err( "Not all required functional descriptors present 0x%08X", requirements ); return -1; } // We got everything. return 0;}//////////////////////////////////////////////////////////////////////////////// Routine to check for the existence of the Functional Descriptors ////////////////////////////////////////////////////////////////////////////////////////static int find_and_parse_ethernet_class_information( struct usb_device *device, ether_dev_t *ether_dev ){ struct usb_config_descriptor *conf = NULL; struct usb_interface *comm_intf_group = NULL; struct usb_interface_descriptor *comm_intf = NULL; int rc = -1; // The assumption here is that find_ethernet_comm_interface // and find_valid_configuration // have already filled in the information about where to find // the a valid commication interface. conf = &( device->config[ether_dev->configuration_num] ); comm_intf_group = &( conf->interface[ether_dev->comm_interface] ); comm_intf = &( comm_intf_group->altsetting[ether_dev->comm_interface_altset_num] ); // Let's check and see if it has the extra information we need... if (comm_intf->extralen > 0) { // This is where the information is SUPPOSED to be. rc = parse_ethernet_class_information( comm_intf->extra, comm_intf->extralen, ether_dev ); } else if (conf->extralen > 0) { // This is a hack. The spec says it should be at the interface // location checked above. However I have seen it here also. // This is the same device that requires the functional descriptor hack above warn( "Ethernet information found at device configuration. This is broken." ); rc = parse_ethernet_class_information( conf->extra, conf->extralen, ether_dev ); } else { // I don't know where else to look. warn( "No ethernet information found." ); rc = -1; } return rc;}//////////////////////////////////////////////////////////////////////////////// Routines to verify the data interface ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////static int get_data_interface_endpoints( struct usb_device *device, ether_dev_t *ether_dev ){ struct usb_config_descriptor *conf = NULL; struct usb_interface *data_intf_group = NULL; struct usb_interface_descriptor *data_intf = NULL; // Walk through and get to the data interface we are checking. conf = &( device->config[ether_dev->configuration_num] ); data_intf_group = &( conf->interface[ether_dev->data_interface] ); data_intf = &( data_intf_group->altsetting[ether_dev->data_interface_altset_num_with_traffic] ); // Start out assuming we won't find anything we can use ether_dev->data_ep_in = 0; ether_dev->data_ep_out = 0; // If these are not BULK endpoints, we don't want them if ( data_intf->endpoint[0].bmAttributes != 0x02 ) { return -1; } if ( data_intf->endpoint[1].bmAttributes != 0x02 ) { return -1; } // Check the first endpoint to see if it is IN or OUT if ( data_intf->endpoint[0].bEndpointAddress & 0x80 ) { // This endpoint is IN ether_dev->data_ep_in = data_intf->endpoint[0].bEndpointAddress & 0x7F; } else { // This endpoint is OUT ether_dev->data_ep_out = data_intf->endpoint[0].bEndpointAddress & 0x7F; ether_dev->data_ep_out_size = data_intf->endpoint[0].wMaxPacketSize; } // Check the second endpoint to see if it is IN or OUT if ( data_intf->endpoint[1].bEndpointAddress & 0x80 ) { // This endpoint is IN ether_dev->data_ep_in = data_intf->endpoint[1].bEndpointAddress & 0x7F; } else { // This endpoint is OUT ether_dev->data_ep_out = data_intf->endpoint[1].bEndpointAddress & 0x7F; ether_dev->data_ep_out_size = data_intf->endpoint[1].wMaxPacketSize; } // Now make sure we got both an IN and an OUT if (ether_dev->data_ep_in && ether_dev->data_ep_out) { // We did get both, we are in good shape... info( "detected BULK OUT packets of size %d", ether_dev->data_ep_out_size ); return 0; } return -1;}static int verify_ethernet_data_interface( struct usb_device *device, ether_dev_t *ether_dev ){ struct usb_config_descriptor *conf = NULL; struct usb_interface *data_intf_group = NULL; struct usb_interface_descriptor *data_intf = NULL; int rc = -1; int status; int altset_num; // The assumption here is that parse_ethernet_class_information() // and find_valid_configuration() // have already filled in the information about where to find // a data interface conf = &( device->config[ether_dev->configuration_num] ); data_intf_group = &( conf->interface[ether_dev->data_interface] ); // start out assuming we won't find what we are looking for. ether_dev->data_interface_altset_num_with_traffic = -1; ether_dev->data_bAlternateSetting_with_traffic = -1; ether_dev->data_interface_altset_num_without_traffic = -1; ether_dev->data_bAlternateSetting_without_traffic = -1; // Walk through every possible setting for this interface until // we find what makes us happy. for ( altset_num = 0; altset_num < data_intf_group->num_altsetting; altset_num++ ) { data_intf = &( data_intf_group->altsetting[altset_num] ); // Is this a data interface we like? if ( ( data_intf->bInterfaceClass == 0x0A ) && ( data_intf->bInterfaceSubClass == 0x00 ) && ( data_intf->bInterfaceProtocol == 0x00 ) ) { if ( data_intf->bNumEndpoints == 2 ) { // We are required to have one of these. // An interface with 2 endpoints to send Ethernet traffic back and forth // It actually may be possible that the device might only // communicate in a vendor specific manner. // That would not be very nice. // We can add that one later. ether_dev->data_bInterfaceNumber = data_intf->bInterfaceNumber; ether_dev->data_interface_altset_num_with_traffic = altset_num; ether_dev->data_bAlternateSetting_with_traffic = data_intf->bAlternateSetting; status = get_data_interface_endpoints( device, ether_dev ); if (!status) { rc = 0; } } if ( data_intf->bNumEndpoints == 0 ) { // According to the spec we are SUPPOSED to have one of these // In fact the device is supposed to come up in this state. // However, I have seen a device that did not have such an interface. // So it must be just optional for our driver... ether_dev->data_bInterfaceNumber = data_intf->bInterfaceNumber; ether_dev->data_interface_altset_num_without_traffic = altset_num; ether_dev->data_bAlternateSetting_without_traffic = data_intf->bAlternateSetting; } } } return rc;}//////////////////////////////////////////////////////////////////////////////// Routine to find a communication interface ///////////////////////////////////////////////////////////////////////////////////////////////////////////////static int find_ethernet_comm_interface( struct usb_device *device, ether_dev_t *ether_dev ){ struct usb_config_descriptor *conf = NULL; struct usb_interface *comm_intf_group = NULL; struct usb_interface_descriptor *comm_intf = NULL; int intf_num; int altset_num; int rc; conf = &( device->config[ether_dev->configuration_num] ); // We need to check and see if any of these interfaces are something we want. // Walk through each interface one at a time for ( intf_num = 0; intf_num < conf->bNumInterfaces; intf_num++ ) { comm_intf_group = &( conf->interface[intf_num] ); // Now for each of those interfaces, check every possible // alternate setting. for ( altset_num = 0; altset_num < comm_intf_group->num_altsetting; altset_num++ ) { comm_intf = &( comm_intf_group->altsetting[altset_num] ); // Is this a communication class of interface of the // ethernet subclass variety. if ( ( comm_intf->bInterfaceClass == 0x02 ) && ( comm_intf->bInterfaceSubClass == 0x06 ) && ( comm_intf->bInterfaceProtocol == 0x00 ) ) { if ( comm_intf->bNumEndpoints == 1 ) { // Good, we found one, we will try this one
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -