diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-10 20:01:30 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-10 20:01:30 -0800 |
commit | c5ce28df0e7c01a1de23c36ebdefcd803f2b6cbb (patch) | |
tree | 9830baf38832769e1cf621708889111bbe3c93df /drivers/net/usb/hso.c | |
parent | 29afc4e9a408f2304e09c6dd0dbcfbd2356d0faa (diff) | |
parent | 9399f0c51489ae8c16d6559b82a452fdc1895e91 (diff) | |
download | linux-c5ce28df0e7c01a1de23c36ebdefcd803f2b6cbb.tar.bz2 |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller:
1) More iov_iter conversion work from Al Viro.
[ The "crypto: switch af_alg_make_sg() to iov_iter" commit was
wrong, and this pull actually adds an extra commit on top of the
branch I'm pulling to fix that up, so that the pre-merge state is
ok. - Linus ]
2) Various optimizations to the ipv4 forwarding information base trie
lookup implementation. From Alexander Duyck.
3) Remove sock_iocb altogether, from CHristoph Hellwig.
4) Allow congestion control algorithm selection via routing metrics.
From Daniel Borkmann.
5) Make ipv4 uncached route list per-cpu, from Eric Dumazet.
6) Handle rfs hash collisions more gracefully, also from Eric Dumazet.
7) Add xmit_more support to r8169, e1000, and e1000e drivers. From
Florian Westphal.
8) Transparent Ethernet Bridging support for GRO, from Jesse Gross.
9) Add BPF packet actions to packet scheduler, from Jiri Pirko.
10) Add support for uniqu flow IDs to openvswitch, from Joe Stringer.
11) New NetCP ethernet driver, from Muralidharan Karicheri and Wingman
Kwok.
12) More sanely handle out-of-window dupacks, which can result in
serious ACK storms. From Neal Cardwell.
13) Various rhashtable bug fixes and enhancements, from Herbert Xu,
Patrick McHardy, and Thomas Graf.
14) Support xmit_more in be2net, from Sathya Perla.
15) Group Policy extensions for vxlan, from Thomas Graf.
16) Remove Checksum Offload support for vxlan, from Tom Herbert.
17) Like ipv4, support lockless transmit over ipv6 UDP sockets. From
Vlad Yasevich.
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1494+1 commits)
crypto: fix af_alg_make_sg() conversion to iov_iter
ipv4: Namespecify TCP PMTU mechanism
i40e: Fix for stats init function call in Rx setup
tcp: don't include Fast Open option in SYN-ACK on pure SYN-data
openvswitch: Only set TUNNEL_VXLAN_OPT if VXLAN-GBP metadata is set
ipv6: Make __ipv6_select_ident static
ipv6: Fix fragment id assignment on LE arches.
bridge: Fix inability to add non-vlan fdb entry
net: Mellanox: Delete unnecessary checks before the function call "vunmap"
cxgb4: Add support in cxgb4 to get expansion rom version via ethtool
ethtool: rename reserved1 memeber in ethtool_drvinfo for expansion ROM version
net: dsa: Remove redundant phy_attach()
IB/mlx4: Reset flow support for IB kernel ULPs
IB/mlx4: Always use the correct port for mirrored multicast attachments
net/bonding: Fix potential bad memory access during bonding events
tipc: remove tipc_snprintf
tipc: nl compat add noop and remove legacy nl framework
tipc: convert legacy nl stats show to nl compat
tipc: convert legacy nl net id get to nl compat
tipc: convert legacy nl net id set to nl compat
...
Diffstat (limited to 'drivers/net/usb/hso.c')
-rw-r--r-- | drivers/net/usb/hso.c | 106 |
1 files changed, 49 insertions, 57 deletions
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 9c5aa922a9f4..6b8efcabb816 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -58,7 +58,6 @@ #include <linux/module.h> #include <linux/ethtool.h> #include <linux/usb.h> -#include <linux/timer.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> @@ -154,6 +153,7 @@ struct hso_net { struct hso_device *parent; struct net_device *net; struct rfkill *rfkill; + char name[24]; struct usb_endpoint_descriptor *in_endp; struct usb_endpoint_descriptor *out_endp; @@ -274,7 +274,6 @@ struct hso_device { u8 usb_gone; struct work_struct async_get_intf; struct work_struct async_put_intf; - struct work_struct reset_device; struct usb_device *usb; struct usb_interface *interface; @@ -340,7 +339,6 @@ static void async_put_intf(struct work_struct *data); static int hso_put_activity(struct hso_device *hso_dev); static int hso_get_activity(struct hso_device *hso_dev); static void tiocmget_intr_callback(struct urb *urb); -static void reset_device(struct work_struct *data); /*****************************************************************************/ /* Helping functions */ /*****************************************************************************/ @@ -533,6 +531,13 @@ static ssize_t hso_sysfs_show_porttype(struct device *dev, } static DEVICE_ATTR(hsotype, S_IRUGO, hso_sysfs_show_porttype, NULL); +static struct attribute *hso_serial_dev_attrs[] = { + &dev_attr_hsotype.attr, + NULL +}; + +ATTRIBUTE_GROUPS(hso_serial_dev); + static int hso_urb_to_index(struct hso_serial *serial, struct urb *urb) { int idx; @@ -696,7 +701,7 @@ static void handle_usb_error(int status, const char *function, case -ETIMEDOUT: explanation = "protocol error"; if (hso_dev) - schedule_work(&hso_dev->reset_device); + usb_queue_reset_device(hso_dev->interface); break; default: explanation = "unknown status"; @@ -1271,7 +1276,6 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) goto err_out; D1("Opening %d", serial->minor); - kref_get(&serial->parent->ref); /* setup */ tty->driver_data = serial; @@ -1290,7 +1294,8 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) if (result) { hso_stop_serial_device(serial->parent); serial->port.count--; - kref_put(&serial->parent->ref, hso_serial_ref_free); + } else { + kref_get(&serial->parent->ref); } } else { D1("Port was already open"); @@ -1340,8 +1345,6 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp) usb_autopm_put_interface(serial->parent->interface); mutex_unlock(&serial->parent->mutex); - - kref_put(&serial->parent->ref, hso_serial_ref_free); } /* close the requested serial port */ @@ -1392,6 +1395,16 @@ static int hso_serial_write_room(struct tty_struct *tty) return room; } +static void hso_serial_cleanup(struct tty_struct *tty) +{ + struct hso_serial *serial = tty->driver_data; + + if (!serial) + return; + + kref_put(&serial->parent->ref, hso_serial_ref_free); +} + /* setup the term */ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) { @@ -2198,8 +2211,8 @@ static int hso_stop_serial_device(struct hso_device *hso_dev) for (i = 0; i < serial->num_rx_urbs; i++) { if (serial->rx_urb[i]) { - usb_kill_urb(serial->rx_urb[i]); - serial->rx_urb_filled[i] = 0; + usb_kill_urb(serial->rx_urb[i]); + serial->rx_urb_filled[i] = 0; } } serial->curr_rx_urb_idx = 0; @@ -2228,15 +2241,15 @@ static int hso_stop_serial_device(struct hso_device *hso_dev) return 0; } +static void hso_serial_tty_unregister(struct hso_serial *serial) +{ + tty_unregister_device(tty_drv, serial->minor); +} + static void hso_serial_common_free(struct hso_serial *serial) { int i; - if (serial->parent->dev) - device_remove_file(serial->parent->dev, &dev_attr_hsotype); - - tty_unregister_device(tty_drv, serial->minor); - for (i = 0; i < serial->num_rx_urbs; i++) { /* unlink and free RX URB */ usb_free_urb(serial->rx_urb[i]); @@ -2246,6 +2259,7 @@ static void hso_serial_common_free(struct hso_serial *serial) /* unlink and free TX URB */ usb_free_urb(serial->tx_urb); + kfree(serial->tx_buffer); kfree(serial->tx_data); tty_port_destroy(&serial->port); } @@ -2264,11 +2278,10 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, goto exit; /* register our minor number */ - serial->parent->dev = tty_port_register_device(&serial->port, tty_drv, - minor, &serial->parent->interface->dev); + serial->parent->dev = tty_port_register_device_attr(&serial->port, + tty_drv, minor, &serial->parent->interface->dev, + serial->parent, hso_serial_dev_groups); dev = serial->parent->dev; - dev_set_drvdata(dev, serial->parent); - i = device_create_file(dev, &dev_attr_hsotype); /* fill in specific data for later use */ serial->minor = minor; @@ -2316,6 +2329,7 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, return 0; exit: + hso_serial_tty_unregister(serial); hso_serial_common_free(serial); return -1; } @@ -2338,7 +2352,6 @@ static struct hso_device *hso_create_device(struct usb_interface *intf, INIT_WORK(&hso_dev->async_get_intf, async_get_intf); INIT_WORK(&hso_dev->async_put_intf, async_put_intf); - INIT_WORK(&hso_dev->reset_device, reset_device); return hso_dev; } @@ -2459,27 +2472,21 @@ static void hso_create_rfkill(struct hso_device *hso_dev, { struct hso_net *hso_net = dev2net(hso_dev); struct device *dev = &hso_net->net->dev; - char *rfkn; + static u32 rfkill_counter; - rfkn = kzalloc(20, GFP_KERNEL); - if (!rfkn) - dev_err(dev, "%s - Out of memory\n", __func__); - - snprintf(rfkn, 20, "hso-%d", - interface->altsetting->desc.bInterfaceNumber); + snprintf(hso_net->name, sizeof(hso_net->name), "hso-%d", + rfkill_counter++); - hso_net->rfkill = rfkill_alloc(rfkn, + hso_net->rfkill = rfkill_alloc(hso_net->name, &interface_to_usbdev(interface)->dev, RFKILL_TYPE_WWAN, &hso_rfkill_ops, hso_dev); if (!hso_net->rfkill) { dev_err(dev, "%s - Out of memory\n", __func__); - kfree(rfkn); return; } if (rfkill_register(hso_net->rfkill) < 0) { rfkill_destroy(hso_net->rfkill); - kfree(rfkn); hso_net->rfkill = NULL; dev_err(dev, "%s - Failed to register rfkill\n", __func__); return; @@ -2594,7 +2601,6 @@ static void hso_free_serial_device(struct hso_device *hso_dev) if (!serial) return; - set_serial_by_index(serial->minor, NULL); hso_serial_common_free(serial); @@ -2684,6 +2690,7 @@ static struct hso_device *hso_create_bulk_serial_device( return hso_dev; exit2: + hso_serial_tty_unregister(serial); hso_serial_common_free(serial); exit: hso_free_tiomget(serial); @@ -3083,26 +3090,6 @@ out: return result; } -static void reset_device(struct work_struct *data) -{ - struct hso_device *hso_dev = - container_of(data, struct hso_device, reset_device); - struct usb_device *usb = hso_dev->usb; - int result; - - if (hso_dev->usb_gone) { - D1("No reset during disconnect\n"); - } else { - result = usb_lock_device_for_reset(usb, hso_dev->interface); - if (result < 0) - D1("unable to lock device for reset: %d\n", result); - else { - usb_reset_device(usb); - usb_unlock_device(usb); - } - } -} - static void hso_serial_ref_free(struct kref *ref) { struct hso_device *hso_dev = container_of(ref, struct hso_device, ref); @@ -3112,18 +3099,22 @@ static void hso_serial_ref_free(struct kref *ref) static void hso_free_interface(struct usb_interface *interface) { - struct hso_serial *hso_dev; + struct hso_serial *serial; int i; for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { if (serial_table[i] && (serial_table[i]->interface == interface)) { - hso_dev = dev2ser(serial_table[i]); - tty_port_tty_hangup(&hso_dev->port, false); - mutex_lock(&hso_dev->parent->mutex); - hso_dev->parent->usb_gone = 1; - mutex_unlock(&hso_dev->parent->mutex); + serial = dev2ser(serial_table[i]); + tty_port_tty_hangup(&serial->port, false); + mutex_lock(&serial->parent->mutex); + serial->parent->usb_gone = 1; + mutex_unlock(&serial->parent->mutex); + cancel_work_sync(&serial_table[i]->async_put_intf); + cancel_work_sync(&serial_table[i]->async_get_intf); + hso_serial_tty_unregister(serial); kref_put(&serial_table[i]->ref, hso_serial_ref_free); + set_serial_by_index(i, NULL); } } @@ -3215,6 +3206,7 @@ static const struct tty_operations hso_serial_ops = { .close = hso_serial_close, .write = hso_serial_write, .write_room = hso_serial_write_room, + .cleanup = hso_serial_cleanup, .ioctl = hso_serial_ioctl, .set_termios = hso_serial_set_termios, .chars_in_buffer = hso_serial_chars_in_buffer, |