diff options
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 @@ | |||
58 | #include <linux/module.h> | 58 | #include <linux/module.h> |
59 | #include <linux/ethtool.h> | 59 | #include <linux/ethtool.h> |
60 | #include <linux/usb.h> | 60 | #include <linux/usb.h> |
61 | #include <linux/timer.h> | ||
62 | #include <linux/tty.h> | 61 | #include <linux/tty.h> |
63 | #include <linux/tty_driver.h> | 62 | #include <linux/tty_driver.h> |
64 | #include <linux/tty_flip.h> | 63 | #include <linux/tty_flip.h> |
@@ -154,6 +153,7 @@ struct hso_net { | |||
154 | struct hso_device *parent; | 153 | struct hso_device *parent; |
155 | struct net_device *net; | 154 | struct net_device *net; |
156 | struct rfkill *rfkill; | 155 | struct rfkill *rfkill; |
156 | char name[24]; | ||
157 | 157 | ||
158 | struct usb_endpoint_descriptor *in_endp; | 158 | struct usb_endpoint_descriptor *in_endp; |
159 | struct usb_endpoint_descriptor *out_endp; | 159 | struct usb_endpoint_descriptor *out_endp; |
@@ -274,7 +274,6 @@ struct hso_device { | |||
274 | u8 usb_gone; | 274 | u8 usb_gone; |
275 | struct work_struct async_get_intf; | 275 | struct work_struct async_get_intf; |
276 | struct work_struct async_put_intf; | 276 | struct work_struct async_put_intf; |
277 | struct work_struct reset_device; | ||
278 | 277 | ||
279 | struct usb_device *usb; | 278 | struct usb_device *usb; |
280 | struct usb_interface *interface; | 279 | struct usb_interface *interface; |
@@ -340,7 +339,6 @@ static void async_put_intf(struct work_struct *data); | |||
340 | static int hso_put_activity(struct hso_device *hso_dev); | 339 | static int hso_put_activity(struct hso_device *hso_dev); |
341 | static int hso_get_activity(struct hso_device *hso_dev); | 340 | static int hso_get_activity(struct hso_device *hso_dev); |
342 | static void tiocmget_intr_callback(struct urb *urb); | 341 | static void tiocmget_intr_callback(struct urb *urb); |
343 | static void reset_device(struct work_struct *data); | ||
344 | /*****************************************************************************/ | 342 | /*****************************************************************************/ |
345 | /* Helping functions */ | 343 | /* Helping functions */ |
346 | /*****************************************************************************/ | 344 | /*****************************************************************************/ |
@@ -533,6 +531,13 @@ static ssize_t hso_sysfs_show_porttype(struct device *dev, | |||
533 | } | 531 | } |
534 | static DEVICE_ATTR(hsotype, S_IRUGO, hso_sysfs_show_porttype, NULL); | 532 | static DEVICE_ATTR(hsotype, S_IRUGO, hso_sysfs_show_porttype, NULL); |
535 | 533 | ||
534 | static struct attribute *hso_serial_dev_attrs[] = { | ||
535 | &dev_attr_hsotype.attr, | ||
536 | NULL | ||
537 | }; | ||
538 | |||
539 | ATTRIBUTE_GROUPS(hso_serial_dev); | ||
540 | |||
536 | static int hso_urb_to_index(struct hso_serial *serial, struct urb *urb) | 541 | static int hso_urb_to_index(struct hso_serial *serial, struct urb *urb) |
537 | { | 542 | { |
538 | int idx; | 543 | int idx; |
@@ -696,7 +701,7 @@ static void handle_usb_error(int status, const char *function, | |||
696 | case -ETIMEDOUT: | 701 | case -ETIMEDOUT: |
697 | explanation = "protocol error"; | 702 | explanation = "protocol error"; |
698 | if (hso_dev) | 703 | if (hso_dev) |
699 | schedule_work(&hso_dev->reset_device); | 704 | usb_queue_reset_device(hso_dev->interface); |
700 | break; | 705 | break; |
701 | default: | 706 | default: |
702 | explanation = "unknown status"; | 707 | explanation = "unknown status"; |
@@ -1271,7 +1276,6 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) | |||
1271 | goto err_out; | 1276 | goto err_out; |
1272 | 1277 | ||
1273 | D1("Opening %d", serial->minor); | 1278 | D1("Opening %d", serial->minor); |
1274 | kref_get(&serial->parent->ref); | ||
1275 | 1279 | ||
1276 | /* setup */ | 1280 | /* setup */ |
1277 | tty->driver_data = serial; | 1281 | tty->driver_data = serial; |
@@ -1290,7 +1294,8 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) | |||
1290 | if (result) { | 1294 | if (result) { |
1291 | hso_stop_serial_device(serial->parent); | 1295 | hso_stop_serial_device(serial->parent); |
1292 | serial->port.count--; | 1296 | serial->port.count--; |
1293 | kref_put(&serial->parent->ref, hso_serial_ref_free); | 1297 | } else { |
1298 | kref_get(&serial->parent->ref); | ||
1294 | } | 1299 | } |
1295 | } else { | 1300 | } else { |
1296 | D1("Port was already open"); | 1301 | D1("Port was already open"); |
@@ -1340,8 +1345,6 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp) | |||
1340 | usb_autopm_put_interface(serial->parent->interface); | 1345 | usb_autopm_put_interface(serial->parent->interface); |
1341 | 1346 | ||
1342 | mutex_unlock(&serial->parent->mutex); | 1347 | mutex_unlock(&serial->parent->mutex); |
1343 | |||
1344 | kref_put(&serial->parent->ref, hso_serial_ref_free); | ||
1345 | } | 1348 | } |
1346 | 1349 | ||
1347 | /* close the requested serial port */ | 1350 | /* close the requested serial port */ |
@@ -1392,6 +1395,16 @@ static int hso_serial_write_room(struct tty_struct *tty) | |||
1392 | return room; | 1395 | return room; |
1393 | } | 1396 | } |
1394 | 1397 | ||
1398 | static void hso_serial_cleanup(struct tty_struct *tty) | ||
1399 | { | ||
1400 | struct hso_serial *serial = tty->driver_data; | ||
1401 | |||
1402 | if (!serial) | ||
1403 | return; | ||
1404 | |||
1405 | kref_put(&serial->parent->ref, hso_serial_ref_free); | ||
1406 | } | ||
1407 | |||
1395 | /* setup the term */ | 1408 | /* setup the term */ |
1396 | static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) | 1409 | static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) |
1397 | { | 1410 | { |
@@ -2198,8 +2211,8 @@ static int hso_stop_serial_device(struct hso_device *hso_dev) | |||
2198 | 2211 | ||
2199 | for (i = 0; i < serial->num_rx_urbs; i++) { | 2212 | for (i = 0; i < serial->num_rx_urbs; i++) { |
2200 | if (serial->rx_urb[i]) { | 2213 | if (serial->rx_urb[i]) { |
2201 | usb_kill_urb(serial->rx_urb[i]); | 2214 | usb_kill_urb(serial->rx_urb[i]); |
2202 | serial->rx_urb_filled[i] = 0; | 2215 | serial->rx_urb_filled[i] = 0; |
2203 | } | 2216 | } |
2204 | } | 2217 | } |
2205 | serial->curr_rx_urb_idx = 0; | 2218 | serial->curr_rx_urb_idx = 0; |
@@ -2228,15 +2241,15 @@ static int hso_stop_serial_device(struct hso_device *hso_dev) | |||
2228 | return 0; | 2241 | return 0; |
2229 | } | 2242 | } |
2230 | 2243 | ||
2244 | static void hso_serial_tty_unregister(struct hso_serial *serial) | ||
2245 | { | ||
2246 | tty_unregister_device(tty_drv, serial->minor); | ||
2247 | } | ||
2248 | |||
2231 | static void hso_serial_common_free(struct hso_serial *serial) | 2249 | static void hso_serial_common_free(struct hso_serial *serial) |
2232 | { | 2250 | { |
2233 | int i; | 2251 | int i; |
2234 | 2252 | ||
2235 | if (serial->parent->dev) | ||
2236 | device_remove_file(serial->parent->dev, &dev_attr_hsotype); | ||
2237 | |||
2238 | tty_unregister_device(tty_drv, serial->minor); | ||
2239 | |||
2240 | for (i = 0; i < serial->num_rx_urbs; i++) { | 2253 | for (i = 0; i < serial->num_rx_urbs; i++) { |
2241 | /* unlink and free RX URB */ | 2254 | /* unlink and free RX URB */ |
2242 | usb_free_urb(serial->rx_urb[i]); | 2255 | usb_free_urb(serial->rx_urb[i]); |
@@ -2246,6 +2259,7 @@ static void hso_serial_common_free(struct hso_serial *serial) | |||
2246 | 2259 | ||
2247 | /* unlink and free TX URB */ | 2260 | /* unlink and free TX URB */ |
2248 | usb_free_urb(serial->tx_urb); | 2261 | usb_free_urb(serial->tx_urb); |
2262 | kfree(serial->tx_buffer); | ||
2249 | kfree(serial->tx_data); | 2263 | kfree(serial->tx_data); |
2250 | tty_port_destroy(&serial->port); | 2264 | tty_port_destroy(&serial->port); |
2251 | } | 2265 | } |
@@ -2264,11 +2278,10 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, | |||
2264 | goto exit; | 2278 | goto exit; |
2265 | 2279 | ||
2266 | /* register our minor number */ | 2280 | /* register our minor number */ |
2267 | serial->parent->dev = tty_port_register_device(&serial->port, tty_drv, | 2281 | serial->parent->dev = tty_port_register_device_attr(&serial->port, |
2268 | minor, &serial->parent->interface->dev); | 2282 | tty_drv, minor, &serial->parent->interface->dev, |
2283 | serial->parent, hso_serial_dev_groups); | ||
2269 | dev = serial->parent->dev; | 2284 | dev = serial->parent->dev; |
2270 | dev_set_drvdata(dev, serial->parent); | ||
2271 | i = device_create_file(dev, &dev_attr_hsotype); | ||
2272 | 2285 | ||
2273 | /* fill in specific data for later use */ | 2286 | /* fill in specific data for later use */ |
2274 | serial->minor = minor; | 2287 | serial->minor = minor; |
@@ -2316,6 +2329,7 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, | |||
2316 | 2329 | ||
2317 | return 0; | 2330 | return 0; |
2318 | exit: | 2331 | exit: |
2332 | hso_serial_tty_unregister(serial); | ||
2319 | hso_serial_common_free(serial); | 2333 | hso_serial_common_free(serial); |
2320 | return -1; | 2334 | return -1; |
2321 | } | 2335 | } |
@@ -2338,7 +2352,6 @@ static struct hso_device *hso_create_device(struct usb_interface *intf, | |||
2338 | 2352 | ||
2339 | INIT_WORK(&hso_dev->async_get_intf, async_get_intf); | 2353 | INIT_WORK(&hso_dev->async_get_intf, async_get_intf); |
2340 | INIT_WORK(&hso_dev->async_put_intf, async_put_intf); | 2354 | INIT_WORK(&hso_dev->async_put_intf, async_put_intf); |
2341 | INIT_WORK(&hso_dev->reset_device, reset_device); | ||
2342 | 2355 | ||
2343 | return hso_dev; | 2356 | return hso_dev; |
2344 | } | 2357 | } |
@@ -2459,27 +2472,21 @@ static void hso_create_rfkill(struct hso_device *hso_dev, | |||
2459 | { | 2472 | { |
2460 | struct hso_net *hso_net = dev2net(hso_dev); | 2473 | struct hso_net *hso_net = dev2net(hso_dev); |
2461 | struct device *dev = &hso_net->net->dev; | 2474 | struct device *dev = &hso_net->net->dev; |
2462 | char *rfkn; | 2475 | static u32 rfkill_counter; |
2463 | 2476 | ||
2464 | rfkn = kzalloc(20, GFP_KERNEL); | 2477 | snprintf(hso_net->name, sizeof(hso_net->name), "hso-%d", |
2465 | if (!rfkn) | 2478 | rfkill_counter++); |
2466 | dev_err(dev, "%s - Out of memory\n", __func__); | ||
2467 | |||
2468 | snprintf(rfkn, 20, "hso-%d", | ||
2469 | interface->altsetting->desc.bInterfaceNumber); | ||
2470 | 2479 | ||
2471 | hso_net->rfkill = rfkill_alloc(rfkn, | 2480 | hso_net->rfkill = rfkill_alloc(hso_net->name, |
2472 | &interface_to_usbdev(interface)->dev, | 2481 | &interface_to_usbdev(interface)->dev, |
2473 | RFKILL_TYPE_WWAN, | 2482 | RFKILL_TYPE_WWAN, |
2474 | &hso_rfkill_ops, hso_dev); | 2483 | &hso_rfkill_ops, hso_dev); |
2475 | if (!hso_net->rfkill) { | 2484 | if (!hso_net->rfkill) { |
2476 | dev_err(dev, "%s - Out of memory\n", __func__); | 2485 | dev_err(dev, "%s - Out of memory\n", __func__); |
2477 | kfree(rfkn); | ||
2478 | return; | 2486 | return; |
2479 | } | 2487 | } |
2480 | if (rfkill_register(hso_net->rfkill) < 0) { | 2488 | if (rfkill_register(hso_net->rfkill) < 0) { |
2481 | rfkill_destroy(hso_net->rfkill); | 2489 | rfkill_destroy(hso_net->rfkill); |
2482 | kfree(rfkn); | ||
2483 | hso_net->rfkill = NULL; | 2490 | hso_net->rfkill = NULL; |
2484 | dev_err(dev, "%s - Failed to register rfkill\n", __func__); | 2491 | dev_err(dev, "%s - Failed to register rfkill\n", __func__); |
2485 | return; | 2492 | return; |
@@ -2594,7 +2601,6 @@ static void hso_free_serial_device(struct hso_device *hso_dev) | |||
2594 | 2601 | ||
2595 | if (!serial) | 2602 | if (!serial) |
2596 | return; | 2603 | return; |
2597 | set_serial_by_index(serial->minor, NULL); | ||
2598 | 2604 | ||
2599 | hso_serial_common_free(serial); | 2605 | hso_serial_common_free(serial); |
2600 | 2606 | ||
@@ -2684,6 +2690,7 @@ static struct hso_device *hso_create_bulk_serial_device( | |||
2684 | return hso_dev; | 2690 | return hso_dev; |
2685 | 2691 | ||
2686 | exit2: | 2692 | exit2: |
2693 | hso_serial_tty_unregister(serial); | ||
2687 | hso_serial_common_free(serial); | 2694 | hso_serial_common_free(serial); |
2688 | exit: | 2695 | exit: |
2689 | hso_free_tiomget(serial); | 2696 | hso_free_tiomget(serial); |
@@ -3083,26 +3090,6 @@ out: | |||
3083 | return result; | 3090 | return result; |
3084 | } | 3091 | } |
3085 | 3092 | ||
3086 | static void reset_device(struct work_struct *data) | ||
3087 | { | ||
3088 | struct hso_device *hso_dev = | ||
3089 | container_of(data, struct hso_device, reset_device); | ||
3090 | struct usb_device *usb = hso_dev->usb; | ||
3091 | int result; | ||
3092 | |||
3093 | if (hso_dev->usb_gone) { | ||
3094 | D1("No reset during disconnect\n"); | ||
3095 | } else { | ||
3096 | result = usb_lock_device_for_reset(usb, hso_dev->interface); | ||
3097 | if (result < 0) | ||
3098 | D1("unable to lock device for reset: %d\n", result); | ||
3099 | else { | ||
3100 | usb_reset_device(usb); | ||
3101 | usb_unlock_device(usb); | ||
3102 | } | ||
3103 | } | ||
3104 | } | ||
3105 | |||
3106 | static void hso_serial_ref_free(struct kref *ref) | 3093 | static void hso_serial_ref_free(struct kref *ref) |
3107 | { | 3094 | { |
3108 | struct hso_device *hso_dev = container_of(ref, struct hso_device, ref); | 3095 | 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) | |||
3112 | 3099 | ||
3113 | static void hso_free_interface(struct usb_interface *interface) | 3100 | static void hso_free_interface(struct usb_interface *interface) |
3114 | { | 3101 | { |
3115 | struct hso_serial *hso_dev; | 3102 | struct hso_serial *serial; |
3116 | int i; | 3103 | int i; |
3117 | 3104 | ||
3118 | for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { | 3105 | for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { |
3119 | if (serial_table[i] && | 3106 | if (serial_table[i] && |
3120 | (serial_table[i]->interface == interface)) { | 3107 | (serial_table[i]->interface == interface)) { |
3121 | hso_dev = dev2ser(serial_table[i]); | 3108 | serial = dev2ser(serial_table[i]); |
3122 | tty_port_tty_hangup(&hso_dev->port, false); | 3109 | tty_port_tty_hangup(&serial->port, false); |
3123 | mutex_lock(&hso_dev->parent->mutex); | 3110 | mutex_lock(&serial->parent->mutex); |
3124 | hso_dev->parent->usb_gone = 1; | 3111 | serial->parent->usb_gone = 1; |
3125 | mutex_unlock(&hso_dev->parent->mutex); | 3112 | mutex_unlock(&serial->parent->mutex); |
3113 | cancel_work_sync(&serial_table[i]->async_put_intf); | ||
3114 | cancel_work_sync(&serial_table[i]->async_get_intf); | ||
3115 | hso_serial_tty_unregister(serial); | ||
3126 | kref_put(&serial_table[i]->ref, hso_serial_ref_free); | 3116 | kref_put(&serial_table[i]->ref, hso_serial_ref_free); |
3117 | set_serial_by_index(i, NULL); | ||
3127 | } | 3118 | } |
3128 | } | 3119 | } |
3129 | 3120 | ||
@@ -3215,6 +3206,7 @@ static const struct tty_operations hso_serial_ops = { | |||
3215 | .close = hso_serial_close, | 3206 | .close = hso_serial_close, |
3216 | .write = hso_serial_write, | 3207 | .write = hso_serial_write, |
3217 | .write_room = hso_serial_write_room, | 3208 | .write_room = hso_serial_write_room, |
3209 | .cleanup = hso_serial_cleanup, | ||
3218 | .ioctl = hso_serial_ioctl, | 3210 | .ioctl = hso_serial_ioctl, |
3219 | .set_termios = hso_serial_set_termios, | 3211 | .set_termios = hso_serial_set_termios, |
3220 | .chars_in_buffer = hso_serial_chars_in_buffer, | 3212 | .chars_in_buffer = hso_serial_chars_in_buffer, |