diff options
Diffstat (limited to 'drivers/net/usb')
29 files changed, 549 insertions, 271 deletions
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 5ee032cafade..3ae80eccd0ef 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -35,6 +35,7 @@ #include <linux/crc32.h> #include <linux/usb/usbnet.h> #include <linux/slab.h> +#include <linux/if_vlan.h> #define DRIVER_VERSION "22-Dec-2011" #define DRIVER_NAME "asix" @@ -321,7 +322,7 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) return 0; } - if ((size > dev->net->mtu + ETH_HLEN) || + if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) || (size + offset > skb->len)) { netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", size); @@ -355,7 +356,7 @@ static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, u32 packet_len; u32 padbytes = 0xffff0000; - padlen = ((skb->len + 4) % 512) ? 0 : 4; + padlen = ((skb->len + 4) & (dev->maxpacket - 1)) ? 0 : 4; if ((!skb_cloned(skb)) && ((headroom + tailroom) >= (4 + padlen))) { @@ -377,7 +378,7 @@ static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, cpu_to_le32s(&packet_len); skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); - if ((skb->len % 512) == 0) { + if (padlen) { cpu_to_le32s(&padbytes); memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); skb_put(skb, sizeof(padbytes)); @@ -1647,6 +1648,7 @@ static struct usb_driver asix_driver = { .resume = usbnet_resume, .disconnect = usbnet_disconnect, .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(asix_driver); diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index 182cfb4aeb1d..26c5bebd9eca 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -338,16 +338,18 @@ static void catc_irq_done(struct urb *urb) } else { catc->rx_urb->dev = catc->usbdev; if ((res = usb_submit_urb(catc->rx_urb, GFP_ATOMIC)) < 0) { - err("submit(rx_urb) status %d", res); + dev_err(&catc->usbdev->dev, + "submit(rx_urb) status %d\n", res); } } } resubmit: res = usb_submit_urb (urb, GFP_ATOMIC); if (res) - err ("can't resubmit intr, %s-%s, status %d", - catc->usbdev->bus->bus_name, - catc->usbdev->devpath, res); + dev_err(&catc->usbdev->dev, + "can't resubmit intr, %s-%s, status %d\n", + catc->usbdev->bus->bus_name, + catc->usbdev->devpath, res); } /* @@ -366,7 +368,8 @@ static int catc_tx_run(struct catc *catc) catc->tx_urb->dev = catc->usbdev; if ((status = usb_submit_urb(catc->tx_urb, GFP_ATOMIC)) < 0) - err("submit(tx_urb), status %d", status); + dev_err(&catc->usbdev->dev, "submit(tx_urb), status %d\n", + status); catc->tx_idx = !catc->tx_idx; catc->tx_ptr = 0; @@ -496,7 +499,8 @@ static void catc_ctrl_run(struct catc *catc) memcpy(catc->ctrl_buf, q->buf, q->len); if ((status = usb_submit_urb(catc->ctrl_urb, GFP_ATOMIC))) - err("submit(ctrl_urb) status %d", status); + dev_err(&catc->usbdev->dev, "submit(ctrl_urb) status %d\n", + status); } static void catc_ctrl_done(struct urb *urb) @@ -555,7 +559,7 @@ static int catc_ctrl_async(struct catc *catc, u8 dir, u8 request, u16 value, catc->ctrl_head = (catc->ctrl_head + 1) & (CTRL_QUEUE - 1); if (catc->ctrl_head == catc->ctrl_tail) { - err("ctrl queue full"); + dev_err(&catc->usbdev->dev, "ctrl queue full\n"); catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1); retval = -1; } @@ -714,7 +718,8 @@ static int catc_open(struct net_device *netdev) catc->irq_urb->dev = catc->usbdev; if ((status = usb_submit_urb(catc->irq_urb, GFP_KERNEL)) < 0) { - err("submit(irq_urb) status %d", status); + dev_err(&catc->usbdev->dev, "submit(irq_urb) status %d\n", + status); return -1; } @@ -769,7 +774,7 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id if (usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 1)) { - err("Can't set altsetting 1."); + dev_err(&intf->dev, "Can't set altsetting 1.\n"); return -EIO; } @@ -799,7 +804,7 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id catc->irq_urb = usb_alloc_urb(0, GFP_KERNEL); if ((!catc->ctrl_urb) || (!catc->tx_urb) || (!catc->rx_urb) || (!catc->irq_urb)) { - err("No free urbs available."); + dev_err(&intf->dev, "No free urbs available.\n"); usb_free_urb(catc->ctrl_urb); usb_free_urb(catc->tx_urb); usb_free_urb(catc->rx_urb); @@ -947,6 +952,7 @@ static struct usb_driver catc_driver = { .probe = catc_probe, .disconnect = catc_disconnect, .id_table = catc_id_table, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(catc_driver); diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c index 3e41b00c6806..d848d4dd5754 100644 --- a/drivers/net/usb/cdc-phonet.c +++ b/drivers/net/usb/cdc-phonet.c @@ -457,6 +457,7 @@ static struct usb_driver usbpn_driver = { .probe = usbpn_probe, .disconnect = usbpn_disconnect, .id_table = usbpn_ids, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(usbpn_driver); diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c index 685a4e22c768..434d5af8e6fb 100644 --- a/drivers/net/usb/cdc_eem.c +++ b/drivers/net/usb/cdc_eem.c @@ -368,6 +368,7 @@ static struct usb_driver eem_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(eem_driver); diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 90a30026a931..a03de7197049 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -83,6 +83,7 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) struct cdc_state *info = (void *) &dev->data; int status; int rndis; + bool android_rndis_quirk = false; struct usb_driver *driver = driver_of(intf); struct usb_cdc_mdlm_desc *desc = NULL; struct usb_cdc_mdlm_detail_desc *detail = NULL; @@ -195,6 +196,11 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) info->control, info->u->bSlaveInterface0, info->data); + /* fall back to hard-wiring for RNDIS */ + if (rndis) { + android_rndis_quirk = true; + goto next_desc; + } goto bad_desc; } if (info->control != intf) { @@ -271,11 +277,15 @@ next_desc: /* Microsoft ActiveSync based and some regular RNDIS devices lack the * CDC descriptors, so we'll hard-wire the interfaces and not check * for descriptors. + * + * Some Android RNDIS devices have a CDC Union descriptor pointing + * to non-existing interfaces. Ignore that and attempt the same + * hard-wired 0 and 1 interfaces. */ - if (rndis && !info->u) { + if (rndis && (!info->u || android_rndis_quirk)) { info->control = usb_ifnum_to_if(dev->udev, 0); info->data = usb_ifnum_to_if(dev->udev, 1); - if (!info->control || !info->data) { + if (!info->control || !info->data || info->control != intf) { dev_dbg(&intf->dev, "rndis: master #0/%p slave #1/%p\n", info->control, @@ -475,6 +485,8 @@ static const struct driver_info wwan_info = { /*-------------------------------------------------------------------------*/ #define HUAWEI_VENDOR_ID 0x12D1 +#define NOVATEL_VENDOR_ID 0x1410 +#define ZTE_VENDOR_ID 0x19D2 static const struct usb_device_id products [] = { /* @@ -592,6 +604,76 @@ static const struct usb_device_id products [] = { * because of bugs/quirks in a given product (like Zaurus, above). */ { + /* Novatel USB551L */ + /* This match must come *before* the generic CDC-ETHER match so that + * we get FLAG_WWAN set on the device, since it's descriptors are + * generic CDC-ETHER. + */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = NOVATEL_VENDOR_ID, + .idProduct = 0xB001, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .driver_info = (unsigned long)&wwan_info, +}, { + /* ZTE (Vodafone) K3805-Z */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = ZTE_VENDOR_ID, + .idProduct = 0x1003, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .driver_info = (unsigned long)&wwan_info, +}, { + /* ZTE (Vodafone) K3806-Z */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = ZTE_VENDOR_ID, + .idProduct = 0x1015, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .driver_info = (unsigned long)&wwan_info, +}, { + /* ZTE (Vodafone) K4510-Z */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = ZTE_VENDOR_ID, + .idProduct = 0x1173, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .driver_info = (unsigned long)&wwan_info, +}, { + /* ZTE (Vodafone) K3770-Z */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = ZTE_VENDOR_ID, + .idProduct = 0x1177, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .driver_info = (unsigned long)&wwan_info, +}, { + /* ZTE (Vodafone) K3772-Z */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_PRODUCT + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = ZTE_VENDOR_ID, + .idProduct = 0x1181, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = USB_CDC_PROTO_NONE, + .driver_info = (unsigned long)&wwan_info, +}, { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), .driver_info = (unsigned long) &cdc_info, @@ -623,6 +705,7 @@ static struct usb_driver cdc_driver = { .resume = usbnet_resume, .reset_resume = usbnet_resume, .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(cdc_driver); diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 7adc9f6b0ea1..4b9513fcf275 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1212,6 +1212,7 @@ static struct usb_driver cdc_ncm_driver = { .resume = usbnet_resume, .reset_resume = usbnet_resume, .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, }; static const struct ethtool_ops cdc_ncm_ethtool_ops = { diff --git a/drivers/net/usb/cdc_subset.c b/drivers/net/usb/cdc_subset.c index b403d934e4e3..0d1fe89ae0bd 100644 --- a/drivers/net/usb/cdc_subset.c +++ b/drivers/net/usb/cdc_subset.c @@ -336,6 +336,7 @@ static struct usb_driver cdc_subset_driver = { .resume = usbnet_resume, .disconnect = usbnet_disconnect, .id_table = products, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(cdc_subset_driver); diff --git a/drivers/net/usb/cx82310_eth.c b/drivers/net/usb/cx82310_eth.c index 0e0531356e62..49ab45e17fe8 100644 --- a/drivers/net/usb/cx82310_eth.c +++ b/drivers/net/usb/cx82310_eth.c @@ -327,6 +327,7 @@ static struct usb_driver cx82310_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(cx82310_driver); diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index b97226318ea5..e0433ce6ced7 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -670,6 +670,7 @@ static struct usb_driver dm9601_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(dm9601_driver); diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c index 38266bdae26b..db3c8021f2a3 100644 --- a/drivers/net/usb/gl620a.c +++ b/drivers/net/usb/gl620a.c @@ -225,6 +225,7 @@ static struct usb_driver gl620a_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(gl620a_driver); diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 2d2a6882ba33..62f30b46fa42 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -106,13 +106,6 @@ #define MAX_RX_URBS 2 -static inline struct hso_serial *get_serial_by_tty(struct tty_struct *tty) -{ - if (tty) - return tty->driver_data; - return NULL; -} - /*****************************************************************************/ /* Debugging functions */ /*****************************************************************************/ @@ -255,9 +248,8 @@ struct hso_serial { u8 dtr_state; unsigned tx_urb_used:1; + struct tty_port port; /* from usb_serial_port */ - struct tty_struct *tty; - int open_count; spinlock_t serial_lock; int (*write_data) (struct hso_serial *serial); @@ -1114,7 +1106,7 @@ static void hso_init_termios(struct ktermios *termios) static void _hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) { - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; struct ktermios *termios; if (!serial) { @@ -1190,7 +1182,7 @@ static void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial) struct urb *urb; urb = serial->rx_urb[0]; - if (serial->open_count > 0) { + if (serial->port.count > 0) { count = put_rxbuf_data(urb, serial); if (count == -1) return; @@ -1226,7 +1218,7 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb) DUMP1(urb->transfer_buffer, urb->actual_length); /* Anyone listening? */ - if (serial->open_count == 0) + if (serial->port.count == 0) return; if (status == 0) { @@ -1268,7 +1260,7 @@ static void hso_unthrottle_tasklet(struct hso_serial *serial) static void hso_unthrottle(struct tty_struct *tty) { - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; tasklet_hi_schedule(&serial->unthrottle_tasklet); } @@ -1304,15 +1296,12 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) kref_get(&serial->parent->ref); /* setup */ - spin_lock_irq(&serial->serial_lock); tty->driver_data = serial; - tty_kref_put(serial->tty); - serial->tty = tty_kref_get(tty); - spin_unlock_irq(&serial->serial_lock); + tty_port_tty_set(&serial->port, tty); /* check for port already opened, if not set the termios */ - serial->open_count++; - if (serial->open_count == 1) { + serial->port.count++; + if (serial->port.count == 1) { serial->rx_state = RX_IDLE; /* Force default termio settings */ _hso_serial_set_termios(tty, NULL); @@ -1324,7 +1313,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) result = hso_start_serial_device(serial->parent, GFP_KERNEL); if (result) { hso_stop_serial_device(serial->parent); - serial->open_count--; + serial->port.count--; kref_put(&serial->parent->ref, hso_serial_ref_free); } } else { @@ -1361,17 +1350,11 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp) /* reset the rts and dtr */ /* do the actual close */ - serial->open_count--; + serial->port.count--; - if (serial->open_count <= 0) { - serial->open_count = 0; - spin_lock_irq(&serial->serial_lock); - if (serial->tty == tty) { - serial->tty->driver_data = NULL; - serial->tty = NULL; - tty_kref_put(tty); - } - spin_unlock_irq(&serial->serial_lock); + if (serial->port.count <= 0) { + serial->port.count = 0; + tty_port_tty_set(&serial->port, NULL); if (!usb_gone) hso_stop_serial_device(serial->parent); tasklet_kill(&serial->unthrottle_tasklet); @@ -1390,7 +1373,7 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp) static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf, int count) { - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; int space, tx_bytes; unsigned long flags; @@ -1422,7 +1405,7 @@ out: /* how much room is there for writing */ static int hso_serial_write_room(struct tty_struct *tty) { - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; int room; unsigned long flags; @@ -1437,7 +1420,7 @@ static int hso_serial_write_room(struct tty_struct *tty) /* setup the term */ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) { - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; unsigned long flags; if (old) @@ -1446,7 +1429,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) /* the actual setup */ spin_lock_irqsave(&serial->serial_lock, flags); - if (serial->open_count) + if (serial->port.count) _hso_serial_set_termios(tty, old); else tty->termios = old; @@ -1458,7 +1441,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) /* how many characters in the buffer */ static int hso_serial_chars_in_buffer(struct tty_struct *tty) { - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; int chars; unsigned long flags; @@ -1629,7 +1612,7 @@ static int hso_get_count(struct tty_struct *tty, struct serial_icounter_struct *icount) { struct uart_icount cnow; - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; struct hso_tiocmget *tiocmget = serial->tiocmget; memset(icount, 0, sizeof(struct serial_icounter_struct)); @@ -1659,7 +1642,7 @@ static int hso_get_count(struct tty_struct *tty, static int hso_serial_tiocmget(struct tty_struct *tty) { int retval; - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; struct hso_tiocmget *tiocmget; u16 UART_state_bitmap; @@ -1693,7 +1676,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty, int val = 0; unsigned long flags; int if_num; - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; /* sanity check */ if (!serial) { @@ -1733,7 +1716,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty, static int hso_serial_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { - struct hso_serial *serial = get_serial_by_tty(tty); + struct hso_serial *serial = tty->driver_data; int ret = 0; D4("IOCTL cmd: %d, arg: %ld", cmd, arg); @@ -1905,7 +1888,7 @@ static void intr_callback(struct urb *urb) D1("Pending read interrupt on port %d\n", i); spin_lock(&serial->serial_lock); if (serial->rx_state == RX_IDLE && - serial->open_count > 0) { + serial->port.count > 0) { /* Setup and send a ctrl req read on * port i */ if (!serial->rx_urb_filled[0]) { @@ -1954,14 +1937,13 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb) spin_lock(&serial->serial_lock); serial->tx_urb_used = 0; - tty = tty_kref_get(serial->tty); spin_unlock(&serial->serial_lock); if (status) { handle_usb_error(status, __func__, serial->parent); - tty_kref_put(tty); return; } hso_put_activity(serial->parent); + tty = tty_port_tty_get(&serial->port); if (tty) { tty_wakeup(tty); tty_kref_put(tty); @@ -2001,7 +1983,6 @@ static void ctrl_callback(struct urb *urb) struct hso_serial *serial = urb->context; struct usb_ctrlrequest *req; int status = urb->status; - struct tty_struct *tty; /* sanity check */ if (!serial) @@ -2009,11 +1990,9 @@ static void ctrl_callback(struct urb *urb) spin_lock(&serial->serial_lock); serial->tx_urb_used = 0; - tty = tty_kref_get(serial->tty); spin_unlock(&serial->serial_lock); if (status) { handle_usb_error(status, __func__, serial->parent); - tty_kref_put(tty); return; } @@ -2031,13 +2010,15 @@ static void ctrl_callback(struct urb *urb) put_rxbuf_data_and_resubmit_ctrl_urb(serial); spin_unlock(&serial->serial_lock); } else { + struct tty_struct *tty = tty_port_tty_get(&serial->port); hso_put_activity(serial->parent); - if (tty) + if (tty) { tty_wakeup(tty); + tty_kref_put(tty); + } /* response to a write command */ hso_kick_transmit(serial); } - tty_kref_put(tty); } /* handle RX data for serial port */ @@ -2053,8 +2034,7 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) return -2; } - /* All callers to put_rxbuf_data hold serial_lock */ - tty = tty_kref_get(serial->tty); + tty = tty_port_tty_get(&serial->port); /* Push data to tty */ if (tty) { @@ -2074,12 +2054,12 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) write_length_remaining -= curr_write_len; tty_flip_buffer_push(tty); } + tty_kref_put(tty); } if (write_length_remaining == 0) { serial->curr_rx_urb_offset = 0; serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; } - tty_kref_put(tty); return write_length_remaining; } @@ -2320,6 +2300,7 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, serial->minor = minor; serial->magic = HSO_SERIAL_MAGIC; spin_lock_init(&serial->serial_lock); + tty_port_init(&serial->port); serial->num_rx_urbs = num_urbs; /* RX, allocate urb and initialize */ @@ -3098,7 +3079,7 @@ static int hso_resume(struct usb_interface *iface) /* Start all serial ports */ for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { if (serial_table[i] && (serial_table[i]->interface == iface)) { - if (dev2ser(serial_table[i])->open_count) { + if (dev2ser(serial_table[i])->port.count) { result = hso_start_serial_device(serial_table[i], GFP_NOIO); hso_kick_transmit(dev2ser(serial_table[i])); @@ -3172,13 +3153,12 @@ static void hso_free_interface(struct usb_interface *interface) if (serial_table[i] && (serial_table[i]->interface == interface)) { hso_dev = dev2ser(serial_table[i]); - spin_lock_irq(&hso_dev->serial_lock); - tty = tty_kref_get(hso_dev->tty); - spin_unlock_irq(&hso_dev->serial_lock); - if (tty) + tty = tty_port_tty_get(&hso_dev->port); + if (tty) { tty_hangup(tty); + tty_kref_put(tty); + } mutex_lock(&hso_dev->parent->mutex); - tty_kref_put(tty); hso_dev->parent->usb_gone = 1; mutex_unlock(&hso_dev->parent->mutex); kref_put(&serial_table[i]->ref, hso_serial_ref_free); @@ -3291,6 +3271,7 @@ static struct usb_driver hso_driver = { .resume = hso_resume, .reset_resume = hso_resume, .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, }; static int __init hso_init(void) @@ -3312,7 +3293,6 @@ static int __init hso_init(void) return -ENOMEM; /* fill in all needed values */ - tty_drv->magic = TTY_DRIVER_MAGIC; tty_drv->driver_name = driver_name; tty_drv->name = tty_filename; @@ -3333,7 +3313,7 @@ static int __init hso_init(void) if (result) { printk(KERN_ERR "%s - tty_register_driver failed(%d)\n", __func__, result); - return result; + goto err_free_tty; } /* register this module as an usb driver */ @@ -3341,13 +3321,16 @@ static int __init hso_init(void) if (result) { printk(KERN_ERR "Could not register hso driver? error: %d\n", result); - /* cleanup serial interface */ - tty_unregister_driver(tty_drv); - return result; + goto err_unreg_tty; } /* done */ return 0; +err_unreg_tty: + tty_unregister_driver(tty_drv); +err_free_tty: + put_tty_driver(tty_drv); + return result; } static void __exit hso_exit(void) @@ -3355,6 +3338,7 @@ static void __exit hso_exit(void) printk(KERN_INFO "hso: unloaded\n"); tty_unregister_driver(tty_drv); + put_tty_driver(tty_drv); /* deregister the usb driver */ usb_deregister(&hso_driver); } diff --git a/drivers/net/usb/int51x1.c b/drivers/net/usb/int51x1.c index 12a22a453ff1..8de641713d5f 100644 --- a/drivers/net/usb/int51x1.c +++ b/drivers/net/usb/int51x1.c @@ -236,6 +236,7 @@ static struct usb_driver int51x1_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(int51x1_driver); diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index dd78c4cbd459..a28a983d465e 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -59,6 +59,7 @@ #define USB_PRODUCT_IPHONE_3G 0x1292 #define USB_PRODUCT_IPHONE_3GS 0x1294 #define USB_PRODUCT_IPHONE_4 0x1297 +#define USB_PRODUCT_IPAD 0x129a #define USB_PRODUCT_IPHONE_4_VZW 0x129c #define USB_PRODUCT_IPHONE_4S 0x12a0 @@ -101,6 +102,10 @@ static struct usb_device_id ipheth_table[] = { IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, IPHETH_USBINTF_PROTO) }, { USB_DEVICE_AND_INTERFACE_INFO( + USB_VENDOR_APPLE, USB_PRODUCT_IPAD, + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, + IPHETH_USBINTF_PROTO) }, + { USB_DEVICE_AND_INTERFACE_INFO( USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4_VZW, IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, IPHETH_USBINTF_PROTO) }, @@ -209,7 +214,8 @@ static void ipheth_rcvbulk_callback(struct urb *urb) case 0: break; default: - err("%s: urb status: %d", __func__, status); + dev_err(&dev->intf->dev, "%s: urb status: %d\n", + __func__, status); return; } @@ -222,7 +228,8 @@ static void ipheth_rcvbulk_callback(struct urb *urb) skb = dev_alloc_skb(len); if (!skb) { - err("%s: dev_alloc_skb: -ENOMEM", __func__); + dev_err(&dev->intf->dev, "%s: dev_alloc_skb: -ENOMEM\n", + __func__); dev->net->stats.rx_dropped++; return; } @@ -251,7 +258,8 @@ static void ipheth_sndbulk_callback(struct urb *urb) status != -ENOENT && status != -ECONNRESET && status != -ESHUTDOWN) - err("%s: urb status: %d", __func__, status); + dev_err(&dev->intf->dev, "%s: urb status: %d\n", + __func__, status); dev_kfree_skb_irq(dev->tx_skb); netif_wake_queue(dev->net); @@ -271,7 +279,8 @@ static int ipheth_carrier_set(struct ipheth_device *dev) dev->ctrl_buf, IPHETH_CTRL_BUF_SIZE, IPHETH_CTRL_TIMEOUT); if (retval < 0) { - err("%s: usb_control_msg: %d", __func__, retval); + dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n", + __func__, retval); return retval; } @@ -308,9 +317,11 @@ static int ipheth_get_macaddr(struct ipheth_device *dev) IPHETH_CTRL_BUF_SIZE, IPHETH_CTRL_TIMEOUT); if (retval < 0) { - err("%s: usb_control_msg: %d", __func__, retval); + dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n", + __func__, retval); } else if (retval < ETH_ALEN) { - err("%s: usb_control_msg: short packet: %d bytes", + dev_err(&dev->intf->dev, + "%s: usb_control_msg: short packet: %d bytes\n", __func__, retval); retval = -EINVAL; } else { @@ -335,7 +346,8 @@ static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags) retval = usb_submit_urb(dev->rx_urb, mem_flags); if (retval) - err("%s: usb_submit_urb: %d", __func__, retval); + dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n", + __func__, retval); return retval; } @@ -396,7 +408,8 @@ static int ipheth_tx(struct sk_buff *skb, struct net_device *net) retval = usb_submit_urb(dev->tx_urb, GFP_ATOMIC); if (retval) { - err("%s: usb_submit_urb: %d", __func__, retval); + dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n", + __func__, retval); dev->net->stats.tx_errors++; dev_kfree_skb_irq(skb); } else { @@ -414,7 +427,7 @@ static void ipheth_tx_timeout(struct net_device *net) { struct ipheth_device *dev = netdev_priv(net); - err("%s: TX timeout", __func__); + dev_err(&dev->intf->dev, "%s: TX timeout\n", __func__); dev->net->stats.tx_errors++; usb_unlink_urb(dev->tx_urb); } @@ -464,7 +477,7 @@ static int ipheth_probe(struct usb_interface *intf, hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM); if (hintf == NULL) { retval = -ENODEV; - err("Unable to find alternate settings interface"); + dev_err(&intf->dev, "Unable to find alternate settings interface\n"); goto err_endpoints; } @@ -477,7 +490,7 @@ static int ipheth_probe(struct usb_interface *intf, } if (!(dev->bulk_in && dev->bulk_out)) { retval = -ENODEV; - err("Unable to find endpoints"); + dev_err(&intf->dev, "Unable to find endpoints\n"); goto err_endpoints; } @@ -495,7 +508,7 @@ static int ipheth_probe(struct usb_interface *intf, retval = ipheth_alloc_urbs(dev); if (retval) { - err("error allocating urbs: %d", retval); + dev_err(&intf->dev, "error allocating urbs: %d\n", retval); goto err_alloc_urbs; } @@ -506,7 +519,7 @@ static int ipheth_probe(struct usb_interface *intf, retval = register_netdev(netdev); if (retval) { - err("error registering netdev: %d", retval); + dev_err(&intf->dev, "error registering netdev: %d\n", retval); retval = -EIO; goto err_register_netdev; } @@ -546,6 +559,7 @@ static struct usb_driver ipheth_driver = { .probe = ipheth_probe, .disconnect = ipheth_disconnect, .id_table = ipheth_table, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(ipheth_driver); diff --git a/drivers/net/usb/kalmia.c b/drivers/net/usb/kalmia.c index 7562649b3d6b..92c49e0a59ec 100644 --- a/drivers/net/usb/kalmia.c +++ b/drivers/net/usb/kalmia.c @@ -372,7 +372,8 @@ static struct usb_driver kalmia_driver = { .probe = usbnet_probe, .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, - .resume = usbnet_resume + .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(kalmia_driver); diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index df2a2cf35a99..d8ad55284389 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -179,6 +179,7 @@ static struct usb_driver kaweth_driver = { .resume = kaweth_resume, .id_table = usb_klsi_table, .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, }; typedef __u8 eth_addr_t[6]; @@ -400,12 +401,13 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth, ret = request_firmware(&fw, fwname, &kaweth->dev->dev); if (ret) { - err("Firmware request failed\n"); + dev_err(&kaweth->intf->dev, "Firmware request failed\n"); return ret; } if (fw->size > KAWETH_FIRMWARE_BUF_SIZE) { - err("Firmware too big: %zu", fw->size); + dev_err(&kaweth->intf->dev, "Firmware too big: %zu\n", + fw->size); release_firmware(fw); return -ENOSPC; } @@ -501,9 +503,10 @@ static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, gfp_t mf) } if (status) - err ("can't resubmit intr, %s-%s, status %d", - kaweth->dev->bus->bus_name, - kaweth->dev->devpath, status); + dev_err(&kaweth->intf->dev, + "can't resubmit intr, %s-%s, status %d\n", + kaweth->dev->bus->bus_name, + kaweth->dev->devpath, status); } static void int_callback(struct urb *u) @@ -576,7 +579,8 @@ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, kaweth->suspend_lowmem_rx = 1; schedule_delayed_work(&kaweth->lowmem_work, HZ/4); } - err("resubmitting rx_urb %d failed", result); + dev_err(&kaweth->intf->dev, "resubmitting rx_urb %d failed\n", + result); } else { kaweth->suspend_lowmem_rx = 0; } @@ -634,20 +638,21 @@ static void kaweth_usb_receive(struct urb *urb) spin_unlock(&kaweth->device_lock); if(status && status != -EREMOTEIO && count != 1) { - err("%s RX status: %d count: %d packet_len: %d", - net->name, - status, - count, - (int)pkt_len); + dev_err(&kaweth->intf->dev, + "%s RX status: %d count: %d packet_len: %d\n", + net->name, status, count, (int)pkt_len); kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); return; } if(kaweth->net && (count > 2)) { if(pkt_len > (count - 2)) { - err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count); - err("Packet len & 2047: %x", pkt_len & 2047); - err("Count 2: %x", count2); + dev_err(&kaweth->intf->dev, + "Packet length too long for USB frame (pkt_len: %x, count: %x)\n", + pkt_len, count); + dev_err(&kaweth->intf->dev, "Packet len & 2047: %x\n", + pkt_len & 2047); + dev_err(&kaweth->intf->dev, "Count 2: %x\n", count2); kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); return; } @@ -686,7 +691,7 @@ static int kaweth_open(struct net_device *net) res = usb_autopm_get_interface(kaweth->intf); if (res) { - err("Interface cannot be resumed."); + dev_err(&kaweth->intf->dev, "Interface cannot be resumed.\n"); return -EIO; } res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL); @@ -907,7 +912,8 @@ static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth) KAWETH_CONTROL_TIMEOUT); if(result < 0) { - err("Failed to set Rx mode: %d", result); + dev_err(&kaweth->intf->dev, "Failed to set Rx mode: %d\n", + result); } else { dbg("Set Rx mode to %d", packet_filter_bitmap); @@ -1045,7 +1051,8 @@ static int kaweth_probe( "kaweth/new_code.bin", 100, 2)) < 0) { - err("Error downloading firmware (%d)", result); + dev_err(&intf->dev, "Error downloading firmware (%d)\n", + result); goto err_fw; } @@ -1053,7 +1060,9 @@ static int kaweth_probe( "kaweth/new_code_fix.bin", 100, 3)) < 0) { - err("Error downloading firmware fix (%d)", result); + dev_err(&intf->dev, + "Error downloading firmware fix (%d)\n", + result); goto err_fw; } @@ -1061,7 +1070,9 @@ static int kaweth_probe( "kaweth/trigger_code.bin", 126, 2)) < 0) { - err("Error downloading trigger code (%d)", result); + dev_err(&intf->dev, + "Error downloading trigger code (%d)\n", + result); goto err_fw; } @@ -1070,13 +1081,14 @@ static int kaweth_probe( "kaweth/trigger_code_fix.bin", 126, 3)) < 0) { - err("Error downloading trigger code fix (%d)", result); + dev_err(&intf->dev, "Error downloading trigger code fix (%d)\n", result); goto err_fw; } if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) { - err("Error triggering firmware (%d)", result); + dev_err(&intf->dev, "Error triggering firmware (%d)\n", + result); goto err_fw; } @@ -1091,7 +1103,7 @@ err_fw: result = kaweth_read_configuration(kaweth); if(result < 0) { - err("Error reading configuration (%d), no net device created", result); + dev_err(&intf->dev, "Error reading configuration (%d), no net device created\n", result); goto err_free_netdev; } @@ -1103,7 +1115,7 @@ err_fw: if(!memcmp(&kaweth->configuration.hw_addr, &bcast_addr, sizeof(bcast_addr))) { - err("Firmware not functioning properly, no net device created"); + dev_err(&intf->dev, "Firmware not functioning properly, no net device created\n"); goto err_free_netdev; } @@ -1113,7 +1125,7 @@ err_fw: } if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) { - err("Error setting SOFS wait"); + dev_err(&intf->dev, "Error setting SOFS wait\n"); goto err_free_netdev; } @@ -1123,7 +1135,7 @@ err_fw: KAWETH_PACKET_FILTER_MULTICAST); if(result < 0) { - err("Error setting receive filter"); + dev_err(&intf->dev, "Error setting receive filter\n"); goto err_free_netdev; } @@ -1175,7 +1187,7 @@ err_fw: SET_NETDEV_DEV(netdev, &intf->dev); if (register_netdev(netdev) != 0) { - err("Error registering netdev."); + dev_err(&intf->dev, "Error registering netdev.\n"); goto err_intfdata; } diff --git a/drivers/net/usb/lg-vl600.c b/drivers/net/usb/lg-vl600.c index 45a981fde43f..808d6506da41 100644 --- a/drivers/net/usb/lg-vl600.c +++ b/drivers/net/usb/lg-vl600.c @@ -344,6 +344,7 @@ static struct usb_driver lg_vl600_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(lg_vl600_driver); diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index c434b6ba0337..03c2d8d653df 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -629,11 +629,31 @@ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb) return skb->len > 0; } +static void mcs7830_status(struct usbnet *dev, struct urb *urb) +{ + u8 *buf = urb->transfer_buffer; + bool link; + + if (urb->actual_length < 16) + return; + + link = !(buf[1] & 0x20); + if (netif_carrier_ok(dev->net) != link) { + if (link) { + netif_carrier_on(dev->net); + usbnet_defer_kevent(dev, EVENT_LINK_RESET); + } else + netif_carrier_off(dev->net); + netdev_dbg(dev->net, "Link Status is: %d\n", link); + } +} + static const struct driver_info moschip_info = { .description = "MOSCHIP 7830/7832/7730 usb-NET adapter", .bind = mcs7830_bind, .rx_fixup = mcs7830_rx_fixup, - .flags = FLAG_ETHER, + .flags = FLAG_ETHER | FLAG_LINK_INTR, + .status = mcs7830_status, .in = 1, .out = 2, }; @@ -642,7 +662,8 @@ static const struct driver_info sitecom_info = { .description = "Sitecom LN-30 usb-NET adapter", .bind = mcs7830_bind, .rx_fixup = mcs7830_rx_fixup, - .flags = FLAG_ETHER, + .flags = FLAG_ETHER | FLAG_LINK_INTR, + .status = mcs7830_status, .in = 1, .out = 2, }; @@ -690,6 +711,7 @@ static struct usb_driver mcs7830_driver = { .suspend = usbnet_suspend, .resume = usbnet_resume, .reset_resume = mcs7830_reset_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(mcs7830_driver); diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c index 83f965cb69e7..28c4d513ba85 100644 --- a/drivers/net/usb/net1080.c +++ b/drivers/net/usb/net1080.c @@ -587,6 +587,7 @@ static struct usb_driver net1080_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(net1080_driver); diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 752393092325..7023220456c5 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -1489,6 +1489,7 @@ static struct usb_driver pegasus_driver = { .id_table = pegasus_ids, .suspend = pegasus_suspend, .resume = pegasus_resume, + .disable_hub_initiated_lpm = 1, }; static void __init parse_id(char *id) diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c index b2b035e29978..4584b9a805b3 100644 --- a/drivers/net/usb/plusb.c +++ b/drivers/net/usb/plusb.c @@ -152,6 +152,7 @@ static struct usb_driver plusb_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(plusb_driver); diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 552d24bf862e..3767a1225860 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -257,29 +257,6 @@ err: return rv; } -/* Gobi devices uses identical class/protocol codes for all interfaces regardless - * of function. Some of these are CDC ACM like and have the exact same endpoints - * we are looking for. This leaves two possible strategies for identifying the - * correct interface: - * a) hardcoding interface number, or - * b) use the fact that the wwan interface is the only one lacking additional - * (CDC functional) descriptors - * - * Let's see if we can get away with the generic b) solution. - */ -static int qmi_wwan_bind_gobi(struct usbnet *dev, struct usb_interface *intf) -{ - int rv = -EINVAL; - - /* ignore any interface with additional descriptors */ - if (intf->cur_altsetting->extralen) - goto err; - - rv = qmi_wwan_bind_shared(dev, intf); -err: - return rv; -} - static void qmi_wwan_unbind_shared(struct usbnet *dev, struct usb_interface *intf) { struct usb_driver *subdriver = (void *)dev->data[0]; @@ -347,29 +324,75 @@ static const struct driver_info qmi_wwan_shared = { .manage_power = qmi_wwan_manage_power, }; -static const struct driver_info qmi_wwan_gobi = { - .description = "Qualcomm Gobi wwan/QMI device", +static const struct driver_info qmi_wwan_force_int0 = { + .description = "Qualcomm WWAN/QMI device", + .flags = FLAG_WWAN, + .bind = qmi_wwan_bind_shared, + .unbind = qmi_wwan_unbind_shared, + .manage_power = qmi_wwan_manage_power, + .data = BIT(0), /* interface whitelist bitmap */ +}; + +static const struct driver_info qmi_wwan_force_int1 = { + .description = "Qualcomm WWAN/QMI device", + .flags = FLAG_WWAN, + .bind = qmi_wwan_bind_shared, + .unbind = qmi_wwan_unbind_shared, + .manage_power = qmi_wwan_manage_power, + .data = BIT(1), /* interface whitelist bitmap */ +}; + +static const struct driver_info qmi_wwan_force_int3 = { + .description = "Qualcomm WWAN/QMI device", .flags = FLAG_WWAN, - .bind = qmi_wwan_bind_gobi, + .bind = qmi_wwan_bind_shared, .unbind = qmi_wwan_unbind_shared, .manage_power = qmi_wwan_manage_power, + .data = BIT(3), /* interface whitelist bitmap */ }; -/* ZTE suck at making USB descriptors */ static const struct driver_info qmi_wwan_force_int4 = { - .description = "Qualcomm Gobi wwan/QMI device", + .description = "Qualcomm WWAN/QMI device", .flags = FLAG_WWAN, - .bind = qmi_wwan_bind_gobi, + .bind = qmi_wwan_bind_shared, .unbind = qmi_wwan_unbind_shared, .manage_power = qmi_wwan_manage_power, .data = BIT(4), /* interface whitelist bitmap */ }; +/* Sierra Wireless provide equally useless interface descriptors + * Devices in QMI mode can be switched between two different + * configurations: + * a) USB interface #8 is QMI/wwan + * b) USB interfaces #8, #19 and #20 are QMI/wwan + * + * Both configurations provide a number of other interfaces (serial++), + * some of which have the same endpoint configuration as we expect, so + * a whitelist or blacklist is necessary. + * + * FIXME: The below whitelist should include BIT(20). It does not + * because I cannot get it to work... + */ +static const struct driver_info qmi_wwan_sierra = { + .description = "Sierra Wireless wwan/QMI device", + .flags = FLAG_WWAN, + .bind = qmi_wwan_bind_shared, + .unbind = qmi_wwan_unbind_shared, + .manage_power = qmi_wwan_manage_power, + .data = BIT(8) | BIT(19), /* interface whitelist bitmap */ +}; #define HUAWEI_VENDOR_ID 0x12D1 + +/* Gobi 1000 QMI/wwan interface number is 3 according to qcserial */ +#define QMI_GOBI1K_DEVICE(vend, prod) \ + USB_DEVICE(vend, prod), \ + .driver_info = (unsigned long)&qmi_wwan_force_int3 + +/* Gobi 2000 and Gobi 3000 QMI/wwan interface number is 0 according to qcserial */ #define QMI_GOBI_DEVICE(vend, prod) \ USB_DEVICE(vend, prod), \ - .driver_info = (unsigned long)&qmi_wwan_gobi + .driver_info = (unsigned long)&qmi_wwan_force_int0 static const struct usb_device_id products[] = { { /* Huawei E392, E398 and possibly others sharing both device id and more... */ @@ -380,6 +403,14 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 8, /* NOTE: This is the *slave* interface of the CDC Union! */ .driver_info = (unsigned long)&qmi_wwan_info, }, + { /* Vodafone/Huawei K5005 (12d1:14c8) and similar modems */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = HUAWEI_VENDOR_ID, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 56, /* NOTE: This is the *slave* interface of the CDC Union! */ + .driver_info = (unsigned long)&qmi_wwan_info, + }, { /* Huawei E392, E398 and possibly others in "Windows mode" * using a combined control and data interface without any CDC * functional descriptors @@ -409,6 +440,15 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 0xff, .driver_info = (unsigned long)&qmi_wwan_force_int4, }, + { /* ZTE (Vodafone) K3520-Z */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x19d2, + .idProduct = 0x0055, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_force_int1, + }, { /* ZTE (Vodafone) K3565-Z */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x19d2, @@ -436,6 +476,15 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 0xff, .driver_info = (unsigned long)&qmi_wwan_force_int4, }, + { /* ZTE (Vodafone) K3765-Z */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x19d2, + .idProduct = 0x2002, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_force_int4, + }, { /* ZTE (Vodafone) K4505-Z */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x19d2, @@ -445,20 +494,33 @@ static const struct usb_device_id products[] = { .bInterfaceProtocol = 0xff, .driver_info = (unsigned long)&qmi_wwan_force_int4, }, - {QMI_GOBI_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ - {QMI_GOBI_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ - {QMI_GOBI_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */ - {QMI_GOBI_DEVICE(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */ - {QMI_GOBI_DEVICE(0x413c, 0x8172)}, /* Dell Gobi Modem device */ - {QMI_GOBI_DEVICE(0x1410, 0xa001)}, /* Novatel Gobi Modem device */ - {QMI_GOBI_DEVICE(0x0b05, 0x1776)}, /* Asus Gobi Modem device */ - {QMI_GOBI_DEVICE(0x19d2, 0xfff3)}, /* ONDA Gobi Modem device */ - {QMI_GOBI_DEVICE(0x05c6, 0x9001)}, /* Generic Gobi Modem device */ - {QMI_GOBI_DEVICE(0x05c6, 0x9002)}, /* Generic Gobi Modem device */ - {QMI_GOBI_DEVICE(0x05c6, 0x9202)}, /* Generic Gobi Modem device */ - {QMI_GOBI_DEVICE(0x05c6, 0x9203)}, /* Generic Gobi Modem device */ - {QMI_GOBI_DEVICE(0x05c6, 0x9222)}, /* Generic Gobi Modem device */ - {QMI_GOBI_DEVICE(0x05c6, 0x9009)}, /* Generic Gobi Modem device */ + { /* Sierra Wireless MC77xx in QMI mode */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x1199, + .idProduct = 0x68a2, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0xff, + .driver_info = (unsigned long)&qmi_wwan_sierra, + }, + + /* Gobi 1000 devices */ + {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ + {QMI_GOBI1K_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ + {QMI_GOBI1K_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */ + {QMI_GOBI1K_DEVICE(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x413c, 0x8172)}, /* Dell Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x1410, 0xa001)}, /* Novatel Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x0b05, 0x1776)}, /* Asus Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x19d2, 0xfff3)}, /* ONDA Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x05c6, 0x9001)}, /* Generic Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x05c6, 0x9002)}, /* Generic Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x05c6, 0x9202)}, /* Generic Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x05c6, 0x9203)}, /* Generic Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x05c6, 0x9222)}, /* Generic Gobi Modem device */ + {QMI_GOBI1K_DEVICE(0x05c6, 0x9009)}, /* Generic Gobi Modem device */ + + /* Gobi 2000 and 3000 devices */ {QMI_GOBI_DEVICE(0x413c, 0x8186)}, /* Dell Gobi 2000 Modem device (N0218, VU936) */ {QMI_GOBI_DEVICE(0x05c6, 0x920b)}, /* Generic Gobi 2000 Modem device */ {QMI_GOBI_DEVICE(0x05c6, 0x9225)}, /* Sony Gobi 2000 Modem device (N0279, VU730) */ @@ -482,6 +544,8 @@ static const struct usb_device_id products[] = { {QMI_GOBI_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */ {QMI_GOBI_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */ {QMI_GOBI_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */ + {QMI_GOBI_DEVICE(0x1199, 0x9015)}, /* Sierra Wireless Gobi 3000 Modem device */ + {QMI_GOBI_DEVICE(0x1199, 0x9019)}, /* Sierra Wireless Gobi 3000 Modem device */ { } /* END */ }; MODULE_DEVICE_TABLE(usb, products); @@ -495,6 +559,7 @@ static struct usb_driver qmi_wwan_driver = { .resume = qmi_wwan_resume, .reset_resume = qmi_wwan_resume, .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, }; static int __init qmi_wwan_init(void) diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index c8f1b5b3aff3..4a4335833c36 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -77,7 +77,9 @@ static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg, if (dev->driver_info->indication) { dev->driver_info->indication(dev, msg, buflen); } else { - switch (msg->status) { + u32 status = le32_to_cpu(msg->status); + + switch (status) { case RNDIS_STATUS_MEDIA_CONNECT: dev_info(udev, "rndis media connect\n"); break; @@ -85,8 +87,7 @@ static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg, dev_info(udev, "rndis media disconnect\n"); break; default: - dev_info(udev, "rndis indication: 0x%08x\n", - le32_to_cpu(msg->status)); + dev_info(udev, "rndis indication: 0x%08x\n", status); } } } @@ -109,16 +110,17 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) int retval; int partial; unsigned count; - __le32 rsp; - u32 xid = 0, msg_len, request_id; + u32 xid = 0, msg_len, request_id, msg_type, rsp, + status; /* REVISIT when this gets called from contexts other than probe() or * disconnect(): either serialize, or dispatch responses on xid */ + msg_type = le32_to_cpu(buf->msg_type); + /* Issue the request; xid is unique, don't bother byteswapping it */ - if (likely(buf->msg_type != RNDIS_MSG_HALT && - buf->msg_type != RNDIS_MSG_RESET)) { + if (likely(msg_type != RNDIS_MSG_HALT && msg_type != RNDIS_MSG_RESET)) { xid = dev->xid++; if (!xid) xid = dev->xid++; @@ -149,7 +151,7 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) } /* Poll the control channel; the request probably completed immediately */ - rsp = buf->msg_type | RNDIS_MSG_COMPLETION; + rsp = le32_to_cpu(buf->msg_type) | RNDIS_MSG_COMPLETION; for (count = 0; count < 10; count++) { memset(buf, 0, CONTROL_BUFFER_SIZE); retval = usb_control_msg(dev->udev, @@ -160,35 +162,36 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) buf, buflen, RNDIS_CONTROL_TIMEOUT_MS); if (likely(retval >= 8)) { + msg_type = le32_to_cpu(buf->msg_type); msg_len = le32_to_cpu(buf->msg_len); + status = le32_to_cpu(buf->status); request_id = (__force u32) buf->request_id; - if (likely(buf->msg_type == rsp)) { + if (likely(msg_type == rsp)) { if (likely(request_id == xid)) { if (unlikely(rsp == RNDIS_MSG_RESET_C)) return 0; - if (likely(RNDIS_STATUS_SUCCESS - == buf->status)) + if (likely(RNDIS_STATUS_SUCCESS == + status)) return 0; dev_dbg(&info->control->dev, "rndis reply status %08x\n", - le32_to_cpu(buf->status)); + status); return -EL3RST; } dev_dbg(&info->control->dev, "rndis reply id %d expected %d\n", request_id, xid); /* then likely retry */ - } else switch (buf->msg_type) { - case RNDIS_MSG_INDICATE: /* fault/event */ + } else switch (msg_type) { + case RNDIS_MSG_INDICATE: /* fault/event */ rndis_msg_indicate(dev, (void *)buf, buflen); - break; - case RNDIS_MSG_KEEPALIVE: { /* ping */ + case RNDIS_MSG_KEEPALIVE: { /* ping */ struct rndis_keepalive_c *msg = (void *)buf; - msg->msg_type = RNDIS_MSG_KEEPALIVE_C; + msg->msg_type = cpu_to_le32(RNDIS_MSG_KEEPALIVE_C); msg->msg_len = cpu_to_le32(sizeof *msg); - msg->status = RNDIS_STATUS_SUCCESS; + msg->status = cpu_to_le32(RNDIS_STATUS_SUCCESS); retval = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), USB_CDC_SEND_ENCAPSULATED_COMMAND, @@ -236,7 +239,7 @@ EXPORT_SYMBOL_GPL(rndis_command); * ActiveSync 4.1 Windows driver. */ static int rndis_query(struct usbnet *dev, struct usb_interface *intf, - void *buf, __le32 oid, u32 in_len, + void *buf, u32 oid, u32 in_len, void **reply, int *reply_len) { int retval; @@ -251,9 +254,9 @@ static int rndis_query(struct usbnet *dev, struct usb_interface *intf, u.buf = buf; memset(u.get, 0, sizeof *u.get + in_len); - u.get->msg_type = RNDIS_MSG_QUERY; + u.get->msg_type = cpu_to_le32(RNDIS_MSG_QUERY); u.get->msg_len = cpu_to_le32(sizeof *u.get + in_len); - u.get->oid = oid; + u.get->oid = cpu_to_le32(oid); u.get->len = cpu_to_le32(in_len); u.get->offset = cpu_to_le32(20); @@ -324,7 +327,7 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) if (retval < 0) goto fail; - u.init->msg_type = RNDIS_MSG_INIT; + u.init->msg_type = cpu_to_le32(RNDIS_MSG_INIT); u.init->msg_len = cpu_to_le32(sizeof *u.init); u.init->major_version = cpu_to_le32(1); u.init->minor_version = cpu_to_le32(0); @@ -395,22 +398,23 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) /* Check physical medium */ phym = NULL; reply_len = sizeof *phym; - retval = rndis_query(dev, intf, u.buf, OID_GEN_PHYSICAL_MEDIUM, - 0, (void **) &phym, &reply_len); + retval = rndis_query(dev, intf, u.buf, + RNDIS_OID_GEN_PHYSICAL_MEDIUM, + 0, (void **) &phym, &reply_len); if (retval != 0 || !phym) { /* OID is optional so don't fail here. */ - phym_unspec = RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED; + phym_unspec = cpu_to_le32(RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED); phym = &phym_unspec; } if ((flags & FLAG_RNDIS_PHYM_WIRELESS) && - *phym != RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { + le32_to_cpup(phym) != RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { netif_dbg(dev, probe, dev->net, "driver requires wireless physical medium, but device is not\n"); retval = -ENODEV; goto halt_fail_and_release; } if ((flags & FLAG_RNDIS_PHYM_NOT_WIRELESS) && - *phym == RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { + le32_to_cpup(phym) == RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { netif_dbg(dev, probe, dev->net, "driver requires non-wireless physical medium, but device is wireless.\n"); retval = -ENODEV; @@ -419,8 +423,9 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) /* Get designated host ethernet address */ reply_len = ETH_ALEN; - retval = rndis_query(dev, intf, u.buf, OID_802_3_PERMANENT_ADDRESS, - 48, (void **) &bp, &reply_len); + retval = rndis_query(dev, intf, u.buf, + RNDIS_OID_802_3_PERMANENT_ADDRESS, + 48, (void **) &bp, &reply_len); if (unlikely(retval< 0)) { dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval); goto halt_fail_and_release; @@ -430,12 +435,12 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) /* set a nonzero filter to enable data transfers */ memset(u.set, 0, sizeof *u.set); - u.set->msg_type = RNDIS_MSG_SET; + u.set->msg_type = cpu_to_le32(RNDIS_MSG_SET); u.set->msg_len = cpu_to_le32(4 + sizeof *u.set); - u.set->oid = OID_GEN_CURRENT_PACKET_FILTER; + u.set->oid = cpu_to_le32(RNDIS_OID_GEN_CURRENT_PACKET_FILTER); u.set->len = cpu_to_le32(4); u.set->offset = cpu_to_le32((sizeof *u.set) - 8); - *(__le32 *)(u.buf + sizeof *u.set) = RNDIS_DEFAULT_FILTER; + *(__le32 *)(u.buf + sizeof *u.set) = cpu_to_le32(RNDIS_DEFAULT_FILTER); retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE); if (unlikely(retval < 0)) { @@ -450,7 +455,7 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) halt_fail_and_release: memset(u.halt, 0, sizeof *u.halt); - u.halt->msg_type = RNDIS_MSG_HALT; + u.halt->msg_type = cpu_to_le32(RNDIS_MSG_HALT); u.halt->msg_len = cpu_to_le32(sizeof *u.halt); (void) rndis_command(dev, (void *)u.halt, CONTROL_BUFFER_SIZE); fail_and_release: @@ -475,7 +480,7 @@ void rndis_unbind(struct usbnet *dev, struct usb_interface *intf) /* try to clear any rndis state/activity (no i/o from stack!) */ halt = kzalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL); if (halt) { - halt->msg_type = RNDIS_MSG_HALT; + halt->msg_type = cpu_to_le32(RNDIS_MSG_HALT); halt->msg_len = cpu_to_le32(sizeof *halt); (void) rndis_command(dev, (void *)halt, CONTROL_BUFFER_SIZE); kfree(halt); @@ -494,16 +499,16 @@ int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb) while (likely(skb->len)) { struct rndis_data_hdr *hdr = (void *)skb->data; struct sk_buff *skb2; - u32 msg_len, data_offset, data_len; + u32 msg_type, msg_len, data_offset, data_len; + msg_type = le32_to_cpu(hdr->msg_type); msg_len = le32_to_cpu(hdr->msg_len); data_offset = le32_to_cpu(hdr->data_offset); data_len = le32_to_cpu(hdr->data_len); /* don't choke if we see oob, per-packet data, etc */ - if (unlikely(hdr->msg_type != RNDIS_MSG_PACKET || - skb->len < msg_len || - (data_offset + data_len + 8) > msg_len)) { + if (unlikely(msg_type != RNDIS_MSG_PACKET || skb->len < msg_len + || (data_offset + data_len + 8) > msg_len)) { dev->net->stats.rx_frame_errors++; netdev_dbg(dev->net, "bad rndis message %d/%d/%d/%d, len %d\n", le32_to_cpu(hdr->msg_type), @@ -569,7 +574,7 @@ rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) fill: hdr = (void *) __skb_push(skb, sizeof *hdr); memset(hdr, 0, sizeof *hdr); - hdr->msg_type = RNDIS_MSG_PACKET; + hdr->msg_type = cpu_to_le32(RNDIS_MSG_PACKET); hdr->msg_len = cpu_to_le32(skb->len); hdr->data_offset = cpu_to_le32(sizeof(*hdr) - 8); hdr->data_len = cpu_to_le32(len); @@ -633,6 +638,7 @@ static struct usb_driver rndis_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(rndis_driver); diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index d363b31053da..0e2c92e0e532 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -203,7 +203,8 @@ static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size) if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC))) { if (ret == -ENODEV) netif_device_detach(dev->netdev); - err("control request submission failed: %d", ret); + dev_err(&dev->udev->dev, + "control request submission failed: %d\n", ret); } else set_bit(RX_REG_SET, &dev->flags); @@ -516,9 +517,9 @@ resubmit: if (res == -ENODEV) netif_device_detach(dev->netdev); else if (res) - err ("can't resubmit intr, %s-%s/input0, status %d", - dev->udev->bus->bus_name, - dev->udev->devpath, res); + dev_err(&dev->udev->dev, + "can't resubmit intr, %s-%s/input0, status %d\n", + dev->udev->bus->bus_name, dev->udev->devpath, res); } static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message) @@ -890,11 +891,11 @@ static int rtl8150_probe(struct usb_interface *intf, dev->intr_interval = 100; /* 100ms */ if (!alloc_all_urbs(dev)) { - err("out of memory"); + dev_err(&intf->dev, "out of memory\n"); goto out; } if (!rtl8150_reset(dev)) { - err("couldn't reset the device"); + dev_err(&intf->dev, "couldn't reset the device\n"); goto out1; } fill_skb_pool(dev); @@ -903,7 +904,7 @@ static int rtl8150_probe(struct usb_interface *intf, usb_set_intfdata(intf, dev); SET_NETDEV_DEV(netdev, &intf->dev); if (register_netdev(netdev) != 0) { - err("couldn't register the device"); + dev_err(&intf->dev, "couldn't register the device\n"); goto out2; } @@ -947,7 +948,8 @@ static struct usb_driver rtl8150_driver = { .disconnect = rtl8150_disconnect, .id_table = rtl8150_table, .suspend = rtl8150_suspend, - .resume = rtl8150_resume + .resume = rtl8150_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(rtl8150_driver); diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c index b59cf20c7817..d75d1f56becf 100644 --- a/drivers/net/usb/sierra_net.c +++ b/drivers/net/usb/sierra_net.c @@ -946,7 +946,7 @@ struct sk_buff *sierra_net_tx_fixup(struct usbnet *dev, struct sk_buff *skb, } static const u8 sierra_net_ifnum_list[] = { 7, 10, 11 }; -static const struct sierra_net_info_data sierra_net_info_data_68A3 = { +static const struct sierra_net_info_data sierra_net_info_data_direct_ip = { .rx_urb_size = 8 * 1024, .whitelist = { .infolen = ARRAY_SIZE(sierra_net_ifnum_list), @@ -954,7 +954,7 @@ static const struct sierra_net_info_data sierra_net_info_data_68A3 = { } }; -static const struct driver_info sierra_net_info_68A3 = { +static const struct driver_info sierra_net_info_direct_ip = { .description = "Sierra Wireless USB-to-WWAN Modem", .flags = FLAG_WWAN | FLAG_SEND_ZLP, .bind = sierra_net_bind, @@ -962,12 +962,18 @@ static const struct driver_info sierra_net_info_68A3 = { .status = sierra_net_status, .rx_fixup = sierra_net_rx_fixup, .tx_fixup = sierra_net_tx_fixup, - .data = (unsigned long)&sierra_net_info_data_68A3, + .data = (unsigned long)&sierra_net_info_data_direct_ip, }; static const struct usb_device_id products[] = { {USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless USB-to-WWAN modem */ - .driver_info = (unsigned long) &sierra_net_info_68A3}, + .driver_info = (unsigned long) &sierra_net_info_direct_ip}, + {USB_DEVICE(0x0F3D, 0x68A3), /* AT&T Direct IP modem */ + .driver_info = (unsigned long) &sierra_net_info_direct_ip}, + {USB_DEVICE(0x1199, 0x68AA), /* Sierra Wireless Direct IP LTE modem */ + .driver_info = (unsigned long) &sierra_net_info_direct_ip}, + {USB_DEVICE(0x0F3D, 0x68AA), /* AT&T Direct IP LTE modem */ + .driver_info = (unsigned long) &sierra_net_info_direct_ip}, {}, /* last item */ }; @@ -982,6 +988,7 @@ static struct usb_driver sierra_net_driver = { .suspend = usbnet_suspend, .resume = usbnet_resume, .no_dynamic_id = 1, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(sierra_net_driver); diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 187d01ccb973..1c6e51588da7 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -98,7 +98,7 @@ static int __must_check smsc75xx_read_reg(struct usbnet *dev, u32 index, if (unlikely(ret < 0)) netdev_warn(dev->net, - "Failed to read register index 0x%08x", index); + "Failed to read reg index 0x%08x: %d", index, ret); le32_to_cpus(buf); *data = *buf; @@ -128,7 +128,7 @@ static int __must_check smsc75xx_write_reg(struct usbnet *dev, u32 index, if (unlikely(ret < 0)) netdev_warn(dev->net, - "Failed to write register index 0x%08x", index); + "Failed to write reg index 0x%08x: %d", index, ret); kfree(buf); @@ -171,7 +171,7 @@ static int smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx) idx &= dev->mii.reg_num_mask; addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR) | ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR) - | MII_ACCESS_READ; + | MII_ACCESS_READ | MII_ACCESS_BUSY; ret = smsc75xx_write_reg(dev, MII_ACCESS, addr); check_warn_goto_done(ret, "Error writing MII_ACCESS"); @@ -210,7 +210,7 @@ static void smsc75xx_mdio_write(struct net_device *netdev, int phy_id, int idx, idx &= dev->mii.reg_num_mask; addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR) | ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR) - | MII_ACCESS_WRITE; + | MII_ACCESS_WRITE | MII_ACCESS_BUSY; ret = smsc75xx_write_reg(dev, MII_ACCESS, addr); check_warn_goto_done(ret, "Error writing MII_ACCESS"); @@ -508,9 +508,9 @@ static int smsc75xx_link_reset(struct usbnet *dev) u16 lcladv, rmtadv; int ret; - /* clear interrupt status */ - ret = smsc75xx_mdio_read(dev->net, mii->phy_id, PHY_INT_SRC); - check_warn_return(ret, "Error reading PHY_INT_SRC"); + /* write to clear phy interrupt status */ + smsc75xx_mdio_write(dev->net, mii->phy_id, PHY_INT_SRC, + PHY_INT_SRC_CLEAR_ALL); ret = smsc75xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL); check_warn_return(ret, "Error writing INT_STS"); @@ -643,7 +643,7 @@ static int smsc75xx_set_mac_address(struct usbnet *dev) static int smsc75xx_phy_initialize(struct usbnet *dev) { - int bmcr, timeout = 0; + int bmcr, ret, timeout = 0; /* Initialize MII structure */ dev->mii.dev = dev->net; @@ -651,6 +651,7 @@ static int smsc75xx_phy_initialize(struct usbnet *dev) dev->mii.mdio_write = smsc75xx_mdio_write; dev->mii.phy_id_mask = 0x1f; dev->mii.reg_num_mask = 0x1f; + dev->mii.supports_gmii = 1; dev->mii.phy_id = SMSC75XX_INTERNAL_PHY_ID; /* reset phy and wait for reset to complete */ @@ -661,7 +662,7 @@ static int smsc75xx_phy_initialize(struct usbnet *dev) bmcr = smsc75xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR); check_warn_return(bmcr, "Error reading MII_BMCR"); timeout++; - } while ((bmcr & MII_BMCR) && (timeout < 100)); + } while ((bmcr & BMCR_RESET) && (timeout < 100)); if (timeout >= 100) { netdev_warn(dev->net, "timeout on PHY Reset"); @@ -671,10 +672,13 @@ static int smsc75xx_phy_initialize(struct usbnet *dev) smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); + smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000, + ADVERTISE_1000FULL); - /* read to clear */ - smsc75xx_mdio_read(dev->net, dev->mii.phy_id, PHY_INT_SRC); - check_warn_return(bmcr, "Error reading PHY_INT_SRC"); + /* read and write to clear phy interrupt status */ + ret = smsc75xx_mdio_read(dev->net, dev->mii.phy_id, PHY_INT_SRC); + check_warn_return(ret, "Error reading PHY_INT_SRC"); + smsc75xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_SRC, 0xffff); smsc75xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_MASK, PHY_INT_MASK_DEFAULT); @@ -899,15 +903,20 @@ static int smsc75xx_reset(struct usbnet *dev) netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x", buf); - /* Configure GPIO pins as LED outputs */ - ret = smsc75xx_read_reg(dev, LED_GPIO_CFG, &buf); - check_warn_return(ret, "Failed to read LED_GPIO_CFG: %d", ret); + ret = smsc75xx_read_reg(dev, E2P_CMD, &buf); + check_warn_return(ret, "Failed to read E2P_CMD: %d", ret); + + /* only set default GPIO/LED settings if no EEPROM is detected */ + if (!(buf & E2P_CMD_LOADED)) { + ret = smsc75xx_read_reg(dev, LED_GPIO_CFG, &buf); + check_warn_return(ret, "Failed to read LED_GPIO_CFG: %d", ret); - buf &= ~(LED_GPIO_CFG_LED2_FUN_SEL | LED_GPIO_CFG_LED10_FUN_SEL); - buf |= LED_GPIO_CFG_LEDGPIO_EN | LED_GPIO_CFG_LED2_FUN_SEL; + buf &= ~(LED_GPIO_CFG_LED2_FUN_SEL | LED_GPIO_CFG_LED10_FUN_SEL); + buf |= LED_GPIO_CFG_LEDGPIO_EN | LED_GPIO_CFG_LED2_FUN_SEL; - ret = smsc75xx_write_reg(dev, LED_GPIO_CFG, buf); - check_warn_return(ret, "Failed to write LED_GPIO_CFG: %d", ret); + ret = smsc75xx_write_reg(dev, LED_GPIO_CFG, buf); + check_warn_return(ret, "Failed to write LED_GPIO_CFG: %d", ret); + } ret = smsc75xx_write_reg(dev, FLOW, 0); check_warn_return(ret, "Failed to write FLOW: %d", ret); @@ -946,6 +955,14 @@ static int smsc75xx_reset(struct usbnet *dev) ret = smsc75xx_write_reg(dev, INT_EP_CTL, buf); check_warn_return(ret, "Failed to write INT_EP_CTL: %d", ret); + /* allow mac to detect speed and duplex from phy */ + ret = smsc75xx_read_reg(dev, MAC_CR, &buf); + check_warn_return(ret, "Failed to read MAC_CR: %d", ret); + + buf |= (MAC_CR_ADD | MAC_CR_ASD); + ret = smsc75xx_write_reg(dev, MAC_CR, buf); + check_warn_return(ret, "Failed to write MAC_CR: %d", ret); + ret = smsc75xx_read_reg(dev, MAC_TX, &buf); check_warn_return(ret, "Failed to read MAC_TX: %d", ret); @@ -1051,6 +1068,7 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->ethtool_ops = &smsc75xx_ethtool_ops; dev->net->flags |= IFF_MULTICAST; dev->net->hard_header_len += SMSC75XX_TX_OVERHEAD; + dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; return 0; } @@ -1211,7 +1229,7 @@ static const struct driver_info smsc75xx_info = { .rx_fixup = smsc75xx_rx_fixup, .tx_fixup = smsc75xx_tx_fixup, .status = smsc75xx_status, - .flags = FLAG_ETHER | FLAG_SEND_ZLP, + .flags = FLAG_ETHER | FLAG_SEND_ZLP | FLAG_LINK_INTR, }; static const struct usb_device_id products[] = { @@ -1236,6 +1254,7 @@ static struct usb_driver smsc75xx_driver = { .suspend = usbnet_suspend, .resume = usbnet_resume, .disconnect = usbnet_disconnect, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(smsc75xx_driver); diff --git a/drivers/net/usb/smsc75xx.h b/drivers/net/usb/smsc75xx.h index 16e98c778344..67eba39e6ee2 100644 --- a/drivers/net/usb/smsc75xx.h +++ b/drivers/net/usb/smsc75xx.h @@ -388,6 +388,7 @@ #define PHY_INT_SRC_ANEG_COMP ((u16)0x0040) #define PHY_INT_SRC_REMOTE_FAULT ((u16)0x0020) #define PHY_INT_SRC_LINK_DOWN ((u16)0x0010) +#define PHY_INT_SRC_CLEAR_ALL ((u16)0xffff) #define PHY_INT_MASK (30) #define PHY_INT_MASK_ENERGY_ON ((u16)0x0080) diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 5f19f84d3494..b1112e753859 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -1017,6 +1017,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->ethtool_ops = &smsc95xx_ethtool_ops; dev->net->flags |= IFF_MULTICAST; dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD_CSUM; + dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; return 0; } @@ -1191,7 +1192,7 @@ static const struct driver_info smsc95xx_info = { .rx_fixup = smsc95xx_rx_fixup, .tx_fixup = smsc95xx_tx_fixup, .status = smsc95xx_status, - .flags = FLAG_ETHER | FLAG_SEND_ZLP, + .flags = FLAG_ETHER | FLAG_SEND_ZLP | FLAG_LINK_INTR, }; static const struct usb_device_id products[] = { @@ -1296,6 +1297,7 @@ static struct usb_driver smsc95xx_driver = { .suspend = usbnet_suspend, .resume = usbnet_resume, .disconnect = usbnet_disconnect, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(smsc95xx_driver); diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index b7b3f5b0d406..aba769d77459 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -210,6 +210,7 @@ static int init_status (struct usbnet *dev, struct usb_interface *intf) } else { usb_fill_int_urb(dev->interrupt, dev->udev, pipe, buf, maxp, intr_complete, dev, period); + dev->interrupt->transfer_flags |= URB_FREE_BUFFER; dev_dbg(&intf->dev, "status ep%din, %d bytes period %d\n", usb_pipeendpoint(pipe), maxp, period); @@ -281,17 +282,32 @@ int usbnet_change_mtu (struct net_device *net, int new_mtu) } EXPORT_SYMBOL_GPL(usbnet_change_mtu); +/* The caller must hold list->lock */ +static void __usbnet_queue_skb(struct sk_buff_head *list, + struct sk_buff *newsk, enum skb_state state) +{ + struct skb_data *entry = (struct skb_data *) newsk->cb; + + __skb_queue_tail(list, newsk); + entry->state = state; +} + /*-------------------------------------------------------------------------*/ /* some LK 2.4 HCDs oopsed if we freed or resubmitted urbs from * completion callbacks. 2.5 should have fixed those bugs... */ -static void defer_bh(struct usbnet *dev, struct sk_buff *skb, struct sk_buff_head *list) +static enum skb_state defer_bh(struct usbnet *dev, struct sk_buff *skb, + struct sk_buff_head *list, enum skb_state state) { unsigned long flags; + enum skb_state old_state; + struct skb_data *entry = (struct skb_data *) skb->cb; spin_lock_irqsave(&list->lock, flags); + old_state = entry->state; + entry->state = state; __skb_unlink(skb, list); spin_unlock(&list->lock); spin_lock(&dev->done.lock); @@ -299,6 +315,7 @@ static void defer_bh(struct usbnet *dev, struct sk_buff *skb, struct sk_buff_hea if (dev->done.qlen == 1) tasklet_schedule(&dev->bh); spin_unlock_irqrestore(&dev->done.lock, flags); + return old_state; } /* some work can't be done in tasklets, so we use keventd @@ -339,7 +356,6 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) entry = (struct skb_data *) skb->cb; entry->urb = urb; entry->dev = dev; - entry->state = rx_start; entry->length = 0; usb_fill_bulk_urb (urb, dev->udev, dev->in, @@ -371,7 +387,7 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) tasklet_schedule (&dev->bh); break; case 0: - __skb_queue_tail (&dev->rxq, skb); + __usbnet_queue_skb(&dev->rxq, skb, rx_start); } } else { netif_dbg(dev, ifdown, dev->net, "rx: stopped\n"); @@ -422,16 +438,17 @@ static void rx_complete (struct urb *urb) struct skb_data *entry = (struct skb_data *) skb->cb; struct usbnet *dev = entry->dev; int urb_status = urb->status; + enum skb_state state; skb_put (skb, urb->actual_length); - entry->state = rx_done; + state = rx_done; entry->urb = NULL; switch (urb_status) { /* success */ case 0: if (skb->len < dev->net->hard_header_len) { - entry->state = rx_cleanup; + state = rx_cleanup; dev->net->stats.rx_errors++; dev->net->stats.rx_length_errors++; netif_dbg(dev, rx_err, dev->net, @@ -470,7 +487,7 @@ static void rx_complete (struct urb *urb) "rx throttle %d\n", urb_status); } block: - entry->state = rx_cleanup; + state = rx_cleanup; entry->urb = urb; urb = NULL; break; @@ -481,17 +498,18 @@ block: // FALLTHROUGH default: - entry->state = rx_cleanup; + state = rx_cleanup; dev->net->stats.rx_errors++; netif_dbg(dev, rx_err, dev->net, "rx status %d\n", urb_status); break; } - defer_bh(dev, skb, &dev->rxq); + state = defer_bh(dev, skb, &dev->rxq, state); if (urb) { if (netif_running (dev->net) && - !test_bit (EVENT_RX_HALT, &dev->flags)) { + !test_bit (EVENT_RX_HALT, &dev->flags) && + state != unlink_start) { rx_submit (dev, urb, GFP_ATOMIC); usb_mark_last_busy(dev->udev); return; @@ -578,16 +596,23 @@ EXPORT_SYMBOL_GPL(usbnet_purge_paused_rxq); static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) { unsigned long flags; - struct sk_buff *skb, *skbnext; + struct sk_buff *skb; int count = 0; spin_lock_irqsave (&q->lock, flags); - skb_queue_walk_safe(q, skb, skbnext) { + while (!skb_queue_empty(q)) { struct skb_data *entry; struct urb *urb; int retval; - entry = (struct skb_data *) skb->cb; + skb_queue_walk(q, skb) { + entry = (struct skb_data *) skb->cb; + if (entry->state != unlink_start) + goto found; + } + break; +found: + entry->state = unlink_start; urb = entry->urb; /* @@ -771,11 +796,13 @@ int usbnet_open (struct net_device *net) if (info->manage_power) { retval = info->manage_power(dev, 1); if (retval < 0) - goto done; + goto done_manage_power_error; usb_autopm_put_interface(dev->intf); } return retval; +done_manage_power_error: + clear_bit(EVENT_DEV_OPEN, &dev->flags); done: usb_autopm_put_interface(dev->intf); done_nopm: @@ -851,9 +878,9 @@ void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) { struct usbnet *dev = netdev_priv(net); - strncpy (info->driver, dev->driver_name, sizeof info->driver); - strncpy (info->version, DRIVER_VERSION, sizeof info->version); - strncpy (info->fw_version, dev->driver_info->description, + strlcpy (info->driver, dev->driver_name, sizeof info->driver); + strlcpy (info->version, DRIVER_VERSION, sizeof info->version); + strlcpy (info->fw_version, dev->driver_info->description, sizeof info->fw_version); usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info); } @@ -884,6 +911,7 @@ static const struct ethtool_ops usbnet_ethtool_ops = { .get_drvinfo = usbnet_get_drvinfo, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, + .get_ts_info = ethtool_op_get_ts_info, }; /*-------------------------------------------------------------------------*/ @@ -1038,8 +1066,7 @@ static void tx_complete (struct urb *urb) } usb_autopm_put_interface_async(dev->intf); - entry->state = tx_done; - defer_bh(dev, skb, &dev->txq); + (void) defer_bh(dev, skb, &dev->txq, tx_done); } /*-------------------------------------------------------------------------*/ @@ -1095,7 +1122,6 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, entry = (struct skb_data *) skb->cb; entry->urb = urb; entry->dev = dev; - entry->state = tx_start; entry->length = length; usb_fill_bulk_urb (urb, dev->udev, dev->out, @@ -1154,7 +1180,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, break; case 0: net->trans_start = jiffies; - __skb_queue_tail (&dev->txq, skb); + __usbnet_queue_skb(&dev->txq, skb, tx_start); if (dev->txq.qlen >= TX_QLEN (dev)) netif_stop_queue (net); } @@ -1178,6 +1204,21 @@ deferred: } EXPORT_SYMBOL_GPL(usbnet_start_xmit); +static void rx_alloc_submit(struct usbnet *dev, gfp_t flags) +{ + struct urb *urb; + int i; + + /* don't refill the queue all at once */ + for (i = 0; i < 10 && dev->rxq.qlen < RX_QLEN(dev); i++) { + urb = usb_alloc_urb(0, flags); + if (urb != NULL) { + if (rx_submit(dev, urb, flags) == -ENOLINK) + return; + } + } +} + /*-------------------------------------------------------------------------*/ // tasklet (work deferred from completions, in_irq) or timer @@ -1217,26 +1258,14 @@ static void usbnet_bh (unsigned long param) !timer_pending (&dev->delay) && !test_bit (EVENT_RX_HALT, &dev->flags)) { int temp = dev->rxq.qlen; - int qlen = RX_QLEN (dev); - - if (temp < qlen) { - struct urb *urb; - int i; - - // don't refill the queue all at once - for (i = 0; i < 10 && dev->rxq.qlen < qlen; i++) { - urb = usb_alloc_urb (0, GFP_ATOMIC); - if (urb != NULL) { - if (rx_submit (dev, urb, GFP_ATOMIC) == - -ENOLINK) - return; - } - } + + if (temp < RX_QLEN(dev)) { + rx_alloc_submit(dev, GFP_ATOMIC); if (temp != dev->rxq.qlen) netif_dbg(dev, link, dev->net, "rxqlen %d --> %d\n", temp, dev->rxq.qlen); - if (dev->rxq.qlen < qlen) + if (dev->rxq.qlen < RX_QLEN(dev)) tasklet_schedule (&dev->bh); } if (dev->txq.qlen < TX_QLEN (dev)) @@ -1443,7 +1472,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) status = register_netdev (net); if (status) - goto out3; + goto out4; netif_info(dev, probe, dev->net, "register '%s' at usb-%s-%s, %s, %pM\n", udev->dev.driver->name, @@ -1461,6 +1490,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) return 0; +out4: + usb_free_urb(dev->interrupt); out3: if (info->unbind) info->unbind (dev, udev); @@ -1487,6 +1518,7 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message) spin_lock_irq(&dev->txq.lock); /* don't autosuspend while transmitting */ if (dev->txq.qlen && PMSG_IS_AUTO(message)) { + dev->suspend_count--; spin_unlock_irq(&dev->txq.lock); return -EBUSY; } else { @@ -1543,6 +1575,13 @@ int usbnet_resume (struct usb_interface *intf) spin_unlock_irq(&dev->txq.lock); if (test_bit(EVENT_DEV_OPEN, &dev->flags)) { + /* handle remote wakeup ASAP */ + if (!dev->wait && + netif_device_present(dev->net) && + !timer_pending(&dev->delay) && + !test_bit(EVENT_RX_HALT, &dev->flags)) + rx_alloc_submit(dev, GFP_KERNEL); + if (!(dev->txq.qlen >= TX_QLEN(dev))) netif_tx_wake_all_queues(dev->net); tasklet_schedule (&dev->bh); diff --git a/drivers/net/usb/zaurus.c b/drivers/net/usb/zaurus.c index 34db195fb8b0..35c90307d473 100644 --- a/drivers/net/usb/zaurus.c +++ b/drivers/net/usb/zaurus.c @@ -377,6 +377,7 @@ static struct usb_driver zaurus_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(zaurus_driver); |