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