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