AT91: Added a generic way to setup AT91 serial ports in Kconfig
[linux-2.6/pdupreez.git] / drivers / isdn / hisax / isdnhdlc.c
blobc69a77a80062f970bc289c543a9eded80e35aa73
1 /*
2 * isdnhdlc.c -- General purpose ISDN HDLC decoder.
4 *Copyright (C) 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
5 * 2001 Frode Isaksen <fisaksen@bewan.com>
6 * 2001 Kai Germaschewski <kai.germaschewski@gmx.de>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <linux/module.h>
24 #include <linux/init.h>
25 #include <linux/crc-ccitt.h>
26 #include "isdnhdlc.h"
28 /*-------------------------------------------------------------------*/
30 MODULE_AUTHOR("Wolfgang Mües <wolfgang@iksw-muees.de>, "
31 "Frode Isaksen <fisaksen@bewan.com>, "
32 "Kai Germaschewski <kai.germaschewski@gmx.de>");
33 MODULE_DESCRIPTION("General purpose ISDN HDLC decoder");
34 MODULE_LICENSE("GPL");
36 /*-------------------------------------------------------------------*/
38 enum {
39 HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7,
40 HDLC_GET_DATA,HDLC_FAST_FLAG
43 enum {
44 HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG,
45 HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG,
46 HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0,
47 HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED
50 void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56)
52 hdlc->bit_shift = 0;
53 hdlc->hdlc_bits1 = 0;
54 hdlc->data_bits = 0;
55 hdlc->ffbit_shift = 0;
56 hdlc->data_received = 0;
57 hdlc->state = HDLC_GET_DATA;
58 hdlc->do_adapt56 = do_adapt56;
59 hdlc->dchannel = 0;
60 hdlc->crc = 0;
61 hdlc->cbin = 0;
62 hdlc->shift_reg = 0;
63 hdlc->ffvalue = 0;
64 hdlc->dstpos = 0;
67 void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56)
69 hdlc->bit_shift = 0;
70 hdlc->hdlc_bits1 = 0;
71 hdlc->data_bits = 0;
72 hdlc->ffbit_shift = 0;
73 hdlc->data_received = 0;
74 hdlc->do_closing = 0;
75 hdlc->ffvalue = 0;
76 if (is_d_channel) {
77 hdlc->dchannel = 1;
78 hdlc->state = HDLC_SEND_FIRST_FLAG;
79 } else {
80 hdlc->dchannel = 0;
81 hdlc->state = HDLC_SEND_FAST_FLAG;
82 hdlc->ffvalue = 0x7e;
84 hdlc->cbin = 0x7e;
85 hdlc->bit_shift = 0;
86 if(do_adapt56){
87 hdlc->do_adapt56 = 1;
88 hdlc->data_bits = 0;
89 hdlc->state = HDLC_SENDFLAG_B0;
90 } else {
91 hdlc->do_adapt56 = 0;
92 hdlc->data_bits = 8;
94 hdlc->shift_reg = 0;
98 isdnhdlc_decode - decodes HDLC frames from a transparent bit stream.
100 The source buffer is scanned for valid HDLC frames looking for
101 flags (01111110) to indicate the start of a frame. If the start of
102 the frame is found, the bit stuffing is removed (0 after 5 1's).
103 When a new flag is found, the complete frame has been received
104 and the CRC is checked.
105 If a valid frame is found, the function returns the frame length
106 excluding the CRC with the bit HDLC_END_OF_FRAME set.
107 If the beginning of a valid frame is found, the function returns
108 the length.
109 If a framing error is found (too many 1s and not a flag) the function
110 returns the length with the bit HDLC_FRAMING_ERROR set.
111 If a CRC error is found the function returns the length with the
112 bit HDLC_CRC_ERROR set.
113 If the frame length exceeds the destination buffer size, the function
114 returns the length with the bit HDLC_LENGTH_ERROR set.
116 src - source buffer
117 slen - source buffer length
118 count - number of bytes removed (decoded) from the source buffer
119 dst _ destination buffer
120 dsize - destination buffer size
121 returns - number of decoded bytes in the destination buffer and status
122 flag.
124 int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
125 int slen, int *count, unsigned char *dst, int dsize)
127 int status=0;
129 static const unsigned char fast_flag[]={
130 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f
133 static const unsigned char fast_flag_value[]={
134 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f
137 static const unsigned char fast_abort[]={
138 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff
141 *count = slen;
143 while(slen > 0){
144 if(hdlc->bit_shift==0){
145 hdlc->cbin = *src++;
146 slen--;
147 hdlc->bit_shift = 8;
148 if(hdlc->do_adapt56){
149 hdlc->bit_shift --;
153 switch(hdlc->state){
154 case STOPPED:
155 return 0;
156 case HDLC_FAST_IDLE:
157 if(hdlc->cbin == 0xff){
158 hdlc->bit_shift = 0;
159 break;
161 hdlc->state = HDLC_GET_FLAG_B0;
162 hdlc->hdlc_bits1 = 0;
163 hdlc->bit_shift = 8;
164 break;
165 case HDLC_GET_FLAG_B0:
166 if(!(hdlc->cbin & 0x80)) {
167 hdlc->state = HDLC_GETFLAG_B1A6;
168 hdlc->hdlc_bits1 = 0;
169 } else {
170 if(!hdlc->do_adapt56){
171 if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1)
172 hdlc->state = HDLC_FAST_IDLE;
175 hdlc->cbin<<=1;
176 hdlc->bit_shift --;
177 break;
178 case HDLC_GETFLAG_B1A6:
179 if(hdlc->cbin & 0x80){
180 hdlc->hdlc_bits1++;
181 if(hdlc->hdlc_bits1==6){
182 hdlc->state = HDLC_GETFLAG_B7;
184 } else {
185 hdlc->hdlc_bits1 = 0;
187 hdlc->cbin<<=1;
188 hdlc->bit_shift --;
189 break;
190 case HDLC_GETFLAG_B7:
191 if(hdlc->cbin & 0x80) {
192 hdlc->state = HDLC_GET_FLAG_B0;
193 } else {
194 hdlc->state = HDLC_GET_DATA;
195 hdlc->crc = 0xffff;
196 hdlc->shift_reg = 0;
197 hdlc->hdlc_bits1 = 0;
198 hdlc->data_bits = 0;
199 hdlc->data_received = 0;
201 hdlc->cbin<<=1;
202 hdlc->bit_shift --;
203 break;
204 case HDLC_GET_DATA:
205 if(hdlc->cbin & 0x80){
206 hdlc->hdlc_bits1++;
207 switch(hdlc->hdlc_bits1){
208 case 6:
209 break;
210 case 7:
211 if(hdlc->data_received) {
212 // bad frame
213 status = -HDLC_FRAMING_ERROR;
215 if(!hdlc->do_adapt56){
216 if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){
217 hdlc->state = HDLC_FAST_IDLE;
218 hdlc->bit_shift=1;
219 break;
221 } else {
222 hdlc->state = HDLC_GET_FLAG_B0;
224 break;
225 default:
226 hdlc->shift_reg>>=1;
227 hdlc->shift_reg |= 0x80;
228 hdlc->data_bits++;
229 break;
231 } else {
232 switch(hdlc->hdlc_bits1){
233 case 5:
234 break;
235 case 6:
236 if(hdlc->data_received){
237 if (hdlc->dstpos < 2) {
238 status = -HDLC_FRAMING_ERROR;
239 } else if (hdlc->crc != 0xf0b8){
240 // crc error
241 status = -HDLC_CRC_ERROR;
242 } else {
243 // remove CRC
244 hdlc->dstpos -= 2;
245 // good frame
246 status = hdlc->dstpos;
249 hdlc->crc = 0xffff;
250 hdlc->shift_reg = 0;
251 hdlc->data_bits = 0;
252 if(!hdlc->do_adapt56){
253 if(hdlc->cbin==fast_flag[hdlc->bit_shift]){
254 hdlc->ffvalue = fast_flag_value[hdlc->bit_shift];
255 hdlc->state = HDLC_FAST_FLAG;
256 hdlc->ffbit_shift = hdlc->bit_shift;
257 hdlc->bit_shift = 1;
258 } else {
259 hdlc->state = HDLC_GET_DATA;
260 hdlc->data_received = 0;
262 } else {
263 hdlc->state = HDLC_GET_DATA;
264 hdlc->data_received = 0;
266 break;
267 default:
268 hdlc->shift_reg>>=1;
269 hdlc->data_bits++;
270 break;
272 hdlc->hdlc_bits1 = 0;
274 if (status) {
275 hdlc->dstpos = 0;
276 *count -= slen;
277 hdlc->cbin <<= 1;
278 hdlc->bit_shift--;
279 return status;
281 if(hdlc->data_bits==8){
282 hdlc->data_bits = 0;
283 hdlc->data_received = 1;
284 hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg);
286 // good byte received
287 if (hdlc->dstpos < dsize) {
288 dst[hdlc->dstpos++] = hdlc->shift_reg;
289 } else {
290 // frame too long
291 status = -HDLC_LENGTH_ERROR;
292 hdlc->dstpos = 0;
295 hdlc->cbin <<= 1;
296 hdlc->bit_shift--;
297 break;
298 case HDLC_FAST_FLAG:
299 if(hdlc->cbin==hdlc->ffvalue){
300 hdlc->bit_shift = 0;
301 break;
302 } else {
303 if(hdlc->cbin == 0xff){
304 hdlc->state = HDLC_FAST_IDLE;
305 hdlc->bit_shift=0;
306 } else if(hdlc->ffbit_shift==8){
307 hdlc->state = HDLC_GETFLAG_B7;
308 break;
309 } else {
310 hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1];
311 hdlc->hdlc_bits1 = hdlc->ffbit_shift-2;
312 if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0;
313 hdlc->data_bits = hdlc->ffbit_shift-1;
314 hdlc->state = HDLC_GET_DATA;
315 hdlc->data_received = 0;
318 break;
319 default:
320 break;
323 *count -= slen;
324 return 0;
328 isdnhdlc_encode - encodes HDLC frames to a transparent bit stream.
330 The bit stream starts with a beginning flag (01111110). After
331 that each byte is added to the bit stream with bit stuffing added
332 (0 after 5 1's).
333 When the last byte has been removed from the source buffer, the
334 CRC (2 bytes is added) and the frame terminates with the ending flag.
335 For the dchannel, the idle character (all 1's) is also added at the end.
336 If this function is called with empty source buffer (slen=0), flags or
337 idle character will be generated.
339 src - source buffer
340 slen - source buffer length
341 count - number of bytes removed (encoded) from source buffer
342 dst _ destination buffer
343 dsize - destination buffer size
344 returns - number of encoded bytes in the destination buffer
346 int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
347 unsigned short slen, int *count,
348 unsigned char *dst, int dsize)
350 static const unsigned char xfast_flag_value[] = {
351 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e
354 int len = 0;
356 *count = slen;
358 while (dsize > 0) {
359 if(hdlc->bit_shift==0){
360 if(slen && !hdlc->do_closing){
361 hdlc->shift_reg = *src++;
362 slen--;
363 if (slen == 0)
364 hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */
365 hdlc->bit_shift = 8;
366 } else {
367 if(hdlc->state == HDLC_SEND_DATA){
368 if(hdlc->data_received){
369 hdlc->state = HDLC_SEND_CRC1;
370 hdlc->crc ^= 0xffff;
371 hdlc->bit_shift = 8;
372 hdlc->shift_reg = hdlc->crc & 0xff;
373 } else if(!hdlc->do_adapt56){
374 hdlc->state = HDLC_SEND_FAST_FLAG;
375 } else {
376 hdlc->state = HDLC_SENDFLAG_B0;
383 switch(hdlc->state){
384 case STOPPED:
385 while (dsize--)
386 *dst++ = 0xff;
388 return dsize;
389 case HDLC_SEND_FAST_FLAG:
390 hdlc->do_closing = 0;
391 if(slen == 0){
392 *dst++ = hdlc->ffvalue;
393 len++;
394 dsize--;
395 break;
397 if(hdlc->bit_shift==8){
398 hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits);
399 hdlc->state = HDLC_SEND_DATA;
400 hdlc->crc = 0xffff;
401 hdlc->hdlc_bits1 = 0;
402 hdlc->data_received = 1;
404 break;
405 case HDLC_SENDFLAG_B0:
406 hdlc->do_closing = 0;
407 hdlc->cbin <<= 1;
408 hdlc->data_bits++;
409 hdlc->hdlc_bits1 = 0;
410 hdlc->state = HDLC_SENDFLAG_B1A6;
411 break;
412 case HDLC_SENDFLAG_B1A6:
413 hdlc->cbin <<= 1;
414 hdlc->data_bits++;
415 hdlc->cbin++;
416 if(++hdlc->hdlc_bits1 == 6)
417 hdlc->state = HDLC_SENDFLAG_B7;
418 break;
419 case HDLC_SENDFLAG_B7:
420 hdlc->cbin <<= 1;
421 hdlc->data_bits++;
422 if(slen == 0){
423 hdlc->state = HDLC_SENDFLAG_B0;
424 break;
426 if(hdlc->bit_shift==8){
427 hdlc->state = HDLC_SEND_DATA;
428 hdlc->crc = 0xffff;
429 hdlc->hdlc_bits1 = 0;
430 hdlc->data_received = 1;
432 break;
433 case HDLC_SEND_FIRST_FLAG:
434 hdlc->data_received = 1;
435 if(hdlc->data_bits==8){
436 hdlc->state = HDLC_SEND_DATA;
437 hdlc->crc = 0xffff;
438 hdlc->hdlc_bits1 = 0;
439 break;
441 hdlc->cbin <<= 1;
442 hdlc->data_bits++;
443 if(hdlc->shift_reg & 0x01)
444 hdlc->cbin++;
445 hdlc->shift_reg >>= 1;
446 hdlc->bit_shift--;
447 if(hdlc->bit_shift==0){
448 hdlc->state = HDLC_SEND_DATA;
449 hdlc->crc = 0xffff;
450 hdlc->hdlc_bits1 = 0;
452 break;
453 case HDLC_SEND_DATA:
454 hdlc->cbin <<= 1;
455 hdlc->data_bits++;
456 if(hdlc->hdlc_bits1 == 5){
457 hdlc->hdlc_bits1 = 0;
458 break;
460 if(hdlc->bit_shift==8){
461 hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg);
463 if(hdlc->shift_reg & 0x01){
464 hdlc->hdlc_bits1++;
465 hdlc->cbin++;
466 hdlc->shift_reg >>= 1;
467 hdlc->bit_shift--;
468 } else {
469 hdlc->hdlc_bits1 = 0;
470 hdlc->shift_reg >>= 1;
471 hdlc->bit_shift--;
473 break;
474 case HDLC_SEND_CRC1:
475 hdlc->cbin <<= 1;
476 hdlc->data_bits++;
477 if(hdlc->hdlc_bits1 == 5){
478 hdlc->hdlc_bits1 = 0;
479 break;
481 if(hdlc->shift_reg & 0x01){
482 hdlc->hdlc_bits1++;
483 hdlc->cbin++;
484 hdlc->shift_reg >>= 1;
485 hdlc->bit_shift--;
486 } else {
487 hdlc->hdlc_bits1 = 0;
488 hdlc->shift_reg >>= 1;
489 hdlc->bit_shift--;
491 if(hdlc->bit_shift==0){
492 hdlc->shift_reg = (hdlc->crc >> 8);
493 hdlc->state = HDLC_SEND_CRC2;
494 hdlc->bit_shift = 8;
496 break;
497 case HDLC_SEND_CRC2:
498 hdlc->cbin <<= 1;
499 hdlc->data_bits++;
500 if(hdlc->hdlc_bits1 == 5){
501 hdlc->hdlc_bits1 = 0;
502 break;
504 if(hdlc->shift_reg & 0x01){
505 hdlc->hdlc_bits1++;
506 hdlc->cbin++;
507 hdlc->shift_reg >>= 1;
508 hdlc->bit_shift--;
509 } else {
510 hdlc->hdlc_bits1 = 0;
511 hdlc->shift_reg >>= 1;
512 hdlc->bit_shift--;
514 if(hdlc->bit_shift==0){
515 hdlc->shift_reg = 0x7e;
516 hdlc->state = HDLC_SEND_CLOSING_FLAG;
517 hdlc->bit_shift = 8;
519 break;
520 case HDLC_SEND_CLOSING_FLAG:
521 hdlc->cbin <<= 1;
522 hdlc->data_bits++;
523 if(hdlc->hdlc_bits1 == 5){
524 hdlc->hdlc_bits1 = 0;
525 break;
527 if(hdlc->shift_reg & 0x01){
528 hdlc->cbin++;
530 hdlc->shift_reg >>= 1;
531 hdlc->bit_shift--;
532 if(hdlc->bit_shift==0){
533 hdlc->ffvalue = xfast_flag_value[hdlc->data_bits];
534 if(hdlc->dchannel){
535 hdlc->ffvalue = 0x7e;
536 hdlc->state = HDLC_SEND_IDLE1;
537 hdlc->bit_shift = 8-hdlc->data_bits;
538 if(hdlc->bit_shift==0)
539 hdlc->state = HDLC_SEND_FAST_IDLE;
540 } else {
541 if(!hdlc->do_adapt56){
542 hdlc->state = HDLC_SEND_FAST_FLAG;
543 hdlc->data_received = 0;
544 } else {
545 hdlc->state = HDLC_SENDFLAG_B0;
546 hdlc->data_received = 0;
548 // Finished with this frame, send flags
549 if (dsize > 1) dsize = 1;
552 break;
553 case HDLC_SEND_IDLE1:
554 hdlc->do_closing = 0;
555 hdlc->cbin <<= 1;
556 hdlc->cbin++;
557 hdlc->data_bits++;
558 hdlc->bit_shift--;
559 if(hdlc->bit_shift==0){
560 hdlc->state = HDLC_SEND_FAST_IDLE;
561 hdlc->bit_shift = 0;
563 break;
564 case HDLC_SEND_FAST_IDLE:
565 hdlc->do_closing = 0;
566 hdlc->cbin = 0xff;
567 hdlc->data_bits = 8;
568 if(hdlc->bit_shift == 8){
569 hdlc->cbin = 0x7e;
570 hdlc->state = HDLC_SEND_FIRST_FLAG;
571 } else {
572 *dst++ = hdlc->cbin;
573 hdlc->bit_shift = hdlc->data_bits = 0;
574 len++;
575 dsize = 0;
577 break;
578 default:
579 break;
581 if(hdlc->do_adapt56){
582 if(hdlc->data_bits==7){
583 hdlc->cbin <<= 1;
584 hdlc->cbin++;
585 hdlc->data_bits++;
588 if(hdlc->data_bits==8){
589 *dst++ = hdlc->cbin;
590 hdlc->data_bits = 0;
591 len++;
592 dsize--;
595 *count -= slen;
597 return len;
600 EXPORT_SYMBOL(isdnhdlc_rcv_init);
601 EXPORT_SYMBOL(isdnhdlc_decode);
602 EXPORT_SYMBOL(isdnhdlc_out_init);
603 EXPORT_SYMBOL(isdnhdlc_encode);