blob: db3a1e4cd4893e62af25041d478318035c2bad96 [file] [log] [blame]
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -08001/*
2 * Common data handling layer for bas_gigaset
3 *
4 * Copyright (c) 2005 by Tilman Schmidt <tilman@imap.cc>,
5 * Hansjoerg Lipp <hjlipp@web.de>.
6 *
7 * =====================================================================
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 * =====================================================================
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -080013 */
14
15#include "gigaset.h"
16#include <linux/crc-ccitt.h>
Akinobu Mita17b3cff2006-12-08 02:36:30 -080017#include <linux/bitrev.h>
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -080018
19/* access methods for isowbuf_t */
20/* ============================ */
21
22/* initialize buffer structure
23 */
24void gigaset_isowbuf_init(struct isowbuf_t *iwb, unsigned char idle)
25{
Tilman Schmidt9d4bee22008-02-06 01:38:28 -080026 iwb->read = 0;
27 iwb->nextread = 0;
28 iwb->write = 0;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -080029 atomic_set(&iwb->writesem, 1);
30 iwb->wbits = 0;
31 iwb->idle = idle;
32 memset(iwb->data + BAS_OUTBUFSIZE, idle, BAS_OUTBUFPAD);
33}
34
35/* compute number of bytes which can be appended to buffer
36 * so that there is still room to append a maximum frame of flags
37 */
38static inline int isowbuf_freebytes(struct isowbuf_t *iwb)
39{
40 int read, write, freebytes;
41
Tilman Schmidt9d4bee22008-02-06 01:38:28 -080042 read = iwb->read;
43 write = iwb->write;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -080044 if ((freebytes = read - write) > 0) {
45 /* no wraparound: need padding space within regular area */
46 return freebytes - BAS_OUTBUFPAD;
47 } else if (read < BAS_OUTBUFPAD) {
48 /* wraparound: can use space up to end of regular area */
49 return BAS_OUTBUFSIZE - write;
50 } else {
51 /* following the wraparound yields more space */
52 return freebytes + BAS_OUTBUFSIZE - BAS_OUTBUFPAD;
53 }
54}
55
56/* compare two offsets within the buffer
57 * The buffer is seen as circular, with the read position as start
58 * returns -1/0/1 if position a </=/> position b without crossing 'read'
59 */
60static inline int isowbuf_poscmp(struct isowbuf_t *iwb, int a, int b)
61{
62 int read;
63 if (a == b)
64 return 0;
Tilman Schmidt9d4bee22008-02-06 01:38:28 -080065 read = iwb->read;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -080066 if (a < b) {
67 if (a < read && read <= b)
68 return +1;
69 else
70 return -1;
71 } else {
72 if (b < read && read <= a)
73 return -1;
74 else
75 return +1;
76 }
77}
78
79/* start writing
80 * acquire the write semaphore
81 * return true if acquired, false if busy
82 */
83static inline int isowbuf_startwrite(struct isowbuf_t *iwb)
84{
85 if (!atomic_dec_and_test(&iwb->writesem)) {
86 atomic_inc(&iwb->writesem);
Tilman Schmidt784d5852006-04-10 22:55:04 -070087 gig_dbg(DEBUG_ISO, "%s: couldn't acquire iso write semaphore",
88 __func__);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -080089 return 0;
90 }
Tilman Schmidt784d5852006-04-10 22:55:04 -070091 gig_dbg(DEBUG_ISO,
92 "%s: acquired iso write semaphore, data[write]=%02x, nbits=%d",
Tilman Schmidt9d4bee22008-02-06 01:38:28 -080093 __func__, iwb->data[iwb->write], iwb->wbits);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -080094 return 1;
95}
96
97/* finish writing
Tilman Schmidt9d4bee22008-02-06 01:38:28 -080098 * release the write semaphore
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -080099 * returns the current write position
100 */
101static inline int isowbuf_donewrite(struct isowbuf_t *iwb)
102{
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800103 int write = iwb->write;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800104 atomic_inc(&iwb->writesem);
105 return write;
106}
107
108/* append bits to buffer without any checks
109 * - data contains bits to append, starting at LSB
110 * - nbits is number of bits to append (0..24)
111 * must be called with the write semaphore held
112 * If more than nbits bits are set in data, the extraneous bits are set in the
113 * buffer too, but the write position is only advanced by nbits.
114 */
115static inline void isowbuf_putbits(struct isowbuf_t *iwb, u32 data, int nbits)
116{
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800117 int write = iwb->write;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800118 data <<= iwb->wbits;
119 data |= iwb->data[write];
120 nbits += iwb->wbits;
121 while (nbits >= 8) {
122 iwb->data[write++] = data & 0xff;
123 write %= BAS_OUTBUFSIZE;
124 data >>= 8;
125 nbits -= 8;
126 }
127 iwb->wbits = nbits;
128 iwb->data[write] = data & 0xff;
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800129 iwb->write = write;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800130}
131
132/* put final flag on HDLC bitstream
133 * also sets the idle fill byte to the correspondingly shifted flag pattern
134 * must be called with the write semaphore held
135 */
136static inline void isowbuf_putflag(struct isowbuf_t *iwb)
137{
138 int write;
139
140 /* add two flags, thus reliably covering one byte */
141 isowbuf_putbits(iwb, 0x7e7e, 8);
142 /* recover the idle flag byte */
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800143 write = iwb->write;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800144 iwb->idle = iwb->data[write];
Tilman Schmidt784d5852006-04-10 22:55:04 -0700145 gig_dbg(DEBUG_ISO, "idle fill byte %02x", iwb->idle);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800146 /* mask extraneous bits in buffer */
147 iwb->data[write] &= (1 << iwb->wbits) - 1;
148}
149
150/* retrieve a block of bytes for sending
151 * The requested number of bytes is provided as a contiguous block.
152 * If necessary, the frame is filled to the requested number of bytes
153 * with the idle value.
154 * returns offset to frame, < 0 on busy or error
155 */
156int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
157{
158 int read, write, limit, src, dst;
159 unsigned char pbyte;
160
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800161 read = iwb->nextread;
162 write = iwb->write;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800163 if (likely(read == write)) {
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800164 /* return idle frame */
165 return read < BAS_OUTBUFPAD ?
Tilman Schmidt784d5852006-04-10 22:55:04 -0700166 BAS_OUTBUFSIZE : read - BAS_OUTBUFPAD;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800167 }
168
169 limit = read + size;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700170 gig_dbg(DEBUG_STREAM, "%s: read=%d write=%d limit=%d",
171 __func__, read, write, limit);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800172#ifdef CONFIG_GIGASET_DEBUG
173 if (unlikely(size < 0 || size > BAS_OUTBUFPAD)) {
Tilman Schmidtc8770dc2008-12-26 01:21:29 -0800174 pr_err("invalid size %d\n", size);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800175 return -EINVAL;
176 }
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800177 src = iwb->read;
Roel Kluinc40499e2009-05-21 15:04:15 -0700178 if (unlikely(limit >= BAS_OUTBUFSIZE + BAS_OUTBUFPAD ||
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800179 (read < src && limit >= src))) {
Tilman Schmidtc8770dc2008-12-26 01:21:29 -0800180 pr_err("isoc write buffer frame reservation violated\n");
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800181 return -EFAULT;
182 }
183#endif
184
185 if (read < write) {
186 /* no wraparound in valid data */
187 if (limit >= write) {
188 /* append idle frame */
189 if (!isowbuf_startwrite(iwb))
190 return -EBUSY;
191 /* write position could have changed */
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800192 write = iwb->write;
193 if (limit >= write) {
Tilman Schmidt917f5082006-04-10 22:55:00 -0700194 pbyte = iwb->data[write]; /* save
195 partial byte */
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800196 limit = write + BAS_OUTBUFPAD;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700197 gig_dbg(DEBUG_STREAM,
198 "%s: filling %d->%d with %02x",
199 __func__, write, limit, iwb->idle);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800200 if (write + BAS_OUTBUFPAD < BAS_OUTBUFSIZE)
201 memset(iwb->data + write, iwb->idle,
202 BAS_OUTBUFPAD);
203 else {
204 /* wraparound, fill entire pad area */
205 memset(iwb->data + write, iwb->idle,
206 BAS_OUTBUFSIZE + BAS_OUTBUFPAD
207 - write);
208 limit = 0;
209 }
Tilman Schmidt784d5852006-04-10 22:55:04 -0700210 gig_dbg(DEBUG_STREAM,
211 "%s: restoring %02x at %d",
212 __func__, pbyte, limit);
Tilman Schmidt917f5082006-04-10 22:55:00 -0700213 iwb->data[limit] = pbyte; /* restore
214 partial byte */
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800215 iwb->write = limit;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800216 }
217 isowbuf_donewrite(iwb);
218 }
219 } else {
220 /* valid data wraparound */
221 if (limit >= BAS_OUTBUFSIZE) {
222 /* copy wrapped part into pad area */
223 src = 0;
224 dst = BAS_OUTBUFSIZE;
225 while (dst < limit && src < write)
226 iwb->data[dst++] = iwb->data[src++];
227 if (dst <= limit) {
228 /* fill pad area with idle byte */
229 memset(iwb->data + dst, iwb->idle,
230 BAS_OUTBUFSIZE + BAS_OUTBUFPAD - dst);
231 }
232 limit = src;
233 }
234 }
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800235 iwb->nextread = limit;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800236 return read;
237}
238
239/* dump_bytes
240 * write hex bytes to syslog for debugging
241 */
242static inline void dump_bytes(enum debuglevel level, const char *tag,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700243 unsigned char *bytes, int count)
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800244{
245#ifdef CONFIG_GIGASET_DEBUG
246 unsigned char c;
247 static char dbgline[3 * 32 + 1];
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800248 int i = 0;
Tilman Schmidt1315d692009-05-13 12:44:17 +0000249
250 if (!(gigaset_debuglevel & level))
251 return;
252
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800253 while (count-- > 0) {
254 if (i > sizeof(dbgline) - 4) {
255 dbgline[i] = '\0';
Tilman Schmidt784d5852006-04-10 22:55:04 -0700256 gig_dbg(level, "%s:%s", tag, dbgline);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800257 i = 0;
258 }
259 c = *bytes++;
260 dbgline[i] = (i && !(i % 12)) ? '-' : ' ';
261 i++;
Harvey Harrison02137f22008-07-30 16:40:22 -0700262 dbgline[i++] = hex_asc_hi(c);
263 dbgline[i++] = hex_asc_lo(c);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800264 }
265 dbgline[i] = '\0';
Tilman Schmidt784d5852006-04-10 22:55:04 -0700266 gig_dbg(level, "%s:%s", tag, dbgline);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800267#endif
268}
269
270/*============================================================================*/
271
272/* bytewise HDLC bitstuffing via table lookup
273 * lookup table: 5 subtables for 0..4 preceding consecutive '1' bits
274 * index: 256*(number of preceding '1' bits) + (next byte to stuff)
275 * value: bit 9.. 0 = result bits
276 * bit 12..10 = number of trailing '1' bits in result
277 * bit 14..13 = number of bits added by stuffing
278 */
Tilman Schmidt35dc8452007-03-29 01:20:34 -0700279static const u16 stufftab[5 * 256] = {
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800280// previous 1s = 0:
281 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
282 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x201f,
283 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
284 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x205f,
285 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
286 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x209f,
287 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
288 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20df,
289 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x048f,
290 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x251f,
291 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x04af,
292 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x255f,
293 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x08c7, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x08cf,
294 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x08d7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x299f,
295 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x0ce7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x0cef,
296 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x10f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x2ddf,
297
298// previous 1s = 1:
299 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x200f,
300 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x202f,
301 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x204f,
302 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x206f,
303 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x208f,
304 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x20af,
305 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x20cf,
306 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20ef,
307 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x250f,
308 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x252f,
309 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x254f,
310 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x256f,
311 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x08c7, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x298f,
312 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x08d7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x29af,
313 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x0ce7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x2dcf,
314 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x10f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x31ef,
315
316// previous 1s = 2:
317 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x2007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x2017,
318 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x2027, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x2037,
319 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x2047, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x2057,
320 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x2067, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x2077,
321 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x2087, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x2097,
322 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x20a7, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x20b7,
323 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x20c7, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x20d7,
324 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x20e7, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20f7,
325 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x2507, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x2517,
326 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x2527, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x2537,
327 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x2547, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x2557,
328 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x2567, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x2577,
329 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x2987, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x2997,
330 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x29a7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x29b7,
331 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x2dc7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x2dd7,
332 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x31e7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x41f7,
333
334// previous 1s = 3:
335 0x0000, 0x0001, 0x0002, 0x2003, 0x0004, 0x0005, 0x0006, 0x200b, 0x0008, 0x0009, 0x000a, 0x2013, 0x000c, 0x000d, 0x000e, 0x201b,
336 0x0010, 0x0011, 0x0012, 0x2023, 0x0014, 0x0015, 0x0016, 0x202b, 0x0018, 0x0019, 0x001a, 0x2033, 0x001c, 0x001d, 0x001e, 0x203b,
337 0x0020, 0x0021, 0x0022, 0x2043, 0x0024, 0x0025, 0x0026, 0x204b, 0x0028, 0x0029, 0x002a, 0x2053, 0x002c, 0x002d, 0x002e, 0x205b,
338 0x0030, 0x0031, 0x0032, 0x2063, 0x0034, 0x0035, 0x0036, 0x206b, 0x0038, 0x0039, 0x003a, 0x2073, 0x003c, 0x003d, 0x203e, 0x207b,
339 0x0040, 0x0041, 0x0042, 0x2083, 0x0044, 0x0045, 0x0046, 0x208b, 0x0048, 0x0049, 0x004a, 0x2093, 0x004c, 0x004d, 0x004e, 0x209b,
340 0x0050, 0x0051, 0x0052, 0x20a3, 0x0054, 0x0055, 0x0056, 0x20ab, 0x0058, 0x0059, 0x005a, 0x20b3, 0x005c, 0x005d, 0x005e, 0x20bb,
341 0x0060, 0x0061, 0x0062, 0x20c3, 0x0064, 0x0065, 0x0066, 0x20cb, 0x0068, 0x0069, 0x006a, 0x20d3, 0x006c, 0x006d, 0x006e, 0x20db,
342 0x0070, 0x0071, 0x0072, 0x20e3, 0x0074, 0x0075, 0x0076, 0x20eb, 0x0078, 0x0079, 0x007a, 0x20f3, 0x207c, 0x207d, 0x20be, 0x40fb,
343 0x0480, 0x0481, 0x0482, 0x2503, 0x0484, 0x0485, 0x0486, 0x250b, 0x0488, 0x0489, 0x048a, 0x2513, 0x048c, 0x048d, 0x048e, 0x251b,
344 0x0490, 0x0491, 0x0492, 0x2523, 0x0494, 0x0495, 0x0496, 0x252b, 0x0498, 0x0499, 0x049a, 0x2533, 0x049c, 0x049d, 0x049e, 0x253b,
345 0x04a0, 0x04a1, 0x04a2, 0x2543, 0x04a4, 0x04a5, 0x04a6, 0x254b, 0x04a8, 0x04a9, 0x04aa, 0x2553, 0x04ac, 0x04ad, 0x04ae, 0x255b,
346 0x04b0, 0x04b1, 0x04b2, 0x2563, 0x04b4, 0x04b5, 0x04b6, 0x256b, 0x04b8, 0x04b9, 0x04ba, 0x2573, 0x04bc, 0x04bd, 0x253e, 0x257b,
347 0x08c0, 0x08c1, 0x08c2, 0x2983, 0x08c4, 0x08c5, 0x08c6, 0x298b, 0x08c8, 0x08c9, 0x08ca, 0x2993, 0x08cc, 0x08cd, 0x08ce, 0x299b,
348 0x08d0, 0x08d1, 0x08d2, 0x29a3, 0x08d4, 0x08d5, 0x08d6, 0x29ab, 0x08d8, 0x08d9, 0x08da, 0x29b3, 0x08dc, 0x08dd, 0x08de, 0x29bb,
349 0x0ce0, 0x0ce1, 0x0ce2, 0x2dc3, 0x0ce4, 0x0ce5, 0x0ce6, 0x2dcb, 0x0ce8, 0x0ce9, 0x0cea, 0x2dd3, 0x0cec, 0x0ced, 0x0cee, 0x2ddb,
350 0x10f0, 0x10f1, 0x10f2, 0x31e3, 0x10f4, 0x10f5, 0x10f6, 0x31eb, 0x20f8, 0x20f9, 0x20fa, 0x41f3, 0x257c, 0x257d, 0x29be, 0x46fb,
351
352// previous 1s = 4:
353 0x0000, 0x2001, 0x0002, 0x2005, 0x0004, 0x2009, 0x0006, 0x200d, 0x0008, 0x2011, 0x000a, 0x2015, 0x000c, 0x2019, 0x000e, 0x201d,
354 0x0010, 0x2021, 0x0012, 0x2025, 0x0014, 0x2029, 0x0016, 0x202d, 0x0018, 0x2031, 0x001a, 0x2035, 0x001c, 0x2039, 0x001e, 0x203d,
355 0x0020, 0x2041, 0x0022, 0x2045, 0x0024, 0x2049, 0x0026, 0x204d, 0x0028, 0x2051, 0x002a, 0x2055, 0x002c, 0x2059, 0x002e, 0x205d,
356 0x0030, 0x2061, 0x0032, 0x2065, 0x0034, 0x2069, 0x0036, 0x206d, 0x0038, 0x2071, 0x003a, 0x2075, 0x003c, 0x2079, 0x203e, 0x407d,
357 0x0040, 0x2081, 0x0042, 0x2085, 0x0044, 0x2089, 0x0046, 0x208d, 0x0048, 0x2091, 0x004a, 0x2095, 0x004c, 0x2099, 0x004e, 0x209d,
358 0x0050, 0x20a1, 0x0052, 0x20a5, 0x0054, 0x20a9, 0x0056, 0x20ad, 0x0058, 0x20b1, 0x005a, 0x20b5, 0x005c, 0x20b9, 0x005e, 0x20bd,
359 0x0060, 0x20c1, 0x0062, 0x20c5, 0x0064, 0x20c9, 0x0066, 0x20cd, 0x0068, 0x20d1, 0x006a, 0x20d5, 0x006c, 0x20d9, 0x006e, 0x20dd,
360 0x0070, 0x20e1, 0x0072, 0x20e5, 0x0074, 0x20e9, 0x0076, 0x20ed, 0x0078, 0x20f1, 0x007a, 0x20f5, 0x207c, 0x40f9, 0x20be, 0x417d,
361 0x0480, 0x2501, 0x0482, 0x2505, 0x0484, 0x2509, 0x0486, 0x250d, 0x0488, 0x2511, 0x048a, 0x2515, 0x048c, 0x2519, 0x048e, 0x251d,
362 0x0490, 0x2521, 0x0492, 0x2525, 0x0494, 0x2529, 0x0496, 0x252d, 0x0498, 0x2531, 0x049a, 0x2535, 0x049c, 0x2539, 0x049e, 0x253d,
363 0x04a0, 0x2541, 0x04a2, 0x2545, 0x04a4, 0x2549, 0x04a6, 0x254d, 0x04a8, 0x2551, 0x04aa, 0x2555, 0x04ac, 0x2559, 0x04ae, 0x255d,
364 0x04b0, 0x2561, 0x04b2, 0x2565, 0x04b4, 0x2569, 0x04b6, 0x256d, 0x04b8, 0x2571, 0x04ba, 0x2575, 0x04bc, 0x2579, 0x253e, 0x467d,
365 0x08c0, 0x2981, 0x08c2, 0x2985, 0x08c4, 0x2989, 0x08c6, 0x298d, 0x08c8, 0x2991, 0x08ca, 0x2995, 0x08cc, 0x2999, 0x08ce, 0x299d,
366 0x08d0, 0x29a1, 0x08d2, 0x29a5, 0x08d4, 0x29a9, 0x08d6, 0x29ad, 0x08d8, 0x29b1, 0x08da, 0x29b5, 0x08dc, 0x29b9, 0x08de, 0x29bd,
367 0x0ce0, 0x2dc1, 0x0ce2, 0x2dc5, 0x0ce4, 0x2dc9, 0x0ce6, 0x2dcd, 0x0ce8, 0x2dd1, 0x0cea, 0x2dd5, 0x0cec, 0x2dd9, 0x0cee, 0x2ddd,
368 0x10f0, 0x31e1, 0x10f2, 0x31e5, 0x10f4, 0x31e9, 0x10f6, 0x31ed, 0x20f8, 0x41f1, 0x20fa, 0x41f5, 0x257c, 0x46f9, 0x29be, 0x4b7d
369};
370
371/* hdlc_bitstuff_byte
372 * perform HDLC bitstuffing for one input byte (8 bits, LSB first)
373 * parameters:
374 * cin input byte
375 * ones number of trailing '1' bits in result before this step
376 * iwb pointer to output buffer structure (write semaphore must be held)
377 * return value:
378 * number of trailing '1' bits in result after this step
379 */
380
381static inline int hdlc_bitstuff_byte(struct isowbuf_t *iwb, unsigned char cin,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700382 int ones)
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800383{
384 u16 stuff;
385 int shiftinc, newones;
386
387 /* get stuffing information for input byte
388 * value: bit 9.. 0 = result bits
389 * bit 12..10 = number of trailing '1' bits in result
390 * bit 14..13 = number of bits added by stuffing
391 */
392 stuff = stufftab[256 * ones + cin];
393 shiftinc = (stuff >> 13) & 3;
394 newones = (stuff >> 10) & 7;
395 stuff &= 0x3ff;
396
397 /* append stuffed byte to output stream */
398 isowbuf_putbits(iwb, stuff, 8 + shiftinc);
399 return newones;
400}
401
402/* hdlc_buildframe
403 * Perform HDLC framing with bitstuffing on a byte buffer
404 * The input buffer is regarded as a sequence of bits, starting with the least
405 * significant bit of the first byte and ending with the most significant bit
406 * of the last byte. A 16 bit FCS is appended as defined by RFC 1662.
407 * Whenever five consecutive '1' bits appear in the resulting bit sequence, a
408 * '0' bit is inserted after them.
409 * The resulting bit string and a closing flag pattern (PPP_FLAG, '01111110')
410 * are appended to the output buffer starting at the given bit position, which
411 * is assumed to already contain a leading flag.
412 * The output buffer must have sufficient length; count + count/5 + 6 bytes
413 * starting at *out are safe and are verified to be present.
414 * parameters:
415 * in input buffer
416 * count number of bytes in input buffer
417 * iwb pointer to output buffer structure (write semaphore must be held)
418 * return value:
419 * position of end of packet in output buffer on success,
420 * -EAGAIN if write semaphore busy or buffer full
421 */
422
423static inline int hdlc_buildframe(struct isowbuf_t *iwb,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700424 unsigned char *in, int count)
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800425{
426 int ones;
427 u16 fcs;
428 int end;
429 unsigned char c;
430
431 if (isowbuf_freebytes(iwb) < count + count / 5 + 6 ||
432 !isowbuf_startwrite(iwb)) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700433 gig_dbg(DEBUG_ISO, "%s: %d bytes free -> -EAGAIN",
434 __func__, isowbuf_freebytes(iwb));
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800435 return -EAGAIN;
436 }
437
438 dump_bytes(DEBUG_STREAM, "snd data", in, count);
439
440 /* bitstuff and checksum input data */
441 fcs = PPP_INITFCS;
442 ones = 0;
443 while (count-- > 0) {
444 c = *in++;
445 ones = hdlc_bitstuff_byte(iwb, c, ones);
446 fcs = crc_ccitt_byte(fcs, c);
447 }
448
449 /* bitstuff and append FCS (complemented, least significant byte first) */
450 fcs ^= 0xffff;
451 ones = hdlc_bitstuff_byte(iwb, fcs & 0x00ff, ones);
452 ones = hdlc_bitstuff_byte(iwb, (fcs >> 8) & 0x00ff, ones);
453
454 /* put closing flag and repeat byte for flag idle */
455 isowbuf_putflag(iwb);
456 end = isowbuf_donewrite(iwb);
457 dump_bytes(DEBUG_STREAM_DUMP, "isowbuf", iwb->data, end + 1);
458 return end;
459}
460
461/* trans_buildframe
462 * Append a block of 'transparent' data to the output buffer,
463 * inverting the bytes.
464 * The output buffer must have sufficient length; count bytes
465 * starting at *out are safe and are verified to be present.
466 * parameters:
467 * in input buffer
468 * count number of bytes in input buffer
469 * iwb pointer to output buffer structure (write semaphore must be held)
470 * return value:
471 * position of end of packet in output buffer on success,
472 * -EAGAIN if write semaphore busy or buffer full
473 */
474
475static inline int trans_buildframe(struct isowbuf_t *iwb,
476 unsigned char *in, int count)
477{
478 int write;
479 unsigned char c;
480
481 if (unlikely(count <= 0))
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800482 return iwb->write;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800483
484 if (isowbuf_freebytes(iwb) < count ||
485 !isowbuf_startwrite(iwb)) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700486 gig_dbg(DEBUG_ISO, "can't put %d bytes", count);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800487 return -EAGAIN;
488 }
489
Tilman Schmidt784d5852006-04-10 22:55:04 -0700490 gig_dbg(DEBUG_STREAM, "put %d bytes", count);
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800491 write = iwb->write;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800492 do {
Akinobu Mita17b3cff2006-12-08 02:36:30 -0800493 c = bitrev8(*in++);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800494 iwb->data[write++] = c;
495 write %= BAS_OUTBUFSIZE;
496 } while (--count > 0);
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800497 iwb->write = write;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800498 iwb->idle = c;
499
500 return isowbuf_donewrite(iwb);
501}
502
503int gigaset_isoc_buildframe(struct bc_state *bcs, unsigned char *in, int len)
504{
505 int result;
506
507 switch (bcs->proto2) {
508 case ISDN_PROTO_L2_HDLC:
509 result = hdlc_buildframe(bcs->hw.bas->isooutbuf, in, len);
Tilman Schmidt784d5852006-04-10 22:55:04 -0700510 gig_dbg(DEBUG_ISO, "%s: %d bytes HDLC -> %d",
511 __func__, len, result);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800512 break;
513 default: /* assume transparent */
514 result = trans_buildframe(bcs->hw.bas->isooutbuf, in, len);
Tilman Schmidt784d5852006-04-10 22:55:04 -0700515 gig_dbg(DEBUG_ISO, "%s: %d bytes trans -> %d",
516 __func__, len, result);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800517 }
518 return result;
519}
520
521/* hdlc_putbyte
522 * append byte c to current skb of B channel structure *bcs, updating fcs
523 */
524static inline void hdlc_putbyte(unsigned char c, struct bc_state *bcs)
525{
526 bcs->fcs = crc_ccitt_byte(bcs->fcs, c);
527 if (unlikely(bcs->skb == NULL)) {
528 /* skipping */
529 return;
530 }
531 if (unlikely(bcs->skb->len == SBUFSIZE)) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700532 dev_warn(bcs->cs->dev, "received oversized packet discarded\n");
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800533 bcs->hw.bas->giants++;
534 dev_kfree_skb_any(bcs->skb);
535 bcs->skb = NULL;
536 return;
537 }
Tilman Schmidt443e1f42006-04-10 22:55:13 -0700538 *__skb_put(bcs->skb, 1) = c;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800539}
540
541/* hdlc_flush
542 * drop partial HDLC data packet
543 */
544static inline void hdlc_flush(struct bc_state *bcs)
545{
546 /* clear skb or allocate new if not skipping */
547 if (likely(bcs->skb != NULL))
548 skb_trim(bcs->skb, 0);
549 else if (!bcs->ignore) {
550 if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
551 skb_reserve(bcs->skb, HW_HDR_LEN);
552 else
Tilman Schmidt784d5852006-04-10 22:55:04 -0700553 dev_err(bcs->cs->dev, "could not allocate skb\n");
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800554 }
555
556 /* reset packet state */
557 bcs->fcs = PPP_INITFCS;
558}
559
560/* hdlc_done
561 * process completed HDLC data packet
562 */
563static inline void hdlc_done(struct bc_state *bcs)
564{
565 struct sk_buff *procskb;
566
567 if (unlikely(bcs->ignore)) {
568 bcs->ignore--;
569 hdlc_flush(bcs);
570 return;
571 }
572
573 if ((procskb = bcs->skb) == NULL) {
574 /* previous error */
Tilman Schmidt784d5852006-04-10 22:55:04 -0700575 gig_dbg(DEBUG_ISO, "%s: skb=NULL", __func__);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800576 gigaset_rcv_error(NULL, bcs->cs, bcs);
577 } else if (procskb->len < 2) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700578 dev_notice(bcs->cs->dev, "received short frame (%d octets)\n",
579 procskb->len);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800580 bcs->hw.bas->runts++;
581 gigaset_rcv_error(procskb, bcs->cs, bcs);
582 } else if (bcs->fcs != PPP_GOODFCS) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700583 dev_notice(bcs->cs->dev, "frame check error (0x%04x)\n",
584 bcs->fcs);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800585 bcs->hw.bas->fcserrs++;
586 gigaset_rcv_error(procskb, bcs->cs, bcs);
587 } else {
588 procskb->len -= 2; /* subtract FCS */
589 procskb->tail -= 2;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700590 gig_dbg(DEBUG_ISO, "%s: good frame (%d octets)",
591 __func__, procskb->len);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800592 dump_bytes(DEBUG_STREAM,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700593 "rcv data", procskb->data, procskb->len);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800594 bcs->hw.bas->goodbytes += procskb->len;
595 gigaset_rcv_skb(procskb, bcs->cs, bcs);
596 }
597
598 if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
599 skb_reserve(bcs->skb, HW_HDR_LEN);
600 else
Tilman Schmidt784d5852006-04-10 22:55:04 -0700601 dev_err(bcs->cs->dev, "could not allocate skb\n");
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800602 bcs->fcs = PPP_INITFCS;
603}
604
605/* hdlc_frag
606 * drop HDLC data packet with non-integral last byte
607 */
608static inline void hdlc_frag(struct bc_state *bcs, unsigned inbits)
609{
610 if (unlikely(bcs->ignore)) {
611 bcs->ignore--;
612 hdlc_flush(bcs);
613 return;
614 }
615
Tilman Schmidt784d5852006-04-10 22:55:04 -0700616 dev_notice(bcs->cs->dev, "received partial byte (%d bits)\n", inbits);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800617 bcs->hw.bas->alignerrs++;
618 gigaset_rcv_error(bcs->skb, bcs->cs, bcs);
619
620 if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
621 skb_reserve(bcs->skb, HW_HDR_LEN);
622 else
Tilman Schmidt784d5852006-04-10 22:55:04 -0700623 dev_err(bcs->cs->dev, "could not allocate skb\n");
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800624 bcs->fcs = PPP_INITFCS;
625}
626
627/* bit counts lookup table for HDLC bit unstuffing
628 * index: input byte
629 * value: bit 0..3 = number of consecutive '1' bits starting from LSB
630 * bit 4..6 = number of consecutive '1' bits starting from MSB
631 * (replacing 8 by 7 to make it fit; the algorithm won't care)
632 * bit 7 set if there are 5 or more "interior" consecutive '1' bits
633 */
Tilman Schmidt35dc8452007-03-29 01:20:34 -0700634static const unsigned char bitcounts[256] = {
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800635 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04,
636 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05,
637 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04,
638 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x80, 0x06,
639 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04,
640 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05,
641 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04,
642 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x80, 0x81, 0x80, 0x07,
643 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x14,
644 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x15,
645 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x14,
646 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x90, 0x16,
647 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x23, 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x24,
648 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x23, 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x25,
649 0x30, 0x31, 0x30, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x31, 0x30, 0x32, 0x30, 0x31, 0x30, 0x34,
650 0x40, 0x41, 0x40, 0x42, 0x40, 0x41, 0x40, 0x43, 0x50, 0x51, 0x50, 0x52, 0x60, 0x61, 0x70, 0x78
651};
652
653/* hdlc_unpack
654 * perform HDLC frame processing (bit unstuffing, flag detection, FCS calculation)
655 * on a sequence of received data bytes (8 bits each, LSB first)
656 * pass on successfully received, complete frames as SKBs via gigaset_rcv_skb
657 * notify of errors via gigaset_rcv_error
658 * tally frames, errors etc. in BC structure counters
659 * parameters:
660 * src received data
661 * count number of received bytes
662 * bcs receiving B channel structure
663 */
664static inline void hdlc_unpack(unsigned char *src, unsigned count,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700665 struct bc_state *bcs)
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800666{
Tilman Schmidtd48c7782006-04-10 22:55:08 -0700667 struct bas_bc_state *ubc = bcs->hw.bas;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800668 int inputstate;
669 unsigned seqlen, inbyte, inbits;
670
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800671 /* load previous state:
672 * inputstate = set of flag bits:
673 * - INS_flag_hunt: no complete opening flag received since connection setup or last abort
674 * - INS_have_data: at least one complete data byte received since last flag
675 * seqlen = number of consecutive '1' bits in last 7 input stream bits (0..7)
676 * inbyte = accumulated partial data byte (if !INS_flag_hunt)
677 * inbits = number of valid bits in inbyte, starting at LSB (0..6)
678 */
679 inputstate = bcs->inputstate;
680 seqlen = ubc->seqlen;
681 inbyte = ubc->inbyte;
682 inbits = ubc->inbits;
683
684 /* bit unstuffing a byte a time
685 * Take your time to understand this; it's straightforward but tedious.
686 * The "bitcounts" lookup table is used to speed up the counting of
687 * leading and trailing '1' bits.
688 */
689 while (count--) {
690 unsigned char c = *src++;
691 unsigned char tabentry = bitcounts[c];
692 unsigned lead1 = tabentry & 0x0f;
693 unsigned trail1 = (tabentry >> 4) & 0x0f;
694
695 seqlen += lead1;
696
697 if (unlikely(inputstate & INS_flag_hunt)) {
698 if (c == PPP_FLAG) {
699 /* flag-in-one */
700 inputstate &= ~(INS_flag_hunt | INS_have_data);
701 inbyte = 0;
702 inbits = 0;
703 } else if (seqlen == 6 && trail1 != 7) {
704 /* flag completed & not followed by abort */
705 inputstate &= ~(INS_flag_hunt | INS_have_data);
706 inbyte = c >> (lead1 + 1);
707 inbits = 7 - lead1;
708 if (trail1 >= 8) {
709 /* interior stuffing: omitting the MSB handles most cases */
710 inbits--;
711 /* correct the incorrectly handled cases individually */
712 switch (c) {
713 case 0xbe:
714 inbyte = 0x3f;
715 break;
716 }
717 }
718 }
719 /* else: continue flag-hunting */
720 } else if (likely(seqlen < 5 && trail1 < 7)) {
721 /* streamlined case: 8 data bits, no stuffing */
722 inbyte |= c << inbits;
723 hdlc_putbyte(inbyte & 0xff, bcs);
724 inputstate |= INS_have_data;
725 inbyte >>= 8;
726 /* inbits unchanged */
727 } else if (likely(seqlen == 6 && inbits == 7 - lead1 &&
728 trail1 + 1 == inbits &&
729 !(inputstate & INS_have_data))) {
730 /* streamlined case: flag idle - state unchanged */
731 } else if (unlikely(seqlen > 6)) {
732 /* abort sequence */
733 ubc->aborts++;
734 hdlc_flush(bcs);
735 inputstate |= INS_flag_hunt;
736 } else if (seqlen == 6) {
737 /* closing flag, including (6 - lead1) '1's and one '0' from inbits */
738 if (inbits > 7 - lead1) {
739 hdlc_frag(bcs, inbits + lead1 - 7);
740 inputstate &= ~INS_have_data;
741 } else {
742 if (inbits < 7 - lead1)
743 ubc->stolen0s ++;
744 if (inputstate & INS_have_data) {
745 hdlc_done(bcs);
746 inputstate &= ~INS_have_data;
747 }
748 }
749
750 if (c == PPP_FLAG) {
751 /* complete flag, LSB overlaps preceding flag */
752 ubc->shared0s ++;
753 inbits = 0;
754 inbyte = 0;
755 } else if (trail1 != 7) {
756 /* remaining bits */
757 inbyte = c >> (lead1 + 1);
758 inbits = 7 - lead1;
759 if (trail1 >= 8) {
760 /* interior stuffing: omitting the MSB handles most cases */
761 inbits--;
762 /* correct the incorrectly handled cases individually */
763 switch (c) {
764 case 0xbe:
765 inbyte = 0x3f;
766 break;
767 }
768 }
769 } else {
770 /* abort sequence follows, skb already empty anyway */
771 ubc->aborts++;
772 inputstate |= INS_flag_hunt;
773 }
774 } else { /* (seqlen < 6) && (seqlen == 5 || trail1 >= 7) */
775
776 if (c == PPP_FLAG) {
777 /* complete flag */
778 if (seqlen == 5)
779 ubc->stolen0s++;
780 if (inbits) {
781 hdlc_frag(bcs, inbits);
782 inbits = 0;
783 inbyte = 0;
784 } else if (inputstate & INS_have_data)
785 hdlc_done(bcs);
786 inputstate &= ~INS_have_data;
787 } else if (trail1 == 7) {
788 /* abort sequence */
789 ubc->aborts++;
790 hdlc_flush(bcs);
791 inputstate |= INS_flag_hunt;
792 } else {
793 /* stuffed data */
794 if (trail1 < 7) { /* => seqlen == 5 */
795 /* stuff bit at position lead1, no interior stuffing */
796 unsigned char mask = (1 << lead1) - 1;
797 c = (c & mask) | ((c & ~mask) >> 1);
798 inbyte |= c << inbits;
799 inbits += 7;
800 } else if (seqlen < 5) { /* trail1 >= 8 */
801 /* interior stuffing: omitting the MSB handles most cases */
802 /* correct the incorrectly handled cases individually */
803 switch (c) {
804 case 0xbe:
805 c = 0x7e;
806 break;
807 }
808 inbyte |= c << inbits;
809 inbits += 7;
810 } else { /* seqlen == 5 && trail1 >= 8 */
811
812 /* stuff bit at lead1 *and* interior stuffing */
813 switch (c) { /* unstuff individually */
814 case 0x7d:
815 c = 0x3f;
816 break;
817 case 0xbe:
818 c = 0x3f;
819 break;
820 case 0x3e:
821 c = 0x1f;
822 break;
823 case 0x7c:
824 c = 0x3e;
825 break;
826 }
827 inbyte |= c << inbits;
828 inbits += 6;
829 }
830 if (inbits >= 8) {
831 inbits -= 8;
832 hdlc_putbyte(inbyte & 0xff, bcs);
833 inputstate |= INS_have_data;
834 inbyte >>= 8;
835 }
836 }
837 }
838 seqlen = trail1 & 7;
839 }
840
841 /* save new state */
842 bcs->inputstate = inputstate;
843 ubc->seqlen = seqlen;
844 ubc->inbyte = inbyte;
845 ubc->inbits = inbits;
846}
847
848/* trans_receive
849 * pass on received USB frame transparently as SKB via gigaset_rcv_skb
850 * invert bytes
851 * tally frames, errors etc. in BC structure counters
852 * parameters:
853 * src received data
854 * count number of received bytes
855 * bcs receiving B channel structure
856 */
857static inline void trans_receive(unsigned char *src, unsigned count,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700858 struct bc_state *bcs)
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800859{
860 struct sk_buff *skb;
861 int dobytes;
862 unsigned char *dst;
863
864 if (unlikely(bcs->ignore)) {
865 bcs->ignore--;
866 hdlc_flush(bcs);
867 return;
868 }
869 if (unlikely((skb = bcs->skb) == NULL)) {
870 bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN);
871 if (!skb) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700872 dev_err(bcs->cs->dev, "could not allocate skb\n");
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800873 return;
874 }
875 skb_reserve(skb, HW_HDR_LEN);
876 }
877 bcs->hw.bas->goodbytes += skb->len;
878 dobytes = TRANSBUFSIZE - skb->len;
879 while (count > 0) {
880 dst = skb_put(skb, count < dobytes ? count : dobytes);
881 while (count > 0 && dobytes > 0) {
Akinobu Mita17b3cff2006-12-08 02:36:30 -0800882 *dst++ = bitrev8(*src++);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800883 count--;
884 dobytes--;
885 }
886 if (dobytes == 0) {
887 gigaset_rcv_skb(skb, bcs->cs, bcs);
888 bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN);
889 if (!skb) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700890 dev_err(bcs->cs->dev,
891 "could not allocate skb\n");
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800892 return;
893 }
894 skb_reserve(bcs->skb, HW_HDR_LEN);
895 dobytes = TRANSBUFSIZE;
896 }
897 }
898}
899
900void gigaset_isoc_receive(unsigned char *src, unsigned count, struct bc_state *bcs)
901{
902 switch (bcs->proto2) {
903 case ISDN_PROTO_L2_HDLC:
904 hdlc_unpack(src, count, bcs);
905 break;
906 default: /* assume transparent */
907 trans_receive(src, count, bcs);
908 }
909}
910
911/* == data input =========================================================== */
912
913static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf)
914{
915 struct cardstate *cs = inbuf->cs;
916 unsigned cbytes = cs->cbytes;
917
918 while (numbytes--) {
919 /* copy next character, check for end of line */
920 switch (cs->respdata[cbytes] = *src++) {
921 case '\r':
922 case '\n':
923 /* end of line */
Tilman Schmidt784d5852006-04-10 22:55:04 -0700924 gig_dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)",
925 __func__, cbytes);
Tilman Schmidt92ba0ee2007-02-12 00:52:26 -0800926 if (cbytes >= MAX_RESP_SIZE - 1)
927 dev_warn(cs->dev, "response too large\n");
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800928 cs->cbytes = cbytes;
929 gigaset_handle_modem_response(cs);
930 cbytes = 0;
931 break;
932 default:
933 /* advance in line buffer, checking for overflow */
934 if (cbytes < MAX_RESP_SIZE - 1)
935 cbytes++;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800936 }
937 }
938
939 /* save state */
940 cs->cbytes = cbytes;
941}
942
943
944/* process a block of data received through the control channel
945 */
946void gigaset_isoc_input(struct inbuf_t *inbuf)
947{
948 struct cardstate *cs = inbuf->cs;
949 unsigned tail, head, numbytes;
950 unsigned char *src;
951
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800952 head = inbuf->head;
953 while (head != (tail = inbuf->tail)) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700954 gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800955 if (head > tail)
956 tail = RBUFSIZE;
957 src = inbuf->data + head;
958 numbytes = tail - head;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700959 gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800960
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800961 if (cs->mstate == MS_LOCKED) {
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800962 gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response",
Tilman Schmidt01371502006-04-10 22:55:11 -0700963 numbytes, src);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800964 gigaset_if_receive(inbuf->cs, src, numbytes);
965 } else {
966 gigaset_dbg_buffer(DEBUG_CMD, "received response",
Tilman Schmidt01371502006-04-10 22:55:11 -0700967 numbytes, src);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800968 cmd_loop(src, numbytes, inbuf);
969 }
970
971 head += numbytes;
972 if (head == RBUFSIZE)
973 head = 0;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700974 gig_dbg(DEBUG_INTR, "setting head to %u", head);
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800975 inbuf->head = head;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800976 }
977}
978
979
980/* == data output ========================================================== */
981
982/* gigaset_send_skb
983 * called by common.c to queue an skb for sending
984 * and start transmission if necessary
985 * parameters:
986 * B Channel control structure
987 * skb
988 * return value:
989 * number of bytes accepted for sending
990 * (skb->len if ok, 0 if out of buffer space)
991 * or error code (< 0, eg. -EINVAL)
992 */
993int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb)
994{
Tilman Schmidtd48c7782006-04-10 22:55:08 -0700995 int len = skb->len;
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700996 unsigned long flags;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800997
Tilman Schmidt73a88812006-04-22 02:35:30 -0700998 spin_lock_irqsave(&bcs->cs->lock, flags);
999 if (!bcs->cs->connected) {
1000 spin_unlock_irqrestore(&bcs->cs->lock, flags);
1001 return -ENODEV;
1002 }
1003
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -08001004 skb_queue_tail(&bcs->squeue, skb);
Tilman Schmidt784d5852006-04-10 22:55:04 -07001005 gig_dbg(DEBUG_ISO, "%s: skb queued, qlen=%d",
1006 __func__, skb_queue_len(&bcs->squeue));
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -08001007
1008 /* tasklet submits URB if necessary */
Tilman Schmidt73a88812006-04-22 02:35:30 -07001009 tasklet_schedule(&bcs->hw.bas->sent_tasklet);
Tilman Schmidt69049cc2006-04-10 22:55:16 -07001010 spin_unlock_irqrestore(&bcs->cs->lock, flags);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -08001011
1012 return len; /* ok so far */
1013}