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>,
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 * =====================================================================
17 #include <linux/crc-ccitt.h>
19 //#define GIG_M10x_STUFF_VOICE_DATA
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.
26 static inline int muststuff(unsigned char c
)
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 */
37 /* == data input =========================================================== */
39 /* process a block of received bytes in command mode (modem response)
41 * number of processed bytes
43 static inline int cmd_loop(unsigned char c
, unsigned char *src
, int numbytes
,
44 struct inbuf_t
*inbuf
)
46 struct cardstate
*cs
= inbuf
->cs
;
47 unsigned cbytes
= cs
->cbytes
;
48 int inputstate
= inbuf
->inputstate
;
49 int startbytes
= numbytes
;
52 cs
->respdata
[cbytes
] = c
;
53 if (c
== 10 || c
== 13) {
54 gig_dbg(DEBUG_TRANSCMD
, "%s: End of Command (%d Bytes)",
57 gigaset_handle_modem_response(cs
); /* can change
62 !(inputstate
& INS_DLE_command
)) {
63 inputstate
&= ~INS_command
;
67 /* advance in line buffer, checking for overflow */
68 if (cbytes
< MAX_RESP_SIZE
- 1)
71 dev_warn(cs
->dev
, "response too large\n");
79 (cs
->dle
|| inputstate
& INS_DLE_command
)) {
80 inputstate
|= INS_DLE_char
;
86 inbuf
->inputstate
= inputstate
;
88 return startbytes
- numbytes
;
91 /* process a block of received bytes in lock mode (tty i/f)
93 * number of processed bytes
95 static inline int lock_loop(unsigned char *src
, int numbytes
,
96 struct inbuf_t
*inbuf
)
98 struct cardstate
*cs
= inbuf
->cs
;
100 gigaset_dbg_buffer(DEBUG_LOCKCMD
, "received response",
102 gigaset_if_receive(cs
, src
, numbytes
);
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.
112 * number of processed bytes
113 * numbytes (all bytes processed) on error --FIXME
115 static inline int hdlc_loop(unsigned char c
, unsigned char *src
, int numbytes
,
116 struct inbuf_t
*inbuf
)
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
;
124 struct sk_buff
*compskb
;
125 int startbytes
= numbytes
;
128 if (unlikely(inputstate
& INS_byte_stuff
)) {
129 inputstate
&= ~INS_byte_stuff
;
133 if (unlikely(c
== PPP_ESCAPE
)) {
134 if (unlikely(!numbytes
)) {
135 inputstate
|= INS_byte_stuff
;
140 if (unlikely(c
== DLE_FLAG
&&
142 inbuf
->inputstate
& INS_DLE_command
))) {
143 inbuf
->inputstate
|= INS_DLE_char
;
144 inputstate
|= INS_byte_stuff
;
149 #ifdef CONFIG_GIGASET_DEBUG
150 if (unlikely(!muststuff(c
)))
151 gig_dbg(DEBUG_HDLC
, "byte stuffed: 0x%02x", c
);
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
161 "7e----------------------------");
165 gigaset_rcv_error(NULL
, cs
, bcs
);
166 } else if (!(inputstate
& INS_have_data
)) { /* 7E 7E */
167 #ifdef CONFIG_GIGASET_DEBUG
173 "7e----------------------------");
178 if (unlikely(fcs
!= PPP_GOODFCS
)) {
180 "Packet checksum at %lu failed, "
181 "packet is corrupted (%u bytes)!\n",
182 bcs
->rcvbytes
, skb
->len
);
184 gigaset_rcv_error(compskb
, cs
, bcs
);
187 if (likely((l
= skb
->len
) > 2)) {
193 inputstate
|= INS_skip_frame
;
196 "invalid packet size (1)!\n");
198 gigaset_rcv_error(NULL
,
202 if (likely(!(error
||
205 gigaset_rcv_skb(skb
, cs
, bcs
);
215 inputstate
&= ~(INS_have_data
| INS_skip_frame
);
216 if (unlikely(bcs
->ignore
)) {
217 inputstate
|= INS_skip_frame
;
219 } else if (likely((skb
= dev_alloc_skb(SBUFSIZE
+ HW_HDR_LEN
)) != NULL
)) {
220 skb_reserve(skb
, HW_HDR_LEN
);
223 "could not allocate new skb\n");
224 inputstate
|= INS_skip_frame
;
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
);
237 #ifdef CONFIG_GIGASET_DEBUG
238 if (unlikely(!(inputstate
& INS_have_data
))) {
239 gig_dbg(DEBUG_HDLC
, "7e (%d x) ================",
245 inputstate
|= INS_have_data
;
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
);
252 inputstate
|= INS_skip_frame
;
255 *__skb_put(skb
, 1) = c
;
256 fcs
= crc_ccitt_byte(fcs
, c
);
259 if (unlikely(!numbytes
))
263 if (unlikely(c
== DLE_FLAG
&&
265 inbuf
->inputstate
& INS_DLE_command
))) {
266 inbuf
->inputstate
|= INS_DLE_char
;
270 bcs
->inputstate
= inputstate
;
273 return startbytes
- numbytes
;
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.
280 * number of processed bytes
281 * numbytes (all bytes processed) on error --FIXME
283 static inline int iraw_loop(unsigned char c
, unsigned char *src
, int numbytes
,
284 struct inbuf_t
*inbuf
)
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
;
294 inputstate
|= INS_have_data
;
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
);
302 inputstate
|= INS_skip_frame
;
305 *__skb_put(skb
, 1) = gigaset_invtab
[c
];
308 if (unlikely(!numbytes
))
312 if (unlikely(c
== DLE_FLAG
&&
314 inbuf
->inputstate
& INS_DLE_command
))) {
315 inbuf
->inputstate
|= INS_DLE_char
;
321 if (likely(inputstate
& INS_have_data
)) {
322 if (likely(!(inputstate
& INS_skip_frame
))) {
323 gigaset_rcv_skb(skb
, cs
, bcs
);
325 inputstate
&= ~(INS_have_data
| INS_skip_frame
);
326 if (unlikely(bcs
->ignore
)) {
327 inputstate
|= INS_skip_frame
;
329 } else if (likely((skb
= dev_alloc_skb(SBUFSIZE
+ HW_HDR_LEN
))
331 skb_reserve(skb
, HW_HDR_LEN
);
333 dev_warn(cs
->dev
, "could not allocate new skb\n");
334 inputstate
|= INS_skip_frame
;
338 bcs
->inputstate
= inputstate
;
340 return startbytes
- numbytes
;
343 /* process a block of data received from the device
345 void gigaset_m10x_input(struct inbuf_t
*inbuf
)
347 struct cardstate
*cs
;
348 unsigned tail
, head
, numbytes
;
349 unsigned char *src
, c
;
352 head
= atomic_read(&inbuf
->head
);
353 tail
= atomic_read(&inbuf
->tail
);
354 gig_dbg(DEBUG_INTR
, "buffer state: %u -> %u", head
, tail
);
358 src
= inbuf
->data
+ head
;
359 numbytes
= (head
> tail
? RBUFSIZE
: tail
) - head
;
360 gig_dbg(DEBUG_INTR
, "processing %u bytes", numbytes
);
363 if (atomic_read(&cs
->mstate
) == MS_LOCKED
) {
364 procbytes
= lock_loop(src
, numbytes
, inbuf
);
366 numbytes
-= procbytes
;
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
;
376 /* <DLE> <DLE> => <DLE> in data stream */
377 inbuf
->inputstate
&= ~INS_DLE_char
;
380 if (!(inbuf
->inputstate
& INS_DLE_char
)) {
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
);
388 procbytes
= iraw_loop(c
, src
, numbytes
, inbuf
);
391 numbytes
-= procbytes
;
392 } else { /* DLE char */
393 inbuf
->inputstate
&= ~INS_DLE_char
;
395 case 'X': /*begin of command*/
396 #ifdef CONFIG_GIGASET_DEBUG
397 if (inbuf
->inputstate
& INS_command
)
399 "received <DLE> 'X' in command mode\n");
402 INS_command
| INS_DLE_command
;
404 case '.': /*end of command*/
405 #ifdef CONFIG_GIGASET_DEBUG
406 if (!(inbuf
->inputstate
& INS_command
))
408 "received <DLE> '.' in hdlc mode\n");
410 inbuf
->inputstate
&= cs
->dle
?
411 ~(INS_DLE_command
|INS_command
)
414 //case DLE_FLAG: /*DLE_FLAG in data stream*/ /* schon oben behandelt! */
417 "received 0x10 0x%02x!\n",
419 /* FIXME: reset driver?? */
425 /* end of buffer, check for wrap */
437 gig_dbg(DEBUG_INTR
, "setting head to %u", head
);
438 atomic_set(&inbuf
->head
, head
);
443 /* == data output ========================================================== */
445 /* Encoding of a PPP packet into an octet stuffed HDLC frame
446 * with FCS, opening and closing flags.
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
452 * pointer to newly allocated skb containing the result frame
454 static struct sk_buff
*HDLC_Encode(struct sk_buff
*skb
, int head
, int tail
)
456 struct sk_buff
*hdlc_skb
;
461 unsigned int stuf_cnt
;
470 fcs
= crc_ccitt_byte(fcs
, *cp
++);
472 fcs
^= 0xffff; /* complement */
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
477 hdlc_skb
= dev_alloc_skb(skb
->len
+ stuf_cnt
+ 6 + tail
+ head
);
482 skb_reserve(hdlc_skb
, head
);
484 /* Copy acknowledge request into new skb */
485 memcpy(hdlc_skb
->head
, skb
->head
, 2);
487 /* Add flag sequence in front of everything.. */
488 *(skb_put(hdlc_skb
, 1)) = PPP_FLAG
;
490 /* Perform byte stuffing while copying data. */
492 if (muststuff(*skb
->data
)) {
493 *(skb_put(hdlc_skb
, 1)) = PPP_ESCAPE
;
494 *(skb_put(hdlc_skb
, 1)) = (*skb
->data
++) ^ PPP_TRANS
;
496 *(skb_put(hdlc_skb
, 1)) = *skb
->data
++;
499 /* Finally add FCS (byte stuffed) and flag sequence */
500 c
= (fcs
& 0x00ff); /* least significant byte first */
502 *(skb_put(hdlc_skb
, 1)) = PPP_ESCAPE
;
505 *(skb_put(hdlc_skb
, 1)) = c
;
507 c
= ((fcs
>> 8) & 0x00ff);
509 *(skb_put(hdlc_skb
, 1)) = PPP_ESCAPE
;
512 *(skb_put(hdlc_skb
, 1)) = c
;
514 *(skb_put(hdlc_skb
, 1)) = PPP_FLAG
;
520 /* Encoding of a raw packet into an octet stuffed bit inverted frame
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
526 * pointer to newly allocated skb containing the result frame
528 static struct sk_buff
*iraw_encode(struct sk_buff
*skb
, int head
, int tail
)
530 struct sk_buff
*iraw_skb
;
535 /* worst case: every byte must be stuffed */
536 iraw_skb
= dev_alloc_skb(2*skb
->len
+ tail
+ head
);
541 skb_reserve(iraw_skb
, head
);
546 c
= gigaset_invtab
[*cp
++];
548 *(skb_put(iraw_skb
, 1)) = c
;
549 *(skb_put(iraw_skb
, 1)) = c
;
556 * called by common.c to queue an skb for sending
557 * and start transmission if necessary
559 * B Channel control structure
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)
566 int gigaset_m10x_send_skb(struct bc_state
*bcs
, struct sk_buff
*skb
)
568 unsigned len
= skb
->len
;
571 if (bcs
->proto2
== ISDN_PROTO_L2_HDLC
)
572 skb
= HDLC_Encode(skb
, HW_HDR_LEN
, 0);
574 skb
= iraw_encode(skb
, HW_HDR_LEN
, 0);
576 err("unable to allocate memory for encoding!\n");
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
);
586 return len
; /* ok so far */