diff options
-rw-r--r-- | drivers/usb/serial/sierra.c | 228 |
1 files changed, 144 insertions, 84 deletions
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 222a6230276b..88ec7bfd9d35 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c | |||
@@ -26,12 +26,10 @@ | |||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/usb.h> | 27 | #include <linux/usb.h> |
28 | #include <linux/usb/serial.h> | 28 | #include <linux/usb/serial.h> |
29 | #include <linux/usb/ch9.h> | ||
30 | 29 | ||
31 | #define SWIMS_USB_REQUEST_SetPower 0x00 | 30 | #define SWIMS_USB_REQUEST_SetPower 0x00 |
32 | #define SWIMS_USB_REQUEST_SetNmea 0x07 | 31 | #define SWIMS_USB_REQUEST_SetNmea 0x07 |
33 | 32 | ||
34 | /* per port private data */ | ||
35 | #define N_IN_URB 4 | 33 | #define N_IN_URB 4 |
36 | #define N_OUT_URB 4 | 34 | #define N_OUT_URB 4 |
37 | #define IN_BUFLEN 4096 | 35 | #define IN_BUFLEN 4096 |
@@ -229,7 +227,6 @@ struct sierra_port_private { | |||
229 | 227 | ||
230 | /* Input endpoints and buffers for this port */ | 228 | /* Input endpoints and buffers for this port */ |
231 | struct urb *in_urbs[N_IN_URB]; | 229 | struct urb *in_urbs[N_IN_URB]; |
232 | char *in_buffer[N_IN_URB]; | ||
233 | 230 | ||
234 | /* Settings for the port */ | 231 | /* Settings for the port */ |
235 | int rts_state; /* Handshaking pins (outputs) */ | 232 | int rts_state; /* Handshaking pins (outputs) */ |
@@ -334,6 +331,17 @@ static int sierra_tiocmset(struct tty_struct *tty, struct file *file, | |||
334 | return sierra_send_setup(port); | 331 | return sierra_send_setup(port); |
335 | } | 332 | } |
336 | 333 | ||
334 | static void sierra_release_urb(struct urb *urb) | ||
335 | { | ||
336 | struct usb_serial_port *port; | ||
337 | if (urb) { | ||
338 | port = urb->context; | ||
339 | dev_dbg(&port->dev, "%s: %p\n", __func__, urb); | ||
340 | kfree(urb->transfer_buffer); | ||
341 | usb_free_urb(urb); | ||
342 | } | ||
343 | } | ||
344 | |||
337 | static void sierra_outdat_callback(struct urb *urb) | 345 | static void sierra_outdat_callback(struct urb *urb) |
338 | { | 346 | { |
339 | struct usb_serial_port *port = urb->context; | 347 | struct usb_serial_port *port = urb->context; |
@@ -458,7 +466,7 @@ static void sierra_indat_callback(struct urb *urb) | |||
458 | " received", __func__); | 466 | " received", __func__); |
459 | 467 | ||
460 | /* Resubmit urb so we continue receiving */ | 468 | /* Resubmit urb so we continue receiving */ |
461 | if (port->port.count && status != -ESHUTDOWN) { | 469 | if (port->port.count && status != -ESHUTDOWN && status != -EPERM) { |
462 | err = usb_submit_urb(urb, GFP_ATOMIC); | 470 | err = usb_submit_urb(urb, GFP_ATOMIC); |
463 | if (err) | 471 | if (err) |
464 | dev_err(&port->dev, "resubmit read urb failed." | 472 | dev_err(&port->dev, "resubmit read urb failed." |
@@ -550,100 +558,184 @@ static int sierra_write_room(struct tty_struct *tty) | |||
550 | return 2048; | 558 | return 2048; |
551 | } | 559 | } |
552 | 560 | ||
553 | static int sierra_open(struct tty_struct *tty, | 561 | static void sierra_stop_rx_urbs(struct usb_serial_port *port) |
554 | struct usb_serial_port *port, struct file *filp) | ||
555 | { | 562 | { |
556 | struct sierra_port_private *portdata; | ||
557 | struct usb_serial *serial = port->serial; | ||
558 | int i; | 563 | int i; |
559 | struct urb *urb; | 564 | struct sierra_port_private *portdata = usb_get_serial_port_data(port); |
560 | int result; | ||
561 | 565 | ||
562 | portdata = usb_get_serial_port_data(port); | 566 | for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) |
567 | usb_kill_urb(portdata->in_urbs[i]); | ||
563 | 568 | ||
564 | dev_dbg(&port->dev, "%s", __func__); | 569 | usb_kill_urb(port->interrupt_in_urb); |
570 | } | ||
565 | 571 | ||
566 | /* Set some sane defaults */ | 572 | static int sierra_submit_rx_urbs(struct usb_serial_port *port, gfp_t mem_flags) |
567 | portdata->rts_state = 1; | 573 | { |
568 | portdata->dtr_state = 1; | 574 | int ok_cnt; |
575 | int err = -EINVAL; | ||
576 | int i; | ||
577 | struct urb *urb; | ||
578 | struct sierra_port_private *portdata = usb_get_serial_port_data(port); | ||
569 | 579 | ||
570 | /* Reset low level data toggle and start reading from endpoints */ | 580 | ok_cnt = 0; |
571 | for (i = 0; i < N_IN_URB; i++) { | 581 | for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) { |
572 | urb = portdata->in_urbs[i]; | 582 | urb = portdata->in_urbs[i]; |
573 | if (!urb) | 583 | if (!urb) |
574 | continue; | 584 | continue; |
575 | if (urb->dev != serial->dev) { | 585 | err = usb_submit_urb(urb, mem_flags); |
576 | dev_dbg(&port->dev, "%s: dev %p != %p", | 586 | if (err) { |
577 | __func__, urb->dev, serial->dev); | 587 | dev_err(&port->dev, "%s: submit urb failed: %d\n", |
578 | continue; | 588 | __func__, err); |
589 | } else { | ||
590 | ok_cnt++; | ||
579 | } | 591 | } |
592 | } | ||
580 | 593 | ||
581 | /* | 594 | if (ok_cnt && port->interrupt_in_urb) { |
582 | * make sure endpoint data toggle is synchronized with the | 595 | err = usb_submit_urb(port->interrupt_in_urb, mem_flags); |
583 | * device | 596 | if (err) { |
584 | */ | 597 | dev_err(&port->dev, "%s: submit intr urb failed: %d\n", |
585 | usb_clear_halt(urb->dev, urb->pipe); | 598 | __func__, err); |
586 | |||
587 | result = usb_submit_urb(urb, GFP_KERNEL); | ||
588 | if (result) { | ||
589 | dev_err(&port->dev, "submit urb %d failed (%d) %d\n", | ||
590 | i, result, urb->transfer_buffer_length); | ||
591 | } | 599 | } |
592 | } | 600 | } |
593 | 601 | ||
594 | sierra_send_setup(port); | 602 | if (ok_cnt > 0) /* at least one rx urb submitted */ |
603 | return 0; | ||
604 | else | ||
605 | return err; | ||
606 | } | ||
607 | |||
608 | static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint, | ||
609 | int dir, void *ctx, int len, | ||
610 | gfp_t mem_flags, | ||
611 | usb_complete_t callback) | ||
612 | { | ||
613 | struct urb *urb; | ||
614 | u8 *buf; | ||
615 | |||
616 | if (endpoint == -1) | ||
617 | return NULL; | ||
595 | 618 | ||
596 | /* start up the interrupt endpoint if we have one */ | 619 | urb = usb_alloc_urb(0, mem_flags); |
597 | if (port->interrupt_in_urb) { | 620 | if (urb == NULL) { |
598 | result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); | 621 | dev_dbg(&serial->dev->dev, "%s: alloc for endpoint %d failed\n", |
599 | if (result) | 622 | __func__, endpoint); |
600 | dev_err(&port->dev, "submit irq_in urb failed %d\n", | 623 | return NULL; |
601 | result); | ||
602 | } | 624 | } |
603 | return 0; | 625 | |
626 | buf = kmalloc(len, mem_flags); | ||
627 | if (buf) { | ||
628 | /* Fill URB using supplied data */ | ||
629 | usb_fill_bulk_urb(urb, serial->dev, | ||
630 | usb_sndbulkpipe(serial->dev, endpoint) | dir, | ||
631 | buf, len, callback, ctx); | ||
632 | |||
633 | /* debug */ | ||
634 | dev_dbg(&serial->dev->dev, "%s %c u : %p d:%p\n", __func__, | ||
635 | dir == USB_DIR_IN ? 'i' : 'o', urb, buf); | ||
636 | } else { | ||
637 | dev_dbg(&serial->dev->dev, "%s %c u:%p d:%p\n", __func__, | ||
638 | dir == USB_DIR_IN ? 'i' : 'o', urb, buf); | ||
639 | |||
640 | sierra_release_urb(urb); | ||
641 | urb = NULL; | ||
642 | } | ||
643 | |||
644 | return urb; | ||
604 | } | 645 | } |
605 | 646 | ||
606 | static void sierra_dtr_rts(struct usb_serial_port *port, int on) | 647 | static void sierra_close(struct usb_serial_port *port) |
607 | { | 648 | { |
649 | int i; | ||
608 | struct usb_serial *serial = port->serial; | 650 | struct usb_serial *serial = port->serial; |
609 | struct sierra_port_private *portdata; | 651 | struct sierra_port_private *portdata; |
610 | 652 | ||
653 | dev_dbg(&port->dev, "%s\n", __func__); | ||
611 | portdata = usb_get_serial_port_data(port); | 654 | portdata = usb_get_serial_port_data(port); |
612 | portdata->rts_state = on; | 655 | |
613 | portdata->dtr_state = on; | 656 | portdata->rts_state = 0; |
657 | portdata->dtr_state = 0; | ||
614 | 658 | ||
615 | if (serial->dev) { | 659 | if (serial->dev) { |
616 | mutex_lock(&serial->disc_mutex); | 660 | mutex_lock(&serial->disc_mutex); |
617 | if (!serial->disconnected) | 661 | if (!serial->disconnected) |
618 | sierra_send_setup(port); | 662 | sierra_send_setup(port); |
619 | mutex_unlock(&serial->disc_mutex); | 663 | mutex_unlock(&serial->disc_mutex); |
664 | |||
665 | /* Stop reading urbs */ | ||
666 | sierra_stop_rx_urbs(port); | ||
667 | /* .. and release them */ | ||
668 | for (i = 0; i < N_IN_URB; i++) { | ||
669 | sierra_release_urb(portdata->in_urbs[i]); | ||
670 | portdata->in_urbs[i] = NULL; | ||
671 | } | ||
620 | } | 672 | } |
621 | } | 673 | } |
622 | 674 | ||
623 | static void sierra_close(struct usb_serial_port *port) | 675 | static int sierra_open(struct tty_struct *tty, |
676 | struct usb_serial_port *port, struct file *filp) | ||
624 | { | 677 | { |
678 | struct sierra_port_private *portdata; | ||
679 | struct usb_serial *serial = port->serial; | ||
625 | int i; | 680 | int i; |
681 | int err; | ||
682 | int endpoint; | ||
683 | struct urb *urb; | ||
684 | |||
685 | portdata = usb_get_serial_port_data(port); | ||
686 | |||
687 | dev_dbg(&port->dev, "%s", __func__); | ||
688 | |||
689 | /* Set some sane defaults */ | ||
690 | portdata->rts_state = 1; | ||
691 | portdata->dtr_state = 1; | ||
692 | |||
693 | |||
694 | endpoint = port->bulk_in_endpointAddress; | ||
695 | for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) { | ||
696 | urb = sierra_setup_urb(serial, endpoint, USB_DIR_IN, port, | ||
697 | IN_BUFLEN, GFP_KERNEL, | ||
698 | sierra_indat_callback); | ||
699 | portdata->in_urbs[i] = urb; | ||
700 | } | ||
701 | /* clear halt condition */ | ||
702 | usb_clear_halt(serial->dev, | ||
703 | usb_sndbulkpipe(serial->dev, endpoint) | USB_DIR_IN); | ||
704 | |||
705 | err = sierra_submit_rx_urbs(port, GFP_KERNEL); | ||
706 | if (err) { | ||
707 | /* get rid of everything as in close */ | ||
708 | sierra_close(port); | ||
709 | return err; | ||
710 | } | ||
711 | sierra_send_setup(port); | ||
712 | |||
713 | return 0; | ||
714 | } | ||
715 | |||
716 | |||
717 | static void sierra_dtr_rts(struct usb_serial_port *port, int on) | ||
718 | { | ||
626 | struct usb_serial *serial = port->serial; | 719 | struct usb_serial *serial = port->serial; |
627 | struct sierra_port_private *portdata; | 720 | struct sierra_port_private *portdata; |
628 | 721 | ||
629 | dev_dbg(&port->dev, "%s", __func__); | ||
630 | portdata = usb_get_serial_port_data(port); | 722 | portdata = usb_get_serial_port_data(port); |
723 | portdata->rts_state = on; | ||
724 | portdata->dtr_state = on; | ||
631 | 725 | ||
632 | if (serial->dev) { | 726 | if (serial->dev) { |
633 | /* Stop reading/writing urbs */ | 727 | mutex_lock(&serial->disc_mutex); |
634 | for (i = 0; i < N_IN_URB; i++) | 728 | if (!serial->disconnected) |
635 | usb_kill_urb(portdata->in_urbs[i]); | 729 | sierra_send_setup(port); |
730 | mutex_unlock(&serial->disc_mutex); | ||
636 | } | 731 | } |
637 | usb_kill_urb(port->interrupt_in_urb); | ||
638 | } | 732 | } |
639 | 733 | ||
640 | static int sierra_startup(struct usb_serial *serial) | 734 | static int sierra_startup(struct usb_serial *serial) |
641 | { | 735 | { |
642 | struct usb_serial_port *port; | 736 | struct usb_serial_port *port; |
643 | struct sierra_port_private *portdata; | 737 | struct sierra_port_private *portdata; |
644 | struct urb *urb; | ||
645 | int i; | 738 | int i; |
646 | int j; | ||
647 | 739 | ||
648 | dev_dbg(&serial->dev->dev, "%s", __func__); | 740 | dev_dbg(&serial->dev->dev, "%s", __func__); |
649 | 741 | ||
@@ -665,34 +757,8 @@ static int sierra_startup(struct usb_serial *serial) | |||
665 | return -ENOMEM; | 757 | return -ENOMEM; |
666 | } | 758 | } |
667 | spin_lock_init(&portdata->lock); | 759 | spin_lock_init(&portdata->lock); |
668 | for (j = 0; j < N_IN_URB; j++) { | 760 | /* Set the port private data pointer */ |
669 | portdata->in_buffer[j] = kmalloc(IN_BUFLEN, GFP_KERNEL); | ||
670 | if (!portdata->in_buffer[j]) { | ||
671 | for (--j; j >= 0; j--) | ||
672 | kfree(portdata->in_buffer[j]); | ||
673 | kfree(portdata); | ||
674 | return -ENOMEM; | ||
675 | } | ||
676 | } | ||
677 | |||
678 | usb_set_serial_port_data(port, portdata); | 761 | usb_set_serial_port_data(port, portdata); |
679 | |||
680 | /* initialize the in urbs */ | ||
681 | for (j = 0; j < N_IN_URB; ++j) { | ||
682 | urb = usb_alloc_urb(0, GFP_KERNEL); | ||
683 | if (urb == NULL) { | ||
684 | dev_dbg(&port->dev, "%s: alloc for in " | ||
685 | "port failed.", __func__); | ||
686 | continue; | ||
687 | } | ||
688 | /* Fill URB using supplied data. */ | ||
689 | usb_fill_bulk_urb(urb, serial->dev, | ||
690 | usb_rcvbulkpipe(serial->dev, | ||
691 | port->bulk_in_endpointAddress), | ||
692 | portdata->in_buffer[j], IN_BUFLEN, | ||
693 | sierra_indat_callback, port); | ||
694 | portdata->in_urbs[j] = urb; | ||
695 | } | ||
696 | } | 762 | } |
697 | 763 | ||
698 | return 0; | 764 | return 0; |
@@ -700,7 +766,7 @@ static int sierra_startup(struct usb_serial *serial) | |||
700 | 766 | ||
701 | static void sierra_shutdown(struct usb_serial *serial) | 767 | static void sierra_shutdown(struct usb_serial *serial) |
702 | { | 768 | { |
703 | int i, j; | 769 | int i; |
704 | struct usb_serial_port *port; | 770 | struct usb_serial_port *port; |
705 | struct sierra_port_private *portdata; | 771 | struct sierra_port_private *portdata; |
706 | 772 | ||
@@ -713,12 +779,6 @@ static void sierra_shutdown(struct usb_serial *serial) | |||
713 | portdata = usb_get_serial_port_data(port); | 779 | portdata = usb_get_serial_port_data(port); |
714 | if (!portdata) | 780 | if (!portdata) |
715 | continue; | 781 | continue; |
716 | |||
717 | for (j = 0; j < N_IN_URB; j++) { | ||
718 | usb_kill_urb(portdata->in_urbs[j]); | ||
719 | usb_free_urb(portdata->in_urbs[j]); | ||
720 | kfree(portdata->in_buffer[j]); | ||
721 | } | ||
722 | kfree(portdata); | 782 | kfree(portdata); |
723 | usb_set_serial_port_data(port, NULL); | 783 | usb_set_serial_port_data(port, NULL); |
724 | } | 784 | } |