aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/gigaset/bas-gigaset.c
diff options
context:
space:
mode:
authorTilman Schmidt <tilman@imap.cc>2006-06-26 03:25:33 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-26 12:58:23 -0400
commit06163f86349f0b39948a86d21b2db0d53e47fd8c (patch)
tree09849d7123bed68086e6d576c8518b85f83869b4 /drivers/isdn/gigaset/bas-gigaset.c
parent9f13fae2479ed2e2801d538d6a22309123c704f6 (diff)
[PATCH] isdn4linux: Gigaset base driver: improve error recovery
The following patch to the Siemens Gigaset base driver adds graceful recovery for some frequently encountered error conditions, by retrying failed control requests (eg. stalled control pipe), and by closing and reopening the AT command channel when it appears to be stuck. Signed-off-by: Tilman Schmidt <tilman@imap.cc> Acked-by: Hansjoerg Lipp <hjlipp@web.de> Cc: Karsten Keil <kkeil@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/isdn/gigaset/bas-gigaset.c')
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c298
1 files changed, 181 insertions, 117 deletions
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index eb41aba3ddef..8a45715dd4c1 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -65,23 +65,22 @@ static struct usb_device_id gigaset_table [] = {
65 65
66MODULE_DEVICE_TABLE(usb, gigaset_table); 66MODULE_DEVICE_TABLE(usb, gigaset_table);
67 67
68/*======================= local function prototypes =============================*/ 68/*======================= local function prototypes ==========================*/
69 69
70/* This function is called if a new device is connected to the USB port. It 70/* function called if a new device belonging to this driver is connected */
71 * checks whether this new device belongs to this driver.
72 */
73static int gigaset_probe(struct usb_interface *interface, 71static int gigaset_probe(struct usb_interface *interface,
74 const struct usb_device_id *id); 72 const struct usb_device_id *id);
75 73
76/* Function will be called if the device is unplugged */ 74/* Function will be called if the device is unplugged */
77static void gigaset_disconnect(struct usb_interface *interface); 75static void gigaset_disconnect(struct usb_interface *interface);
78 76
79static void read_ctrl_callback(struct urb *, struct pt_regs *); 77static int atread_submit(struct cardstate *, int);
80static void stopurbs(struct bas_bc_state *); 78static void stopurbs(struct bas_bc_state *);
79static int req_submit(struct bc_state *, int, int, int);
81static int atwrite_submit(struct cardstate *, unsigned char *, int); 80static int atwrite_submit(struct cardstate *, unsigned char *, int);
82static int start_cbsend(struct cardstate *); 81static int start_cbsend(struct cardstate *);
83 82
84/*==============================================================================*/ 83/*============================================================================*/
85 84
86struct bas_cardstate { 85struct bas_cardstate {
87 struct usb_device *udev; /* USB device pointer */ 86 struct usb_device *udev; /* USB device pointer */
@@ -91,6 +90,7 @@ struct bas_cardstate {
91 struct urb *urb_ctrl; /* control pipe default URB */ 90 struct urb *urb_ctrl; /* control pipe default URB */
92 struct usb_ctrlrequest dr_ctrl; 91 struct usb_ctrlrequest dr_ctrl;
93 struct timer_list timer_ctrl; /* control request timeout */ 92 struct timer_list timer_ctrl; /* control request timeout */
93 int retry_ctrl;
94 94
95 struct timer_list timer_atrdy; /* AT command ready timeout */ 95 struct timer_list timer_atrdy; /* AT command ready timeout */
96 struct urb *urb_cmd_out; /* for sending AT commands */ 96 struct urb *urb_cmd_out; /* for sending AT commands */
@@ -307,6 +307,7 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
307 * hang up any existing connection because of an unrecoverable error 307 * hang up any existing connection because of an unrecoverable error
308 * This function may be called from any context and takes care of scheduling 308 * This function may be called from any context and takes care of scheduling
309 * the necessary actions for execution outside of interrupt context. 309 * the necessary actions for execution outside of interrupt context.
310 * cs->lock must not be held.
310 * argument: 311 * argument:
311 * B channel control structure 312 * B channel control structure
312 */ 313 */
@@ -325,14 +326,17 @@ static inline void error_hangup(struct bc_state *bcs)
325 326
326/* error_reset 327/* error_reset
327 * reset Gigaset device because of an unrecoverable error 328 * reset Gigaset device because of an unrecoverable error
328 * This function may be called from any context, and should take care of 329 * This function may be called from any context, and takes care of
329 * scheduling the necessary actions for execution outside of interrupt context. 330 * scheduling the necessary actions for execution outside of interrupt context.
330 * Right now, it just generates a kernel message calling for help. 331 * cs->lock must not be held.
331 * argument: 332 * argument:
332 * controller state structure 333 * controller state structure
333 */ 334 */
334static inline void error_reset(struct cardstate *cs) 335static inline void error_reset(struct cardstate *cs)
335{ 336{
337 /* close AT command channel to recover (ignore errors) */
338 req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT);
339
336 //FIXME try to recover without bothering the user 340 //FIXME try to recover without bothering the user
337 dev_err(cs->dev, 341 dev_err(cs->dev,
338 "unrecoverable error - please disconnect Gigaset base to reset\n"); 342 "unrecoverable error - please disconnect Gigaset base to reset\n");
@@ -403,14 +407,30 @@ static void cmd_in_timeout(unsigned long data)
403{ 407{
404 struct cardstate *cs = (struct cardstate *) data; 408 struct cardstate *cs = (struct cardstate *) data;
405 struct bas_cardstate *ucs = cs->hw.bas; 409 struct bas_cardstate *ucs = cs->hw.bas;
410 int rc;
406 411
407 if (!ucs->rcvbuf_size) { 412 if (!ucs->rcvbuf_size) {
408 gig_dbg(DEBUG_USBREQ, "%s: no receive in progress", __func__); 413 gig_dbg(DEBUG_USBREQ, "%s: no receive in progress", __func__);
409 return; 414 return;
410 } 415 }
411 416
412 dev_err(cs->dev, "timeout reading AT response\n"); 417 if (ucs->retry_cmd_in++ < BAS_RETRY) {
413 error_reset(cs); //FIXME retry? 418 dev_notice(cs->dev, "control read: timeout, retry %d\n",
419 ucs->retry_cmd_in);
420 rc = atread_submit(cs, BAS_TIMEOUT);
421 if (rc >= 0 || rc == -ENODEV)
422 /* resubmitted or disconnected */
423 /* - bypass regular exit block */
424 return;
425 } else {
426 dev_err(cs->dev,
427 "control read: timeout, giving up after %d tries\n",
428 ucs->retry_cmd_in);
429 }
430 kfree(ucs->rcvbuf);
431 ucs->rcvbuf = NULL;
432 ucs->rcvbuf_size = 0;
433 error_reset(cs);
414} 434}
415 435
416/* set/clear bits in base connection state, return previous state 436/* set/clear bits in base connection state, return previous state
@@ -428,6 +448,96 @@ inline static int update_basstate(struct bas_cardstate *ucs,
428 return state; 448 return state;
429} 449}
430 450
451/* read_ctrl_callback
452 * USB completion handler for control pipe input
453 * called by the USB subsystem in interrupt context
454 * parameter:
455 * urb USB request block
456 * urb->context = inbuf structure for controller state
457 */
458static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs)
459{
460 struct inbuf_t *inbuf = urb->context;
461 struct cardstate *cs = inbuf->cs;
462 struct bas_cardstate *ucs = cs->hw.bas;
463 int have_data = 0;
464 unsigned numbytes;
465 int rc;
466
467 update_basstate(ucs, 0, BS_ATRDPEND);
468
469 if (!ucs->rcvbuf_size) {
470 dev_warn(cs->dev, "%s: no receive in progress\n", __func__);
471 return;
472 }
473
474 del_timer(&ucs->timer_cmd_in);
475
476 switch (urb->status) {
477 case 0: /* normal completion */
478 numbytes = urb->actual_length;
479 if (unlikely(numbytes != ucs->rcvbuf_size)) {
480 dev_warn(cs->dev,
481 "control read: received %d chars, expected %d\n",
482 numbytes, ucs->rcvbuf_size);
483 if (numbytes > ucs->rcvbuf_size)
484 numbytes = ucs->rcvbuf_size;
485 }
486
487 /* copy received bytes to inbuf */
488 have_data = gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes);
489
490 if (unlikely(numbytes < ucs->rcvbuf_size)) {
491 /* incomplete - resubmit for remaining bytes */
492 ucs->rcvbuf_size -= numbytes;
493 ucs->retry_cmd_in = 0;
494 rc = atread_submit(cs, BAS_TIMEOUT);
495 if (rc >= 0 || rc == -ENODEV)
496 /* resubmitted or disconnected */
497 /* - bypass regular exit block */
498 return;
499 error_reset(cs);
500 }
501 break;
502
503 case -ENOENT: /* cancelled */
504 case -ECONNRESET: /* cancelled (async) */
505 case -EINPROGRESS: /* pending */
506 case -ENODEV: /* device removed */
507 case -ESHUTDOWN: /* device shut down */
508 /* no action necessary */
509 gig_dbg(DEBUG_USBREQ, "%s: %s",
510 __func__, get_usb_statmsg(urb->status));
511 break;
512
513 default: /* severe trouble */
514 dev_warn(cs->dev, "control read: %s\n",
515 get_usb_statmsg(urb->status));
516 if (ucs->retry_cmd_in++ < BAS_RETRY) {
517 dev_notice(cs->dev, "control read: retry %d\n",
518 ucs->retry_cmd_in);
519 rc = atread_submit(cs, BAS_TIMEOUT);
520 if (rc >= 0 || rc == -ENODEV)
521 /* resubmitted or disconnected */
522 /* - bypass regular exit block */
523 return;
524 } else {
525 dev_err(cs->dev,
526 "control read: giving up after %d tries\n",
527 ucs->retry_cmd_in);
528 }
529 error_reset(cs);
530 }
531
532 kfree(ucs->rcvbuf);
533 ucs->rcvbuf = NULL;
534 ucs->rcvbuf_size = 0;
535 if (have_data) {
536 gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
537 gigaset_schedule_event(cs);
538 }
539}
540
431/* atread_submit 541/* atread_submit
432 * submit an HD_READ_ATMESSAGE command URB and optionally start a timeout 542 * submit an HD_READ_ATMESSAGE command URB and optionally start a timeout
433 * parameters: 543 * parameters:
@@ -466,7 +576,7 @@ static int atread_submit(struct cardstate *cs, int timeout)
466 if ((ret = usb_submit_urb(ucs->urb_cmd_in, SLAB_ATOMIC)) != 0) { 576 if ((ret = usb_submit_urb(ucs->urb_cmd_in, SLAB_ATOMIC)) != 0) {
467 update_basstate(ucs, 0, BS_ATRDPEND); 577 update_basstate(ucs, 0, BS_ATRDPEND);
468 dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: %s\n", 578 dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: %s\n",
469 get_usb_statmsg(ret)); 579 get_usb_rcmsg(ret));
470 return ret; 580 return ret;
471 } 581 }
472 582
@@ -611,9 +721,12 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs)
611 kfree(ucs->rcvbuf); 721 kfree(ucs->rcvbuf);
612 ucs->rcvbuf = NULL; 722 ucs->rcvbuf = NULL;
613 ucs->rcvbuf_size = 0; 723 ucs->rcvbuf_size = 0;
614 if (rc != -ENODEV) 724 if (rc != -ENODEV) {
615 //FIXME corrective action? 725 //FIXME corrective action?
726 spin_unlock_irqrestore(&cs->lock, flags);
616 error_reset(cs); 727 error_reset(cs);
728 break;
729 }
617 } 730 }
618 spin_unlock_irqrestore(&cs->lock, flags); 731 spin_unlock_irqrestore(&cs->lock, flags);
619 break; 732 break;
@@ -643,97 +756,6 @@ resubmit:
643 } 756 }
644} 757}
645 758
646/* read_ctrl_callback
647 * USB completion handler for control pipe input
648 * called by the USB subsystem in interrupt context
649 * parameter:
650 * urb USB request block
651 * urb->context = inbuf structure for controller state
652 */
653static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs)
654{
655 struct inbuf_t *inbuf = urb->context;
656 struct cardstate *cs = inbuf->cs;
657 struct bas_cardstate *ucs = cs->hw.bas;
658 int have_data = 0;
659 unsigned numbytes;
660 int rc;
661
662 update_basstate(ucs, 0, BS_ATRDPEND);
663
664 if (!ucs->rcvbuf_size) {
665 dev_warn(cs->dev, "%s: no receive in progress\n", __func__);
666 return;
667 }
668
669 del_timer(&ucs->timer_cmd_in);
670
671 switch (urb->status) {
672 case 0: /* normal completion */
673 numbytes = urb->actual_length;
674 if (unlikely(numbytes == 0)) {
675 dev_warn(cs->dev,
676 "control read: empty block received\n");
677 goto retry;
678 }
679 if (unlikely(numbytes != ucs->rcvbuf_size)) {
680 dev_warn(cs->dev,
681 "control read: received %d chars, expected %d\n",
682 numbytes, ucs->rcvbuf_size);
683 if (numbytes > ucs->rcvbuf_size)
684 numbytes = ucs->rcvbuf_size;
685 }
686
687 /* copy received bytes to inbuf */
688 have_data = gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes);
689
690 if (unlikely(numbytes < ucs->rcvbuf_size)) {
691 /* incomplete - resubmit for remaining bytes */
692 ucs->rcvbuf_size -= numbytes;
693 ucs->retry_cmd_in = 0;
694 goto retry;
695 }
696 break;
697
698 case -ENOENT: /* cancelled */
699 case -ECONNRESET: /* cancelled (async) */
700 case -EINPROGRESS: /* pending */
701 case -ENODEV: /* device removed */
702 case -ESHUTDOWN: /* device shut down */
703 /* no action necessary */
704 gig_dbg(DEBUG_USBREQ, "%s: %s",
705 __func__, get_usb_statmsg(urb->status));
706 break;
707
708 default: /* severe trouble */
709 dev_warn(cs->dev, "control read: %s\n",
710 get_usb_statmsg(urb->status));
711 retry:
712 if (ucs->retry_cmd_in++ < BAS_RETRY) {
713 dev_notice(cs->dev, "control read: retry %d\n",
714 ucs->retry_cmd_in);
715 rc = atread_submit(cs, BAS_TIMEOUT);
716 if (rc >= 0 || rc == -ENODEV)
717 /* resubmitted or disconnected */
718 /* - bypass regular exit block */
719 return;
720 } else {
721 dev_err(cs->dev,
722 "control read: giving up after %d tries\n",
723 ucs->retry_cmd_in);
724 }
725 error_reset(cs);
726 }
727
728 kfree(ucs->rcvbuf);
729 ucs->rcvbuf = NULL;
730 ucs->rcvbuf_size = 0;
731 if (have_data) {
732 gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
733 gigaset_schedule_event(cs);
734 }
735}
736
737/* read_iso_callback 759/* read_iso_callback
738 * USB completion handler for B channel isochronous input 760 * USB completion handler for B channel isochronous input
739 * called by the USB subsystem in interrupt context 761 * called by the USB subsystem in interrupt context
@@ -1378,6 +1400,7 @@ static void req_timeout(unsigned long data)
1378 case HD_CLOSE_B1CHANNEL: 1400 case HD_CLOSE_B1CHANNEL:
1379 dev_err(bcs->cs->dev, "timeout closing channel %d\n", 1401 dev_err(bcs->cs->dev, "timeout closing channel %d\n",
1380 bcs->channel + 1); 1402 bcs->channel + 1);
1403 error_reset(bcs->cs);
1381 break; 1404 break;
1382 1405
1383 default: 1406 default:
@@ -1396,22 +1419,61 @@ static void req_timeout(unsigned long data)
1396static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs) 1419static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs)
1397{ 1420{
1398 struct bas_cardstate *ucs = urb->context; 1421 struct bas_cardstate *ucs = urb->context;
1422 int rc;
1399 unsigned long flags; 1423 unsigned long flags;
1400 1424
1401 spin_lock_irqsave(&ucs->lock, flags); 1425 /* check status */
1402 if (urb->status && ucs->pending) { 1426 switch (urb->status) {
1403 dev_err(&ucs->interface->dev, 1427 case 0: /* normal completion */
1404 "control request 0x%02x failed: %s\n", 1428 spin_lock_irqsave(&ucs->lock, flags);
1405 ucs->pending, get_usb_statmsg(urb->status)); 1429 switch (ucs->pending) {
1406 del_timer(&ucs->timer_ctrl); 1430 case HD_DEVICE_INIT_ACK: /* no reply expected */
1407 ucs->pending = 0; 1431 del_timer(&ucs->timer_ctrl);
1408 } 1432 ucs->pending = 0;
1409 /* individual handling of specific request types */ 1433 break;
1410 switch (ucs->pending) { 1434 }
1411 case HD_DEVICE_INIT_ACK: /* no reply expected */ 1435 spin_unlock_irqrestore(&ucs->lock, flags);
1412 ucs->pending = 0; 1436 return;
1437
1438 case -ENOENT: /* cancelled */
1439 case -ECONNRESET: /* cancelled (async) */
1440 case -EINPROGRESS: /* pending */
1441 case -ENODEV: /* device removed */
1442 case -ESHUTDOWN: /* device shut down */
1443 /* ignore silently */
1444 gig_dbg(DEBUG_USBREQ, "%s: %s",
1445 __func__, get_usb_statmsg(urb->status));
1413 break; 1446 break;
1447
1448 default: /* any failure */
1449 if (++ucs->retry_ctrl > BAS_RETRY) {
1450 dev_err(&ucs->interface->dev,
1451 "control request 0x%02x failed: %s\n",
1452 ucs->dr_ctrl.bRequest,
1453 get_usb_statmsg(urb->status));
1454 break; /* give up */
1455 }
1456 dev_notice(&ucs->interface->dev,
1457 "control request 0x%02x: %s, retry %d\n",
1458 ucs->dr_ctrl.bRequest, get_usb_statmsg(urb->status),
1459 ucs->retry_ctrl);
1460 /* urb->dev is clobbered by USB subsystem */
1461 urb->dev = ucs->udev;
1462 rc = usb_submit_urb(urb, SLAB_ATOMIC);
1463 if (unlikely(rc)) {
1464 dev_err(&ucs->interface->dev,
1465 "could not resubmit request 0x%02x: %s\n",
1466 ucs->dr_ctrl.bRequest, get_usb_rcmsg(rc));
1467 break;
1468 }
1469 /* resubmitted */
1470 return;
1414 } 1471 }
1472
1473 /* failed, clear pending request */
1474 spin_lock_irqsave(&ucs->lock, flags);
1475 del_timer(&ucs->timer_ctrl);
1476 ucs->pending = 0;
1415 spin_unlock_irqrestore(&ucs->lock, flags); 1477 spin_unlock_irqrestore(&ucs->lock, flags);
1416} 1478}
1417 1479
@@ -1455,9 +1517,11 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout)
1455 usb_sndctrlpipe(ucs->udev, 0), 1517 usb_sndctrlpipe(ucs->udev, 0),
1456 (unsigned char*) &ucs->dr_ctrl, NULL, 0, 1518 (unsigned char*) &ucs->dr_ctrl, NULL, 0,
1457 write_ctrl_callback, ucs); 1519 write_ctrl_callback, ucs);
1458 if ((ret = usb_submit_urb(ucs->urb_ctrl, SLAB_ATOMIC)) != 0) { 1520 ucs->retry_ctrl = 0;
1521 ret = usb_submit_urb(ucs->urb_ctrl, SLAB_ATOMIC);
1522 if (unlikely(ret)) {
1459 dev_err(bcs->cs->dev, "could not submit request 0x%02x: %s\n", 1523 dev_err(bcs->cs->dev, "could not submit request 0x%02x: %s\n",
1460 req, get_usb_statmsg(ret)); 1524 req, get_usb_rcmsg(ret));
1461 spin_unlock_irqrestore(&ucs->lock, flags); 1525 spin_unlock_irqrestore(&ucs->lock, flags);
1462 return ret; 1526 return ret;
1463 } 1527 }