VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / drivers / isdn / tpam / tpam_crcpc.c
1 /* $Id: tpam_crcpc.c,v 1.1.2.2 2001/09/23 22:25:03 kai Exp $
2  *
3  * Turbo PAM ISDN driver for Linux. (Kernel Driver - CRC encoding)
4  *
5  * Copyright 1998-2000 AUVERTECH Télécom
6  * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
7  *
8  * This software may be used and distributed according to the terms
9  * of the GNU General Public License, incorporated herein by reference.
10  *
11  * For all support questions please contact: <support@auvertech.fr>
12  *
13  */
14
15 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
16
17 Module Name:
18
19     crcpc.c
20
21 Abstract:
22
23     Modem HDLC coding
24     Software HDLC coding / decoding
25
26 Revision History:
27
28 ---------------------------------------------------------------------------*/
29
30 #include <linux/crc-ccitt.h>
31 #include "tpam.h"
32
33 #define  HDLC_CTRL_CHAR_CMPL_MASK       0x20    /* HDLC control character complement mask */
34 #define  HDLC_FLAG                      0x7E    /* HDLC flag */
35 #define  HDLC_CTRL_ESC                  0x7D    /* HDLC control escapr character */
36 #define  HDLC_LIKE_FCS_INIT_VAL         0xFFFF  /* FCS initial value (0xFFFF for new equipment or 0) */
37 #define  HDLC_FCS_OK                    0xF0B8  /* This value is the only valid value of FCS */
38
39 #define TRUE    1
40 #define FALSE   0
41
42 static u8 ap_t_ctrl_char_complemented[256]; /* list of characters to complement */
43
44 static void ap_hdlc_like_ctrl_char_list (u32 ctrl_char) {
45         int i;
46
47         for (i = 0; i < 256; ++i)
48                 ap_t_ctrl_char_complemented[i] = FALSE;
49         for (i = 0; i < 32; ++i)
50                 if ((ctrl_char >> i) & 0x0001)
51                         ap_t_ctrl_char_complemented [i] = TRUE;
52         ap_t_ctrl_char_complemented[HDLC_FLAG] = TRUE;
53         ap_t_ctrl_char_complemented[HDLC_CTRL_ESC] = TRUE;
54                 
55 }
56
57 void init_CRC(void) {
58         ap_hdlc_like_ctrl_char_list(0xffffffff);
59 }
60
61 void hdlc_encode_modem(u8 *buffer_in, u32 lng_in,
62                        u8 *buffer_out, u32 *lng_out) {
63         u16 fcs;
64         register u8 data;
65         register u8 *p_data_out = buffer_out;
66
67         fcs = HDLC_LIKE_FCS_INIT_VAL;
68
69         /*
70          *   Insert HDLC flag at the beginning of the frame
71          */
72         *p_data_out++ = HDLC_FLAG;
73
74 #define ESCAPE_CHAR(data_out, data) \
75         if (ap_t_ctrl_char_complemented[data]) { \
76                 *data_out++ = HDLC_CTRL_ESC; \
77                 *data_out++ = data ^ 0x20; \
78         } \
79         else \
80                 *data_out++ = data;
81
82         while (lng_in--) {
83                 data = *buffer_in++;
84
85                 /*
86                  *   FCS calculation
87                  */
88                 fcs = crc_ccitt_byte(fcs, data);
89
90                 ESCAPE_CHAR(p_data_out, data);
91         }
92
93         /*
94          *  Add FCS and closing flag
95          */
96         fcs ^= 0xFFFF;  // Complement
97
98         data = (u8)(fcs & 0xff);        /* LSB */
99         ESCAPE_CHAR(p_data_out, data);
100
101         data = (u8)((fcs >> 8));        /* MSB */
102         ESCAPE_CHAR(p_data_out, data);
103 #undef ESCAPE_CHAR
104
105         *p_data_out++ = HDLC_FLAG;
106
107         *lng_out = (u32)(p_data_out - buffer_out);
108 }
109
110 void hdlc_no_accm_encode(u8 *buffer_in, u32 lng_in, 
111                          u8 *buffer_out, u32 *lng_out) {
112         u16 fcs;
113         register u8 data;
114         register u8 *p_data_out = buffer_out;
115
116         /*
117          *   Insert HDLC flag at the beginning of the frame
118          */
119         fcs = HDLC_LIKE_FCS_INIT_VAL;
120
121         while (lng_in--) {
122                 data = *buffer_in++;
123                 /* calculate FCS */
124                 fcs = crc_ccitt_byte(fcs, data);
125                 *p_data_out++ = data;
126         }
127
128         /*
129          *  Add FCS and closing flag
130          */
131         fcs ^= 0xFFFF;  // Complement
132         data = (u8)(fcs);    
133         *p_data_out++ = data;
134
135         data =(u8)((fcs >> 8));   // revense MSB / LSB
136         *p_data_out++ = data;
137  
138         *lng_out = (u32)(p_data_out - buffer_out);
139 }
140
141 u32 hdlc_no_accm_decode(u8 *buffer_in, u32 lng_in) {
142         u16 fcs;
143         u32 lng = lng_in;
144         register u8 data;
145
146         /*
147          *   Insert HDLC flag at the beginning of the frame
148          */
149         fcs = HDLC_LIKE_FCS_INIT_VAL;
150
151         while (lng_in--) {
152                 data = *buffer_in++;
153                 /* calculate FCS */
154                 fcs = crc_ccitt_byte(fcs, data);
155         }
156
157         if (fcs == HDLC_FCS_OK) 
158                 return (lng-2);
159         else 
160                 return 0;
161 }
162