Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * isdnhdlc.c -- General purpose ISDN HDLC decoder. | |
3 | * | |
6bd4bcd3 | 4 | * Copyright (C) |
c38fc3bc | 5 | * 2009 Karsten Keil <keil@b1-systems.de> |
6bd4bcd3 KK |
6 | * 2002 Wolfgang Mües <wolfgang@iksw-muees.de> |
7 | * 2001 Frode Isaksen <fisaksen@bewan.com> | |
8 | * 2001 Kai Germaschewski <kai.germaschewski@gmx.de> | |
1da177e4 | 9 | * |
6bd4bcd3 KK |
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. | |
1da177e4 | 14 | * |
6bd4bcd3 KK |
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. | |
1da177e4 | 19 | * |
6bd4bcd3 KK |
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. | |
1da177e4 LT |
23 | */ |
24 | ||
25 | #include <linux/module.h> | |
26 | #include <linux/init.h> | |
27 | #include <linux/crc-ccitt.h> | |
cb3824ba | 28 | #include <linux/isdn/hdlc.h> |
c38fc3bc | 29 | #include <linux/bitrev.h> |
1da177e4 LT |
30 | |
31 | /*-------------------------------------------------------------------*/ | |
32 | ||
96de0e25 | 33 | MODULE_AUTHOR("Wolfgang Mües <wolfgang@iksw-muees.de>, " |
1da177e4 LT |
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"); | |
38 | ||
39 | /*-------------------------------------------------------------------*/ | |
40 | ||
1da177e4 | 41 | enum { |
6bd4bcd3 KK |
42 | HDLC_FAST_IDLE, HDLC_GET_FLAG_B0, HDLC_GETFLAG_B1A6, HDLC_GETFLAG_B7, |
43 | HDLC_GET_DATA, HDLC_FAST_FLAG | |
1da177e4 LT |
44 | }; |
45 | ||
46 | enum { | |
6bd4bcd3 KK |
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, | |
f3fad223 | 50 | HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED, HDLC_SENDFLAG_ONE |
1da177e4 LT |
51 | }; |
52 | ||
c38fc3bc | 53 | void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features) |
1da177e4 | 54 | { |
c38fc3bc | 55 | memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); |
1da177e4 | 56 | hdlc->state = HDLC_GET_DATA; |
c38fc3bc KK |
57 | if (features & HDLC_56KBIT) |
58 | hdlc->do_adapt56 = 1; | |
59 | if (features & HDLC_BITREVERSE) | |
60 | hdlc->do_bitreverse = 1; | |
1da177e4 | 61 | } |
6bd4bcd3 | 62 | EXPORT_SYMBOL(isdnhdlc_out_init); |
1da177e4 | 63 | |
c38fc3bc | 64 | void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features) |
1da177e4 | 65 | { |
c38fc3bc KK |
66 | memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); |
67 | if (features & HDLC_DCHANNEL) { | |
1da177e4 LT |
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; | |
74 | } | |
75 | hdlc->cbin = 0x7e; | |
c38fc3bc | 76 | if (features & HDLC_56KBIT) { |
1da177e4 | 77 | hdlc->do_adapt56 = 1; |
1da177e4 | 78 | hdlc->state = HDLC_SENDFLAG_B0; |
c38fc3bc | 79 | } else |
1da177e4 | 80 | hdlc->data_bits = 8; |
c38fc3bc KK |
81 | if (features & HDLC_BITREVERSE) |
82 | hdlc->do_bitreverse = 1; | |
1da177e4 | 83 | } |
6bd4bcd3 KK |
84 | EXPORT_SYMBOL(isdnhdlc_rcv_init); |
85 | ||
86 | static int | |
87 | check_frame(struct isdnhdlc_vars *hdlc) | |
88 | { | |
89 | int status; | |
90 | ||
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; | |
100 | } | |
101 | return status; | |
102 | } | |
1da177e4 LT |
103 | |
104 | /* | |
105 | isdnhdlc_decode - decodes HDLC frames from a transparent bit stream. | |
106 | ||
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. | |
122 | ||
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. | |
130 | */ | |
6bd4bcd3 KK |
131 | int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen, |
132 | int *count, u8 *dst, int dsize) | |
1da177e4 | 133 | { |
6bd4bcd3 | 134 | int status = 0; |
1da177e4 | 135 | |
6bd4bcd3 KK |
136 | static const unsigned char fast_flag[] = { |
137 | 0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f | |
1da177e4 LT |
138 | }; |
139 | ||
6bd4bcd3 KK |
140 | static const unsigned char fast_flag_value[] = { |
141 | 0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f | |
1da177e4 LT |
142 | }; |
143 | ||
6bd4bcd3 KK |
144 | static const unsigned char fast_abort[] = { |
145 | 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff | |
1da177e4 LT |
146 | }; |
147 | ||
6bd4bcd3 KK |
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;\ | |
158 | } \ | |
159 | } while (0) | |
160 | ||
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) | |
171 | ||
1da177e4 LT |
172 | *count = slen; |
173 | ||
6bd4bcd3 KK |
174 | while (slen > 0) { |
175 | if (hdlc->bit_shift == 0) { | |
c38fc3bc KK |
176 | /* the code is for bitreverse streams */ |
177 | if (hdlc->do_bitreverse == 0) | |
178 | hdlc->cbin = bitrev8(*src++); | |
179 | else | |
180 | hdlc->cbin = *src++; | |
1da177e4 LT |
181 | slen--; |
182 | hdlc->bit_shift = 8; | |
6bd4bcd3 KK |
183 | if (hdlc->do_adapt56) |
184 | hdlc->bit_shift--; | |
1da177e4 LT |
185 | } |
186 | ||
6bd4bcd3 | 187 | switch (hdlc->state) { |
1da177e4 LT |
188 | case STOPPED: |
189 | return 0; | |
190 | case HDLC_FAST_IDLE: | |
6bd4bcd3 | 191 | if (hdlc->cbin == 0xff) { |
1da177e4 LT |
192 | hdlc->bit_shift = 0; |
193 | break; | |
194 | } | |
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: | |
6bd4bcd3 | 200 | if (!(hdlc->cbin & 0x80)) { |
1da177e4 LT |
201 | hdlc->state = HDLC_GETFLAG_B1A6; |
202 | hdlc->hdlc_bits1 = 0; | |
203 | } else { | |
6bd4bcd3 KK |
204 | if ((!hdlc->do_adapt56) && |
205 | (++hdlc->hdlc_bits1 >= 8) && | |
206 | (hdlc->bit_shift == 1)) | |
1da177e4 | 207 | hdlc->state = HDLC_FAST_IDLE; |
1da177e4 | 208 | } |
6bd4bcd3 KK |
209 | hdlc->cbin <<= 1; |
210 | hdlc->bit_shift--; | |
1da177e4 LT |
211 | break; |
212 | case HDLC_GETFLAG_B1A6: | |
6bd4bcd3 | 213 | if (hdlc->cbin & 0x80) { |
1da177e4 | 214 | hdlc->hdlc_bits1++; |
6bd4bcd3 | 215 | if (hdlc->hdlc_bits1 == 6) |
1da177e4 | 216 | hdlc->state = HDLC_GETFLAG_B7; |
6bd4bcd3 | 217 | } else |
1da177e4 | 218 | hdlc->hdlc_bits1 = 0; |
6bd4bcd3 KK |
219 | hdlc->cbin <<= 1; |
220 | hdlc->bit_shift--; | |
1da177e4 LT |
221 | break; |
222 | case HDLC_GETFLAG_B7: | |
6bd4bcd3 | 223 | if (hdlc->cbin & 0x80) { |
1da177e4 LT |
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; | |
232 | } | |
6bd4bcd3 KK |
233 | hdlc->cbin <<= 1; |
234 | hdlc->bit_shift--; | |
1da177e4 LT |
235 | break; |
236 | case HDLC_GET_DATA: | |
6bd4bcd3 | 237 | if (hdlc->cbin & 0x80) { |
1da177e4 | 238 | hdlc->hdlc_bits1++; |
6bd4bcd3 | 239 | switch (hdlc->hdlc_bits1) { |
1da177e4 LT |
240 | case 6: |
241 | break; | |
242 | case 7: | |
6bd4bcd3 KK |
243 | if (hdlc->data_received) |
244 | /* bad frame */ | |
1da177e4 | 245 | status = -HDLC_FRAMING_ERROR; |
6bd4bcd3 KK |
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; | |
1da177e4 LT |
252 | break; |
253 | } | |
6bd4bcd3 | 254 | } else |
1da177e4 | 255 | hdlc->state = HDLC_GET_FLAG_B0; |
1da177e4 LT |
256 | break; |
257 | default: | |
6bd4bcd3 | 258 | hdlc->shift_reg >>= 1; |
1da177e4 LT |
259 | hdlc->shift_reg |= 0x80; |
260 | hdlc->data_bits++; | |
261 | break; | |
262 | } | |
263 | } else { | |
6bd4bcd3 | 264 | switch (hdlc->hdlc_bits1) { |
1da177e4 LT |
265 | case 5: |
266 | break; | |
267 | case 6: | |
6bd4bcd3 KK |
268 | if (hdlc->data_received) |
269 | status = check_frame(hdlc); | |
1da177e4 LT |
270 | hdlc->crc = 0xffff; |
271 | hdlc->shift_reg = 0; | |
272 | hdlc->data_bits = 0; | |
6bd4bcd3 KK |
273 | if (!hdlc->do_adapt56) |
274 | handle_fast_flag(hdlc); | |
275 | else { | |
1da177e4 LT |
276 | hdlc->state = HDLC_GET_DATA; |
277 | hdlc->data_received = 0; | |
278 | } | |
279 | break; | |
280 | default: | |
6bd4bcd3 | 281 | hdlc->shift_reg >>= 1; |
1da177e4 LT |
282 | hdlc->data_bits++; |
283 | break; | |
284 | } | |
285 | hdlc->hdlc_bits1 = 0; | |
286 | } | |
287 | if (status) { | |
288 | hdlc->dstpos = 0; | |
289 | *count -= slen; | |
290 | hdlc->cbin <<= 1; | |
291 | hdlc->bit_shift--; | |
292 | return status; | |
293 | } | |
6bd4bcd3 | 294 | if (hdlc->data_bits == 8) { |
1da177e4 LT |
295 | hdlc->data_bits = 0; |
296 | hdlc->data_received = 1; | |
6bd4bcd3 KK |
297 | hdlc->crc = crc_ccitt_byte(hdlc->crc, |
298 | hdlc->shift_reg); | |
1da177e4 | 299 | |
6bd4bcd3 KK |
300 | /* good byte received */ |
301 | if (hdlc->dstpos < dsize) | |
1da177e4 | 302 | dst[hdlc->dstpos++] = hdlc->shift_reg; |
6bd4bcd3 KK |
303 | else { |
304 | /* frame too long */ | |
1da177e4 LT |
305 | status = -HDLC_LENGTH_ERROR; |
306 | hdlc->dstpos = 0; | |
307 | } | |
308 | } | |
309 | hdlc->cbin <<= 1; | |
310 | hdlc->bit_shift--; | |
311 | break; | |
312 | case HDLC_FAST_FLAG: | |
6bd4bcd3 | 313 | if (hdlc->cbin == hdlc->ffvalue) { |
1da177e4 LT |
314 | hdlc->bit_shift = 0; |
315 | break; | |
316 | } else { | |
6bd4bcd3 | 317 | if (hdlc->cbin == 0xff) { |
1da177e4 | 318 | hdlc->state = HDLC_FAST_IDLE; |
6bd4bcd3 KK |
319 | hdlc->bit_shift = 0; |
320 | } else if (hdlc->ffbit_shift == 8) { | |
1da177e4 LT |
321 | hdlc->state = HDLC_GETFLAG_B7; |
322 | break; | |
6bd4bcd3 KK |
323 | } else |
324 | handle_abort(hdlc); | |
1da177e4 LT |
325 | } |
326 | break; | |
327 | default: | |
328 | break; | |
329 | } | |
330 | } | |
331 | *count -= slen; | |
332 | return 0; | |
333 | } | |
6bd4bcd3 | 334 | EXPORT_SYMBOL(isdnhdlc_decode); |
1da177e4 LT |
335 | /* |
336 | isdnhdlc_encode - encodes HDLC frames to a transparent bit stream. | |
337 | ||
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. | |
346 | ||
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 | |
353 | */ | |
6bd4bcd3 KK |
354 | int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, |
355 | int *count, u8 *dst, int dsize) | |
1da177e4 LT |
356 | { |
357 | static const unsigned char xfast_flag_value[] = { | |
6bd4bcd3 | 358 | 0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9, 0xfc, 0x7e |
1da177e4 LT |
359 | }; |
360 | ||
361 | int len = 0; | |
362 | ||
363 | *count = slen; | |
364 | ||
f3fad223 KK |
365 | /* special handling for one byte frames */ |
366 | if ((slen == 1) && (hdlc->state == HDLC_SEND_FAST_FLAG)) | |
367 | hdlc->state = HDLC_SENDFLAG_ONE; | |
1da177e4 | 368 | while (dsize > 0) { |
6bd4bcd3 KK |
369 | if (hdlc->bit_shift == 0) { |
370 | if (slen && !hdlc->do_closing) { | |
1da177e4 LT |
371 | hdlc->shift_reg = *src++; |
372 | slen--; | |
373 | if (slen == 0) | |
6bd4bcd3 KK |
374 | /* closing sequence, CRC + flag(s) */ |
375 | hdlc->do_closing = 1; | |
1da177e4 LT |
376 | hdlc->bit_shift = 8; |
377 | } else { | |
6bd4bcd3 KK |
378 | if (hdlc->state == HDLC_SEND_DATA) { |
379 | if (hdlc->data_received) { | |
1da177e4 LT |
380 | hdlc->state = HDLC_SEND_CRC1; |
381 | hdlc->crc ^= 0xffff; | |
382 | hdlc->bit_shift = 8; | |
6bd4bcd3 KK |
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; | |
1da177e4 LT |
391 | } |
392 | ||
393 | } | |
394 | } | |
395 | ||
6bd4bcd3 | 396 | switch (hdlc->state) { |
1da177e4 LT |
397 | case STOPPED: |
398 | while (dsize--) | |
399 | *dst++ = 0xff; | |
1da177e4 LT |
400 | return dsize; |
401 | case HDLC_SEND_FAST_FLAG: | |
402 | hdlc->do_closing = 0; | |
6bd4bcd3 | 403 | if (slen == 0) { |
c38fc3bc KK |
404 | /* the code is for bitreverse streams */ |
405 | if (hdlc->do_bitreverse == 0) | |
406 | *dst++ = bitrev8(hdlc->ffvalue); | |
407 | else | |
408 | *dst++ = hdlc->ffvalue; | |
1da177e4 LT |
409 | len++; |
410 | dsize--; | |
411 | break; | |
412 | } | |
f3fad223 KK |
413 | /* fall through */ |
414 | case HDLC_SENDFLAG_ONE: | |
6bd4bcd3 KK |
415 | if (hdlc->bit_shift == 8) { |
416 | hdlc->cbin = hdlc->ffvalue >> | |
417 | (8 - hdlc->data_bits); | |
1da177e4 LT |
418 | hdlc->state = HDLC_SEND_DATA; |
419 | hdlc->crc = 0xffff; | |
420 | hdlc->hdlc_bits1 = 0; | |
421 | hdlc->data_received = 1; | |
422 | } | |
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++; | |
6bd4bcd3 | 435 | if (++hdlc->hdlc_bits1 == 6) |
1da177e4 LT |
436 | hdlc->state = HDLC_SENDFLAG_B7; |
437 | break; | |
438 | case HDLC_SENDFLAG_B7: | |
439 | hdlc->cbin <<= 1; | |
440 | hdlc->data_bits++; | |
6bd4bcd3 | 441 | if (slen == 0) { |
1da177e4 LT |
442 | hdlc->state = HDLC_SENDFLAG_B0; |
443 | break; | |
444 | } | |
6bd4bcd3 | 445 | if (hdlc->bit_shift == 8) { |
1da177e4 LT |
446 | hdlc->state = HDLC_SEND_DATA; |
447 | hdlc->crc = 0xffff; | |
448 | hdlc->hdlc_bits1 = 0; | |
449 | hdlc->data_received = 1; | |
450 | } | |
451 | break; | |
452 | case HDLC_SEND_FIRST_FLAG: | |
453 | hdlc->data_received = 1; | |
6bd4bcd3 | 454 | if (hdlc->data_bits == 8) { |
1da177e4 LT |
455 | hdlc->state = HDLC_SEND_DATA; |
456 | hdlc->crc = 0xffff; | |
457 | hdlc->hdlc_bits1 = 0; | |
458 | break; | |
459 | } | |
460 | hdlc->cbin <<= 1; | |
461 | hdlc->data_bits++; | |
6bd4bcd3 | 462 | if (hdlc->shift_reg & 0x01) |
1da177e4 LT |
463 | hdlc->cbin++; |
464 | hdlc->shift_reg >>= 1; | |
465 | hdlc->bit_shift--; | |
6bd4bcd3 | 466 | if (hdlc->bit_shift == 0) { |
1da177e4 LT |
467 | hdlc->state = HDLC_SEND_DATA; |
468 | hdlc->crc = 0xffff; | |
469 | hdlc->hdlc_bits1 = 0; | |
470 | } | |
471 | break; | |
472 | case HDLC_SEND_DATA: | |
473 | hdlc->cbin <<= 1; | |
474 | hdlc->data_bits++; | |
6bd4bcd3 | 475 | if (hdlc->hdlc_bits1 == 5) { |
1da177e4 LT |
476 | hdlc->hdlc_bits1 = 0; |
477 | break; | |
478 | } | |
6bd4bcd3 KK |
479 | if (hdlc->bit_shift == 8) |
480 | hdlc->crc = crc_ccitt_byte(hdlc->crc, | |
481 | hdlc->shift_reg); | |
482 | if (hdlc->shift_reg & 0x01) { | |
1da177e4 LT |
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--; | |
491 | } | |
492 | break; | |
493 | case HDLC_SEND_CRC1: | |
494 | hdlc->cbin <<= 1; | |
495 | hdlc->data_bits++; | |
6bd4bcd3 | 496 | if (hdlc->hdlc_bits1 == 5) { |
1da177e4 LT |
497 | hdlc->hdlc_bits1 = 0; |
498 | break; | |
499 | } | |
6bd4bcd3 | 500 | if (hdlc->shift_reg & 0x01) { |
1da177e4 LT |
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--; | |
509 | } | |
6bd4bcd3 | 510 | if (hdlc->bit_shift == 0) { |
1da177e4 LT |
511 | hdlc->shift_reg = (hdlc->crc >> 8); |
512 | hdlc->state = HDLC_SEND_CRC2; | |
513 | hdlc->bit_shift = 8; | |
514 | } | |
515 | break; | |
516 | case HDLC_SEND_CRC2: | |
517 | hdlc->cbin <<= 1; | |
518 | hdlc->data_bits++; | |
6bd4bcd3 | 519 | if (hdlc->hdlc_bits1 == 5) { |
1da177e4 LT |
520 | hdlc->hdlc_bits1 = 0; |
521 | break; | |
522 | } | |
6bd4bcd3 | 523 | if (hdlc->shift_reg & 0x01) { |
1da177e4 LT |
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--; | |
532 | } | |
6bd4bcd3 | 533 | if (hdlc->bit_shift == 0) { |
1da177e4 LT |
534 | hdlc->shift_reg = 0x7e; |
535 | hdlc->state = HDLC_SEND_CLOSING_FLAG; | |
536 | hdlc->bit_shift = 8; | |
537 | } | |
538 | break; | |
539 | case HDLC_SEND_CLOSING_FLAG: | |
540 | hdlc->cbin <<= 1; | |
541 | hdlc->data_bits++; | |
6bd4bcd3 | 542 | if (hdlc->hdlc_bits1 == 5) { |
1da177e4 LT |
543 | hdlc->hdlc_bits1 = 0; |
544 | break; | |
545 | } | |
6bd4bcd3 | 546 | if (hdlc->shift_reg & 0x01) |
1da177e4 | 547 | hdlc->cbin++; |
1da177e4 LT |
548 | hdlc->shift_reg >>= 1; |
549 | hdlc->bit_shift--; | |
6bd4bcd3 KK |
550 | if (hdlc->bit_shift == 0) { |
551 | hdlc->ffvalue = | |
552 | xfast_flag_value[hdlc->data_bits]; | |
553 | if (hdlc->dchannel) { | |
1da177e4 LT |
554 | hdlc->ffvalue = 0x7e; |
555 | hdlc->state = HDLC_SEND_IDLE1; | |
556 | hdlc->bit_shift = 8-hdlc->data_bits; | |
6bd4bcd3 KK |
557 | if (hdlc->bit_shift == 0) |
558 | hdlc->state = | |
559 | HDLC_SEND_FAST_IDLE; | |
1da177e4 | 560 | } else { |
6bd4bcd3 KK |
561 | if (!hdlc->do_adapt56) { |
562 | hdlc->state = | |
563 | HDLC_SEND_FAST_FLAG; | |
1da177e4 LT |
564 | hdlc->data_received = 0; |
565 | } else { | |
566 | hdlc->state = HDLC_SENDFLAG_B0; | |
567 | hdlc->data_received = 0; | |
568 | } | |
6bd4bcd3 KK |
569 | /* Finished this frame, send flags */ |
570 | if (dsize > 1) | |
571 | dsize = 1; | |
1da177e4 LT |
572 | } |
573 | } | |
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--; | |
6bd4bcd3 | 581 | if (hdlc->bit_shift == 0) { |
1da177e4 LT |
582 | hdlc->state = HDLC_SEND_FAST_IDLE; |
583 | hdlc->bit_shift = 0; | |
584 | } | |
585 | break; | |
586 | case HDLC_SEND_FAST_IDLE: | |
587 | hdlc->do_closing = 0; | |
588 | hdlc->cbin = 0xff; | |
589 | hdlc->data_bits = 8; | |
6bd4bcd3 | 590 | if (hdlc->bit_shift == 8) { |
1da177e4 LT |
591 | hdlc->cbin = 0x7e; |
592 | hdlc->state = HDLC_SEND_FIRST_FLAG; | |
593 | } else { | |
c38fc3bc KK |
594 | /* the code is for bitreverse streams */ |
595 | if (hdlc->do_bitreverse == 0) | |
596 | *dst++ = bitrev8(hdlc->cbin); | |
597 | else | |
598 | *dst++ = hdlc->cbin; | |
6bd4bcd3 KK |
599 | hdlc->bit_shift = 0; |
600 | hdlc->data_bits = 0; | |
1da177e4 LT |
601 | len++; |
602 | dsize = 0; | |
603 | } | |
604 | break; | |
605 | default: | |
606 | break; | |
607 | } | |
6bd4bcd3 KK |
608 | if (hdlc->do_adapt56) { |
609 | if (hdlc->data_bits == 7) { | |
1da177e4 LT |
610 | hdlc->cbin <<= 1; |
611 | hdlc->cbin++; | |
612 | hdlc->data_bits++; | |
613 | } | |
614 | } | |
6bd4bcd3 | 615 | if (hdlc->data_bits == 8) { |
c38fc3bc KK |
616 | /* the code is for bitreverse streams */ |
617 | if (hdlc->do_bitreverse == 0) | |
618 | *dst++ = bitrev8(hdlc->cbin); | |
619 | else | |
620 | *dst++ = hdlc->cbin; | |
1da177e4 LT |
621 | hdlc->data_bits = 0; |
622 | len++; | |
623 | dsize--; | |
624 | } | |
625 | } | |
626 | *count -= slen; | |
627 | ||
628 | return len; | |
629 | } | |
1da177e4 | 630 | EXPORT_SYMBOL(isdnhdlc_encode); |