# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.302 -> 1.303 # drivers/usb/CDCEther.c 1.5 -> 1.6 # drivers/usb/CDCEther.h 1.2 -> 1.3 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/04/02 bhards@bigpond.net.au 1.303 # USB CDCEther driver update # # 1. adds support for devices that don't have the interrupt endpoint, which is # basically Sharp Zaurus SL-5000D support. Untested by me, if anyone has this # hardware, please test and report. # # 2. Ethtool ioctl support. Currently the link state always reports good, but # if I had proper interrupt support on a test device, I could probably make it # more logical. Anyone with a CDC Ethernet device that actually reports # anything over the interrupt notification endpoint should get in contact with # me. # # 3. Removes the ALIGN macro. # # 4. Avoids the "device not claimed" warning. # # 5. General code cleanup. # -------------------------------------------- # diff -Nru a/drivers/usb/CDCEther.c b/drivers/usb/CDCEther.c --- a/drivers/usb/CDCEther.c Wed Apr 3 10:47:46 2002 +++ b/drivers/usb/CDCEther.c Wed Apr 3 10:47:46 2002 @@ -1,4 +1,4 @@ -// Portions of this file taken from +// Portions of this file taken from // Petko Manolov - Petkan (petkan@dce.bg) // from his driver pegasus.c @@ -25,20 +25,27 @@ #include #include #include -#include #include +#include +#include + +#define DEBUG +#include + #include "CDCEther.h" -static const char *version = __FILE__ ": v0.98.5 22 Sep 2001 Brad Hards and another"; +#define SHORT_DRIVER_DESC "CDC Ethernet Class" +#define DRIVER_VERSION "0.98.6" -/* Take any CDC device, and sort it out in probe() */ +static const char *version = __FILE__ ": " DRIVER_VERSION " 7 Jan 2002 Brad Hards and another"; +// We only try to claim CDC Ethernet model devices */ static struct usb_device_id CDCEther_ids[] = { - { USB_DEVICE_INFO(USB_CLASS_COMM, 0, 0) }, - { } /* Terminating null entry */ + { USB_INTERFACE_INFO(USB_CLASS_COMM, 6, 0) }, + { } }; -/* - * module parameter that provides an alternate upper limit on the +/* + * module parameter that provides an alternate upper limit on the * number of multicast filters we use, with a default to use all * the filters available to us. Note that the actual number used * is the lesser of this parameter and the number returned in the @@ -47,7 +54,6 @@ */ static int multicast_filter_limit = 32767; - ////////////////////////////////////////////////////////////////////////////// // Callback routines from USB device ///////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -59,7 +65,16 @@ int count = urb->actual_length, res; struct sk_buff *skb; - // Sanity check + switch ( urb->status ) { + case USB_ST_NOERROR: + break; + case USB_ST_URB_KILLED: + return; + default: + dbg("rx status %d", urb->status); + } + + // Sanity check if ( !ether_dev || !(ether_dev->flags & CDC_ETHER_RUNNING) ) { dbg("BULK IN callback but driver is not active!"); return; @@ -133,7 +148,7 @@ // Give this to the USB subsystem so it can tell us // when more data arrives. if ( (res = usb_submit_urb(ðer_dev->rx_urb)) ) { - warn( __FUNCTION__ " failed submint rx_urb %d", res); + warn( __FUNCTION__ " failed submit rx_urb %d", res); } // We are no longer busy, show us the frames!!! @@ -160,47 +175,69 @@ // Hmm... What on Earth could have happened??? if ( urb->status ) { - info("%s: TX status %d", ether_dev->net->name, urb->status); + dbg("%s: TX status %d", ether_dev->net->name, urb->status); } // Update the network interface and tell it we are // ready for another frame ether_dev->net->trans_start = jiffies; netif_wake_queue( ether_dev->net ); + } -//static void intr_callback( struct urb *urb ) -//{ -// ether_dev_t *ether_dev = urb->context; -// struct net_device *net; -// __u8 *d; -// -// if ( !ether_dev ) -// return; -// -// switch ( urb->status ) { -// case USB_ST_NOERROR: -// break; -// case USB_ST_URB_KILLED: -// return; -// default: -// info("intr status %d", urb->status); -// } -// -// d = urb->transfer_buffer; -// net = ether_dev->net; -// if ( d[0] & 0xfc ) { -// ether_dev->stats.tx_errors++; -// if ( d[0] & TX_UNDERRUN ) -// ether_dev->stats.tx_fifo_errors++; -// if ( d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT) ) -// ether_dev->stats.tx_aborted_errors++; -// if ( d[0] & LATE_COL ) -// ether_dev->stats.tx_window_errors++; -// if ( d[0] & (NO_CARRIER | LOSS_CARRIER) ) -// ether_dev->stats.tx_carrier_errors++; -// } -//} +#if 0 +static void setpktfilter_done( struct urb *urb ) +{ + ether_dev_t *ether_dev = urb->context; + struct net_device *net; + + if ( !ether_dev ) + return; + dbg("got ctrl callback for setting packet filter"); + switch ( urb->status ) { + case USB_ST_NOERROR: + break; + case USB_ST_URB_KILLED: + return; + default: + dbg("intr status %d", urb->status); + } +} +#endif + +static void intr_callback( struct urb *urb ) +{ + ether_dev_t *ether_dev = urb->context; + struct net_device *net; + __u8 *d; + + if ( !ether_dev ) + return; + dbg("got intr callback"); + switch ( urb->status ) { + case USB_ST_NOERROR: + break; + case USB_ST_URB_KILLED: + return; + default: + dbg("intr status %d", urb->status); + } + + d = urb->transfer_buffer; + dbg("d: %x", d[0]); + net = ether_dev->net; + if ( d[0] & 0xfc ) { + ether_dev->stats.tx_errors++; + if ( d[0] & TX_UNDERRUN ) + ether_dev->stats.tx_fifo_errors++; + if ( d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT) ) + ether_dev->stats.tx_aborted_errors++; + if ( d[0] & LATE_COL ) + ether_dev->stats.tx_window_errors++; + if ( d[0] & (NO_CARRIER | LOSS_CARRIER) ) + netif_carrier_off(net); + } +} ////////////////////////////////////////////////////////////////////////////// // Routines for turning net traffic on and off on the USB side /////////////// @@ -213,8 +250,8 @@ // Here would be the time to set the data interface to the configuration where // it has two endpoints that use a protocol we can understand. - if (usb_set_interface( usb, - ether_dev->data_bInterfaceNumber, + if (usb_set_interface( usb, + ether_dev->data_bInterfaceNumber, ether_dev->data_bAlternateSetting_with_traffic ) ) { err("usb_set_interface() failed" ); err("Attempted to set interface %d", ether_dev->data_bInterfaceNumber); @@ -230,8 +267,8 @@ // no endpoints. This is what the spec suggests. if (ether_dev->data_interface_altset_num_without_traffic >= 0 ) { - if (usb_set_interface( ether_dev->usb, - ether_dev->data_bInterfaceNumber, + if (usb_set_interface( ether_dev->usb, + ether_dev->data_bInterfaceNumber, ether_dev->data_bAlternateSetting_without_traffic ) ) { err("usb_set_interface() failed"); } @@ -326,6 +363,9 @@ return 0; } +////////////////////////////////////////////////////////////////////////////// +// Standard routines for kernel Ethernet Device ////////////////////////////// +////////////////////////////////////////////////////////////////////////////// static struct net_device_stats *CDCEther_netdev_stats( struct net_device *net ) { // Easy enough! @@ -343,19 +383,33 @@ return -EIO; } - // Prep a receive URB + /* 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, + 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... + /* Put it out there so the device can send us stuff */ + if ( (res = usb_submit_urb(ðer_dev->rx_urb)) ) { + /* Hmm... Okay... */ warn( __FUNCTION__ " failed rx_urb %d", 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( __FUNCTION__ " failed intr_urb %d", res ); + } + } + // Tell the kernel we are ready to start receiving from it netif_start_queue( net ); @@ -386,92 +440,133 @@ 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 CDCEther_ioctl( struct net_device *net, struct ifreq *rq, int cmd ) +static int netdev_ethtool_ioctl(struct net_device *netdev, void *useraddr) { - //__u16 *data = (__u16 *)&rq->ifr_data; - //ether_dev_t *ether_dev = net->priv; + 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 */ +} - // No support here yet. - // Do we need support??? +static int CDCEther_ioctl( struct net_device *net, struct ifreq *rq, int cmd ) +{ switch(cmd) { - case SIOCDEVPRIVATE: - return -EOPNOTSUPP; - case SIOCDEVPRIVATE+1: - return -EOPNOTSUPP; - case SIOCDEVPRIVATE+2: - //return 0; - return -EOPNOTSUPP; - default: - return -EOPNOTSUPP; + 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) { - usb_control_msg(ether_dev->usb, +#if 0 + devrequest *dr = ðer_dev->ctrl_dr; + int res; + + dr->requesttype = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE; + dr->request = SET_ETHERNET_PACKET_FILTER; + dr->value = cpu_to_le16(ether_dev->mode_flags); + dr->index = cpu_to_le16((u16)ether_dev->comm_interface); + dr->length = 0; + + FILL_CONTROL_URB(ðer_dev->ctrl_urb, + ether_dev->usb, usb_sndctrlpipe(ether_dev->usb, 0), - SET_ETHERNET_PACKET_FILTER, /* request */ - USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE, /* request type */ - cpu_to_le16(ether_dev->mode_flags), /* value */ - cpu_to_le16((u16)ether_dev->comm_interface), /* index */ + dr, + NULL, NULL, - 0, /* size */ - HZ); /* timeout */ -} + setpktfilter_done, + ether_dev); + if ( (res = usb_submit_urb(ðer_dev->ctrl_urb)) ) { + warn( __FUNCTION__ " failed submit ctrl_urb %d", 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. */ - info( "%s: Promiscuous mode enabled", net->name); + /* 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. */ - info("%s: set too many MC filters, using allmulti", net->name); + } 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 */ - info("%s: using allmulti", net->name); + /* 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 { + } else { /* do multicast filtering in hardware */ - struct dev_mc_list *mclist; - info("%s: set multicast filters", net->name); + 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); + 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, @@ -487,10 +582,9 @@ kfree(buff); } -#if 0 CDC_SetEthernetPacketFilter(ether_dev); -#endif - // Tell the kernel to start giving frames to us again. + + /* Tell the kernel to start giving frames to us again. */ netif_wake_queue(net); } @@ -498,40 +592,42 @@ // Routines used to parse out the Functional Descriptors ///////////////////// ////////////////////////////////////////////////////////////////////////////// -static int parse_header_functional_descriptor( int *bFunctionLength, - int bDescriptorType, +/* 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. + /* 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; + + /* 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 + /* 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); + dbg( "Found Header descriptor, CDC version %x.", ether_dev->bcdCDC); - // We've seen one of these + /* We've seen one of these */ *requirements &= ~REQ_HDR_FUNC_DESCR; - - // It's all good. + + /* 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, @@ -539,77 +635,89 @@ ether_dev_t *ether_dev, int *requirements ) { - // Check to make sure we haven't seen one of these already. + /* 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) { + /* Check for appropriate length */ + if (*bFunctionLength != UNION_FUNC_DESC_LEN) { // It is NOT the size we expected. - err( "Unsupported length in Union Functional Descriptor" ); + err( "Invalid length in Union Functional Descriptor." ); return -1; } - // Sanity check of sorts + /* 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. + /* 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 + 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" ); + err( "Union Functional Descriptor is broken beyond repair." ); return -1; } - } else{ // Descriptor is OK - // We'll need this in a few microseconds! + } else{ /* Descriptor is OK */ ether_dev->data_interface = data[1]; } - // We've seen one of these now. + /* We've seen one of these */ *requirements &= ~REQ_UNION_FUNC_DESCR; - - // Done + + /* Success */ return 0; } -static int parse_ethernet_functional_descriptor( int *bFunctionLength, +/* 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. + //* 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" ); + /* 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. + + /* 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; + 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 now. + /* We've seen one of these */ *requirements &= ~REQ_ETH_FUNC_DESCR; - - // That's all she wrote. + + /* Success */ return 0; } @@ -620,15 +728,15 @@ ether_dev_t *ether_dev, int *requirements ) { - // There should only be one type if we are sane + /* There should only be one type if we are sane */ if (bDescriptorType != CS_INTERFACE) { - info( "Invalid bDescriptorType found." ); + err( "Invalid bDescriptorType found." ); return -1; } - // The Subtype tells the tale. - switch (bDescriptorSubtype){ - case 0x00: // Header Functional Descriptor + /* The Subtype tells the tale - CDC spec Table 25 */ + switch (bDescriptorSubtype) { + case 0x00: /* Header Functional Descriptor */ return parse_header_functional_descriptor( bFunctionLength, bDescriptorType, bDescriptorSubtype, @@ -636,7 +744,7 @@ ether_dev, requirements ); break; - case 0x06: // Union Functional Descriptor + case 0x06: /* Union Functional Descriptor */ return parse_union_functional_descriptor( bFunctionLength, bDescriptorType, bDescriptorSubtype, @@ -644,7 +752,7 @@ ether_dev, requirements ); break; - case 0x0F: // Ethernet Networking Functional Descriptor + case 0x0F: /* Ethernet Networking Functional Descriptor */ return parse_ethernet_functional_descriptor( bFunctionLength, bDescriptorType, bDescriptorSubtype, @@ -652,12 +760,12 @@ 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 ); + 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??? + /* How did we get here? */ return -1; } @@ -668,46 +776,49 @@ int bFunctionLength; int bDescriptorType; int bDescriptorSubtype; - int requirements = REQUIREMENTS_TOTAL; + 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 + /* 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 + /* Length */ bFunctionLength = data[loc]; loc++; - - // Type + + /* Type */ bDescriptorType = data[loc]; loc++; - - // Subtype + + /* Subtype */ bDescriptorSubtype = data[loc]; loc++; - // ship this off to be processed elsewhere. + /* ship this off to be processed */ rc = parse_protocol_unit_functional_descriptor( &bFunctionLength, bDescriptorType, bDescriptorSubtype, &data[loc], ether_dev, &requirements ); - // Did it process okay? + /* Did it process okay? */ if (rc) { - // Something was hosed somewhere. - // No need to continue; + /* Something was hosed somewhere. */ + /* No need to continue */ err("Bad descriptor parsing: %x", rc ); return -1; } - // We have already taken three bytes. + /* 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. + /* 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 ); + err( "Not all required functional descriptors present 0x%08X.", requirements ); return -1; } - // We got everything. + /* We got everything */ return 0; } @@ -721,28 +832,28 @@ 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. + /* 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... + /* 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. + /* 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." ); + /* 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. - warn( "No ethernet information found." ); + /* I don't know where else to look */ + err( "No ethernet information found." ); rc = -1; } return rc; @@ -757,47 +868,43 @@ 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. + + /* 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 + /* 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 ) { + + /* 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 != 0x02 ) { + } + 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 & 0x80 ) { - // This endpoint is IN + /* 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 { - // This endpoint is OUT - ether_dev->data_ep_out = data_intf->endpoint[0].bEndpointAddress & 0x7F; + 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 & 0x80 ) { - // This endpoint is IN + /* 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 { - // This endpoint is OUT - ether_dev->data_ep_out = data_intf->endpoint[1].bEndpointAddress & 0x7F; + 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 + + /* 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 ); + dbg( "detected BULK OUT packets of size %d", ether_dev->data_ep_out_size ); return 0; } return -1; @@ -887,45 +994,45 @@ 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 - // 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. + /* 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; @@ -1005,8 +1112,8 @@ static inline unsigned char hex2dec( unsigned char digit ) { - // Is there a standard way to do this??? - // I have written this code TOO MANY times. + /* Is there a standard way to do this??? */ + /* I have written this code TOO MANY times. */ if ( (digit >= '0') && (digit <= '9') ) { return (digit - '0'); } @@ -1016,9 +1123,14 @@ if ( (digit >= 'A') && (digit <= 'F') ) { return (digit - 'A' + 10); } - return 0; + 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]; @@ -1026,7 +1138,7 @@ int len; unsigned char buffer[13]; - // Let's assume we don't get anything... + /* Let's assume we don't get anything */ mac_addr[0] = 0x00; mac_addr[1] = 0x00; mac_addr[2] = 0x00; @@ -1034,22 +1146,30 @@ mac_addr[4] = 0x00; mac_addr[5] = 0x00; - // Let's ask the device... - len = usb_string(ether_dev->usb, ether_dev->iMACAddress, buffer, 13); + /* 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! + /* Sanity check */ if (len != 12) { - // You gotta love failing sanity checks + /* You gotta love failing sanity checks */ err("Attempting to get MAC address returned %d bytes", len); return; } - // Fill in the mac_addr + /* Fill in the mac_addr */ for (i = 0; i < 6; i++) { - mac_addr[i] = ( hex2dec( buffer[2 * i] ) << 4 ) + hex2dec( buffer[2 * i + 1] ); + 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 the kernel's network driver. + /* Now copy it over to our network device structure */ memcpy( ether_dev->net->dev_addr, mac_addr, sizeof(mac_addr) ); } @@ -1067,12 +1187,12 @@ unsigned char sern[256]; unsigned char *mac_addr; - // Default empty strings in case we don't find a real one + /* 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 + /* Try to get the device Manufacturer */ string_num = ether_dev->usb->descriptor.iManufacturer; if (string_num) { // Put it into its buffer @@ -1081,7 +1201,7 @@ manu[len] = 0x00; } - // Try to get the device Product Name + /* Try to get the device Product Name */ string_num = ether_dev->usb->descriptor.iProduct; if (string_num) { // Put it into its buffer @@ -1090,7 +1210,7 @@ prod[len] = 0x00; } - // Try to get the device Serial Number + /* Try to get the device Serial Number */ string_num = ether_dev->usb->descriptor.iSerialNumber; if (string_num) { // Put it into its buffer @@ -1099,14 +1219,20 @@ sern[len] = 0x00; } - // This makes it easier for us to print + /* 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] ); + /* 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 */ @@ -1227,11 +1353,7 @@ // 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 + /* 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 ); @@ -1239,11 +1361,8 @@ // 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; + return ether_dev; } @@ -1313,7 +1432,7 @@ int __init CDCEther_init(void) { - info( "%s", version ); + dbg( "%s", version ); return usb_register( &CDCEther_driver ); } @@ -1333,10 +1452,9 @@ 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"); - -MODULE_DEVICE_TABLE (usb, CDCEther_ids); ////////////////////////////////////////////////////////////////////////////// // End of file /////////////////////////////////////////////////////////////// diff -Nru a/drivers/usb/CDCEther.h b/drivers/usb/CDCEther.h --- a/drivers/usb/CDCEther.h Wed Apr 3 10:47:46 2002 +++ b/drivers/usb/CDCEther.h Wed Apr 3 10:47:46 2002 @@ -1,4 +1,4 @@ -// Portions of this file taken from +// Portions of this file taken from // Petko Manolov - Petkan (petkan@dce.bg) // from his driver pegasus.h @@ -18,11 +18,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - +/* From CDC Spec Table 24 */ #define CS_INTERFACE 0x24 #define CDC_ETHER_MAX_MTU 1536 +/* These definitions are used with the ether_dev_t flags element */ #define CDC_ETHER_PRESENT 0x00000001 #define CDC_ETHER_RUNNING 0x00000002 #define CDC_ETHER_TX_BUSY 0x00000004 @@ -31,10 +32,10 @@ #define CDC_ETHER_TX_TIMEOUT (HZ*10) -#define TX_UNDERRUN 0x80 +#define TX_UNDERRUN 0x80 #define EXCESSIVE_COL 0x40 -#define LATE_COL 0x20 -#define NO_CARRIER 0x10 +#define LATE_COL 0x20 +#define NO_CARRIER 0x10 #define LOSS_CARRIER 0x08 #define JABBER_TIMEOUT 0x04 @@ -43,22 +44,13 @@ #define CDC_ETHER_REQ_GET_REGS 0xf0 #define CDC_ETHER_REQ_SET_REGS 0xf1 #define CDC_ETHER_REQ_SET_REG PIPERIDER_REQ_SET_REGS -#define ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES))) - -#define MODE_FLAG_PROMISCUOUS (1<<0) -#define MODE_FLAG_ALL_MULTICAST (1<<1) -#define MODE_FLAG_DIRECTED (1<<2) -#define MODE_FLAG_BROADCAST (1<<3) -#define MODE_FLAG_MULTICAST (1<<4) - -#define SET_ETHERNET_MULTICAST_FILTER 0x40 -#define SET_ETHERNET_PACKET_FILTER 0x43 typedef struct _ether_dev_t { struct usb_device *usb; struct net_device *net; struct net_device_stats stats; unsigned flags; + unsigned properties; int configuration_num; int bConfigurationValue; int comm_interface; @@ -79,20 +71,44 @@ __u8 iMACAddress; __u32 bmEthernetStatistics; __u16 wMaxSegmentSize; - __u16 mode_flags; __u16 wNumberMCFilters; __u8 bNumberPowerFilters; + __u16 mode_flags; int intr_interval; - struct urb rx_urb, tx_urb, intr_urb; - unsigned char ALIGN(rx_buff[CDC_ETHER_MAX_MTU]); - unsigned char ALIGN(tx_buff[CDC_ETHER_MAX_MTU]); - unsigned char ALIGN(intr_buff[8]); + devrequest ctrl_dr; + struct urb rx_urb, tx_urb, intr_urb, ctrl_urb; + unsigned char rx_buff[CDC_ETHER_MAX_MTU] __attribute__((aligned(L1_CACHE_BYTES))); + unsigned char tx_buff[CDC_ETHER_MAX_MTU] __attribute__((aligned(L1_CACHE_BYTES))); + unsigned char intr_buff[8] __attribute__((aligned(L1_CACHE_BYTES))) ; } ether_dev_t; +/* These definitions used in the Ethernet Packet Filtering requests */ +/* See CDC Spec Table 62 */ +#define MODE_FLAG_PROMISCUOUS (1<<0) +#define MODE_FLAG_ALL_MULTICAST (1<<1) +#define MODE_FLAG_DIRECTED (1<<2) +#define MODE_FLAG_BROADCAST (1<<3) +#define MODE_FLAG_MULTICAST (1<<4) + +/* CDC Spec class requests - CDC Spec Table 46 */ +#define SET_ETHERNET_MULTICAST_FILTER 0x40 +#define SET_ETHERNET_PACKET_FILTER 0x43 + + +/* These definitions are used with the ether_dev_t properties field */ +#define HAVE_NOTIFICATION_ELEMENT 0x0001 +#define PERFECT_FILTERING 0x0002 +#define NO_SET_MULTICAST 0x0004 + +/* These definitions are used in the requirements parser */ #define REQ_HDR_FUNC_DESCR 0x0001 #define REQ_UNION_FUNC_DESCR 0x0002 #define REQ_ETH_FUNC_DESCR 0x0004 -#define REQUIREMENTS_TOTAL 0x0007 +#define REQUIREMENTS_TOTAL REQ_ETH_FUNC_DESCR | REQ_UNION_FUNC_DESCR | REQ_HDR_FUNC_DESCR +/* Some useful lengths */ +#define HEADER_FUNC_DESC_LEN 0x5 +#define UNION_FUNC_DESC_LEN 0x5 +#define ETHERNET_FUNC_DESC_LEN 0xD /* 13 for all you decimal weenies */