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