aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/sierra.c
diff options
context:
space:
mode:
authorElina Pasheva <epasheva@sierrawireless.com>2009-06-11 09:30:21 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-11 11:51:07 -0400
commitb9a44bc19f48fd82b8f411500a9bb0ea4153d23c (patch)
tree4471763f807213de8dd04036150c8a3963429d03 /drivers/usb/serial/sierra.c
parent00b040deca907a113f5bef67a6cc7a4f65a5ace9 (diff)
sierra: driver urb handling improvements
[Folded from eight patches into one as the original set according to the author "All of the patches need to be applied to obtain a working product" so keeping them split seems unhelpful Merge fixes done versus other conflicting changes and moved the spin_lock_init from open to setup time -- Alan] Summary of the changes and code re-organization in this patch: - The memory for urbs is allocated and urbs are submitted only for the active interfaces (instead of pre-allocating these for all interfaces). This will save memory especially in the case of using composite devices. - The code has been re-organized and functionality has been extracted from sierra_startup(), sierra_shutdown(), sierra_open(), sierra_close() and added in helper functions sierra_release_urb(), sierra_stop_rx_urbs(), sierra_submit_rx_urbs() and sierra_setup_urb() - Added function sierra_release_urb() to free an urb and its transfer buffer. - Removed unecessary include file reference and comment. - Added function sierra_stop_rx_urbs() that takes care of the release of receive and interrupt urbs. This function is to be called by sierra_close() whenever an interface is de-activated. - Added new function sierra_submit_rx_urbs() that handles the submission of receive urbs and interrupt urbs (if any) during the interface activation. This function is to be called by sierra_open(). Added a second parameter to pass the memory allocation (as suggested by Oliver Neukum) so that this function can be used in post_reset() and resume(). - Added new function sierra_setup_urb() that contains the functionality to allocate an urb, fill bulk urb using the supplied memory allocation flag and release urb upon error. Added parameter so that the caller pass the memory allocation flag for flexibility. - Moved sierra_close() before sierra_open() to resolve dependencies introduced by the code reorganization. - Modified sierra_close() to call sierra_stop_rx_urbs() and sierra_release_urb() functions added in previous patch. - Modified sierra_open() to call sierra_setup_urb() and sierra_submit_rx_urbs() functions; note urbs are allocated and submitted for each activated interface. - Modified sierra_startup() so that allocation of urbs happens whenever an interface is activated (urb allocation is moved to sierra_open()). - Modified sierra_shutdown() so that urbs are freed whenever an interface is de-activated (urb freeing moved to sierra_close() as shown in previous patch from the series) - Removed unecessary data structure from sierra_port_private_data - Suppress an entry in logs by not re-submitting an urb when usb_submit_urb() returns -EPERM, as this shows that usb_kill_urb() is running (as suggested by Oliver Neukum) Signed-off-by: Elina Pasheva <epasheva@sierrawireless.com> Signed-off-by: Alan Cox <alan.cox@linux.intel.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/usb/serial/sierra.c')
-rw-r--r--drivers/usb/serial/sierra.c228
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
334static 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
337static void sierra_outdat_callback(struct urb *urb) 345static 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
553static int sierra_open(struct tty_struct *tty, 561static 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 */ 572static 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
608static 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
606static void sierra_dtr_rts(struct usb_serial_port *port, int on) 647static 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
623static void sierra_close(struct usb_serial_port *port) 675static 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
717static 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
640static int sierra_startup(struct usb_serial *serial) 734static 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
701static void sierra_shutdown(struct usb_serial *serial) 767static 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 }