Merge git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
[linux-2.6] / drivers / isdn / hisax / isdnhdlc.c
1 /*
2  * isdnhdlc.c  --  General purpose ISDN HDLC decoder.
3  *
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>
7  *
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.
12  *
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.
17  *
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.
21  */
22
23 #include <linux/module.h>
24 #include <linux/init.h>
25 #include <linux/crc-ccitt.h>
26 #include "isdnhdlc.h"
27
28 /*-------------------------------------------------------------------*/
29
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");
35
36 /*-------------------------------------------------------------------*/
37
38 enum {
39         HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7,
40         HDLC_GET_DATA,HDLC_FAST_FLAG
41 };
42
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
48 };
49
50 void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56)
51 {
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;
65 }
66
67 void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56)
68 {
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;
83         }
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;
93         }
94         hdlc->shift_reg = 0;
95 }
96
97 /*
98   isdnhdlc_decode - decodes HDLC frames from a transparent bit stream.
99
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.
115
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.
123  */
124 int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
125                      int slen, int *count, unsigned char *dst, int dsize)
126 {
127         int status=0;
128
129         static const unsigned char fast_flag[]={
130                 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f
131         };
132
133         static const unsigned char fast_flag_value[]={
134                 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f
135         };
136
137         static const unsigned char fast_abort[]={
138                 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff
139         };
140
141         *count = slen;
142
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 --;
150                         }
151                 }
152
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;
160                         }
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;
173                                 }
174                         }
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;
183                                 }
184                         } else {
185                                 hdlc->hdlc_bits1 = 0;
186                         }
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;
200                         }
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;
214                                         }
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;
220                                                 }
221                                         } else {
222                                                 hdlc->state = HDLC_GET_FLAG_B0;
223                                         }
224                                         break;
225                                 default:
226                                         hdlc->shift_reg>>=1;
227                                         hdlc->shift_reg |= 0x80;
228                                         hdlc->data_bits++;
229                                         break;
230                                 }
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;
247                                                 }
248                                         }
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;
261                                                 }
262                                         } else {
263                                                 hdlc->state = HDLC_GET_DATA;
264                                                 hdlc->data_received = 0;
265                                         }
266                                         break;
267                                 default:
268                                         hdlc->shift_reg>>=1;
269                                         hdlc->data_bits++;
270                                         break;
271                                 }
272                                 hdlc->hdlc_bits1 = 0;
273                         }
274                         if (status) {
275                                 hdlc->dstpos = 0;
276                                 *count -= slen;
277                                 hdlc->cbin <<= 1;
278                                 hdlc->bit_shift--;
279                                 return status;
280                         }
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);
285
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;
293                                 }
294                         }
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;
316                                 }
317                         }
318                         break;
319                 default:
320                         break;
321                 }
322         }
323         *count -= slen;
324         return 0;
325 }
326
327 /*
328   isdnhdlc_encode - encodes HDLC frames to a transparent bit stream.
329
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.
338
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
345 */
346 int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
347                 unsigned short slen, int *count,
348                 unsigned char *dst, int dsize)
349 {
350         static const unsigned char xfast_flag_value[] = {
351                 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e
352         };
353
354         int len = 0;
355
356         *count = slen;
357
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;
377                                         }
378                                 }
379
380                         }
381                 }
382
383                 switch(hdlc->state){
384                 case STOPPED:
385                         while (dsize--)
386                                 *dst++ = 0xff;
387
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;
396                         }
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;
403                         }
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;
425                         }
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;
431                         }
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;
440                         }
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;
451                         }
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;
459                         }
460                         if(hdlc->bit_shift==8){
461                                 hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg);
462                         }
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--;
472                         }
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;
480                         }
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--;
490                         }
491                         if(hdlc->bit_shift==0){
492                                 hdlc->shift_reg = (hdlc->crc >> 8);
493                                 hdlc->state = HDLC_SEND_CRC2;
494                                 hdlc->bit_shift = 8;
495                         }
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;
503                         }
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--;
513                         }
514                         if(hdlc->bit_shift==0){
515                                 hdlc->shift_reg = 0x7e;
516                                 hdlc->state = HDLC_SEND_CLOSING_FLAG;
517                                 hdlc->bit_shift = 8;
518                         }
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;
526                         }
527                         if(hdlc->shift_reg & 0x01){
528                                 hdlc->cbin++;
529                         }
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;
547                                         }
548                                         // Finished with this frame, send flags
549                                         if (dsize > 1) dsize = 1;
550                                 }
551                         }
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;
562                         }
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;
576                         }
577                         break;
578                 default:
579                         break;
580                 }
581                 if(hdlc->do_adapt56){
582                         if(hdlc->data_bits==7){
583                                 hdlc->cbin <<= 1;
584                                 hdlc->cbin++;
585                                 hdlc->data_bits++;
586                         }
587                 }
588                 if(hdlc->data_bits==8){
589                         *dst++ = hdlc->cbin;
590                         hdlc->data_bits = 0;
591                         len++;
592                         dsize--;
593                 }
594         }
595         *count -= slen;
596
597         return len;
598 }
599
600 EXPORT_SYMBOL(isdnhdlc_rcv_init);
601 EXPORT_SYMBOL(isdnhdlc_decode);
602 EXPORT_SYMBOL(isdnhdlc_out_init);
603 EXPORT_SYMBOL(isdnhdlc_encode);