From f7df0b8d924ad2f39852ea397d39a51fbb955212 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 5 Aug 2010 10:29:19 +0000 Subject: drivers/isdn: Adjust confusing if indentation In hisax/hfc_sx.c and mISDN/l1oip_core.c, the code after the if is outdented so that it is not aligned with the if branch. In mISDN/dsp_cmx.c, an else is added between the original if branch and the following statement, in line with the code following it. Without this change, the first assignment to dsp->rx_W has no useful effect. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r disable braces4@ position p1,p2; statement S1,S2; @@ ( if (...) { ... } | if (...) S1@p1 S2@p2 ) @script:python@ p1 << r.p1; p2 << r.p2; @@ if (p1[0].column == p2[0].column): cocci.print_main("branch",p1) cocci.print_secs("after",p2) // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/isdn/hisax/hfc_sx.c | 13 +++++++------ drivers/isdn/mISDN/dsp_cmx.c | 1 + drivers/isdn/mISDN/l1oip_core.c | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c index be5faf4aa86..5aa138eb0b3 100644 --- a/drivers/isdn/hisax/hfc_sx.c +++ b/drivers/isdn/hisax/hfc_sx.c @@ -234,13 +234,14 @@ read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max) count++; if (count > trans_max) count = trans_max; /* limit length */ - if ((skb = dev_alloc_skb(count))) { - dst = skb_put(skb, count); - while (count--) + skb = dev_alloc_skb(count); + if (skb) { + dst = skb_put(skb, count); + while (count--) *dst++ = Read_hfc(cs, HFCSX_FIF_DRD); - return(skb); - } - else return(NULL); /* no memory */ + return skb; + } else + return NULL; /* no memory */ } do { diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index 713ef2b805a..76d9e673b4e 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -1237,6 +1237,7 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) if (dsp->cmx_delay) dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) & CMX_BUFF_MASK; + else dsp->rx_W = (dsp->rx_R + (dsp_poll >> 1)) & CMX_BUFF_MASK; } else { diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c index 22f38e48ac4..5b59796ed25 100644 --- a/drivers/isdn/mISDN/l1oip_core.c +++ b/drivers/isdn/mISDN/l1oip_core.c @@ -972,7 +972,7 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) if (debug & DEBUG_L1OIP_SOCKET) printk(KERN_DEBUG "%s: got new ip address from user " "space.\n", __func__); - l1oip_socket_open(hc); + l1oip_socket_open(hc); break; case MISDN_CTRL_UNSETPEER: if (debug & DEBUG_L1OIP_SOCKET) -- cgit v1.2.3-70-g09d2 From 017d79ef0073fdb170dcf185dc4c2456a304d659 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 4 Sep 2010 08:38:59 +0000 Subject: isdn: potential buffer overflows cs->ics.parm.setup.phone is a 32 character array. In each of these cases we're copying from a 35 character array into a 32 character array so we should use strlcpy() instead of strcpy(). Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/isdn/divert/isdn_divert.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c index 70cf6bac7a5..48e6d220f62 100644 --- a/drivers/isdn/divert/isdn_divert.c +++ b/drivers/isdn/divert/isdn_divert.c @@ -77,7 +77,7 @@ static void deflect_timer_expire(ulong arg) case DEFLECT_ALERT: cs->ics.command = ISDN_CMD_REDIR; /* protocol */ - strcpy(cs->ics.parm.setup.phone,cs->deflect_dest); + strlcpy(cs->ics.parm.setup.phone, cs->deflect_dest, sizeof(cs->ics.parm.setup.phone)); strcpy(cs->ics.parm.setup.eazmsn,"Testtext delayed"); divert_if.ll_cmd(&cs->ics); spin_lock_irqsave(&divert_lock, flags); @@ -251,7 +251,7 @@ int deflect_extern_action(u_char cmd, ulong callid, char *to_nr) case 2: /* redir */ del_timer(&cs->timer); - strcpy(cs->ics.parm.setup.phone, to_nr); + strlcpy(cs->ics.parm.setup.phone, to_nr, sizeof(cs->ics.parm.setup.phone)); strcpy(cs->ics.parm.setup.eazmsn, "Testtext manual"); ic.command = ISDN_CMD_REDIR; if ((i = divert_if.ll_cmd(&ic))) @@ -480,7 +480,7 @@ static int isdn_divert_icall(isdn_ctrl *ic) if (!cs->timer.expires) { strcpy(ic->parm.setup.eazmsn,"Testtext direct"); ic->parm.setup.screen = dv->rule.screen; - strcpy(ic->parm.setup.phone,dv->rule.to_nr); + strlcpy(ic->parm.setup.phone, dv->rule.to_nr, sizeof(ic->parm.setup.phone)); cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); retval = 5; -- cgit v1.2.3-70-g09d2 From f417f5e4ba79a08e992c79a4bb84c8a8c5062017 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 4 Sep 2010 08:33:03 +0000 Subject: isdn: cleanup: make buffer smaller This showed up in my audit because we use strcpy() to copy "ds" into a 32 character buffer inside the isdn_tty_dial() function. But it turns out that we only ever use the first 32 characters so it's OK. I have changed the declaration to make the static checkers happy. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/isdn/i4l/isdn_tty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 51dc60da333..f013ee15327 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -3515,7 +3515,7 @@ isdn_tty_parse_at(modem_info * info) { atemu *m = &info->emu; char *p; - char ds[40]; + char ds[ISDN_MSNLEN]; #ifdef ISDN_DEBUG_AT printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd); @@ -3594,7 +3594,7 @@ isdn_tty_parse_at(modem_info * info) break; case '3': p++; - sprintf(ds, "\r\n%d", info->emu.charge); + snprintf(ds, sizeof(ds), "\r\n%d", info->emu.charge); isdn_tty_at_cout(ds, info); break; default:; -- cgit v1.2.3-70-g09d2 From a7a4f1c1a52912eb8b3bd4d8f628d83a8b5d69dd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 7 Sep 2010 05:14:30 +0000 Subject: drivers: isdn: capi: use simple_strtol to convert numbers Signed-off-by: Andy Shevchenko Cc: Karsten Keil Cc: Tilman Schmidt Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller --- drivers/isdn/capi/capidrv.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index 2978bdaa6b8..e54e79d4e2c 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -1515,8 +1515,13 @@ static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep) while (*s) { int digit1 = 0; int digit2 = 0; - if (!isdigit(*s)) return -3; - while (isdigit(*s)) { digit1 = digit1*10 + (*s - '0'); s++; } + char *endp; + + digit1 = simple_strtoul(s, &endp, 10); + if (s == endp) + return -3; + s = endp; + if (digit1 <= 0 || digit1 > 30) return -4; if (*s == 0 || *s == ',' || *s == ' ') { bmask |= (1 << digit1); @@ -1526,8 +1531,12 @@ static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep) } if (*s != '-') return -5; s++; - if (!isdigit(*s)) return -3; - while (isdigit(*s)) { digit2 = digit2*10 + (*s - '0'); s++; } + + digit2 = simple_strtoul(s, &endp, 10); + if (s == endp) + return -3; + s = endp; + if (digit2 <= 0 || digit2 > 30) return -4; if (*s == 0 || *s == ',' || *s == ' ') { if (digit1 > digit2) -- cgit v1.2.3-70-g09d2 From 6f68ad7fbb421df0aa3c267768245b2e86a91f74 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 13 Sep 2010 18:23:52 +0000 Subject: drivers/isdn: Use static const char * const where possible Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/isdn/pcbit/edss1.c | 2 +- drivers/isdn/pcbit/edss1.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/pcbit/edss1.c b/drivers/isdn/pcbit/edss1.c index d5920ae22d7..80c9c16fd5e 100644 --- a/drivers/isdn/pcbit/edss1.c +++ b/drivers/isdn/pcbit/edss1.c @@ -33,7 +33,7 @@ #include "callbacks.h" -char * isdn_state_table[] = { +const char * const isdn_state_table[] = { "Closed", "Call initiated", "Overlap sending", diff --git a/drivers/isdn/pcbit/edss1.h b/drivers/isdn/pcbit/edss1.h index 0b64f97015d..39f8346e28c 100644 --- a/drivers/isdn/pcbit/edss1.h +++ b/drivers/isdn/pcbit/edss1.h @@ -90,7 +90,7 @@ struct fsm_timer_entry { unsigned long timeout; /* in seconds */ }; -extern char * isdn_state_table[]; +extern const char * const isdn_state_table[]; void pcbit_fsm_event(struct pcbit_dev *, struct pcbit_chan *, unsigned short event, struct callb_data *); -- cgit v1.2.3-70-g09d2 From 72250d44bc76d3d7fa9253aeeb063a467e2458fa Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 14 Sep 2010 09:35:04 +0000 Subject: i4l: kill big kernel lock The isdn4linux driver uses the big kernel lock only to serialize access to a few fields in its own modem_info structure. The easiest replacement is a driver-wide mutex. More fine-grained locking would be more appropriate here, but likely harder to implement. Signed-off-by: Arnd Bergmann Cc: Karsten Keil Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller --- drivers/isdn/i4l/isdn_tty.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index f013ee15327..c463162843b 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include "isdn_common.h" #include "isdn_tty.h" #ifdef CONFIG_ISDN_AUDIO @@ -28,6 +28,7 @@ /* Prototypes */ +static DEFINE_MUTEX(modem_info_mutex); static int isdn_tty_edit_at(const char *, int, modem_info *); static void isdn_tty_check_esc(const u_char *, u_char, int, int *, u_long *); static void isdn_tty_modem_reset_regs(modem_info *, int); @@ -1354,14 +1355,14 @@ isdn_tty_tiocmget(struct tty_struct *tty, struct file *file) if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; - lock_kernel(); + mutex_lock(&modem_info_mutex); #ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line); #endif control = info->mcr; status = info->msr; - unlock_kernel(); + mutex_unlock(&modem_info_mutex); return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) @@ -1385,7 +1386,7 @@ isdn_tty_tiocmset(struct tty_struct *tty, struct file *file, printk(KERN_DEBUG "ttyI%d ioctl TIOCMxxx: %x %x\n", info->line, set, clear); #endif - lock_kernel(); + mutex_lock(&modem_info_mutex); if (set & TIOCM_RTS) info->mcr |= UART_MCR_RTS; if (set & TIOCM_DTR) { @@ -1407,7 +1408,7 @@ isdn_tty_tiocmset(struct tty_struct *tty, struct file *file, isdn_tty_modem_hup(info, 1); } } - unlock_kernel(); + mutex_unlock(&modem_info_mutex); return 0; } -- cgit v1.2.3-70-g09d2 From 1a19eb753a591f8b39946b7fda91b25f07454835 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 14 Sep 2010 09:35:05 +0000 Subject: misdn: kill big kernel lock The use of the big kernel lock in misdn is completely bogus, so let's just remove it. Signed-off-by: Arnd Bergmann Cc: Karsten Keil Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller --- drivers/isdn/mISDN/stack.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c index b159bd59e64..a5b632e6755 100644 --- a/drivers/isdn/mISDN/stack.c +++ b/drivers/isdn/mISDN/stack.c @@ -18,7 +18,6 @@ #include #include #include -#include #include "core.h" static u_int *debug; @@ -205,13 +204,7 @@ mISDNStackd(void *data) struct mISDNstack *st = data; int err = 0; -#ifdef CONFIG_SMP - lock_kernel(); -#endif sigfillset(¤t->blocked); -#ifdef CONFIG_SMP - unlock_kernel(); -#endif if (*debug & DEBUG_MSG_THREAD) printk(KERN_DEBUG "mISDNStackd %s started\n", dev_name(&st->dev->dev)); -- cgit v1.2.3-70-g09d2 From b33ffa5cbf52ee751bb8068218ebb3c742c5a515 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Thu, 30 Sep 2010 13:34:30 +0000 Subject: isdn/gigaset: bas_gigaset locking fix Unlock cs->lock before calling error_hangup() which is marked "cs->lock must not be held". Signed-off-by: Tilman Schmidt CC: stable Signed-off-by: David S. Miller --- drivers/isdn/gigaset/bas-gigaset.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 707d9c94cf9..e143050e1b5 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -1598,13 +1598,13 @@ static int gigaset_init_bchannel(struct bc_state *bcs) ret = starturbs(bcs); if (ret < 0) { + spin_unlock_irqrestore(&cs->lock, flags); dev_err(cs->dev, "could not start isochronous I/O for channel B%d: %s\n", bcs->channel + 1, ret == -EFAULT ? "null URB" : get_usb_rcmsg(ret)); if (ret != -ENODEV) error_hangup(bcs); - spin_unlock_irqrestore(&cs->lock, flags); return ret; } @@ -1614,11 +1614,11 @@ static int gigaset_init_bchannel(struct bc_state *bcs) dev_err(cs->dev, "could not open channel B%d\n", bcs->channel + 1); stopurbs(bcs->hw.bas); - if (ret != -ENODEV) - error_hangup(bcs); } spin_unlock_irqrestore(&cs->lock, flags); + if (ret < 0 && ret != -ENODEV) + error_hangup(bcs); return ret; } -- cgit v1.2.3-70-g09d2 From c8701a08d6a4efeae45d84d0aa87172f23b14e3c Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Thu, 30 Sep 2010 13:34:40 +0000 Subject: 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 CC: stable Signed-off-by: David S. Miller --- drivers/isdn/gigaset/bas-gigaset.c | 83 +++++++++++++++----------------------- 1 file changed, 33 insertions(+), 50 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index e143050e1b5..131976d880d 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) return; } - if (ucs->retry_cmd_in++ < BAS_RETRY) { - dev_notice(cs->dev, "control read: timeout, retry %d\n", - ucs->retry_cmd_in); - rc = atread_submit(cs, BAS_TIMEOUT); - if (rc >= 0 || rc == -ENODEV) - /* resubmitted or disconnected */ - /* - bypass regular exit block */ - return; - } else { + if (ucs->retry_cmd_in++ >= BAS_RETRY) { dev_err(cs->dev, "control read: timeout, giving up after %d tries\n", ucs->retry_cmd_in); + kfree(ucs->rcvbuf); + ucs->rcvbuf = NULL; + ucs->rcvbuf_size = 0; + error_reset(cs); + return; + } + + gig_dbg(DEBUG_USBREQ, "%s: timeout, retry %d", + __func__, ucs->retry_cmd_in); + rc = atread_submit(cs, BAS_TIMEOUT); + if (rc < 0) { + kfree(ucs->rcvbuf); + ucs->rcvbuf = NULL; + ucs->rcvbuf_size = 0; + if (rc != -ENODEV) + error_reset(cs); } - kfree(ucs->rcvbuf); - ucs->rcvbuf = NULL; - ucs->rcvbuf_size = 0; - error_reset(cs); } /* read_ctrl_callback @@ -470,18 +474,11 @@ static void read_ctrl_callback(struct urb *urb) struct cardstate *cs = inbuf->cs; struct bas_cardstate *ucs = cs->hw.bas; int status = urb->status; - int have_data = 0; unsigned numbytes; int rc; update_basstate(ucs, 0, BS_ATRDPEND); wake_up(&ucs->waitqueue); - - if (!ucs->rcvbuf_size) { - dev_warn(cs->dev, "%s: no receive in progress\n", __func__); - return; - } - del_timer(&ucs->timer_cmd_in); switch (status) { @@ -495,19 +492,10 @@ static void read_ctrl_callback(struct urb *urb) numbytes = ucs->rcvbuf_size; } - /* copy received bytes to inbuf */ - have_data = gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes); - - if (unlikely(numbytes < ucs->rcvbuf_size)) { - /* incomplete - resubmit for remaining bytes */ - ucs->rcvbuf_size -= numbytes; - ucs->retry_cmd_in = 0; - rc = atread_submit(cs, BAS_TIMEOUT); - if (rc >= 0 || rc == -ENODEV) - /* resubmitted or disconnected */ - /* - bypass regular exit block */ - return; - error_reset(cs); + /* copy received bytes to inbuf, notify event layer */ + if (gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes)) { + gig_dbg(DEBUG_INTR, "%s-->BH", __func__); + gigaset_schedule_event(cs); } break; @@ -516,37 +504,32 @@ static void read_ctrl_callback(struct urb *urb) case -EINPROGRESS: /* pending */ case -ENODEV: /* device removed */ case -ESHUTDOWN: /* device shut down */ - /* no action necessary */ + /* no further action necessary */ gig_dbg(DEBUG_USBREQ, "%s: %s", __func__, get_usb_statmsg(status)); break; - default: /* severe trouble */ - dev_warn(cs->dev, "control read: %s\n", - get_usb_statmsg(status)); + default: /* other errors: retry */ if (ucs->retry_cmd_in++ < BAS_RETRY) { - dev_notice(cs->dev, "control read: retry %d\n", - ucs->retry_cmd_in); + gig_dbg(DEBUG_USBREQ, "%s: %s, retry %d", __func__, + get_usb_statmsg(status), ucs->retry_cmd_in); rc = atread_submit(cs, BAS_TIMEOUT); - if (rc >= 0 || rc == -ENODEV) - /* resubmitted or disconnected */ - /* - bypass regular exit block */ + if (rc >= 0) + /* successfully resubmitted, skip freeing */ return; - } else { - dev_err(cs->dev, - "control read: giving up after %d tries\n", - ucs->retry_cmd_in); + if (rc == -ENODEV) + /* disconnect, no further action necessary */ + break; } + dev_err(cs->dev, "control read: %s, giving up after %d tries\n", + get_usb_statmsg(status), ucs->retry_cmd_in); error_reset(cs); } + /* read finished, free buffer */ kfree(ucs->rcvbuf); ucs->rcvbuf = NULL; ucs->rcvbuf_size = 0; - if (have_data) { - gig_dbg(DEBUG_INTR, "%s-->BH", __func__); - gigaset_schedule_event(cs); - } } /* atread_submit -- cgit v1.2.3-70-g09d2 From f3d531b99fb30945b4a64d6e2e86e1e62605aca5 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Thu, 30 Sep 2010 13:34:51 +0000 Subject: isdn/gigaset: correct bas_gigaset rx buffer handling In transparent data reception, avoid a NULL pointer dereference in case an skbuff cannot be allocated, remove an inappropriate call to the HDLC flush routine, and correct the accounting of received bytes for continued buffers. Signed-off-by: Tilman Schmidt CC: stable Signed-off-by: David S. Miller --- drivers/isdn/gigaset/isocdata.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index 2dfd346fc88..f39ccdf87a1 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -842,13 +842,14 @@ static inline void trans_receive(unsigned char *src, unsigned count, if (unlikely(bcs->ignore)) { bcs->ignore--; - hdlc_flush(bcs); return; } skb = bcs->rx_skb; - if (skb == NULL) + if (skb == NULL) { skb = gigaset_new_rx_skb(bcs); - bcs->hw.bas->goodbytes += skb->len; + if (skb == NULL) + return; + } dobytes = bcs->rx_bufsize - skb->len; while (count > 0) { dst = skb_put(skb, count < dobytes ? count : dobytes); @@ -860,6 +861,7 @@ static inline void trans_receive(unsigned char *src, unsigned count, if (dobytes == 0) { dump_bytes(DEBUG_STREAM_DUMP, "rcv data", skb->data, skb->len); + bcs->hw.bas->goodbytes += skb->len; gigaset_skb_rcvd(bcs, skb); skb = gigaset_new_rx_skb(bcs); if (skb == NULL) -- cgit v1.2.3-70-g09d2 From befba36ab942c44ba1d3761a7439324fff83638f Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Thu, 30 Sep 2010 13:35:01 +0000 Subject: isdn/gigaset: drop obsolete debug option Remove the debug flag DEBUG_DRIVER and associated code. It doesn't serve any useful purpose anymore. Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller --- drivers/isdn/gigaset/common.c | 26 -------------------------- drivers/isdn/gigaset/gigaset.h | 3 +-- drivers/isdn/gigaset/i4l.c | 2 -- 3 files changed, 1 insertion(+), 30 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index 3ca561eccd9..db621db67f6 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -1026,32 +1026,6 @@ struct cardstate *gigaset_get_cs_by_id(int id) return ret; } -void gigaset_debugdrivers(void) -{ - unsigned long flags; - static struct cardstate *cs; - struct gigaset_driver *drv; - unsigned i; - - spin_lock_irqsave(&driver_lock, flags); - list_for_each_entry(drv, &drivers, list) { - gig_dbg(DEBUG_DRIVER, "driver %p", drv); - spin_lock(&drv->lock); - for (i = 0; i < drv->minors; ++i) { - gig_dbg(DEBUG_DRIVER, " index %u", i); - cs = drv->cs + i; - gig_dbg(DEBUG_DRIVER, " cardstate %p", cs); - gig_dbg(DEBUG_DRIVER, " flags 0x%02x", cs->flags); - gig_dbg(DEBUG_DRIVER, " minor_index %u", - cs->minor_index); - gig_dbg(DEBUG_DRIVER, " driver %p", cs->driver); - gig_dbg(DEBUG_DRIVER, " i4l id %d", cs->myid); - } - spin_unlock(&drv->lock); - } - spin_unlock_irqrestore(&driver_lock, flags); -} - static struct cardstate *gigaset_get_cs_by_minor(unsigned minor) { unsigned long flags; diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index a69512fb119..6dd360734cf 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -70,7 +70,6 @@ enum debuglevel { DEBUG_STREAM_DUMP = 0x00080, /* application data stream content */ DEBUG_LLDATA = 0x00100, /* sent/received LL data */ DEBUG_EVENT = 0x00200, /* event processing */ - DEBUG_DRIVER = 0x00400, /* driver structure */ DEBUG_HDLC = 0x00800, /* M10x HDLC processing */ DEBUG_CHANNEL = 0x01000, /* channel allocation/deallocation */ DEBUG_TRANSCMD = 0x02000, /* AT-COMMANDS+RESPONSES */ @@ -727,7 +726,7 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, /* Deallocate driver structure. */ void gigaset_freedriver(struct gigaset_driver *drv); -void gigaset_debugdrivers(void); + struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty); struct cardstate *gigaset_get_cs_by_id(int id); void gigaset_blockdriver(struct gigaset_driver *drv); diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c index 34bca37d65b..9bec8b96996 100644 --- a/drivers/isdn/gigaset/i4l.c +++ b/drivers/isdn/gigaset/i4l.c @@ -201,8 +201,6 @@ static int command_from_LL(isdn_ctrl *cntrl) int i; size_t l; - gigaset_debugdrivers(); - gig_dbg(DEBUG_CMD, "driver: %d, command: %d, arg: 0x%lx", cntrl->driver, cntrl->command, cntrl->arg); -- cgit v1.2.3-70-g09d2 From 1d5a9edcd5f1fe6483afca33294ed0ebab793ebf Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Thu, 30 Sep 2010 13:35:11 +0000 Subject: isdn/gigaset: bas_gigaset timer cleanup Use setup_timer() and mod_timer() instead of direct assignment to timer structure members, simplify the argument of one timer routine, and make extra sure all timers are stopped during suspend. Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller --- drivers/isdn/gigaset/bas-gigaset.c | 65 +++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 33 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 131976d880d..e865c5dc028 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -588,10 +588,7 @@ static int atread_submit(struct cardstate *cs, int timeout) if (timeout > 0) { gig_dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout); - ucs->timer_cmd_in.expires = jiffies + timeout * HZ / 10; - ucs->timer_cmd_in.data = (unsigned long) cs; - ucs->timer_cmd_in.function = cmd_in_timeout; - add_timer(&ucs->timer_cmd_in); + mod_timer(&ucs->timer_cmd_in, jiffies + timeout * HZ / 10); } return 0; } @@ -1356,12 +1353,12 @@ error: /* req_timeout * timeout routine for control output request * argument: - * B channel control structure + * controller state structure */ static void req_timeout(unsigned long data) { - struct bc_state *bcs = (struct bc_state *) data; - struct bas_cardstate *ucs = bcs->cs->hw.bas; + struct cardstate *cs = (struct cardstate *) data; + struct bas_cardstate *ucs = cs->hw.bas; int pending; unsigned long flags; @@ -1378,38 +1375,44 @@ static void req_timeout(unsigned long data) break; case HD_OPEN_ATCHANNEL: - dev_err(bcs->cs->dev, "timeout opening AT channel\n"); - error_reset(bcs->cs); + dev_err(cs->dev, "timeout opening AT channel\n"); + error_reset(cs); break; - case HD_OPEN_B2CHANNEL: case HD_OPEN_B1CHANNEL: - dev_err(bcs->cs->dev, "timeout opening channel %d\n", - bcs->channel + 1); - error_hangup(bcs); + dev_err(cs->dev, "timeout opening channel 1\n"); + error_hangup(&cs->bcs[0]); + break; + + case HD_OPEN_B2CHANNEL: + dev_err(cs->dev, "timeout opening channel 2\n"); + error_hangup(&cs->bcs[1]); break; case HD_CLOSE_ATCHANNEL: - dev_err(bcs->cs->dev, "timeout closing AT channel\n"); - error_reset(bcs->cs); + dev_err(cs->dev, "timeout closing AT channel\n"); + error_reset(cs); break; - case HD_CLOSE_B2CHANNEL: case HD_CLOSE_B1CHANNEL: - dev_err(bcs->cs->dev, "timeout closing channel %d\n", - bcs->channel + 1); - error_reset(bcs->cs); + dev_err(cs->dev, "timeout closing channel 1\n"); + error_reset(cs); + break; + + case HD_CLOSE_B2CHANNEL: + dev_err(cs->dev, "timeout closing channel 2\n"); + error_reset(cs); break; case HD_RESET_INTERRUPT_PIPE: /* error recovery escalation */ - dev_err(bcs->cs->dev, + dev_err(cs->dev, "reset interrupt pipe timeout, attempting USB reset\n"); - usb_queue_reset_device(bcs->cs->hw.bas->interface); + usb_queue_reset_device(ucs->interface); break; default: - dev_warn(bcs->cs->dev, "request 0x%02x timed out, clearing\n", + dev_warn(cs->dev, "request 0x%02x timed out, clearing\n", pending); } @@ -1540,10 +1543,7 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout) if (timeout > 0) { gig_dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout); - ucs->timer_ctrl.expires = jiffies + timeout * HZ / 10; - ucs->timer_ctrl.data = (unsigned long) bcs; - ucs->timer_ctrl.function = req_timeout; - add_timer(&ucs->timer_ctrl); + mod_timer(&ucs->timer_ctrl, jiffies + timeout * HZ / 10); } spin_unlock_irqrestore(&ucs->lock, flags); @@ -1809,10 +1809,7 @@ static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len) if (!(update_basstate(ucs, BS_ATTIMER, BS_ATREADY) & BS_ATTIMER)) { gig_dbg(DEBUG_OUTPUT, "setting ATREADY timeout of %d/10 secs", ATRDY_TIMEOUT); - ucs->timer_atrdy.expires = jiffies + ATRDY_TIMEOUT * HZ / 10; - ucs->timer_atrdy.data = (unsigned long) cs; - ucs->timer_atrdy.function = atrdy_timeout; - add_timer(&ucs->timer_atrdy); + mod_timer(&ucs->timer_atrdy, jiffies + ATRDY_TIMEOUT * HZ / 10); } return 0; } @@ -2114,9 +2111,9 @@ static int gigaset_initcshw(struct cardstate *cs) ucs->pending = 0; ucs->basstate = 0; - init_timer(&ucs->timer_ctrl); - init_timer(&ucs->timer_atrdy); - init_timer(&ucs->timer_cmd_in); + setup_timer(&ucs->timer_ctrl, req_timeout, (unsigned long) cs); + setup_timer(&ucs->timer_atrdy, atrdy_timeout, (unsigned long) cs); + setup_timer(&ucs->timer_cmd_in, cmd_in_timeout, (unsigned long) cs); init_waitqueue_head(&ucs->waitqueue); return 1; @@ -2387,6 +2384,8 @@ static int gigaset_suspend(struct usb_interface *intf, pm_message_t message) usb_kill_urb(ucs->urb_ctrl); usb_kill_urb(ucs->urb_int_in); del_timer_sync(&ucs->timer_ctrl); + del_timer_sync(&ucs->timer_atrdy); + del_timer_sync(&ucs->timer_cmd_in); gig_dbg(DEBUG_SUSPEND, "suspend complete"); return 0; -- cgit v1.2.3-70-g09d2 From 60798c68bebf6009df9da634e79ebdd8c8227238 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Thu, 30 Sep 2010 13:35:21 +0000 Subject: isdn/gigaset: try USB reset for bas_gigaset error recovery In error_reset(), if sending HD_RESET_INTERRUPT_PIPE to the device fails, try performing an USB reset. Also correct an error in the leading comment. Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller --- drivers/isdn/gigaset/bas-gigaset.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index e865c5dc028..7520bc6f387 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -350,7 +350,7 @@ static inline void error_hangup(struct bc_state *bcs) * reset Gigaset device because of an unrecoverable error * This function may be called from any context, and takes care of * scheduling the necessary actions for execution outside of interrupt context. - * cs->lock must not be held. + * cs->hw.bas->lock must not be held. * argument: * controller state structure */ @@ -358,7 +358,9 @@ static inline void error_reset(struct cardstate *cs) { /* reset interrupt pipe to recover (ignore errors) */ update_basstate(cs->hw.bas, BS_RESETTING, 0); - req_submit(cs->bcs, HD_RESET_INTERRUPT_PIPE, 0, BAS_TIMEOUT); + if (req_submit(cs->bcs, HD_RESET_INTERRUPT_PIPE, 0, BAS_TIMEOUT)) + /* submission failed, escalate to USB port reset */ + usb_queue_reset_device(cs->hw.bas->interface); } /* check_pending -- cgit v1.2.3-70-g09d2 From 4cb5e42f6132bf2d2851f8dd67bd8499979c7ebc Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Thu, 30 Sep 2010 13:35:31 +0000 Subject: isdn/gigaset: unclog bas_gigaset AT response pipe Recover from a lost HD_RECEIVEATDATA_ACK message by sending a zero-length HD_READ_ATMESSAGE command when ev_layer sends "+++". Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller --- drivers/isdn/gigaset/bas-gigaset.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers/isdn') diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 7520bc6f387..540f6d0bb75 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -1896,6 +1896,28 @@ static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb) * The next command will reopen the AT channel automatically. */ if (cb->len == 3 && !memcmp(cb->buf, "+++", 3)) { + /* If an HD_RECEIVEATDATA_ACK message remains unhandled + * because of an error, the base never sends another one. + * The response channel is thus effectively blocked. + * Closing and reopening the AT channel does *not* clear + * this condition. + * As a stopgap measure, submit a zero-length AT read + * before closing the AT channel. This has the undocumented + * effect of triggering a new HD_RECEIVEATDATA_ACK message + * from the base if necessary. + * The subsequent AT channel close then discards any pending + * messages. + */ + spin_lock_irqsave(&cs->lock, flags); + if (!(cs->hw.bas->basstate & BS_ATRDPEND)) { + kfree(cs->hw.bas->rcvbuf); + cs->hw.bas->rcvbuf = NULL; + cs->hw.bas->rcvbuf_size = 0; + cs->hw.bas->retry_cmd_in = 0; + atread_submit(cs, 0); + } + spin_unlock_irqrestore(&cs->lock, flags); + rc = req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT); if (cb->wake_tasklet) tasklet_schedule(cb->wake_tasklet); -- cgit v1.2.3-70-g09d2 From c9c0c3043452d30ab87135ba3753ce7855a3a8e7 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Thu, 30 Sep 2010 13:35:42 +0000 Subject: isdn/gigaset: fix bas_gigaset interrupt read error handling Rework the handling of USB errors in interrupt input reads to clear halts correctly, delay URB resubmission after errors, limit retries, and improve error recovery. Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller --- drivers/isdn/gigaset/bas-gigaset.c | 106 ++++++++++++++++++++++++++++++++----- 1 file changed, 93 insertions(+), 13 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 540f6d0bb75..71e3fdee441 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -109,6 +109,9 @@ struct bas_cardstate { struct urb *urb_int_in; /* URB for interrupt pipe */ unsigned char *int_in_buf; + struct work_struct int_in_wq; /* for usb_clear_halt() */ + struct timer_list timer_int_in; /* int read retry delay */ + int retry_int_in; spinlock_t lock; /* locks all following */ int basstate; /* bitmap (BS_*) */ @@ -595,6 +598,62 @@ static int atread_submit(struct cardstate *cs, int timeout) return 0; } +/* int_in_work + * workqueue routine to clear halt on interrupt in endpoint + */ + +static void int_in_work(struct work_struct *work) +{ + struct bas_cardstate *ucs = + container_of(work, struct bas_cardstate, int_in_wq); + struct urb *urb = ucs->urb_int_in; + struct cardstate *cs = urb->context; + int rc; + + /* clear halt condition */ + rc = usb_clear_halt(ucs->udev, urb->pipe); + gig_dbg(DEBUG_USBREQ, "clear_halt: %s", get_usb_rcmsg(rc)); + if (rc == 0) + /* success, resubmit interrupt read URB */ + rc = usb_submit_urb(urb, GFP_ATOMIC); + if (rc != 0 && rc != -ENODEV) { + dev_err(cs->dev, "clear halt failed: %s\n", get_usb_rcmsg(rc)); + rc = usb_lock_device_for_reset(ucs->udev, ucs->interface); + if (rc == 0) { + rc = usb_reset_device(ucs->udev); + usb_unlock_device(ucs->udev); + } + } + ucs->retry_int_in = 0; +} + +/* int_in_resubmit + * timer routine for interrupt read delayed resubmit + * argument: + * controller state structure + */ +static void int_in_resubmit(unsigned long data) +{ + struct cardstate *cs = (struct cardstate *) data; + struct bas_cardstate *ucs = cs->hw.bas; + int rc; + + if (ucs->retry_int_in++ >= BAS_RETRY) { + dev_err(cs->dev, "interrupt read: giving up after %d tries\n", + ucs->retry_int_in); + usb_queue_reset_device(ucs->interface); + return; + } + + gig_dbg(DEBUG_USBREQ, "%s: retry %d", __func__, ucs->retry_int_in); + rc = usb_submit_urb(ucs->urb_int_in, GFP_ATOMIC); + if (rc != 0 && rc != -ENODEV) { + dev_err(cs->dev, "could not resubmit interrupt URB: %s\n", + get_usb_rcmsg(rc)); + usb_queue_reset_device(ucs->interface); + } +} + /* read_int_callback * USB completion handler for interrupt pipe input * called by the USB subsystem in interrupt context @@ -615,19 +674,29 @@ static void read_int_callback(struct urb *urb) switch (status) { case 0: /* success */ + ucs->retry_int_in = 0; break; + case -EPIPE: /* endpoint stalled */ + schedule_work(&ucs->int_in_wq); + /* fall through */ case -ENOENT: /* cancelled */ case -ECONNRESET: /* cancelled (async) */ case -EINPROGRESS: /* pending */ - /* ignore silently */ + case -ENODEV: /* device removed */ + case -ESHUTDOWN: /* device shut down */ + /* no further action necessary */ gig_dbg(DEBUG_USBREQ, "%s: %s", __func__, get_usb_statmsg(status)); return; - case -ENODEV: /* device removed */ - case -ESHUTDOWN: /* device shut down */ - gig_dbg(DEBUG_USBREQ, "%s: device disconnected", __func__); + case -EPROTO: /* protocol error or unplug */ + case -EILSEQ: + case -ETIME: + /* resubmit after delay */ + gig_dbg(DEBUG_USBREQ, "%s: %s", + __func__, get_usb_statmsg(status)); + mod_timer(&ucs->timer_int_in, jiffies + HZ / 10); return; - default: /* severe trouble */ + default: /* other errors: just resubmit */ dev_warn(cs->dev, "interrupt read: %s\n", get_usb_statmsg(status)); goto resubmit; @@ -705,6 +774,13 @@ static void read_int_callback(struct urb *urb) break; } spin_lock_irqsave(&cs->lock, flags); + if (ucs->basstate & BS_ATRDPEND) { + spin_unlock_irqrestore(&cs->lock, flags); + dev_warn(cs->dev, + "HD_RECEIVEATDATA_ACK(%d) during HD_READ_ATMESSAGE(%d) ignored\n", + l, ucs->rcvbuf_size); + break; + } if (ucs->rcvbuf_size) { /* throw away previous buffer - we have no queue */ dev_err(cs->dev, @@ -717,7 +793,6 @@ static void read_int_callback(struct urb *urb) if (ucs->rcvbuf == NULL) { spin_unlock_irqrestore(&cs->lock, flags); dev_err(cs->dev, "out of memory receiving AT data\n"); - error_reset(cs); break; } ucs->rcvbuf_size = l; @@ -727,13 +802,10 @@ static void read_int_callback(struct urb *urb) kfree(ucs->rcvbuf); ucs->rcvbuf = NULL; ucs->rcvbuf_size = 0; - if (rc != -ENODEV) { - spin_unlock_irqrestore(&cs->lock, flags); - error_reset(cs); - break; - } } spin_unlock_irqrestore(&cs->lock, flags); + if (rc < 0 && rc != -ENODEV) + error_reset(cs); break; case HD_RESET_INTERRUPT_PIPE_ACK: @@ -2138,7 +2210,9 @@ static int gigaset_initcshw(struct cardstate *cs) setup_timer(&ucs->timer_ctrl, req_timeout, (unsigned long) cs); setup_timer(&ucs->timer_atrdy, atrdy_timeout, (unsigned long) cs); setup_timer(&ucs->timer_cmd_in, cmd_in_timeout, (unsigned long) cs); + setup_timer(&ucs->timer_int_in, int_in_resubmit, (unsigned long) cs); init_waitqueue_head(&ucs->waitqueue); + INIT_WORK(&ucs->int_in_wq, int_in_work); return 1; } @@ -2286,6 +2360,7 @@ static int gigaset_probe(struct usb_interface *interface, get_usb_rcmsg(rc)); goto error; } + ucs->retry_int_in = 0; /* tell the device that the driver is ready */ rc = req_submit(cs->bcs, HD_DEVICE_INIT_ACK, 0, 0); @@ -2338,10 +2413,12 @@ static void gigaset_disconnect(struct usb_interface *interface) /* stop driver (common part) */ gigaset_stop(cs); - /* stop timers and URBs, free ressources */ + /* stop delayed work and URBs, free ressources */ del_timer_sync(&ucs->timer_ctrl); del_timer_sync(&ucs->timer_atrdy); del_timer_sync(&ucs->timer_cmd_in); + del_timer_sync(&ucs->timer_int_in); + cancel_work_sync(&ucs->int_in_wq); freeurbs(cs); usb_set_intfdata(interface, NULL); kfree(ucs->rcvbuf); @@ -2404,12 +2481,14 @@ static int gigaset_suspend(struct usb_interface *intf, pm_message_t message) /* in case of timeout, proceed anyway */ } - /* kill all URBs and timers that might still be pending */ + /* kill all URBs and delayed work that might still be pending */ usb_kill_urb(ucs->urb_ctrl); usb_kill_urb(ucs->urb_int_in); del_timer_sync(&ucs->timer_ctrl); del_timer_sync(&ucs->timer_atrdy); del_timer_sync(&ucs->timer_cmd_in); + del_timer_sync(&ucs->timer_int_in); + cancel_work_sync(&ucs->int_in_wq); gig_dbg(DEBUG_SUSPEND, "suspend complete"); return 0; @@ -2431,6 +2510,7 @@ static int gigaset_resume(struct usb_interface *intf) get_usb_rcmsg(rc)); return rc; } + ucs->retry_int_in = 0; /* clear suspend flag to reallow activity */ update_basstate(ucs, 0, BS_SUSPEND); -- cgit v1.2.3-70-g09d2 From bb7196d2bf30e4cb06fe5fed046c9084465e854c Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Thu, 30 Sep 2010 13:35:52 +0000 Subject: isdn/gigaset: improve bas_gigaset USB error reporting Rephrase some USB error messages to make them clearer and more consistent. Downgrade some warning messages that may occur during normal operation to debug messages. Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller --- drivers/isdn/gigaset/bas-gigaset.c | 112 ++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 51 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 71e3fdee441..178942a2ee6 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -172,7 +172,7 @@ static char *get_usb_rcmsg(int rc) case -EAGAIN: return "start frame too early or too much scheduled"; case -EFBIG: - return "too many isochronous frames requested"; + return "too many isoc frames requested"; case -EPIPE: return "endpoint stalled"; case -EMSGSIZE: @@ -203,13 +203,13 @@ static char *get_usb_statmsg(int status) case -ENOENT: return "unlinked (sync)"; case -EINPROGRESS: - return "pending"; + return "URB still pending"; case -EPROTO: - return "bit stuffing error, timeout, or unknown USB error"; + return "bitstuff error, timeout, or unknown USB error"; case -EILSEQ: return "CRC mismatch, timeout, or unknown USB error"; case -ETIME: - return "timed out"; + return "USB response timeout"; case -EPIPE: return "endpoint stalled"; case -ECOMM: @@ -217,15 +217,15 @@ static char *get_usb_statmsg(int status) case -ENOSR: return "OUT buffer underrun"; case -EOVERFLOW: - return "too much data"; + return "endpoint babble"; case -EREMOTEIO: - return "short packet detected"; + return "short packet"; case -ENODEV: return "device removed"; case -EXDEV: - return "partial isochronous transfer"; + return "partial isoc transfer"; case -EINVAL: - return "invalid argument"; + return "ISO madness"; case -ECONNRESET: return "unlinked (async)"; case -ESHUTDOWN: @@ -872,6 +872,7 @@ static void read_iso_callback(struct urb *urb) tasklet_hi_schedule(&ubc->rcvd_tasklet); } else { /* tasklet still busy, drop data and resubmit URB */ + gig_dbg(DEBUG_ISO, "%s: overrun", __func__); ubc->loststatus = status; for (i = 0; i < BAS_NUMFRAMES; i++) { ubc->isoinlost += urb->iso_frame_desc[i].actual_length; @@ -887,13 +888,11 @@ static void read_iso_callback(struct urb *urb) urb->dev = bcs->cs->hw.bas->udev; urb->transfer_flags = URB_ISO_ASAP; urb->number_of_packets = BAS_NUMFRAMES; - gig_dbg(DEBUG_ISO, "%s: isoc read overrun/resubmit", - __func__); rc = usb_submit_urb(urb, GFP_ATOMIC); if (unlikely(rc != 0 && rc != -ENODEV)) { dev_err(bcs->cs->dev, - "could not resubmit isochronous read " - "URB: %s\n", get_usb_rcmsg(rc)); + "could not resubmit isoc read URB: %s\n", + get_usb_rcmsg(rc)); dump_urb(DEBUG_ISO, "isoc read", urb); error_hangup(bcs); } @@ -1135,7 +1134,7 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx) gig_dbg(DEBUG_ISO, "%s: disconnected", __func__); else dev_err(ucx->bcs->cs->dev, - "could not submit isochronous write URB: %s\n", + "could not submit isoc write URB: %s\n", get_usb_rcmsg(rc)); return rc; } @@ -1180,7 +1179,7 @@ static void write_iso_tasklet(unsigned long data) ubc->isooutovfl = NULL; spin_unlock_irqrestore(&ubc->isooutlock, flags); if (ovfl) { - dev_err(cs->dev, "isochronous write buffer underrun\n"); + dev_err(cs->dev, "isoc write underrun\n"); error_hangup(bcs); break; } @@ -1205,7 +1204,7 @@ static void write_iso_tasklet(unsigned long data) if (next) { /* couldn't put it back */ dev_err(cs->dev, - "losing isochronous write URB\n"); + "losing isoc write URB\n"); error_hangup(bcs); } } @@ -1232,10 +1231,10 @@ static void write_iso_tasklet(unsigned long data) if (ifd->status || ifd->actual_length != ifd->length) { dev_warn(cs->dev, - "isochronous write: frame %d: %s, " - "only %d of %d bytes sent\n", - i, get_usb_statmsg(ifd->status), - ifd->actual_length, ifd->length); + "isoc write: frame %d[%d/%d]: %s\n", + i, ifd->actual_length, + ifd->length, + get_usb_statmsg(ifd->status)); offset = (ifd->offset + ifd->actual_length) % BAS_OUTBUFSIZE; @@ -1244,11 +1243,11 @@ static void write_iso_tasklet(unsigned long data) } break; case -EPIPE: /* stall - probably underrun */ - dev_err(cs->dev, "isochronous write stalled\n"); + dev_err(cs->dev, "isoc write: stalled\n"); error_hangup(bcs); break; - default: /* severe trouble */ - dev_warn(cs->dev, "isochronous write: %s\n", + default: /* other errors */ + dev_warn(cs->dev, "isoc write: %s\n", get_usb_statmsg(status)); } @@ -1304,6 +1303,7 @@ static void read_iso_tasklet(unsigned long data) struct cardstate *cs = bcs->cs; struct urb *urb; int status; + struct usb_iso_packet_descriptor *ifd; char *rcvbuf; unsigned long flags; int totleft, numbytes, offset, frame, rc; @@ -1321,8 +1321,7 @@ static void read_iso_tasklet(unsigned long data) ubc->isoindone = NULL; if (unlikely(ubc->loststatus != -EINPROGRESS)) { dev_warn(cs->dev, - "isochronous read overrun, " - "dropped URB with status: %s, %d bytes lost\n", + "isoc read overrun, URB dropped (status: %s, %d bytes)\n", get_usb_statmsg(ubc->loststatus), ubc->isoinlost); ubc->loststatus = -EINPROGRESS; @@ -1352,11 +1351,11 @@ static void read_iso_tasklet(unsigned long data) __func__, get_usb_statmsg(status)); continue; /* -> skip */ case -EPIPE: - dev_err(cs->dev, "isochronous read stalled\n"); + dev_err(cs->dev, "isoc read: stalled\n"); error_hangup(bcs); continue; /* -> skip */ - default: /* severe trouble */ - dev_warn(cs->dev, "isochronous read: %s\n", + default: /* other error */ + dev_warn(cs->dev, "isoc read: %s\n", get_usb_statmsg(status)); goto error; } @@ -1364,40 +1363,52 @@ static void read_iso_tasklet(unsigned long data) rcvbuf = urb->transfer_buffer; totleft = urb->actual_length; for (frame = 0; totleft > 0 && frame < BAS_NUMFRAMES; frame++) { - numbytes = urb->iso_frame_desc[frame].actual_length; - if (unlikely(urb->iso_frame_desc[frame].status)) + ifd = &urb->iso_frame_desc[frame]; + numbytes = ifd->actual_length; + switch (ifd->status) { + case 0: /* success */ + break; + case -EPROTO: /* protocol error or unplug */ + case -EILSEQ: + case -ETIME: + /* probably just disconnected, ignore */ + gig_dbg(DEBUG_ISO, + "isoc read: frame %d[%d]: %s\n", + frame, numbytes, + get_usb_statmsg(ifd->status)); + break; + default: /* other error */ + /* report, assume transferred bytes are ok */ dev_warn(cs->dev, - "isochronous read: frame %d[%d]: %s\n", + "isoc read: frame %d[%d]: %s\n", frame, numbytes, - get_usb_statmsg( - urb->iso_frame_desc[frame].status)); + get_usb_statmsg(ifd->status)); + } if (unlikely(numbytes > BAS_MAXFRAME)) dev_warn(cs->dev, - "isochronous read: frame %d: " - "numbytes (%d) > BAS_MAXFRAME\n", - frame, numbytes); + "isoc read: frame %d[%d]: %s\n", + frame, numbytes, + "exceeds max frame size"); if (unlikely(numbytes > totleft)) { dev_warn(cs->dev, - "isochronous read: frame %d: " - "numbytes (%d) > totleft (%d)\n", - frame, numbytes, totleft); + "isoc read: frame %d[%d]: %s\n", + frame, numbytes, + "exceeds total transfer length"); numbytes = totleft; } - offset = urb->iso_frame_desc[frame].offset; + offset = ifd->offset; if (unlikely(offset + numbytes > BAS_INBUFSIZE)) { dev_warn(cs->dev, - "isochronous read: frame %d: " - "offset (%d) + numbytes (%d) " - "> BAS_INBUFSIZE\n", - frame, offset, numbytes); + "isoc read: frame %d[%d]: %s\n", + frame, numbytes, + "exceeds end of buffer"); numbytes = BAS_INBUFSIZE - offset; } gigaset_isoc_receive(rcvbuf + offset, numbytes, bcs); totleft -= numbytes; } if (unlikely(totleft > 0)) - dev_warn(cs->dev, - "isochronous read: %d data bytes missing\n", + dev_warn(cs->dev, "isoc read: %d data bytes missing\n", totleft); error: @@ -1413,9 +1424,9 @@ error: rc = usb_submit_urb(urb, GFP_ATOMIC); if (unlikely(rc != 0 && rc != -ENODEV)) { dev_err(cs->dev, - "could not resubmit isochronous read URB: %s\n", + "could not resubmit isoc read URB: %s\n", get_usb_rcmsg(rc)); - dump_urb(DEBUG_ISO, "resubmit iso read", urb); + dump_urb(DEBUG_ISO, "resubmit isoc read", urb); error_hangup(bcs); } } @@ -1647,8 +1658,7 @@ static int gigaset_init_bchannel(struct bc_state *bcs) if (cs->hw.bas->basstate & BS_SUSPEND) { dev_notice(cs->dev, - "not starting isochronous I/O, " - "suspend in progress\n"); + "not starting isoc I/O, suspend in progress\n"); spin_unlock_irqrestore(&cs->lock, flags); return -EHOSTUNREACH; } @@ -1657,7 +1667,7 @@ static int gigaset_init_bchannel(struct bc_state *bcs) if (ret < 0) { spin_unlock_irqrestore(&cs->lock, flags); dev_err(cs->dev, - "could not start isochronous I/O for channel B%d: %s\n", + "could not start isoc I/O for channel B%d: %s\n", bcs->channel + 1, ret == -EFAULT ? "null URB" : get_usb_rcmsg(ret)); if (ret != -ENODEV) @@ -2086,7 +2096,7 @@ static int gigaset_freebcshw(struct bc_state *bcs) /* kill URBs and tasklets before freeing - better safe than sorry */ ubc->running = 0; - gig_dbg(DEBUG_INIT, "%s: killing iso URBs", __func__); + gig_dbg(DEBUG_INIT, "%s: killing isoc URBs", __func__); for (i = 0; i < BAS_OUTURBS; ++i) { usb_kill_urb(ubc->isoouturbs[i].urb); usb_free_urb(ubc->isoouturbs[i].urb); -- cgit v1.2.3-70-g09d2 From c2dddf941409635601e56c1990c5ab0bd395742c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 4 Oct 2010 09:24:59 +0000 Subject: eicon: make buffer larger In diva_mnt_add_xdi_adapter() we do this: strcpy (clients[id].drvName, tmp); strcpy (clients[id].Dbg.drvName, tmp); The "clients[id].drvName" is a 128 character buffer and "clients[id].Dbg.drvName" was originally a 16 character buffer but I've changed it to 128 as well. We don't actually use 128 characters but we do use more than 16. I've also changed the size of "tmp" to 128 characters instead of 256. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/isdn/hardware/eicon/debug.c | 2 +- drivers/isdn/hardware/eicon/debuglib.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/hardware/eicon/debug.c b/drivers/isdn/hardware/eicon/debug.c index 33ce89eed65..36264012088 100644 --- a/drivers/isdn/hardware/eicon/debug.c +++ b/drivers/isdn/hardware/eicon/debug.c @@ -862,7 +862,7 @@ void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d) { diva_os_spin_lock_magic_t old_irql, old_irql1; dword sec, usec, logical, serial, org_mask; int id, best_id = 0, free_id = -1; - char tmp[256]; + char tmp[128]; diva_dbg_entry_head_t* pmsg = NULL; int len; word size; diff --git a/drivers/isdn/hardware/eicon/debuglib.h b/drivers/isdn/hardware/eicon/debuglib.h index 8ea587783e1..02eed6b4354 100644 --- a/drivers/isdn/hardware/eicon/debuglib.h +++ b/drivers/isdn/hardware/eicon/debuglib.h @@ -249,7 +249,7 @@ typedef struct _DbgHandle_ } regTime ; /* timestamp for registration */ void *pIrp ; /* ptr to pending i/o request */ unsigned long dbgMask ; /* current debug mask */ - char drvName[16] ; /* ASCII name of registered driver */ + char drvName[128] ; /* ASCII name of registered driver */ char drvTag[64] ; /* revision string */ DbgEnd dbg_end ; /* function for debug closing */ DbgLog dbg_prt ; /* function for debug appending */ -- cgit v1.2.3-70-g09d2 From b003f4e171304234eae9cc11c9fd7f1cbaaf0d6b Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Sun, 17 Oct 2010 05:18:15 +0000 Subject: CAPI: Silence lockdep warning on get_capi_appl_by_nr usage As long as we hold capi_controller_lock, we can safely access capi_applications without RCU protection as no one can modify the application list underneath us. Introduce an RCU-free __get_capi_appl_by_nr for this purpose. This silences lockdep warnings on suspicious rcu_dereference usage. Signed-off-by: Jan Kiszka Signed-off-by: David S. Miller --- drivers/isdn/capi/kcapi.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers/isdn') diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index b054494df84..3acf94cc5ac 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -98,6 +98,16 @@ static inline struct capi_ctr *get_capi_ctr_by_nr(u16 contr) return capi_controller[contr - 1]; } +static inline struct capi20_appl *__get_capi_appl_by_nr(u16 applid) +{ + lockdep_assert_held(&capi_controller_lock); + + if (applid - 1 >= CAPI_MAXAPPL) + return NULL; + + return capi_applications[applid - 1]; +} + static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid) { if (applid - 1 >= CAPI_MAXAPPL) @@ -185,10 +195,9 @@ static void notify_up(u32 contr) ctr->state = CAPI_CTR_RUNNING; for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { - ap = get_capi_appl_by_nr(applid); - if (!ap) - continue; - register_appl(ctr, applid, &ap->rparam); + ap = __get_capi_appl_by_nr(applid); + if (ap) + register_appl(ctr, applid, &ap->rparam); } wake_up_interruptible_all(&ctr->state_wait_queue); @@ -215,7 +224,7 @@ static void ctr_down(struct capi_ctr *ctr, int new_state) memset(ctr->serial, 0, sizeof(ctr->serial)); for (applid = 1; applid <= CAPI_MAXAPPL; applid++) { - ap = get_capi_appl_by_nr(applid); + ap = __get_capi_appl_by_nr(applid); if (ap) capi_ctr_put(ctr); } -- cgit v1.2.3-70-g09d2