blob: ce3cd77094b334f8e362ca67404c8ab1baa2ffbd [file] [log] [blame]
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -08001/*
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>,
Tilman Schmidt70440cf2006-04-10 22:55:14 -07006 * Stefan Eilers.
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -08007 *
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 * =====================================================================
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -080014 */
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 */
26static 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 */
43static inline int cmd_loop(unsigned char c, unsigned char *src, int numbytes,
Tilman Schmidt784d5852006-04-10 22:55:04 -070044 struct inbuf_t *inbuf)
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -080045{
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) {
Tilman Schmidt784d5852006-04-10 22:55:04 -070054 gig_dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)",
55 __func__, cbytes);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -080056 cs->cbytes = cbytes;
Tilman Schmidt917f5082006-04-10 22:55:00 -070057 gigaset_handle_modem_response(cs); /* can change
58 cs->dle */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -080059 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
Tilman Schmidt784d5852006-04-10 22:55:04 -070071 dev_warn(cs->dev, "response too large\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -080072 }
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 */
95static inline int lock_loop(unsigned char *src, int numbytes,
Tilman Schmidt784d5852006-04-10 22:55:04 -070096 struct inbuf_t *inbuf)
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -080097{
98 struct cardstate *cs = inbuf->cs;
99
Tilman Schmidt917f5082006-04-10 22:55:00 -0700100 gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response",
Tilman Schmidt01371502006-04-10 22:55:11 -0700101 numbytes, src);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800102 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 */
115static inline int hdlc_loop(unsigned char c, unsigned char *src, int numbytes,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700116 struct inbuf_t *inbuf)
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800117{
118 struct cardstate *cs = inbuf->cs;
119 struct bc_state *bcs = inbuf->bcs;
Tilman Schmidtd48c7782006-04-10 22:55:08 -0700120 int inputstate = bcs->inputstate;
121 __u16 fcs = bcs->fcs;
122 struct sk_buff *skb = bcs->skb;
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800123 unsigned char error;
124 struct sk_buff *compskb;
125 int startbytes = numbytes;
126 int l;
127
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800128 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 }
147byte_stuff:
148 c ^= PPP_TRANS;
149#ifdef CONFIG_GIGASET_DEBUG
150 if (unlikely(!muststuff(c)))
Tilman Schmidt784d5852006-04-10 22:55:04 -0700151 gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800152#endif
153 } else if (unlikely(c == PPP_FLAG)) {
154 if (unlikely(inputstate & INS_skip_frame)) {
155 if (!(inputstate & INS_have_data)) { /* 7E 7E */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800156#ifdef CONFIG_GIGASET_DEBUG
157 ++bcs->emptycount;
158#endif
159 } else
Tilman Schmidt784d5852006-04-10 22:55:04 -0700160 gig_dbg(DEBUG_HDLC,
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800161 "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 */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800167#ifdef CONFIG_GIGASET_DEBUG
168 ++bcs->emptycount;
169#endif
170 break;
171 } else {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700172 gig_dbg(DEBUG_HDLC,
173 "7e----------------------------");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800174
175 /* end of frame */
176 error = 0;
177
178 if (unlikely(fcs != PPP_GOODFCS)) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700179 dev_err(cs->dev,
180 "Packet checksum at %lu failed, "
181 "packet is corrupted (%u bytes)!\n",
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800182 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) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700195 dev_err(cs->dev,
196 "invalid packet size (1)!\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800197 error = 1;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700198 gigaset_rcv_error(NULL,
199 cs, bcs);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800200 }
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 {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700222 dev_warn(cs->dev,
223 "could not allocate new skb\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800224 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>. */
Tilman Schmidt784d5852006-04-10 22:55:04 -0700231 gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800232#endif
233 }
234
235 /* add character */
236
237#ifdef CONFIG_GIGASET_DEBUG
238 if (unlikely(!(inputstate & INS_have_data))) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700239 gig_dbg(DEBUG_HDLC, "7e (%d x) ================",
240 bcs->emptycount);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800241 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)) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700249 dev_warn(cs->dev, "received packet too long\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800250 dev_kfree_skb_any(skb);
251 skb = NULL;
252 inputstate |= INS_skip_frame;
253 break;
254 }
Tilman Schmidt443e1f42006-04-10 22:55:13 -0700255 *__skb_put(skb, 1) = c;
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800256 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 */
283static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700284 struct inbuf_t *inbuf)
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800285{
286 struct cardstate *cs = inbuf->cs;
287 struct bc_state *bcs = inbuf->bcs;
Tilman Schmidtd48c7782006-04-10 22:55:08 -0700288 int inputstate = bcs->inputstate;
289 struct sk_buff *skb = bcs->skb;
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800290 int startbytes = numbytes;
291
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800292 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
Tilman Schmidt784d5852006-04-10 22:55:04 -0700299 dev_warn(cs->dev, "received packet too long\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800300 dev_kfree_skb_any(skb);
301 skb = NULL;
302 inputstate |= INS_skip_frame;
303 break;
304 }
Tilman Schmidt443e1f42006-04-10 22:55:13 -0700305 *__skb_put(skb, 1) = gigaset_invtab[c];
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800306 }
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 {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700333 dev_warn(cs->dev, "could not allocate new skb\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800334 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 */
345void 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);
Tilman Schmidt784d5852006-04-10 22:55:04 -0700354 gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800355
356 if (head != tail) {
357 cs = inbuf->cs;
358 src = inbuf->data + head;
359 numbytes = (head > tail ? RBUFSIZE : tail) - head;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700360 gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800361
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
Tilman Schmidt917f5082006-04-10 22:55:00 -0700382 /* FIXME use function pointers? */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800383 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;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700392 } else { /* DLE char */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800393 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)
Tilman Schmidt784d5852006-04-10 22:55:04 -0700398 dev_err(cs->dev,
399 "received <DLE> 'X' in command mode\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800400#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))
Tilman Schmidt784d5852006-04-10 22:55:04 -0700407 dev_err(cs->dev,
408 "received <DLE> '.' in hdlc mode\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800409#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:
Tilman Schmidt784d5852006-04-10 22:55:04 -0700416 dev_err(cs->dev,
417 "received 0x10 0x%02x!\n",
418 (int) c);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800419 /* FIXME: reset driver?? */
420 }
421 }
422 }
423nextbyte:
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
Tilman Schmidt784d5852006-04-10 22:55:04 -0700437 gig_dbg(DEBUG_INTR, "setting head to %u", head);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800438 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 */
454static 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 }
Tilman Schmidt784d5852006-04-10 22:55:04 -0700472 fcs ^= 0xffff; /* complement */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800473
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) {
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800479 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 */
Tilman Schmidt784d5852006-04-10 22:55:04 -0700500 c = (fcs & 0x00ff); /* least significant byte first */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800501 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 */
528static 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) {
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800538 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 */
566int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb)
567{
Tilman Schmidtd48c7782006-04-10 22:55:08 -0700568 unsigned len = skb->len;
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700569 unsigned long flags;
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800570
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);
Tilman Schmidt784d5852006-04-10 22:55:04 -0700575 if (!skb) {
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700576 err("unable to allocate memory for encoding!\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800577 return -ENOMEM;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700578 }
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800579
580 skb_queue_tail(&bcs->squeue, skb);
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700581 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);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800585
586 return len; /* ok so far */
587}