| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * isdnhdlc.c  --  General purpose ISDN HDLC decoder. | 
 | 3 |  * | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 4 |  * Copyright (C) | 
| Karsten Keil | c38fc3b | 2009-07-08 20:31:42 +0200 | [diff] [blame] | 5 |  *	2009	Karsten Keil		<keil@b1-systems.de> | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 6 |  *	2002	Wolfgang Mües		<wolfgang@iksw-muees.de> | 
 | 7 |  *	2001	Frode Isaksen		<fisaksen@bewan.com> | 
 | 8 |  *      2001	Kai Germaschewski	<kai.germaschewski@gmx.de> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 9 |  * | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 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. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 14 |  * | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 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. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 19 |  * | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 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. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 23 |  */ | 
 | 24 |  | 
 | 25 | #include <linux/module.h> | 
 | 26 | #include <linux/init.h> | 
 | 27 | #include <linux/crc-ccitt.h> | 
| Karsten Keil | cb3824b | 2009-07-08 14:21:12 +0200 | [diff] [blame] | 28 | #include <linux/isdn/hdlc.h> | 
| Karsten Keil | c38fc3b | 2009-07-08 20:31:42 +0200 | [diff] [blame] | 29 | #include <linux/bitrev.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 30 |  | 
 | 31 | /*-------------------------------------------------------------------*/ | 
 | 32 |  | 
| Jan Engelhardt | 96de0e2 | 2007-10-19 23:21:04 +0200 | [diff] [blame] | 33 | MODULE_AUTHOR("Wolfgang Mües <wolfgang@iksw-muees.de>, " | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 41 | enum { | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 42 | 	HDLC_FAST_IDLE, HDLC_GET_FLAG_B0, HDLC_GETFLAG_B1A6, HDLC_GETFLAG_B7, | 
 | 43 | 	HDLC_GET_DATA, HDLC_FAST_FLAG | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 44 | }; | 
 | 45 |  | 
 | 46 | enum { | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 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, | 
| Karsten Keil | f3fad22 | 2009-07-08 20:58:33 +0200 | [diff] [blame] | 50 | 	HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED, HDLC_SENDFLAG_ONE | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 51 | }; | 
 | 52 |  | 
| Karsten Keil | c38fc3b | 2009-07-08 20:31:42 +0200 | [diff] [blame] | 53 | void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 54 | { | 
| Karsten Keil | c38fc3b | 2009-07-08 20:31:42 +0200 | [diff] [blame] | 55 | 	memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 56 | 	hdlc->state = HDLC_GET_DATA; | 
| Karsten Keil | c38fc3b | 2009-07-08 20:31:42 +0200 | [diff] [blame] | 57 | 	if (features & HDLC_56KBIT) | 
 | 58 | 		hdlc->do_adapt56 = 1; | 
 | 59 | 	if (features & HDLC_BITREVERSE) | 
 | 60 | 		hdlc->do_bitreverse = 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 61 | } | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 62 | EXPORT_SYMBOL(isdnhdlc_out_init); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 63 |  | 
| Karsten Keil | c38fc3b | 2009-07-08 20:31:42 +0200 | [diff] [blame] | 64 | void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 65 | { | 
| Karsten Keil | c38fc3b | 2009-07-08 20:31:42 +0200 | [diff] [blame] | 66 | 	memset(hdlc, 0, sizeof(struct isdnhdlc_vars)); | 
 | 67 | 	if (features & HDLC_DCHANNEL) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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; | 
| Karsten Keil | c38fc3b | 2009-07-08 20:31:42 +0200 | [diff] [blame] | 76 | 	if (features & HDLC_56KBIT) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 77 | 		hdlc->do_adapt56 = 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 78 | 		hdlc->state = HDLC_SENDFLAG_B0; | 
| Karsten Keil | c38fc3b | 2009-07-08 20:31:42 +0200 | [diff] [blame] | 79 | 	} else | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 80 | 		hdlc->data_bits = 8; | 
| Karsten Keil | c38fc3b | 2009-07-08 20:31:42 +0200 | [diff] [blame] | 81 | 	if (features & HDLC_BITREVERSE) | 
 | 82 | 		hdlc->do_bitreverse = 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 83 | } | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 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 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |  */ | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 131 | int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen, | 
 | 132 | 	int *count, u8 *dst, int dsize) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 133 | { | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 134 | 	int status = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 135 |  | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 136 | 	static const unsigned char fast_flag[] = { | 
 | 137 | 		0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 138 | 	}; | 
 | 139 |  | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 140 | 	static const unsigned char fast_flag_value[] = { | 
 | 141 | 		0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 142 | 	}; | 
 | 143 |  | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 144 | 	static const unsigned char fast_abort[] = { | 
 | 145 | 		0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 146 | 	}; | 
 | 147 |  | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 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 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 172 | 	*count = slen; | 
 | 173 |  | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 174 | 	while (slen > 0) { | 
 | 175 | 		if (hdlc->bit_shift == 0) { | 
| Karsten Keil | c38fc3b | 2009-07-08 20:31:42 +0200 | [diff] [blame] | 176 | 			/* the code is for bitreverse streams */ | 
 | 177 | 			if (hdlc->do_bitreverse == 0) | 
 | 178 | 				hdlc->cbin = bitrev8(*src++); | 
 | 179 | 			else | 
 | 180 | 				hdlc->cbin = *src++; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 181 | 			slen--; | 
 | 182 | 			hdlc->bit_shift = 8; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 183 | 			if (hdlc->do_adapt56) | 
 | 184 | 				hdlc->bit_shift--; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 185 | 		} | 
 | 186 |  | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 187 | 		switch (hdlc->state) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 188 | 		case STOPPED: | 
 | 189 | 			return 0; | 
 | 190 | 		case HDLC_FAST_IDLE: | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 191 | 			if (hdlc->cbin == 0xff) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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: | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 200 | 			if (!(hdlc->cbin & 0x80)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 201 | 				hdlc->state = HDLC_GETFLAG_B1A6; | 
 | 202 | 				hdlc->hdlc_bits1 = 0; | 
 | 203 | 			} else { | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 204 | 				if ((!hdlc->do_adapt56) && | 
 | 205 | 				    (++hdlc->hdlc_bits1 >= 8) && | 
 | 206 | 				    (hdlc->bit_shift == 1)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 207 | 						hdlc->state = HDLC_FAST_IDLE; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 208 | 			} | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 209 | 			hdlc->cbin <<= 1; | 
 | 210 | 			hdlc->bit_shift--; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 211 | 			break; | 
 | 212 | 		case HDLC_GETFLAG_B1A6: | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 213 | 			if (hdlc->cbin & 0x80) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 214 | 				hdlc->hdlc_bits1++; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 215 | 				if (hdlc->hdlc_bits1 == 6) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 216 | 					hdlc->state = HDLC_GETFLAG_B7; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 217 | 			} else | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 218 | 				hdlc->hdlc_bits1 = 0; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 219 | 			hdlc->cbin <<= 1; | 
 | 220 | 			hdlc->bit_shift--; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 221 | 			break; | 
 | 222 | 		case HDLC_GETFLAG_B7: | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 223 | 			if (hdlc->cbin & 0x80) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | 			} | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 233 | 			hdlc->cbin <<= 1; | 
 | 234 | 			hdlc->bit_shift--; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 235 | 			break; | 
 | 236 | 		case HDLC_GET_DATA: | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 237 | 			if (hdlc->cbin & 0x80) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 238 | 				hdlc->hdlc_bits1++; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 239 | 				switch (hdlc->hdlc_bits1) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 240 | 				case 6: | 
 | 241 | 					break; | 
 | 242 | 				case 7: | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 243 | 					if (hdlc->data_received) | 
 | 244 | 						/* bad frame */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 245 | 						status = -HDLC_FRAMING_ERROR; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 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; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 252 | 							break; | 
 | 253 | 						} | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 254 | 					} else | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 255 | 						hdlc->state = HDLC_GET_FLAG_B0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 256 | 					break; | 
 | 257 | 				default: | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 258 | 					hdlc->shift_reg >>= 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 259 | 					hdlc->shift_reg |= 0x80; | 
 | 260 | 					hdlc->data_bits++; | 
 | 261 | 					break; | 
 | 262 | 				} | 
 | 263 | 			} else { | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 264 | 				switch (hdlc->hdlc_bits1) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 265 | 				case 5: | 
 | 266 | 					break; | 
 | 267 | 				case 6: | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 268 | 					if (hdlc->data_received) | 
 | 269 | 						status = check_frame(hdlc); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 270 | 					hdlc->crc = 0xffff; | 
 | 271 | 					hdlc->shift_reg = 0; | 
 | 272 | 					hdlc->data_bits = 0; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 273 | 					if (!hdlc->do_adapt56) | 
 | 274 | 						handle_fast_flag(hdlc); | 
 | 275 | 					else { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 276 | 						hdlc->state = HDLC_GET_DATA; | 
 | 277 | 						hdlc->data_received = 0; | 
 | 278 | 					} | 
 | 279 | 					break; | 
 | 280 | 				default: | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 281 | 					hdlc->shift_reg >>= 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | 			} | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 294 | 			if (hdlc->data_bits == 8) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 295 | 				hdlc->data_bits = 0; | 
 | 296 | 				hdlc->data_received = 1; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 297 | 				hdlc->crc = crc_ccitt_byte(hdlc->crc, | 
 | 298 | 						hdlc->shift_reg); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 299 |  | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 300 | 				/* good byte received */ | 
 | 301 | 				if (hdlc->dstpos < dsize) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 302 | 					dst[hdlc->dstpos++] = hdlc->shift_reg; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 303 | 				else { | 
 | 304 | 					/* frame too long */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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: | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 313 | 			if (hdlc->cbin == hdlc->ffvalue) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 314 | 				hdlc->bit_shift = 0; | 
 | 315 | 				break; | 
 | 316 | 			} else { | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 317 | 				if (hdlc->cbin == 0xff) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 318 | 					hdlc->state = HDLC_FAST_IDLE; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 319 | 					hdlc->bit_shift = 0; | 
 | 320 | 				} else if (hdlc->ffbit_shift == 8) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 321 | 					hdlc->state = HDLC_GETFLAG_B7; | 
 | 322 | 					break; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 323 | 				} else | 
 | 324 | 					handle_abort(hdlc); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 325 | 			} | 
 | 326 | 			break; | 
 | 327 | 		default: | 
 | 328 | 			break; | 
 | 329 | 		} | 
 | 330 | 	} | 
 | 331 | 	*count -= slen; | 
 | 332 | 	return 0; | 
 | 333 | } | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 334 | EXPORT_SYMBOL(isdnhdlc_decode); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | */ | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 354 | int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen, | 
 | 355 | 	int *count, u8 *dst, int dsize) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 356 | { | 
 | 357 | 	static const unsigned char xfast_flag_value[] = { | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 358 | 		0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9, 0xfc, 0x7e | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 359 | 	}; | 
 | 360 |  | 
 | 361 | 	int len = 0; | 
 | 362 |  | 
 | 363 | 	*count = slen; | 
 | 364 |  | 
| Karsten Keil | f3fad22 | 2009-07-08 20:58:33 +0200 | [diff] [blame] | 365 | 	/* special handling for one byte frames */ | 
 | 366 | 	if ((slen == 1) && (hdlc->state == HDLC_SEND_FAST_FLAG)) | 
 | 367 | 		hdlc->state = HDLC_SENDFLAG_ONE; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 368 | 	while (dsize > 0) { | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 369 | 		if (hdlc->bit_shift == 0) { | 
 | 370 | 			if (slen && !hdlc->do_closing) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 371 | 				hdlc->shift_reg = *src++; | 
 | 372 | 				slen--; | 
 | 373 | 				if (slen == 0) | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 374 | 					/* closing sequence, CRC + flag(s) */ | 
 | 375 | 					hdlc->do_closing = 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 376 | 				hdlc->bit_shift = 8; | 
 | 377 | 			} else { | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 378 | 				if (hdlc->state == HDLC_SEND_DATA) { | 
 | 379 | 					if (hdlc->data_received) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 380 | 						hdlc->state = HDLC_SEND_CRC1; | 
 | 381 | 						hdlc->crc ^= 0xffff; | 
 | 382 | 						hdlc->bit_shift = 8; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 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; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 391 | 				} | 
 | 392 |  | 
 | 393 | 			} | 
 | 394 | 		} | 
 | 395 |  | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 396 | 		switch (hdlc->state) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 397 | 		case STOPPED: | 
 | 398 | 			while (dsize--) | 
 | 399 | 				*dst++ = 0xff; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 400 | 			return dsize; | 
 | 401 | 		case HDLC_SEND_FAST_FLAG: | 
 | 402 | 			hdlc->do_closing = 0; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 403 | 			if (slen == 0) { | 
| Karsten Keil | c38fc3b | 2009-07-08 20:31:42 +0200 | [diff] [blame] | 404 | 				/* the code is for bitreverse streams */ | 
 | 405 | 				if (hdlc->do_bitreverse == 0) | 
 | 406 | 					*dst++ = bitrev8(hdlc->ffvalue); | 
 | 407 | 				else | 
 | 408 | 					*dst++ = hdlc->ffvalue; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 409 | 				len++; | 
 | 410 | 				dsize--; | 
 | 411 | 				break; | 
 | 412 | 			} | 
| Karsten Keil | f3fad22 | 2009-07-08 20:58:33 +0200 | [diff] [blame] | 413 | 			/* fall through */ | 
 | 414 | 		case HDLC_SENDFLAG_ONE: | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 415 | 			if (hdlc->bit_shift == 8) { | 
 | 416 | 				hdlc->cbin = hdlc->ffvalue >> | 
 | 417 | 					(8 - hdlc->data_bits); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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++; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 435 | 			if (++hdlc->hdlc_bits1 == 6) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 436 | 				hdlc->state = HDLC_SENDFLAG_B7; | 
 | 437 | 			break; | 
 | 438 | 		case HDLC_SENDFLAG_B7: | 
 | 439 | 			hdlc->cbin <<= 1; | 
 | 440 | 			hdlc->data_bits++; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 441 | 			if (slen == 0) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 442 | 				hdlc->state = HDLC_SENDFLAG_B0; | 
 | 443 | 				break; | 
 | 444 | 			} | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 445 | 			if (hdlc->bit_shift == 8) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 454 | 			if (hdlc->data_bits == 8) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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++; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 462 | 			if (hdlc->shift_reg & 0x01) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 463 | 				hdlc->cbin++; | 
 | 464 | 			hdlc->shift_reg >>= 1; | 
 | 465 | 			hdlc->bit_shift--; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 466 | 			if (hdlc->bit_shift == 0) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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++; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 475 | 			if (hdlc->hdlc_bits1 == 5) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 476 | 				hdlc->hdlc_bits1 = 0; | 
 | 477 | 				break; | 
 | 478 | 			} | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 479 | 			if (hdlc->bit_shift == 8) | 
 | 480 | 				hdlc->crc = crc_ccitt_byte(hdlc->crc, | 
 | 481 | 					hdlc->shift_reg); | 
 | 482 | 			if (hdlc->shift_reg & 0x01) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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++; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 496 | 			if (hdlc->hdlc_bits1 == 5) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 497 | 				hdlc->hdlc_bits1 = 0; | 
 | 498 | 				break; | 
 | 499 | 			} | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 500 | 			if (hdlc->shift_reg & 0x01) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | 			} | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 510 | 			if (hdlc->bit_shift == 0) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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++; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 519 | 			if (hdlc->hdlc_bits1 == 5) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 520 | 				hdlc->hdlc_bits1 = 0; | 
 | 521 | 				break; | 
 | 522 | 			} | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 523 | 			if (hdlc->shift_reg & 0x01) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | 			} | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 533 | 			if (hdlc->bit_shift == 0) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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++; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 542 | 			if (hdlc->hdlc_bits1 == 5) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 543 | 				hdlc->hdlc_bits1 = 0; | 
 | 544 | 				break; | 
 | 545 | 			} | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 546 | 			if (hdlc->shift_reg & 0x01) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 547 | 				hdlc->cbin++; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 548 | 			hdlc->shift_reg >>= 1; | 
 | 549 | 			hdlc->bit_shift--; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 550 | 			if (hdlc->bit_shift == 0) { | 
 | 551 | 				hdlc->ffvalue = | 
 | 552 | 					xfast_flag_value[hdlc->data_bits]; | 
 | 553 | 				if (hdlc->dchannel) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 554 | 					hdlc->ffvalue = 0x7e; | 
 | 555 | 					hdlc->state = HDLC_SEND_IDLE1; | 
 | 556 | 					hdlc->bit_shift = 8-hdlc->data_bits; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 557 | 					if (hdlc->bit_shift == 0) | 
 | 558 | 						hdlc->state = | 
 | 559 | 							HDLC_SEND_FAST_IDLE; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 560 | 				} else { | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 561 | 					if (!hdlc->do_adapt56) { | 
 | 562 | 						hdlc->state = | 
 | 563 | 							HDLC_SEND_FAST_FLAG; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 564 | 						hdlc->data_received = 0; | 
 | 565 | 					} else { | 
 | 566 | 						hdlc->state = HDLC_SENDFLAG_B0; | 
 | 567 | 						hdlc->data_received = 0; | 
 | 568 | 					} | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 569 | 					/* Finished this frame, send flags */ | 
 | 570 | 					if (dsize > 1) | 
 | 571 | 						dsize = 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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--; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 581 | 			if (hdlc->bit_shift == 0) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 590 | 			if (hdlc->bit_shift == 8) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 591 | 				hdlc->cbin = 0x7e; | 
 | 592 | 				hdlc->state = HDLC_SEND_FIRST_FLAG; | 
 | 593 | 			} else { | 
| Karsten Keil | c38fc3b | 2009-07-08 20:31:42 +0200 | [diff] [blame] | 594 | 				/* the code is for bitreverse streams */ | 
 | 595 | 				if (hdlc->do_bitreverse == 0) | 
 | 596 | 					*dst++ = bitrev8(hdlc->cbin); | 
 | 597 | 				else | 
 | 598 | 					*dst++ = hdlc->cbin; | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 599 | 				hdlc->bit_shift = 0; | 
 | 600 | 				hdlc->data_bits = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 601 | 				len++; | 
 | 602 | 				dsize = 0; | 
 | 603 | 			} | 
 | 604 | 			break; | 
 | 605 | 		default: | 
 | 606 | 			break; | 
 | 607 | 		} | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 608 | 		if (hdlc->do_adapt56) { | 
 | 609 | 			if (hdlc->data_bits == 7) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 610 | 				hdlc->cbin <<= 1; | 
 | 611 | 				hdlc->cbin++; | 
 | 612 | 				hdlc->data_bits++; | 
 | 613 | 			} | 
 | 614 | 		} | 
| Karsten Keil | 6bd4bcd | 2009-07-08 19:11:09 +0200 | [diff] [blame] | 615 | 		if (hdlc->data_bits == 8) { | 
| Karsten Keil | c38fc3b | 2009-07-08 20:31:42 +0200 | [diff] [blame] | 616 | 			/* the code is for bitreverse streams */ | 
 | 617 | 			if (hdlc->do_bitreverse == 0) | 
 | 618 | 				*dst++ = bitrev8(hdlc->cbin); | 
 | 619 | 			else | 
 | 620 | 				*dst++ = hdlc->cbin; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 621 | 			hdlc->data_bits = 0; | 
 | 622 | 			len++; | 
 | 623 | 			dsize--; | 
 | 624 | 		} | 
 | 625 | 	} | 
 | 626 | 	*count -= slen; | 
 | 627 |  | 
 | 628 | 	return len; | 
 | 629 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 630 | EXPORT_SYMBOL(isdnhdlc_encode); |