blob: a375d0a411b50b30f7b175ba1b07b8f9b945a22e [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>,
6 * Stefan Eilers <Eilers.Stefan@epost.de>.
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 * =====================================================================
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",
101 numbytes, src, 0);
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;
120 int inputstate;
121 __u16 fcs;
122 struct sk_buff *skb;
123 unsigned char error;
124 struct sk_buff *compskb;
125 int startbytes = numbytes;
126 int l;
127
128 IFNULLRETVAL(bcs, numbytes);
129 inputstate = bcs->inputstate;
130 fcs = bcs->fcs;
131 skb = bcs->skb;
132 IFNULLRETVAL(skb, numbytes);
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 }
153byte_stuff:
154 c ^= PPP_TRANS;
155#ifdef CONFIG_GIGASET_DEBUG
156 if (unlikely(!muststuff(c)))
Tilman Schmidt784d5852006-04-10 22:55:04 -0700157 gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800158#endif
159 } else if (unlikely(c == PPP_FLAG)) {
160 if (unlikely(inputstate & INS_skip_frame)) {
161 if (!(inputstate & INS_have_data)) { /* 7E 7E */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800162#ifdef CONFIG_GIGASET_DEBUG
163 ++bcs->emptycount;
164#endif
165 } else
Tilman Schmidt784d5852006-04-10 22:55:04 -0700166 gig_dbg(DEBUG_HDLC,
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800167 "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 */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800173#ifdef CONFIG_GIGASET_DEBUG
174 ++bcs->emptycount;
175#endif
176 break;
177 } else {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700178 gig_dbg(DEBUG_HDLC,
179 "7e----------------------------");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800180
181 /* end of frame */
182 error = 0;
183
184 if (unlikely(fcs != PPP_GOODFCS)) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700185 dev_err(cs->dev,
186 "Packet checksum at %lu failed, "
187 "packet is corrupted (%u bytes)!\n",
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800188 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) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700201 dev_err(cs->dev,
202 "invalid packet size (1)!\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800203 error = 1;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700204 gigaset_rcv_error(NULL,
205 cs, bcs);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800206 }
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 {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700228 dev_warn(cs->dev,
229 "could not allocate new skb\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800230 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>. */
Tilman Schmidt784d5852006-04-10 22:55:04 -0700237 gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800238#endif
239 }
240
241 /* add character */
242
243#ifdef CONFIG_GIGASET_DEBUG
244 if (unlikely(!(inputstate & INS_have_data))) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700245 gig_dbg(DEBUG_HDLC, "7e (%d x) ================",
246 bcs->emptycount);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800247 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)) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700255 dev_warn(cs->dev, "received packet too long\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800256 dev_kfree_skb_any(skb);
257 skb = NULL;
258 inputstate |= INS_skip_frame;
259 break;
260 }
261 *gigaset_skb_put_quick(skb, 1) = c;
262 /* *__skb_put (skb, 1) = c; */
263 fcs = crc_ccitt_byte(fcs, c);
264 }
265
266 if (unlikely(!numbytes))
267 break;
268 c = *src++;
269 --numbytes;
270 if (unlikely(c == DLE_FLAG &&
271 (cs->dle ||
272 inbuf->inputstate & INS_DLE_command))) {
273 inbuf->inputstate |= INS_DLE_char;
274 break;
275 }
276 }
277 bcs->inputstate = inputstate;
278 bcs->fcs = fcs;
279 bcs->skb = skb;
280 return startbytes - numbytes;
281}
282
283/* process a block of received bytes in transparent data mode
284 * Invert bytes, undoing byte stuffing and watching for DLE escapes.
285 * If DLE is encountered, return immediately to let the caller handle it.
286 * Return value:
287 * number of processed bytes
288 * numbytes (all bytes processed) on error --FIXME
289 */
290static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700291 struct inbuf_t *inbuf)
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800292{
293 struct cardstate *cs = inbuf->cs;
294 struct bc_state *bcs = inbuf->bcs;
295 int inputstate;
296 struct sk_buff *skb;
297 int startbytes = numbytes;
298
299 IFNULLRETVAL(bcs, numbytes);
300 inputstate = bcs->inputstate;
301 skb = bcs->skb;
302 IFNULLRETVAL(skb, numbytes);
303
304 for (;;) {
305 /* add character */
306 inputstate |= INS_have_data;
307
308 if (likely(!(inputstate & INS_skip_frame))) {
309 if (unlikely(skb->len == SBUFSIZE)) {
310 //FIXME just pass skb up and allocate a new one
Tilman Schmidt784d5852006-04-10 22:55:04 -0700311 dev_warn(cs->dev, "received packet too long\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800312 dev_kfree_skb_any(skb);
313 skb = NULL;
314 inputstate |= INS_skip_frame;
315 break;
316 }
317 *gigaset_skb_put_quick(skb, 1) = gigaset_invtab[c];
318 }
319
320 if (unlikely(!numbytes))
321 break;
322 c = *src++;
323 --numbytes;
324 if (unlikely(c == DLE_FLAG &&
325 (cs->dle ||
326 inbuf->inputstate & INS_DLE_command))) {
327 inbuf->inputstate |= INS_DLE_char;
328 break;
329 }
330 }
331
332 /* pass data up */
333 if (likely(inputstate & INS_have_data)) {
334 if (likely(!(inputstate & INS_skip_frame))) {
335 gigaset_rcv_skb(skb, cs, bcs);
336 }
337 inputstate &= ~(INS_have_data | INS_skip_frame);
338 if (unlikely(bcs->ignore)) {
339 inputstate |= INS_skip_frame;
340 skb = NULL;
341 } else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN))
342 != NULL)) {
343 skb_reserve(skb, HW_HDR_LEN);
344 } else {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700345 dev_warn(cs->dev, "could not allocate new skb\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800346 inputstate |= INS_skip_frame;
347 }
348 }
349
350 bcs->inputstate = inputstate;
351 bcs->skb = skb;
352 return startbytes - numbytes;
353}
354
355/* process a block of data received from the device
356 */
357void gigaset_m10x_input(struct inbuf_t *inbuf)
358{
359 struct cardstate *cs;
360 unsigned tail, head, numbytes;
361 unsigned char *src, c;
362 int procbytes;
363
364 head = atomic_read(&inbuf->head);
365 tail = atomic_read(&inbuf->tail);
Tilman Schmidt784d5852006-04-10 22:55:04 -0700366 gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800367
368 if (head != tail) {
369 cs = inbuf->cs;
370 src = inbuf->data + head;
371 numbytes = (head > tail ? RBUFSIZE : tail) - head;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700372 gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800373
374 while (numbytes) {
375 if (atomic_read(&cs->mstate) == MS_LOCKED) {
376 procbytes = lock_loop(src, numbytes, inbuf);
377 src += procbytes;
378 numbytes -= procbytes;
379 } else {
380 c = *src++;
381 --numbytes;
382 if (c == DLE_FLAG && (cs->dle ||
383 inbuf->inputstate & INS_DLE_command)) {
384 if (!(inbuf->inputstate & INS_DLE_char)) {
385 inbuf->inputstate |= INS_DLE_char;
386 goto nextbyte;
387 }
388 /* <DLE> <DLE> => <DLE> in data stream */
389 inbuf->inputstate &= ~INS_DLE_char;
390 }
391
392 if (!(inbuf->inputstate & INS_DLE_char)) {
393
Tilman Schmidt917f5082006-04-10 22:55:00 -0700394 /* FIXME use function pointers? */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800395 if (inbuf->inputstate & INS_command)
396 procbytes = cmd_loop(c, src, numbytes, inbuf);
397 else if (inbuf->bcs->proto2 == ISDN_PROTO_L2_HDLC)
398 procbytes = hdlc_loop(c, src, numbytes, inbuf);
399 else
400 procbytes = iraw_loop(c, src, numbytes, inbuf);
401
402 src += procbytes;
403 numbytes -= procbytes;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700404 } else { /* DLE char */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800405 inbuf->inputstate &= ~INS_DLE_char;
406 switch (c) {
407 case 'X': /*begin of command*/
408#ifdef CONFIG_GIGASET_DEBUG
409 if (inbuf->inputstate & INS_command)
Tilman Schmidt784d5852006-04-10 22:55:04 -0700410 dev_err(cs->dev,
411 "received <DLE> 'X' in command mode\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800412#endif
413 inbuf->inputstate |=
414 INS_command | INS_DLE_command;
415 break;
416 case '.': /*end of command*/
417#ifdef CONFIG_GIGASET_DEBUG
418 if (!(inbuf->inputstate & INS_command))
Tilman Schmidt784d5852006-04-10 22:55:04 -0700419 dev_err(cs->dev,
420 "received <DLE> '.' in hdlc mode\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800421#endif
422 inbuf->inputstate &= cs->dle ?
423 ~(INS_DLE_command|INS_command)
424 : ~INS_DLE_command;
425 break;
426 //case DLE_FLAG: /*DLE_FLAG in data stream*/ /* schon oben behandelt! */
427 default:
Tilman Schmidt784d5852006-04-10 22:55:04 -0700428 dev_err(cs->dev,
429 "received 0x10 0x%02x!\n",
430 (int) c);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800431 /* FIXME: reset driver?? */
432 }
433 }
434 }
435nextbyte:
436 if (!numbytes) {
437 /* end of buffer, check for wrap */
438 if (head > tail) {
439 head = 0;
440 src = inbuf->data;
441 numbytes = tail;
442 } else {
443 head = tail;
444 break;
445 }
446 }
447 }
448
Tilman Schmidt784d5852006-04-10 22:55:04 -0700449 gig_dbg(DEBUG_INTR, "setting head to %u", head);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800450 atomic_set(&inbuf->head, head);
451 }
452}
453
454
455/* == data output ========================================================== */
456
457/* Encoding of a PPP packet into an octet stuffed HDLC frame
458 * with FCS, opening and closing flags.
459 * parameters:
460 * skb skb containing original packet (freed upon return)
461 * head number of headroom bytes to allocate in result skb
462 * tail number of tailroom bytes to allocate in result skb
463 * Return value:
464 * pointer to newly allocated skb containing the result frame
465 */
466static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail)
467{
468 struct sk_buff *hdlc_skb;
469 __u16 fcs;
470 unsigned char c;
471 unsigned char *cp;
472 int len;
473 unsigned int stuf_cnt;
474
475 stuf_cnt = 0;
476 fcs = PPP_INITFCS;
477 cp = skb->data;
478 len = skb->len;
479 while (len--) {
480 if (muststuff(*cp))
481 stuf_cnt++;
482 fcs = crc_ccitt_byte(fcs, *cp++);
483 }
Tilman Schmidt784d5852006-04-10 22:55:04 -0700484 fcs ^= 0xffff; /* complement */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800485
486 /* size of new buffer: original size + number of stuffing bytes
487 * + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes
488 */
489 hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + tail + head);
490 if (!hdlc_skb) {
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800491 dev_kfree_skb(skb);
492 return NULL;
493 }
494 skb_reserve(hdlc_skb, head);
495
496 /* Copy acknowledge request into new skb */
497 memcpy(hdlc_skb->head, skb->head, 2);
498
499 /* Add flag sequence in front of everything.. */
500 *(skb_put(hdlc_skb, 1)) = PPP_FLAG;
501
502 /* Perform byte stuffing while copying data. */
503 while (skb->len--) {
504 if (muststuff(*skb->data)) {
505 *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
506 *(skb_put(hdlc_skb, 1)) = (*skb->data++) ^ PPP_TRANS;
507 } else
508 *(skb_put(hdlc_skb, 1)) = *skb->data++;
509 }
510
511 /* Finally add FCS (byte stuffed) and flag sequence */
Tilman Schmidt784d5852006-04-10 22:55:04 -0700512 c = (fcs & 0x00ff); /* least significant byte first */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800513 if (muststuff(c)) {
514 *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
515 c ^= PPP_TRANS;
516 }
517 *(skb_put(hdlc_skb, 1)) = c;
518
519 c = ((fcs >> 8) & 0x00ff);
520 if (muststuff(c)) {
521 *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
522 c ^= PPP_TRANS;
523 }
524 *(skb_put(hdlc_skb, 1)) = c;
525
526 *(skb_put(hdlc_skb, 1)) = PPP_FLAG;
527
528 dev_kfree_skb(skb);
529 return hdlc_skb;
530}
531
532/* Encoding of a raw packet into an octet stuffed bit inverted frame
533 * parameters:
534 * skb skb containing original packet (freed upon return)
535 * head number of headroom bytes to allocate in result skb
536 * tail number of tailroom bytes to allocate in result skb
537 * Return value:
538 * pointer to newly allocated skb containing the result frame
539 */
540static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
541{
542 struct sk_buff *iraw_skb;
543 unsigned char c;
544 unsigned char *cp;
545 int len;
546
547 /* worst case: every byte must be stuffed */
548 iraw_skb = dev_alloc_skb(2*skb->len + tail + head);
549 if (!iraw_skb) {
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800550 dev_kfree_skb(skb);
551 return NULL;
552 }
553 skb_reserve(iraw_skb, head);
554
555 cp = skb->data;
556 len = skb->len;
557 while (len--) {
558 c = gigaset_invtab[*cp++];
559 if (c == DLE_FLAG)
560 *(skb_put(iraw_skb, 1)) = c;
561 *(skb_put(iraw_skb, 1)) = c;
562 }
563 dev_kfree_skb(skb);
564 return iraw_skb;
565}
566
567/* gigaset_send_skb
568 * called by common.c to queue an skb for sending
569 * and start transmission if necessary
570 * parameters:
571 * B Channel control structure
572 * skb
573 * Return value:
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)
577 */
578int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb)
579{
580 unsigned len;
581
582 IFNULLRETVAL(bcs, -EFAULT);
583 IFNULLRETVAL(skb, -EFAULT);
584 len = skb->len;
585
586 if (bcs->proto2 == ISDN_PROTO_L2_HDLC)
587 skb = HDLC_Encode(skb, HW_HDR_LEN, 0);
588 else
589 skb = iraw_encode(skb, HW_HDR_LEN, 0);
Tilman Schmidt784d5852006-04-10 22:55:04 -0700590 if (!skb) {
591 dev_err(bcs->cs->dev,
592 "unable to allocate memory for encoding!\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800593 return -ENOMEM;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700594 }
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800595
596 skb_queue_tail(&bcs->squeue, skb);
597 tasklet_schedule(&bcs->cs->write_tasklet);
598
599 return len; /* ok so far */
600}