diff options
| author | Kai Germaschewski <kai@tp1.ruhr-uni-bochum.de> | 2002-10-29 08:49:56 -0600 |
|---|---|---|
| committer | Kai Germaschewski <kai@tp1.ruhr-uni-bochum.de> | 2002-10-29 08:49:56 -0600 |
| commit | 620a00187ea32b497e5cf46aa73949b5ad7a4fbf (patch) | |
| tree | 8c030213c36e5583f96043ab2a53989e912af72e | |
| parent | 772059d9ff21963bbc890b94f735f2d93d067173 (diff) | |
ISDN: Move the tty receive queue out of generic code
Moving the tty receive queue into the tty-specific data in fact
simplifies the common code (which doesn't need to know it at all, now),
and the tty code, which can access the queue more directly.
| -rw-r--r-- | drivers/isdn/i4l/isdn_audio.c | 5 | ||||
| -rw-r--r-- | drivers/isdn/i4l/isdn_common.c | 182 | ||||
| -rw-r--r-- | drivers/isdn/i4l/isdn_common.h | 3 | ||||
| -rw-r--r-- | drivers/isdn/i4l/isdn_tty.c | 110 | ||||
| -rw-r--r-- | drivers/isdn/i4l/isdn_tty.h | 7 | ||||
| -rw-r--r-- | include/linux/isdn.h | 3 |
6 files changed, 119 insertions, 191 deletions
diff --git a/drivers/isdn/i4l/isdn_audio.c b/drivers/isdn/i4l/isdn_audio.c index 4a4bfcd68f6b..fddfa960b0bb 100644 --- a/drivers/isdn/i4l/isdn_audio.c +++ b/drivers/isdn/i4l/isdn_audio.c @@ -14,6 +14,7 @@ #include <linux/isdn.h> #include "isdn_audio.h" #include "isdn_common.h" +#include "isdn_tty.h" /* * Misc. lookup-tables. @@ -564,7 +565,7 @@ isdn_audio_eval_dtmf(modem_info * info) cli(); di = isdn_slot_driver(info->isdn_slot); ch = isdn_slot_channel(info->isdn_slot); - isdn_slot_queue_tail(info->isdn_slot, skb, 2); + isdn_tty_queue_tail(info, skb, 2); restore_flags(flags); /* Schedule dequeuing */ if ((dev->modempoll) && (info->rcvsched)) @@ -683,7 +684,7 @@ isdn_audio_put_dle_code(modem_info * info, u_char code) cli(); di = isdn_slot_driver(info->isdn_slot); ch = isdn_slot_channel(info->isdn_slot); - isdn_slot_queue_tail(info->isdn_slot, skb, 2); + isdn_tty_queue_tail(info, skb, 2); restore_flags(flags); /* Schedule dequeuing */ if ((dev->modempoll) && (info->rcvsched)) diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index 3383f1f341b2..8c58b98c3438 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -299,13 +299,8 @@ slot_data_req(struct fsm_inst *fi, int pr, void *arg) { struct isdn_slot *slot = fi->userdata; struct sk_buff *skb = arg; - int retval; - /* Update statistics */ -// slots[sl].ibytes += skb->len; - - retval = isdn_drv_writebuf_skb(slot->di, slot->ch, 1, skb); - return retval; + return isdn_drv_writebuf_skb(slot->di, slot->ch, 1, skb); } static int @@ -401,7 +396,6 @@ slot_unbind(struct fsm_inst *fi, int pr, void *arg) slot->iv110.v110 = NULL; // 20.10.99 JIM, try to reinitialize v110 ! isdn_slot_set_usage(sl, ISDN_USAGE_NONE); - isdn_slot_queue_purge(sl); return 0; } @@ -497,12 +491,6 @@ struct isdn_driver { int maxbufsize; /* Maximum Buffersize supported*/ int stavail; /* Chars avail on Status-device*/ isdn_if *interface; /* Interface to driver */ - int *rcverr; /* Error-counters for B rx */ - int *rcvcount; /* Byte-counters for B rx */ - struct sk_buff_head *rpqueue; -#ifdef CONFIG_ISDN_AUDIO - unsigned long DLEflag; /* Insert DLE at next read */ -#endif char msn2eaz[10][ISDN_MSNLEN]; /* MSN->EAZ */ struct fsm_inst fi; } driver; @@ -578,13 +566,6 @@ isdn_drv_lookup(char *drvid) static void drv_destroy(struct isdn_driver *drv) { - int i; - - kfree(drv->rcverr); - kfree(drv->rcvcount); - for (i = 0; i < drv->channels; i++) - skb_queue_purge(&drv->rpqueue[i]); - kfree(drv->rpqueue); kfree(drv); } @@ -1446,108 +1427,6 @@ isdn_getnum(char **p) #define DLE 0x10 -/* - * isdn_slot_readbchan() tries to get data from the read-queue. - * It MUST be called with interrupts off. - */ -int -isdn_slot_readbchan(int sl, u_char * buf, u_char * fp, int len) -{ - int count; - int count_pull; - int count_put; - int dflag; - int di = isdn_slot_driver(sl); - int ch = isdn_slot_channel(sl); - struct sk_buff *skb; - u_char *cp; - - if (!drivers[di]) - return 0; - if (skb_queue_empty(&drivers[di]->rpqueue[ch])) - return 0; - - if (len > drivers[di]->rcvcount[ch]) - len = drivers[di]->rcvcount[ch]; - cp = buf; - count = 0; - while (len) { - if (!(skb = skb_peek(&drivers[di]->rpqueue[ch]))) - break; -#ifdef CONFIG_ISDN_AUDIO - if (ISDN_AUDIO_SKB_LOCK(skb)) - break; - ISDN_AUDIO_SKB_LOCK(skb) = 1; - if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (drivers[di]->DLEflag & (1 << ch))) { - char *p = skb->data; - unsigned long DLEmask = (1 << ch); - - dflag = 0; - count_pull = count_put = 0; - while ((count_pull < skb->len) && (len > 0)) { - len--; - if (drivers[di]->DLEflag & DLEmask) { - *cp++ = DLE; - drivers[di]->DLEflag &= ~DLEmask; - } else { - *cp++ = *p; - if (*p == DLE) { - drivers[di]->DLEflag |= DLEmask; - (ISDN_AUDIO_SKB_DLECOUNT(skb))--; - } - p++; - count_pull++; - } - count_put++; - } - if (count_pull >= skb->len) - dflag = 1; - } else { -#endif - /* No DLE's in buff, so simply copy it */ - dflag = 1; - if ((count_pull = skb->len) > len) { - count_pull = len; - dflag = 0; - } - count_put = count_pull; - memcpy(cp, skb->data, count_put); - cp += count_put; - len -= count_put; -#ifdef CONFIG_ISDN_AUDIO - } -#endif - count += count_put; - if (fp) { - memset(fp, 0, count_put); - fp += count_put; - } - if (dflag) { - /* We got all the data in this buff. - * Now we can dequeue it. - */ - if (fp) - *(fp - 1) = 0xff; -#ifdef CONFIG_ISDN_AUDIO - ISDN_AUDIO_SKB_LOCK(skb) = 0; -#endif - skb = skb_dequeue(&drivers[di]->rpqueue[ch]); - dev_kfree_skb(skb); - } else { - /* Not yet emptied this buff, so it - * must stay in the queue, for further calls - * but we pull off the data we got until now. - */ - skb_pull(skb, count_pull); -#ifdef CONFIG_ISDN_AUDIO - ISDN_AUDIO_SKB_LOCK(skb) = 0; -#endif - } - drivers[di]->rcvcount[ch] -= count_put; - } - return count; -} - static __inline int isdn_minor2drv(int minor) { @@ -2380,40 +2259,6 @@ isdn_add_channels(struct isdn_driver *d, int drvidx, int n, int adding) ISDN_MAX_CHANNELS); return -1; } - if ((adding) && (d->rcverr)) - kfree(d->rcverr); - if (!(d->rcverr = kmalloc(sizeof(int) * m, GFP_KERNEL))) { - printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n"); - return -1; - } - memset((char *) d->rcverr, 0, sizeof(int) * m); - - if ((adding) && (d->rcvcount)) - kfree(d->rcvcount); - if (!(d->rcvcount = kmalloc(sizeof(int) * m, GFP_KERNEL))) { - printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n"); - if (!adding) kfree(d->rcverr); - return -1; - } - memset((char *) d->rcvcount, 0, sizeof(int) * m); - - if ((adding) && (d->rpqueue)) { - for (j = 0; j < d->channels; j++) - skb_queue_purge(&d->rpqueue[j]); - kfree(d->rpqueue); - } - if (!(d->rpqueue = kmalloc(sizeof(struct sk_buff_head) * m, GFP_KERNEL))) { - printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n"); - if (!adding) { - kfree(d->rcvcount); - kfree(d->rcverr); - } - return -1; - } - for (j = 0; j < m; j++) { - skb_queue_head_init(&d->rpqueue[j]); - } - dev->channels += n; save_flags(flags); cli(); @@ -2690,31 +2535,6 @@ isdn_slot_priv(int sl) } int -isdn_slot_queue_empty(int sl) -{ - BUG_ON(sl < 0); - - return skb_queue_empty(&drivers[slots[sl].di]->rpqueue[slots[sl].ch]); -} - -void -isdn_slot_queue_tail(int sl, struct sk_buff *skb, int len) -{ - BUG_ON(sl < 0); - - __skb_queue_tail(&drivers[slots[sl].di]->rpqueue[slots[sl].ch], skb); - drivers[slots[sl].di]->rcvcount[slots[sl].ch] += len; -} - -void -isdn_slot_queue_purge(int sl) -{ - BUG_ON(sl < 0); - - skb_queue_purge(&drivers[slots[sl].di]->rpqueue[slots[sl].ch]); -} - -int isdn_hard_header_len(void) { int drvidx; diff --git a/drivers/isdn/i4l/isdn_common.h b/drivers/isdn/i4l/isdn_common.h index f06ccab719f2..edcf4f00d8e2 100644 --- a/drivers/isdn/i4l/isdn_common.h +++ b/drivers/isdn/i4l/isdn_common.h @@ -99,9 +99,6 @@ extern void isdn_slot_set_priv(int sl, int usage, void *priv, int (*stat_cb)(in extern void *isdn_slot_priv(int sl); extern int isdn_hard_header_len(void); -int isdn_slot_queue_empty(int sl); -void isdn_slot_queue_tail(int sl, struct sk_buff *skb, int len); -void isdn_slot_queue_purge(int sl); int isdn_drv_maxbufsize(int di); int isdn_drv_writebuf_skb(int di, int ch, int x, struct sk_buff *skb); int isdn_drv_hdrlen(int di); diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index a4c7d393e58a..3a688ba73c07 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -110,6 +110,103 @@ isdn_tty_try_read(modem_info * info, struct sk_buff *skb) return 0; } +/* + * isdn_slot_readbchan() tries to get data from the read-queue. + * It MUST be called with interrupts off. + */ +static int +isdn_tty_readbchan(struct modem_info *info, u_char * buf, u_char * fp, int len) +{ + int count; + int count_pull; + int count_put; + int dflag; + struct sk_buff *skb; + u_char *cp; + + if (skb_queue_empty(&info->rpqueue)) + return 0; + + if (len > info->rcvcount) + len = info->rcvcount; + cp = buf; + count = 0; + while (len) { + if (!(skb = skb_peek(&info->rpqueue))) + break; +#ifdef CONFIG_ISDN_AUDIO + if (ISDN_AUDIO_SKB_LOCK(skb)) + break; + ISDN_AUDIO_SKB_LOCK(skb) = 1; + if (ISDN_AUDIO_SKB_DLECOUNT(skb) || info->DLEflag) { + char *p = skb->data; + + dflag = 0; + count_pull = count_put = 0; + while ((count_pull < skb->len) && (len > 0)) { + len--; + if (info->DLEflag) { + *cp++ = DLE; + info->DLEflag = 0; + } else { + *cp++ = *p; + if (*p == DLE) { + info->DLEflag = 1; + (ISDN_AUDIO_SKB_DLECOUNT(skb))--; + } + p++; + count_pull++; + } + count_put++; + } + if (count_pull >= skb->len) + dflag = 1; + } else { +#endif + /* No DLE's in buff, so simply copy it */ + dflag = 1; + if ((count_pull = skb->len) > len) { + count_pull = len; + dflag = 0; + } + count_put = count_pull; + memcpy(cp, skb->data, count_put); + cp += count_put; + len -= count_put; +#ifdef CONFIG_ISDN_AUDIO + } +#endif + count += count_put; + if (fp) { + memset(fp, 0, count_put); + fp += count_put; + } + if (dflag) { + /* We got all the data in this buff. + * Now we can dequeue it. + */ + if (fp) + *(fp - 1) = 0xff; +#ifdef CONFIG_ISDN_AUDIO + ISDN_AUDIO_SKB_LOCK(skb) = 0; +#endif + skb = skb_dequeue(&info->rpqueue); + dev_kfree_skb(skb); + } else { + /* Not yet emptied this buff, so it + * must stay in the queue, for further calls + * but we pull off the data we got until now. + */ + skb_pull(skb, count_pull); +#ifdef CONFIG_ISDN_AUDIO + ISDN_AUDIO_SKB_LOCK(skb) = 0; +#endif + } + info->rcvcount -= count_put; + } + return count; +} + /* isdn_tty_readmodem() is called periodically from within timer-interrupt. * It tries getting received data from the receive queue an stuff it into * the tty's flip-buffer. @@ -142,7 +239,7 @@ isdn_tty_readmodem(void) if (c > 0) { save_flags(flags); cli(); - r = isdn_slot_readbchan(info->isdn_slot, + r = isdn_tty_readbchan(info, tty->flip.char_buf_ptr, tty->flip.flag_buf_ptr, c); /* CISCO AsyncPPP Hack */ @@ -263,7 +360,7 @@ isdn_tty_rcv_skb(int i, struct sk_buff *skb) /* Try to deliver directly via tty-flip-buf if queue is empty */ save_flags(flags); cli(); - if (isdn_slot_queue_empty(i)) + if (skb_queue_empty(&info->rpqueue)) if (isdn_tty_try_read(info, skb)) { restore_flags(flags); return 1; @@ -271,7 +368,7 @@ isdn_tty_rcv_skb(int i, struct sk_buff *skb) /* Direct deliver failed or queue wasn't empty. * Queue up for later dequeueing via timer-irq. */ - isdn_slot_queue_tail(i, skb, skb->len + isdn_tty_queue_tail(info, skb, skb->len #ifdef CONFIG_ISDN_AUDIO + ISDN_AUDIO_SKB_DLECOUNT(skb) #endif @@ -739,6 +836,7 @@ isdn_tty_modem_hup(modem_info * info, int local) isdn_slot_all_eaz(slot); info->emu.mdmreg[REG_RINGCNT] = 0; + skb_queue_purge(&info->rpqueue); isdn_slot_free(slot); isdn_slot_set_priv(slot, 0, NULL, NULL, NULL); info->isdn_slot = -1; @@ -2025,6 +2123,7 @@ isdn_tty_init(void) init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); info->isdn_slot = -1; + skb_queue_head_init(&info->rpqueue); info->xmit_size = ISDN_SERIAL_XMIT_SIZE; skb_queue_head_init(&info->xmit_queue); #ifdef CONFIG_ISDN_AUDIO @@ -2067,6 +2166,7 @@ isdn_tty_exit(void) for (i = 0; i < ISDN_MAX_CHANNELS; i++) { info = &isdn_mdm.info[i]; isdn_tty_cleanup_xmit(info); + skb_queue_purge(&info->rpqueue); #ifdef CONFIG_ISDN_TTY_FAX kfree(info->fax); #endif @@ -2430,7 +2530,7 @@ isdn_tty_at_cout(char *msg, modem_info * info) di = -1; ch = -1; } if ((info->online) && (((tty->flip.count + strlen(msg)) >= TTY_FLIPBUF_SIZE) || - (!isdn_slot_queue_empty(info->isdn_slot)))) { + (!skb_queue_empty(&info->rpqueue)))) { skb = alloc_skb(strlen(msg) #ifdef CONFIG_ISDN_AUDIO + sizeof(isdn_audio_skb) @@ -2473,7 +2573,7 @@ isdn_tty_at_cout(char *msg, modem_info * info) } } if (skb) { - isdn_slot_queue_tail(info->isdn_slot, skb, skb->len); + isdn_tty_queue_tail(info, skb, skb->len); restore_flags(flags); /* Schedule dequeuing */ if ((dev->modempoll) && (info->rcvsched)) diff --git a/drivers/isdn/i4l/isdn_tty.h b/drivers/isdn/i4l/isdn_tty.h index 48194fd4c619..96c14d1765e0 100644 --- a/drivers/isdn/i4l/isdn_tty.h +++ b/drivers/isdn/i4l/isdn_tty.h @@ -129,3 +129,10 @@ struct isdn_modem { }; extern struct isdn_modem isdn_mdm; + +static inline void +isdn_tty_queue_tail(modem_info *info, struct sk_buff *skb, int len) +{ + __skb_queue_tail(&info->rpqueue, skb); + info->rcvcount += len; +} diff --git a/include/linux/isdn.h b/include/linux/isdn.h index 74376a0a5e38..4ab5ac856cc9 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -328,6 +328,8 @@ typedef struct modem_info { int dialing; /* Dial in progress or ATA */ int rcvsched; /* Receive needs schedule */ int isdn_slot; /* Index to isdn-driver/channel */ + struct sk_buff_head rpqueue; /* Queue of recv'd packets */ + int rcvcount; /* Byte-counters for B rx */ int ncarrier; /* Flag: schedule NO CARRIER */ unsigned char last_cause[8]; /* Last cause message */ unsigned char last_num[ISDN_MSNLEN]; @@ -344,6 +346,7 @@ typedef struct modem_info { struct sk_buff_head xmit_queue; /* transmit queue */ atomic_t xmit_lock; /* Semaphore for isdn_tty_write */ #ifdef CONFIG_ISDN_AUDIO + unsigned long DLEflag; /* Insert DLE at next read */ int vonline; /* Voice-channel status */ /* Bit 0 = recording */ /* Bit 1 = playback */ |
