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 @@
#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))
......
......@@ -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();
......@@ -2689,31 +2534,6 @@ isdn_slot_priv(int sl)
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
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
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);
......
......@@ -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))
......
......@@ -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;
}
......@@ -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 */
......
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