aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn
diff options
context:
space:
mode:
authorTilman Schmidt <tilman@imap.cc>2010-09-30 09:34:40 -0400
committerDavid S. Miller <davem@davemloft.net>2010-10-01 03:33:33 -0400
commitc8701a08d6a4efeae45d84d0aa87172f23b14e3c (patch)
tree4f51fcc9ac6d091036b2d9bd24521d7ee4553ff0 /drivers/isdn
parentb33ffa5cbf52ee751bb8068218ebb3c742c5a515 (diff)
isdn/gigaset: fix bas_gigaset AT read error handling
Rework the handling of USB errors in AT response reads to fix a possible infinite retry loop and a memory leak, and silence a few overly verbose kernel messages. Signed-off-by: Tilman Schmidt <tilman@imap.cc> CC: stable <stable@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/isdn')
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c83
1 files changed, 33 insertions, 50 deletions
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index e143050e1b5c..131976d880d0 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -438,23 +438,27 @@ static void cmd_in_timeout(unsigned long data)
438 return; 438 return;
439 } 439 }
440 440
441 if (ucs->retry_cmd_in++ < BAS_RETRY) { 441 if (ucs->retry_cmd_in++ >= BAS_RETRY) {
442 dev_notice(cs->dev, "control read: timeout, retry %d\n",
443 ucs->retry_cmd_in);
444 rc = atread_submit(cs, BAS_TIMEOUT);
445 if (rc >= 0 || rc == -ENODEV)
446 /* resubmitted or disconnected */
447 /* - bypass regular exit block */
448 return;
449 } else {
450 dev_err(cs->dev, 442 dev_err(cs->dev,
451 "control read: timeout, giving up after %d tries\n", 443 "control read: timeout, giving up after %d tries\n",
452 ucs->retry_cmd_in); 444 ucs->retry_cmd_in);
445 kfree(ucs->rcvbuf);
446 ucs->rcvbuf = NULL;
447 ucs->rcvbuf_size = 0;
448 error_reset(cs);
449 return;
450 }
451
452 gig_dbg(DEBUG_USBREQ, "%s: timeout, retry %d",
453 __func__, ucs->retry_cmd_in);
454 rc = atread_submit(cs, BAS_TIMEOUT);
455 if (rc < 0) {
456 kfree(ucs->rcvbuf);
457 ucs->rcvbuf = NULL;
458 ucs->rcvbuf_size = 0;
459 if (rc != -ENODEV)
460 error_reset(cs);
453 } 461 }
454 kfree(ucs->rcvbuf);
455 ucs->rcvbuf = NULL;
456 ucs->rcvbuf_size = 0;
457 error_reset(cs);
458} 462}
459 463
460/* read_ctrl_callback 464/* read_ctrl_callback
@@ -470,18 +474,11 @@ static void read_ctrl_callback(struct urb *urb)
470 struct cardstate *cs = inbuf->cs; 474 struct cardstate *cs = inbuf->cs;
471 struct bas_cardstate *ucs = cs->hw.bas; 475 struct bas_cardstate *ucs = cs->hw.bas;
472 int status = urb->status; 476 int status = urb->status;
473 int have_data = 0;
474 unsigned numbytes; 477 unsigned numbytes;
475 int rc; 478 int rc;
476 479
477 update_basstate(ucs, 0, BS_ATRDPEND); 480 update_basstate(ucs, 0, BS_ATRDPEND);
478 wake_up(&ucs->waitqueue); 481 wake_up(&ucs->waitqueue);
479
480 if (!ucs->rcvbuf_size) {
481 dev_warn(cs->dev, "%s: no receive in progress\n", __func__);
482 return;
483 }
484
485 del_timer(&ucs->timer_cmd_in); 482 del_timer(&ucs->timer_cmd_in);
486 483
487 switch (status) { 484 switch (status) {
@@ -495,19 +492,10 @@ static void read_ctrl_callback(struct urb *urb)
495 numbytes = ucs->rcvbuf_size; 492 numbytes = ucs->rcvbuf_size;
496 } 493 }
497 494
498 /* copy received bytes to inbuf */ 495 /* copy received bytes to inbuf, notify event layer */
499 have_data = gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes); 496 if (gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes)) {
500 497 gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
501 if (unlikely(numbytes < ucs->rcvbuf_size)) { 498 gigaset_schedule_event(cs);
502 /* incomplete - resubmit for remaining bytes */
503 ucs->rcvbuf_size -= numbytes;
504 ucs->retry_cmd_in = 0;
505 rc = atread_submit(cs, BAS_TIMEOUT);
506 if (rc >= 0 || rc == -ENODEV)
507 /* resubmitted or disconnected */
508 /* - bypass regular exit block */
509 return;
510 error_reset(cs);
511 } 499 }
512 break; 500 break;
513 501
@@ -516,37 +504,32 @@ static void read_ctrl_callback(struct urb *urb)
516 case -EINPROGRESS: /* pending */ 504 case -EINPROGRESS: /* pending */
517 case -ENODEV: /* device removed */ 505 case -ENODEV: /* device removed */
518 case -ESHUTDOWN: /* device shut down */ 506 case -ESHUTDOWN: /* device shut down */
519 /* no action necessary */ 507 /* no further action necessary */
520 gig_dbg(DEBUG_USBREQ, "%s: %s", 508 gig_dbg(DEBUG_USBREQ, "%s: %s",
521 __func__, get_usb_statmsg(status)); 509 __func__, get_usb_statmsg(status));
522 break; 510 break;
523 511
524 default: /* severe trouble */ 512 default: /* other errors: retry */
525 dev_warn(cs->dev, "control read: %s\n",
526 get_usb_statmsg(status));
527 if (ucs->retry_cmd_in++ < BAS_RETRY) { 513 if (ucs->retry_cmd_in++ < BAS_RETRY) {
528 dev_notice(cs->dev, "control read: retry %d\n", 514 gig_dbg(DEBUG_USBREQ, "%s: %s, retry %d", __func__,
529 ucs->retry_cmd_in); 515 get_usb_statmsg(status), ucs->retry_cmd_in);
530 rc = atread_submit(cs, BAS_TIMEOUT); 516 rc = atread_submit(cs, BAS_TIMEOUT);
531 if (rc >= 0 || rc == -ENODEV) 517 if (rc >= 0)
532 /* resubmitted or disconnected */ 518 /* successfully resubmitted, skip freeing */
533 /* - bypass regular exit block */
534 return; 519 return;
535 } else { 520 if (rc == -ENODEV)
536 dev_err(cs->dev, 521 /* disconnect, no further action necessary */
537 "control read: giving up after %d tries\n", 522 break;
538 ucs->retry_cmd_in);
539 } 523 }
524 dev_err(cs->dev, "control read: %s, giving up after %d tries\n",
525 get_usb_statmsg(status), ucs->retry_cmd_in);
540 error_reset(cs); 526 error_reset(cs);
541 } 527 }
542 528
529 /* read finished, free buffer */
543 kfree(ucs->rcvbuf); 530 kfree(ucs->rcvbuf);
544 ucs->rcvbuf = NULL; 531 ucs->rcvbuf = NULL;
545 ucs->rcvbuf_size = 0; 532 ucs->rcvbuf_size = 0;
546 if (have_data) {
547 gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
548 gigaset_schedule_event(cs);
549 }
550} 533}
551 534
552/* atread_submit 535/* atread_submit