Merge branch 'linux-next' of git://git.infradead.org/ubi-2.6
[linux-block.git] / drivers / isdn / gigaset / asyncdata.c
CommitLineData
07dc1f9f
HL
1/*
2 * Common data handling layer for ser_gigaset and usb_gigaset
3 *
4 * Copyright (c) 2005 by Tilman Schmidt <tilman@imap.cc>,
5 * Hansjoerg Lipp <hjlipp@web.de>,
70440cf2 6 * Stefan Eilers.
07dc1f9f
HL
7 *
8 * =====================================================================
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
13 * =====================================================================
07dc1f9f
HL
14 */
15
16#include "gigaset.h"
17#include <linux/crc-ccitt.h>
17b3cff0 18#include <linux/bitrev.h>
07dc1f9f 19
07dc1f9f
HL
20/* check if byte must be stuffed/escaped
21 * I'm not sure which data should be encoded.
22 * Therefore I will go the hard way and decode every value
23 * less than 0x20, the flag sequence and the control escape char.
24 */
25static inline int muststuff(unsigned char c)
26{
27 if (c < PPP_TRANS) return 1;
28 if (c == PPP_FLAG) return 1;
29 if (c == PPP_ESCAPE) return 1;
30 /* other possible candidates: */
31 /* 0x91: XON with parity set */
32 /* 0x93: XOFF with parity set */
33 return 0;
34}
35
36/* == data input =========================================================== */
37
38/* process a block of received bytes in command mode (modem response)
39 * Return value:
40 * number of processed bytes
41 */
42static inline int cmd_loop(unsigned char c, unsigned char *src, int numbytes,
784d5858 43 struct inbuf_t *inbuf)
07dc1f9f
HL
44{
45 struct cardstate *cs = inbuf->cs;
46 unsigned cbytes = cs->cbytes;
47 int inputstate = inbuf->inputstate;
48 int startbytes = numbytes;
49
50 for (;;) {
51 cs->respdata[cbytes] = c;
52 if (c == 10 || c == 13) {
784d5858
TS
53 gig_dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)",
54 __func__, cbytes);
07dc1f9f 55 cs->cbytes = cbytes;
917f5085
TS
56 gigaset_handle_modem_response(cs); /* can change
57 cs->dle */
07dc1f9f
HL
58 cbytes = 0;
59
60 if (cs->dle &&
61 !(inputstate & INS_DLE_command)) {
62 inputstate &= ~INS_command;
63 break;
64 }
65 } else {
66 /* advance in line buffer, checking for overflow */
67 if (cbytes < MAX_RESP_SIZE - 1)
68 cbytes++;
69 else
784d5858 70 dev_warn(cs->dev, "response too large\n");
07dc1f9f
HL
71 }
72
73 if (!numbytes)
74 break;
75 c = *src++;
76 --numbytes;
77 if (c == DLE_FLAG &&
78 (cs->dle || inputstate & INS_DLE_command)) {
79 inputstate |= INS_DLE_char;
80 break;
81 }
82 }
83
84 cs->cbytes = cbytes;
85 inbuf->inputstate = inputstate;
86
87 return startbytes - numbytes;
88}
89
90/* process a block of received bytes in lock mode (tty i/f)
91 * Return value:
92 * number of processed bytes
93 */
94static inline int lock_loop(unsigned char *src, int numbytes,
784d5858 95 struct inbuf_t *inbuf)
07dc1f9f
HL
96{
97 struct cardstate *cs = inbuf->cs;
98
917f5085 99 gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response",
01371500 100 numbytes, src);
07dc1f9f
HL
101 gigaset_if_receive(cs, src, numbytes);
102
103 return numbytes;
104}
105
106/* process a block of received bytes in HDLC data mode
107 * Collect HDLC frames, undoing byte stuffing and watching for DLE escapes.
108 * When a frame is complete, check the FCS and pass valid frames to the LL.
109 * If DLE is encountered, return immediately to let the caller handle it.
110 * Return value:
111 * number of processed bytes
112 * numbytes (all bytes processed) on error --FIXME
113 */
114static inline int hdlc_loop(unsigned char c, unsigned char *src, int numbytes,
784d5858 115 struct inbuf_t *inbuf)
07dc1f9f
HL
116{
117 struct cardstate *cs = inbuf->cs;
118 struct bc_state *bcs = inbuf->bcs;
d48c7784
TS
119 int inputstate = bcs->inputstate;
120 __u16 fcs = bcs->fcs;
121 struct sk_buff *skb = bcs->skb;
07dc1f9f
HL
122 unsigned char error;
123 struct sk_buff *compskb;
124 int startbytes = numbytes;
125 int l;
126
07dc1f9f
HL
127 if (unlikely(inputstate & INS_byte_stuff)) {
128 inputstate &= ~INS_byte_stuff;
129 goto byte_stuff;
130 }
131 for (;;) {
132 if (unlikely(c == PPP_ESCAPE)) {
133 if (unlikely(!numbytes)) {
134 inputstate |= INS_byte_stuff;
135 break;
136 }
137 c = *src++;
138 --numbytes;
139 if (unlikely(c == DLE_FLAG &&
140 (cs->dle ||
141 inbuf->inputstate & INS_DLE_command))) {
142 inbuf->inputstate |= INS_DLE_char;
143 inputstate |= INS_byte_stuff;
144 break;
145 }
146byte_stuff:
147 c ^= PPP_TRANS;
07dc1f9f 148 if (unlikely(!muststuff(c)))
784d5858 149 gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c);
07dc1f9f
HL
150 } else if (unlikely(c == PPP_FLAG)) {
151 if (unlikely(inputstate & INS_skip_frame)) {
07dc1f9f 152#ifdef CONFIG_GIGASET_DEBUG
236b87c2 153 if (!(inputstate & INS_have_data)) { /* 7E 7E */
07dc1f9f 154 ++bcs->emptycount;
07dc1f9f 155 } else
784d5858 156 gig_dbg(DEBUG_HDLC,
07dc1f9f 157 "7e----------------------------");
236b87c2 158#endif
07dc1f9f
HL
159
160 /* end of frame */
161 error = 1;
162 gigaset_rcv_error(NULL, cs, bcs);
163 } else if (!(inputstate & INS_have_data)) { /* 7E 7E */
07dc1f9f
HL
164#ifdef CONFIG_GIGASET_DEBUG
165 ++bcs->emptycount;
166#endif
167 break;
168 } else {
784d5858
TS
169 gig_dbg(DEBUG_HDLC,
170 "7e----------------------------");
07dc1f9f
HL
171
172 /* end of frame */
173 error = 0;
174
175 if (unlikely(fcs != PPP_GOODFCS)) {
784d5858 176 dev_err(cs->dev,
0a305720
TS
177 "Checksum failed, %u bytes corrupted!\n",
178 skb->len);
07dc1f9f
HL
179 compskb = NULL;
180 gigaset_rcv_error(compskb, cs, bcs);
181 error = 1;
182 } else {
183 if (likely((l = skb->len) > 2)) {
184 skb->tail -= 2;
185 skb->len -= 2;
186 } else {
187 dev_kfree_skb(skb);
188 skb = NULL;
189 inputstate |= INS_skip_frame;
190 if (l == 1) {
784d5858
TS
191 dev_err(cs->dev,
192 "invalid packet size (1)!\n");
07dc1f9f 193 error = 1;
784d5858
TS
194 gigaset_rcv_error(NULL,
195 cs, bcs);
07dc1f9f
HL
196 }
197 }
198 if (likely(!(error ||
199 (inputstate &
200 INS_skip_frame)))) {
201 gigaset_rcv_skb(skb, cs, bcs);
202 }
203 }
204 }
205
206 if (unlikely(error))
207 if (skb)
208 dev_kfree_skb(skb);
209
210 fcs = PPP_INITFCS;
211 inputstate &= ~(INS_have_data | INS_skip_frame);
212 if (unlikely(bcs->ignore)) {
213 inputstate |= INS_skip_frame;
214 skb = NULL;
215 } else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)) {
216 skb_reserve(skb, HW_HDR_LEN);
217 } else {
784d5858
TS
218 dev_warn(cs->dev,
219 "could not allocate new skb\n");
07dc1f9f
HL
220 inputstate |= INS_skip_frame;
221 }
222
223 break;
07dc1f9f
HL
224 } else if (unlikely(muststuff(c))) {
225 /* Should not happen. Possible after ZDLE=1<CR><LF>. */
784d5858 226 gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c);
07dc1f9f
HL
227 }
228
229 /* add character */
230
231#ifdef CONFIG_GIGASET_DEBUG
232 if (unlikely(!(inputstate & INS_have_data))) {
784d5858
TS
233 gig_dbg(DEBUG_HDLC, "7e (%d x) ================",
234 bcs->emptycount);
07dc1f9f
HL
235 bcs->emptycount = 0;
236 }
237#endif
238
239 inputstate |= INS_have_data;
240
241 if (likely(!(inputstate & INS_skip_frame))) {
242 if (unlikely(skb->len == SBUFSIZE)) {
784d5858 243 dev_warn(cs->dev, "received packet too long\n");
07dc1f9f
HL
244 dev_kfree_skb_any(skb);
245 skb = NULL;
246 inputstate |= INS_skip_frame;
247 break;
248 }
443e1f45 249 *__skb_put(skb, 1) = c;
07dc1f9f
HL
250 fcs = crc_ccitt_byte(fcs, c);
251 }
252
253 if (unlikely(!numbytes))
254 break;
255 c = *src++;
256 --numbytes;
257 if (unlikely(c == DLE_FLAG &&
258 (cs->dle ||
259 inbuf->inputstate & INS_DLE_command))) {
260 inbuf->inputstate |= INS_DLE_char;
261 break;
262 }
263 }
264 bcs->inputstate = inputstate;
265 bcs->fcs = fcs;
266 bcs->skb = skb;
267 return startbytes - numbytes;
268}
269
270/* process a block of received bytes in transparent data mode
271 * Invert bytes, undoing byte stuffing and watching for DLE escapes.
272 * If DLE is encountered, return immediately to let the caller handle it.
273 * Return value:
274 * number of processed bytes
275 * numbytes (all bytes processed) on error --FIXME
276 */
277static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes,
784d5858 278 struct inbuf_t *inbuf)
07dc1f9f
HL
279{
280 struct cardstate *cs = inbuf->cs;
281 struct bc_state *bcs = inbuf->bcs;
d48c7784
TS
282 int inputstate = bcs->inputstate;
283 struct sk_buff *skb = bcs->skb;
07dc1f9f
HL
284 int startbytes = numbytes;
285
07dc1f9f
HL
286 for (;;) {
287 /* add character */
288 inputstate |= INS_have_data;
289
290 if (likely(!(inputstate & INS_skip_frame))) {
291 if (unlikely(skb->len == SBUFSIZE)) {
292 //FIXME just pass skb up and allocate a new one
784d5858 293 dev_warn(cs->dev, "received packet too long\n");
07dc1f9f
HL
294 dev_kfree_skb_any(skb);
295 skb = NULL;
296 inputstate |= INS_skip_frame;
297 break;
298 }
17b3cff0 299 *__skb_put(skb, 1) = bitrev8(c);
07dc1f9f
HL
300 }
301
302 if (unlikely(!numbytes))
303 break;
304 c = *src++;
305 --numbytes;
306 if (unlikely(c == DLE_FLAG &&
307 (cs->dle ||
308 inbuf->inputstate & INS_DLE_command))) {
309 inbuf->inputstate |= INS_DLE_char;
310 break;
311 }
312 }
313
314 /* pass data up */
315 if (likely(inputstate & INS_have_data)) {
316 if (likely(!(inputstate & INS_skip_frame))) {
317 gigaset_rcv_skb(skb, cs, bcs);
318 }
319 inputstate &= ~(INS_have_data | INS_skip_frame);
320 if (unlikely(bcs->ignore)) {
321 inputstate |= INS_skip_frame;
322 skb = NULL;
323 } else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN))
324 != NULL)) {
325 skb_reserve(skb, HW_HDR_LEN);
326 } else {
784d5858 327 dev_warn(cs->dev, "could not allocate new skb\n");
07dc1f9f
HL
328 inputstate |= INS_skip_frame;
329 }
330 }
331
332 bcs->inputstate = inputstate;
333 bcs->skb = skb;
334 return startbytes - numbytes;
335}
336
337/* process a block of data received from the device
338 */
339void gigaset_m10x_input(struct inbuf_t *inbuf)
340{
341 struct cardstate *cs;
342 unsigned tail, head, numbytes;
343 unsigned char *src, c;
344 int procbytes;
345
9d4bee2b
TS
346 head = inbuf->head;
347 tail = inbuf->tail;
784d5858 348 gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
07dc1f9f
HL
349
350 if (head != tail) {
351 cs = inbuf->cs;
352 src = inbuf->data + head;
353 numbytes = (head > tail ? RBUFSIZE : tail) - head;
784d5858 354 gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
07dc1f9f
HL
355
356 while (numbytes) {
9d4bee2b 357 if (cs->mstate == MS_LOCKED) {
07dc1f9f
HL
358 procbytes = lock_loop(src, numbytes, inbuf);
359 src += procbytes;
360 numbytes -= procbytes;
361 } else {
362 c = *src++;
363 --numbytes;
364 if (c == DLE_FLAG && (cs->dle ||
365 inbuf->inputstate & INS_DLE_command)) {
366 if (!(inbuf->inputstate & INS_DLE_char)) {
367 inbuf->inputstate |= INS_DLE_char;
368 goto nextbyte;
369 }
370 /* <DLE> <DLE> => <DLE> in data stream */
371 inbuf->inputstate &= ~INS_DLE_char;
372 }
373
374 if (!(inbuf->inputstate & INS_DLE_char)) {
375
917f5085 376 /* FIXME use function pointers? */
07dc1f9f
HL
377 if (inbuf->inputstate & INS_command)
378 procbytes = cmd_loop(c, src, numbytes, inbuf);
379 else if (inbuf->bcs->proto2 == ISDN_PROTO_L2_HDLC)
380 procbytes = hdlc_loop(c, src, numbytes, inbuf);
381 else
382 procbytes = iraw_loop(c, src, numbytes, inbuf);
383
384 src += procbytes;
385 numbytes -= procbytes;
784d5858 386 } else { /* DLE char */
07dc1f9f
HL
387 inbuf->inputstate &= ~INS_DLE_char;
388 switch (c) {
389 case 'X': /*begin of command*/
07dc1f9f 390 if (inbuf->inputstate & INS_command)
236b87c2 391 dev_warn(cs->dev,
784d5858 392 "received <DLE> 'X' in command mode\n");
07dc1f9f
HL
393 inbuf->inputstate |=
394 INS_command | INS_DLE_command;
395 break;
396 case '.': /*end of command*/
07dc1f9f 397 if (!(inbuf->inputstate & INS_command))
236b87c2 398 dev_warn(cs->dev,
784d5858 399 "received <DLE> '.' in hdlc mode\n");
07dc1f9f
HL
400 inbuf->inputstate &= cs->dle ?
401 ~(INS_DLE_command|INS_command)
402 : ~INS_DLE_command;
403 break;
404 //case DLE_FLAG: /*DLE_FLAG in data stream*/ /* schon oben behandelt! */
405 default:
784d5858
TS
406 dev_err(cs->dev,
407 "received 0x10 0x%02x!\n",
408 (int) c);
07dc1f9f
HL
409 /* FIXME: reset driver?? */
410 }
411 }
412 }
413nextbyte:
414 if (!numbytes) {
415 /* end of buffer, check for wrap */
416 if (head > tail) {
417 head = 0;
418 src = inbuf->data;
419 numbytes = tail;
420 } else {
421 head = tail;
422 break;
423 }
424 }
425 }
426
784d5858 427 gig_dbg(DEBUG_INTR, "setting head to %u", head);
9d4bee2b 428 inbuf->head = head;
07dc1f9f
HL
429 }
430}
d5c1682f 431EXPORT_SYMBOL_GPL(gigaset_m10x_input);
07dc1f9f
HL
432
433
434/* == data output ========================================================== */
435
436/* Encoding of a PPP packet into an octet stuffed HDLC frame
437 * with FCS, opening and closing flags.
438 * parameters:
439 * skb skb containing original packet (freed upon return)
440 * head number of headroom bytes to allocate in result skb
441 * tail number of tailroom bytes to allocate in result skb
442 * Return value:
443 * pointer to newly allocated skb containing the result frame
444 */
445static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail)
446{
447 struct sk_buff *hdlc_skb;
448 __u16 fcs;
449 unsigned char c;
450 unsigned char *cp;
451 int len;
452 unsigned int stuf_cnt;
453
454 stuf_cnt = 0;
455 fcs = PPP_INITFCS;
456 cp = skb->data;
457 len = skb->len;
458 while (len--) {
459 if (muststuff(*cp))
460 stuf_cnt++;
461 fcs = crc_ccitt_byte(fcs, *cp++);
462 }
784d5858 463 fcs ^= 0xffff; /* complement */
07dc1f9f
HL
464
465 /* size of new buffer: original size + number of stuffing bytes
466 * + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes
467 */
468 hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + tail + head);
469 if (!hdlc_skb) {
07dc1f9f
HL
470 dev_kfree_skb(skb);
471 return NULL;
472 }
473 skb_reserve(hdlc_skb, head);
474
475 /* Copy acknowledge request into new skb */
476 memcpy(hdlc_skb->head, skb->head, 2);
477
478 /* Add flag sequence in front of everything.. */
479 *(skb_put(hdlc_skb, 1)) = PPP_FLAG;
480
481 /* Perform byte stuffing while copying data. */
482 while (skb->len--) {
483 if (muststuff(*skb->data)) {
484 *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
485 *(skb_put(hdlc_skb, 1)) = (*skb->data++) ^ PPP_TRANS;
486 } else
487 *(skb_put(hdlc_skb, 1)) = *skb->data++;
488 }
489
490 /* Finally add FCS (byte stuffed) and flag sequence */
784d5858 491 c = (fcs & 0x00ff); /* least significant byte first */
07dc1f9f
HL
492 if (muststuff(c)) {
493 *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
494 c ^= PPP_TRANS;
495 }
496 *(skb_put(hdlc_skb, 1)) = c;
497
498 c = ((fcs >> 8) & 0x00ff);
499 if (muststuff(c)) {
500 *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
501 c ^= PPP_TRANS;
502 }
503 *(skb_put(hdlc_skb, 1)) = c;
504
505 *(skb_put(hdlc_skb, 1)) = PPP_FLAG;
506
507 dev_kfree_skb(skb);
508 return hdlc_skb;
509}
510
511/* Encoding of a raw packet into an octet stuffed bit inverted frame
512 * parameters:
513 * skb skb containing original packet (freed upon return)
514 * head number of headroom bytes to allocate in result skb
515 * tail number of tailroom bytes to allocate in result skb
516 * Return value:
517 * pointer to newly allocated skb containing the result frame
518 */
519static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
520{
521 struct sk_buff *iraw_skb;
522 unsigned char c;
523 unsigned char *cp;
524 int len;
525
526 /* worst case: every byte must be stuffed */
527 iraw_skb = dev_alloc_skb(2*skb->len + tail + head);
528 if (!iraw_skb) {
07dc1f9f
HL
529 dev_kfree_skb(skb);
530 return NULL;
531 }
532 skb_reserve(iraw_skb, head);
533
534 cp = skb->data;
535 len = skb->len;
536 while (len--) {
17b3cff0 537 c = bitrev8(*cp++);
07dc1f9f
HL
538 if (c == DLE_FLAG)
539 *(skb_put(iraw_skb, 1)) = c;
540 *(skb_put(iraw_skb, 1)) = c;
541 }
542 dev_kfree_skb(skb);
543 return iraw_skb;
544}
545
546/* gigaset_send_skb
547 * called by common.c to queue an skb for sending
548 * and start transmission if necessary
549 * parameters:
550 * B Channel control structure
551 * skb
552 * Return value:
553 * number of bytes accepted for sending
554 * (skb->len if ok, 0 if out of buffer space)
555 * or error code (< 0, eg. -EINVAL)
556 */
557int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb)
558{
d48c7784 559 unsigned len = skb->len;
69049cc8 560 unsigned long flags;
07dc1f9f
HL
561
562 if (bcs->proto2 == ISDN_PROTO_L2_HDLC)
563 skb = HDLC_Encode(skb, HW_HDR_LEN, 0);
564 else
565 skb = iraw_encode(skb, HW_HDR_LEN, 0);
784d5858 566 if (!skb) {
5002779d
TS
567 dev_err(bcs->cs->dev,
568 "unable to allocate memory for encoding!\n");
07dc1f9f 569 return -ENOMEM;
784d5858 570 }
07dc1f9f
HL
571
572 skb_queue_tail(&bcs->squeue, skb);
69049cc8
TS
573 spin_lock_irqsave(&bcs->cs->lock, flags);
574 if (bcs->cs->connected)
575 tasklet_schedule(&bcs->cs->write_tasklet);
576 spin_unlock_irqrestore(&bcs->cs->lock, flags);
07dc1f9f
HL
577
578 return len; /* ok so far */
579}
d5c1682f 580EXPORT_SYMBOL_GPL(gigaset_m10x_send_skb);