G'day,
This patch (against 2.4.19-pre4, should apply widely) to the CDC Ethernet
model driver implements a number of changes:
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.
I still have to do a lot of locking, but I'd like to seperate out some of the
changes.
Greg - please hold this patch. I'd like to get some test reports from the
Zaurus owners (and others) before applying.
Brad
diff -Naur -X dontdiff linux-2.4.19-pre4-clean/Documentation/Configure.help linux-2.4.19-pre4-CDCEther/Documentation/Configure.help
--- linux-2.4.19-pre4-clean/Documentation/Configure.help Sat Mar 23 18:09:38 2002
+++ linux-2.4.19-pre4-CDCEther/Documentation/Configure.help Sat Mar 23 22:12:34 2002
@@ -13385,6 +13385,7 @@
* Motorola (DM100 and SB4100)
* Broadcom Cable Modem (reference design)
* Toshiba PCX1100U and possibly other cable modems
+ * Sharp Zaurus SL-5000D
The device creates a network device (ethX, where X depends on what
other networking devices you have in use), as for a normal PCI
diff -Naur -X dontdiff linux-2.4.19-pre4-clean/drivers/usb/CDCEther.c linux-2.4.19-pre4-CDCEther/drivers/usb/CDCEther.c
--- linux-2.4.19-pre4-clean/drivers/usb/CDCEther.c Sat Mar 23 18:08:30 2002
+++ linux-2.4.19-pre4-CDCEther/drivers/usb/CDCEther.c Sat Mar 23 21:53:32 2002
@@ -1,4 +1,4 @@
-// Portions of this file taken from
+// Portions of this file taken from
// Petko Manolov - Petkan ([EMAIL PROTECTED])
// from his driver pegasus.c
@@ -25,20 +25,27 @@
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include <linux/usb.h>
#include <linux/module.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
+
+#define DEBUG
+#include <linux/usb.h>
+
#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,11 +1452,10 @@
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 -Naur -X dontdiff linux-2.4.19-pre4-clean/drivers/usb/CDCEther.h linux-2.4.19-pre4-CDCEther/drivers/usb/CDCEther.h
--- linux-2.4.19-pre4-clean/drivers/usb/CDCEther.h Sat Mar 23 18:08:30 2002
+++ linux-2.4.19-pre4-CDCEther/drivers/usb/CDCEther.h Sat Mar 23 21:17:12 2002
@@ -1,4 +1,4 @@
-// Portions of this file taken from
+// Portions of this file taken from
// Petko Manolov - Petkan ([EMAIL PROTECTED])
// 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 */