diff options
author | Alan Cox <alan@linux.intel.com> | 2009-06-11 07:36:09 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-11 11:50:58 -0400 |
commit | 10077d4a6674f535abdbe25cdecb1202af7948f1 (patch) | |
tree | 44097ec16c58c6bab56c5af4b20eba96503eeb92 /drivers/usb/class/cdc-acm.c | |
parent | b39933fbd304021580800796683b8ddaa3dd0a6a (diff) |
tty: cdc_acm add krefs
Now we have a port structure begin using the fields and kref counts
Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
-rw-r--r-- | drivers/usb/class/cdc-acm.c | 164 |
1 files changed, 98 insertions, 66 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 41d4ca527f82..b4e73aa759d6 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
@@ -62,7 +62,7 @@ | |||
62 | #include <linux/tty_flip.h> | 62 | #include <linux/tty_flip.h> |
63 | #include <linux/module.h> | 63 | #include <linux/module.h> |
64 | #include <linux/mutex.h> | 64 | #include <linux/mutex.h> |
65 | #include <asm/uaccess.h> | 65 | #include <linux/uaccess.h> |
66 | #include <linux/usb.h> | 66 | #include <linux/usb.h> |
67 | #include <linux/usb/cdc.h> | 67 | #include <linux/usb/cdc.h> |
68 | #include <asm/byteorder.h> | 68 | #include <asm/byteorder.h> |
@@ -87,7 +87,7 @@ static struct acm *acm_table[ACM_TTY_MINORS]; | |||
87 | 87 | ||
88 | static DEFINE_MUTEX(open_mutex); | 88 | static DEFINE_MUTEX(open_mutex); |
89 | 89 | ||
90 | #define ACM_READY(acm) (acm && acm->dev && acm->used) | 90 | #define ACM_READY(acm) (acm && acm->dev && acm->port.count) |
91 | 91 | ||
92 | static const struct tty_port_operations acm_port_ops = { | 92 | static const struct tty_port_operations acm_port_ops = { |
93 | }; | 93 | }; |
@@ -265,6 +265,7 @@ static void acm_ctrl_irq(struct urb *urb) | |||
265 | { | 265 | { |
266 | struct acm *acm = urb->context; | 266 | struct acm *acm = urb->context; |
267 | struct usb_cdc_notification *dr = urb->transfer_buffer; | 267 | struct usb_cdc_notification *dr = urb->transfer_buffer; |
268 | struct tty_struct *tty; | ||
268 | unsigned char *data; | 269 | unsigned char *data; |
269 | int newctrl; | 270 | int newctrl; |
270 | int retval; | 271 | int retval; |
@@ -297,12 +298,16 @@ static void acm_ctrl_irq(struct urb *urb) | |||
297 | break; | 298 | break; |
298 | 299 | ||
299 | case USB_CDC_NOTIFY_SERIAL_STATE: | 300 | case USB_CDC_NOTIFY_SERIAL_STATE: |
300 | 301 | tty = tty_port_tty_get(&acm->port); | |
301 | newctrl = get_unaligned_le16(data); | 302 | newctrl = get_unaligned_le16(data); |
302 | 303 | ||
303 | if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { | 304 | if (tty) { |
304 | dbg("calling hangup"); | 305 | if (!acm->clocal && |
305 | tty_hangup(acm->tty); | 306 | (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { |
307 | dbg("calling hangup"); | ||
308 | tty_hangup(tty); | ||
309 | } | ||
310 | tty_kref_put(tty); | ||
306 | } | 311 | } |
307 | 312 | ||
308 | acm->ctrlin = newctrl; | 313 | acm->ctrlin = newctrl; |
@@ -374,15 +379,14 @@ static void acm_rx_tasklet(unsigned long _acm) | |||
374 | { | 379 | { |
375 | struct acm *acm = (void *)_acm; | 380 | struct acm *acm = (void *)_acm; |
376 | struct acm_rb *buf; | 381 | struct acm_rb *buf; |
377 | struct tty_struct *tty = acm->tty; | 382 | struct tty_struct *tty; |
378 | struct acm_ru *rcv; | 383 | struct acm_ru *rcv; |
379 | unsigned long flags; | 384 | unsigned long flags; |
380 | unsigned char throttled; | 385 | unsigned char throttled; |
381 | 386 | ||
382 | dbg("Entering acm_rx_tasklet"); | 387 | dbg("Entering acm_rx_tasklet"); |
383 | 388 | ||
384 | if (!ACM_READY(acm)) | 389 | if (!ACM_READY(acm)) { |
385 | { | ||
386 | dbg("acm_rx_tasklet: ACM not ready"); | 390 | dbg("acm_rx_tasklet: ACM not ready"); |
387 | return; | 391 | return; |
388 | } | 392 | } |
@@ -390,12 +394,13 @@ static void acm_rx_tasklet(unsigned long _acm) | |||
390 | spin_lock_irqsave(&acm->throttle_lock, flags); | 394 | spin_lock_irqsave(&acm->throttle_lock, flags); |
391 | throttled = acm->throttle; | 395 | throttled = acm->throttle; |
392 | spin_unlock_irqrestore(&acm->throttle_lock, flags); | 396 | spin_unlock_irqrestore(&acm->throttle_lock, flags); |
393 | if (throttled) | 397 | if (throttled) { |
394 | { | ||
395 | dbg("acm_rx_tasklet: throttled"); | 398 | dbg("acm_rx_tasklet: throttled"); |
396 | return; | 399 | return; |
397 | } | 400 | } |
398 | 401 | ||
402 | tty = tty_port_tty_get(&acm->port); | ||
403 | |||
399 | next_buffer: | 404 | next_buffer: |
400 | spin_lock_irqsave(&acm->read_lock, flags); | 405 | spin_lock_irqsave(&acm->read_lock, flags); |
401 | if (list_empty(&acm->filled_read_bufs)) { | 406 | if (list_empty(&acm->filled_read_bufs)) { |
@@ -409,20 +414,22 @@ next_buffer: | |||
409 | 414 | ||
410 | dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size); | 415 | dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size); |
411 | 416 | ||
412 | tty_buffer_request_room(tty, buf->size); | 417 | if (tty) { |
413 | spin_lock_irqsave(&acm->throttle_lock, flags); | 418 | spin_lock_irqsave(&acm->throttle_lock, flags); |
414 | throttled = acm->throttle; | 419 | throttled = acm->throttle; |
415 | spin_unlock_irqrestore(&acm->throttle_lock, flags); | 420 | spin_unlock_irqrestore(&acm->throttle_lock, flags); |
416 | if (!throttled) | 421 | if (!throttled) { |
417 | tty_insert_flip_string(tty, buf->base, buf->size); | 422 | tty_buffer_request_room(tty, buf->size); |
418 | tty_flip_buffer_push(tty); | 423 | tty_insert_flip_string(tty, buf->base, buf->size); |
419 | 424 | tty_flip_buffer_push(tty); | |
420 | if (throttled) { | 425 | } else { |
421 | dbg("Throttling noticed"); | 426 | tty_kref_put(tty); |
422 | spin_lock_irqsave(&acm->read_lock, flags); | 427 | dbg("Throttling noticed"); |
423 | list_add(&buf->list, &acm->filled_read_bufs); | 428 | spin_lock_irqsave(&acm->read_lock, flags); |
424 | spin_unlock_irqrestore(&acm->read_lock, flags); | 429 | list_add(&buf->list, &acm->filled_read_bufs); |
425 | return; | 430 | spin_unlock_irqrestore(&acm->read_lock, flags); |
431 | return; | ||
432 | } | ||
426 | } | 433 | } |
427 | 434 | ||
428 | spin_lock_irqsave(&acm->read_lock, flags); | 435 | spin_lock_irqsave(&acm->read_lock, flags); |
@@ -431,6 +438,8 @@ next_buffer: | |||
431 | goto next_buffer; | 438 | goto next_buffer; |
432 | 439 | ||
433 | urbs: | 440 | urbs: |
441 | tty_kref_put(tty); | ||
442 | |||
434 | while (!list_empty(&acm->spare_read_bufs)) { | 443 | while (!list_empty(&acm->spare_read_bufs)) { |
435 | spin_lock_irqsave(&acm->read_lock, flags); | 444 | spin_lock_irqsave(&acm->read_lock, flags); |
436 | if (list_empty(&acm->spare_read_urbs)) { | 445 | if (list_empty(&acm->spare_read_urbs)) { |
@@ -502,11 +511,14 @@ static void acm_write_bulk(struct urb *urb) | |||
502 | static void acm_softint(struct work_struct *work) | 511 | static void acm_softint(struct work_struct *work) |
503 | { | 512 | { |
504 | struct acm *acm = container_of(work, struct acm, work); | 513 | struct acm *acm = container_of(work, struct acm, work); |
514 | struct tty_struct *tty; | ||
505 | 515 | ||
506 | dev_vdbg(&acm->data->dev, "tx work\n"); | 516 | dev_vdbg(&acm->data->dev, "tx work\n"); |
507 | if (!ACM_READY(acm)) | 517 | if (!ACM_READY(acm)) |
508 | return; | 518 | return; |
509 | tty_wakeup(acm->tty); | 519 | tty = tty_port_tty_get(&acm->port); |
520 | tty_wakeup(tty); | ||
521 | tty_kref_put(tty); | ||
510 | } | 522 | } |
511 | 523 | ||
512 | static void acm_waker(struct work_struct *waker) | 524 | static void acm_waker(struct work_struct *waker) |
@@ -546,8 +558,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
546 | rv = 0; | 558 | rv = 0; |
547 | 559 | ||
548 | set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); | 560 | set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); |
561 | |||
549 | tty->driver_data = acm; | 562 | tty->driver_data = acm; |
550 | acm->tty = tty; | 563 | tty_port_tty_set(&acm->port, tty); |
551 | 564 | ||
552 | if (usb_autopm_get_interface(acm->control) < 0) | 565 | if (usb_autopm_get_interface(acm->control) < 0) |
553 | goto early_bail; | 566 | goto early_bail; |
@@ -555,11 +568,10 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
555 | acm->control->needs_remote_wakeup = 1; | 568 | acm->control->needs_remote_wakeup = 1; |
556 | 569 | ||
557 | mutex_lock(&acm->mutex); | 570 | mutex_lock(&acm->mutex); |
558 | if (acm->used++) { | 571 | if (acm->port.count++) { |
559 | usb_autopm_put_interface(acm->control); | 572 | usb_autopm_put_interface(acm->control); |
560 | goto done; | 573 | goto done; |
561 | } | 574 | } |
562 | |||
563 | 575 | ||
564 | acm->ctrlurb->dev = acm->dev; | 576 | acm->ctrlurb->dev = acm->dev; |
565 | if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { | 577 | if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { |
@@ -570,6 +582,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
570 | if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) && | 582 | if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) && |
571 | (acm->ctrl_caps & USB_CDC_CAP_LINE)) | 583 | (acm->ctrl_caps & USB_CDC_CAP_LINE)) |
572 | goto full_bailout; | 584 | goto full_bailout; |
585 | |||
573 | usb_autopm_put_interface(acm->control); | 586 | usb_autopm_put_interface(acm->control); |
574 | 587 | ||
575 | INIT_LIST_HEAD(&acm->spare_read_urbs); | 588 | INIT_LIST_HEAD(&acm->spare_read_urbs); |
@@ -585,7 +598,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
585 | acm->throttle = 0; | 598 | acm->throttle = 0; |
586 | 599 | ||
587 | tasklet_schedule(&acm->urb_task); | 600 | tasklet_schedule(&acm->urb_task); |
588 | 601 | rv = tty_port_block_til_ready(&acm->port, tty, filp); | |
589 | done: | 602 | done: |
590 | mutex_unlock(&acm->mutex); | 603 | mutex_unlock(&acm->mutex); |
591 | err_out: | 604 | err_out: |
@@ -596,16 +609,17 @@ full_bailout: | |||
596 | usb_kill_urb(acm->ctrlurb); | 609 | usb_kill_urb(acm->ctrlurb); |
597 | bail_out: | 610 | bail_out: |
598 | usb_autopm_put_interface(acm->control); | 611 | usb_autopm_put_interface(acm->control); |
599 | acm->used--; | 612 | acm->port.count--; |
600 | mutex_unlock(&acm->mutex); | 613 | mutex_unlock(&acm->mutex); |
601 | early_bail: | 614 | early_bail: |
602 | mutex_unlock(&open_mutex); | 615 | mutex_unlock(&open_mutex); |
616 | tty_port_tty_set(&acm->port, NULL); | ||
603 | return -EIO; | 617 | return -EIO; |
604 | } | 618 | } |
605 | 619 | ||
606 | static void acm_tty_unregister(struct acm *acm) | 620 | static void acm_tty_unregister(struct acm *acm) |
607 | { | 621 | { |
608 | int i,nr; | 622 | int i, nr; |
609 | 623 | ||
610 | nr = acm->rx_buflimit; | 624 | nr = acm->rx_buflimit; |
611 | tty_unregister_device(acm_tty_driver, acm->minor); | 625 | tty_unregister_device(acm_tty_driver, acm->minor); |
@@ -622,37 +636,51 @@ static void acm_tty_unregister(struct acm *acm) | |||
622 | 636 | ||
623 | static int acm_tty_chars_in_buffer(struct tty_struct *tty); | 637 | static int acm_tty_chars_in_buffer(struct tty_struct *tty); |
624 | 638 | ||
639 | static void acm_port_down(struct acm *acm, int drain) | ||
640 | { | ||
641 | int i, nr = acm->rx_buflimit; | ||
642 | mutex_lock(&open_mutex); | ||
643 | if (acm->dev) { | ||
644 | usb_autopm_get_interface(acm->control); | ||
645 | acm_set_control(acm, acm->ctrlout = 0); | ||
646 | /* try letting the last writes drain naturally */ | ||
647 | if (drain) { | ||
648 | wait_event_interruptible_timeout(acm->drain_wait, | ||
649 | (ACM_NW == acm_wb_is_avail(acm)) || !acm->dev, | ||
650 | ACM_CLOSE_TIMEOUT * HZ); | ||
651 | } | ||
652 | usb_kill_urb(acm->ctrlurb); | ||
653 | for (i = 0; i < ACM_NW; i++) | ||
654 | usb_kill_urb(acm->wb[i].urb); | ||
655 | for (i = 0; i < nr; i++) | ||
656 | usb_kill_urb(acm->ru[i].urb); | ||
657 | acm->control->needs_remote_wakeup = 0; | ||
658 | usb_autopm_put_interface(acm->control); | ||
659 | } | ||
660 | mutex_unlock(&open_mutex); | ||
661 | } | ||
662 | |||
663 | static void acm_tty_hangup(struct tty_struct *tty) | ||
664 | { | ||
665 | struct acm *acm = tty->driver_data; | ||
666 | tty_port_hangup(&acm->port); | ||
667 | acm_port_down(acm, 0); | ||
668 | } | ||
669 | |||
625 | static void acm_tty_close(struct tty_struct *tty, struct file *filp) | 670 | static void acm_tty_close(struct tty_struct *tty, struct file *filp) |
626 | { | 671 | { |
627 | struct acm *acm = tty->driver_data; | 672 | struct acm *acm = tty->driver_data; |
628 | int i,nr; | ||
629 | 673 | ||
630 | if (!acm || !acm->used) | 674 | /* Perform the closing process and see if we need to do the hardware |
675 | shutdown */ | ||
676 | if (tty_port_close_start(&acm->port, tty, filp) == 0) | ||
631 | return; | 677 | return; |
632 | 678 | acm_port_down(acm, 0); | |
633 | nr = acm->rx_buflimit; | 679 | tty_port_close_end(&acm->port, tty); |
634 | mutex_lock(&open_mutex); | 680 | mutex_lock(&open_mutex); |
635 | if (!--acm->used) { | 681 | tty_port_tty_set(&acm->port, NULL); |
636 | if (acm->dev) { | 682 | if (!acm->dev) |
637 | usb_autopm_get_interface(acm->control); | 683 | acm_tty_unregister(acm); |
638 | acm_set_control(acm, acm->ctrlout = 0); | ||
639 | |||
640 | /* try letting the last writes drain naturally */ | ||
641 | wait_event_interruptible_timeout(acm->drain_wait, | ||
642 | (ACM_NW == acm_wb_is_avail(acm)) | ||
643 | || !acm->dev, | ||
644 | ACM_CLOSE_TIMEOUT * HZ); | ||
645 | |||
646 | usb_kill_urb(acm->ctrlurb); | ||
647 | for (i = 0; i < ACM_NW; i++) | ||
648 | usb_kill_urb(acm->wb[i].urb); | ||
649 | for (i = 0; i < nr; i++) | ||
650 | usb_kill_urb(acm->ru[i].urb); | ||
651 | acm->control->needs_remote_wakeup = 0; | ||
652 | usb_autopm_put_interface(acm->control); | ||
653 | } else | ||
654 | acm_tty_unregister(acm); | ||
655 | } | ||
656 | mutex_unlock(&open_mutex); | 684 | mutex_unlock(&open_mutex); |
657 | } | 685 | } |
658 | 686 | ||
@@ -885,8 +913,8 @@ static int acm_write_buffers_alloc(struct acm *acm) | |||
885 | return 0; | 913 | return 0; |
886 | } | 914 | } |
887 | 915 | ||
888 | static int acm_probe (struct usb_interface *intf, | 916 | static int acm_probe(struct usb_interface *intf, |
889 | const struct usb_device_id *id) | 917 | const struct usb_device_id *id) |
890 | { | 918 | { |
891 | struct usb_cdc_union_desc *union_header = NULL; | 919 | struct usb_cdc_union_desc *union_header = NULL; |
892 | struct usb_cdc_country_functional_desc *cfd = NULL; | 920 | struct usb_cdc_country_functional_desc *cfd = NULL; |
@@ -1232,6 +1260,7 @@ static void acm_disconnect(struct usb_interface *intf) | |||
1232 | { | 1260 | { |
1233 | struct acm *acm = usb_get_intfdata(intf); | 1261 | struct acm *acm = usb_get_intfdata(intf); |
1234 | struct usb_device *usb_dev = interface_to_usbdev(intf); | 1262 | struct usb_device *usb_dev = interface_to_usbdev(intf); |
1263 | struct tty_struct *tty; | ||
1235 | 1264 | ||
1236 | /* sibling interface is already cleaning up */ | 1265 | /* sibling interface is already cleaning up */ |
1237 | if (!acm) | 1266 | if (!acm) |
@@ -1258,16 +1287,18 @@ static void acm_disconnect(struct usb_interface *intf) | |||
1258 | usb_driver_release_interface(&acm_driver, intf == acm->control ? | 1287 | usb_driver_release_interface(&acm_driver, intf == acm->control ? |
1259 | acm->data : acm->control); | 1288 | acm->data : acm->control); |
1260 | 1289 | ||
1261 | if (!acm->used) { | 1290 | if (acm->port.count == 0) { |
1262 | acm_tty_unregister(acm); | 1291 | acm_tty_unregister(acm); |
1263 | mutex_unlock(&open_mutex); | 1292 | mutex_unlock(&open_mutex); |
1264 | return; | 1293 | return; |
1265 | } | 1294 | } |
1266 | 1295 | ||
1267 | mutex_unlock(&open_mutex); | 1296 | mutex_unlock(&open_mutex); |
1268 | 1297 | tty = tty_port_tty_get(&acm->port); | |
1269 | if (acm->tty) | 1298 | if (tty) { |
1270 | tty_hangup(acm->tty); | 1299 | tty_hangup(tty); |
1300 | tty_kref_put(tty); | ||
1301 | } | ||
1271 | } | 1302 | } |
1272 | 1303 | ||
1273 | #ifdef CONFIG_PM | 1304 | #ifdef CONFIG_PM |
@@ -1302,7 +1333,7 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message) | |||
1302 | */ | 1333 | */ |
1303 | mutex_lock(&acm->mutex); | 1334 | mutex_lock(&acm->mutex); |
1304 | 1335 | ||
1305 | if (acm->used) | 1336 | if (acm->port.count) |
1306 | stop_data_traffic(acm); | 1337 | stop_data_traffic(acm); |
1307 | 1338 | ||
1308 | mutex_unlock(&acm->mutex); | 1339 | mutex_unlock(&acm->mutex); |
@@ -1324,7 +1355,7 @@ static int acm_resume(struct usb_interface *intf) | |||
1324 | return 0; | 1355 | return 0; |
1325 | 1356 | ||
1326 | mutex_lock(&acm->mutex); | 1357 | mutex_lock(&acm->mutex); |
1327 | if (acm->used) { | 1358 | if (acm->port.count) { |
1328 | rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); | 1359 | rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); |
1329 | if (rv < 0) | 1360 | if (rv < 0) |
1330 | goto err_out; | 1361 | goto err_out; |
@@ -1434,6 +1465,7 @@ static struct usb_driver acm_driver = { | |||
1434 | static const struct tty_operations acm_ops = { | 1465 | static const struct tty_operations acm_ops = { |
1435 | .open = acm_tty_open, | 1466 | .open = acm_tty_open, |
1436 | .close = acm_tty_close, | 1467 | .close = acm_tty_close, |
1468 | .hangup = acm_tty_hangup, | ||
1437 | .write = acm_tty_write, | 1469 | .write = acm_tty_write, |
1438 | .write_room = acm_tty_write_room, | 1470 | .write_room = acm_tty_write_room, |
1439 | .ioctl = acm_tty_ioctl, | 1471 | .ioctl = acm_tty_ioctl, |