1 /* $Id: isdn_v110.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
3 * Linux ISDN subsystem, V.110 related functions (linklevel).
5 * Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
12 #include <linux/string.h>
13 #include <linux/kernel.h>
14 #include <linux/slab.h>
16 #include <linux/delay.h>
18 #include <linux/isdn.h>
19 #include "isdn_v110.h"
21 #undef ISDN_V110_DEBUG
23 char *isdn_v110_revision
= "$Revision: 1.1.2.2 $";
25 #define V110_38400 255
30 * The following data are precoded matrices, online and offline matrix
31 * for 9600, 19200 und 38400, respectively
33 static unsigned char V110_OnMatrix_9600
[] =
34 {0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
35 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd,
36 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
37 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd};
39 static unsigned char V110_OffMatrix_9600
[] =
40 {0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
41 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
42 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
43 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
45 static unsigned char V110_OnMatrix_19200
[] =
46 {0xf0, 0xf0, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7,
47 0xfd, 0xff, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7};
49 static unsigned char V110_OffMatrix_19200
[] =
50 {0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
51 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
53 static unsigned char V110_OnMatrix_38400
[] =
54 {0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0xfd, 0x7f, 0x7f, 0x7f, 0x7f};
56 static unsigned char V110_OffMatrix_38400
[] =
57 {0x00, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff};
60 * FlipBits reorders sequences of keylen bits in one byte.
61 * E.g. source order 7654321 will be converted to 45670123 when keylen = 4,
62 * and to 67452301 when keylen = 2. This is necessary because ordering on
63 * the isdn line is the other way.
65 static __inline
unsigned char
66 FlipBits(unsigned char c
, int keylen
)
69 unsigned char bit
= 128;
72 int hunks
= (8 / keylen
);
75 for (i
= 0; i
< hunks
; i
++) {
76 for (j
= 0; j
< keylen
; j
++) {
78 c
|= bit
>> (keylen
- j
- 1);
86 /* isdn_v110_open allocates and initializes private V.110 data
87 * structures and returns a pointer to these.
89 static isdn_v110_stream
*
90 isdn_v110_open(unsigned char key
, int hdrlen
, int maxsize
)
95 if ((v
= kmalloc(sizeof(isdn_v110_stream
), GFP_ATOMIC
)) == NULL
)
97 memset(v
, 0, sizeof(isdn_v110_stream
));
100 for (i
= 0; key
& (1 << i
); i
++)
103 v
->nbytes
= 8 / v
->nbits
;
108 v
->OnlineFrame
= V110_OnMatrix_38400
;
109 v
->OfflineFrame
= V110_OffMatrix_38400
;
112 v
->OnlineFrame
= V110_OnMatrix_19200
;
113 v
->OfflineFrame
= V110_OffMatrix_19200
;
116 v
->OnlineFrame
= V110_OnMatrix_9600
;
117 v
->OfflineFrame
= V110_OffMatrix_9600
;
120 v
->framelen
= v
->nbytes
* 10;
126 v
->maxsize
= maxsize
- hdrlen
;
127 if ((v
->encodebuf
= kmalloc(maxsize
, GFP_ATOMIC
)) == NULL
) {
134 /* isdn_v110_close frees private V.110 data structures */
136 isdn_v110_close(isdn_v110_stream
* v
)
140 #ifdef ISDN_V110_DEBUG
141 printk(KERN_DEBUG
"v110 close\n");
149 * ValidHeaderBytes return the number of valid bytes in v->decodebuf
152 ValidHeaderBytes(isdn_v110_stream
* v
)
155 for (i
= 0; (i
< v
->decodelen
) && (i
< v
->nbytes
); i
++)
156 if ((v
->decodebuf
[i
] & v
->key
) != 0)
162 * SyncHeader moves the decodebuf ptr to the next valid header
165 SyncHeader(isdn_v110_stream
* v
)
167 unsigned char *rbuf
= v
->decodebuf
;
168 int len
= v
->decodelen
;
172 for (rbuf
++, len
--; len
> 0; len
--, rbuf
++) /* such den SyncHeader in buf ! */
173 if ((*rbuf
& v
->key
) == 0) /* erstes byte gefunden ? */
176 memcpy(v
->decodebuf
, rbuf
, len
);
179 #ifdef ISDN_V110_DEBUG
180 printk(KERN_DEBUG
"isdn_v110: Header resync\n");
184 /* DecodeMatrix takes n (n>=1) matrices (v110 frames, 10 bytes) where
185 len is the number of matrix-lines. len must be a multiple of 10, i.e.
186 only complete matices must be given.
187 From these, netto data is extracted and returned in buf. The return-value
188 is the bytecount of the decoded data.
191 DecodeMatrix(isdn_v110_stream
* v
, unsigned char *m
, int len
, unsigned char *buf
)
196 int introducer
= v
->introducer
;
198 unsigned char b
= v
->b
;
200 while (line
< len
) { /* Are we done with all lines of the matrix? */
201 if ((line
% 10) == 0) { /* the 0. line of the matrix is always 0 ! */
202 if (m
[line
] != 0x00) { /* not 0 ? -> error! */
203 #ifdef ISDN_V110_DEBUG
204 printk(KERN_DEBUG
"isdn_v110: DecodeMatrix, V110 Bad Header\n");
205 /* returning now is not the right thing, though :-( */
208 line
++; /* next line of matrix */
210 } else if ((line
% 10) == 5) { /* in line 5 there's only e-bits ! */
211 if ((m
[line
] & 0x70) != 0x30) { /* 011 has to be at the beginning! */
212 #ifdef ISDN_V110_DEBUG
213 printk(KERN_DEBUG
"isdn_v110: DecodeMatrix, V110 Bad 5th line\n");
214 /* returning now is not the right thing, though :-( */
217 line
++; /* next line */
219 } else if (!introducer
) { /* every byte starts with 10 (stopbit, startbit) */
220 introducer
= (m
[line
] & mbit
) ? 0 : 1; /* current bit of the matrix */
222 if (mbit
> 2) { /* was it the last bit in this line ? */
223 mbit
>>= 1; /* no -> take next */
225 } /* otherwise start with leftmost bit in the next line */
229 } else { /* otherwise we need to set a data bit */
230 if (m
[line
] & mbit
) /* was that bit set in the matrix ? */
231 b
|= dbit
; /* yes -> set it in the data byte */
233 b
&= dbit
- 1; /* no -> clear it in the data byte */
234 if (dbit
< 128) /* is that data byte done ? */
235 dbit
<<= 1; /* no, got the next bit */
236 else { /* data byte is done */
237 buf
[buflen
++] = b
; /* copy byte into the output buffer */
238 introducer
= b
= 0; /* init of the intro sequence and of the data byte */
239 dbit
= 1; /* next we look for the 0th bit */
241 goto next_byte
; /* look for next bit in the matrix */
244 v
->introducer
= introducer
;
247 return buflen
; /* return number of bytes in the output buffer */
251 * DecodeStream receives V.110 coded data from the input stream. It recovers the
253 * The input stream doesn't need to be framed
256 isdn_v110_decode(isdn_v110_stream
* v
, struct sk_buff
*skb
)
261 unsigned char *v110_buf
;
265 printk(KERN_WARNING
"isdn_v110_decode called with NULL skb!\n");
271 /* invalid handle, no chance to proceed */
272 printk(KERN_WARNING
"isdn_v110_decode called with NULL stream!\n");
276 if (v
->decodelen
== 0) /* cache empty? */
277 for (; len
> 0; len
--, rbuf
++) /* scan for SyncHeader in buf */
278 if ((*rbuf
& v
->key
) == 0)
279 break; /* found first byte */
284 /* copy new data to decode-buffer */
285 memcpy(&(v
->decodebuf
[v
->decodelen
]), rbuf
, len
);
288 if (v
->decodelen
< v
->nbytes
) { /* got a new header ? */
290 return NULL
; /* no, try later */
292 if (ValidHeaderBytes(v
) != v
->nbytes
) { /* is that a valid header? */
293 SyncHeader(v
); /* no -> look for header */
296 len
= (v
->decodelen
- (v
->decodelen
% (10 * v
->nbytes
))) / v
->nbytes
;
297 if ((v110_buf
= kmalloc(len
, GFP_ATOMIC
)) == NULL
) {
298 printk(KERN_WARNING
"isdn_v110_decode: Couldn't allocate v110_buf\n");
302 for (i
= 0; i
< len
; i
++) {
304 for (j
= 0; j
< v
->nbytes
; j
++)
305 v110_buf
[i
] |= (v
->decodebuf
[(i
* v
->nbytes
) + j
] & v
->key
) << (8 - ((j
+ 1) * v
->nbits
));
306 v110_buf
[i
] = FlipBits(v110_buf
[i
], v
->nbits
);
308 v
->decodelen
= (v
->decodelen
% (10 * v
->nbytes
));
309 memcpy(v
->decodebuf
, &(v
->decodebuf
[len
* v
->nbytes
]), v
->decodelen
);
311 skb_trim(skb
, DecodeMatrix(v
, v110_buf
, len
, skb
->data
));
321 /* EncodeMatrix takes input data in buf, len is the bytecount.
322 Data is encoded into v110 frames in m. Return value is the number of
323 matrix-lines generated.
326 EncodeMatrix(unsigned char *buf
, int len
, unsigned char *m
, int mlen
)
333 int ibit
[] = {0, 1, 1};
335 while ((i
< len
) && (line
< mlen
)) { /* while we still have input data */
336 switch (line
% 10) { /* in which line of the matrix are we? */
338 m
[line
++] = 0x00; /* line 0 is always 0 */
339 mbit
= 128; /* go on with the 7th bit */
342 m
[line
++] = 0xbf; /* line 5 is always 10111111 */
343 mbit
= 128; /* go on with the 7th bit */
347 printk(KERN_WARNING
"isdn_v110 (EncodeMatrix): buffer full!\n");
351 switch (mbit
) { /* leftmost or rightmost bit ? */
353 line
++; /* rightmost -> go to next line */
355 printk(KERN_WARNING
"isdn_v110 (EncodeMatrix): buffer full!\n");
359 m
[line
] = 128; /* leftmost -> set byte to 1000000 */
360 mbit
= 64; /* current bit in the matrix line */
363 if (introducer
) { /* set 110 sequence ? */
364 introducer
--; /* set on digit less */
365 m
[line
] |= ibit
[introducer
] ? mbit
: 0; /* set corresponding bit */
366 mbit
>>= 1; /* bit of matrix line >> 1 */
367 goto next_bit
; /* and go on there */
368 } /* else push data bits into the matrix! */
369 m
[line
] |= (buf
[i
] & dbit
) ? mbit
: 0; /* set data bit in matrix */
370 if (dbit
== 128) { /* was it the last one? */
371 dbit
= 1; /* then go on with first bit of */
372 i
++; /* next byte in input buffer */
373 if (i
< len
) /* input buffer done ? */
374 introducer
= 3; /* no, write introducer 110 */
375 else { /* input buffer done ! */
376 m
[line
] |= (mbit
- 1) & 0xfe; /* set remaining bits in line to 1 */
379 } else /* not the last data bit */
380 dbit
<<= 1; /* then go to next data bit */
381 mbit
>>= 1; /* go to next bit of matrix */
385 /* if necessary, generate remaining lines of the matrix... */
386 if ((line
) && ((line
+ 10) < mlen
))
387 switch (++line
% 10) {
407 return line
; /* that's how many lines we have */
411 * Build a sync frame.
413 static struct sk_buff
*
414 isdn_v110_sync(isdn_v110_stream
*v
)
419 /* invalid handle, no chance to proceed */
420 printk(KERN_WARNING
"isdn_v110_sync called with NULL stream!\n");
423 if ((skb
= dev_alloc_skb(v
->framelen
+ v
->skbres
))) {
424 skb_reserve(skb
, v
->skbres
);
425 memcpy(skb_put(skb
, v
->framelen
), v
->OfflineFrame
, v
->framelen
);
431 * Build an idle frame.
433 static struct sk_buff
*
434 isdn_v110_idle(isdn_v110_stream
*v
)
439 /* invalid handle, no chance to proceed */
440 printk(KERN_WARNING
"isdn_v110_sync called with NULL stream!\n");
443 if ((skb
= dev_alloc_skb(v
->framelen
+ v
->skbres
))) {
444 skb_reserve(skb
, v
->skbres
);
445 memcpy(skb_put(skb
, v
->framelen
), v
->OnlineFrame
, v
->framelen
);
451 isdn_v110_encode(isdn_v110_stream
* v
, struct sk_buff
*skb
)
462 unsigned char *v110buf
;
464 struct sk_buff
*nskb
;
467 /* invalid handle, no chance to proceed */
468 printk(KERN_WARNING
"isdn_v110_encode called with NULL stream!\n");
472 /* invalid skb, no chance to proceed */
473 printk(KERN_WARNING
"isdn_v110_encode called with NULL skb!\n");
477 nframes
= (rlen
+ 3) / 4;
478 v110buf
= v
->encodebuf
;
479 if ((nframes
* 40) > v
->maxsize
) {
481 rlen
= v
->maxsize
/ 40;
484 if (!(nskb
= dev_alloc_skb(size
+ v
->skbres
+ sizeof(int)))) {
485 printk(KERN_WARNING
"isdn_v110_encode: Couldn't alloc skb\n");
488 skb_reserve(nskb
, v
->skbres
+ sizeof(int));
490 memcpy(skb_put(nskb
, v
->framelen
), v
->OnlineFrame
, v
->framelen
);
491 *((int *)skb_push(nskb
, sizeof(int))) = 0;
494 mlen
= EncodeMatrix(skb
->data
, rlen
, v110buf
, size
);
495 /* now distribute 2 or 4 bits each to the output stream! */
496 rbuf
= skb_put(nskb
, size
);
498 sval1
= 8 - v
->nbits
;
499 sval2
= v
->key
<< sval1
;
500 for (i
= 0; i
< mlen
; i
++) {
501 v110buf
[i
] = FlipBits(v110buf
[i
], v
->nbits
);
502 for (j
= 0; j
< v
->nbytes
; j
++) {
504 *rbuf
++ = ~v
->key
| (((v110buf
[i
] << (j
* v
->nbits
)) & sval2
) >> sval1
);
506 printk(KERN_WARNING
"isdn_v110_encode: buffers full!\n");
513 skb_trim(nskb
, olen
);
514 *((int *)skb_push(nskb
, sizeof(int))) = rlen
;
519 isdn_v110_stat_callback(int idx
, isdn_ctrl
*c
)
521 isdn_v110_stream
*v
= NULL
;
527 switch (c
->command
) {
528 case ISDN_STAT_BSENT
:
529 /* Keep the send-queue of the driver filled
531 * If number of outstanding frames < 3,
532 * send down an Idle-Frame (or an Sync-Frame, if
535 if (!(v
= dev
->v110
[idx
]))
537 atomic_inc(&dev
->v110use
[idx
]);
538 for (i
=0; i
* v
->framelen
< c
->parm
.length
; i
++) {
539 if (v
->skbidle
> 0) {
548 for (i
= v
->skbuser
+ v
->skbidle
; i
< 2; i
++) {
551 skb
= isdn_v110_sync(v
);
553 skb
= isdn_v110_idle(v
);
555 if (dev
->drv
[c
->driver
]->interface
->writebuf_skb(c
->driver
, c
->arg
, 1, skb
) <= 0) {
566 atomic_dec(&dev
->v110use
[idx
]);
571 atomic_inc(&dev
->v110use
[idx
]);
572 if (atomic_dec_and_test(&dev
->v110use
[idx
])) {
573 isdn_v110_close(dev
->v110
[idx
]);
574 dev
->v110
[idx
] = NULL
;
580 case ISDN_STAT_BCONN
:
581 if (dev
->v110emu
[idx
] && (dev
->v110
[idx
] == NULL
)) {
582 int hdrlen
= dev
->drv
[c
->driver
]->interface
->hl_hdrlen
;
583 int maxsize
= dev
->drv
[c
->driver
]->interface
->maxbufsize
;
584 atomic_inc(&dev
->v110use
[idx
]);
585 switch (dev
->v110emu
[idx
]) {
586 case ISDN_PROTO_L2_V11096
:
587 dev
->v110
[idx
] = isdn_v110_open(V110_9600
, hdrlen
, maxsize
);
589 case ISDN_PROTO_L2_V11019
:
590 dev
->v110
[idx
] = isdn_v110_open(V110_19200
, hdrlen
, maxsize
);
592 case ISDN_PROTO_L2_V11038
:
593 dev
->v110
[idx
] = isdn_v110_open(V110_38400
, hdrlen
, maxsize
);
597 if ((v
= dev
->v110
[idx
])) {
598 while (v
->SyncInit
) {
599 struct sk_buff
*skb
= isdn_v110_sync(v
);
600 if (dev
->drv
[c
->driver
]->interface
->writebuf_skb(c
->driver
, c
->arg
, 1, skb
) <= 0) {
602 /* Unable to send, try later */
609 printk(KERN_WARNING
"isdn_v110: Couldn't open stream for chan %d\n", idx
);
610 atomic_dec(&dev
->v110use
[idx
]);