Merge branch 'x86/urgent' into x86/pat
[deliverable/linux.git] / drivers / isdn / gigaset / isocdata.c
CommitLineData
76bb4685
HL
1/*
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 * =====================================================================
76bb4685
HL
13 */
14
15#include "gigaset.h"
16#include <linux/crc-ccitt.h>
17b3cff0 17#include <linux/bitrev.h>
76bb4685
HL
18
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{
9d4bee2b
TS
26 iwb->read = 0;
27 iwb->nextread = 0;
28 iwb->write = 0;
76bb4685
HL
29 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
9d4bee2b
TS
42 read = iwb->read;
43 write = iwb->write;
76bb4685
HL
44 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;
9d4bee2b 65 read = iwb->read;
76bb4685
HL
66 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);
784d5858
TS
87 gig_dbg(DEBUG_ISO, "%s: couldn't acquire iso write semaphore",
88 __func__);
76bb4685
HL
89 return 0;
90 }
784d5858
TS
91 gig_dbg(DEBUG_ISO,
92 "%s: acquired iso write semaphore, data[write]=%02x, nbits=%d",
9d4bee2b 93 __func__, iwb->data[iwb->write], iwb->wbits);
76bb4685
HL
94 return 1;
95}
96
97/* finish writing
9d4bee2b 98 * release the write semaphore
76bb4685
HL
99 * returns the current write position
100 */
101static inline int isowbuf_donewrite(struct isowbuf_t *iwb)
102{
9d4bee2b 103 int write = iwb->write;
76bb4685
HL
104 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{
9d4bee2b 117 int write = iwb->write;
76bb4685
HL
118 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;
9d4bee2b 129 iwb->write = write;
76bb4685
HL
130}
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 */
9d4bee2b 143 write = iwb->write;
76bb4685 144 iwb->idle = iwb->data[write];
784d5858 145 gig_dbg(DEBUG_ISO, "idle fill byte %02x", iwb->idle);
76bb4685
HL
146 /* 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
9d4bee2b
TS
161 read = iwb->nextread;
162 write = iwb->write;
76bb4685 163 if (likely(read == write)) {
76bb4685
HL
164 /* return idle frame */
165 return read < BAS_OUTBUFPAD ?
784d5858 166 BAS_OUTBUFSIZE : read - BAS_OUTBUFPAD;
76bb4685
HL
167 }
168
169 limit = read + size;
784d5858
TS
170 gig_dbg(DEBUG_STREAM, "%s: read=%d write=%d limit=%d",
171 __func__, read, write, limit);
76bb4685
HL
172#ifdef CONFIG_GIGASET_DEBUG
173 if (unlikely(size < 0 || size > BAS_OUTBUFPAD)) {
c8770dca 174 pr_err("invalid size %d\n", size);
76bb4685
HL
175 return -EINVAL;
176 }
76bb4685
HL
177#endif
178
179 if (read < write) {
180 /* no wraparound in valid data */
181 if (limit >= write) {
182 /* append idle frame */
183 if (!isowbuf_startwrite(iwb))
184 return -EBUSY;
185 /* write position could have changed */
9d4bee2b
TS
186 write = iwb->write;
187 if (limit >= write) {
917f5085
TS
188 pbyte = iwb->data[write]; /* save
189 partial byte */
76bb4685 190 limit = write + BAS_OUTBUFPAD;
784d5858
TS
191 gig_dbg(DEBUG_STREAM,
192 "%s: filling %d->%d with %02x",
193 __func__, write, limit, iwb->idle);
76bb4685
HL
194 if (write + BAS_OUTBUFPAD < BAS_OUTBUFSIZE)
195 memset(iwb->data + write, iwb->idle,
196 BAS_OUTBUFPAD);
197 else {
198 /* wraparound, fill entire pad area */
199 memset(iwb->data + write, iwb->idle,
200 BAS_OUTBUFSIZE + BAS_OUTBUFPAD
201 - write);
202 limit = 0;
203 }
784d5858
TS
204 gig_dbg(DEBUG_STREAM,
205 "%s: restoring %02x at %d",
206 __func__, pbyte, limit);
917f5085
TS
207 iwb->data[limit] = pbyte; /* restore
208 partial byte */
9d4bee2b 209 iwb->write = limit;
76bb4685
HL
210 }
211 isowbuf_donewrite(iwb);
212 }
213 } else {
214 /* valid data wraparound */
215 if (limit >= BAS_OUTBUFSIZE) {
216 /* copy wrapped part into pad area */
217 src = 0;
218 dst = BAS_OUTBUFSIZE;
219 while (dst < limit && src < write)
220 iwb->data[dst++] = iwb->data[src++];
221 if (dst <= limit) {
222 /* fill pad area with idle byte */
223 memset(iwb->data + dst, iwb->idle,
224 BAS_OUTBUFSIZE + BAS_OUTBUFPAD - dst);
225 }
226 limit = src;
227 }
228 }
9d4bee2b 229 iwb->nextread = limit;
76bb4685
HL
230 return read;
231}
232
233/* dump_bytes
234 * write hex bytes to syslog for debugging
235 */
236static inline void dump_bytes(enum debuglevel level, const char *tag,
784d5858 237 unsigned char *bytes, int count)
76bb4685
HL
238{
239#ifdef CONFIG_GIGASET_DEBUG
240 unsigned char c;
241 static char dbgline[3 * 32 + 1];
76bb4685 242 int i = 0;
1315d696
TS
243
244 if (!(gigaset_debuglevel & level))
245 return;
246
76bb4685
HL
247 while (count-- > 0) {
248 if (i > sizeof(dbgline) - 4) {
249 dbgline[i] = '\0';
784d5858 250 gig_dbg(level, "%s:%s", tag, dbgline);
76bb4685
HL
251 i = 0;
252 }
253 c = *bytes++;
254 dbgline[i] = (i && !(i % 12)) ? '-' : ' ';
255 i++;
02137f2e
HH
256 dbgline[i++] = hex_asc_hi(c);
257 dbgline[i++] = hex_asc_lo(c);
76bb4685
HL
258 }
259 dbgline[i] = '\0';
784d5858 260 gig_dbg(level, "%s:%s", tag, dbgline);
76bb4685
HL
261#endif
262}
263
264/*============================================================================*/
265
266/* bytewise HDLC bitstuffing via table lookup
267 * lookup table: 5 subtables for 0..4 preceding consecutive '1' bits
268 * index: 256*(number of preceding '1' bits) + (next byte to stuff)
269 * value: bit 9.. 0 = result bits
270 * bit 12..10 = number of trailing '1' bits in result
271 * bit 14..13 = number of bits added by stuffing
272 */
35dc8457 273static const u16 stufftab[5 * 256] = {
76bb4685
HL
274// previous 1s = 0:
275 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
276 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x201f,
277 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
278 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x205f,
279 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
280 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x209f,
281 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
282 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20df,
283 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x048f,
284 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x251f,
285 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x04af,
286 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x255f,
287 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x08c7, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x08cf,
288 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x08d7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x299f,
289 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x0ce7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x0cef,
290 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x10f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x2ddf,
291
292// previous 1s = 1:
293 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x200f,
294 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x202f,
295 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x204f,
296 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x206f,
297 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x208f,
298 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x20af,
299 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x20cf,
300 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20ef,
301 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x250f,
302 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x252f,
303 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x254f,
304 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x256f,
305 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x08c7, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x298f,
306 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x08d7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x29af,
307 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x0ce7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x2dcf,
308 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x10f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x31ef,
309
310// previous 1s = 2:
311 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x2007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x2017,
312 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x2027, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x2037,
313 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x2047, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x2057,
314 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x2067, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x2077,
315 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x2087, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x2097,
316 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x20a7, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x20b7,
317 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x20c7, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x20d7,
318 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x20e7, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20f7,
319 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x2507, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x2517,
320 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x2527, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x2537,
321 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x2547, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x2557,
322 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x2567, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x2577,
323 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x2987, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x2997,
324 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x29a7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x29b7,
325 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x2dc7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x2dd7,
326 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x31e7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x41f7,
327
328// previous 1s = 3:
329 0x0000, 0x0001, 0x0002, 0x2003, 0x0004, 0x0005, 0x0006, 0x200b, 0x0008, 0x0009, 0x000a, 0x2013, 0x000c, 0x000d, 0x000e, 0x201b,
330 0x0010, 0x0011, 0x0012, 0x2023, 0x0014, 0x0015, 0x0016, 0x202b, 0x0018, 0x0019, 0x001a, 0x2033, 0x001c, 0x001d, 0x001e, 0x203b,
331 0x0020, 0x0021, 0x0022, 0x2043, 0x0024, 0x0025, 0x0026, 0x204b, 0x0028, 0x0029, 0x002a, 0x2053, 0x002c, 0x002d, 0x002e, 0x205b,
332 0x0030, 0x0031, 0x0032, 0x2063, 0x0034, 0x0035, 0x0036, 0x206b, 0x0038, 0x0039, 0x003a, 0x2073, 0x003c, 0x003d, 0x203e, 0x207b,
333 0x0040, 0x0041, 0x0042, 0x2083, 0x0044, 0x0045, 0x0046, 0x208b, 0x0048, 0x0049, 0x004a, 0x2093, 0x004c, 0x004d, 0x004e, 0x209b,
334 0x0050, 0x0051, 0x0052, 0x20a3, 0x0054, 0x0055, 0x0056, 0x20ab, 0x0058, 0x0059, 0x005a, 0x20b3, 0x005c, 0x005d, 0x005e, 0x20bb,
335 0x0060, 0x0061, 0x0062, 0x20c3, 0x0064, 0x0065, 0x0066, 0x20cb, 0x0068, 0x0069, 0x006a, 0x20d3, 0x006c, 0x006d, 0x006e, 0x20db,
336 0x0070, 0x0071, 0x0072, 0x20e3, 0x0074, 0x0075, 0x0076, 0x20eb, 0x0078, 0x0079, 0x007a, 0x20f3, 0x207c, 0x207d, 0x20be, 0x40fb,
337 0x0480, 0x0481, 0x0482, 0x2503, 0x0484, 0x0485, 0x0486, 0x250b, 0x0488, 0x0489, 0x048a, 0x2513, 0x048c, 0x048d, 0x048e, 0x251b,
338 0x0490, 0x0491, 0x0492, 0x2523, 0x0494, 0x0495, 0x0496, 0x252b, 0x0498, 0x0499, 0x049a, 0x2533, 0x049c, 0x049d, 0x049e, 0x253b,
339 0x04a0, 0x04a1, 0x04a2, 0x2543, 0x04a4, 0x04a5, 0x04a6, 0x254b, 0x04a8, 0x04a9, 0x04aa, 0x2553, 0x04ac, 0x04ad, 0x04ae, 0x255b,
340 0x04b0, 0x04b1, 0x04b2, 0x2563, 0x04b4, 0x04b5, 0x04b6, 0x256b, 0x04b8, 0x04b9, 0x04ba, 0x2573, 0x04bc, 0x04bd, 0x253e, 0x257b,
341 0x08c0, 0x08c1, 0x08c2, 0x2983, 0x08c4, 0x08c5, 0x08c6, 0x298b, 0x08c8, 0x08c9, 0x08ca, 0x2993, 0x08cc, 0x08cd, 0x08ce, 0x299b,
342 0x08d0, 0x08d1, 0x08d2, 0x29a3, 0x08d4, 0x08d5, 0x08d6, 0x29ab, 0x08d8, 0x08d9, 0x08da, 0x29b3, 0x08dc, 0x08dd, 0x08de, 0x29bb,
343 0x0ce0, 0x0ce1, 0x0ce2, 0x2dc3, 0x0ce4, 0x0ce5, 0x0ce6, 0x2dcb, 0x0ce8, 0x0ce9, 0x0cea, 0x2dd3, 0x0cec, 0x0ced, 0x0cee, 0x2ddb,
344 0x10f0, 0x10f1, 0x10f2, 0x31e3, 0x10f4, 0x10f5, 0x10f6, 0x31eb, 0x20f8, 0x20f9, 0x20fa, 0x41f3, 0x257c, 0x257d, 0x29be, 0x46fb,
345
346// previous 1s = 4:
347 0x0000, 0x2001, 0x0002, 0x2005, 0x0004, 0x2009, 0x0006, 0x200d, 0x0008, 0x2011, 0x000a, 0x2015, 0x000c, 0x2019, 0x000e, 0x201d,
348 0x0010, 0x2021, 0x0012, 0x2025, 0x0014, 0x2029, 0x0016, 0x202d, 0x0018, 0x2031, 0x001a, 0x2035, 0x001c, 0x2039, 0x001e, 0x203d,
349 0x0020, 0x2041, 0x0022, 0x2045, 0x0024, 0x2049, 0x0026, 0x204d, 0x0028, 0x2051, 0x002a, 0x2055, 0x002c, 0x2059, 0x002e, 0x205d,
350 0x0030, 0x2061, 0x0032, 0x2065, 0x0034, 0x2069, 0x0036, 0x206d, 0x0038, 0x2071, 0x003a, 0x2075, 0x003c, 0x2079, 0x203e, 0x407d,
351 0x0040, 0x2081, 0x0042, 0x2085, 0x0044, 0x2089, 0x0046, 0x208d, 0x0048, 0x2091, 0x004a, 0x2095, 0x004c, 0x2099, 0x004e, 0x209d,
352 0x0050, 0x20a1, 0x0052, 0x20a5, 0x0054, 0x20a9, 0x0056, 0x20ad, 0x0058, 0x20b1, 0x005a, 0x20b5, 0x005c, 0x20b9, 0x005e, 0x20bd,
353 0x0060, 0x20c1, 0x0062, 0x20c5, 0x0064, 0x20c9, 0x0066, 0x20cd, 0x0068, 0x20d1, 0x006a, 0x20d5, 0x006c, 0x20d9, 0x006e, 0x20dd,
354 0x0070, 0x20e1, 0x0072, 0x20e5, 0x0074, 0x20e9, 0x0076, 0x20ed, 0x0078, 0x20f1, 0x007a, 0x20f5, 0x207c, 0x40f9, 0x20be, 0x417d,
355 0x0480, 0x2501, 0x0482, 0x2505, 0x0484, 0x2509, 0x0486, 0x250d, 0x0488, 0x2511, 0x048a, 0x2515, 0x048c, 0x2519, 0x048e, 0x251d,
356 0x0490, 0x2521, 0x0492, 0x2525, 0x0494, 0x2529, 0x0496, 0x252d, 0x0498, 0x2531, 0x049a, 0x2535, 0x049c, 0x2539, 0x049e, 0x253d,
357 0x04a0, 0x2541, 0x04a2, 0x2545, 0x04a4, 0x2549, 0x04a6, 0x254d, 0x04a8, 0x2551, 0x04aa, 0x2555, 0x04ac, 0x2559, 0x04ae, 0x255d,
358 0x04b0, 0x2561, 0x04b2, 0x2565, 0x04b4, 0x2569, 0x04b6, 0x256d, 0x04b8, 0x2571, 0x04ba, 0x2575, 0x04bc, 0x2579, 0x253e, 0x467d,
359 0x08c0, 0x2981, 0x08c2, 0x2985, 0x08c4, 0x2989, 0x08c6, 0x298d, 0x08c8, 0x2991, 0x08ca, 0x2995, 0x08cc, 0x2999, 0x08ce, 0x299d,
360 0x08d0, 0x29a1, 0x08d2, 0x29a5, 0x08d4, 0x29a9, 0x08d6, 0x29ad, 0x08d8, 0x29b1, 0x08da, 0x29b5, 0x08dc, 0x29b9, 0x08de, 0x29bd,
361 0x0ce0, 0x2dc1, 0x0ce2, 0x2dc5, 0x0ce4, 0x2dc9, 0x0ce6, 0x2dcd, 0x0ce8, 0x2dd1, 0x0cea, 0x2dd5, 0x0cec, 0x2dd9, 0x0cee, 0x2ddd,
362 0x10f0, 0x31e1, 0x10f2, 0x31e5, 0x10f4, 0x31e9, 0x10f6, 0x31ed, 0x20f8, 0x41f1, 0x20fa, 0x41f5, 0x257c, 0x46f9, 0x29be, 0x4b7d
363};
364
365/* hdlc_bitstuff_byte
366 * perform HDLC bitstuffing for one input byte (8 bits, LSB first)
367 * parameters:
368 * cin input byte
369 * ones number of trailing '1' bits in result before this step
370 * iwb pointer to output buffer structure (write semaphore must be held)
371 * return value:
372 * number of trailing '1' bits in result after this step
373 */
374
375static inline int hdlc_bitstuff_byte(struct isowbuf_t *iwb, unsigned char cin,
784d5858 376 int ones)
76bb4685
HL
377{
378 u16 stuff;
379 int shiftinc, newones;
380
381 /* get stuffing information for input byte
382 * value: bit 9.. 0 = result bits
383 * bit 12..10 = number of trailing '1' bits in result
384 * bit 14..13 = number of bits added by stuffing
385 */
386 stuff = stufftab[256 * ones + cin];
387 shiftinc = (stuff >> 13) & 3;
388 newones = (stuff >> 10) & 7;
389 stuff &= 0x3ff;
390
391 /* append stuffed byte to output stream */
392 isowbuf_putbits(iwb, stuff, 8 + shiftinc);
393 return newones;
394}
395
396/* hdlc_buildframe
397 * Perform HDLC framing with bitstuffing on a byte buffer
398 * The input buffer is regarded as a sequence of bits, starting with the least
399 * significant bit of the first byte and ending with the most significant bit
400 * of the last byte. A 16 bit FCS is appended as defined by RFC 1662.
401 * Whenever five consecutive '1' bits appear in the resulting bit sequence, a
402 * '0' bit is inserted after them.
403 * The resulting bit string and a closing flag pattern (PPP_FLAG, '01111110')
404 * are appended to the output buffer starting at the given bit position, which
405 * is assumed to already contain a leading flag.
406 * The output buffer must have sufficient length; count + count/5 + 6 bytes
407 * starting at *out are safe and are verified to be present.
408 * parameters:
409 * in input buffer
410 * count number of bytes in input buffer
411 * iwb pointer to output buffer structure (write semaphore must be held)
412 * return value:
413 * position of end of packet in output buffer on success,
414 * -EAGAIN if write semaphore busy or buffer full
415 */
416
417static inline int hdlc_buildframe(struct isowbuf_t *iwb,
784d5858 418 unsigned char *in, int count)
76bb4685
HL
419{
420 int ones;
421 u16 fcs;
422 int end;
423 unsigned char c;
424
425 if (isowbuf_freebytes(iwb) < count + count / 5 + 6 ||
426 !isowbuf_startwrite(iwb)) {
784d5858
TS
427 gig_dbg(DEBUG_ISO, "%s: %d bytes free -> -EAGAIN",
428 __func__, isowbuf_freebytes(iwb));
76bb4685
HL
429 return -EAGAIN;
430 }
431
432 dump_bytes(DEBUG_STREAM, "snd data", in, count);
433
434 /* bitstuff and checksum input data */
435 fcs = PPP_INITFCS;
436 ones = 0;
437 while (count-- > 0) {
438 c = *in++;
439 ones = hdlc_bitstuff_byte(iwb, c, ones);
440 fcs = crc_ccitt_byte(fcs, c);
441 }
442
443 /* bitstuff and append FCS (complemented, least significant byte first) */
444 fcs ^= 0xffff;
445 ones = hdlc_bitstuff_byte(iwb, fcs & 0x00ff, ones);
446 ones = hdlc_bitstuff_byte(iwb, (fcs >> 8) & 0x00ff, ones);
447
448 /* put closing flag and repeat byte for flag idle */
449 isowbuf_putflag(iwb);
450 end = isowbuf_donewrite(iwb);
451 dump_bytes(DEBUG_STREAM_DUMP, "isowbuf", iwb->data, end + 1);
452 return end;
453}
454
455/* trans_buildframe
456 * Append a block of 'transparent' data to the output buffer,
457 * inverting the bytes.
458 * The output buffer must have sufficient length; count bytes
459 * starting at *out are safe and are verified to be present.
460 * parameters:
461 * in input buffer
462 * count number of bytes in input buffer
463 * iwb pointer to output buffer structure (write semaphore must be held)
464 * return value:
465 * position of end of packet in output buffer on success,
466 * -EAGAIN if write semaphore busy or buffer full
467 */
468
469static inline int trans_buildframe(struct isowbuf_t *iwb,
470 unsigned char *in, int count)
471{
472 int write;
473 unsigned char c;
474
475 if (unlikely(count <= 0))
9d4bee2b 476 return iwb->write;
76bb4685
HL
477
478 if (isowbuf_freebytes(iwb) < count ||
479 !isowbuf_startwrite(iwb)) {
784d5858 480 gig_dbg(DEBUG_ISO, "can't put %d bytes", count);
76bb4685
HL
481 return -EAGAIN;
482 }
483
784d5858 484 gig_dbg(DEBUG_STREAM, "put %d bytes", count);
9d4bee2b 485 write = iwb->write;
76bb4685 486 do {
17b3cff0 487 c = bitrev8(*in++);
76bb4685
HL
488 iwb->data[write++] = c;
489 write %= BAS_OUTBUFSIZE;
490 } while (--count > 0);
9d4bee2b 491 iwb->write = write;
76bb4685
HL
492 iwb->idle = c;
493
494 return isowbuf_donewrite(iwb);
495}
496
497int gigaset_isoc_buildframe(struct bc_state *bcs, unsigned char *in, int len)
498{
499 int result;
500
501 switch (bcs->proto2) {
502 case ISDN_PROTO_L2_HDLC:
503 result = hdlc_buildframe(bcs->hw.bas->isooutbuf, in, len);
784d5858
TS
504 gig_dbg(DEBUG_ISO, "%s: %d bytes HDLC -> %d",
505 __func__, len, result);
76bb4685
HL
506 break;
507 default: /* assume transparent */
508 result = trans_buildframe(bcs->hw.bas->isooutbuf, in, len);
784d5858
TS
509 gig_dbg(DEBUG_ISO, "%s: %d bytes trans -> %d",
510 __func__, len, result);
76bb4685
HL
511 }
512 return result;
513}
514
515/* hdlc_putbyte
516 * append byte c to current skb of B channel structure *bcs, updating fcs
517 */
518static inline void hdlc_putbyte(unsigned char c, struct bc_state *bcs)
519{
520 bcs->fcs = crc_ccitt_byte(bcs->fcs, c);
521 if (unlikely(bcs->skb == NULL)) {
522 /* skipping */
523 return;
524 }
525 if (unlikely(bcs->skb->len == SBUFSIZE)) {
784d5858 526 dev_warn(bcs->cs->dev, "received oversized packet discarded\n");
76bb4685
HL
527 bcs->hw.bas->giants++;
528 dev_kfree_skb_any(bcs->skb);
529 bcs->skb = NULL;
530 return;
531 }
443e1f45 532 *__skb_put(bcs->skb, 1) = c;
76bb4685
HL
533}
534
535/* hdlc_flush
536 * drop partial HDLC data packet
537 */
538static inline void hdlc_flush(struct bc_state *bcs)
539{
540 /* clear skb or allocate new if not skipping */
541 if (likely(bcs->skb != NULL))
542 skb_trim(bcs->skb, 0);
543 else if (!bcs->ignore) {
544 if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
545 skb_reserve(bcs->skb, HW_HDR_LEN);
546 else
784d5858 547 dev_err(bcs->cs->dev, "could not allocate skb\n");
76bb4685
HL
548 }
549
550 /* reset packet state */
551 bcs->fcs = PPP_INITFCS;
552}
553
554/* hdlc_done
555 * process completed HDLC data packet
556 */
557static inline void hdlc_done(struct bc_state *bcs)
558{
559 struct sk_buff *procskb;
560
561 if (unlikely(bcs->ignore)) {
562 bcs->ignore--;
563 hdlc_flush(bcs);
564 return;
565 }
566
567 if ((procskb = bcs->skb) == NULL) {
568 /* previous error */
784d5858 569 gig_dbg(DEBUG_ISO, "%s: skb=NULL", __func__);
76bb4685
HL
570 gigaset_rcv_error(NULL, bcs->cs, bcs);
571 } else if (procskb->len < 2) {
784d5858
TS
572 dev_notice(bcs->cs->dev, "received short frame (%d octets)\n",
573 procskb->len);
76bb4685
HL
574 bcs->hw.bas->runts++;
575 gigaset_rcv_error(procskb, bcs->cs, bcs);
576 } else if (bcs->fcs != PPP_GOODFCS) {
784d5858
TS
577 dev_notice(bcs->cs->dev, "frame check error (0x%04x)\n",
578 bcs->fcs);
76bb4685
HL
579 bcs->hw.bas->fcserrs++;
580 gigaset_rcv_error(procskb, bcs->cs, bcs);
581 } else {
582 procskb->len -= 2; /* subtract FCS */
583 procskb->tail -= 2;
784d5858
TS
584 gig_dbg(DEBUG_ISO, "%s: good frame (%d octets)",
585 __func__, procskb->len);
76bb4685 586 dump_bytes(DEBUG_STREAM,
784d5858 587 "rcv data", procskb->data, procskb->len);
76bb4685
HL
588 bcs->hw.bas->goodbytes += procskb->len;
589 gigaset_rcv_skb(procskb, bcs->cs, bcs);
590 }
591
592 if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
593 skb_reserve(bcs->skb, HW_HDR_LEN);
594 else
784d5858 595 dev_err(bcs->cs->dev, "could not allocate skb\n");
76bb4685
HL
596 bcs->fcs = PPP_INITFCS;
597}
598
599/* hdlc_frag
600 * drop HDLC data packet with non-integral last byte
601 */
602static inline void hdlc_frag(struct bc_state *bcs, unsigned inbits)
603{
604 if (unlikely(bcs->ignore)) {
605 bcs->ignore--;
606 hdlc_flush(bcs);
607 return;
608 }
609
784d5858 610 dev_notice(bcs->cs->dev, "received partial byte (%d bits)\n", inbits);
76bb4685
HL
611 bcs->hw.bas->alignerrs++;
612 gigaset_rcv_error(bcs->skb, bcs->cs, bcs);
613
614 if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
615 skb_reserve(bcs->skb, HW_HDR_LEN);
616 else
784d5858 617 dev_err(bcs->cs->dev, "could not allocate skb\n");
76bb4685
HL
618 bcs->fcs = PPP_INITFCS;
619}
620
621/* bit counts lookup table for HDLC bit unstuffing
622 * index: input byte
623 * value: bit 0..3 = number of consecutive '1' bits starting from LSB
624 * bit 4..6 = number of consecutive '1' bits starting from MSB
625 * (replacing 8 by 7 to make it fit; the algorithm won't care)
626 * bit 7 set if there are 5 or more "interior" consecutive '1' bits
627 */
35dc8457 628static const unsigned char bitcounts[256] = {
76bb4685
HL
629 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04,
630 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05,
631 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04,
632 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x80, 0x06,
633 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04,
634 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05,
635 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, 0x80, 0x81, 0x80, 0x07,
637 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x14,
638 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x15,
639 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x14,
640 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x90, 0x16,
641 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x23, 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x24,
642 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x23, 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x25,
643 0x30, 0x31, 0x30, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x31, 0x30, 0x32, 0x30, 0x31, 0x30, 0x34,
644 0x40, 0x41, 0x40, 0x42, 0x40, 0x41, 0x40, 0x43, 0x50, 0x51, 0x50, 0x52, 0x60, 0x61, 0x70, 0x78
645};
646
647/* hdlc_unpack
648 * perform HDLC frame processing (bit unstuffing, flag detection, FCS calculation)
649 * on a sequence of received data bytes (8 bits each, LSB first)
650 * pass on successfully received, complete frames as SKBs via gigaset_rcv_skb
651 * notify of errors via gigaset_rcv_error
652 * tally frames, errors etc. in BC structure counters
653 * parameters:
654 * src received data
655 * count number of received bytes
656 * bcs receiving B channel structure
657 */
658static inline void hdlc_unpack(unsigned char *src, unsigned count,
784d5858 659 struct bc_state *bcs)
76bb4685 660{
d48c7784 661 struct bas_bc_state *ubc = bcs->hw.bas;
76bb4685
HL
662 int inputstate;
663 unsigned seqlen, inbyte, inbits;
664
76bb4685
HL
665 /* load previous state:
666 * inputstate = set of flag bits:
667 * - INS_flag_hunt: no complete opening flag received since connection setup or last abort
668 * - INS_have_data: at least one complete data byte received since last flag
669 * seqlen = number of consecutive '1' bits in last 7 input stream bits (0..7)
670 * inbyte = accumulated partial data byte (if !INS_flag_hunt)
671 * inbits = number of valid bits in inbyte, starting at LSB (0..6)
672 */
673 inputstate = bcs->inputstate;
674 seqlen = ubc->seqlen;
675 inbyte = ubc->inbyte;
676 inbits = ubc->inbits;
677
678 /* bit unstuffing a byte a time
679 * Take your time to understand this; it's straightforward but tedious.
680 * The "bitcounts" lookup table is used to speed up the counting of
681 * leading and trailing '1' bits.
682 */
683 while (count--) {
684 unsigned char c = *src++;
685 unsigned char tabentry = bitcounts[c];
686 unsigned lead1 = tabentry & 0x0f;
687 unsigned trail1 = (tabentry >> 4) & 0x0f;
688
689 seqlen += lead1;
690
691 if (unlikely(inputstate & INS_flag_hunt)) {
692 if (c == PPP_FLAG) {
693 /* flag-in-one */
694 inputstate &= ~(INS_flag_hunt | INS_have_data);
695 inbyte = 0;
696 inbits = 0;
697 } else if (seqlen == 6 && trail1 != 7) {
698 /* flag completed & not followed by abort */
699 inputstate &= ~(INS_flag_hunt | INS_have_data);
700 inbyte = c >> (lead1 + 1);
701 inbits = 7 - lead1;
702 if (trail1 >= 8) {
703 /* interior stuffing: omitting the MSB handles most cases */
704 inbits--;
705 /* correct the incorrectly handled cases individually */
706 switch (c) {
707 case 0xbe:
708 inbyte = 0x3f;
709 break;
710 }
711 }
712 }
713 /* else: continue flag-hunting */
714 } else if (likely(seqlen < 5 && trail1 < 7)) {
715 /* streamlined case: 8 data bits, no stuffing */
716 inbyte |= c << inbits;
717 hdlc_putbyte(inbyte & 0xff, bcs);
718 inputstate |= INS_have_data;
719 inbyte >>= 8;
720 /* inbits unchanged */
721 } else if (likely(seqlen == 6 && inbits == 7 - lead1 &&
722 trail1 + 1 == inbits &&
723 !(inputstate & INS_have_data))) {
724 /* streamlined case: flag idle - state unchanged */
725 } else if (unlikely(seqlen > 6)) {
726 /* abort sequence */
727 ubc->aborts++;
728 hdlc_flush(bcs);
729 inputstate |= INS_flag_hunt;
730 } else if (seqlen == 6) {
731 /* closing flag, including (6 - lead1) '1's and one '0' from inbits */
732 if (inbits > 7 - lead1) {
733 hdlc_frag(bcs, inbits + lead1 - 7);
734 inputstate &= ~INS_have_data;
735 } else {
736 if (inbits < 7 - lead1)
737 ubc->stolen0s ++;
738 if (inputstate & INS_have_data) {
739 hdlc_done(bcs);
740 inputstate &= ~INS_have_data;
741 }
742 }
743
744 if (c == PPP_FLAG) {
745 /* complete flag, LSB overlaps preceding flag */
746 ubc->shared0s ++;
747 inbits = 0;
748 inbyte = 0;
749 } else if (trail1 != 7) {
750 /* remaining bits */
751 inbyte = c >> (lead1 + 1);
752 inbits = 7 - lead1;
753 if (trail1 >= 8) {
754 /* interior stuffing: omitting the MSB handles most cases */
755 inbits--;
756 /* correct the incorrectly handled cases individually */
757 switch (c) {
758 case 0xbe:
759 inbyte = 0x3f;
760 break;
761 }
762 }
763 } else {
764 /* abort sequence follows, skb already empty anyway */
765 ubc->aborts++;
766 inputstate |= INS_flag_hunt;
767 }
768 } else { /* (seqlen < 6) && (seqlen == 5 || trail1 >= 7) */
769
770 if (c == PPP_FLAG) {
771 /* complete flag */
772 if (seqlen == 5)
773 ubc->stolen0s++;
774 if (inbits) {
775 hdlc_frag(bcs, inbits);
776 inbits = 0;
777 inbyte = 0;
778 } else if (inputstate & INS_have_data)
779 hdlc_done(bcs);
780 inputstate &= ~INS_have_data;
781 } else if (trail1 == 7) {
782 /* abort sequence */
783 ubc->aborts++;
784 hdlc_flush(bcs);
785 inputstate |= INS_flag_hunt;
786 } else {
787 /* stuffed data */
788 if (trail1 < 7) { /* => seqlen == 5 */
789 /* stuff bit at position lead1, no interior stuffing */
790 unsigned char mask = (1 << lead1) - 1;
791 c = (c & mask) | ((c & ~mask) >> 1);
792 inbyte |= c << inbits;
793 inbits += 7;
794 } else if (seqlen < 5) { /* trail1 >= 8 */
795 /* interior stuffing: omitting the MSB handles most cases */
796 /* correct the incorrectly handled cases individually */
797 switch (c) {
798 case 0xbe:
799 c = 0x7e;
800 break;
801 }
802 inbyte |= c << inbits;
803 inbits += 7;
804 } else { /* seqlen == 5 && trail1 >= 8 */
805
806 /* stuff bit at lead1 *and* interior stuffing */
807 switch (c) { /* unstuff individually */
808 case 0x7d:
809 c = 0x3f;
810 break;
811 case 0xbe:
812 c = 0x3f;
813 break;
814 case 0x3e:
815 c = 0x1f;
816 break;
817 case 0x7c:
818 c = 0x3e;
819 break;
820 }
821 inbyte |= c << inbits;
822 inbits += 6;
823 }
824 if (inbits >= 8) {
825 inbits -= 8;
826 hdlc_putbyte(inbyte & 0xff, bcs);
827 inputstate |= INS_have_data;
828 inbyte >>= 8;
829 }
830 }
831 }
832 seqlen = trail1 & 7;
833 }
834
835 /* save new state */
836 bcs->inputstate = inputstate;
837 ubc->seqlen = seqlen;
838 ubc->inbyte = inbyte;
839 ubc->inbits = inbits;
840}
841
842/* trans_receive
843 * pass on received USB frame transparently as SKB via gigaset_rcv_skb
844 * invert bytes
845 * tally frames, errors etc. in BC structure counters
846 * parameters:
847 * src received data
848 * count number of received bytes
849 * bcs receiving B channel structure
850 */
851static inline void trans_receive(unsigned char *src, unsigned count,
784d5858 852 struct bc_state *bcs)
76bb4685
HL
853{
854 struct sk_buff *skb;
855 int dobytes;
856 unsigned char *dst;
857
858 if (unlikely(bcs->ignore)) {
859 bcs->ignore--;
860 hdlc_flush(bcs);
861 return;
862 }
863 if (unlikely((skb = bcs->skb) == NULL)) {
864 bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN);
865 if (!skb) {
784d5858 866 dev_err(bcs->cs->dev, "could not allocate skb\n");
76bb4685
HL
867 return;
868 }
869 skb_reserve(skb, HW_HDR_LEN);
870 }
871 bcs->hw.bas->goodbytes += skb->len;
872 dobytes = TRANSBUFSIZE - skb->len;
873 while (count > 0) {
874 dst = skb_put(skb, count < dobytes ? count : dobytes);
875 while (count > 0 && dobytes > 0) {
17b3cff0 876 *dst++ = bitrev8(*src++);
76bb4685
HL
877 count--;
878 dobytes--;
879 }
880 if (dobytes == 0) {
881 gigaset_rcv_skb(skb, bcs->cs, bcs);
882 bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN);
883 if (!skb) {
784d5858
TS
884 dev_err(bcs->cs->dev,
885 "could not allocate skb\n");
76bb4685
HL
886 return;
887 }
888 skb_reserve(bcs->skb, HW_HDR_LEN);
889 dobytes = TRANSBUFSIZE;
890 }
891 }
892}
893
894void gigaset_isoc_receive(unsigned char *src, unsigned count, struct bc_state *bcs)
895{
896 switch (bcs->proto2) {
897 case ISDN_PROTO_L2_HDLC:
898 hdlc_unpack(src, count, bcs);
899 break;
900 default: /* assume transparent */
901 trans_receive(src, count, bcs);
902 }
903}
904
905/* == data input =========================================================== */
906
907static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf)
908{
909 struct cardstate *cs = inbuf->cs;
910 unsigned cbytes = cs->cbytes;
911
912 while (numbytes--) {
913 /* copy next character, check for end of line */
914 switch (cs->respdata[cbytes] = *src++) {
915 case '\r':
916 case '\n':
917 /* end of line */
784d5858
TS
918 gig_dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)",
919 __func__, cbytes);
92ba0ee2
TS
920 if (cbytes >= MAX_RESP_SIZE - 1)
921 dev_warn(cs->dev, "response too large\n");
76bb4685
HL
922 cs->cbytes = cbytes;
923 gigaset_handle_modem_response(cs);
924 cbytes = 0;
925 break;
926 default:
927 /* advance in line buffer, checking for overflow */
928 if (cbytes < MAX_RESP_SIZE - 1)
929 cbytes++;
76bb4685
HL
930 }
931 }
932
933 /* save state */
934 cs->cbytes = cbytes;
935}
936
937
938/* process a block of data received through the control channel
939 */
940void gigaset_isoc_input(struct inbuf_t *inbuf)
941{
942 struct cardstate *cs = inbuf->cs;
943 unsigned tail, head, numbytes;
944 unsigned char *src;
945
9d4bee2b
TS
946 head = inbuf->head;
947 while (head != (tail = inbuf->tail)) {
784d5858 948 gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
76bb4685
HL
949 if (head > tail)
950 tail = RBUFSIZE;
951 src = inbuf->data + head;
952 numbytes = tail - head;
784d5858 953 gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
76bb4685 954
9d4bee2b 955 if (cs->mstate == MS_LOCKED) {
76bb4685 956 gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response",
01371500 957 numbytes, src);
76bb4685
HL
958 gigaset_if_receive(inbuf->cs, src, numbytes);
959 } else {
960 gigaset_dbg_buffer(DEBUG_CMD, "received response",
01371500 961 numbytes, src);
76bb4685
HL
962 cmd_loop(src, numbytes, inbuf);
963 }
964
965 head += numbytes;
966 if (head == RBUFSIZE)
967 head = 0;
784d5858 968 gig_dbg(DEBUG_INTR, "setting head to %u", head);
9d4bee2b 969 inbuf->head = head;
76bb4685
HL
970 }
971}
972
973
974/* == data output ========================================================== */
975
976/* gigaset_send_skb
977 * called by common.c to queue an skb for sending
978 * and start transmission if necessary
979 * parameters:
980 * B Channel control structure
981 * skb
982 * return value:
983 * number of bytes accepted for sending
984 * (skb->len if ok, 0 if out of buffer space)
985 * or error code (< 0, eg. -EINVAL)
986 */
987int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb)
988{
d48c7784 989 int len = skb->len;
69049cc8 990 unsigned long flags;
76bb4685 991
73a88814
TS
992 spin_lock_irqsave(&bcs->cs->lock, flags);
993 if (!bcs->cs->connected) {
994 spin_unlock_irqrestore(&bcs->cs->lock, flags);
995 return -ENODEV;
996 }
997
76bb4685 998 skb_queue_tail(&bcs->squeue, skb);
784d5858
TS
999 gig_dbg(DEBUG_ISO, "%s: skb queued, qlen=%d",
1000 __func__, skb_queue_len(&bcs->squeue));
76bb4685
HL
1001
1002 /* tasklet submits URB if necessary */
73a88814 1003 tasklet_schedule(&bcs->hw.bas->sent_tasklet);
69049cc8 1004 spin_unlock_irqrestore(&bcs->cs->lock, flags);
76bb4685
HL
1005
1006 return len; /* ok so far */
1007}
This page took 0.730573 seconds and 5 git commands to generate.