1 /* $Id: isdn_v110.c,v 1.2 1998/02/22 19:44:25 fritz Exp $
3 * Linux ISDN subsystem, V.110 related functions (linklevel).
5 * Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * $Log: isdn_v110.c,v $
22 * Revision 1.2 1998/02/22 19:44:25 fritz
23 * Bugfixes and improvements regarding V.110, V.110 now running.
25 * Revision 1.1 1998/02/20 17:32:09 fritz
26 * First checkin (not yet completely functionable).
29 #include <linux/string.h>
30 #include <linux/kernel.h>
31 #include <linux/malloc.h>
34 #include <linux/isdn.h>
35 #include "isdn_v110.h"
37 #undef ISDN_V110_DEBUG
39 char *isdn_v110_revision
= "$Revision: 1.2 $";
41 #define V110_38400 255
45 /* Die folgenden Daten sind fertig kodierte Matrizen, jeweils
46 als online und offline matrix für 9600, 19200 und 38400
48 static unsigned char V110_OnMatrix_9600
[] =
49 {0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
50 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd,
51 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
52 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd};
54 static unsigned char V110_OffMatrix_9600
[] =
55 {0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
56 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
57 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
58 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
60 static unsigned char V110_OnMatrix_19200
[] =
61 {0xf0, 0xf0, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7,
62 0xfd, 0xff, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7};
64 static unsigned char V110_OffMatrix_19200
[] =
65 {0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
68 static unsigned char V110_OnMatrix_38400
[] =
69 {0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0xfd, 0x7f, 0x7f, 0x7f, 0x7f};
71 static unsigned char V110_OffMatrix_38400
[] =
72 {0x00, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff};
75 /* FlipBits dreht die Reihenfolge von jeweils keylen bits in einem byte um.
76 Aus der Bitreihenfolge 76543210 werden bei keylen=4 die bits 45670123,
77 bei keylen=2 die bits 67452301. Dies ist notwendig, weil die reihenfolge
78 auf der isdn-leitung falsch herum ist.
81 static __inline
unsigned char
82 FlipBits(unsigned char c
, int keylen
)
85 unsigned char bit
= 128;
88 int hunks
= (8 / keylen
);
91 for (i
= 0; i
< hunks
; i
++) {
92 for (j
= 0; j
< keylen
; j
++) {
94 c
|= bit
>> (keylen
- j
- 1);
102 /* isdn_v110_open allocates and initializes private V.110 data
103 * structures and returns a pointer to these.
105 static isdn_v110_stream
*
106 isdn_v110_open(unsigned char key
, int hdrlen
, int maxsize
)
111 if ((v
= kmalloc(sizeof(isdn_v110_stream
), GFP_KERNEL
)) == NULL
)
113 memset(v
, 0, sizeof(isdn_v110_stream
));
116 for (i
= 0; key
& (1 << i
); i
++)
119 v
->nbytes
= 8 / v
->nbits
;
124 v
->OnlineFrame
= V110_OnMatrix_38400
;
125 v
->OfflineFrame
= V110_OffMatrix_38400
;
128 v
->OnlineFrame
= V110_OnMatrix_19200
;
129 v
->OfflineFrame
= V110_OffMatrix_19200
;
132 v
->OnlineFrame
= V110_OnMatrix_9600
;
133 v
->OfflineFrame
= V110_OffMatrix_9600
;
136 v
->framelen
= v
->nbytes
* 10;
142 v
->maxsize
= maxsize
- hdrlen
;
143 if ((v
->encodebuf
= kmalloc(maxsize
, GFP_KERNEL
)) == NULL
) {
150 /* isdn_v110_close frees private V.110 data structures */
152 isdn_v110_close(isdn_v110_stream
* v
)
156 #ifdef ISDN_V110_DEBUG
157 printk(KERN_DEBUG
"v110 close\n");
159 printk(KERN_DEBUG
"isdn_v110_close: nbytes=%d\n", v
->nbytes
);
160 printk(KERN_DEBUG
"isdn_v110_close: nbits=%d\n", v
->nbits
);
161 printk(KERN_DEBUG
"isdn_v110_close: key=%d\n", v
->key
);
162 printk(KERN_DEBUG
"isdn_v110_close: SyncInit=%d\n", v
->SyncInit
);
163 printk(KERN_DEBUG
"isdn_v110:close: decodelen=%d\n", v
->decodelen
);
164 printk(KERN_DEBUG
"isdn_v110_close: framelen=%d\n", v
->framelen
);
172 /* ValidHeaderBytes prüft, wieviele bytes in v->decodebuf gültig sind */
175 ValidHeaderBytes(isdn_v110_stream
* v
)
178 for (i
= 0; (i
< v
->decodelen
) && (i
< v
->nbytes
); i
++)
179 if ((v
->decodebuf
[i
] & v
->key
) != 0)
184 /* SyncHeader schiebt den decodebuf pointer auf den nächsten gültigen header */
187 SyncHeader(isdn_v110_stream
* v
)
189 unsigned char *rbuf
= v
->decodebuf
;
190 int len
= v
->decodelen
;
194 for (rbuf
++, len
--; len
> 0; len
--, rbuf
++) /* such den SyncHeader in buf ! */
195 if ((*rbuf
& v
->key
) == 0) /* erstes byte gefunden ? */
198 memcpy(v
->decodebuf
, rbuf
, len
);
201 #ifdef ISDN_V110_DEBUG
202 printk(KERN_DEBUG
"isdn_v110: Header resync\n");
206 /* DecodeMatrix takes n (n>=1) matrices (v110 frames, 10 bytes) where
207 len is the number of matrix-lines. len must be a multiple of 10, i.e.
208 only complete matices must be given.
209 From these, netto data is extracted and returned in buf. The return-value
210 is the bytecount of the decoded data.
213 DecodeMatrix(isdn_v110_stream
* v
, unsigned char *m
, int len
, unsigned char *buf
)
218 int introducer
= v
->introducer
;
220 unsigned char b
= v
->b
;
222 while (line
< len
) { /* sind schon alle matrizenzeilen abgearbeitet? */
223 if ((line
% 10) == 0) { /* die 0. zeile der matrix ist immer null ! */
224 if (m
[line
] != 0x00) { /* nicht 0 ? dann fehler! */
225 #ifdef ISDN_V110_DEBUG
226 printk(KERN_DEBUG
"isdn_v110: DecodeMatrix, V110 Bad Header\n");
230 dann einen return zu machen, ist auch irgendwie nicht das richtige! :-(
231 v->introducer = 0; v->dbit = 1; v->b = 0;
232 return buflen; anzahl schon erzeugter daten zurückgeben!
235 line
++; /* sonst die nächste matrixzeile nehmen */
237 } else if ((line
% 10) == 5) { /* in zeile 5 stehen nur e-bits ! */
238 if ((m
[line
] & 0x70) != 0x30) { /* 011 muß am anfang stehen! */
239 #ifdef ISDN_V110_DEBUG
240 printk(KERN_DEBUG
"isdn_v110: DecodeMatrix, V110 Bad 5th line\n");
242 /* dann einen return zu machen, ist auch irgendwie nicht das richtige! :-(
243 v->introducer = 0; v->dbit = 1; v->b = 0;
247 line
++; /* alles klar, nächste zeile */
249 } else if (!introducer
) { /* every byte starts with 10 (stopbit, startbit) */
250 introducer
= (m
[line
] & mbit
) ? 0 : 1; /* aktuelles bit der matrix */
252 if (mbit
> 2) { /* war es das letzte bit dieser matrixzeile ? */
253 mbit
>>= 1; /* nein, nimm das nächste in dieser zeile */
255 } /* sonst links in der nächsten zeile anfangen */
259 } else { /* sonst müssen wir ein datenbit setzen */
260 if (m
[line
] & mbit
) /* war das bit in der matrix gesetzt ? */
261 b
|= dbit
; /* ja, dann setz es auch im datenbyte */
263 b
&= dbit
- 1; /* nein, lösch bit im datenbyte */
264 if (dbit
< 128) /* haben wir schon ein ganzes byte voll ? */
265 dbit
<<= 1; /* nein, auf zum nächsten datenbit */
266 else { /* ein ganzes datenbyte ist voll */
267 buf
[buflen
++] = b
; /* byte in den output buffer kopieren */
268 introducer
= b
= 0; /* Init der Introsequenz und des datenbytes */
269 dbit
= 1; /* als nächstes suchen wir das nullte bit */
271 goto next_byte
; /* suche das nächste bit in der matrix */
274 v
->introducer
= introducer
;
277 return buflen
; /* return anzahl der bytes im output buffer */
280 /* DecodeStream erhält vom input stream V110 kodierte Daten, die zu den
281 V110 frames zusammengepackt werden müssen. Die Daten können an diese
282 Schnittstelle so übergeben werden, wie sie von der Leitung kommen, ohne
283 darauf achten zu müssen, das frames usw. eingehalten werden.
286 isdn_v110_decode(isdn_v110_stream
* v
, struct sk_buff
*skb
)
291 unsigned char *v110_buf
;
295 printk(KERN_WARNING
"isdn_v110_decode called with NULL skb!\n");
301 /* invalid handle, no chance to proceed */
302 printk(KERN_WARNING
"isdn_v110_decode called with NULL stream!\n");
306 if (v
->decodelen
== 0) /* cache empty? */
307 for (; len
> 0; len
--, rbuf
++) /* scan for SyncHeader in buf */
308 if ((*rbuf
& v
->key
) == 0)
309 break; /* found first byte */
314 /* copy new data to decode-buffer */
315 memcpy(&(v
->decodebuf
[v
->decodelen
]), rbuf
, len
);
318 if (v
->decodelen
< v
->nbytes
) { /* got a new header ? */
320 return NULL
; /* no, try later */
322 if (ValidHeaderBytes(v
) != v
->nbytes
) { /* ist es ein ungültiger header ? */
323 SyncHeader(v
); /* nein, such einen header */
326 len
= (v
->decodelen
- (v
->decodelen
% (10 * v
->nbytes
))) / v
->nbytes
;
327 if ((v110_buf
= kmalloc(len
, GFP_ATOMIC
)) == NULL
) {
328 printk(KERN_WARNING
"isdn_v110_decode: Couldn't allocate v110_buf\n");
332 for (i
= 0; i
< len
; i
++) {
334 for (j
= 0; j
< v
->nbytes
; j
++)
335 v110_buf
[i
] |= (v
->decodebuf
[(i
* v
->nbytes
) + j
] & v
->key
) << (8 - ((j
+ 1) * v
->nbits
));
336 v110_buf
[i
] = FlipBits(v110_buf
[i
], v
->nbits
);
338 v
->decodelen
= (v
->decodelen
% (10 * v
->nbytes
));
339 memcpy(v
->decodebuf
, &(v
->decodebuf
[len
* v
->nbytes
]), v
->decodelen
);
341 skb_trim(skb
, DecodeMatrix(v
, v110_buf
, len
, skb
->data
));
351 /* EncodeMatrix takes input data in buf, len is the bytecount.
352 Data is encoded into v110 frames in m. Return value is the number of
353 matrix-lines generated.
356 EncodeMatrix(unsigned char *buf
, int len
, unsigned char *m
, int mlen
)
363 int ibit
[] = {0, 1, 1};
365 while ((i
< len
) && (line
< mlen
)) { /* solange noch input da ist */
366 switch (line
% 10) { /* in welcher matrixzeile sind wir ? */
368 m
[line
++] = 0x00; /* zeile 0 ist immer 0 */
369 mbit
= 128; /* und es geht mit dem 7. bit weiter */
372 m
[line
++] = 0xbf; /* zeile 5 ist immer 10111111 */
373 mbit
= 128; /* und es geht mit dem 7. bit weiter */
377 printk(KERN_WARNING
"isdn_v110 (EncodeMatrix): buffer full!\n");
381 switch (mbit
) { /* ganz linkes oder rechtes bit ? */
383 line
++; /* ganz rechts ! dann in die nächste */
385 printk(KERN_WARNING
"isdn_v110 (EncodeMatrix): buffer full!\n");
389 m
[line
] = 128; /* ganz links byte auf 1000000 setzen */
390 mbit
= 64; /* aktuelles bit in der matrixzeile */
393 if (introducer
) { /* 110 sequenz setzen ? */
394 introducer
--; /* ein digit weniger setzen */
395 m
[line
] |= ibit
[introducer
] ? mbit
: 0; /* entsprechendes bit setzen */
396 mbit
>>= 1; /* bit der matrixzeile >> 1 */
397 goto next_bit
; /* und dort weiter machen */
398 } /* else datenbits in die matrix packen! */
399 m
[line
] |= (buf
[i
] & dbit
) ? mbit
: 0; /* datenbit in matrix setzen */
400 if (dbit
== 128) { /* war es das letzte datenbit ? */
401 dbit
= 1; /* dann mach beim nächsten weiter */
402 i
++; /* nächste datenbyte des input buffers */
403 if (i
< len
) /* war es schon das letzte ? */
404 introducer
= 3; /* nein, schreib den introducer 110 */
405 else { /* war das letzte datenbyte ! */
406 m
[line
] |= (mbit
- 1) & 0xfe; /* setz restliche bits der zeile auf 1 */
409 } else /* nicht das letzte datenbit */
410 dbit
<<= 1; /* dann gehe zum nächsten datenbit */
411 mbit
>>= 1; /* und setz bit der matrix weiter */
415 /* evtl. noch restliche zeilen in der matrix generieren... */
416 if ((line
) && ((line
+ 10) < mlen
))
417 switch (++line
% 10) {
437 return line
; /* soviele matrixzeilen sind es */
441 * Build a sync frame.
443 static struct sk_buff
*
444 isdn_v110_sync(isdn_v110_stream
*v
)
449 /* invalid handle, no chance to proceed */
450 printk(KERN_WARNING
"isdn_v110_sync called with NULL stream!\n");
453 if ((skb
= dev_alloc_skb(v
->framelen
+ v
->skbres
))) {
454 skb_reserve(skb
, v
->skbres
);
455 memcpy(skb_put(skb
, v
->framelen
), v
->OfflineFrame
, v
->framelen
);
461 * Build an idle frame.
463 static struct sk_buff
*
464 isdn_v110_idle(isdn_v110_stream
*v
)
469 /* invalid handle, no chance to proceed */
470 printk(KERN_WARNING
"isdn_v110_sync called with NULL stream!\n");
473 if ((skb
= dev_alloc_skb(v
->framelen
+ v
->skbres
))) {
474 skb_reserve(skb
, v
->skbres
);
475 memcpy(skb_put(skb
, v
->framelen
), v
->OnlineFrame
, v
->framelen
);
481 isdn_v110_encode(isdn_v110_stream
* v
, struct sk_buff
*skb
)
492 unsigned char *v110buf
;
494 struct sk_buff
*nskb
;
497 /* invalid handle, no chance to proceed */
498 printk(KERN_WARNING
"isdn_v110_encode called with NULL stream!\n");
502 /* invalid skb, no chance to proceed */
503 printk(KERN_WARNING
"isdn_v110_encode called with NULL skb!\n");
507 nframes
= (rlen
+ 3) / 4;
508 v110buf
= v
->encodebuf
;
509 if ((nframes
* 40) > v
->maxsize
) {
511 rlen
= v
->maxsize
/ 40;
514 if (!(nskb
= dev_alloc_skb(size
+ v
->skbres
+ sizeof(int)))) {
515 printk(KERN_WARNING
"isdn_v110_encode: Couldn't alloc skb\n");
518 skb_reserve(nskb
, v
->skbres
+ sizeof(int));
520 memcpy(skb_put(nskb
, v
->framelen
), v
->OnlineFrame
, v
->framelen
);
521 *((int *)skb_push(nskb
, sizeof(int))) = 0;
524 mlen
= EncodeMatrix(skb
->data
, rlen
, v110buf
, size
);
525 /* jetzt noch jeweils 2 oder 4 bits auf den output stream verteilen! */
526 rbuf
= skb_put(nskb
, size
);
528 sval1
= 8 - v
->nbits
;
529 sval2
= v
->key
<< sval1
;
530 for (i
= 0; i
< mlen
; i
++) {
531 v110buf
[i
] = FlipBits(v110buf
[i
], v
->nbits
);
532 for (j
= 0; j
< v
->nbytes
; j
++) {
534 *rbuf
++ = ~v
->key
| (((v110buf
[i
] << (j
* v
->nbits
)) & sval2
) >> sval1
);
536 printk(KERN_WARNING
"isdn_v110_encode: buffers full!\n");
543 skb_trim(nskb
, olen
);
544 *((int *)skb_push(nskb
, sizeof(int))) = rlen
;
549 isdn_v110_stat_callback(int idx
, isdn_ctrl
* c
)
551 isdn_v110_stream
*v
= NULL
;
557 switch (c
->command
) {
558 case ISDN_STAT_BSENT
:
559 /* Keep the send-queue of the driver filled
561 * If number of outstanding frames < 3,
562 * send down an Idle-Frame (or an Sync-Frame, if
565 if (!(v
= dev
->v110
[idx
]))
567 atomic_inc(&dev
->v110use
[idx
]);
568 if (v
->skbidle
> 0) {
576 for (i
= v
->skbuser
+ v
->skbidle
; i
< 2; i
++) {
579 skb
= isdn_v110_sync(v
);
581 skb
= isdn_v110_idle(v
);
583 if (dev
->drv
[c
->driver
]->interface
->writebuf_skb(c
->driver
, c
->arg
, 1, skb
) <= 0) {
594 atomic_dec(&dev
->v110use
[idx
]);
599 atomic_inc(&dev
->v110use
[idx
]);
600 if (atomic_dec_and_test(&dev
->v110use
[idx
])) {
601 isdn_v110_close(dev
->v110
[idx
]);
602 dev
->v110
[idx
] = NULL
;
608 case ISDN_STAT_BCONN
:
609 if (dev
->v110emu
[idx
] && (dev
->v110
[idx
] == NULL
)) {
610 int hdrlen
= dev
->drv
[c
->driver
]->interface
->hl_hdrlen
;
611 int maxsize
= dev
->drv
[c
->driver
]->interface
->maxbufsize
;
612 atomic_inc(&dev
->v110use
[idx
]);
613 switch (dev
->v110emu
[idx
]) {
614 case ISDN_PROTO_L2_V11096
:
615 dev
->v110
[idx
] = isdn_v110_open(V110_9600
, hdrlen
, maxsize
);
617 case ISDN_PROTO_L2_V11019
:
618 dev
->v110
[idx
] = isdn_v110_open(V110_19200
, hdrlen
, maxsize
);
620 case ISDN_PROTO_L2_V11038
:
621 dev
->v110
[idx
] = isdn_v110_open(V110_38400
, hdrlen
, maxsize
);
625 if ((v
= dev
->v110
[idx
])) {
626 while (v
->SyncInit
) {
627 struct sk_buff
*skb
= isdn_v110_sync(v
);
628 if (dev
->drv
[c
->driver
]->interface
->writebuf_skb(c
->driver
, c
->arg
, 1, skb
) <= 0) {
630 /* Unable to send, try later */
637 printk(KERN_WARNING
"isdn_v110: Couldn't open stream for chan %d\n", idx
);
638 atomic_dec(&dev
->v110use
[idx
]);