📄 cdcether.c
字号:
// 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; } // This communication interface seems to give us everything // we require. We have all the ethernet info we need. // Let's get out of here and go home right now. return 0; } else { // bNumEndPoints != 1 // We found an interface that had the wrong number of // endpoints but would have otherwise been okay } // end bNumEndpoints check. } // end interface specifics check. } // 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 // is using this device, so we will go ahead and give up. return -1; } } // We made it all the way through. // I guess no one has claimed any of these interfaces. return 0;}//////////////////////////////////////////////////////////////////////////////// Routines to ask for and set the kernel network interface's MAC address ////// Used by driver's probe routine //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////static inline unsigned char hex2dec( unsigned char digit ){ // Is there a standard way to do this??? // I have written this code TOO MANY times. if ( (digit >= '0') && (digit <= '9') ) { return (digit - '0'); } if ( (digit >= 'a') && (digit <= 'f') ) { return (digit - 'a' + 10); } if ( (digit >= 'A') && (digit <= 'F') ) { return (digit - 'A' + 10); } return 0;}static void set_ethernet_addr( ether_dev_t *ether_dev ){ unsigned char mac_addr[6]; int i; int len; unsigned char buffer[13]; // Let's assume we don't get anything... mac_addr[0] = 0x00; mac_addr[1] = 0x00; mac_addr[2] = 0x00; mac_addr[3] = 0x00; mac_addr[4] = 0x00; mac_addr[5] = 0x00; // Let's ask the device... len = usb_string(ether_dev->usb, ether_dev->iMACAddress, buffer, 13); // Sanity check! if (len != 12) { // You gotta love failing sanity checks err("Attempting to get MAC address returned %d bytes", len); return; } // Fill in the mac_addr for (i = 0; i < 6; i++) { mac_addr[i] = ( hex2dec( buffer[2 * i] ) << 4 ) + hex2dec( buffer[2 * i + 1] ); } // Now copy it over to the kernel's network driver. memcpy( ether_dev->net->dev_addr, mac_addr, sizeof(mac_addr) );}//////////////////////////////////////////////////////////////////////////////// Routine to print to syslog information about the driver ///////////////////// Used by driver's probe routine //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////void log_device_info(ether_dev_t *ether_dev){ int len; int string_num; unsigned char manu[256]; unsigned char prod[256]; unsigned char sern[256]; unsigned char *mac_addr; // Default empty strings in case we don't find a real one manu[0] = 0x00; prod[0] = 0x00; sern[0] = 0x00; // Try to get the device Manufacturer string_num = ether_dev->usb->descriptor.iManufacturer; if (string_num) { // Put it into its buffer len = usb_string(ether_dev->usb, string_num, manu, 255); // Just to be safe manu[len] = 0x00; } // Try to get the device Product Name string_num = ether_dev->usb->descriptor.iProduct; if (string_num) { // Put it into its buffer len = usb_string(ether_dev->usb, string_num, prod, 255); // Just to be safe prod[len] = 0x00; } // Try to get the device Serial Number string_num = ether_dev->usb->descriptor.iSerialNumber; if (string_num) { // Put it into its buffer len = usb_string(ether_dev->usb, string_num, sern, 255); // Just to be safe sern[len] = 0x00; } // This makes it easier for us to print mac_addr = ether_dev->net->dev_addr; // Now send everything we found to the syslog info( "%s: %s %s %s %02X:%02X:%02X:%02X:%02X:%02X", ether_dev->net->name, manu, prod, sern, mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5] );}/* Forward declaration */static struct usb_driver CDCEther_driver ;//////////////////////////////////////////////////////////////////////////////// Module's probe routine ////////////////////////////////////////////////////// claims interfaces if they are for an Ethernet CDC ///////////////////////////////////////////////////////////////////////////////////////////////////////static void * CDCEther_probe( struct usb_device *usb, unsigned int ifnum, const struct usb_device_id *id){ struct net_device *net; ether_dev_t *ether_dev; int rc; // First we should check the active configuration to see if // any other driver has claimed any of the interfaces. if ( check_for_claimed_interfaces( usb->actconfig ) ) { // Someone has already put there grubby paws on this device. // We don't want it now... return NULL; } // We might be finding a device we can use. // We all go ahead and allocate our storage space. // We need to because we have to start filling in the data that // we are going to need later. if(!(ether_dev = kmalloc(sizeof(ether_dev_t), GFP_KERNEL))) { err("out of memory allocating device structure"); return NULL; } // Zero everything out. memset(ether_dev, 0, sizeof(ether_dev_t)); // Let's see if we can find a configuration we can use. rc = find_valid_configuration( usb, ether_dev ); if (rc) { // Nope we couldn't find one we liked. // This device was not meant for us to control. kfree( ether_dev ); return NULL; } // Now that we FOUND a configuration. let's try to make the // device go into it. if ( usb_set_configuration( usb, ether_dev->bConfigurationValue ) ) { err("usb_set_configuration() failed"); kfree( ether_dev ); return NULL; } // Now set the communication interface up as required. if (usb_set_interface(usb, ether_dev->comm_bInterfaceNumber, ether_dev->comm_bAlternateSetting)) { err("usb_set_interface() failed"); kfree( ether_dev ); return NULL; } // Only turn traffic on right now if we must... if (ether_dev->data_interface_altset_num_without_traffic >= 0) { // We found an alternate setting for the data // interface that allows us to turn off traffic. // We should use it. if (usb_set_interface( usb, ether_dev->data_bInterfaceNumber, ether_dev->data_bAlternateSetting_without_traffic)) { err("usb_set_interface() failed"); kfree( ether_dev ); return NULL; } } else { // We didn't find an alternate setting for the data // interface that would let us turn off traffic. // Oh well, let's go ahead and do what we must... if (usb_set_interface( usb, ether_dev->data_bInterfaceNumber, ether_dev->data_bAlternateSetting_with_traffic)) { err("usb_set_interface() failed"); kfree( ether_dev ); return NULL; } } // Now we need to get a kernel Ethernet interface. net = init_etherdev( NULL, 0 ); if ( !net ) { // Hmm... The kernel is not sharing today... // Fine, we didn't want it anyway... err( "Unable to initialize ethernet device" ); kfree( ether_dev ); return NULL; } // Now that we have an ethernet device, let's set it up // (And I don't mean "set [it] up the bomb".) net->priv = ether_dev; SET_MODULE_OWNER(net); net->open = CDCEther_open; net->stop = CDCEther_close; net->watchdog_timeo = CDC_ETHER_TX_TIMEOUT; net->tx_timeout = CDCEther_tx_timeout; // TX timeout function net->do_ioctl = CDCEther_ioctl; net->hard_start_xmit = CDCEther_start_xmit; net->set_multicast_list = CDCEther_set_multicast; net->get_stats = CDCEther_netdev_stats; net->mtu = ether_dev->wMaxSegmentSize - 14; // We'll keep track of this information for later... ether_dev->usb = usb; ether_dev->net = net; // and don't forget the MAC address. set_ethernet_addr( ether_dev ); // Send a message to syslog about what we are handling log_device_info( ether_dev ); // I claim this interface to be a CDC Ethernet Networking device usb_driver_claim_interface( &CDCEther_driver, &(usb->config[ether_dev->configuration_num].interface[ether_dev->comm_interface]), ether_dev ); // I claim this interface to be a CDC Ethernet Networking device usb_driver_claim_interface( &CDCEther_driver, &(usb->config[ether_dev->configuration_num].interface[ether_dev->data_interface]), ether_dev ); // Does this REALLY do anything??? usb_inc_dev_use( usb ); // TODO - last minute HACK ether_dev->comm_ep_in = 5; // Okay, we are finally done... return NULL;}//////////////////////////////////////////////////////////////////////////////// Module's disconnect routine ///////////////////////////////////////////////// Called when the driver is unloaded or the device is unplugged /////////////// (Whichever happens first assuming the driver suceeded at its probe) /////////////////////////////////////////////////////////////////////////////////////static void CDCEther_disconnect( struct usb_device *usb, void *ptr ){ ether_dev_t *ether_dev = ptr; // Sanity check!!! if ( !ether_dev || !ether_dev->usb ) { // We failed. We are insane!!! warn("unregistering non-existant device"); return; } // Make sure we fail the sanity check if we try this again. ether_dev->usb = NULL; // It is possible that this function is called before // the "close" function. // This tells the close function we are already disconnected ether_dev->flags |= CDC_ETHER_UNPLUG; // We don't need the network device any more unregister_netdev( ether_dev->net ); // For sanity checks ether_dev->net = NULL; // I ask again, does this do anything??? usb_dec_dev_use( usb ); // We are done with this interface usb_driver_release_interface( &CDCEther_driver, &(usb->config[ether_dev->configuration_num].interface[ether_dev->comm_interface]) ); // We are done with this interface too usb_driver_release_interface( &CDCEther_driver, &(usb->config[ether_dev->configuration_num].interface[ether_dev->data_interface]) ); // No more tied up kernel memory kfree( ether_dev ); // This does no good, but it looks nice! ether_dev = NULL;}//////////////////////////////////////////////////////////////////////////////// Driver info /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////static struct usb_driver CDCEther_driver = { name: "CDCEther", probe: CDCEther_probe, disconnect: CDCEther_disconnect, id_table: CDCEther_ids,};//////////////////////////////////////////////////////////////////////////////// init and exit routines called when driver is installed and uninstalled //////////////////////////////////////////////////////////////////////////////////int __init CDCEther_init(void){ info( "%s", version ); return usb_register( &CDCEther_driver );}void __exit CDCEther_exit(void){ usb_deregister( &CDCEther_driver );}//////////////////////////////////////////////////////////////////////////////// Module info /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////module_init( CDCEther_init );module_exit( CDCEther_exit );MODULE_AUTHOR("Brad Hards and another");MODULE_DESCRIPTION("USB CDC Ethernet driver");MODULE_LICENSE("GPL");MODULE_PARM (multicast_filter_limit, "i");MODULE_PARM_DESC (multicast_filter_limit, "CDCEther maximum number of filtered multicast addresses");MODULE_DEVICE_TABLE (usb, CDCEther_ids);//////////////////////////////////////////////////////////////////////////////// End of file /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -