* disconnect; other cleanups. (db) Flush net1080 fifos
* after several sequential framing errors. (Johannes Erdfelt)
* 22-aug-2003 AX8817X support (Dave Hollis).
+ * 14-jun-2004 Trivial patch for AX8817X based Buffalo LUA-U2-KTX in Japan
+ * (Neil Bortnak)
*
*-------------------------------------------------------------------------*/
+// #define DEBUG // error path messages, extra info
+// #define VERBOSE // more; success messages
+
#include <linux/config.h>
+#ifdef CONFIG_USB_DEBUG
+# define DEBUG
+#endif
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/sched.h>
#include <linux/mii.h>
#include <asm/uaccess.h>
#include <asm/unaligned.h>
-
-
-// #define DEBUG // error path messages, extra info
-// #define VERBOSE // more; success messages
-#define REALLY_QUEUE
-
-#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG)
-# define DEBUG
-#endif
#include <linux/usb.h>
-
#include <asm/io.h>
#include <asm/scatterlist.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
-
#define DRIVER_VERSION "25-Aug-2003"
+
/*-------------------------------------------------------------------------*/
/*
* For high speed, each frame comfortably fits almost 36 max size
* Ethernet packets (so queues should be bigger).
*/
-#ifdef REALLY_QUEUE
#define RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
#define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
-#else
-#define RX_QLEN(dev) 1
-#define TX_QLEN(dev) 1
-#endif
// packets are always ethernet inside
// ... except they can be bigger (limit of 64K with NetChip framing)
for (tmp = 0; tmp < intf->num_altsetting; tmp++) {
unsigned ep;
- in = out = 0;
+ in = out = NULL;
alt = intf->altsetting + tmp;
/* take the first altsetting with in-bulk + out-bulk;
#define AX_MCAST_FILTER_SIZE 8
#define AX_MAX_MCAST 64
+#define AX_INTERRUPT_BUFSIZE 8
+
+/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
+struct ax8817x_data {
+ u8 multi_filter[AX_MCAST_FILTER_SIZE];
+ struct urb *int_urb;
+ u8 *int_buf;
+};
+
static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
u16 size, void *data)
{
usb_free_urb(urb);
}
+static void ax8817x_interrupt_complete(struct urb *urb, struct pt_regs *regs)
+{
+ struct usbnet *dev = (struct usbnet *)urb->context;
+ struct ax8817x_data *data = (struct ax8817x_data *)&dev->data;
+ int link;
+
+ if (urb->status < 0) {
+ printk(KERN_DEBUG "ax8817x_interrupt_complete() failed with %d",
+ urb->status);
+ } else {
+ if (data->int_buf[5] == 0x90) {
+ link = data->int_buf[2] & 0x01;
+ if (netif_carrier_ok(dev->net) != link) {
+ if (link)
+ netif_carrier_on(dev->net);
+ else
+ netif_carrier_off(dev->net);
+ devdbg(dev, "ax8817x - Link Status is: %d", link);
+ }
+ }
+ usb_submit_urb(data->int_urb, GFP_KERNEL);
+ }
+}
+
static void ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
u16 size, void *data)
{
static void ax8817x_set_multicast(struct net_device *net)
{
struct usbnet *dev = (struct usbnet *) net->priv;
+ struct ax8817x_data *data = (struct ax8817x_data *)&dev->data;
u8 rx_ctl = 0x8c;
if (net->flags & IFF_PROMISC) {
* for our 8 byte filter buffer
* to avoid allocating memory that
* is tricky to free later */
- u8 *multi_filter = (u8 *)&dev->data;
struct dev_mc_list *mc_list = net->mc_list;
u32 crc_bits;
int i;
- memset(multi_filter, 0, AX_MCAST_FILTER_SIZE);
+ memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);
/* Build the multicast hash filter. */
for (i = 0; i < net->mc_count; i++) {
crc_bits =
ether_crc(ETH_ALEN,
mc_list->dmi_addr) >> 26;
- multi_filter[crc_bits >> 3] |=
+ data->multi_filter[crc_bits >> 3] |=
1 << (crc_bits & 7);
mc_list = mc_list->next;
}
ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
- AX_MCAST_FILTER_SIZE, multi_filter);
+ AX_MCAST_FILTER_SIZE, data->multi_filter);
rx_ctl |= 0x10;
}
ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf);
}
-void ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
+static void ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
{
struct usbnet *dev = (struct usbnet *)net->priv;
u8 opt;
}
}
-int ax8817x_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
+static int ax8817x_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
{
struct usbnet *dev = (struct usbnet *)net->priv;
u8 opt = 0;
return 0;
}
-int ax8817x_get_eeprom(struct net_device *net,
- struct ethtool_eeprom *eeprom, u8 *data)
+static int ax8817x_get_eeprom(struct net_device *net,
+ struct ethtool_eeprom *eeprom, u8 *data)
{
struct usbnet *dev = (struct usbnet *)net->priv;
u16 *ebuf = (u16 *)data;
info->eedump_len = 0x3e;
}
-static u32 ax8817x_get_link (struct net_device *net)
-{
- struct usbnet *dev = (struct usbnet *)net->priv;
-
- return (u32)mii_link_ok(&dev->mii);
-}
-
static int ax8817x_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
{
struct usbnet *dev = (struct usbnet *)net->priv;
devices that may be connected at the same time. */
static struct ethtool_ops ax8817x_ethtool_ops = {
.get_drvinfo = ax8817x_get_drvinfo,
- .get_link = ax8817x_get_link,
+ .get_link = ethtool_op_get_link,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_wol = ax8817x_get_wol,
{
int ret;
u8 buf[6];
- u16 *buf16 = (u16 *) buf;
int i;
unsigned long gpio_bits = dev->driver_info->data;
+ struct ax8817x_data *data = (struct ax8817x_data *)dev->data;
dev->in = usb_rcvbulkpipe(dev->udev, 3);
dev->out = usb_sndbulkpipe(dev->udev, 2);
+ // allocate irq urb
+ if ((data->int_urb = usb_alloc_urb (0, GFP_KERNEL)) == 0) {
+ dbg ("%s: cannot allocate interrupt URB",
+ dev->net->name);
+ return -ENOMEM;
+ }
+
+ if ((data->int_buf = kmalloc(AX_INTERRUPT_BUFSIZE, GFP_KERNEL)) == NULL) {
+ dbg ("%s: cannot allocate memory for interrupt buffer",
+ dev->net->name);
+ usb_free_urb(data->int_urb);
+ return -ENOMEM;
+ }
+ memset(data->int_buf, 0, AX_INTERRUPT_BUFSIZE);
+
+ usb_fill_int_urb (data->int_urb, dev->udev,
+ usb_rcvintpipe (dev->udev, 1),
+ data->int_buf, AX_INTERRUPT_BUFSIZE,
+ ax8817x_interrupt_complete, dev,
+ dev->udev->speed == USB_SPEED_HIGH ? 8 : 100);
+
/* Toggle the GPIOs in a manufacturer/model specific way */
for (i = 2; i >= 0; i--) {
if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS,
(gpio_bits >> (i * 8)) & 0xff, 0, 0,
buf)) < 0)
return ret;
- wait_ms(5);
+ msleep(5);
}
if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, buf)) < 0) {
dev->mii.reg_num_mask = 0x1f;
dev->mii.phy_id = buf[1];
- if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf)) < 0) {
- dbg("Failed to go to software MII mode: %02x", ret);
- return ret;
- }
-
- *buf16 = cpu_to_le16(BMCR_RESET);
- if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG,
- dev->mii.phy_id, MII_BMCR, 2, buf16)) < 0) {
- dbg("Failed to write MII reg - MII_BMCR: %02x", ret);
- return ret;
- }
+ dev->net->set_multicast_list = ax8817x_set_multicast;
+ dev->net->ethtool_ops = &ax8817x_ethtool_ops;
- /* Advertise that we can do full-duplex pause */
- *buf16 = cpu_to_le16(ADVERTISE_ALL | ADVERTISE_CSMA | 0x0400);
- if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG,
- dev->mii.phy_id, MII_ADVERTISE,
- 2, buf16)) < 0) {
- dbg("Failed to write MII_REG advertisement: %02x", ret);
- return ret;
- }
+ ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR,
+ cpu_to_le16(BMCR_RESET));
+ ax8817x_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ cpu_to_le16(ADVERTISE_ALL | ADVERTISE_CSMA | 0x0400));
+ mii_nway_restart(&dev->mii);
- *buf16 = cpu_to_le16(BMCR_ANENABLE | BMCR_ANRESTART);
- if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG,
- dev->mii.phy_id, MII_BMCR,
- 2, buf16)) < 0) {
- dbg("Failed to write MII reg autonegotiate: %02x", ret);
+ if((ret = usb_submit_urb(data->int_urb, GFP_KERNEL)) < 0) {
+ dbg("Failed to submit interrupt URB: %02x", ret);
+ usb_free_urb(data->int_urb);
return ret;
}
- if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf)) < 0) {
- dbg("Failed to set hardware MII: %02x", ret);
- return ret;
- }
+ return 0;
+}
- dev->net->set_multicast_list = ax8817x_set_multicast;
- dev->net->ethtool_ops = &ax8817x_ethtool_ops;
+static void ax8817x_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+ struct ax8817x_data *data = (struct ax8817x_data *)dev->data;
- return 0;
+ usb_unlink_urb(data->int_urb);
+ usb_free_urb(data->int_urb);
+ kfree(data->int_buf);
}
static const struct driver_info ax8817x_info = {
.description = "ASIX AX8817x USB 2.0 Ethernet",
.bind = ax8817x_bind,
+ .unbind = ax8817x_unbind,
.flags = FLAG_ETHER,
.data = 0x00130103,
};
static const struct driver_info dlink_dub_e100_info = {
.description = "DLink DUB-E100 USB Ethernet",
.bind = ax8817x_bind,
+ .unbind = ax8817x_unbind,
.flags = FLAG_ETHER,
.data = 0x009f9d9f,
};
static const struct driver_info netgear_fa120_info = {
.description = "Netgear FA-120 USB Ethernet",
.bind = ax8817x_bind,
+ .unbind = ax8817x_unbind,
.flags = FLAG_ETHER,
.data = 0x00130103,
};
static const struct driver_info hawking_uf200_info = {
.description = "Hawking UF200 USB Ethernet",
.bind = ax8817x_bind,
+ .unbind = ax8817x_unbind,
.flags = FLAG_ETHER,
.data = 0x001f1d1f,
};
*/
static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf)
{
- u8 *buf = intf->altsetting->extra;
- int len = intf->altsetting->extralen;
+ u8 *buf = intf->cur_altsetting->extra;
+ int len = intf->cur_altsetting->extralen;
struct usb_interface_descriptor *d;
struct cdc_state *info = (void *) &dev->data;
int status;
/* this assumes that if there's a non-RNDIS vendor variant
* of cdc-acm, it'll fail RNDIS requests cleanly.
*/
- rndis = (intf->altsetting->desc.bInterfaceProtocol == 0xff);
+ rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff);
memset (info, 0, sizeof *info);
info->control = intf;
if (!info->control || !info->data) {
dev_dbg (&intf->dev,
"master #%u/%p slave #%u/%p\n",
- info->u->bMasterInterface0
+ info->u->bMasterInterface0,
info->control,
info->u->bSlaveInterface0,
info->data);
}
/* a data interface altsetting does the real i/o */
- d = &info->data->altsetting->desc;
+ d = &info->data->cur_altsetting->desc;
if (d->bInterfaceClass != USB_CLASS_CDC_DATA) {
dev_dbg (&intf->dev, "slave class %u\n",
d->bInterfaceClass);
/* ensure immediate exit from usbnet_disconnect */
usb_set_intfdata(info->data, NULL);
usb_driver_release_interface (&usbnet_driver, info->data);
- info->data = 0;
+ info->data = NULL;
}
/* and vice versa (just in case) */
/* ensure immediate exit from usbnet_disconnect */
usb_set_intfdata(info->control, NULL);
usb_driver_release_interface (&usbnet_driver, info->control);
- info->control = 0;
+ info->control = NULL;
}
}
unsigned char buf [13];
tmp = usb_string (dev->udev, e->iMACAddress, buf, sizeof buf);
- if (tmp < 0)
+ if (tmp != 12) {
+ dev_dbg (&dev->udev->dev,
+ "bad MAC string %d fetch, %d\n", e->iMACAddress, tmp);
+ if (tmp >= 0)
+ tmp = -EINVAL;
return tmp;
- else if (tmp != 12)
- return -EINVAL;
+ }
for (i = tmp = 0; i < 6; i++, tmp += 2)
dev->net->dev_addr [i] =
(nibble (buf [tmp]) << 4) + nibble (buf [tmp + 1]);
status = get_ethernet_addr (dev, info->ether);
if (status < 0) {
+ usb_set_intfdata(info->data, NULL);
usb_driver_release_interface (&usbnet_driver, info->data);
return status;
}
req,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, regnum,
- 0, 0, // data is in setup packet
+ NULL, 0, // data is in setup packet
CONTROL_TIMEOUT_JIFFIES);
}
req,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
val, index,
- 0, 0,
+ NULL, 0,
CONTROL_TIMEOUT_JIFFIES);
}
skb_put (skb, urb->actual_length);
entry->state = rx_done;
- entry->urb = 0;
+ entry->urb = NULL;
switch (urb_status) {
// success
block:
entry->state = rx_cleanup;
entry->urb = urb;
- urb = 0;
+ urb = NULL;
break;
// data overrun ... flush fifo?
schedule_timeout (UNLINK_TIMEOUT_JIFFIES);
devdbg (dev, "waited for %d urb completions", temp);
}
- dev->wait = 0;
+ dev->wait = NULL;
remove_wait_queue (&unlink_wakeup, &wait);
/* deferred work (task, timer, softirq) must also stop.
struct usbnet *dev = (struct usbnet *)net->priv;
if (dev->mii.mdio_read != NULL && dev->mii.mdio_write != NULL)
- return generic_mii_ioctl(&dev->mii,
- (struct mii_ioctl_data *) &rq->ifr_data,
- cmd, NULL);
+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
}
#endif
return -EOPNOTSUPP;
/* tasklet could resubmit itself forever if memory is tight */
if (test_bit (EVENT_RX_MEMORY, &dev->flags)) {
- struct urb *urb = 0;
+ struct urb *urb = NULL;
if (netif_running (dev->net))
urb = usb_alloc_urb (0, GFP_KERNEL);
}
}
- urb->dev = 0;
+ urb->dev = NULL;
entry->state = tx_done;
defer_bh (dev, skb);
}
struct usbnet *dev = (struct usbnet *) net->priv;
int length;
int retval = NET_XMIT_SUCCESS;
- struct urb *urb = 0;
+ struct urb *urb = NULL;
struct skb_data *entry;
struct driver_info *info = dev->driver_info;
unsigned long flags;
#ifdef CONFIG_USB_NET1080
- struct nc_header *header = 0;
- struct nc_trailer *trailer = 0;
+ struct nc_header *header = NULL;
+ struct nc_trailer *trailer = NULL;
#endif /* CONFIG_USB_NET1080 */
// some devices want funky USB-level framing, for
// precondition: never called in_interrupt
-int
+static int
usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
{
struct usbnet *dev;
// Hawking UF200, TrendNet TU2-ET100
USB_DEVICE (0x07b8, 0x420a),
.driver_info = (unsigned long) &hawking_uf200_info,
+}, {
+ // Billionton Systems, USB2AR
+ USB_DEVICE (0x08dd, 0x90ff),
+ .driver_info = (unsigned long) &ax8817x_info,
}, {
// ATEN UC210T
USB_DEVICE (0x0557, 0x2009),
.driver_info = (unsigned long) &ax8817x_info,
+}, {
+ // Buffalo LUA-U2-KTX
+ USB_DEVICE (0x0411, 0x003d),
+ .driver_info = (unsigned long) &ax8817x_info,
+}, {
+ // Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter"
+ USB_DEVICE (0x6189, 0x182d),
+ .driver_info = (unsigned long) &ax8817x_info,
},
#endif