Bugfixes and improvements regarding V.110, V.110 now running.

This commit is contained in:
Fritz Elfert 1998-02-22 19:44:25 +00:00
parent 0e3d57583a
commit 862c1367d1
3 changed files with 143 additions and 116 deletions

View File

@ -21,6 +21,11 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.53 1998/02/20 17:18:05 fritz
* Changes for recent kernels.
* Added common stub for sending commands to lowlevel.
* Added V.110.
*
* Revision 1.52 1998/01/31 22:05:57 keil
* Lots of changes for X.25 support:
* Added generic support for connection-controlling encapsulation protocols
@ -1949,30 +1954,43 @@ int
isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb)
{
int ret;
struct sk_buff *nskb;
int v110_ret = skb->len;
int idx = isdn_dc2minor(drvidx, chan);
if (dev->v110[idx]) {
atomic_inc(&dev->v110use[idx]);
skb = isdn_v110_encode(dev->v110[idx], skb);
nskb = isdn_v110_encode(dev->v110[idx], skb);
atomic_dec(&dev->v110use[idx]);
if (!skb)
if (!nskb)
return 0;
v110_ret = *((int *)nskb->data);
skb_pull(nskb, sizeof(int));
if (!nskb->len) {
dev_kfree_skb(nskb);
dev_kfree_skb(skb);
return v110_ret;
}
/* V.110 must always be acknowledged */
ack = 1;
}
ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb);
ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, nskb);
} else
ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb);
if (ret > 0) {
dev->obytes[idx] += ret;
if (dev->v110[idx]) {
atomic_inc(&dev->v110use[idx]);
dev->v110[idx]->skbuser++;
atomic_dec(&dev->v110use[idx]);
dev_kfree_skb(skb);
/* For V.110 return unencoded data length */
printk(KERN_DEBUG "xmit2 V110 %d\n", skb->len);
ret = v110_ret;
if (ret == skb->len)
dev_kfree_skb(skb);
}
}
} else
if (dev->v110[idx])
dev_kfree_skb(nskb);
return ret;
}

View File

@ -20,6 +20,11 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.46 1998/02/20 17:23:08 fritz
* Changes for recent kernels.
* Merged in contributions by Thomas Pfeiffer (V.110 T.70+ Extended FAX stuff)
* Added symbolic constants for Modem-Registers.
*
* Revision 1.45 1998/01/31 22:07:49 keil
* changes for newer kernels
*
@ -2676,6 +2681,12 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
#endif
m->mdmreg[REG_PSIZE] = i / 16;
info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
switch (m->mdmreg[REG_L2PROT]) {
case ISDN_PROTO_L2_V11096:
case ISDN_PROTO_L2_V11019:
case ISDN_PROTO_L2_V11038:
info->xmit_size /= 10;
}
break;
case 'D':
/* &D - Set DCD-Low-behavior */
@ -2731,7 +2742,7 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
break;
case 38400:
m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11038;
m->mdmreg[REG_SI2] = 200; /* ??? */
m->mdmreg[REG_SI2] = 198; /* no existing standard for this */
info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
break;
default:
@ -2777,7 +2788,7 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
}
break;
case 'X':
/* &X - Switch to BTX-Mode */
/* &X - Switch to BTX-Mode and T.70 */
p[0]++;
switch (isdn_getnum(p)) {
case 0:
@ -2787,7 +2798,14 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
case 1:
m->mdmreg[REG_T70] |= BIT_T70;
m->mdmreg[REG_T70] &= ~BIT_T70_EXT;
m->mdmreg[REG_L2PROT] = 0;
m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
info->xmit_size = 112;
m->mdmreg[REG_SI1] = 4;
m->mdmreg[REG_SI2] = 0;
break;
case 2:
m->mdmreg[REG_T70] |= (BIT_T70 | BIT_T70_EXT);
m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
info->xmit_size = 112;
m->mdmreg[REG_SI1] = 4;
m->mdmreg[REG_SI2] = 0;
@ -2807,11 +2825,11 @@ isdn_tty_check_ats(int mreg, int mval, modem_info * info, atemu * m)
{
/* Some plausibility checks */
switch (mreg) {
case 14:
case REG_L2PROT:
if (mval > ISDN_PROTO_L2_MAX)
return 1;
break;
case 16:
case REG_PSIZE:
if ((mval * 16) > ISDN_SERIAL_XMIT_MAX)
return 1;
#ifdef CONFIG_ISDN_AUDIO
@ -2819,10 +2837,16 @@ isdn_tty_check_ats(int mreg, int mval, modem_info * info, atemu * m)
return 1;
#endif
info->xmit_size = mval * 16;
switch (m->mdmreg[REG_L2PROT]) {
case ISDN_PROTO_L2_V11096:
case ISDN_PROTO_L2_V11019:
case ISDN_PROTO_L2_V11038:
info->xmit_size /= 10;
}
break;
case 20:
case 21:
case 22:
case REG_SI1I:
case REG_PLAN:
case REG_SCREEN:
/* readonly registers */
return 1;
}

View File

@ -19,6 +19,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.1 1998/02/20 17:32:09 fritz
* First checkin (not yet completely functionable).
*
*/
#include <linux/string.h>
#include <linux/kernel.h>
@ -28,6 +31,8 @@
#include <linux/isdn.h>
#include "isdn_v110.h"
#undef ISDN_V110_DEBUG
char *isdn_v110_revision = "$Revision$";
#define V110_38400 255
@ -37,51 +42,40 @@ char *isdn_v110_revision = "$Revision$";
/* Die folgenden Daten sind fertig kodierte Matrizen, jeweils
als online und offline matrix für 9600, 19200 und 38400
*/
unsigned char V110_OnMatrix_9600[] =
static unsigned char V110_OnMatrix_9600[] =
{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd,
0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd};
unsigned char V110_OffMatrix_9600[] =
static unsigned char V110_OffMatrix_9600[] =
{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
unsigned char V110_OnMatrix_19200[] =
static unsigned char V110_OnMatrix_19200[] =
{0xf0, 0xf0, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7,
0xfd, 0xff, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7};
unsigned char V110_OffMatrix_19200[] =
static unsigned char V110_OffMatrix_19200[] =
{0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
unsigned char V110_OnMatrix_38400[] =
static unsigned char V110_OnMatrix_38400[] =
{0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0xfd, 0x7f, 0x7f, 0x7f, 0x7f};
unsigned char V110_OffMatrix_38400[] =
static unsigned char V110_OffMatrix_38400[] =
{0x00, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff};
#ifdef DEBUG
static int anz = 0;
static void
pr_bin(unsigned char c)
{
printk(KERN_DEBUG "%.2x %d %d %d %d %d %d %d %d\n", c, c & 128. c & 64, c & 32, c & 16, c & 8, c & 4, c & 2, c & 1);
}
#endif
/* FlipBits dreht die Reihenfolge von jeweils keylen bits in einem byte um.
Aus der Bitreihenfolge 76543210 werden bei keylen=4 die bits 45670123,
bei keylen=2 die bits 67452301. Dies ist notwendig, weil die reihenfolge
auf der isdn-leitung falsch herum ist.
*/
static unsigned char
static __inline unsigned char
FlipBits(unsigned char c, int keylen)
{
unsigned char b = c;
@ -121,7 +115,6 @@ isdn_v110_open(unsigned char key, int hdrlen, int maxsize)
v->nbytes = 8 / v->nbits;
v->decodelen = 0;
v->encodelen = 0;
switch (key) {
case V110_38400:
@ -144,9 +137,10 @@ isdn_v110_open(unsigned char key, int hdrlen, int maxsize)
v->b = 0;
v->skbres = hdrlen;
v->maxsize = maxsize - hdrlen;
#if (DEBUG > 1)
printk(KERN_DEBUG "keylen=%d, bytes in stream=%d\n", v->nbits, v->nbytes);
#endif
if ((v->encodebuf = kmalloc(maxsize, GFP_KERNEL)) == NULL) {
kfree(v);
return NULL;
}
return v;
}
@ -156,16 +150,18 @@ isdn_v110_close(isdn_v110_stream * v)
{
if (v == NULL)
return;
#ifdef ISDN_V110_DEBUG
printk(KERN_DEBUG "v110 close\n");
#if (DEBUG > 1)
#if 0
printk(KERN_DEBUG "isdn_v110_close: nbytes=%d\n", v->nbytes);
printk(KERN_DEBUG "isdn_v110_close: nbits=%d\n", v->nbits);
printk(KERN_DEBUG "isdn_v110_close: key=%d\n", v->key);
printk(KERN_DEBUG "isdn_v110_close: SyncInit=%d\n", v->SyncInit);
printk(KERN_DEBUG "isdn_v110_close: encodelen=%d\n", v->encodelen);
printk(KERN_DEBUG "isdn_v110:close: decodelen=%d\n", v->decodelen);
printk(KERN_DEBUG "isdn_v110_close: framelen=%d\n", v->framelen);
#endif
#endif
kfree(v->encodebuf);
kfree(v);
}
@ -199,7 +195,9 @@ SyncHeader(isdn_v110_stream * v)
memcpy(v->decodebuf, rbuf, len);
v->decodelen = len;
#ifdef ISDN_V110_DEBUG
printk(KERN_DEBUG "isdn_v110: Header resync\n");
#endif
}
/* DecodeMatrix takes n (n>=1) matrices (v110 frames, 10 bytes) where
@ -221,18 +219,23 @@ DecodeMatrix(isdn_v110_stream * v, unsigned char *m, int len, unsigned char *buf
while (line < len) { /* sind schon alle matrizenzeilen abgearbeitet? */
if ((line % 10) == 0) { /* die 0. zeile der matrix ist immer null ! */
if (m[line] != 0x00) { /* nicht 0 ? dann fehler! */
#ifdef ISDN_V110_DEBUG
printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad Header\n");
#endif
/* dann einen return zu machen, ist auch irgendwie nicht das richtige! :-(
v->introducer = 0; v->dbit = 1; v->b = 0;
return buflen; // anzahl schon erzeugter daten zurückgeben!
*/
/*
dann einen return zu machen, ist auch irgendwie nicht das richtige! :-(
v->introducer = 0; v->dbit = 1; v->b = 0;
return buflen; anzahl schon erzeugter daten zurückgeben!
*/
}
line++; /* sonst die nächste matrixzeile nehmen */
continue;
} else if ((line % 10) == 5) { /* in zeile 5 stehen nur e-bits ! */
if ((m[line] & 0x70) != 0x30) { /* 011 muß am anfang stehen! */
#ifdef ISDN_V110_DEBUG
printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad 5th line\n");
#endif
/* dann einen return zu machen, ist auch irgendwie nicht das richtige! :-(
v->introducer = 0; v->dbit = 1; v->b = 0;
return buflen;
@ -240,10 +243,8 @@ DecodeMatrix(isdn_v110_stream * v, unsigned char *m, int len, unsigned char *buf
}
line++; /* alles klar, nächste zeile */
continue;
} else if (introducer != 0x06) { /* vor jedem datenbyte kommt "110" ! */
introducer <<= 1; /* shifte die schon vorhanden bits */
introducer &= 0x07; /* nur die letzten drei sind relevant */
introducer |= (m[line] & mbit) ? 1 : 0; /* aktuelles bit der matrix */
} else if (!introducer) { /* every byte starts with 10 (stopbit, startbit) */
introducer = (m[line] & mbit) ? 0 : 1; /* aktuelles bit der matrix */
next_byte:
if (mbit > 2) { /* war es das letzte bit dieser matrixzeile ? */
mbit >>= 1; /* nein, nimm das nächste in dieser zeile */
@ -320,7 +321,7 @@ isdn_v110_decode(isdn_v110_stream * v, struct sk_buff *skb)
goto ReSync;
}
len = (v->decodelen - (v->decodelen % (10 * v->nbytes))) / v->nbytes;
if ((v110_buf = kmalloc(4096, GFP_ATOMIC)) == NULL) {
if ((v110_buf = kmalloc(len, GFP_ATOMIC)) == NULL) {
printk(KERN_WARNING "isdn_v110_decode: Couldn't allocate v110_buf\n");
dev_kfree_skb(skb);
return NULL;
@ -330,20 +331,20 @@ isdn_v110_decode(isdn_v110_stream * v, struct sk_buff *skb)
for (j = 0; j < v->nbytes; j++)
v110_buf[i] |= (v->decodebuf[(i * v->nbytes) + j] & v->key) << (8 - ((j + 1) * v->nbits));
v110_buf[i] = FlipBits(v110_buf[i], v->nbits);
#if (DEBUG > 1)
pr_bin(v110_buf[i]);
#endif
}
v->decodelen = (v->decodelen % (10 * v->nbytes));
memcpy(v->decodebuf, &(v->decodebuf[len * v->nbytes]), v->decodelen);
skb_trim(skb, DecodeMatrix(v, v110_buf, len, skb->data));
kfree(v110_buf);
return skb;
if (skb->len)
return skb;
else {
kfree_skb(skb);
return NULL;
}
}
#define TEMP_BUFSIZE 4000
/* EncodeMatrix takes input data in buf, len is the bytecount.
Data is encoded into v110 frames in m. Return value is the number of
matrix-lines generated.
@ -370,7 +371,7 @@ EncodeMatrix(unsigned char *buf, int len, unsigned char *m, int mlen)
break;
}
if (line >= mlen) {
printk(KERN_DEBUG "isdn_v110: EncodeMatrix, matrix buffer full!\n");
printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
return line;
}
next_bit:
@ -378,7 +379,7 @@ EncodeMatrix(unsigned char *buf, int len, unsigned char *m, int mlen)
case 1:
line++; /* ganz rechts ! dann in die nächste */
if (line >= mlen) {
printk(KERN_DEBUG "isdn_v110: EncodeMatrix, matrix buffer full!\n");
printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n");
return line;
}
case 128:
@ -436,10 +437,10 @@ EncodeMatrix(unsigned char *buf, int len, unsigned char *m, int mlen)
/*
* Build a sync frame.
*/
struct sk_buff *
static struct sk_buff *
isdn_v110_sync(isdn_v110_stream *v)
{
struct sk_buff *skb = NULL;
struct sk_buff *skb;
if (v == NULL) {
/* invalid handle, no chance to proceed */
@ -456,10 +457,10 @@ isdn_v110_sync(isdn_v110_stream *v)
/*
* Build an idle frame.
*/
struct sk_buff *
static struct sk_buff *
isdn_v110_idle(isdn_v110_stream *v)
{
struct sk_buff *skb = NULL;
struct sk_buff *skb;
if (v == NULL) {
/* invalid handle, no chance to proceed */
@ -478,14 +479,16 @@ isdn_v110_encode(isdn_v110_stream * v, struct sk_buff *skb)
{
int i;
int j;
int mlen = 0;
int n = 0;
int olen = 0;
int space;
int rlen;
int mlen;
int olen;
int size;
int len;
unsigned char *v110buf = NULL;
int sval1;
int sval2;
int nframes;
unsigned char *v110buf;
unsigned char *rbuf;
struct sk_buff *nskb;
if (v == NULL) {
/* invalid handle, no chance to proceed */
@ -497,63 +500,46 @@ isdn_v110_encode(isdn_v110_stream * v, struct sk_buff *skb)
printk(KERN_WARNING "isdn_v110_encode called with NULL skb!\n");
return NULL;
}
sti();
size = v->maxsize;
len = skb->len;
if ((v110buf = kmalloc(TEMP_BUFSIZE, GFP_ATOMIC)) == NULL) {
printk(KERN_WARNING "isdn_v110_encode: Couldn't alloc v110buf\n");
return NULL;
}
mlen = EncodeMatrix(skb->data, skb->len, v110buf, TEMP_BUFSIZE);
dev_kfree_skb(skb);
if (!(skb = dev_alloc_skb(size + v->skbres))) {
printk(KERN_WARNING "isdn_v110_encode: Couldn't alloc skb\n");
kfree(v110buf);
return NULL;
}
skb_reserve(skb, v->skbres);
if (v->encodelen) {
n = size > v->encodelen ? v->encodelen : size;
memcpy(skb_put(skb, n), v->encodebuf, n);
v->encodelen -= n;
#if (DEBUG > 3)
printk(KERN_DEBUG "isdn_v110_encode: cping encodebuf %d bytes size=%d\n", n, size)
#endif
if (v->encodelen)
memcpy(v->encodebuf, &(v->encodebuf[n]), v->encodelen);
size -= n;
} else if (len == 0) {
memcpy(skb_put(skb, v->framelen), v->OnlineFrame, v->framelen);
kfree(v110buf);
return skb;
}
/* jetzt noch jeweils 2 oder 4 bits auf den output stream verteilen! */
space = size + sizeof(v->encodebuf) - v->encodelen;
if (size) {
rbuf = skb_put(skb, size);
rlen = skb->len;
nframes = (rlen + 3) / 4;
v110buf = v->encodebuf;
if ((nframes * 40) > v->maxsize) {
size = v->maxsize;
rlen = v->maxsize / 40;
} else
rbuf = &(v->encodebuf[v->encodelen]);
size = nframes * 40;
if (!(nskb = dev_alloc_skb(size + v->skbres + sizeof(int)))) {
printk(KERN_WARNING "isdn_v110_encode: Couldn't alloc skb\n");
return NULL;
}
skb_reserve(nskb, v->skbres + sizeof(int));
if (skb->len == 0) {
memcpy(skb_put(nskb, v->framelen), v->OnlineFrame, v->framelen);
*((int *)skb_push(nskb, sizeof(int))) = 0;
return nskb;
}
mlen = EncodeMatrix(skb->data, rlen, v110buf, size);
/* jetzt noch jeweils 2 oder 4 bits auf den output stream verteilen! */
rbuf = skb_put(nskb, size);
olen = 0;
sval1 = 8 - v->nbits;
sval2 = v->key << sval1;
for (i = 0; i < mlen; i++) {
v110buf[i] = FlipBits(v110buf[i], v->nbits);
for (j = 0; j < v->nbytes; j++) {
if (space--)
*rbuf++ = ~v->key | (((v110buf[i] << (j * v->nbits)) & (v->key << (8 - v->nbits))) >> (8 - v->nbits));
if (size--)
*rbuf++ = ~v->key | (((v110buf[i] << (j * v->nbits)) & sval2) >> sval1);
else {
printk(KERN_DEBUG "isdn_v110_encode: all buffers full!\n");
printk(KERN_WARNING "isdn_v110_encode: buffers full!\n");
goto buffer_full;
}
if (++olen == size)
rbuf = &(v->encodebuf[v->encodelen]);
olen++;
}
}
buffer_full:
if (olen > size) {
v->encodelen += olen - size;
printk(KERN_DEBUG "isdn_v110_encode: using encodebuf %d bytes, size=%d!\n", v->encodelen, size);
} else
skb_trim(skb, olen + n);
kfree(v110buf);
return skb;
skb_trim(nskb, olen);
*((int *)skb_push(nskb, sizeof(int))) = rlen;
return nskb;
}
int
@ -576,17 +562,17 @@ isdn_v110_stat_callback(int idx, isdn_ctrl * c)
if (!(v = dev->v110[idx]))
return 0;
atomic_inc(&dev->v110use[idx]);
if (v->skbidle) {
if (v->skbidle > 0) {
v->skbidle--;
ret = 1;
} else {
if (v->skbuser)
if (v->skbuser > 0)
v->skbuser--;
ret = 0;
}
for (i = v->skbuser + v->skbidle; i < 2; i++) {
struct sk_buff *skb;
if (v->SyncInit)
if (v->SyncInit > 0)
skb = isdn_v110_sync(v);
else
skb = isdn_v110_idle(v);
@ -644,7 +630,6 @@ isdn_v110_stat_callback(int idx, isdn_ctrl * c)
v->SyncInit--;
v->skbidle++;
}
printk(KERN_DEBUG "v110_open\n");
} else
printk(KERN_WARNING "isdn_v110: Couldn't open stream for chan %d\n", idx);
atomic_dec(&dev->v110use[idx]);