aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorOliver Neukum <oliver@neukum.org>2009-09-04 17:19:53 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-09-23 09:46:39 -0400
commite6929a9020acbeb04d9a3ad9a88234c15be808fd (patch)
treecc720f3426c9dc7b0d4d6b4e2fd259fcf0487495 /drivers/usb
parentad45f1dc836cb175e9aeea927837dd48039d652c (diff)
USB: support for autosuspend in sierra while online
This implements support for autosuspend in the sierra driver while online. Remote wakeup is used for reception. Transmission is facilitated with a queue and the asynchronous autopm mechanism. To prevent races a private flag for opened ports and a counter of running transmissions needs to be added. Signed-off-by: Oliver Neukum <oliver@neukum.org> Tested-by: Elina Pasheva <epasheva@sierrawireless.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/serial/sierra.c157
1 files changed, 152 insertions, 5 deletions
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 55391bbe1230..68fa0e43b781 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -51,6 +51,12 @@ struct sierra_iface_info {
51 const u8 *ifaceinfo; /* pointer to the array holding the numbers */ 51 const u8 *ifaceinfo; /* pointer to the array holding the numbers */
52}; 52};
53 53
54struct sierra_intf_private {
55 spinlock_t susp_lock;
56 unsigned int suspended:1;
57 int in_flight;
58};
59
54static int sierra_set_power_state(struct usb_device *udev, __u16 swiState) 60static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
55{ 61{
56 int result; 62 int result;
@@ -144,6 +150,7 @@ static int sierra_probe(struct usb_serial *serial,
144{ 150{
145 int result = 0; 151 int result = 0;
146 struct usb_device *udev; 152 struct usb_device *udev;
153 struct sierra_intf_private *data;
147 u8 ifnum; 154 u8 ifnum;
148 155
149 udev = serial->dev; 156 udev = serial->dev;
@@ -171,6 +178,11 @@ static int sierra_probe(struct usb_serial *serial,
171 return -ENODEV; 178 return -ENODEV;
172 } 179 }
173 180
181 data = serial->private = kzalloc(sizeof(struct sierra_intf_private), GFP_KERNEL);
182 if (!data)
183 return -ENOMEM;
184 spin_lock_init(&data->susp_lock);
185
174 return result; 186 return result;
175} 187}
176 188
@@ -261,13 +273,18 @@ static struct usb_driver sierra_driver = {
261 .name = "sierra", 273 .name = "sierra",
262 .probe = usb_serial_probe, 274 .probe = usb_serial_probe,
263 .disconnect = usb_serial_disconnect, 275 .disconnect = usb_serial_disconnect,
276 .suspend = usb_serial_suspend,
277 .resume = usb_serial_resume,
264 .id_table = id_table, 278 .id_table = id_table,
265 .no_dynamic_id = 1, 279 .no_dynamic_id = 1,
280 .supports_autosuspend = 1,
266}; 281};
267 282
268struct sierra_port_private { 283struct sierra_port_private {
269 spinlock_t lock; /* lock the structure */ 284 spinlock_t lock; /* lock the structure */
270 int outstanding_urbs; /* number of out urbs in flight */ 285 int outstanding_urbs; /* number of out urbs in flight */
286 struct usb_anchor active;
287 struct usb_anchor delayed;
271 288
272 /* Input endpoints and buffers for this port */ 289 /* Input endpoints and buffers for this port */
273 struct urb *in_urbs[N_IN_URB]; 290 struct urb *in_urbs[N_IN_URB];
@@ -279,6 +296,8 @@ struct sierra_port_private {
279 int dsr_state; 296 int dsr_state;
280 int dcd_state; 297 int dcd_state;
281 int ri_state; 298 int ri_state;
299
300 unsigned int opened:1;
282}; 301};
283 302
284static int sierra_send_setup(struct usb_serial_port *port) 303static int sierra_send_setup(struct usb_serial_port *port)
@@ -390,21 +409,25 @@ static void sierra_outdat_callback(struct urb *urb)
390{ 409{
391 struct usb_serial_port *port = urb->context; 410 struct usb_serial_port *port = urb->context;
392 struct sierra_port_private *portdata = usb_get_serial_port_data(port); 411 struct sierra_port_private *portdata = usb_get_serial_port_data(port);
412 struct sierra_intf_private *intfdata;
393 int status = urb->status; 413 int status = urb->status;
394 unsigned long flags;
395 414
396 dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number); 415 dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number);
416 intfdata = port->serial->private;
397 417
398 /* free up the transfer buffer, as usb_free_urb() does not do this */ 418 /* free up the transfer buffer, as usb_free_urb() does not do this */
399 kfree(urb->transfer_buffer); 419 kfree(urb->transfer_buffer);
400 420 usb_autopm_put_interface_async(port->serial->interface);
401 if (status) 421 if (status)
402 dev_dbg(&port->dev, "%s - nonzero write bulk status " 422 dev_dbg(&port->dev, "%s - nonzero write bulk status "
403 "received: %d\n", __func__, status); 423 "received: %d\n", __func__, status);
404 424
405 spin_lock_irqsave(&portdata->lock, flags); 425 spin_lock(&portdata->lock);
406 --portdata->outstanding_urbs; 426 --portdata->outstanding_urbs;
407 spin_unlock_irqrestore(&portdata->lock, flags); 427 spin_unlock(&portdata->lock);
428 spin_lock(&intfdata->susp_lock);
429 --intfdata->in_flight;
430 spin_unlock(&intfdata->susp_lock);
408 431
409 usb_serial_port_softint(port); 432 usb_serial_port_softint(port);
410} 433}
@@ -414,6 +437,7 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port,
414 const unsigned char *buf, int count) 437 const unsigned char *buf, int count)
415{ 438{
416 struct sierra_port_private *portdata = usb_get_serial_port_data(port); 439 struct sierra_port_private *portdata = usb_get_serial_port_data(port);
440 struct sierra_intf_private *intfdata;
417 struct usb_serial *serial = port->serial; 441 struct usb_serial *serial = port->serial;
418 unsigned long flags; 442 unsigned long flags;
419 unsigned char *buffer; 443 unsigned char *buffer;
@@ -426,9 +450,9 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port,
426 return 0; 450 return 0;
427 451
428 portdata = usb_get_serial_port_data(port); 452 portdata = usb_get_serial_port_data(port);
453 intfdata = serial->private;
429 454
430 dev_dbg(&port->dev, "%s: write (%zd bytes)\n", __func__, writesize); 455 dev_dbg(&port->dev, "%s: write (%zd bytes)\n", __func__, writesize);
431
432 spin_lock_irqsave(&portdata->lock, flags); 456 spin_lock_irqsave(&portdata->lock, flags);
433 dev_dbg(&port->dev, "%s - outstanding_urbs: %d\n", __func__, 457 dev_dbg(&port->dev, "%s - outstanding_urbs: %d\n", __func__,
434 portdata->outstanding_urbs); 458 portdata->outstanding_urbs);
@@ -442,6 +466,14 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port,
442 portdata->outstanding_urbs); 466 portdata->outstanding_urbs);
443 spin_unlock_irqrestore(&portdata->lock, flags); 467 spin_unlock_irqrestore(&portdata->lock, flags);
444 468
469 retval = usb_autopm_get_interface_async(serial->interface);
470 if (retval < 0) {
471 spin_lock_irqsave(&portdata->lock, flags);
472 portdata->outstanding_urbs--;
473 spin_unlock_irqrestore(&portdata->lock, flags);
474 goto error_simple;
475 }
476
445 buffer = kmalloc(writesize, GFP_ATOMIC); 477 buffer = kmalloc(writesize, GFP_ATOMIC);
446 if (!buffer) { 478 if (!buffer) {
447 dev_err(&port->dev, "out of memory\n"); 479 dev_err(&port->dev, "out of memory\n");
@@ -468,14 +500,29 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port,
468 /* Handle the need to send a zero length packet */ 500 /* Handle the need to send a zero length packet */
469 urb->transfer_flags |= URB_ZERO_PACKET; 501 urb->transfer_flags |= URB_ZERO_PACKET;
470 502
503 spin_lock_irqsave(&intfdata->susp_lock, flags);
504
505 if (intfdata->suspended) {
506 usb_anchor_urb(urb, &portdata->delayed);
507 spin_unlock_irqrestore(&intfdata->susp_lock, flags);
508 goto skip_power;
509 } else {
510 usb_anchor_urb(urb, &portdata->active);
511 }
471 /* send it down the pipe */ 512 /* send it down the pipe */
472 retval = usb_submit_urb(urb, GFP_ATOMIC); 513 retval = usb_submit_urb(urb, GFP_ATOMIC);
473 if (retval) { 514 if (retval) {
515 usb_unanchor_urb(urb);
516 spin_unlock_irqrestore(&intfdata->susp_lock, flags);
474 dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed " 517 dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed "
475 "with status = %d\n", __func__, retval); 518 "with status = %d\n", __func__, retval);
476 goto error; 519 goto error;
520 } else {
521 intfdata->in_flight++;
522 spin_unlock_irqrestore(&intfdata->susp_lock, flags);
477 } 523 }
478 524
525skip_power:
479 /* we are done with this urb, so let the host driver 526 /* we are done with this urb, so let the host driver
480 * really free it when it is finished with it */ 527 * really free it when it is finished with it */
481 usb_free_urb(urb); 528 usb_free_urb(urb);
@@ -491,6 +538,8 @@ error_no_buffer:
491 dev_dbg(&port->dev, "%s - 2. outstanding_urbs: %d\n", __func__, 538 dev_dbg(&port->dev, "%s - 2. outstanding_urbs: %d\n", __func__,
492 portdata->outstanding_urbs); 539 portdata->outstanding_urbs);
493 spin_unlock_irqrestore(&portdata->lock, flags); 540 spin_unlock_irqrestore(&portdata->lock, flags);
541 usb_autopm_put_interface_async(serial->interface);
542error_simple:
494 return retval; 543 return retval;
495} 544}
496 545
@@ -530,6 +579,7 @@ static void sierra_indat_callback(struct urb *urb)
530 579
531 /* Resubmit urb so we continue receiving */ 580 /* Resubmit urb so we continue receiving */
532 if (port->port.count && status != -ESHUTDOWN && status != -EPERM) { 581 if (port->port.count && status != -ESHUTDOWN && status != -EPERM) {
582 usb_mark_last_busy(port->serial->dev);
533 err = usb_submit_urb(urb, GFP_ATOMIC); 583 err = usb_submit_urb(urb, GFP_ATOMIC);
534 if (err) 584 if (err)
535 dev_err(&port->dev, "resubmit read urb failed." 585 dev_err(&port->dev, "resubmit read urb failed."
@@ -591,6 +641,7 @@ static void sierra_instat_callback(struct urb *urb)
591 641
592 /* Resubmit urb so we continue receiving IRQ data */ 642 /* Resubmit urb so we continue receiving IRQ data */
593 if (port->port.count && status != -ESHUTDOWN && status != -ENOENT) { 643 if (port->port.count && status != -ESHUTDOWN && status != -ENOENT) {
644 usb_mark_last_busy(serial->dev);
594 urb->dev = serial->dev; 645 urb->dev = serial->dev;
595 err = usb_submit_urb(urb, GFP_ATOMIC); 646 err = usb_submit_urb(urb, GFP_ATOMIC);
596 if (err) 647 if (err)
@@ -711,6 +762,8 @@ static void sierra_close(struct usb_serial_port *port)
711 int i; 762 int i;
712 struct usb_serial *serial = port->serial; 763 struct usb_serial *serial = port->serial;
713 struct sierra_port_private *portdata; 764 struct sierra_port_private *portdata;
765 struct sierra_intf_private *intfdata = port->serial->private;
766
714 767
715 dev_dbg(&port->dev, "%s\n", __func__); 768 dev_dbg(&port->dev, "%s\n", __func__);
716 portdata = usb_get_serial_port_data(port); 769 portdata = usb_get_serial_port_data(port);
@@ -723,6 +776,10 @@ static void sierra_close(struct usb_serial_port *port)
723 if (!serial->disconnected) 776 if (!serial->disconnected)
724 sierra_send_setup(port); 777 sierra_send_setup(port);
725 mutex_unlock(&serial->disc_mutex); 778 mutex_unlock(&serial->disc_mutex);
779 spin_lock_irq(&intfdata->susp_lock);
780 portdata->opened = 0;
781 spin_unlock_irq(&intfdata->susp_lock);
782
726 783
727 /* Stop reading urbs */ 784 /* Stop reading urbs */
728 sierra_stop_rx_urbs(port); 785 sierra_stop_rx_urbs(port);
@@ -731,6 +788,8 @@ static void sierra_close(struct usb_serial_port *port)
731 sierra_release_urb(portdata->in_urbs[i]); 788 sierra_release_urb(portdata->in_urbs[i]);
732 portdata->in_urbs[i] = NULL; 789 portdata->in_urbs[i] = NULL;
733 } 790 }
791 usb_autopm_get_interface(serial->interface);
792 serial->interface->needs_remote_wakeup = 0;
734 } 793 }
735} 794}
736 795
@@ -738,6 +797,7 @@ static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port)
738{ 797{
739 struct sierra_port_private *portdata; 798 struct sierra_port_private *portdata;
740 struct usb_serial *serial = port->serial; 799 struct usb_serial *serial = port->serial;
800 struct sierra_intf_private *intfdata = serial->private;
741 int i; 801 int i;
742 int err; 802 int err;
743 int endpoint; 803 int endpoint;
@@ -771,6 +831,12 @@ static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port)
771 } 831 }
772 sierra_send_setup(port); 832 sierra_send_setup(port);
773 833
834 serial->interface->needs_remote_wakeup = 1;
835 spin_lock_irq(&intfdata->susp_lock);
836 portdata->opened = 1;
837 spin_unlock_irq(&intfdata->susp_lock);
838 usb_autopm_put_interface(serial->interface);
839
774 return 0; 840 return 0;
775} 841}
776 842
@@ -818,6 +884,8 @@ static int sierra_startup(struct usb_serial *serial)
818 return -ENOMEM; 884 return -ENOMEM;
819 } 885 }
820 spin_lock_init(&portdata->lock); 886 spin_lock_init(&portdata->lock);
887 init_usb_anchor(&portdata->active);
888 init_usb_anchor(&portdata->delayed);
821 /* Set the port private data pointer */ 889 /* Set the port private data pointer */
822 usb_set_serial_port_data(port, portdata); 890 usb_set_serial_port_data(port, portdata);
823 } 891 }
@@ -844,6 +912,83 @@ static void sierra_release(struct usb_serial *serial)
844 } 912 }
845} 913}
846 914
915static void stop_read_write_urbs(struct usb_serial *serial)
916{
917 int i, j;
918 struct usb_serial_port *port;
919 struct sierra_port_private *portdata;
920
921 /* Stop reading/writing urbs */
922 for (i = 0; i < serial->num_ports; ++i) {
923 port = serial->port[i];
924 portdata = usb_get_serial_port_data(port);
925 for (j = 0; j < N_IN_URB; j++)
926 usb_kill_urb(portdata->in_urbs[j]);
927 usb_kill_anchored_urbs(&portdata->active);
928 }
929}
930
931static int sierra_suspend(struct usb_serial *serial, pm_message_t message)
932{
933 struct sierra_intf_private *intfdata;
934 int b;
935
936 if (serial->dev->auto_pm) {
937 intfdata = serial->private;
938 spin_lock_irq(&intfdata->susp_lock);
939 b = intfdata->in_flight;
940
941 if (b) {
942 spin_unlock_irq(&intfdata->susp_lock);
943 return -EBUSY;
944 } else {
945 intfdata->suspended = 1;
946 spin_unlock_irq(&intfdata->susp_lock);
947 }
948 }
949 stop_read_write_urbs(serial);
950
951 return 0;
952}
953
954static int sierra_resume(struct usb_serial *serial)
955{
956 struct usb_serial_port *port;
957 struct sierra_intf_private *intfdata = serial->private;
958 struct sierra_port_private *portdata;
959 struct urb *urb;
960 int ec = 0;
961 int i, err;
962
963 spin_lock_irq(&intfdata->susp_lock);
964 for (i = 0; i < serial->num_ports; i++) {
965 port = serial->port[i];
966 portdata = usb_get_serial_port_data(port);
967
968 while ((urb = usb_get_from_anchor(&portdata->delayed))) {
969 usb_anchor_urb(urb, &portdata->active);
970 intfdata->in_flight++;
971 err = usb_submit_urb(urb, GFP_ATOMIC);
972 if (err < 0) {
973 intfdata->in_flight--;
974 usb_unanchor_urb(urb);
975 usb_scuttle_anchored_urbs(&portdata->delayed);
976 break;
977 }
978 }
979
980 if (portdata->opened) {
981 err = sierra_submit_rx_urbs(port, GFP_ATOMIC);
982 if (err)
983 ec++;
984 }
985 }
986 intfdata->suspended = 0;
987 spin_unlock_irq(&intfdata->susp_lock);
988
989 return ec ? -EIO : 0;
990}
991
847static struct usb_serial_driver sierra_device = { 992static struct usb_serial_driver sierra_device = {
848 .driver = { 993 .driver = {
849 .owner = THIS_MODULE, 994 .owner = THIS_MODULE,
@@ -864,6 +1009,8 @@ static struct usb_serial_driver sierra_device = {
864 .tiocmset = sierra_tiocmset, 1009 .tiocmset = sierra_tiocmset,
865 .attach = sierra_startup, 1010 .attach = sierra_startup,
866 .release = sierra_release, 1011 .release = sierra_release,
1012 .suspend = sierra_suspend,
1013 .resume = sierra_resume,
867 .read_int_callback = sierra_instat_callback, 1014 .read_int_callback = sierra_instat_callback,
868}; 1015};
869 1016