]>
git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/blob - drivers/isdn/gigaset/asyncdata.c
2 * Common data handling layer for ser_gigaset and usb_gigaset
4 * Copyright (c) 2005 by Tilman Schmidt <tilman@imap.cc>,
5 * Hansjoerg Lipp <hjlipp@web.de>,
6 * Stefan Eilers <Eilers.Stefan@epost.de>.
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 * =====================================================================
15 * =====================================================================
16 * Version: $Id: asyncdata.c,v 1.2.2.7 2005/11/13 23:05:18 hjlipp Exp $
17 * =====================================================================
21 #include <linux/crc-ccitt.h>
23 //#define GIG_M10x_STUFF_VOICE_DATA
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.
30 static inline int muststuff(unsigned char c
)
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 */
41 /* == data input =========================================================== */
43 /* process a block of received bytes in command mode (modem response)
45 * number of processed bytes
47 static inline int cmd_loop(unsigned char c
, unsigned char *src
, int numbytes
,
48 struct inbuf_t
*inbuf
)
50 struct cardstate
*cs
= inbuf
->cs
;
51 unsigned cbytes
= cs
->cbytes
;
52 int inputstate
= inbuf
->inputstate
;
53 int startbytes
= numbytes
;
56 cs
->respdata
[cbytes
] = c
;
57 if (c
== 10 || c
== 13) {
58 dbg(DEBUG_TRANSCMD
, "%s: End of Command (%d Bytes)",
61 gigaset_handle_modem_response(cs
); /* can change cs->dle */
65 !(inputstate
& INS_DLE_command
)) {
66 inputstate
&= ~INS_command
;
70 /* advance in line buffer, checking for overflow */
71 if (cbytes
< MAX_RESP_SIZE
- 1)
74 warn("response too large");
82 (cs
->dle
|| inputstate
& INS_DLE_command
)) {
83 inputstate
|= INS_DLE_char
;
89 inbuf
->inputstate
= inputstate
;
91 return startbytes
- numbytes
;
94 /* process a block of received bytes in lock mode (tty i/f)
96 * number of processed bytes
98 static inline int lock_loop(unsigned char *src
, int numbytes
,
99 struct inbuf_t
*inbuf
)
101 struct cardstate
*cs
= inbuf
->cs
;
103 gigaset_dbg_buffer(DEBUG_LOCKCMD
, "received response", numbytes
, src
, 0);
104 gigaset_if_receive(cs
, src
, numbytes
);
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.
114 * number of processed bytes
115 * numbytes (all bytes processed) on error --FIXME
117 static inline int hdlc_loop(unsigned char c
, unsigned char *src
, int numbytes
,
118 struct inbuf_t
*inbuf
)
120 struct cardstate
*cs
= inbuf
->cs
;
121 struct bc_state
*bcs
= inbuf
->bcs
;
126 struct sk_buff
*compskb
;
127 int startbytes
= numbytes
;
130 IFNULLRETVAL(bcs
, numbytes
);
131 inputstate
= bcs
->inputstate
;
134 IFNULLRETVAL(skb
, numbytes
);
136 if (unlikely(inputstate
& INS_byte_stuff
)) {
137 inputstate
&= ~INS_byte_stuff
;
141 if (unlikely(c
== PPP_ESCAPE
)) {
142 if (unlikely(!numbytes
)) {
143 inputstate
|= INS_byte_stuff
;
148 if (unlikely(c
== DLE_FLAG
&&
150 inbuf
->inputstate
& INS_DLE_command
))) {
151 inbuf
->inputstate
|= INS_DLE_char
;
152 inputstate
|= INS_byte_stuff
;
157 #ifdef CONFIG_GIGASET_DEBUG
158 if (unlikely(!muststuff(c
)))
160 "byte stuffed: 0x%02x", c
);
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
171 "7e----------------------------");
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
184 "7e----------------------------");
189 if (unlikely(fcs
!= PPP_GOODFCS
)) {
190 err("Packet checksum at %lu failed, "
191 "packet is corrupted (%u bytes)!",
192 bcs
->rcvbytes
, skb
->len
);
194 gigaset_rcv_error(compskb
, cs
, bcs
);
197 if (likely((l
= skb
->len
) > 2)) {
203 inputstate
|= INS_skip_frame
;
205 err("invalid packet size (1)!");
207 gigaset_rcv_error(NULL
, cs
, bcs
);
210 if (likely(!(error
||
213 gigaset_rcv_skb(skb
, cs
, bcs
);
223 inputstate
&= ~(INS_have_data
| INS_skip_frame
);
224 if (unlikely(bcs
->ignore
)) {
225 inputstate
|= INS_skip_frame
;
227 } else if (likely((skb
= dev_alloc_skb(SBUFSIZE
+ HW_HDR_LEN
)) != NULL
)) {
228 skb_reserve(skb
, HW_HDR_LEN
);
230 warn("could not allocate new skb");
231 inputstate
|= INS_skip_frame
;
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
);
244 #ifdef CONFIG_GIGASET_DEBUG
245 if (unlikely(!(inputstate
& INS_have_data
))) {
247 "7e (%d x) ================", bcs
->emptycount
);
252 inputstate
|= INS_have_data
;
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
);
259 inputstate
|= INS_skip_frame
;
262 *gigaset_skb_put_quick(skb
, 1) = c
;
263 /* *__skb_put (skb, 1) = c; */
264 fcs
= crc_ccitt_byte(fcs
, c
);
267 if (unlikely(!numbytes
))
271 if (unlikely(c
== DLE_FLAG
&&
273 inbuf
->inputstate
& INS_DLE_command
))) {
274 inbuf
->inputstate
|= INS_DLE_char
;
278 bcs
->inputstate
= inputstate
;
281 return startbytes
- numbytes
;
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.
288 * number of processed bytes
289 * numbytes (all bytes processed) on error --FIXME
291 static inline int iraw_loop(unsigned char c
, unsigned char *src
, int numbytes
,
292 struct inbuf_t
*inbuf
)
294 struct cardstate
*cs
= inbuf
->cs
;
295 struct bc_state
*bcs
= inbuf
->bcs
;
298 int startbytes
= numbytes
;
300 IFNULLRETVAL(bcs
, numbytes
);
301 inputstate
= bcs
->inputstate
;
303 IFNULLRETVAL(skb
, numbytes
);
307 inputstate
|= INS_have_data
;
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
);
315 inputstate
|= INS_skip_frame
;
318 *gigaset_skb_put_quick(skb
, 1) = gigaset_invtab
[c
];
321 if (unlikely(!numbytes
))
325 if (unlikely(c
== DLE_FLAG
&&
327 inbuf
->inputstate
& INS_DLE_command
))) {
328 inbuf
->inputstate
|= INS_DLE_char
;
334 if (likely(inputstate
& INS_have_data
)) {
335 if (likely(!(inputstate
& INS_skip_frame
))) {
336 gigaset_rcv_skb(skb
, cs
, bcs
);
338 inputstate
&= ~(INS_have_data
| INS_skip_frame
);
339 if (unlikely(bcs
->ignore
)) {
340 inputstate
|= INS_skip_frame
;
342 } else if (likely((skb
= dev_alloc_skb(SBUFSIZE
+ HW_HDR_LEN
))
344 skb_reserve(skb
, HW_HDR_LEN
);
346 warn("could not allocate new skb");
347 inputstate
|= INS_skip_frame
;
351 bcs
->inputstate
= inputstate
;
353 return startbytes
- numbytes
;
356 /* process a block of data received from the device
358 void gigaset_m10x_input(struct inbuf_t
*inbuf
)
360 struct cardstate
*cs
;
361 unsigned tail
, head
, numbytes
;
362 unsigned char *src
, c
;
365 head
= atomic_read(&inbuf
->head
);
366 tail
= atomic_read(&inbuf
->tail
);
367 dbg(DEBUG_INTR
, "buffer state: %u -> %u", head
, tail
);
371 src
= inbuf
->data
+ head
;
372 numbytes
= (head
> tail
? RBUFSIZE
: tail
) - head
;
373 dbg(DEBUG_INTR
, "processing %u bytes", numbytes
);
376 if (atomic_read(&cs
->mstate
) == MS_LOCKED
) {
377 procbytes
= lock_loop(src
, numbytes
, inbuf
);
379 numbytes
-= procbytes
;
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
;
389 /* <DLE> <DLE> => <DLE> in data stream */
390 inbuf
->inputstate
&= ~INS_DLE_char
;
393 if (!(inbuf
->inputstate
& INS_DLE_char
)) {
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
);
402 procbytes
= iraw_loop(c
, src
, numbytes
, inbuf
);
405 numbytes
-= procbytes
;
406 } else { /* DLE-char */
407 inbuf
->inputstate
&= ~INS_DLE_char
;
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");
415 INS_command
| INS_DLE_command
;
417 case '.': /*end of command*/
418 #ifdef CONFIG_GIGASET_DEBUG
419 if (!(inbuf
->inputstate
& INS_command
))
420 err("received <DLE> '.' in hdlc mode");
422 inbuf
->inputstate
&= cs
->dle
?
423 ~(INS_DLE_command
|INS_command
)
426 //case DLE_FLAG: /*DLE_FLAG in data stream*/ /* schon oben behandelt! */
428 err("received 0x10 0x%02x!", (int) c
);
429 /* FIXME: reset driver?? */
435 /* end of buffer, check for wrap */
447 dbg(DEBUG_INTR
, "setting head to %u", head
);
448 atomic_set(&inbuf
->head
, head
);
453 /* == data output ========================================================== */
455 /* Encoding of a PPP packet into an octet stuffed HDLC frame
456 * with FCS, opening and closing flags.
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
462 * pointer to newly allocated skb containing the result frame
464 static struct sk_buff
*HDLC_Encode(struct sk_buff
*skb
, int head
, int tail
)
466 struct sk_buff
*hdlc_skb
;
471 unsigned int stuf_cnt
;
480 fcs
= crc_ccitt_byte(fcs
, *cp
++);
482 fcs
^= 0xffff; /* complement */
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
487 hdlc_skb
= dev_alloc_skb(skb
->len
+ stuf_cnt
+ 6 + tail
+ head
);
489 err("unable to allocate memory for HDLC encoding!");
493 skb_reserve(hdlc_skb
, head
);
495 /* Copy acknowledge request into new skb */
496 memcpy(hdlc_skb
->head
, skb
->head
, 2);
498 /* Add flag sequence in front of everything.. */
499 *(skb_put(hdlc_skb
, 1)) = PPP_FLAG
;
501 /* Perform byte stuffing while copying data. */
503 if (muststuff(*skb
->data
)) {
504 *(skb_put(hdlc_skb
, 1)) = PPP_ESCAPE
;
505 *(skb_put(hdlc_skb
, 1)) = (*skb
->data
++) ^ PPP_TRANS
;
507 *(skb_put(hdlc_skb
, 1)) = *skb
->data
++;
510 /* Finally add FCS (byte stuffed) and flag sequence */
511 c
= (fcs
& 0x00ff); /* least significant byte first */
513 *(skb_put(hdlc_skb
, 1)) = PPP_ESCAPE
;
516 *(skb_put(hdlc_skb
, 1)) = c
;
518 c
= ((fcs
>> 8) & 0x00ff);
520 *(skb_put(hdlc_skb
, 1)) = PPP_ESCAPE
;
523 *(skb_put(hdlc_skb
, 1)) = c
;
525 *(skb_put(hdlc_skb
, 1)) = PPP_FLAG
;
531 /* Encoding of a raw packet into an octet stuffed bit inverted frame
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
537 * pointer to newly allocated skb containing the result frame
539 static struct sk_buff
*iraw_encode(struct sk_buff
*skb
, int head
, int tail
)
541 struct sk_buff
*iraw_skb
;
546 /* worst case: every byte must be stuffed */
547 iraw_skb
= dev_alloc_skb(2*skb
->len
+ tail
+ head
);
549 err("unable to allocate memory for HDLC encoding!");
553 skb_reserve(iraw_skb
, head
);
558 c
= gigaset_invtab
[*cp
++];
560 *(skb_put(iraw_skb
, 1)) = c
;
561 *(skb_put(iraw_skb
, 1)) = c
;
568 * called by common.c to queue an skb for sending
569 * and start transmission if necessary
571 * B Channel control structure
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)
578 int gigaset_m10x_send_skb(struct bc_state
*bcs
, struct sk_buff
*skb
)
582 IFNULLRETVAL(bcs
, -EFAULT
);
583 IFNULLRETVAL(skb
, -EFAULT
);
586 if (bcs
->proto2
== ISDN_PROTO_L2_HDLC
)
587 skb
= HDLC_Encode(skb
, HW_HDR_LEN
, 0);
589 skb
= iraw_encode(skb
, HW_HDR_LEN
, 0);
593 skb_queue_tail(&bcs
->squeue
, skb
);
594 tasklet_schedule(&bcs
->cs
->write_tasklet
);
596 return len
; /* ok so far */