Linux 2.6.34-rc3
[pohmelfs.git] / drivers / isdn / i4l / isdnhdlc.c
blobc989aa35dc2fc56ede0c29eafb8e34cd378bf1ae
1 /*
2 * isdnhdlc.c -- General purpose ISDN HDLC decoder.
4 * Copyright (C)
5 * 2009 Karsten Keil <keil@b1-systems.de>
6 * 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
7 * 2001 Frode Isaksen <fisaksen@bewan.com>
8 * 2001 Kai Germaschewski <kai.germaschewski@gmx.de>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <linux/module.h>
26 #include <linux/init.h>
27 #include <linux/crc-ccitt.h>
28 #include <linux/isdn/hdlc.h>
29 #include <linux/bitrev.h>
31 /*-------------------------------------------------------------------*/
33 MODULE_AUTHOR("Wolfgang Mües <wolfgang@iksw-muees.de>, "
34 "Frode Isaksen <fisaksen@bewan.com>, "
35 "Kai Germaschewski <kai.germaschewski@gmx.de>");
36 MODULE_DESCRIPTION("General purpose ISDN HDLC decoder");
37 MODULE_LICENSE("GPL");
39 /*-------------------------------------------------------------------*/
41 enum {
42 HDLC_FAST_IDLE, HDLC_GET_FLAG_B0, HDLC_GETFLAG_B1A6, HDLC_GETFLAG_B7,
43 HDLC_GET_DATA, HDLC_FAST_FLAG
46 enum {
47 HDLC_SEND_DATA, HDLC_SEND_CRC1, HDLC_SEND_FAST_FLAG,
48 HDLC_SEND_FIRST_FLAG, HDLC_SEND_CRC2, HDLC_SEND_CLOSING_FLAG,
49 HDLC_SEND_IDLE1, HDLC_SEND_FAST_IDLE, HDLC_SENDFLAG_B0,
50 HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED, HDLC_SENDFLAG_ONE
53 void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features)
55 memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
56 hdlc->state = HDLC_GET_DATA;
57 if (features & HDLC_56KBIT)
58 hdlc->do_adapt56 = 1;
59 if (features & HDLC_BITREVERSE)
60 hdlc->do_bitreverse = 1;
62 EXPORT_SYMBOL(isdnhdlc_out_init);
64 void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features)
66 memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
67 if (features & HDLC_DCHANNEL) {
68 hdlc->dchannel = 1;
69 hdlc->state = HDLC_SEND_FIRST_FLAG;
70 } else {
71 hdlc->dchannel = 0;
72 hdlc->state = HDLC_SEND_FAST_FLAG;
73 hdlc->ffvalue = 0x7e;
75 hdlc->cbin = 0x7e;
76 if (features & HDLC_56KBIT) {
77 hdlc->do_adapt56 = 1;
78 hdlc->state = HDLC_SENDFLAG_B0;
79 } else
80 hdlc->data_bits = 8;
81 if (features & HDLC_BITREVERSE)
82 hdlc->do_bitreverse = 1;
84 EXPORT_SYMBOL(isdnhdlc_rcv_init);
86 static int
87 check_frame(struct isdnhdlc_vars *hdlc)
89 int status;
91 if (hdlc->dstpos < 2) /* too small - framing error */
92 status = -HDLC_FRAMING_ERROR;
93 else if (hdlc->crc != 0xf0b8) /* crc error */
94 status = -HDLC_CRC_ERROR;
95 else {
96 /* remove CRC */
97 hdlc->dstpos -= 2;
98 /* good frame */
99 status = hdlc->dstpos;
101 return status;
105 isdnhdlc_decode - decodes HDLC frames from a transparent bit stream.
107 The source buffer is scanned for valid HDLC frames looking for
108 flags (01111110) to indicate the start of a frame. If the start of
109 the frame is found, the bit stuffing is removed (0 after 5 1's).
110 When a new flag is found, the complete frame has been received
111 and the CRC is checked.
112 If a valid frame is found, the function returns the frame length
113 excluding the CRC with the bit HDLC_END_OF_FRAME set.
114 If the beginning of a valid frame is found, the function returns
115 the length.
116 If a framing error is found (too many 1s and not a flag) the function
117 returns the length with the bit HDLC_FRAMING_ERROR set.
118 If a CRC error is found the function returns the length with the
119 bit HDLC_CRC_ERROR set.
120 If the frame length exceeds the destination buffer size, the function
121 returns the length with the bit HDLC_LENGTH_ERROR set.
123 src - source buffer
124 slen - source buffer length
125 count - number of bytes removed (decoded) from the source buffer
126 dst _ destination buffer
127 dsize - destination buffer size
128 returns - number of decoded bytes in the destination buffer and status
129 flag.
131 int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen,
132 int *count, u8 *dst, int dsize)
134 int status = 0;
136 static const unsigned char fast_flag[] = {
137 0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f
140 static const unsigned char fast_flag_value[] = {
141 0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f
144 static const unsigned char fast_abort[] = {
145 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
148 #define handle_fast_flag(h) \
149 do {\
150 if (h->cbin == fast_flag[h->bit_shift]) {\
151 h->ffvalue = fast_flag_value[h->bit_shift];\
152 h->state = HDLC_FAST_FLAG;\
153 h->ffbit_shift = h->bit_shift;\
154 h->bit_shift = 1;\
155 } else {\
156 h->state = HDLC_GET_DATA;\
157 h->data_received = 0;\
159 } while (0)
161 #define handle_abort(h) \
162 do {\
163 h->shift_reg = fast_abort[h->ffbit_shift - 1];\
164 h->hdlc_bits1 = h->ffbit_shift - 2;\
165 if (h->hdlc_bits1 < 0)\
166 h->hdlc_bits1 = 0;\
167 h->data_bits = h->ffbit_shift - 1;\
168 h->state = HDLC_GET_DATA;\
169 h->data_received = 0;\
170 } while (0)
172 *count = slen;
174 while (slen > 0) {
175 if (hdlc->bit_shift == 0) {
176 /* the code is for bitreverse streams */
177 if (hdlc->do_bitreverse == 0)
178 hdlc->cbin = bitrev8(*src++);
179 else
180 hdlc->cbin = *src++;
181 slen--;
182 hdlc->bit_shift = 8;
183 if (hdlc->do_adapt56)
184 hdlc->bit_shift--;
187 switch (hdlc->state) {
188 case STOPPED:
189 return 0;
190 case HDLC_FAST_IDLE:
191 if (hdlc->cbin == 0xff) {
192 hdlc->bit_shift = 0;
193 break;
195 hdlc->state = HDLC_GET_FLAG_B0;
196 hdlc->hdlc_bits1 = 0;
197 hdlc->bit_shift = 8;
198 break;
199 case HDLC_GET_FLAG_B0:
200 if (!(hdlc->cbin & 0x80)) {
201 hdlc->state = HDLC_GETFLAG_B1A6;
202 hdlc->hdlc_bits1 = 0;
203 } else {
204 if ((!hdlc->do_adapt56) &&
205 (++hdlc->hdlc_bits1 >= 8) &&
206 (hdlc->bit_shift == 1))
207 hdlc->state = HDLC_FAST_IDLE;
209 hdlc->cbin <<= 1;
210 hdlc->bit_shift--;
211 break;
212 case HDLC_GETFLAG_B1A6:
213 if (hdlc->cbin & 0x80) {
214 hdlc->hdlc_bits1++;
215 if (hdlc->hdlc_bits1 == 6)
216 hdlc->state = HDLC_GETFLAG_B7;
217 } else
218 hdlc->hdlc_bits1 = 0;
219 hdlc->cbin <<= 1;
220 hdlc->bit_shift--;
221 break;
222 case HDLC_GETFLAG_B7:
223 if (hdlc->cbin & 0x80) {
224 hdlc->state = HDLC_GET_FLAG_B0;
225 } else {
226 hdlc->state = HDLC_GET_DATA;
227 hdlc->crc = 0xffff;
228 hdlc->shift_reg = 0;
229 hdlc->hdlc_bits1 = 0;
230 hdlc->data_bits = 0;
231 hdlc->data_received = 0;
233 hdlc->cbin <<= 1;
234 hdlc->bit_shift--;
235 break;
236 case HDLC_GET_DATA:
237 if (hdlc->cbin & 0x80) {
238 hdlc->hdlc_bits1++;
239 switch (hdlc->hdlc_bits1) {
240 case 6:
241 break;
242 case 7:
243 if (hdlc->data_received)
244 /* bad frame */
245 status = -HDLC_FRAMING_ERROR;
246 if (!hdlc->do_adapt56) {
247 if (hdlc->cbin == fast_abort
248 [hdlc->bit_shift + 1]) {
249 hdlc->state =
250 HDLC_FAST_IDLE;
251 hdlc->bit_shift = 1;
252 break;
254 } else
255 hdlc->state = HDLC_GET_FLAG_B0;
256 break;
257 default:
258 hdlc->shift_reg >>= 1;
259 hdlc->shift_reg |= 0x80;
260 hdlc->data_bits++;
261 break;
263 } else {
264 switch (hdlc->hdlc_bits1) {
265 case 5:
266 break;
267 case 6:
268 if (hdlc->data_received)
269 status = check_frame(hdlc);
270 hdlc->crc = 0xffff;
271 hdlc->shift_reg = 0;
272 hdlc->data_bits = 0;
273 if (!hdlc->do_adapt56)
274 handle_fast_flag(hdlc);
275 else {
276 hdlc->state = HDLC_GET_DATA;
277 hdlc->data_received = 0;
279 break;
280 default:
281 hdlc->shift_reg >>= 1;
282 hdlc->data_bits++;
283 break;
285 hdlc->hdlc_bits1 = 0;
287 if (status) {
288 hdlc->dstpos = 0;
289 *count -= slen;
290 hdlc->cbin <<= 1;
291 hdlc->bit_shift--;
292 return status;
294 if (hdlc->data_bits == 8) {
295 hdlc->data_bits = 0;
296 hdlc->data_received = 1;
297 hdlc->crc = crc_ccitt_byte(hdlc->crc,
298 hdlc->shift_reg);
300 /* good byte received */
301 if (hdlc->dstpos < dsize)
302 dst[hdlc->dstpos++] = hdlc->shift_reg;
303 else {
304 /* frame too long */
305 status = -HDLC_LENGTH_ERROR;
306 hdlc->dstpos = 0;
309 hdlc->cbin <<= 1;
310 hdlc->bit_shift--;
311 break;
312 case HDLC_FAST_FLAG:
313 if (hdlc->cbin == hdlc->ffvalue) {
314 hdlc->bit_shift = 0;
315 break;
316 } else {
317 if (hdlc->cbin == 0xff) {
318 hdlc->state = HDLC_FAST_IDLE;
319 hdlc->bit_shift = 0;
320 } else if (hdlc->ffbit_shift == 8) {
321 hdlc->state = HDLC_GETFLAG_B7;
322 break;
323 } else
324 handle_abort(hdlc);
326 break;
327 default:
328 break;
331 *count -= slen;
332 return 0;
334 EXPORT_SYMBOL(isdnhdlc_decode);
336 isdnhdlc_encode - encodes HDLC frames to a transparent bit stream.
338 The bit stream starts with a beginning flag (01111110). After
339 that each byte is added to the bit stream with bit stuffing added
340 (0 after 5 1's).
341 When the last byte has been removed from the source buffer, the
342 CRC (2 bytes is added) and the frame terminates with the ending flag.
343 For the dchannel, the idle character (all 1's) is also added at the end.
344 If this function is called with empty source buffer (slen=0), flags or
345 idle character will be generated.
347 src - source buffer
348 slen - source buffer length
349 count - number of bytes removed (encoded) from source buffer
350 dst _ destination buffer
351 dsize - destination buffer size
352 returns - number of encoded bytes in the destination buffer
354 int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen,
355 int *count, u8 *dst, int dsize)
357 static const unsigned char xfast_flag_value[] = {
358 0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9, 0xfc, 0x7e
361 int len = 0;
363 *count = slen;
365 /* special handling for one byte frames */
366 if ((slen == 1) && (hdlc->state == HDLC_SEND_FAST_FLAG))
367 hdlc->state = HDLC_SENDFLAG_ONE;
368 while (dsize > 0) {
369 if (hdlc->bit_shift == 0) {
370 if (slen && !hdlc->do_closing) {
371 hdlc->shift_reg = *src++;
372 slen--;
373 if (slen == 0)
374 /* closing sequence, CRC + flag(s) */
375 hdlc->do_closing = 1;
376 hdlc->bit_shift = 8;
377 } else {
378 if (hdlc->state == HDLC_SEND_DATA) {
379 if (hdlc->data_received) {
380 hdlc->state = HDLC_SEND_CRC1;
381 hdlc->crc ^= 0xffff;
382 hdlc->bit_shift = 8;
383 hdlc->shift_reg =
384 hdlc->crc & 0xff;
385 } else if (!hdlc->do_adapt56)
386 hdlc->state =
387 HDLC_SEND_FAST_FLAG;
388 else
389 hdlc->state =
390 HDLC_SENDFLAG_B0;
396 switch (hdlc->state) {
397 case STOPPED:
398 while (dsize--)
399 *dst++ = 0xff;
400 return dsize;
401 case HDLC_SEND_FAST_FLAG:
402 hdlc->do_closing = 0;
403 if (slen == 0) {
404 /* the code is for bitreverse streams */
405 if (hdlc->do_bitreverse == 0)
406 *dst++ = bitrev8(hdlc->ffvalue);
407 else
408 *dst++ = hdlc->ffvalue;
409 len++;
410 dsize--;
411 break;
413 /* fall through */
414 case HDLC_SENDFLAG_ONE:
415 if (hdlc->bit_shift == 8) {
416 hdlc->cbin = hdlc->ffvalue >>
417 (8 - hdlc->data_bits);
418 hdlc->state = HDLC_SEND_DATA;
419 hdlc->crc = 0xffff;
420 hdlc->hdlc_bits1 = 0;
421 hdlc->data_received = 1;
423 break;
424 case HDLC_SENDFLAG_B0:
425 hdlc->do_closing = 0;
426 hdlc->cbin <<= 1;
427 hdlc->data_bits++;
428 hdlc->hdlc_bits1 = 0;
429 hdlc->state = HDLC_SENDFLAG_B1A6;
430 break;
431 case HDLC_SENDFLAG_B1A6:
432 hdlc->cbin <<= 1;
433 hdlc->data_bits++;
434 hdlc->cbin++;
435 if (++hdlc->hdlc_bits1 == 6)
436 hdlc->state = HDLC_SENDFLAG_B7;
437 break;
438 case HDLC_SENDFLAG_B7:
439 hdlc->cbin <<= 1;
440 hdlc->data_bits++;
441 if (slen == 0) {
442 hdlc->state = HDLC_SENDFLAG_B0;
443 break;
445 if (hdlc->bit_shift == 8) {
446 hdlc->state = HDLC_SEND_DATA;
447 hdlc->crc = 0xffff;
448 hdlc->hdlc_bits1 = 0;
449 hdlc->data_received = 1;
451 break;
452 case HDLC_SEND_FIRST_FLAG:
453 hdlc->data_received = 1;
454 if (hdlc->data_bits == 8) {
455 hdlc->state = HDLC_SEND_DATA;
456 hdlc->crc = 0xffff;
457 hdlc->hdlc_bits1 = 0;
458 break;
460 hdlc->cbin <<= 1;
461 hdlc->data_bits++;
462 if (hdlc->shift_reg & 0x01)
463 hdlc->cbin++;
464 hdlc->shift_reg >>= 1;
465 hdlc->bit_shift--;
466 if (hdlc->bit_shift == 0) {
467 hdlc->state = HDLC_SEND_DATA;
468 hdlc->crc = 0xffff;
469 hdlc->hdlc_bits1 = 0;
471 break;
472 case HDLC_SEND_DATA:
473 hdlc->cbin <<= 1;
474 hdlc->data_bits++;
475 if (hdlc->hdlc_bits1 == 5) {
476 hdlc->hdlc_bits1 = 0;
477 break;
479 if (hdlc->bit_shift == 8)
480 hdlc->crc = crc_ccitt_byte(hdlc->crc,
481 hdlc->shift_reg);
482 if (hdlc->shift_reg & 0x01) {
483 hdlc->hdlc_bits1++;
484 hdlc->cbin++;
485 hdlc->shift_reg >>= 1;
486 hdlc->bit_shift--;
487 } else {
488 hdlc->hdlc_bits1 = 0;
489 hdlc->shift_reg >>= 1;
490 hdlc->bit_shift--;
492 break;
493 case HDLC_SEND_CRC1:
494 hdlc->cbin <<= 1;
495 hdlc->data_bits++;
496 if (hdlc->hdlc_bits1 == 5) {
497 hdlc->hdlc_bits1 = 0;
498 break;
500 if (hdlc->shift_reg & 0x01) {
501 hdlc->hdlc_bits1++;
502 hdlc->cbin++;
503 hdlc->shift_reg >>= 1;
504 hdlc->bit_shift--;
505 } else {
506 hdlc->hdlc_bits1 = 0;
507 hdlc->shift_reg >>= 1;
508 hdlc->bit_shift--;
510 if (hdlc->bit_shift == 0) {
511 hdlc->shift_reg = (hdlc->crc >> 8);
512 hdlc->state = HDLC_SEND_CRC2;
513 hdlc->bit_shift = 8;
515 break;
516 case HDLC_SEND_CRC2:
517 hdlc->cbin <<= 1;
518 hdlc->data_bits++;
519 if (hdlc->hdlc_bits1 == 5) {
520 hdlc->hdlc_bits1 = 0;
521 break;
523 if (hdlc->shift_reg & 0x01) {
524 hdlc->hdlc_bits1++;
525 hdlc->cbin++;
526 hdlc->shift_reg >>= 1;
527 hdlc->bit_shift--;
528 } else {
529 hdlc->hdlc_bits1 = 0;
530 hdlc->shift_reg >>= 1;
531 hdlc->bit_shift--;
533 if (hdlc->bit_shift == 0) {
534 hdlc->shift_reg = 0x7e;
535 hdlc->state = HDLC_SEND_CLOSING_FLAG;
536 hdlc->bit_shift = 8;
538 break;
539 case HDLC_SEND_CLOSING_FLAG:
540 hdlc->cbin <<= 1;
541 hdlc->data_bits++;
542 if (hdlc->hdlc_bits1 == 5) {
543 hdlc->hdlc_bits1 = 0;
544 break;
546 if (hdlc->shift_reg & 0x01)
547 hdlc->cbin++;
548 hdlc->shift_reg >>= 1;
549 hdlc->bit_shift--;
550 if (hdlc->bit_shift == 0) {
551 hdlc->ffvalue =
552 xfast_flag_value[hdlc->data_bits];
553 if (hdlc->dchannel) {
554 hdlc->ffvalue = 0x7e;
555 hdlc->state = HDLC_SEND_IDLE1;
556 hdlc->bit_shift = 8-hdlc->data_bits;
557 if (hdlc->bit_shift == 0)
558 hdlc->state =
559 HDLC_SEND_FAST_IDLE;
560 } else {
561 if (!hdlc->do_adapt56) {
562 hdlc->state =
563 HDLC_SEND_FAST_FLAG;
564 hdlc->data_received = 0;
565 } else {
566 hdlc->state = HDLC_SENDFLAG_B0;
567 hdlc->data_received = 0;
569 /* Finished this frame, send flags */
570 if (dsize > 1)
571 dsize = 1;
574 break;
575 case HDLC_SEND_IDLE1:
576 hdlc->do_closing = 0;
577 hdlc->cbin <<= 1;
578 hdlc->cbin++;
579 hdlc->data_bits++;
580 hdlc->bit_shift--;
581 if (hdlc->bit_shift == 0) {
582 hdlc->state = HDLC_SEND_FAST_IDLE;
583 hdlc->bit_shift = 0;
585 break;
586 case HDLC_SEND_FAST_IDLE:
587 hdlc->do_closing = 0;
588 hdlc->cbin = 0xff;
589 hdlc->data_bits = 8;
590 if (hdlc->bit_shift == 8) {
591 hdlc->cbin = 0x7e;
592 hdlc->state = HDLC_SEND_FIRST_FLAG;
593 } else {
594 /* the code is for bitreverse streams */
595 if (hdlc->do_bitreverse == 0)
596 *dst++ = bitrev8(hdlc->cbin);
597 else
598 *dst++ = hdlc->cbin;
599 hdlc->bit_shift = 0;
600 hdlc->data_bits = 0;
601 len++;
602 dsize = 0;
604 break;
605 default:
606 break;
608 if (hdlc->do_adapt56) {
609 if (hdlc->data_bits == 7) {
610 hdlc->cbin <<= 1;
611 hdlc->cbin++;
612 hdlc->data_bits++;
615 if (hdlc->data_bits == 8) {
616 /* the code is for bitreverse streams */
617 if (hdlc->do_bitreverse == 0)
618 *dst++ = bitrev8(hdlc->cbin);
619 else
620 *dst++ = hdlc->cbin;
621 hdlc->data_bits = 0;
622 len++;
623 dsize--;
626 *count -= slen;
628 return len;
630 EXPORT_SYMBOL(isdnhdlc_encode);