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