📄 cdcether.c
字号:
err( "Invalid bDescriptorType found." ); return -1; } /* The Subtype tells the tale - CDC spec Table 25 */ 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; /* We init to our needs, and then clear * bits as we find the descriptors */ /* As long as there is something here, we will try to parse it */ /* All of the functional descriptors start with the same 3 byte pattern */ while (loc < length) { /* Length */ bFunctionLength = data[loc]; loc++; /* Type */ bDescriptorType = data[loc]; loc++; /* Subtype */ bDescriptorSubtype = data[loc]; loc++; /* ship this off to be processed */ 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 move the loc pointer along, remembering * that 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 */ dbg( "Ethernet information found at device configuration. Trying to use it anyway." ); rc = parse_ethernet_class_information( conf->extra, conf->extralen, ether_dev ); } else { /* I don't know where else to look */ err( "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 != USB_ENDPOINT_XFER_BULK ) { return -1; } if ( data_intf->endpoint[1].bmAttributes != USB_ENDPOINT_XFER_BULK ) { return -1; } /* Check the first endpoint to see if it is IN or OUT */ if ( data_intf->endpoint[0].bEndpointAddress & USB_DIR_IN ) { ether_dev->data_ep_in = data_intf->endpoint[0].bEndpointAddress & 0x7F; } else { ether_dev->data_ep_out = data_intf->endpoint[0].bEndpointAddress; 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 & USB_DIR_IN ) { ether_dev->data_ep_in = data_intf->endpoint[1].bEndpointAddress & 0x7F; } else { ether_dev->data_ep_out = data_intf->endpoint[1].bEndpointAddress; 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) { dbg( "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] ); /* Good, we found one, we will try this one */ /* Fill in the structure */ ether_dev->comm_interface = intf_num; ether_dev->comm_bInterfaceNumber = comm_intf->bInterfaceNumber; ether_dev->comm_interface_altset_num = altset_num; ether_dev->comm_bAlternateSetting = comm_intf->bAlternateSetting; // Look for the Ethernet Functional Descriptors rc = find_and_parse_ethernet_class_information( device, ether_dev ); if (rc) { // Nope this was no good after all. continue; } /* Check that we really can talk to the data interface * This includes # of endpoints, protocols, etc. */ rc = verify_ethernet_data_interface( device, ether_dev ); if (rc) { /* We got something we didn't like */ continue; } /* It is a bit ambiguous whether the Ethernet model really requires * the notification element (usually an interrupt endpoint) or not * And some products (eg Sharp Zaurus) don't support it, so we * only use the notification element if present */ /* We check for a sane endpoint before using it */ if ( (comm_intf->bNumEndpoints == 1) && (comm_intf->endpoint[0].bEndpointAddress & USB_DIR_IN) && (comm_intf->endpoint[0].bmAttributes == USB_ENDPOINT_XFER_INT)) { ether_dev->properties |= HAVE_NOTIFICATION_ELEMENT; ether_dev->comm_ep_in = (comm_intf->endpoint[0].bEndpointAddress & 0x7F); dbg("interrupt address: %x",ether_dev->comm_ep_in); ether_dev->intr_interval = (comm_intf->endpoint[0].bInterval); dbg("interrupt interval: %d",ether_dev->intr_interval); } // This communication interface seems to give us everything // we require. We have all the ethernet info we need. return 0; } // end for altset_num } // end for intf_num return -1;}//////////////////////////////////////////////////////////////////////////////// Routine to go through all configurations and find one that ////////////////// is an Ethernet Networking Device ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////static int find_valid_configuration( struct usb_device *device, ether_dev_t *ether_dev ){ struct usb_config_descriptor *conf = NULL; int conf_num; int rc; // We will try each and every possible configuration for ( conf_num = 0; conf_num < device->descriptor.bNumConfigurations; conf_num++ ) { conf = &( device->config[conf_num] ); // Our first requirement : 2 interfaces if ( conf->bNumInterfaces != 2 ) { // I currently don't know how to handle devices with any number of interfaces // other than 2. continue; } // This one passed our first check, fill in some // useful data ether_dev->configuration_num = conf_num; ether_dev->bConfigurationValue = conf->bConfigurationValue; // Now run it through the ringers and see what comes // out the other side. rc = find_ethernet_comm_interface( device, ether_dev ); // Check if we found an ethernet Communcation Device if ( !rc ) { // We found one. return 0; } } // None of the configurations suited us. return -1;}//////////////////////////////////////////////////////////////////////////////// Routine that checks a given configuration to see if any driver ////////////// has claimed any of the devices interfaces ///////////////////////////////////////////////////////////////////////////////////////////////////////////////static int check_for_claimed_interfaces( struct usb_config_descriptor *config ){ struct usb_interface *comm_intf_group; int intf_num; // Go through all the interfaces and make sure none are // claimed by anybody else. for ( intf_num = 0; intf_num < config->bNumInterfaces; intf_num++ ) { comm_intf_group = &( config->interface[intf_num] ); if ( usb_interface_claimed( comm_intf_group ) ) { // Somebody has beat us to this guy. // We can't change the configuration out from underneath of whoever
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -