📄 cdcether.c
字号:
// 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 16;}/* CDC Ethernet devices provide the MAC address as a string *//* We get an index to the string in the Ethernet functional header *//* This routine retrieves the string, sanity checks it, and sets the *//* MAC address in the network device *//* The encoding is a bit wacky - see CDC Spec Table 41 for details */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 */ if (0 > (len = usb_string(ether_dev->usb, ether_dev->iMACAddress, buffer, 13))) { err("Attempting to get MAC address failed: %d", -1*len); return; } /* 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++) { if ((16 == buffer[2 * i]) || (16 == buffer[2 * i + 1])) { err("Bad value in MAC address"); } else { mac_addr[i] = ( hex2dec( buffer[2 * i] ) << 4 ) + hex2dec( buffer[2 * i + 1] ); } } /* Now copy it over to our network device structure */ 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", ether_dev->net->name, manu, prod, sern); dbg( "%s: %02X:%02X:%02X:%02X:%02X:%02X", ether_dev->net->name, 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 ); /* We need to manually claim the data interface, while the comm interface gets claimed in the return */ 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 ); // Okay, we are finally done... return ether_dev;}//////////////////////////////////////////////////////////////////////////////// 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){ dbg( "%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_DEVICE_TABLE (usb, CDCEther_ids);MODULE_PARM (multicast_filter_limit, "i");MODULE_PARM_DESC (multicast_filter_limit, "CDCEther maximum number of filtered multicast addresses");//////////////////////////////////////////////////////////////////////////////// End of file /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -