So, for a little project I'm cooking up I needed a couple of USB Ethernet interfaces. There's no shortage of ebay sellers of these so I grabbed a couple from the first UK seller I found, with them arriving promptly the next day.
Now, in the last few years Linux's hardware support has improved to the point that I don't spend as much time worrying about whether things will work: they invariably do.
So, plug and play, right? Sadly in this case I was disappointed. Plugging in the adapter prompted a report that it was there and was indeed a 10/100 Ethernet device, but nothing further. No driver support on the plain-vanilla Debian install currently gracing my netbook. That was surprise one.
Surprise two was finding that the supplied driver CD (how quaint!) had a Linux directory. Fortunately out-of-tree drivers follow a reasonably standardised structure so the Chinese README wasn't a problem. However it wasn't all plain sailing.
% make
Building QF9700 USB2NET chip driver...
make[1]: Entering directory `/usr/src/linux-headers-2.6.32-trunk-amd64'
CC [M] /home/mrq1/tmp/qf9700/qf9700.o
/home/mrq1/tmp/qf9700/qf9700.c: In function ‘qf9700_bind’:
/home/mrq1/tmp/qf9700/qf9700.c:380: error: ‘struct net_device’ has no member named ‘do_ioctl’
/home/mrq1/tmp/qf9700/qf9700.c:381: error: ‘struct net_device’ has no member named ‘set_multicast_list’
/home/mrq1/tmp/qf9700/qf9700.c: In function ‘qf9700_rx_fixup’:
/home/mrq1/tmp/qf9700/qf9700.c:443: error: ‘struct usbnet’ has no member named ‘stats’
/home/mrq1/tmp/qf9700/qf9700.c:444: error: ‘struct usbnet’ has no member named ‘stats’
/home/mrq1/tmp/qf9700/qf9700.c:445: error: ‘struct usbnet’ has no member named ‘stats’
/home/mrq1/tmp/qf9700/qf9700.c:446: error: ‘struct usbnet’ has no member named ‘stats’
/home/mrq1/tmp/qf9700/qf9700.c:447: error: ‘struct usbnet’ has no member named ‘stats’
make[4]: *** [/home/mrq1/tmp/qf9700/qf9700.o] Error 1
make[3]: *** [_module_/home/mrq1/tmp/qf9700] Error 2
make[2]: *** [sub-make] Error 2
make[1]: *** [all] Error 2
make[1]: Leaving directory `/usr/src/linux-headers-2.6.32-trunk-amd64'
make: *** [all] Error 2
At this point I'm wondering if I've bought an (admittedly cheap) lemon.
Undeterred, I took the somewhat blunt approach of commenting out the lines that GCC had complained about, and lo and behold, it builds!
Better than that, it loaded without crashing the machine and appeared to work as intended, and with a little bit of poking around on google and refering to the source of other usbnet drivers I was able to bring the driver (hopefully) in line with the current network device API.
diff -ru a/qf9700.c b/qf9700.c
--- a/qf9700.c 2010-10-09 09:50:52.000000000 +0100
+++ b/qf9700.c 2011-01-21 09:59:58.019399508 +0000
@@ -368,6 +368,17 @@
qf_write_async(dev, MAR, QF_MCAST_SIZE, hashes);
qf_write_reg_async(dev, RCR, rx_ctl);
}
+static const struct net_device_ops qf9700_netdev_ops = {
+ .ndo_open = usbnet_open,
+ .ndo_stop = usbnet_stop,
+ .ndo_start_xmit = usbnet_start_xmit,
+ .ndo_tx_timeout = usbnet_tx_timeout,
+ .ndo_change_mtu = usbnet_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_do_ioctl = qf9700_ioctl,
+ .ndo_set_multicast_list = qf9700_set_multicast,
+};
static int qf9700_bind(struct usbnet *dev, struct usb_interface *intf)
{
@@ -377,8 +388,7 @@
if (ret)
goto out;
- dev->net->do_ioctl = qf9700_ioctl;
- dev->net->set_multicast_list = qf9700_set_multicast;
+ dev->net->netdev_ops = &qf9700_netdev_ops;
dev->net->ethtool_ops = &qf9700_ethtool_ops;
dev->net->hard_header_len += QF_TX_OVERHEAD;
dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
@@ -440,11 +450,11 @@
len = (skb->data[1] | (skb->data[2] << 8)) - 4;
if (unlikely(status & 0xbf)) {
- if (status & 0x01) dev->stats.rx_fifo_errors++;
- if (status & 0x02) dev->stats.rx_crc_errors++;
- if (status & 0x04) dev->stats.rx_frame_errors++;
- if (status & 0x20) dev->stats.rx_missed_errors++;
- if (status & 0x90) dev->stats.rx_length_errors++;
+ if (status & 0x01) dev->net->stats.rx_fifo_errors++;
+ if (status & 0x02) dev->net->stats.rx_crc_errors++;
+ if (status & 0x04) dev->net->stats.rx_frame_errors++;
+ if (status & 0x20) dev->net->stats.rx_missed_errors++;
+ if (status & 0x90) dev->net->stats.rx_length_errors++;
return 0;
}
As it doesn't appear to have a home on the web anywhere I've dropped the original driver and my changes
here, should anyone else need it.