Commit 10077d4a6674f535abdbe25cdecb1202af7948f1
Committed by
Linus Torvalds
1 parent
b39933fbd3
Exists in
master
and in
7 other branches
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>
Showing 2 changed files with 98 additions and 68 deletions Side-by-side Diff
drivers/usb/class/cdc-acm.c
... | ... | @@ -62,7 +62,7 @@ |
62 | 62 | #include <linux/tty_flip.h> |
63 | 63 | #include <linux/module.h> |
64 | 64 | #include <linux/mutex.h> |
65 | -#include <asm/uaccess.h> | |
65 | +#include <linux/uaccess.h> | |
66 | 66 | #include <linux/usb.h> |
67 | 67 | #include <linux/usb/cdc.h> |
68 | 68 | #include <asm/byteorder.h> |
... | ... | @@ -87,7 +87,7 @@ |
87 | 87 | |
88 | 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 | 92 | static const struct tty_port_operations acm_port_ops = { |
93 | 93 | }; |
... | ... | @@ -265,6 +265,7 @@ |
265 | 265 | { |
266 | 266 | struct acm *acm = urb->context; |
267 | 267 | struct usb_cdc_notification *dr = urb->transfer_buffer; |
268 | + struct tty_struct *tty; | |
268 | 269 | unsigned char *data; |
269 | 270 | int newctrl; |
270 | 271 | int retval; |
271 | 272 | |
... | ... | @@ -297,12 +298,16 @@ |
297 | 298 | break; |
298 | 299 | |
299 | 300 | case USB_CDC_NOTIFY_SERIAL_STATE: |
300 | - | |
301 | + tty = tty_port_tty_get(&acm->port); | |
301 | 302 | newctrl = get_unaligned_le16(data); |
302 | 303 | |
303 | - if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { | |
304 | - dbg("calling hangup"); | |
305 | - tty_hangup(acm->tty); | |
304 | + if (tty) { | |
305 | + if (!acm->clocal && | |
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 | 313 | acm->ctrlin = newctrl; |
309 | 314 | |
... | ... | @@ -374,15 +379,14 @@ |
374 | 379 | { |
375 | 380 | struct acm *acm = (void *)_acm; |
376 | 381 | struct acm_rb *buf; |
377 | - struct tty_struct *tty = acm->tty; | |
382 | + struct tty_struct *tty; | |
378 | 383 | struct acm_ru *rcv; |
379 | 384 | unsigned long flags; |
380 | 385 | unsigned char throttled; |
381 | 386 | |
382 | 387 | dbg("Entering acm_rx_tasklet"); |
383 | 388 | |
384 | - if (!ACM_READY(acm)) | |
385 | - { | |
389 | + if (!ACM_READY(acm)) { | |
386 | 390 | dbg("acm_rx_tasklet: ACM not ready"); |
387 | 391 | return; |
388 | 392 | } |
389 | 393 | |
... | ... | @@ -390,12 +394,13 @@ |
390 | 394 | spin_lock_irqsave(&acm->throttle_lock, flags); |
391 | 395 | throttled = acm->throttle; |
392 | 396 | spin_unlock_irqrestore(&acm->throttle_lock, flags); |
393 | - if (throttled) | |
394 | - { | |
397 | + if (throttled) { | |
395 | 398 | dbg("acm_rx_tasklet: throttled"); |
396 | 399 | return; |
397 | 400 | } |
398 | 401 | |
402 | + tty = tty_port_tty_get(&acm->port); | |
403 | + | |
399 | 404 | next_buffer: |
400 | 405 | spin_lock_irqsave(&acm->read_lock, flags); |
401 | 406 | if (list_empty(&acm->filled_read_bufs)) { |
... | ... | @@ -409,20 +414,22 @@ |
409 | 414 | |
410 | 415 | dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size); |
411 | 416 | |
412 | - tty_buffer_request_room(tty, buf->size); | |
413 | - spin_lock_irqsave(&acm->throttle_lock, flags); | |
414 | - throttled = acm->throttle; | |
415 | - spin_unlock_irqrestore(&acm->throttle_lock, flags); | |
416 | - if (!throttled) | |
417 | - tty_insert_flip_string(tty, buf->base, buf->size); | |
418 | - tty_flip_buffer_push(tty); | |
419 | - | |
420 | - if (throttled) { | |
421 | - dbg("Throttling noticed"); | |
422 | - spin_lock_irqsave(&acm->read_lock, flags); | |
423 | - list_add(&buf->list, &acm->filled_read_bufs); | |
424 | - spin_unlock_irqrestore(&acm->read_lock, flags); | |
425 | - return; | |
417 | + if (tty) { | |
418 | + spin_lock_irqsave(&acm->throttle_lock, flags); | |
419 | + throttled = acm->throttle; | |
420 | + spin_unlock_irqrestore(&acm->throttle_lock, flags); | |
421 | + if (!throttled) { | |
422 | + tty_buffer_request_room(tty, buf->size); | |
423 | + tty_insert_flip_string(tty, buf->base, buf->size); | |
424 | + tty_flip_buffer_push(tty); | |
425 | + } else { | |
426 | + tty_kref_put(tty); | |
427 | + dbg("Throttling noticed"); | |
428 | + spin_lock_irqsave(&acm->read_lock, flags); | |
429 | + list_add(&buf->list, &acm->filled_read_bufs); | |
430 | + spin_unlock_irqrestore(&acm->read_lock, flags); | |
431 | + return; | |
432 | + } | |
426 | 433 | } |
427 | 434 | |
428 | 435 | spin_lock_irqsave(&acm->read_lock, flags); |
... | ... | @@ -431,6 +438,8 @@ |
431 | 438 | goto next_buffer; |
432 | 439 | |
433 | 440 | urbs: |
441 | + tty_kref_put(tty); | |
442 | + | |
434 | 443 | while (!list_empty(&acm->spare_read_bufs)) { |
435 | 444 | spin_lock_irqsave(&acm->read_lock, flags); |
436 | 445 | if (list_empty(&acm->spare_read_urbs)) { |
437 | 446 | |
... | ... | @@ -502,11 +511,14 @@ |
502 | 511 | static void acm_softint(struct work_struct *work) |
503 | 512 | { |
504 | 513 | struct acm *acm = container_of(work, struct acm, work); |
514 | + struct tty_struct *tty; | |
505 | 515 | |
506 | 516 | dev_vdbg(&acm->data->dev, "tx work\n"); |
507 | 517 | if (!ACM_READY(acm)) |
508 | 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 | 524 | static void acm_waker(struct work_struct *waker) |
513 | 525 | |
... | ... | @@ -546,8 +558,9 @@ |
546 | 558 | rv = 0; |
547 | 559 | |
548 | 560 | set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); |
561 | + | |
549 | 562 | tty->driver_data = acm; |
550 | - acm->tty = tty; | |
563 | + tty_port_tty_set(&acm->port, tty); | |
551 | 564 | |
552 | 565 | if (usb_autopm_get_interface(acm->control) < 0) |
553 | 566 | goto early_bail; |
554 | 567 | |
555 | 568 | |
... | ... | @@ -555,12 +568,11 @@ |
555 | 568 | acm->control->needs_remote_wakeup = 1; |
556 | 569 | |
557 | 570 | mutex_lock(&acm->mutex); |
558 | - if (acm->used++) { | |
571 | + if (acm->port.count++) { | |
559 | 572 | usb_autopm_put_interface(acm->control); |
560 | 573 | goto done; |
561 | - } | |
574 | + } | |
562 | 575 | |
563 | - | |
564 | 576 | acm->ctrlurb->dev = acm->dev; |
565 | 577 | if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { |
566 | 578 | dbg("usb_submit_urb(ctrl irq) failed"); |
... | ... | @@ -570,6 +582,7 @@ |
570 | 582 | if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) && |
571 | 583 | (acm->ctrl_caps & USB_CDC_CAP_LINE)) |
572 | 584 | goto full_bailout; |
585 | + | |
573 | 586 | usb_autopm_put_interface(acm->control); |
574 | 587 | |
575 | 588 | INIT_LIST_HEAD(&acm->spare_read_urbs); |
... | ... | @@ -585,7 +598,7 @@ |
585 | 598 | acm->throttle = 0; |
586 | 599 | |
587 | 600 | tasklet_schedule(&acm->urb_task); |
588 | - | |
601 | + rv = tty_port_block_til_ready(&acm->port, tty, filp); | |
589 | 602 | done: |
590 | 603 | mutex_unlock(&acm->mutex); |
591 | 604 | err_out: |
592 | 605 | |
593 | 606 | |
... | ... | @@ -596,16 +609,17 @@ |
596 | 609 | usb_kill_urb(acm->ctrlurb); |
597 | 610 | bail_out: |
598 | 611 | usb_autopm_put_interface(acm->control); |
599 | - acm->used--; | |
612 | + acm->port.count--; | |
600 | 613 | mutex_unlock(&acm->mutex); |
601 | 614 | early_bail: |
602 | 615 | mutex_unlock(&open_mutex); |
616 | + tty_port_tty_set(&acm->port, NULL); | |
603 | 617 | return -EIO; |
604 | 618 | } |
605 | 619 | |
606 | 620 | static void acm_tty_unregister(struct acm *acm) |
607 | 621 | { |
608 | - int i,nr; | |
622 | + int i, nr; | |
609 | 623 | |
610 | 624 | nr = acm->rx_buflimit; |
611 | 625 | tty_unregister_device(acm_tty_driver, acm->minor); |
612 | 626 | |
613 | 627 | |
614 | 628 | |
615 | 629 | |
... | ... | @@ -622,37 +636,51 @@ |
622 | 636 | |
623 | 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 | 670 | static void acm_tty_close(struct tty_struct *tty, struct file *filp) |
626 | 671 | { |
627 | 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 | 677 | return; |
632 | - | |
633 | - nr = acm->rx_buflimit; | |
678 | + acm_port_down(acm, 0); | |
679 | + tty_port_close_end(&acm->port, tty); | |
634 | 680 | mutex_lock(&open_mutex); |
635 | - if (!--acm->used) { | |
636 | - if (acm->dev) { | |
637 | - usb_autopm_get_interface(acm->control); | |
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 | - } | |
681 | + tty_port_tty_set(&acm->port, NULL); | |
682 | + if (!acm->dev) | |
683 | + acm_tty_unregister(acm); | |
656 | 684 | mutex_unlock(&open_mutex); |
657 | 685 | } |
658 | 686 | |
... | ... | @@ -885,8 +913,8 @@ |
885 | 913 | return 0; |
886 | 914 | } |
887 | 915 | |
888 | -static int acm_probe (struct usb_interface *intf, | |
889 | - const struct usb_device_id *id) | |
916 | +static int acm_probe(struct usb_interface *intf, | |
917 | + const struct usb_device_id *id) | |
890 | 918 | { |
891 | 919 | struct usb_cdc_union_desc *union_header = NULL; |
892 | 920 | struct usb_cdc_country_functional_desc *cfd = NULL; |
... | ... | @@ -1232,6 +1260,7 @@ |
1232 | 1260 | { |
1233 | 1261 | struct acm *acm = usb_get_intfdata(intf); |
1234 | 1262 | struct usb_device *usb_dev = interface_to_usbdev(intf); |
1263 | + struct tty_struct *tty; | |
1235 | 1264 | |
1236 | 1265 | /* sibling interface is already cleaning up */ |
1237 | 1266 | if (!acm) |
1238 | 1267 | |
... | ... | @@ -1258,16 +1287,18 @@ |
1258 | 1287 | usb_driver_release_interface(&acm_driver, intf == acm->control ? |
1259 | 1288 | acm->data : acm->control); |
1260 | 1289 | |
1261 | - if (!acm->used) { | |
1290 | + if (acm->port.count == 0) { | |
1262 | 1291 | acm_tty_unregister(acm); |
1263 | 1292 | mutex_unlock(&open_mutex); |
1264 | 1293 | return; |
1265 | 1294 | } |
1266 | 1295 | |
1267 | 1296 | mutex_unlock(&open_mutex); |
1268 | - | |
1269 | - if (acm->tty) | |
1270 | - tty_hangup(acm->tty); | |
1297 | + tty = tty_port_tty_get(&acm->port); | |
1298 | + if (tty) { | |
1299 | + tty_hangup(tty); | |
1300 | + tty_kref_put(tty); | |
1301 | + } | |
1271 | 1302 | } |
1272 | 1303 | |
1273 | 1304 | #ifdef CONFIG_PM |
... | ... | @@ -1302,7 +1333,7 @@ |
1302 | 1333 | */ |
1303 | 1334 | mutex_lock(&acm->mutex); |
1304 | 1335 | |
1305 | - if (acm->used) | |
1336 | + if (acm->port.count) | |
1306 | 1337 | stop_data_traffic(acm); |
1307 | 1338 | |
1308 | 1339 | mutex_unlock(&acm->mutex); |
... | ... | @@ -1324,7 +1355,7 @@ |
1324 | 1355 | return 0; |
1325 | 1356 | |
1326 | 1357 | mutex_lock(&acm->mutex); |
1327 | - if (acm->used) { | |
1358 | + if (acm->port.count) { | |
1328 | 1359 | rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); |
1329 | 1360 | if (rv < 0) |
1330 | 1361 | goto err_out; |
... | ... | @@ -1434,6 +1465,7 @@ |
1434 | 1465 | static const struct tty_operations acm_ops = { |
1435 | 1466 | .open = acm_tty_open, |
1436 | 1467 | .close = acm_tty_close, |
1468 | + .hangup = acm_tty_hangup, | |
1437 | 1469 | .write = acm_tty_write, |
1438 | 1470 | .write_room = acm_tty_write_room, |
1439 | 1471 | .ioctl = acm_tty_ioctl, |
drivers/usb/class/cdc-acm.h
... | ... | @@ -89,7 +89,6 @@ |
89 | 89 | struct usb_device *dev; /* the corresponding usb device */ |
90 | 90 | struct usb_interface *control; /* control interface */ |
91 | 91 | struct usb_interface *data; /* data interface */ |
92 | - struct tty_struct *tty; /* the corresponding tty */ | |
93 | 92 | struct tty_port port; /* our tty port data */ |
94 | 93 | struct urb *ctrlurb; /* urbs */ |
95 | 94 | u8 *ctrl_buffer; /* buffers of urbs */ |
... | ... | @@ -121,7 +120,6 @@ |
121 | 120 | unsigned int ctrlout; /* output control lines (DTR, RTS) */ |
122 | 121 | unsigned int writesize; /* max packet size for the output bulk endpoint */ |
123 | 122 | unsigned int readsize,ctrlsize; /* buffer sizes for freeing */ |
124 | - unsigned int used; /* someone has this acm's device open */ | |
125 | 123 | unsigned int minor; /* acm minor number */ |
126 | 124 | unsigned char throttle; /* throttled by tty layer */ |
127 | 125 | unsigned char clocal; /* termios CLOCAL */ |