X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fnet%2Fusbnet.c;h=cca6e72cf2fab8e90998bc8108bda9bfd68bbf99;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=58b3cf13145c93dfad4c888e9efcca55cdaad271;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 58b3cf131..cca6e72cf 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -104,10 +104,18 @@ * 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 +#ifdef CONFIG_USB_DEBUG +# define DEBUG +#endif #include #include #include @@ -120,25 +128,15 @@ #include #include #include - - -// #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 - #include #include #include #include - #define DRIVER_VERSION "25-Aug-2003" + /*-------------------------------------------------------------------------*/ /* @@ -148,13 +146,8 @@ * 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) @@ -173,7 +166,7 @@ #define CONTROL_TIMEOUT_JIFFIES ((CONTROL_TIMEOUT_MS * HZ)/1000) // between wakeups -#define UNLINK_TIMEOUT_JIFFIES ((3 /*ms*/ * HZ)/1000) +#define UNLINK_TIMEOUT_MS 3 /*-------------------------------------------------------------------------*/ @@ -275,7 +268,7 @@ static const char driver_name [] = "usbnet"; /* use ethtool to change the level for any given device */ static int msg_level = 1; -MODULE_PARM (msg_level, "i"); +module_param (msg_level, int, 0); MODULE_PARM_DESC (msg_level, "Initial message level (default = 1)"); @@ -323,7 +316,7 @@ get_endpoints (struct usbnet *dev, struct usb_interface *intf) 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; @@ -461,6 +454,15 @@ static const struct driver_info an2720_info = { #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) { @@ -503,6 +505,30 @@ static void ax8817x_async_cmd_callback(struct urb *urb, struct pt_regs *regs) 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) { @@ -542,6 +568,7 @@ static void ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 i 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) { @@ -556,25 +583,24 @@ static void ax8817x_set_multicast(struct net_device *net) * 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; } @@ -606,7 +632,7 @@ static void ax8817x_mdio_write(struct net_device *netdev, int phy_id, int loc, i 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; @@ -626,7 +652,7 @@ void ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) } } -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; @@ -646,8 +672,8 @@ int ax8817x_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) 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; @@ -676,13 +702,6 @@ static void ax8817x_get_drvinfo (struct net_device *net, 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; @@ -702,7 +721,7 @@ static int ax8817x_set_settings(struct net_device *net, struct ethtool_cmd *cmd) 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, @@ -716,20 +735,41 @@ static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) { 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) { @@ -763,49 +803,37 @@ static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) 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, }; @@ -813,6 +841,7 @@ static const struct driver_info ax8817x_info = { 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, }; @@ -820,6 +849,7 @@ static const struct driver_info dlink_dub_e100_info = { 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, }; @@ -827,6 +857,7 @@ static const struct driver_info netgear_fa120_info = { static const struct driver_info hawking_uf200_info = { .description = "Hawking UF200 USB Ethernet", .bind = ax8817x_bind, + .unbind = ax8817x_unbind, .flags = FLAG_ETHER, .data = 0x001f1d1f, }; @@ -906,8 +937,8 @@ struct ether_desc { u8 iMACAddress; u32 bmEthernetStatistics; - u16 wMaxSegmentSize; - u16 wNumberMCFilters; + __le16 wMaxSegmentSize; + __le16 wNumberMCFilters; u8 bNumberPowerFilters; } __attribute__ ((packed)); @@ -928,8 +959,8 @@ static struct usb_driver usbnet_driver; */ 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; @@ -955,7 +986,7 @@ static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf) /* 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; @@ -1006,7 +1037,7 @@ static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *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); @@ -1025,7 +1056,7 @@ static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf) } /* 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); @@ -1043,7 +1074,7 @@ static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf) info->u->bLength); goto bad_desc; } - dev->net->mtu = cpu_to_le16p ( + dev->net->mtu = le16_to_cpup ( &info->ether->wMaxSegmentSize) - ETH_HLEN; /* because of Zaurus, we may be ignoring the host @@ -1093,7 +1124,7 @@ static void cdc_unbind (struct usbnet *dev, struct usb_interface *intf) /* 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) */ @@ -1101,7 +1132,7 @@ static void cdc_unbind (struct usbnet *dev, struct usb_interface *intf) /* 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; } } @@ -1142,10 +1173,13 @@ get_ethernet_addr (struct usbnet *dev, struct ether_desc *e) 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]); @@ -1163,6 +1197,7 @@ static int cdc_bind (struct usbnet *dev, struct usb_interface *intf) 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; } @@ -1644,7 +1679,7 @@ nc_vendor_write (struct usbnet *dev, u8 req, u8 regnum, u16 value) 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); } @@ -2087,7 +2122,7 @@ pl_vendor_req (struct usbnet *dev, u8 req, u8 val, u8 index) req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, val, index, - 0, 0, + NULL, 0, CONTROL_TIMEOUT_JIFFIES); } @@ -2421,7 +2456,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs) skb_put (skb, urb->actual_length); entry->state = rx_done; - entry->urb = 0; + entry->urb = NULL; switch (urb_status) { // success @@ -2465,7 +2500,7 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs) block: entry->state = rx_cleanup; entry->urb = urb; - urb = 0; + urb = NULL; break; // data overrun ... flush fifo? @@ -2556,11 +2591,10 @@ static int usbnet_stop (struct net_device *net) while (skb_queue_len (&dev->rxq) && skb_queue_len (&dev->txq) && skb_queue_len (&dev->done)) { - set_current_state (TASK_UNINTERRUPTIBLE); - schedule_timeout (UNLINK_TIMEOUT_JIFFIES); + msleep(UNLINK_TIMEOUT_MS); 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. @@ -2674,9 +2708,7 @@ static int usbnet_ioctl (struct net_device *net, struct ifreq *rq, int cmd) 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; @@ -2721,7 +2753,7 @@ kevent (void *data) /* 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); @@ -2776,7 +2808,7 @@ static void tx_complete (struct urb *urb, struct pt_regs *regs) } } - urb->dev = 0; + urb->dev = NULL; entry->state = tx_done; defer_bh (dev, skb); } @@ -2800,13 +2832,13 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) 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 @@ -3014,7 +3046,7 @@ static struct ethtool_ops usbnet_ethtool_ops; // precondition: never called in_interrupt -int +static int usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) { struct usbnet *dev; @@ -3204,10 +3236,22 @@ static const struct usb_device_id products [] = { // 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