Merge master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6] / 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 EXPORT_SYMBOL_GPL(gigaset_m10x_input);
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  */
461 static 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                 dev_kfree_skb(skb);
487                 return NULL;
488         }
489         skb_reserve(hdlc_skb, head);
490
491         /* Copy acknowledge request into new skb */
492         memcpy(hdlc_skb->head, skb->head, 2);
493
494         /* Add flag sequence in front of everything.. */
495         *(skb_put(hdlc_skb, 1)) = PPP_FLAG;
496
497         /* Perform byte stuffing while copying data. */
498         while (skb->len--) {
499                 if (muststuff(*skb->data)) {
500                         *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
501                         *(skb_put(hdlc_skb, 1)) = (*skb->data++) ^ PPP_TRANS;
502                 } else
503                         *(skb_put(hdlc_skb, 1)) = *skb->data++;
504         }
505
506         /* Finally add FCS (byte stuffed) and flag sequence */
507         c = (fcs & 0x00ff);     /* least significant byte first */
508         if (muststuff(c)) {
509                 *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
510                 c ^= PPP_TRANS;
511         }
512         *(skb_put(hdlc_skb, 1)) = c;
513
514         c = ((fcs >> 8) & 0x00ff);
515         if (muststuff(c)) {
516                 *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
517                 c ^= PPP_TRANS;
518         }
519         *(skb_put(hdlc_skb, 1)) = c;
520
521         *(skb_put(hdlc_skb, 1)) = PPP_FLAG;
522
523         dev_kfree_skb(skb);
524         return hdlc_skb;
525 }
526
527 /* Encoding of a raw packet into an octet stuffed bit inverted frame
528  * parameters:
529  *      skb     skb containing original packet (freed upon return)
530  *      head    number of headroom bytes to allocate in result skb
531  *      tail    number of tailroom bytes to allocate in result skb
532  * Return value:
533  *      pointer to newly allocated skb containing the result frame
534  */
535 static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
536 {
537         struct sk_buff *iraw_skb;
538         unsigned char c;
539         unsigned char *cp;
540         int len;
541
542         /* worst case: every byte must be stuffed */
543         iraw_skb = dev_alloc_skb(2*skb->len + tail + head);
544         if (!iraw_skb) {
545                 dev_kfree_skb(skb);
546                 return NULL;
547         }
548         skb_reserve(iraw_skb, head);
549
550         cp = skb->data;
551         len = skb->len;
552         while (len--) {
553                 c = bitrev8(*cp++);
554                 if (c == DLE_FLAG)
555                         *(skb_put(iraw_skb, 1)) = c;
556                 *(skb_put(iraw_skb, 1)) = c;
557         }
558         dev_kfree_skb(skb);
559         return iraw_skb;
560 }
561
562 /* gigaset_send_skb
563  * called by common.c to queue an skb for sending
564  * and start transmission if necessary
565  * parameters:
566  *      B Channel control structure
567  *      skb
568  * Return value:
569  *      number of bytes accepted for sending
570  *      (skb->len if ok, 0 if out of buffer space)
571  *      or error code (< 0, eg. -EINVAL)
572  */
573 int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb)
574 {
575         unsigned len = skb->len;
576         unsigned long flags;
577
578         if (bcs->proto2 == ISDN_PROTO_L2_HDLC)
579                 skb = HDLC_Encode(skb, HW_HDR_LEN, 0);
580         else
581                 skb = iraw_encode(skb, HW_HDR_LEN, 0);
582         if (!skb) {
583                 err("unable to allocate memory for encoding!\n");
584                 return -ENOMEM;
585         }
586
587         skb_queue_tail(&bcs->squeue, skb);
588         spin_lock_irqsave(&bcs->cs->lock, flags);
589         if (bcs->cs->connected)
590                 tasklet_schedule(&bcs->cs->write_tasklet);
591         spin_unlock_irqrestore(&bcs->cs->lock, flags);
592
593         return len;     /* ok so far */
594 }
595 EXPORT_SYMBOL_GPL(gigaset_m10x_send_skb);