Commit 620a0018 authored by Kai Germaschewski's avatar Kai Germaschewski

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.
parent 772059d9
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/isdn.h> #include <linux/isdn.h>
#include "isdn_audio.h" #include "isdn_audio.h"
#include "isdn_common.h" #include "isdn_common.h"
#include "isdn_tty.h"
/* /*
* Misc. lookup-tables. * Misc. lookup-tables.
...@@ -564,7 +565,7 @@ isdn_audio_eval_dtmf(modem_info * info) ...@@ -564,7 +565,7 @@ isdn_audio_eval_dtmf(modem_info * info)
cli(); cli();
di = isdn_slot_driver(info->isdn_slot); di = isdn_slot_driver(info->isdn_slot);
ch = isdn_slot_channel(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); restore_flags(flags);
/* Schedule dequeuing */ /* Schedule dequeuing */
if ((dev->modempoll) && (info->rcvsched)) if ((dev->modempoll) && (info->rcvsched))
...@@ -683,7 +684,7 @@ isdn_audio_put_dle_code(modem_info * info, u_char code) ...@@ -683,7 +684,7 @@ isdn_audio_put_dle_code(modem_info * info, u_char code)
cli(); cli();
di = isdn_slot_driver(info->isdn_slot); di = isdn_slot_driver(info->isdn_slot);
ch = isdn_slot_channel(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); restore_flags(flags);
/* Schedule dequeuing */ /* Schedule dequeuing */
if ((dev->modempoll) && (info->rcvsched)) if ((dev->modempoll) && (info->rcvsched))
......
...@@ -299,13 +299,8 @@ slot_data_req(struct fsm_inst *fi, int pr, void *arg) ...@@ -299,13 +299,8 @@ slot_data_req(struct fsm_inst *fi, int pr, void *arg)
{ {
struct isdn_slot *slot = fi->userdata; struct isdn_slot *slot = fi->userdata;
struct sk_buff *skb = arg; struct sk_buff *skb = arg;
int retval;
/* Update statistics */ return isdn_drv_writebuf_skb(slot->di, slot->ch, 1, skb);
// slots[sl].ibytes += skb->len;
retval = isdn_drv_writebuf_skb(slot->di, slot->ch, 1, skb);
return retval;
} }
static int static int
...@@ -401,7 +396,6 @@ slot_unbind(struct fsm_inst *fi, int pr, void *arg) ...@@ -401,7 +396,6 @@ slot_unbind(struct fsm_inst *fi, int pr, void *arg)
slot->iv110.v110 = NULL; slot->iv110.v110 = NULL;
// 20.10.99 JIM, try to reinitialize v110 ! // 20.10.99 JIM, try to reinitialize v110 !
isdn_slot_set_usage(sl, ISDN_USAGE_NONE); isdn_slot_set_usage(sl, ISDN_USAGE_NONE);
isdn_slot_queue_purge(sl);
return 0; return 0;
} }
...@@ -497,12 +491,6 @@ struct isdn_driver { ...@@ -497,12 +491,6 @@ struct isdn_driver {
int maxbufsize; /* Maximum Buffersize supported*/ int maxbufsize; /* Maximum Buffersize supported*/
int stavail; /* Chars avail on Status-device*/ int stavail; /* Chars avail on Status-device*/
isdn_if *interface; /* Interface to driver */ 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 */ char msn2eaz[10][ISDN_MSNLEN]; /* MSN->EAZ */
struct fsm_inst fi; struct fsm_inst fi;
} driver; } driver;
...@@ -578,13 +566,6 @@ isdn_drv_lookup(char *drvid) ...@@ -578,13 +566,6 @@ isdn_drv_lookup(char *drvid)
static void static void
drv_destroy(struct isdn_driver *drv) 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); kfree(drv);
} }
...@@ -1446,108 +1427,6 @@ isdn_getnum(char **p) ...@@ -1446,108 +1427,6 @@ isdn_getnum(char **p)
#define DLE 0x10 #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 static __inline int
isdn_minor2drv(int minor) isdn_minor2drv(int minor)
{ {
...@@ -2380,40 +2259,6 @@ isdn_add_channels(struct isdn_driver *d, int drvidx, int n, int adding) ...@@ -2380,40 +2259,6 @@ isdn_add_channels(struct isdn_driver *d, int drvidx, int n, int adding)
ISDN_MAX_CHANNELS); ISDN_MAX_CHANNELS);
return -1; 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; dev->channels += n;
save_flags(flags); save_flags(flags);
cli(); cli();
...@@ -2689,31 +2534,6 @@ isdn_slot_priv(int sl) ...@@ -2689,31 +2534,6 @@ isdn_slot_priv(int sl)
return slots[sl].priv; return slots[sl].priv;
} }
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 int
isdn_hard_header_len(void) isdn_hard_header_len(void)
{ {
......
...@@ -99,9 +99,6 @@ extern void isdn_slot_set_priv(int sl, int usage, void *priv, int (*stat_cb)(in ...@@ -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 void *isdn_slot_priv(int sl);
extern int isdn_hard_header_len(void); 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_maxbufsize(int di);
int isdn_drv_writebuf_skb(int di, int ch, int x, struct sk_buff *skb); int isdn_drv_writebuf_skb(int di, int ch, int x, struct sk_buff *skb);
int isdn_drv_hdrlen(int di); int isdn_drv_hdrlen(int di);
......
...@@ -110,6 +110,103 @@ isdn_tty_try_read(modem_info * info, struct sk_buff *skb) ...@@ -110,6 +110,103 @@ isdn_tty_try_read(modem_info * info, struct sk_buff *skb)
return 0; 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. /* isdn_tty_readmodem() is called periodically from within timer-interrupt.
* It tries getting received data from the receive queue an stuff it into * It tries getting received data from the receive queue an stuff it into
* the tty's flip-buffer. * the tty's flip-buffer.
...@@ -142,7 +239,7 @@ isdn_tty_readmodem(void) ...@@ -142,7 +239,7 @@ isdn_tty_readmodem(void)
if (c > 0) { if (c > 0) {
save_flags(flags); save_flags(flags);
cli(); cli();
r = isdn_slot_readbchan(info->isdn_slot, r = isdn_tty_readbchan(info,
tty->flip.char_buf_ptr, tty->flip.char_buf_ptr,
tty->flip.flag_buf_ptr, c); tty->flip.flag_buf_ptr, c);
/* CISCO AsyncPPP Hack */ /* CISCO AsyncPPP Hack */
...@@ -263,7 +360,7 @@ isdn_tty_rcv_skb(int i, struct sk_buff *skb) ...@@ -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 */ /* Try to deliver directly via tty-flip-buf if queue is empty */
save_flags(flags); save_flags(flags);
cli(); cli();
if (isdn_slot_queue_empty(i)) if (skb_queue_empty(&info->rpqueue))
if (isdn_tty_try_read(info, skb)) { if (isdn_tty_try_read(info, skb)) {
restore_flags(flags); restore_flags(flags);
return 1; return 1;
...@@ -271,7 +368,7 @@ isdn_tty_rcv_skb(int i, struct sk_buff *skb) ...@@ -271,7 +368,7 @@ isdn_tty_rcv_skb(int i, struct sk_buff *skb)
/* Direct deliver failed or queue wasn't empty. /* Direct deliver failed or queue wasn't empty.
* Queue up for later dequeueing via timer-irq. * 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 #ifdef CONFIG_ISDN_AUDIO
+ ISDN_AUDIO_SKB_DLECOUNT(skb) + ISDN_AUDIO_SKB_DLECOUNT(skb)
#endif #endif
...@@ -739,6 +836,7 @@ isdn_tty_modem_hup(modem_info * info, int local) ...@@ -739,6 +836,7 @@ isdn_tty_modem_hup(modem_info * info, int local)
isdn_slot_all_eaz(slot); isdn_slot_all_eaz(slot);
info->emu.mdmreg[REG_RINGCNT] = 0; info->emu.mdmreg[REG_RINGCNT] = 0;
skb_queue_purge(&info->rpqueue);
isdn_slot_free(slot); isdn_slot_free(slot);
isdn_slot_set_priv(slot, 0, NULL, NULL, NULL); isdn_slot_set_priv(slot, 0, NULL, NULL, NULL);
info->isdn_slot = -1; info->isdn_slot = -1;
...@@ -2025,6 +2123,7 @@ isdn_tty_init(void) ...@@ -2025,6 +2123,7 @@ isdn_tty_init(void)
init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->close_wait);
info->isdn_slot = -1; info->isdn_slot = -1;
skb_queue_head_init(&info->rpqueue);
info->xmit_size = ISDN_SERIAL_XMIT_SIZE; info->xmit_size = ISDN_SERIAL_XMIT_SIZE;
skb_queue_head_init(&info->xmit_queue); skb_queue_head_init(&info->xmit_queue);
#ifdef CONFIG_ISDN_AUDIO #ifdef CONFIG_ISDN_AUDIO
...@@ -2067,6 +2166,7 @@ isdn_tty_exit(void) ...@@ -2067,6 +2166,7 @@ isdn_tty_exit(void)
for (i = 0; i < ISDN_MAX_CHANNELS; i++) { for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
info = &isdn_mdm.info[i]; info = &isdn_mdm.info[i];
isdn_tty_cleanup_xmit(info); isdn_tty_cleanup_xmit(info);
skb_queue_purge(&info->rpqueue);
#ifdef CONFIG_ISDN_TTY_FAX #ifdef CONFIG_ISDN_TTY_FAX
kfree(info->fax); kfree(info->fax);
#endif #endif
...@@ -2430,7 +2530,7 @@ isdn_tty_at_cout(char *msg, modem_info * info) ...@@ -2430,7 +2530,7 @@ isdn_tty_at_cout(char *msg, modem_info * info)
di = -1; ch = -1; di = -1; ch = -1;
} }
if ((info->online) && (((tty->flip.count + strlen(msg)) >= TTY_FLIPBUF_SIZE) || 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) skb = alloc_skb(strlen(msg)
#ifdef CONFIG_ISDN_AUDIO #ifdef CONFIG_ISDN_AUDIO
+ sizeof(isdn_audio_skb) + sizeof(isdn_audio_skb)
...@@ -2473,7 +2573,7 @@ isdn_tty_at_cout(char *msg, modem_info * info) ...@@ -2473,7 +2573,7 @@ isdn_tty_at_cout(char *msg, modem_info * info)
} }
} }
if (skb) { if (skb) {
isdn_slot_queue_tail(info->isdn_slot, skb, skb->len); isdn_tty_queue_tail(info, skb, skb->len);
restore_flags(flags); restore_flags(flags);
/* Schedule dequeuing */ /* Schedule dequeuing */
if ((dev->modempoll) && (info->rcvsched)) if ((dev->modempoll) && (info->rcvsched))
......
...@@ -129,3 +129,10 @@ struct isdn_modem { ...@@ -129,3 +129,10 @@ struct isdn_modem {
}; };
extern struct isdn_modem isdn_mdm; 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;
}
...@@ -328,6 +328,8 @@ typedef struct modem_info { ...@@ -328,6 +328,8 @@ typedef struct modem_info {
int dialing; /* Dial in progress or ATA */ int dialing; /* Dial in progress or ATA */
int rcvsched; /* Receive needs schedule */ int rcvsched; /* Receive needs schedule */
int isdn_slot; /* Index to isdn-driver/channel */ 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 */ int ncarrier; /* Flag: schedule NO CARRIER */
unsigned char last_cause[8]; /* Last cause message */ unsigned char last_cause[8]; /* Last cause message */
unsigned char last_num[ISDN_MSNLEN]; unsigned char last_num[ISDN_MSNLEN];
...@@ -344,6 +346,7 @@ typedef struct modem_info { ...@@ -344,6 +346,7 @@ typedef struct modem_info {
struct sk_buff_head xmit_queue; /* transmit queue */ struct sk_buff_head xmit_queue; /* transmit queue */
atomic_t xmit_lock; /* Semaphore for isdn_tty_write */ atomic_t xmit_lock; /* Semaphore for isdn_tty_write */
#ifdef CONFIG_ISDN_AUDIO #ifdef CONFIG_ISDN_AUDIO
unsigned long DLEflag; /* Insert DLE at next read */
int vonline; /* Voice-channel status */ int vonline; /* Voice-channel status */
/* Bit 0 = recording */ /* Bit 0 = recording */
/* Bit 1 = playback */ /* Bit 1 = playback */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment