Pull bugzilla-5653 into release branch
[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 #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  */
26 static 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  */
43 static 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                         gig_dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)",
55                                 __func__, cbytes);
56                         cs->cbytes = cbytes;
57                         gigaset_handle_modem_response(cs); /* can change
58                                                               cs->dle */
59                         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                                 dev_warn(cs->dev, "response too large\n");
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  */
95 static inline int lock_loop(unsigned char *src, int numbytes,
96                             struct inbuf_t *inbuf)
97 {
98         struct cardstate *cs = inbuf->cs;
99
100         gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response",
101                            numbytes, src);
102         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  */
115 static 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 = bcs->inputstate;
121         __u16 fcs = bcs->fcs;
122         struct sk_buff *skb = bcs->skb;
123         unsigned char error;
124         struct sk_buff *compskb;
125         int startbytes = numbytes;
126         int l;
127
128         if (unlikely(inputstate & INS_byte_stuff)) {
129                 inputstate &= ~INS_byte_stuff;
130                 goto byte_stuff;
131         }
132         for (;;) {
133                 if (unlikely(c == PPP_ESCAPE)) {
134                         if (unlikely(!numbytes)) {
135                                 inputstate |= INS_byte_stuff;
136                                 break;
137                         }
138                         c = *src++;
139                         --numbytes;
140                         if (unlikely(c == DLE_FLAG &&
141                                      (cs->dle ||
142                                       inbuf->inputstate & INS_DLE_command))) {
143                                 inbuf->inputstate |= INS_DLE_char;
144                                 inputstate |= INS_byte_stuff;
145                                 break;
146                         }
147 byte_stuff:
148                         c ^= PPP_TRANS;
149 #ifdef CONFIG_GIGASET_DEBUG
150                         if (unlikely(!muststuff(c)))
151                                 gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c);
152 #endif
153                 } else if (unlikely(c == PPP_FLAG)) {
154                         if (unlikely(inputstate & INS_skip_frame)) {
155                                 if (!(inputstate & INS_have_data)) { /* 7E 7E */
156 #ifdef CONFIG_GIGASET_DEBUG
157                                         ++bcs->emptycount;
158 #endif
159                                 } else
160                                         gig_dbg(DEBUG_HDLC,
161                                             "7e----------------------------");
162
163                                 /* end of frame */
164                                 error = 1;
165                                 gigaset_rcv_error(NULL, cs, bcs);
166                         } else if (!(inputstate & INS_have_data)) { /* 7E 7E */
167 #ifdef CONFIG_GIGASET_DEBUG
168                                 ++bcs->emptycount;
169 #endif
170                                 break;
171                         } else {
172                                 gig_dbg(DEBUG_HDLC,
173                                         "7e----------------------------");
174
175                                 /* end of frame */
176                                 error = 0;
177
178                                 if (unlikely(fcs != PPP_GOODFCS)) {
179                                         dev_err(cs->dev,
180                                             "Packet checksum at %lu failed, "
181                                             "packet is corrupted (%u bytes)!\n",
182                                             bcs->rcvbytes, skb->len);
183                                         compskb = NULL;
184                                         gigaset_rcv_error(compskb, cs, bcs);
185                                         error = 1;
186                                 } else {
187                                         if (likely((l = skb->len) > 2)) {
188                                                 skb->tail -= 2;
189                                                 skb->len -= 2;
190                                         } else {
191                                                 dev_kfree_skb(skb);
192                                                 skb = NULL;
193                                                 inputstate |= INS_skip_frame;
194                                                 if (l == 1) {
195                                                         dev_err(cs->dev,
196                                                   "invalid packet size (1)!\n");
197                                                         error = 1;
198                                                         gigaset_rcv_error(NULL,
199                                                                 cs, bcs);
200                                                 }
201                                         }
202                                         if (likely(!(error ||
203                                                      (inputstate &
204                                                       INS_skip_frame)))) {
205                                                 gigaset_rcv_skb(skb, cs, bcs);
206                                         }
207                                 }
208                         }
209
210                         if (unlikely(error))
211                                 if (skb)
212                                         dev_kfree_skb(skb);
213
214                         fcs = PPP_INITFCS;
215                         inputstate &= ~(INS_have_data | INS_skip_frame);
216                         if (unlikely(bcs->ignore)) {
217                                 inputstate |= INS_skip_frame;
218                                 skb = NULL;
219                         } else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)) {
220                                 skb_reserve(skb, HW_HDR_LEN);
221                         } else {
222                                 dev_warn(cs->dev,
223                                          "could not allocate new skb\n");
224                                 inputstate |= INS_skip_frame;
225                         }
226
227                         break;
228 #ifdef CONFIG_GIGASET_DEBUG
229                 } else if (unlikely(muststuff(c))) {
230                         /* Should not happen. Possible after ZDLE=1<CR><LF>. */
231                         gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c);
232 #endif
233                 }
234
235                 /* add character */
236
237 #ifdef CONFIG_GIGASET_DEBUG
238                 if (unlikely(!(inputstate & INS_have_data))) {
239                         gig_dbg(DEBUG_HDLC, "7e (%d x) ================",
240                                 bcs->emptycount);
241                         bcs->emptycount = 0;
242                 }
243 #endif
244
245                 inputstate |= INS_have_data;
246
247                 if (likely(!(inputstate & INS_skip_frame))) {
248                         if (unlikely(skb->len == SBUFSIZE)) {
249                                 dev_warn(cs->dev, "received packet too long\n");
250                                 dev_kfree_skb_any(skb);
251                                 skb = NULL;
252                                 inputstate |= INS_skip_frame;
253                                 break;
254                         }
255                         *__skb_put(skb, 1) = c;
256                         fcs = crc_ccitt_byte(fcs, c);
257                 }
258
259                 if (unlikely(!numbytes))
260                         break;
261                 c = *src++;
262                 --numbytes;
263                 if (unlikely(c == DLE_FLAG &&
264                              (cs->dle ||
265                               inbuf->inputstate & INS_DLE_command))) {
266                         inbuf->inputstate |= INS_DLE_char;
267                         break;
268                 }
269         }
270         bcs->inputstate = inputstate;
271         bcs->fcs = fcs;
272         bcs->skb = skb;
273         return startbytes - numbytes;
274 }
275
276 /* process a block of received bytes in transparent data mode
277  * Invert bytes, undoing byte stuffing and watching for DLE escapes.
278  * If DLE is encountered, return immediately to let the caller handle it.
279  * Return value:
280  *      number of processed bytes
281  *      numbytes (all bytes processed) on error --FIXME
282  */
283 static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes,
284                             struct inbuf_t *inbuf)
285 {
286         struct cardstate *cs = inbuf->cs;
287         struct bc_state *bcs = inbuf->bcs;
288         int inputstate = bcs->inputstate;
289         struct sk_buff *skb = bcs->skb;
290         int startbytes = numbytes;
291
292         for (;;) {
293                 /* add character */
294                 inputstate |= INS_have_data;
295
296                 if (likely(!(inputstate & INS_skip_frame))) {
297                         if (unlikely(skb->len == SBUFSIZE)) {
298                                 //FIXME just pass skb up and allocate a new one
299                                 dev_warn(cs->dev, "received packet too long\n");
300                                 dev_kfree_skb_any(skb);
301                                 skb = NULL;
302                                 inputstate |= INS_skip_frame;
303                                 break;
304                         }
305                         *__skb_put(skb, 1) = gigaset_invtab[c];
306                 }
307
308                 if (unlikely(!numbytes))
309                         break;
310                 c = *src++;
311                 --numbytes;
312                 if (unlikely(c == DLE_FLAG &&
313                              (cs->dle ||
314                               inbuf->inputstate & INS_DLE_command))) {
315                         inbuf->inputstate |= INS_DLE_char;
316                         break;
317                 }
318         }
319
320         /* pass data up */
321         if (likely(inputstate & INS_have_data)) {
322                 if (likely(!(inputstate & INS_skip_frame))) {
323                         gigaset_rcv_skb(skb, cs, bcs);
324                 }
325                 inputstate &= ~(INS_have_data | INS_skip_frame);
326                 if (unlikely(bcs->ignore)) {
327                         inputstate |= INS_skip_frame;
328                         skb = NULL;
329                 } else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN))
330                                   != NULL)) {
331                         skb_reserve(skb, HW_HDR_LEN);
332                 } else {
333                         dev_warn(cs->dev, "could not allocate new skb\n");
334                         inputstate |= INS_skip_frame;
335                 }
336         }
337
338         bcs->inputstate = inputstate;
339         bcs->skb = skb;
340         return startbytes - numbytes;
341 }
342
343 /* process a block of data received from the device
344  */
345 void gigaset_m10x_input(struct inbuf_t *inbuf)
346 {
347         struct cardstate *cs;
348         unsigned tail, head, numbytes;
349         unsigned char *src, c;
350         int procbytes;
351
352         head = atomic_read(&inbuf->head);
353         tail = atomic_read(&inbuf->tail);
354         gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
355
356         if (head != tail) {
357                 cs = inbuf->cs;
358                 src = inbuf->data + head;
359                 numbytes = (head > tail ? RBUFSIZE : tail) - head;
360                 gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
361
362                 while (numbytes) {
363                         if (atomic_read(&cs->mstate) == MS_LOCKED) {
364                                 procbytes = lock_loop(src, numbytes, inbuf);
365                                 src += procbytes;
366                                 numbytes -= procbytes;
367                         } else {
368                                 c = *src++;
369                                 --numbytes;
370                                 if (c == DLE_FLAG && (cs->dle ||
371                                     inbuf->inputstate & INS_DLE_command)) {
372                                         if (!(inbuf->inputstate & INS_DLE_char)) {
373                                                 inbuf->inputstate |= INS_DLE_char;
374                                                 goto nextbyte;
375                                         }
376                                         /* <DLE> <DLE> => <DLE> in data stream */
377                                         inbuf->inputstate &= ~INS_DLE_char;
378                                 }
379
380                                 if (!(inbuf->inputstate & INS_DLE_char)) {
381
382                                         /* FIXME use function pointers?  */
383                                         if (inbuf->inputstate & INS_command)
384                                                 procbytes = cmd_loop(c, src, numbytes, inbuf);
385                                         else if (inbuf->bcs->proto2 == ISDN_PROTO_L2_HDLC)
386                                                 procbytes = hdlc_loop(c, src, numbytes, inbuf);
387                                         else
388                                                 procbytes = iraw_loop(c, src, numbytes, inbuf);
389
390                                         src += procbytes;
391                                         numbytes -= procbytes;
392                                 } else {  /* DLE char */
393                                         inbuf->inputstate &= ~INS_DLE_char;
394                                         switch (c) {
395                                         case 'X': /*begin of command*/
396 #ifdef CONFIG_GIGASET_DEBUG
397                                                 if (inbuf->inputstate & INS_command)
398                                                         dev_err(cs->dev,
399                                         "received <DLE> 'X' in command mode\n");
400 #endif
401                                                 inbuf->inputstate |=
402                                                         INS_command | INS_DLE_command;
403                                                 break;
404                                         case '.': /*end of command*/
405 #ifdef CONFIG_GIGASET_DEBUG
406                                                 if (!(inbuf->inputstate & INS_command))
407                                                         dev_err(cs->dev,
408                                         "received <DLE> '.' in hdlc mode\n");
409 #endif
410                                                 inbuf->inputstate &= cs->dle ?
411                                                         ~(INS_DLE_command|INS_command)
412                                                         : ~INS_DLE_command;
413                                                 break;
414                                         //case DLE_FLAG: /*DLE_FLAG in data stream*/ /* schon oben behandelt! */
415                                         default:
416                                                 dev_err(cs->dev,
417                                                       "received 0x10 0x%02x!\n",
418                                                         (int) c);
419                                                 /* FIXME: reset driver?? */
420                                         }
421                                 }
422                         }
423 nextbyte:
424                         if (!numbytes) {
425                                 /* end of buffer, check for wrap */
426                                 if (head > tail) {
427                                         head = 0;
428                                         src = inbuf->data;
429                                         numbytes = tail;
430                                 } else {
431                                         head = tail;
432                                         break;
433                                 }
434                         }
435                 }
436
437                 gig_dbg(DEBUG_INTR, "setting head to %u", head);
438                 atomic_set(&inbuf->head, head);
439         }
440 }
441
442
443 /* == data output ========================================================== */
444
445 /* Encoding of a PPP packet into an octet stuffed HDLC frame
446  * with FCS, opening and closing flags.
447  * parameters:
448  *      skb     skb containing original packet (freed upon return)
449  *      head    number of headroom bytes to allocate in result skb
450  *      tail    number of tailroom bytes to allocate in result skb
451  * Return value:
452  *      pointer to newly allocated skb containing the result frame
453  */
454 static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail)
455 {
456         struct sk_buff *hdlc_skb;
457         __u16 fcs;
458         unsigned char c;
459         unsigned char *cp;
460         int len;
461         unsigned int stuf_cnt;
462
463         stuf_cnt = 0;
464         fcs = PPP_INITFCS;
465         cp = skb->data;
466         len = skb->len;
467         while (len--) {
468                 if (muststuff(*cp))
469                         stuf_cnt++;
470                 fcs = crc_ccitt_byte(fcs, *cp++);
471         }
472         fcs ^= 0xffff;                  /* complement */
473
474         /* size of new buffer: original size + number of stuffing bytes
475          * + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes
476          */
477         hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + tail + head);
478         if (!hdlc_skb) {
479                 dev_kfree_skb(skb);
480                 return NULL;
481         }
482         skb_reserve(hdlc_skb, head);
483
484         /* Copy acknowledge request into new skb */
485         memcpy(hdlc_skb->head, skb->head, 2);
486
487         /* Add flag sequence in front of everything.. */
488         *(skb_put(hdlc_skb, 1)) = PPP_FLAG;
489
490         /* Perform byte stuffing while copying data. */
491         while (skb->len--) {
492                 if (muststuff(*skb->data)) {
493                         *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
494                         *(skb_put(hdlc_skb, 1)) = (*skb->data++) ^ PPP_TRANS;
495                 } else
496                         *(skb_put(hdlc_skb, 1)) = *skb->data++;
497         }
498
499         /* Finally add FCS (byte stuffed) and flag sequence */
500         c = (fcs & 0x00ff);     /* least significant byte first */
501         if (muststuff(c)) {
502                 *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
503                 c ^= PPP_TRANS;
504         }
505         *(skb_put(hdlc_skb, 1)) = c;
506
507         c = ((fcs >> 8) & 0x00ff);
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         *(skb_put(hdlc_skb, 1)) = PPP_FLAG;
515
516         dev_kfree_skb(skb);
517         return hdlc_skb;
518 }
519
520 /* Encoding of a raw packet into an octet stuffed bit inverted frame
521  * parameters:
522  *      skb     skb containing original packet (freed upon return)
523  *      head    number of headroom bytes to allocate in result skb
524  *      tail    number of tailroom bytes to allocate in result skb
525  * Return value:
526  *      pointer to newly allocated skb containing the result frame
527  */
528 static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
529 {
530         struct sk_buff *iraw_skb;
531         unsigned char c;
532         unsigned char *cp;
533         int len;
534
535         /* worst case: every byte must be stuffed */
536         iraw_skb = dev_alloc_skb(2*skb->len + tail + head);
537         if (!iraw_skb) {
538                 dev_kfree_skb(skb);
539                 return NULL;
540         }
541         skb_reserve(iraw_skb, head);
542
543         cp = skb->data;
544         len = skb->len;
545         while (len--) {
546                 c = gigaset_invtab[*cp++];
547                 if (c == DLE_FLAG)
548                         *(skb_put(iraw_skb, 1)) = c;
549                 *(skb_put(iraw_skb, 1)) = c;
550         }
551         dev_kfree_skb(skb);
552         return iraw_skb;
553 }
554
555 /* gigaset_send_skb
556  * called by common.c to queue an skb for sending
557  * and start transmission if necessary
558  * parameters:
559  *      B Channel control structure
560  *      skb
561  * Return value:
562  *      number of bytes accepted for sending
563  *      (skb->len if ok, 0 if out of buffer space)
564  *      or error code (< 0, eg. -EINVAL)
565  */
566 int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb)
567 {
568         unsigned len = skb->len;
569         unsigned long flags;
570
571         if (bcs->proto2 == ISDN_PROTO_L2_HDLC)
572                 skb = HDLC_Encode(skb, HW_HDR_LEN, 0);
573         else
574                 skb = iraw_encode(skb, HW_HDR_LEN, 0);
575         if (!skb) {
576                 err("unable to allocate memory for encoding!\n");
577                 return -ENOMEM;
578         }
579
580         skb_queue_tail(&bcs->squeue, skb);
581         spin_lock_irqsave(&bcs->cs->lock, flags);
582         if (bcs->cs->connected)
583                 tasklet_schedule(&bcs->cs->write_tasklet);
584         spin_unlock_irqrestore(&bcs->cs->lock, flags);
585
586         return len;     /* ok so far */
587 }