aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn
diff options
context:
space:
mode:
authorTilman Schmidt <tilman@imap.cc>2008-02-06 04:38:26 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-06 13:41:11 -0500
commit024fd299ba6e933055fccf1bb1cc2e7bdc58bde6 (patch)
tree1cb59fb034b9e5a22621d6387b9c8ec317e7be76 /drivers/isdn
parentc652cbd8ee114307baab072e4e560dce5c5fb12a (diff)
bas_gigaset: suspend support
Add basic suspend/resume support to the bas_gigaset ISDN driver for the Siemens Gigaset SX255 series of ISDN DECT bases. Only the USB aspects are handled so far; the ISDN subsystem is not notified in any way, for lack of information about how to do that. The driver will refuse to suspend if a connection is active. Signed-off-by: Tilman Schmidt <tilman@imap.cc> Cc: Greg KH <gregkh@suse.de> Cc: Hansjoerg Lipp <hjlipp@web.de> Cc: Karsten Keil <kkeil@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/isdn')
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c166
1 files changed, 164 insertions, 2 deletions
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index d60a6510e92b..1c401b3f88e1 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -73,6 +73,14 @@ static int gigaset_probe(struct usb_interface *interface,
73/* Function will be called if the device is unplugged */ 73/* Function will be called if the device is unplugged */
74static void gigaset_disconnect(struct usb_interface *interface); 74static void gigaset_disconnect(struct usb_interface *interface);
75 75
76/* functions called before/after suspend */
77static int gigaset_suspend(struct usb_interface *intf, pm_message_t message);
78static int gigaset_resume(struct usb_interface *intf);
79
80/* functions called before/after device reset */
81static int gigaset_pre_reset(struct usb_interface *intf);
82static int gigaset_post_reset(struct usb_interface *intf);
83
76static int atread_submit(struct cardstate *, int); 84static int atread_submit(struct cardstate *, int);
77static void stopurbs(struct bas_bc_state *); 85static void stopurbs(struct bas_bc_state *);
78static int req_submit(struct bc_state *, int, int, int); 86static int req_submit(struct bc_state *, int, int, int);
@@ -107,6 +115,7 @@ struct bas_cardstate {
107 spinlock_t lock; /* locks all following */ 115 spinlock_t lock; /* locks all following */
108 atomic_t basstate; /* bitmap (BS_*) */ 116 atomic_t basstate; /* bitmap (BS_*) */
109 int pending; /* uncompleted base request */ 117 int pending; /* uncompleted base request */
118 wait_queue_head_t waitqueue;
110 int rcvbuf_size; /* size of AT receive buffer */ 119 int rcvbuf_size; /* size of AT receive buffer */
111 /* 0: no receive in progress */ 120 /* 0: no receive in progress */
112 int retry_cmd_in; /* receive req retry count */ 121 int retry_cmd_in; /* receive req retry count */
@@ -121,6 +130,7 @@ struct bas_cardstate {
121#define BS_ATTIMER 0x020 /* waiting for HD_READY_SEND_ATDATA */ 130#define BS_ATTIMER 0x020 /* waiting for HD_READY_SEND_ATDATA */
122#define BS_ATRDPEND 0x040 /* urb_cmd_in in use */ 131#define BS_ATRDPEND 0x040 /* urb_cmd_in in use */
123#define BS_ATWRPEND 0x080 /* urb_cmd_out in use */ 132#define BS_ATWRPEND 0x080 /* urb_cmd_out in use */
133#define BS_SUSPEND 0x100 /* USB port suspended */
124 134
125 135
126static struct gigaset_driver *driver = NULL; 136static struct gigaset_driver *driver = NULL;
@@ -132,6 +142,11 @@ static struct usb_driver gigaset_usb_driver = {
132 .probe = gigaset_probe, 142 .probe = gigaset_probe,
133 .disconnect = gigaset_disconnect, 143 .disconnect = gigaset_disconnect,
134 .id_table = gigaset_table, 144 .id_table = gigaset_table,
145 .suspend = gigaset_suspend,
146 .resume = gigaset_resume,
147 .reset_resume = gigaset_post_reset,
148 .pre_reset = gigaset_pre_reset,
149 .post_reset = gigaset_post_reset,
135}; 150};
136 151
137/* get message text for usb_submit_urb return code 152/* get message text for usb_submit_urb return code
@@ -465,6 +480,7 @@ static void read_ctrl_callback(struct urb *urb)
465 int rc; 480 int rc;
466 481
467 update_basstate(ucs, 0, BS_ATRDPEND); 482 update_basstate(ucs, 0, BS_ATRDPEND);
483 wake_up(&ucs->waitqueue);
468 484
469 if (!ucs->rcvbuf_size) { 485 if (!ucs->rcvbuf_size) {
470 dev_warn(cs->dev, "%s: no receive in progress\n", __func__); 486 dev_warn(cs->dev, "%s: no receive in progress\n", __func__);
@@ -551,17 +567,28 @@ static void read_ctrl_callback(struct urb *urb)
551static int atread_submit(struct cardstate *cs, int timeout) 567static int atread_submit(struct cardstate *cs, int timeout)
552{ 568{
553 struct bas_cardstate *ucs = cs->hw.bas; 569 struct bas_cardstate *ucs = cs->hw.bas;
570 int basstate;
554 int ret; 571 int ret;
555 572
556 gig_dbg(DEBUG_USBREQ, "-------> HD_READ_ATMESSAGE (%d)", 573 gig_dbg(DEBUG_USBREQ, "-------> HD_READ_ATMESSAGE (%d)",
557 ucs->rcvbuf_size); 574 ucs->rcvbuf_size);
558 575
559 if (update_basstate(ucs, BS_ATRDPEND, 0) & BS_ATRDPEND) { 576 basstate = update_basstate(ucs, BS_ATRDPEND, 0);
577 if (basstate & BS_ATRDPEND) {
560 dev_err(cs->dev, 578 dev_err(cs->dev,
561 "could not submit HD_READ_ATMESSAGE: URB busy\n"); 579 "could not submit HD_READ_ATMESSAGE: URB busy\n");
562 return -EBUSY; 580 return -EBUSY;
563 } 581 }
564 582
583 if (basstate & BS_SUSPEND) {
584 dev_notice(cs->dev,
585 "HD_READ_ATMESSAGE not submitted, "
586 "suspend in progress\n");
587 update_basstate(ucs, 0, BS_ATRDPEND);
588 /* treat like disconnect */
589 return -ENODEV;
590 }
591
565 ucs->dr_cmd_in.bRequestType = IN_VENDOR_REQ; 592 ucs->dr_cmd_in.bRequestType = IN_VENDOR_REQ;
566 ucs->dr_cmd_in.bRequest = HD_READ_ATMESSAGE; 593 ucs->dr_cmd_in.bRequest = HD_READ_ATMESSAGE;
567 ucs->dr_cmd_in.wValue = 0; 594 ucs->dr_cmd_in.wValue = 0;
@@ -747,6 +774,7 @@ static void read_int_callback(struct urb *urb)
747 } 774 }
748 775
749 check_pending(ucs); 776 check_pending(ucs);
777 wake_up(&ucs->waitqueue);
750 778
751resubmit: 779resubmit:
752 rc = usb_submit_urb(urb, GFP_ATOMIC); 780 rc = usb_submit_urb(urb, GFP_ATOMIC);
@@ -1416,6 +1444,8 @@ static void req_timeout(unsigned long data)
1416 dev_warn(bcs->cs->dev, "request 0x%02x timed out, clearing\n", 1444 dev_warn(bcs->cs->dev, "request 0x%02x timed out, clearing\n",
1417 pending); 1445 pending);
1418 } 1446 }
1447
1448 wake_up(&ucs->waitqueue);
1419} 1449}
1420 1450
1421/* write_ctrl_callback 1451/* write_ctrl_callback
@@ -1456,7 +1486,9 @@ static void write_ctrl_callback(struct urb *urb)
1456 break; 1486 break;
1457 1487
1458 default: /* any failure */ 1488 default: /* any failure */
1459 if (++ucs->retry_ctrl > BAS_RETRY) { 1489 /* don't retry if suspend requested */
1490 if (++ucs->retry_ctrl > BAS_RETRY ||
1491 (atomic_read(&ucs->basstate) & BS_SUSPEND)) {
1460 dev_err(&ucs->interface->dev, 1492 dev_err(&ucs->interface->dev,
1461 "control request 0x%02x failed: %s\n", 1493 "control request 0x%02x failed: %s\n",
1462 ucs->dr_ctrl.bRequest, 1494 ucs->dr_ctrl.bRequest,
@@ -1485,6 +1517,7 @@ static void write_ctrl_callback(struct urb *urb)
1485 del_timer(&ucs->timer_ctrl); 1517 del_timer(&ucs->timer_ctrl);
1486 ucs->pending = 0; 1518 ucs->pending = 0;
1487 spin_unlock_irqrestore(&ucs->lock, flags); 1519 spin_unlock_irqrestore(&ucs->lock, flags);
1520 wake_up(&ucs->waitqueue);
1488} 1521}
1489 1522
1490/* req_submit 1523/* req_submit
@@ -1570,6 +1603,14 @@ static int gigaset_init_bchannel(struct bc_state *bcs)
1570 return -ENODEV; 1603 return -ENODEV;
1571 } 1604 }
1572 1605
1606 if (atomic_read(&cs->hw.bas->basstate) & BS_SUSPEND) {
1607 dev_notice(cs->dev,
1608 "not starting isochronous I/O, "
1609 "suspend in progress\n");
1610 spin_unlock_irqrestore(&cs->lock, flags);
1611 return -EHOSTUNREACH;
1612 }
1613
1573 if ((ret = starturbs(bcs)) < 0) { 1614 if ((ret = starturbs(bcs)) < 0) {
1574 dev_err(cs->dev, 1615 dev_err(cs->dev,
1575 "could not start isochronous I/O for channel B%d: %s\n", 1616 "could not start isochronous I/O for channel B%d: %s\n",
@@ -1682,6 +1723,7 @@ static void write_command_callback(struct urb *urb)
1682 unsigned long flags; 1723 unsigned long flags;
1683 1724
1684 update_basstate(ucs, 0, BS_ATWRPEND); 1725 update_basstate(ucs, 0, BS_ATWRPEND);
1726 wake_up(&ucs->waitqueue);
1685 1727
1686 /* check status */ 1728 /* check status */
1687 switch (status) { 1729 switch (status) {
@@ -1705,6 +1747,13 @@ static void write_command_callback(struct urb *urb)
1705 ucs->retry_cmd_out); 1747 ucs->retry_cmd_out);
1706 break; 1748 break;
1707 } 1749 }
1750 if (atomic_read(&ucs->basstate) & BS_SUSPEND) {
1751 dev_warn(cs->dev,
1752 "command write: %s, "
1753 "won't retry - suspend requested\n",
1754 get_usb_statmsg(status));
1755 break;
1756 }
1708 if (cs->cmdbuf == NULL) { 1757 if (cs->cmdbuf == NULL) {
1709 dev_warn(cs->dev, 1758 dev_warn(cs->dev,
1710 "command write: %s, " 1759 "command write: %s, "
@@ -1813,6 +1862,12 @@ static int start_cbsend(struct cardstate *cs)
1813 int rc; 1862 int rc;
1814 int retval = 0; 1863 int retval = 0;
1815 1864
1865 /* check if suspend requested */
1866 if (atomic_read(&ucs->basstate) & BS_SUSPEND) {
1867 gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "suspending");
1868 return -EHOSTUNREACH;
1869 }
1870
1816 /* check if AT channel is open */ 1871 /* check if AT channel is open */
1817 if (!(atomic_read(&ucs->basstate) & BS_ATOPEN)) { 1872 if (!(atomic_read(&ucs->basstate) & BS_ATOPEN)) {
1818 gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "AT channel not open"); 1873 gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "AT channel not open");
@@ -2099,6 +2154,7 @@ static int gigaset_initcshw(struct cardstate *cs)
2099 init_timer(&ucs->timer_ctrl); 2154 init_timer(&ucs->timer_ctrl);
2100 init_timer(&ucs->timer_atrdy); 2155 init_timer(&ucs->timer_atrdy);
2101 init_timer(&ucs->timer_cmd_in); 2156 init_timer(&ucs->timer_cmd_in);
2157 init_waitqueue_head(&ucs->waitqueue);
2102 2158
2103 return 1; 2159 return 1;
2104} 2160}
@@ -2311,6 +2367,112 @@ static void gigaset_disconnect(struct usb_interface *interface)
2311 gigaset_unassign(cs); 2367 gigaset_unassign(cs);
2312} 2368}
2313 2369
2370/* gigaset_suspend
2371 * This function is called before the USB connection is suspended.
2372 */
2373static int gigaset_suspend(struct usb_interface *intf, pm_message_t message)
2374{
2375 struct cardstate *cs = usb_get_intfdata(intf);
2376 struct bas_cardstate *ucs = cs->hw.bas;
2377 int basstate;
2378 int rc;
2379
2380 /* set suspend flag; this stops AT command/response traffic */
2381 if (update_basstate(ucs, BS_SUSPEND, 0) & BS_SUSPEND) {
2382 gig_dbg(DEBUG_SUSPEND, "already suspended");
2383 return 0;
2384 }
2385
2386 /* wait a bit for blocking conditions to go away */
2387 rc = wait_event_timeout(ucs->waitqueue,
2388 !(atomic_read(&ucs->basstate) &
2389 (BS_B1OPEN|BS_B2OPEN|BS_ATRDPEND|BS_ATWRPEND)),
2390 BAS_TIMEOUT*HZ/10);
2391 gig_dbg(DEBUG_SUSPEND, "wait_event_timeout() -> %d", rc);
2392
2393 /* check for conditions preventing suspend */
2394 basstate = atomic_read(&ucs->basstate);
2395 if (basstate & (BS_B1OPEN|BS_B2OPEN|BS_ATRDPEND|BS_ATWRPEND)) {
2396 dev_warn(cs->dev, "cannot suspend:\n");
2397 if (basstate & BS_B1OPEN)
2398 dev_warn(cs->dev, " B channel 1 open\n");
2399 if (basstate & BS_B2OPEN)
2400 dev_warn(cs->dev, " B channel 2 open\n");
2401 if (basstate & BS_ATRDPEND)
2402 dev_warn(cs->dev, " receiving AT reply\n");
2403 if (basstate & BS_ATWRPEND)
2404 dev_warn(cs->dev, " sending AT command\n");
2405 update_basstate(ucs, 0, BS_SUSPEND);
2406 return -EBUSY;
2407 }
2408
2409 /* close AT channel if open */
2410 if (basstate & BS_ATOPEN) {
2411 gig_dbg(DEBUG_SUSPEND, "closing AT channel");
2412 rc = req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, 0);
2413 if (rc) {
2414 update_basstate(ucs, 0, BS_SUSPEND);
2415 return rc;
2416 }
2417 wait_event_timeout(ucs->waitqueue, !ucs->pending,
2418 BAS_TIMEOUT*HZ/10);
2419 /* in case of timeout, proceed anyway */
2420 }
2421
2422 /* kill all URBs and timers that might still be pending */
2423 usb_kill_urb(ucs->urb_ctrl);
2424 usb_kill_urb(ucs->urb_int_in);
2425 del_timer_sync(&ucs->timer_ctrl);
2426
2427 gig_dbg(DEBUG_SUSPEND, "suspend complete");
2428 return 0;
2429}
2430
2431/* gigaset_resume
2432 * This function is called after the USB connection has been resumed.
2433 */
2434static int gigaset_resume(struct usb_interface *intf)
2435{
2436 struct cardstate *cs = usb_get_intfdata(intf);
2437 struct bas_cardstate *ucs = cs->hw.bas;
2438 int rc;
2439
2440 /* resubmit interrupt URB for spontaneous messages from base */
2441 rc = usb_submit_urb(ucs->urb_int_in, GFP_KERNEL);
2442 if (rc) {
2443 dev_err(cs->dev, "could not resubmit interrupt URB: %s\n",
2444 get_usb_rcmsg(rc));
2445 return rc;
2446 }
2447
2448 /* clear suspend flag to reallow activity */
2449 update_basstate(ucs, 0, BS_SUSPEND);
2450
2451 gig_dbg(DEBUG_SUSPEND, "resume complete");
2452 return 0;
2453}
2454
2455/* gigaset_pre_reset
2456 * This function is called before the USB connection is reset.
2457 */
2458static int gigaset_pre_reset(struct usb_interface *intf)
2459{
2460 /* handle just like suspend */
2461 return gigaset_suspend(intf, PMSG_ON);
2462}
2463
2464/* gigaset_post_reset
2465 * This function is called after the USB connection has been reset.
2466 */
2467static int gigaset_post_reset(struct usb_interface *intf)
2468{
2469 /* FIXME: send HD_DEVICE_INIT_ACK? */
2470
2471 /* resume operations */
2472 return gigaset_resume(intf);
2473}
2474
2475
2314static const struct gigaset_ops gigops = { 2476static const struct gigaset_ops gigops = {
2315 gigaset_write_cmd, 2477 gigaset_write_cmd,
2316 gigaset_write_room, 2478 gigaset_write_room,