blob: 8667daaa1a82e74eb74af3704ea4021e283c50e6 [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>
17
18/* access methods for isowbuf_t */
19/* ============================ */
20
21/* initialize buffer structure
22 */
23void gigaset_isowbuf_init(struct isowbuf_t *iwb, unsigned char idle)
24{
25 atomic_set(&iwb->read, 0);
26 atomic_set(&iwb->nextread, 0);
27 atomic_set(&iwb->write, 0);
28 atomic_set(&iwb->writesem, 1);
29 iwb->wbits = 0;
30 iwb->idle = idle;
31 memset(iwb->data + BAS_OUTBUFSIZE, idle, BAS_OUTBUFPAD);
32}
33
34/* compute number of bytes which can be appended to buffer
35 * so that there is still room to append a maximum frame of flags
36 */
37static inline int isowbuf_freebytes(struct isowbuf_t *iwb)
38{
39 int read, write, freebytes;
40
41 read = atomic_read(&iwb->read);
42 write = atomic_read(&iwb->write);
43 if ((freebytes = read - write) > 0) {
44 /* no wraparound: need padding space within regular area */
45 return freebytes - BAS_OUTBUFPAD;
46 } else if (read < BAS_OUTBUFPAD) {
47 /* wraparound: can use space up to end of regular area */
48 return BAS_OUTBUFSIZE - write;
49 } else {
50 /* following the wraparound yields more space */
51 return freebytes + BAS_OUTBUFSIZE - BAS_OUTBUFPAD;
52 }
53}
54
55/* compare two offsets within the buffer
56 * The buffer is seen as circular, with the read position as start
57 * returns -1/0/1 if position a </=/> position b without crossing 'read'
58 */
59static inline int isowbuf_poscmp(struct isowbuf_t *iwb, int a, int b)
60{
61 int read;
62 if (a == b)
63 return 0;
64 read = atomic_read(&iwb->read);
65 if (a < b) {
66 if (a < read && read <= b)
67 return +1;
68 else
69 return -1;
70 } else {
71 if (b < read && read <= a)
72 return -1;
73 else
74 return +1;
75 }
76}
77
78/* start writing
79 * acquire the write semaphore
80 * return true if acquired, false if busy
81 */
82static inline int isowbuf_startwrite(struct isowbuf_t *iwb)
83{
84 if (!atomic_dec_and_test(&iwb->writesem)) {
85 atomic_inc(&iwb->writesem);
Tilman Schmidt784d5852006-04-10 22:55:04 -070086 gig_dbg(DEBUG_ISO, "%s: couldn't acquire iso write semaphore",
87 __func__);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -080088 return 0;
89 }
90#ifdef CONFIG_GIGASET_DEBUG
Tilman Schmidt784d5852006-04-10 22:55:04 -070091 gig_dbg(DEBUG_ISO,
92 "%s: acquired iso write semaphore, data[write]=%02x, nbits=%d",
93 __func__, iwb->data[atomic_read(&iwb->write)], iwb->wbits);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -080094#endif
95 return 1;
96}
97
98/* finish writing
99 * release the write semaphore and update the maximum buffer fill level
100 * returns the current write position
101 */
102static inline int isowbuf_donewrite(struct isowbuf_t *iwb)
103{
104 int write = atomic_read(&iwb->write);
105 atomic_inc(&iwb->writesem);
106 return write;
107}
108
109/* append bits to buffer without any checks
110 * - data contains bits to append, starting at LSB
111 * - nbits is number of bits to append (0..24)
112 * must be called with the write semaphore held
113 * If more than nbits bits are set in data, the extraneous bits are set in the
114 * buffer too, but the write position is only advanced by nbits.
115 */
116static inline void isowbuf_putbits(struct isowbuf_t *iwb, u32 data, int nbits)
117{
118 int write = atomic_read(&iwb->write);
119 data <<= iwb->wbits;
120 data |= iwb->data[write];
121 nbits += iwb->wbits;
122 while (nbits >= 8) {
123 iwb->data[write++] = data & 0xff;
124 write %= BAS_OUTBUFSIZE;
125 data >>= 8;
126 nbits -= 8;
127 }
128 iwb->wbits = nbits;
129 iwb->data[write] = data & 0xff;
130 atomic_set(&iwb->write, write);
131}
132
133/* put final flag on HDLC bitstream
134 * also sets the idle fill byte to the correspondingly shifted flag pattern
135 * must be called with the write semaphore held
136 */
137static inline void isowbuf_putflag(struct isowbuf_t *iwb)
138{
139 int write;
140
141 /* add two flags, thus reliably covering one byte */
142 isowbuf_putbits(iwb, 0x7e7e, 8);
143 /* recover the idle flag byte */
144 write = atomic_read(&iwb->write);
145 iwb->idle = iwb->data[write];
Tilman Schmidt784d5852006-04-10 22:55:04 -0700146 gig_dbg(DEBUG_ISO, "idle fill byte %02x", iwb->idle);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800147 /* mask extraneous bits in buffer */
148 iwb->data[write] &= (1 << iwb->wbits) - 1;
149}
150
151/* retrieve a block of bytes for sending
152 * The requested number of bytes is provided as a contiguous block.
153 * If necessary, the frame is filled to the requested number of bytes
154 * with the idle value.
155 * returns offset to frame, < 0 on busy or error
156 */
157int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size)
158{
159 int read, write, limit, src, dst;
160 unsigned char pbyte;
161
162 read = atomic_read(&iwb->nextread);
163 write = atomic_read(&iwb->write);
164 if (likely(read == write)) {
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800165 /* return idle frame */
166 return read < BAS_OUTBUFPAD ?
Tilman Schmidt784d5852006-04-10 22:55:04 -0700167 BAS_OUTBUFSIZE : read - BAS_OUTBUFPAD;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800168 }
169
170 limit = read + size;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700171 gig_dbg(DEBUG_STREAM, "%s: read=%d write=%d limit=%d",
172 __func__, read, write, limit);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800173#ifdef CONFIG_GIGASET_DEBUG
174 if (unlikely(size < 0 || size > BAS_OUTBUFPAD)) {
175 err("invalid size %d", size);
176 return -EINVAL;
177 }
178 src = atomic_read(&iwb->read);
179 if (unlikely(limit > BAS_OUTBUFSIZE + BAS_OUTBUFPAD ||
180 (read < src && limit >= src))) {
181 err("isoc write buffer frame reservation violated");
182 return -EFAULT;
183 }
184#endif
185
186 if (read < write) {
187 /* no wraparound in valid data */
188 if (limit >= write) {
189 /* append idle frame */
190 if (!isowbuf_startwrite(iwb))
191 return -EBUSY;
192 /* write position could have changed */
193 if (limit >= (write = atomic_read(&iwb->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 */
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800215 atomic_set(&iwb->write, limit);
216 }
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 }
235 atomic_set(&iwb->nextread, limit);
236 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];
248 static const char hexdigit[] = "0123456789abcdef";
249 int i = 0;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800250 while (count-- > 0) {
251 if (i > sizeof(dbgline) - 4) {
252 dbgline[i] = '\0';
Tilman Schmidt784d5852006-04-10 22:55:04 -0700253 gig_dbg(level, "%s:%s", tag, dbgline);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800254 i = 0;
255 }
256 c = *bytes++;
257 dbgline[i] = (i && !(i % 12)) ? '-' : ' ';
258 i++;
259 dbgline[i++] = hexdigit[(c >> 4) & 0x0f];
260 dbgline[i++] = hexdigit[c & 0x0f];
261 }
262 dbgline[i] = '\0';
Tilman Schmidt784d5852006-04-10 22:55:04 -0700263 gig_dbg(level, "%s:%s", tag, dbgline);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800264#endif
265}
266
267/*============================================================================*/
268
269/* bytewise HDLC bitstuffing via table lookup
270 * lookup table: 5 subtables for 0..4 preceding consecutive '1' bits
271 * index: 256*(number of preceding '1' bits) + (next byte to stuff)
272 * value: bit 9.. 0 = result bits
273 * bit 12..10 = number of trailing '1' bits in result
274 * bit 14..13 = number of bits added by stuffing
275 */
276static u16 stufftab[5 * 256] = {
277// previous 1s = 0:
278 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
279 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x201f,
280 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
281 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x205f,
282 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
283 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x209f,
284 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
285 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20df,
286 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x048f,
287 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x251f,
288 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x04af,
289 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x255f,
290 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x08c7, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x08cf,
291 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x08d7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x299f,
292 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x0ce7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x0cef,
293 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x10f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x2ddf,
294
295// previous 1s = 1:
296 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x200f,
297 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x202f,
298 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x204f,
299 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x206f,
300 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x208f,
301 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x20af,
302 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x20cf,
303 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20ef,
304 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x250f,
305 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x252f,
306 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x254f,
307 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x256f,
308 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x08c7, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x298f,
309 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x08d7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x29af,
310 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x0ce7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x2dcf,
311 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x10f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x31ef,
312
313// previous 1s = 2:
314 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x2007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x2017,
315 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x2027, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x2037,
316 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x2047, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x2057,
317 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x2067, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x2077,
318 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x2087, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x2097,
319 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x20a7, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x20b7,
320 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x20c7, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x20d7,
321 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x20e7, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20f7,
322 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x2507, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x2517,
323 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x2527, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x2537,
324 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x2547, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x2557,
325 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x2567, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x2577,
326 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x2987, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x2997,
327 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x29a7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x29b7,
328 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x2dc7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x2dd7,
329 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x31e7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x41f7,
330
331// previous 1s = 3:
332 0x0000, 0x0001, 0x0002, 0x2003, 0x0004, 0x0005, 0x0006, 0x200b, 0x0008, 0x0009, 0x000a, 0x2013, 0x000c, 0x000d, 0x000e, 0x201b,
333 0x0010, 0x0011, 0x0012, 0x2023, 0x0014, 0x0015, 0x0016, 0x202b, 0x0018, 0x0019, 0x001a, 0x2033, 0x001c, 0x001d, 0x001e, 0x203b,
334 0x0020, 0x0021, 0x0022, 0x2043, 0x0024, 0x0025, 0x0026, 0x204b, 0x0028, 0x0029, 0x002a, 0x2053, 0x002c, 0x002d, 0x002e, 0x205b,
335 0x0030, 0x0031, 0x0032, 0x2063, 0x0034, 0x0035, 0x0036, 0x206b, 0x0038, 0x0039, 0x003a, 0x2073, 0x003c, 0x003d, 0x203e, 0x207b,
336 0x0040, 0x0041, 0x0042, 0x2083, 0x0044, 0x0045, 0x0046, 0x208b, 0x0048, 0x0049, 0x004a, 0x2093, 0x004c, 0x004d, 0x004e, 0x209b,
337 0x0050, 0x0051, 0x0052, 0x20a3, 0x0054, 0x0055, 0x0056, 0x20ab, 0x0058, 0x0059, 0x005a, 0x20b3, 0x005c, 0x005d, 0x005e, 0x20bb,
338 0x0060, 0x0061, 0x0062, 0x20c3, 0x0064, 0x0065, 0x0066, 0x20cb, 0x0068, 0x0069, 0x006a, 0x20d3, 0x006c, 0x006d, 0x006e, 0x20db,
339 0x0070, 0x0071, 0x0072, 0x20e3, 0x0074, 0x0075, 0x0076, 0x20eb, 0x0078, 0x0079, 0x007a, 0x20f3, 0x207c, 0x207d, 0x20be, 0x40fb,
340 0x0480, 0x0481, 0x0482, 0x2503, 0x0484, 0x0485, 0x0486, 0x250b, 0x0488, 0x0489, 0x048a, 0x2513, 0x048c, 0x048d, 0x048e, 0x251b,
341 0x0490, 0x0491, 0x0492, 0x2523, 0x0494, 0x0495, 0x0496, 0x252b, 0x0498, 0x0499, 0x049a, 0x2533, 0x049c, 0x049d, 0x049e, 0x253b,
342 0x04a0, 0x04a1, 0x04a2, 0x2543, 0x04a4, 0x04a5, 0x04a6, 0x254b, 0x04a8, 0x04a9, 0x04aa, 0x2553, 0x04ac, 0x04ad, 0x04ae, 0x255b,
343 0x04b0, 0x04b1, 0x04b2, 0x2563, 0x04b4, 0x04b5, 0x04b6, 0x256b, 0x04b8, 0x04b9, 0x04ba, 0x2573, 0x04bc, 0x04bd, 0x253e, 0x257b,
344 0x08c0, 0x08c1, 0x08c2, 0x2983, 0x08c4, 0x08c5, 0x08c6, 0x298b, 0x08c8, 0x08c9, 0x08ca, 0x2993, 0x08cc, 0x08cd, 0x08ce, 0x299b,
345 0x08d0, 0x08d1, 0x08d2, 0x29a3, 0x08d4, 0x08d5, 0x08d6, 0x29ab, 0x08d8, 0x08d9, 0x08da, 0x29b3, 0x08dc, 0x08dd, 0x08de, 0x29bb,
346 0x0ce0, 0x0ce1, 0x0ce2, 0x2dc3, 0x0ce4, 0x0ce5, 0x0ce6, 0x2dcb, 0x0ce8, 0x0ce9, 0x0cea, 0x2dd3, 0x0cec, 0x0ced, 0x0cee, 0x2ddb,
347 0x10f0, 0x10f1, 0x10f2, 0x31e3, 0x10f4, 0x10f5, 0x10f6, 0x31eb, 0x20f8, 0x20f9, 0x20fa, 0x41f3, 0x257c, 0x257d, 0x29be, 0x46fb,
348
349// previous 1s = 4:
350 0x0000, 0x2001, 0x0002, 0x2005, 0x0004, 0x2009, 0x0006, 0x200d, 0x0008, 0x2011, 0x000a, 0x2015, 0x000c, 0x2019, 0x000e, 0x201d,
351 0x0010, 0x2021, 0x0012, 0x2025, 0x0014, 0x2029, 0x0016, 0x202d, 0x0018, 0x2031, 0x001a, 0x2035, 0x001c, 0x2039, 0x001e, 0x203d,
352 0x0020, 0x2041, 0x0022, 0x2045, 0x0024, 0x2049, 0x0026, 0x204d, 0x0028, 0x2051, 0x002a, 0x2055, 0x002c, 0x2059, 0x002e, 0x205d,
353 0x0030, 0x2061, 0x0032, 0x2065, 0x0034, 0x2069, 0x0036, 0x206d, 0x0038, 0x2071, 0x003a, 0x2075, 0x003c, 0x2079, 0x203e, 0x407d,
354 0x0040, 0x2081, 0x0042, 0x2085, 0x0044, 0x2089, 0x0046, 0x208d, 0x0048, 0x2091, 0x004a, 0x2095, 0x004c, 0x2099, 0x004e, 0x209d,
355 0x0050, 0x20a1, 0x0052, 0x20a5, 0x0054, 0x20a9, 0x0056, 0x20ad, 0x0058, 0x20b1, 0x005a, 0x20b5, 0x005c, 0x20b9, 0x005e, 0x20bd,
356 0x0060, 0x20c1, 0x0062, 0x20c5, 0x0064, 0x20c9, 0x0066, 0x20cd, 0x0068, 0x20d1, 0x006a, 0x20d5, 0x006c, 0x20d9, 0x006e, 0x20dd,
357 0x0070, 0x20e1, 0x0072, 0x20e5, 0x0074, 0x20e9, 0x0076, 0x20ed, 0x0078, 0x20f1, 0x007a, 0x20f5, 0x207c, 0x40f9, 0x20be, 0x417d,
358 0x0480, 0x2501, 0x0482, 0x2505, 0x0484, 0x2509, 0x0486, 0x250d, 0x0488, 0x2511, 0x048a, 0x2515, 0x048c, 0x2519, 0x048e, 0x251d,
359 0x0490, 0x2521, 0x0492, 0x2525, 0x0494, 0x2529, 0x0496, 0x252d, 0x0498, 0x2531, 0x049a, 0x2535, 0x049c, 0x2539, 0x049e, 0x253d,
360 0x04a0, 0x2541, 0x04a2, 0x2545, 0x04a4, 0x2549, 0x04a6, 0x254d, 0x04a8, 0x2551, 0x04aa, 0x2555, 0x04ac, 0x2559, 0x04ae, 0x255d,
361 0x04b0, 0x2561, 0x04b2, 0x2565, 0x04b4, 0x2569, 0x04b6, 0x256d, 0x04b8, 0x2571, 0x04ba, 0x2575, 0x04bc, 0x2579, 0x253e, 0x467d,
362 0x08c0, 0x2981, 0x08c2, 0x2985, 0x08c4, 0x2989, 0x08c6, 0x298d, 0x08c8, 0x2991, 0x08ca, 0x2995, 0x08cc, 0x2999, 0x08ce, 0x299d,
363 0x08d0, 0x29a1, 0x08d2, 0x29a5, 0x08d4, 0x29a9, 0x08d6, 0x29ad, 0x08d8, 0x29b1, 0x08da, 0x29b5, 0x08dc, 0x29b9, 0x08de, 0x29bd,
364 0x0ce0, 0x2dc1, 0x0ce2, 0x2dc5, 0x0ce4, 0x2dc9, 0x0ce6, 0x2dcd, 0x0ce8, 0x2dd1, 0x0cea, 0x2dd5, 0x0cec, 0x2dd9, 0x0cee, 0x2ddd,
365 0x10f0, 0x31e1, 0x10f2, 0x31e5, 0x10f4, 0x31e9, 0x10f6, 0x31ed, 0x20f8, 0x41f1, 0x20fa, 0x41f5, 0x257c, 0x46f9, 0x29be, 0x4b7d
366};
367
368/* hdlc_bitstuff_byte
369 * perform HDLC bitstuffing for one input byte (8 bits, LSB first)
370 * parameters:
371 * cin input byte
372 * ones number of trailing '1' bits in result before this step
373 * iwb pointer to output buffer structure (write semaphore must be held)
374 * return value:
375 * number of trailing '1' bits in result after this step
376 */
377
378static inline int hdlc_bitstuff_byte(struct isowbuf_t *iwb, unsigned char cin,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700379 int ones)
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800380{
381 u16 stuff;
382 int shiftinc, newones;
383
384 /* get stuffing information for input byte
385 * value: bit 9.. 0 = result bits
386 * bit 12..10 = number of trailing '1' bits in result
387 * bit 14..13 = number of bits added by stuffing
388 */
389 stuff = stufftab[256 * ones + cin];
390 shiftinc = (stuff >> 13) & 3;
391 newones = (stuff >> 10) & 7;
392 stuff &= 0x3ff;
393
394 /* append stuffed byte to output stream */
395 isowbuf_putbits(iwb, stuff, 8 + shiftinc);
396 return newones;
397}
398
399/* hdlc_buildframe
400 * Perform HDLC framing with bitstuffing on a byte buffer
401 * The input buffer is regarded as a sequence of bits, starting with the least
402 * significant bit of the first byte and ending with the most significant bit
403 * of the last byte. A 16 bit FCS is appended as defined by RFC 1662.
404 * Whenever five consecutive '1' bits appear in the resulting bit sequence, a
405 * '0' bit is inserted after them.
406 * The resulting bit string and a closing flag pattern (PPP_FLAG, '01111110')
407 * are appended to the output buffer starting at the given bit position, which
408 * is assumed to already contain a leading flag.
409 * The output buffer must have sufficient length; count + count/5 + 6 bytes
410 * starting at *out are safe and are verified to be present.
411 * parameters:
412 * in input buffer
413 * count number of bytes in input buffer
414 * iwb pointer to output buffer structure (write semaphore must be held)
415 * return value:
416 * position of end of packet in output buffer on success,
417 * -EAGAIN if write semaphore busy or buffer full
418 */
419
420static inline int hdlc_buildframe(struct isowbuf_t *iwb,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700421 unsigned char *in, int count)
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800422{
423 int ones;
424 u16 fcs;
425 int end;
426 unsigned char c;
427
428 if (isowbuf_freebytes(iwb) < count + count / 5 + 6 ||
429 !isowbuf_startwrite(iwb)) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700430 gig_dbg(DEBUG_ISO, "%s: %d bytes free -> -EAGAIN",
431 __func__, isowbuf_freebytes(iwb));
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800432 return -EAGAIN;
433 }
434
435 dump_bytes(DEBUG_STREAM, "snd data", in, count);
436
437 /* bitstuff and checksum input data */
438 fcs = PPP_INITFCS;
439 ones = 0;
440 while (count-- > 0) {
441 c = *in++;
442 ones = hdlc_bitstuff_byte(iwb, c, ones);
443 fcs = crc_ccitt_byte(fcs, c);
444 }
445
446 /* bitstuff and append FCS (complemented, least significant byte first) */
447 fcs ^= 0xffff;
448 ones = hdlc_bitstuff_byte(iwb, fcs & 0x00ff, ones);
449 ones = hdlc_bitstuff_byte(iwb, (fcs >> 8) & 0x00ff, ones);
450
451 /* put closing flag and repeat byte for flag idle */
452 isowbuf_putflag(iwb);
453 end = isowbuf_donewrite(iwb);
454 dump_bytes(DEBUG_STREAM_DUMP, "isowbuf", iwb->data, end + 1);
455 return end;
456}
457
458/* trans_buildframe
459 * Append a block of 'transparent' data to the output buffer,
460 * inverting the bytes.
461 * The output buffer must have sufficient length; count bytes
462 * starting at *out are safe and are verified to be present.
463 * parameters:
464 * in input buffer
465 * count number of bytes in input buffer
466 * iwb pointer to output buffer structure (write semaphore must be held)
467 * return value:
468 * position of end of packet in output buffer on success,
469 * -EAGAIN if write semaphore busy or buffer full
470 */
471
472static inline int trans_buildframe(struct isowbuf_t *iwb,
473 unsigned char *in, int count)
474{
475 int write;
476 unsigned char c;
477
478 if (unlikely(count <= 0))
479 return atomic_read(&iwb->write); /* better ideas? */
480
481 if (isowbuf_freebytes(iwb) < count ||
482 !isowbuf_startwrite(iwb)) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700483 gig_dbg(DEBUG_ISO, "can't put %d bytes", count);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800484 return -EAGAIN;
485 }
486
Tilman Schmidt784d5852006-04-10 22:55:04 -0700487 gig_dbg(DEBUG_STREAM, "put %d bytes", count);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800488 write = atomic_read(&iwb->write);
489 do {
490 c = gigaset_invtab[*in++];
491 iwb->data[write++] = c;
492 write %= BAS_OUTBUFSIZE;
493 } while (--count > 0);
494 atomic_set(&iwb->write, write);
495 iwb->idle = c;
496
497 return isowbuf_donewrite(iwb);
498}
499
500int gigaset_isoc_buildframe(struct bc_state *bcs, unsigned char *in, int len)
501{
502 int result;
503
504 switch (bcs->proto2) {
505 case ISDN_PROTO_L2_HDLC:
506 result = hdlc_buildframe(bcs->hw.bas->isooutbuf, in, len);
Tilman Schmidt784d5852006-04-10 22:55:04 -0700507 gig_dbg(DEBUG_ISO, "%s: %d bytes HDLC -> %d",
508 __func__, len, result);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800509 break;
510 default: /* assume transparent */
511 result = trans_buildframe(bcs->hw.bas->isooutbuf, in, len);
Tilman Schmidt784d5852006-04-10 22:55:04 -0700512 gig_dbg(DEBUG_ISO, "%s: %d bytes trans -> %d",
513 __func__, len, result);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800514 }
515 return result;
516}
517
518/* hdlc_putbyte
519 * append byte c to current skb of B channel structure *bcs, updating fcs
520 */
521static inline void hdlc_putbyte(unsigned char c, struct bc_state *bcs)
522{
523 bcs->fcs = crc_ccitt_byte(bcs->fcs, c);
524 if (unlikely(bcs->skb == NULL)) {
525 /* skipping */
526 return;
527 }
528 if (unlikely(bcs->skb->len == SBUFSIZE)) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700529 dev_warn(bcs->cs->dev, "received oversized packet discarded\n");
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800530 bcs->hw.bas->giants++;
531 dev_kfree_skb_any(bcs->skb);
532 bcs->skb = NULL;
533 return;
534 }
Tilman Schmidt443e1f42006-04-10 22:55:13 -0700535 *__skb_put(bcs->skb, 1) = c;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800536}
537
538/* hdlc_flush
539 * drop partial HDLC data packet
540 */
541static inline void hdlc_flush(struct bc_state *bcs)
542{
543 /* clear skb or allocate new if not skipping */
544 if (likely(bcs->skb != NULL))
545 skb_trim(bcs->skb, 0);
546 else if (!bcs->ignore) {
547 if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
548 skb_reserve(bcs->skb, HW_HDR_LEN);
549 else
Tilman Schmidt784d5852006-04-10 22:55:04 -0700550 dev_err(bcs->cs->dev, "could not allocate skb\n");
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800551 }
552
553 /* reset packet state */
554 bcs->fcs = PPP_INITFCS;
555}
556
557/* hdlc_done
558 * process completed HDLC data packet
559 */
560static inline void hdlc_done(struct bc_state *bcs)
561{
562 struct sk_buff *procskb;
563
564 if (unlikely(bcs->ignore)) {
565 bcs->ignore--;
566 hdlc_flush(bcs);
567 return;
568 }
569
570 if ((procskb = bcs->skb) == NULL) {
571 /* previous error */
Tilman Schmidt784d5852006-04-10 22:55:04 -0700572 gig_dbg(DEBUG_ISO, "%s: skb=NULL", __func__);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800573 gigaset_rcv_error(NULL, bcs->cs, bcs);
574 } else if (procskb->len < 2) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700575 dev_notice(bcs->cs->dev, "received short frame (%d octets)\n",
576 procskb->len);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800577 bcs->hw.bas->runts++;
578 gigaset_rcv_error(procskb, bcs->cs, bcs);
579 } else if (bcs->fcs != PPP_GOODFCS) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700580 dev_notice(bcs->cs->dev, "frame check error (0x%04x)\n",
581 bcs->fcs);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800582 bcs->hw.bas->fcserrs++;
583 gigaset_rcv_error(procskb, bcs->cs, bcs);
584 } else {
585 procskb->len -= 2; /* subtract FCS */
586 procskb->tail -= 2;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700587 gig_dbg(DEBUG_ISO, "%s: good frame (%d octets)",
588 __func__, procskb->len);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800589 dump_bytes(DEBUG_STREAM,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700590 "rcv data", procskb->data, procskb->len);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800591 bcs->hw.bas->goodbytes += procskb->len;
592 gigaset_rcv_skb(procskb, bcs->cs, bcs);
593 }
594
595 if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
596 skb_reserve(bcs->skb, HW_HDR_LEN);
597 else
Tilman Schmidt784d5852006-04-10 22:55:04 -0700598 dev_err(bcs->cs->dev, "could not allocate skb\n");
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800599 bcs->fcs = PPP_INITFCS;
600}
601
602/* hdlc_frag
603 * drop HDLC data packet with non-integral last byte
604 */
605static inline void hdlc_frag(struct bc_state *bcs, unsigned inbits)
606{
607 if (unlikely(bcs->ignore)) {
608 bcs->ignore--;
609 hdlc_flush(bcs);
610 return;
611 }
612
Tilman Schmidt784d5852006-04-10 22:55:04 -0700613 dev_notice(bcs->cs->dev, "received partial byte (%d bits)\n", inbits);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800614 bcs->hw.bas->alignerrs++;
615 gigaset_rcv_error(bcs->skb, bcs->cs, bcs);
616
617 if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)
618 skb_reserve(bcs->skb, HW_HDR_LEN);
619 else
Tilman Schmidt784d5852006-04-10 22:55:04 -0700620 dev_err(bcs->cs->dev, "could not allocate skb\n");
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800621 bcs->fcs = PPP_INITFCS;
622}
623
624/* bit counts lookup table for HDLC bit unstuffing
625 * index: input byte
626 * value: bit 0..3 = number of consecutive '1' bits starting from LSB
627 * bit 4..6 = number of consecutive '1' bits starting from MSB
628 * (replacing 8 by 7 to make it fit; the algorithm won't care)
629 * bit 7 set if there are 5 or more "interior" consecutive '1' bits
630 */
631static unsigned char bitcounts[256] = {
632 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04,
633 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05,
634 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04,
635 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x80, 0x06,
636 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04,
637 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05,
638 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04,
639 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x80, 0x81, 0x80, 0x07,
640 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x14,
641 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x15,
642 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x14,
643 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x90, 0x16,
644 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x23, 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x24,
645 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x23, 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x25,
646 0x30, 0x31, 0x30, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x31, 0x30, 0x32, 0x30, 0x31, 0x30, 0x34,
647 0x40, 0x41, 0x40, 0x42, 0x40, 0x41, 0x40, 0x43, 0x50, 0x51, 0x50, 0x52, 0x60, 0x61, 0x70, 0x78
648};
649
650/* hdlc_unpack
651 * perform HDLC frame processing (bit unstuffing, flag detection, FCS calculation)
652 * on a sequence of received data bytes (8 bits each, LSB first)
653 * pass on successfully received, complete frames as SKBs via gigaset_rcv_skb
654 * notify of errors via gigaset_rcv_error
655 * tally frames, errors etc. in BC structure counters
656 * parameters:
657 * src received data
658 * count number of received bytes
659 * bcs receiving B channel structure
660 */
661static inline void hdlc_unpack(unsigned char *src, unsigned count,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700662 struct bc_state *bcs)
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800663{
Tilman Schmidtd48c7782006-04-10 22:55:08 -0700664 struct bas_bc_state *ubc = bcs->hw.bas;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800665 int inputstate;
666 unsigned seqlen, inbyte, inbits;
667
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800668 /* load previous state:
669 * inputstate = set of flag bits:
670 * - INS_flag_hunt: no complete opening flag received since connection setup or last abort
671 * - INS_have_data: at least one complete data byte received since last flag
672 * seqlen = number of consecutive '1' bits in last 7 input stream bits (0..7)
673 * inbyte = accumulated partial data byte (if !INS_flag_hunt)
674 * inbits = number of valid bits in inbyte, starting at LSB (0..6)
675 */
676 inputstate = bcs->inputstate;
677 seqlen = ubc->seqlen;
678 inbyte = ubc->inbyte;
679 inbits = ubc->inbits;
680
681 /* bit unstuffing a byte a time
682 * Take your time to understand this; it's straightforward but tedious.
683 * The "bitcounts" lookup table is used to speed up the counting of
684 * leading and trailing '1' bits.
685 */
686 while (count--) {
687 unsigned char c = *src++;
688 unsigned char tabentry = bitcounts[c];
689 unsigned lead1 = tabentry & 0x0f;
690 unsigned trail1 = (tabentry >> 4) & 0x0f;
691
692 seqlen += lead1;
693
694 if (unlikely(inputstate & INS_flag_hunt)) {
695 if (c == PPP_FLAG) {
696 /* flag-in-one */
697 inputstate &= ~(INS_flag_hunt | INS_have_data);
698 inbyte = 0;
699 inbits = 0;
700 } else if (seqlen == 6 && trail1 != 7) {
701 /* flag completed & not followed by abort */
702 inputstate &= ~(INS_flag_hunt | INS_have_data);
703 inbyte = c >> (lead1 + 1);
704 inbits = 7 - lead1;
705 if (trail1 >= 8) {
706 /* interior stuffing: omitting the MSB handles most cases */
707 inbits--;
708 /* correct the incorrectly handled cases individually */
709 switch (c) {
710 case 0xbe:
711 inbyte = 0x3f;
712 break;
713 }
714 }
715 }
716 /* else: continue flag-hunting */
717 } else if (likely(seqlen < 5 && trail1 < 7)) {
718 /* streamlined case: 8 data bits, no stuffing */
719 inbyte |= c << inbits;
720 hdlc_putbyte(inbyte & 0xff, bcs);
721 inputstate |= INS_have_data;
722 inbyte >>= 8;
723 /* inbits unchanged */
724 } else if (likely(seqlen == 6 && inbits == 7 - lead1 &&
725 trail1 + 1 == inbits &&
726 !(inputstate & INS_have_data))) {
727 /* streamlined case: flag idle - state unchanged */
728 } else if (unlikely(seqlen > 6)) {
729 /* abort sequence */
730 ubc->aborts++;
731 hdlc_flush(bcs);
732 inputstate |= INS_flag_hunt;
733 } else if (seqlen == 6) {
734 /* closing flag, including (6 - lead1) '1's and one '0' from inbits */
735 if (inbits > 7 - lead1) {
736 hdlc_frag(bcs, inbits + lead1 - 7);
737 inputstate &= ~INS_have_data;
738 } else {
739 if (inbits < 7 - lead1)
740 ubc->stolen0s ++;
741 if (inputstate & INS_have_data) {
742 hdlc_done(bcs);
743 inputstate &= ~INS_have_data;
744 }
745 }
746
747 if (c == PPP_FLAG) {
748 /* complete flag, LSB overlaps preceding flag */
749 ubc->shared0s ++;
750 inbits = 0;
751 inbyte = 0;
752 } else if (trail1 != 7) {
753 /* remaining bits */
754 inbyte = c >> (lead1 + 1);
755 inbits = 7 - lead1;
756 if (trail1 >= 8) {
757 /* interior stuffing: omitting the MSB handles most cases */
758 inbits--;
759 /* correct the incorrectly handled cases individually */
760 switch (c) {
761 case 0xbe:
762 inbyte = 0x3f;
763 break;
764 }
765 }
766 } else {
767 /* abort sequence follows, skb already empty anyway */
768 ubc->aborts++;
769 inputstate |= INS_flag_hunt;
770 }
771 } else { /* (seqlen < 6) && (seqlen == 5 || trail1 >= 7) */
772
773 if (c == PPP_FLAG) {
774 /* complete flag */
775 if (seqlen == 5)
776 ubc->stolen0s++;
777 if (inbits) {
778 hdlc_frag(bcs, inbits);
779 inbits = 0;
780 inbyte = 0;
781 } else if (inputstate & INS_have_data)
782 hdlc_done(bcs);
783 inputstate &= ~INS_have_data;
784 } else if (trail1 == 7) {
785 /* abort sequence */
786 ubc->aborts++;
787 hdlc_flush(bcs);
788 inputstate |= INS_flag_hunt;
789 } else {
790 /* stuffed data */
791 if (trail1 < 7) { /* => seqlen == 5 */
792 /* stuff bit at position lead1, no interior stuffing */
793 unsigned char mask = (1 << lead1) - 1;
794 c = (c & mask) | ((c & ~mask) >> 1);
795 inbyte |= c << inbits;
796 inbits += 7;
797 } else if (seqlen < 5) { /* trail1 >= 8 */
798 /* interior stuffing: omitting the MSB handles most cases */
799 /* correct the incorrectly handled cases individually */
800 switch (c) {
801 case 0xbe:
802 c = 0x7e;
803 break;
804 }
805 inbyte |= c << inbits;
806 inbits += 7;
807 } else { /* seqlen == 5 && trail1 >= 8 */
808
809 /* stuff bit at lead1 *and* interior stuffing */
810 switch (c) { /* unstuff individually */
811 case 0x7d:
812 c = 0x3f;
813 break;
814 case 0xbe:
815 c = 0x3f;
816 break;
817 case 0x3e:
818 c = 0x1f;
819 break;
820 case 0x7c:
821 c = 0x3e;
822 break;
823 }
824 inbyte |= c << inbits;
825 inbits += 6;
826 }
827 if (inbits >= 8) {
828 inbits -= 8;
829 hdlc_putbyte(inbyte & 0xff, bcs);
830 inputstate |= INS_have_data;
831 inbyte >>= 8;
832 }
833 }
834 }
835 seqlen = trail1 & 7;
836 }
837
838 /* save new state */
839 bcs->inputstate = inputstate;
840 ubc->seqlen = seqlen;
841 ubc->inbyte = inbyte;
842 ubc->inbits = inbits;
843}
844
845/* trans_receive
846 * pass on received USB frame transparently as SKB via gigaset_rcv_skb
847 * invert bytes
848 * tally frames, errors etc. in BC structure counters
849 * parameters:
850 * src received data
851 * count number of received bytes
852 * bcs receiving B channel structure
853 */
854static inline void trans_receive(unsigned char *src, unsigned count,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700855 struct bc_state *bcs)
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800856{
857 struct sk_buff *skb;
858 int dobytes;
859 unsigned char *dst;
860
861 if (unlikely(bcs->ignore)) {
862 bcs->ignore--;
863 hdlc_flush(bcs);
864 return;
865 }
866 if (unlikely((skb = bcs->skb) == NULL)) {
867 bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN);
868 if (!skb) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700869 dev_err(bcs->cs->dev, "could not allocate skb\n");
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800870 return;
871 }
872 skb_reserve(skb, HW_HDR_LEN);
873 }
874 bcs->hw.bas->goodbytes += skb->len;
875 dobytes = TRANSBUFSIZE - skb->len;
876 while (count > 0) {
877 dst = skb_put(skb, count < dobytes ? count : dobytes);
878 while (count > 0 && dobytes > 0) {
879 *dst++ = gigaset_invtab[*src++];
880 count--;
881 dobytes--;
882 }
883 if (dobytes == 0) {
884 gigaset_rcv_skb(skb, bcs->cs, bcs);
885 bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN);
886 if (!skb) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700887 dev_err(bcs->cs->dev,
888 "could not allocate skb\n");
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800889 return;
890 }
891 skb_reserve(bcs->skb, HW_HDR_LEN);
892 dobytes = TRANSBUFSIZE;
893 }
894 }
895}
896
897void gigaset_isoc_receive(unsigned char *src, unsigned count, struct bc_state *bcs)
898{
899 switch (bcs->proto2) {
900 case ISDN_PROTO_L2_HDLC:
901 hdlc_unpack(src, count, bcs);
902 break;
903 default: /* assume transparent */
904 trans_receive(src, count, bcs);
905 }
906}
907
908/* == data input =========================================================== */
909
910static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf)
911{
912 struct cardstate *cs = inbuf->cs;
913 unsigned cbytes = cs->cbytes;
914
915 while (numbytes--) {
916 /* copy next character, check for end of line */
917 switch (cs->respdata[cbytes] = *src++) {
918 case '\r':
919 case '\n':
920 /* end of line */
Tilman Schmidt784d5852006-04-10 22:55:04 -0700921 gig_dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)",
922 __func__, cbytes);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800923 cs->cbytes = cbytes;
924 gigaset_handle_modem_response(cs);
925 cbytes = 0;
926 break;
927 default:
928 /* advance in line buffer, checking for overflow */
929 if (cbytes < MAX_RESP_SIZE - 1)
930 cbytes++;
931 else
Tilman Schmidt784d5852006-04-10 22:55:04 -0700932 dev_warn(cs->dev, "response too large\n");
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800933 }
934 }
935
936 /* save state */
937 cs->cbytes = cbytes;
938}
939
940
941/* process a block of data received through the control channel
942 */
943void gigaset_isoc_input(struct inbuf_t *inbuf)
944{
945 struct cardstate *cs = inbuf->cs;
946 unsigned tail, head, numbytes;
947 unsigned char *src;
948
949 head = atomic_read(&inbuf->head);
950 while (head != (tail = atomic_read(&inbuf->tail))) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700951 gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800952 if (head > tail)
953 tail = RBUFSIZE;
954 src = inbuf->data + head;
955 numbytes = tail - head;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700956 gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800957
958 if (atomic_read(&cs->mstate) == MS_LOCKED) {
959 gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response",
Tilman Schmidt01371502006-04-10 22:55:11 -0700960 numbytes, src);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800961 gigaset_if_receive(inbuf->cs, src, numbytes);
962 } else {
963 gigaset_dbg_buffer(DEBUG_CMD, "received response",
Tilman Schmidt01371502006-04-10 22:55:11 -0700964 numbytes, src);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800965 cmd_loop(src, numbytes, inbuf);
966 }
967
968 head += numbytes;
969 if (head == RBUFSIZE)
970 head = 0;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700971 gig_dbg(DEBUG_INTR, "setting head to %u", head);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800972 atomic_set(&inbuf->head, head);
973 }
974}
975
976
977/* == data output ========================================================== */
978
979/* gigaset_send_skb
980 * called by common.c to queue an skb for sending
981 * and start transmission if necessary
982 * parameters:
983 * B Channel control structure
984 * skb
985 * return value:
986 * number of bytes accepted for sending
987 * (skb->len if ok, 0 if out of buffer space)
988 * or error code (< 0, eg. -EINVAL)
989 */
990int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb)
991{
Tilman Schmidtd48c7782006-04-10 22:55:08 -0700992 int len = skb->len;
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700993 unsigned long flags;
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -0800994
Tilman Schmidt73a88812006-04-22 02:35:30 -0700995 spin_lock_irqsave(&bcs->cs->lock, flags);
996 if (!bcs->cs->connected) {
997 spin_unlock_irqrestore(&bcs->cs->lock, flags);
998 return -ENODEV;
999 }
1000
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -08001001 skb_queue_tail(&bcs->squeue, skb);
Tilman Schmidt784d5852006-04-10 22:55:04 -07001002 gig_dbg(DEBUG_ISO, "%s: skb queued, qlen=%d",
1003 __func__, skb_queue_len(&bcs->squeue));
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -08001004
1005 /* tasklet submits URB if necessary */
Tilman Schmidt73a88812006-04-22 02:35:30 -07001006 tasklet_schedule(&bcs->hw.bas->sent_tasklet);
Tilman Schmidt69049cc2006-04-10 22:55:16 -07001007 spin_unlock_irqrestore(&bcs->cs->lock, flags);
Hansjoerg Lipp76bb4682006-03-26 01:38:36 -08001008
1009 return len; /* ok so far */
1010}