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