more changes on original files
[linux-2.4.git] / drivers / usb / auerisdn_b.c
1 /*****************************************************************************/
2 /*
3  *      auerisdn_b.c  --  Auerswald PBX/System Telephone ISDN B-channel interface.
4  *
5  *      Copyright (C) 2002  Wolfgang Mües (wolfgang@iksw-muees.de)
6  *
7  *      This program is free software; you can redistribute it and/or modify
8  *      it under the terms of the GNU General Public License as published by
9  *      the Free Software Foundation; either version 2 of the License, or
10  *      (at your option) any later version.
11  *
12  *      This program is distributed in the hope that it will be useful,
13  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *      GNU General Public License for more details.
16  *
17  *      You should have received a copy of the GNU General Public License
18  *      along with this program; if not, write to the Free Software
19  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21  /*****************************************************************************/
22
23 #include <linux/isdnif.h>       /* ISDN constants */
24 #include <linux/netdevice.h>    /* skb functions */
25
26 #undef DEBUG                    /* include debug macros until it's done */
27 #include <linux/usb.h>          /* standard usb header */
28
29 #include "auerisdn.h"
30 #include "auermain.h"
31
32 /*-------------------------------------------------------------------*/
33 /* ISDN B channel support defines                                    */
34 #define AUISDN_BC_1MS           8       /* Bytes per channel and ms */
35 #define AUISDN_BC_INC           4       /* change INT OUT size increment */
36 #define AUISDN_BCDATATHRESHOLD  48      /* for unsymmetric 2-B-channels */
37 #define AUISDN_TOGGLETIME       6       /* Timeout for unsymmetric serve */
38
39 /*-------------------------------------------------------------------*/
40 /* Debug support                                                     */
41 #ifdef DEBUG
42 #define dump( desc, adr, len) \
43 do {                    \
44         unsigned int u; \
45         printk (KERN_DEBUG); \
46         printk (desc); \
47         for (u = 0; u < len; u++) \
48                 printk (" %02X", adr[u] & 0xFF); \
49         printk ("\n"); \
50 } while (0)
51 #else
52 #define dump( desc, adr, len)
53 #endif
54
55 /*-------------------------------------------------------------------*/
56
57 /* Callback to L2 for HISAX */
58 /* This callback can be called from 3 sources:
59    a) from hisax context (answer from a l2l1 function)
60    b) from interrupt context (a B channel paket arrived, a B channel paket was sent)
61    c) from kernel daemon context (probe/disconnecting)
62 */
63 void auerisdn_b_l1l2(struct auerisdnbc *bc, int pr, void *arg)
64 {
65         struct auerhisax *ahp;
66         struct sk_buff *skb;
67
68         /* do the callback */
69         ahp = bc->cp->isdn.ahp;
70         if (ahp) {
71                 ahp->hisax_b_if[bc->channel].ifc.l1l2(&ahp->
72                                                       hisax_b_if[bc->
73                                                                  channel].
74                                                       ifc, pr, arg);
75         } else {
76                 dbg("auerisdn_b_l1l2 called without ahp");
77                 if (pr == (PH_DATA | INDICATION)) {
78                         skb = (struct sk_buff *) arg;
79                         if (skb) {
80                                 skb_pull(skb, skb->len);
81                                 dev_kfree_skb_any(skb);
82                         }
83                 }
84         }
85 }
86
87 /* fill the INT OUT data buffer with new data */
88 /* Transfer buffer size to fill is in urbp->transfer_buffer_length */
89 static void auerisdn_bintbo_newdata(struct auerisdn *ip)
90 {
91         unsigned long flags;
92         struct urb *urbp = ip->intbo_urbp;
93         struct auerisdnbc *bc = &ip->bc[0];     /* start with B-channel 0 */
94         struct sk_buff *skb;
95         unsigned char *ucp;
96         int buf_size;
97         int len;
98         int bytes_sent;
99         int i;
100
101         /* FIXME: this algorithm is fixed to 2 B-channels */
102         /* Which B channel should we serve? */
103         if (ip->bc[1].mode != L1_MODE_NULL) {
104                 /* B channel 1 is used */
105                 if (bc->mode != L1_MODE_NULL) {
106                         /* both B-channels are used */
107                         if (ip->intbo_toggletimer) {
108                                 /* simply toggling */
109                                 ip->intbo_toggletimer--;
110                                 i = ip->intbo_index ^ 1;        /* serve both channels equal */
111                         } else {
112                                 /* search the B channel with the most demand of data */
113                                 i = bc->txfree - ip->bc[1].txfree;
114                                 if (i < -AUISDN_BCDATATHRESHOLD)
115                                         i = 1;  /* B channel 1 needs more data */
116                                 else if (i > AUISDN_BCDATATHRESHOLD)
117                                         i = 0;  /* B channel 0 needs more data */
118                                 else
119                                         i = ip->intbo_index ^ 1;        /* serve both channels equal */
120                                 if (i == ip->intbo_index)
121                                         ip->intbo_toggletimer =
122                                             AUISDN_TOGGLETIME;
123                         }
124                         bc = &ip->bc[i];
125                         ip->intbo_index = i;
126                 } else {
127                         bc = &ip->bc[1];
128                 }
129         }
130         dbg("INTBO: Fill B%d with %d Bytes, %d Bytes free",
131             bc->channel + 1, urbp->transfer_buffer_length - AUH_SIZE,
132             bc->txfree);
133
134         /* Fill the buffer with data */
135         ucp = ip->intbo_bufp;
136         *ucp++ = AUH_B1CHANNEL + bc->channel;   /* First byte is channel nr. */
137         buf_size = urbp->transfer_buffer_length - AUH_SIZE;
138         len = 0;
139         while (len < buf_size) {
140                 spin_lock_irqsave(&bc->txskb_lock, flags);
141                 if ((skb = bc->txskb)) {
142                         /* dump ("raw tx data:", skb->data, skb->len); */
143                         if (bc->mode == L1_MODE_TRANS) {
144                                 bytes_sent = buf_size - len;
145                                 if (skb->len < bytes_sent)
146                                         bytes_sent = skb->len;
147                                 {       /* swap tx bytes */
148                                         register unsigned char *src =
149                                             skb->data;
150                                         unsigned int count;
151                                         for (count = 0; count < bytes_sent;
152                                              count++)
153                                                 *ucp++ =
154                                                     isdnhdlc_bit_rev_tab
155                                                     [*src++];
156                                 }
157                                 len += bytes_sent;
158                                 bc->lastbyte = skb->data[bytes_sent - 1];
159                         } else {
160                                 int bs =
161                                     isdnhdlc_encode(&bc->outp_hdlc_state,
162                                                     skb->data, skb->len,
163                                                     &bytes_sent,
164                                                     ucp, buf_size - len);
165                                 /* dump ("hdlc data:", ucp, bs); */
166                                 len += bs;
167                                 ucp += bs;
168                         }
169                         skb_pull(skb, bytes_sent);
170
171                         if (!skb->len) {
172                                 // Frame sent
173                                 bc->txskb = NULL;
174                                 spin_unlock_irqrestore(&bc->txskb_lock,
175                                                        flags);
176                                 auerisdn_b_l1l2(bc, PH_DATA | CONFIRM,
177                                                 (void *) skb->truesize);
178                                 dev_kfree_skb_any(skb);
179                                 continue;       //while
180                         }
181                 } else {
182                         if (bc->mode == L1_MODE_TRANS) {
183                                 memset(ucp, bc->lastbyte, buf_size - len);
184                                 ucp += buf_size - len;
185                                 len = buf_size;
186                                 /* dbg ("fill = 0xFF"); */
187                         } else {
188                                 // Send flags
189                                 int bs =
190                                     isdnhdlc_encode(&bc->outp_hdlc_state,
191                                                     NULL, 0, &bytes_sent,
192                                                     ucp, buf_size - len);
193                                 /* dbg ("fill = 0x%02X", (int)*ucp); */
194                                 len += bs;
195                                 ucp += bs;
196                         }
197                 }
198                 spin_unlock_irqrestore(&bc->txskb_lock, flags);
199         }
200         /* dbg ("%d Bytes to TX buffer", len); */
201 }
202
203
204 /* INT OUT completion handler */
205 static void auerisdn_bintbo_complete(struct urb *urbp)
206 {
207         struct auerisdn *ip = urbp->context;
208
209         /* unlink completion? */
210         if ((urbp->status == -ENOENT) || (urbp->status == -ECONNRESET)) {
211                 /* should we restart with another size? */
212                 if (ip->intbo_state == INTBOS_CHANGE) {
213                         dbg("state => RESTART");
214                         ip->intbo_state = INTBOS_RESTART;
215                 } else {
216                         /* set up variables for later restart */
217                         dbg("INTBO stopped");
218                         ip->intbo_state = INTBOS_IDLE;
219                 }
220                 /* nothing more to do */
221                 return;
222         }
223
224         /* other state != 0? */
225         if (urbp->status) {
226                 warn("auerisdn_bintbo_complete: status = %d",
227                      urbp->status);
228                 return;
229         }
230
231         /* Should we fill in new data? */
232         if (ip->intbo_state == INTBOS_CHANGE) {
233                 dbg("state == INTBOS_CHANGE, no new data");
234                 return;
235         }
236
237         /* fill in new data */
238         auerisdn_bintbo_newdata(ip);
239 }
240
241 /* set up the INT OUT URB the first time */
242 /* Don't start the URB */
243 static void auerisdn_bintbo_setup(struct auerisdn *ip, unsigned int len)
244 {
245         ip->intbo_state = INTBOS_IDLE;
246         FILL_INT_URB(ip->intbo_urbp, ip->usbdev,
247                      usb_sndintpipe(ip->usbdev, ip->intbo_endp),
248                      ip->intbo_bufp, len, auerisdn_bintbo_complete, ip,
249                      ip->outInterval);
250         ip->intbo_urbp->transfer_flags |= USB_ASYNC_UNLINK;
251         ip->intbo_urbp->status = 0;
252 }
253
254 /* restart the INT OUT endpoint */
255 static void auerisdn_bintbo_restart(struct auerisdn *ip)
256 {
257         struct urb *urbp = ip->intbo_urbp;
258         int status;
259
260         /* dbg ("auerisdn_intbo_restart"); */
261
262         /* fresh restart */
263         auerisdn_bintbo_setup(ip, ip->paketsize + AUH_SIZE);
264
265         /* Fill in new data */
266         auerisdn_bintbo_newdata(ip);
267
268         /* restart the urb */
269         ip->intbo_state = INTBOS_RUNNING;
270         status = usb_submit_urb(urbp);
271         if (status < 0) {
272                 err("can't submit INT OUT urb, status = %d", status);
273                 urbp->status = status;
274                 urbp->complete(urbp);
275         }
276 }
277
278 /* change the size of the INT OUT endpoint */
279 static void auerisdn_bchange(struct auerisdn *ip, unsigned int paketsize)
280 {
281         /* changing... */
282         dbg("txfree[0] = %d, txfree[1] = %d, old size = %d, new size = %d",
283             ip->bc[0].txfree, ip->bc[1].txfree, ip->paketsize, paketsize);
284         ip->paketsize = paketsize;
285
286         if (paketsize == 0) {
287                 /* stop the INT OUT endpoint */
288                 dbg("stop unlinking INT out urb");
289                 ip->intbo_state = INTBOS_IDLE;
290                 usb_unlink_urb(ip->intbo_urbp);
291                 return;
292         }
293         if (ip->intbo_state != INTBOS_IDLE) {
294                 /* dbg ("unlinking INT out urb"); */
295                 ip->intbo_state = INTBOS_CHANGE;
296                 usb_unlink_urb(ip->intbo_urbp);
297         } else {
298                 /* dbg ("restart immediately"); */
299                 auerisdn_bintbo_restart(ip);
300         }
301 }
302
303 /* serve the outgoing B channel interrupt */
304 /* Called from the INT IN completion handler */
305 static void auerisdn_bserv(struct auerisdn *ip)
306 {
307         struct auerisdnbc *bc;
308         unsigned int u;
309         unsigned int paketsize;
310
311         /* should we start the INT OUT endpoint again? */
312         if (ip->intbo_state == INTBOS_RESTART) {
313                 /* dbg ("Restart INT OUT from INT IN"); */
314                 auerisdn_bintbo_restart(ip);
315                 return;
316         }
317         /* no new calculation if change already in progress */
318         if (ip->intbo_state == INTBOS_CHANGE)
319                 return;
320
321         /* calculation of transfer parameters for INT OUT endpoint */
322         paketsize = 0;
323         for (u = 0; u < AUISDN_BCHANNELS; u++) {
324                 bc = &ip->bc[u];
325                 if (bc->mode != L1_MODE_NULL) { /* B channel is active */
326                         unsigned int bpp = AUISDN_BC_1MS * ip->outInterval;
327                         if (bc->txfree < bpp) { /* buffer is full, throttle */
328                                 bc->txsize = bpp - AUISDN_BC_INC;
329                                 paketsize += bpp - AUISDN_BC_INC;
330                         } else if (bc->txfree < bpp * 2) {
331                                 paketsize += bc->txsize;        /* schmidt-trigger, continue */
332                         } else if (bc->txfree < bpp * 4) {      /* we are in synch */
333                                 bc->txsize = bpp;
334                                 paketsize += bpp;
335                         } else if (bc->txfree > bc->ofsize / 2) {/* we have to fill the buffer */
336                                 bc->txsize = bpp + AUISDN_BC_INC;
337                                 paketsize += bpp + AUISDN_BC_INC;
338                         } else {
339                                 paketsize += bc->txsize;        /* schmidt-trigger, continue */
340                         }
341                 }
342         }
343
344         /* check if we have to change the paket size */
345         if (paketsize != ip->paketsize)
346                 auerisdn_bchange(ip, paketsize);
347 }
348
349 /* Send activation/deactivation state to L2 */
350 static void auerisdn_bconf(struct auerisdnbc *bc)
351 {
352         unsigned long flags;
353         struct sk_buff *skb;
354
355         if (bc->mode == L1_MODE_NULL) {
356                 auerisdn_b_l1l2(bc, PH_DEACTIVATE | INDICATION, NULL);
357                 /* recycle old txskb */
358                 spin_lock_irqsave(&bc->txskb_lock, flags);
359                 skb = bc->txskb;
360                 bc->txskb = NULL;
361                 spin_unlock_irqrestore(&bc->txskb_lock, flags);
362                 if (skb) {
363                         skb_pull(skb, skb->len);
364                         auerisdn_b_l1l2(bc, PH_DATA | CONFIRM,
365                                         (void *) skb->truesize);
366                         dev_kfree_skb_any(skb);
367                 }
368         } else {
369                 auerisdn_b_l1l2(bc, PH_ACTIVATE | INDICATION, NULL);
370         }
371 }
372
373 /* B channel setup completion handler */
374 static void auerisdn_bmode_complete(struct urb *urb)
375 {
376         struct auerswald *cp;
377         struct auerbuf *bp = (struct auerbuf *) urb->context;
378         struct auerisdnbc *bc;
379         int channel;
380
381         dbg("auerisdn_bmode_complete called");
382         cp = ((struct auerswald *) ((char *) (bp->list) -
383                                     (unsigned
384                                      long) (&((struct auerswald *) 0)->
385                                             bufctl)));
386
387         /* select the B-channel */
388         channel = le16_to_cpu(bp->dr->wIndex);
389         channel -= AUH_B1CHANNEL;
390         if (channel < 0)
391                 goto rel;
392         if (channel >= AUISDN_BCHANNELS)
393                 goto rel;
394         bc = &cp->isdn.bc[channel];
395
396         /* Check for success */
397         if (urb->status) {
398                 err("complete with non-zero status: %d", urb->status);
399         } else {
400                 bc->mode = *bp->bufp;
401         }
402         /* Signal current mode to L2 */
403         auerisdn_bconf(bc);
404
405         /* reuse the buffer */
406       rel:auerbuf_releasebuf(bp);
407
408         /* Wake up all processes waiting for a buffer */
409         wake_up(&cp->bufferwait);
410 }
411
412 /* Setup a B channel transfer mode */
413 static void auerisdn_bmode(struct auerisdnbc *bc, unsigned int mode)
414 {
415         struct auerswald *cp = bc->cp;
416         struct auerbuf *bp;
417         int ret;
418
419         /* don't allow activation on disconnect */
420         if (cp->disconnecting) {
421                 mode = L1_MODE_NULL;
422
423                 /* Else check if something changed */
424         } else if (bc->mode != mode) {
425                 if ((mode != L1_MODE_NULL) && (mode != L1_MODE_TRANS)) {
426                         /* init RX hdlc decoder */
427                         dbg("rcv init");
428                         isdnhdlc_rcv_init(&bc->inp_hdlc_state, 0);
429                         /* init TX hdlc decoder */
430                         dbg("out init");
431                         isdnhdlc_out_init(&bc->outp_hdlc_state, 0, 0);
432                 }
433                 /* stop ASAP */
434                 if (mode == L1_MODE_NULL)
435                         bc->mode = mode;
436                 if ((bc->mode == L1_MODE_NULL) || (mode == L1_MODE_NULL)) {
437                         /* Activation or deactivation required */
438
439                         /* get a buffer for the command */
440                         bp = auerbuf_getbuf(&cp->bufctl);
441                         /* if no buffer available: can't change the mode */
442                         if (!bp) {
443                                 err("auerisdn_bmode: no data buffer available");
444                                 return;
445                         }
446
447                         /* fill the control message */
448                         bp->dr->bRequestType = AUT_WREQ;
449                         bp->dr->bRequest = AUV_CHANNELCTL;
450                         if (mode != L1_MODE_NULL)
451                                 bp->dr->wValue = cpu_to_le16(1);
452                         else
453                                 bp->dr->wValue = cpu_to_le16(0);
454                         bp->dr->wIndex =
455                             cpu_to_le16(AUH_B1CHANNEL + bc->channel);
456                         bp->dr->wLength = cpu_to_le16(0);
457                         *bp->bufp = mode;
458                         FILL_CONTROL_URB(bp->urbp, cp->usbdev,
459                                          usb_sndctrlpipe(cp->usbdev, 0),
460                                          (unsigned char *) bp->dr,
461                                          bp->bufp, 0,
462                                          (usb_complete_t)
463                                          auerisdn_bmode_complete, bp);
464
465                         /* submit the control msg */
466                         ret =
467                             auerchain_submit_urb(&cp->controlchain,
468                                                  bp->urbp);
469                         if (ret) {
470                                 bp->urbp->status = ret;
471                                 auerisdn_bmode_complete(bp->urbp);
472                         }
473                         return;
474                 }
475         }
476         /* new mode is set */
477         bc->mode = mode;
478
479         /* send confirmation to L2 */
480         auerisdn_bconf(bc);
481 }
482
483 /* B-channel transfer function L2->L1 */
484 void auerisdn_b_l2l1(struct hisax_if *ifc, int pr, void *arg,
485                      unsigned int channel)
486 {
487         struct auerhisax *ahp;
488         struct auerisdnbc *bc;
489         struct auerswald *cp;
490         struct sk_buff *skb;
491         unsigned long flags;
492         int mode;
493
494         cp = NULL;
495         ahp = (struct auerhisax *) ifc->priv;
496         if (ahp)
497                 cp = ahp->cp;
498         if (cp && !cp->disconnecting) {
499                 /* normal execution */
500                 bc = &cp->isdn.bc[channel];
501                 switch (pr) {
502                 case PH_ACTIVATE | REQUEST:     /* activation request */
503                         mode = (int) arg;       /* one of the L1_MODE constants */
504                         dbg("B%d, PH_ACTIVATE_REQUEST Mode = %d",
505                             bc->channel + 1, mode);
506                         auerisdn_bmode(bc, mode);
507                         break;
508                 case PH_DEACTIVATE | REQUEST:   /* deactivation request */
509                         dbg("B%d, PH_DEACTIVATE_REQUEST", bc->channel + 1);
510                         auerisdn_bmode(bc, L1_MODE_NULL);
511                         break;
512                 case PH_DATA | REQUEST: /* Transmit data request */
513                         skb = (struct sk_buff *) arg;
514                         spin_lock_irqsave(&bc->txskb_lock, flags);
515                         if (bc->txskb) {
516                                 err("Overflow in B channel TX");
517                                 skb_pull(skb, skb->len);
518                                 dev_kfree_skb_any(skb);
519                         } else {
520                                 if (cp->disconnecting
521                                     || (bc->mode == L1_MODE_NULL)) {
522                                         skb_pull(skb, skb->len);
523                                         spin_unlock_irqrestore(&bc->
524                                                                txskb_lock,
525                                                                flags);
526                                         auerisdn_b_l1l2(bc,
527                                                         PH_DATA | CONFIRM,
528                                                         (void *) skb->
529                                                         truesize);
530                                         dev_kfree_skb_any(skb);
531                                         goto next;
532                                 } else
533                                         bc->txskb = skb;
534                         }
535                         spin_unlock_irqrestore(&bc->txskb_lock, flags);
536                       next:break;
537                 default:
538                         warn("pr %#x\n", pr);
539                         break;
540                 }
541         } else {
542                 /* hisax interface is down */
543                 switch (pr) {
544                 case PH_ACTIVATE | REQUEST:     /* activation request */
545                         dbg("B channel: PH_ACTIVATE | REQUEST with interface down");
546                         /* don't answer this request! Endless... */
547                         break;
548                 case PH_DEACTIVATE | REQUEST:   /* deactivation request */
549                         dbg("B channel: PH_DEACTIVATE | REQUEST with interface down");
550                         ifc->l1l2(ifc, PH_DEACTIVATE | INDICATION, NULL);
551                         break;
552                 case PH_DATA | REQUEST: /* Transmit data request */
553                         dbg("B channel: PH_DATA | REQUEST with interface down");
554                         skb = (struct sk_buff *) arg;
555                         /* free data buffer */
556                         if (skb) {
557                                 skb_pull(skb, skb->len);
558                                 dev_kfree_skb_any(skb);
559                         }
560                         /* send confirmation back to layer 2 */
561                         ifc->l1l2(ifc, PH_DATA | CONFIRM, NULL);
562                         break;
563                 default:
564                         warn("pr %#x\n", pr);
565                         break;
566                 }
567         }
568 }
569
570 /* Completion handler for B channel input endpoint */
571 void auerisdn_intbi_complete(struct urb *urb)
572 {
573         unsigned int bytecount;
574         unsigned char *ucp;
575         int channel;
576         unsigned int syncbit;
577         unsigned int syncdata;
578         struct auerisdnbc *bc;
579         struct sk_buff *skb;
580         int count;
581         int status;
582         struct auerswald *cp = (struct auerswald *) urb->context;
583         /* do not respond to an error condition */
584         if (urb->status != 0) {
585                 dbg("nonzero URB status = %d", urb->status);
586                 return;
587         }
588         if (cp->disconnecting)
589                 return;
590
591         /* Parse and extract the header information */
592         bytecount = urb->actual_length;
593         ucp = cp->isdn.intbi_bufp;
594         if (!bytecount)
595                 return;         /* no data */
596         channel = *ucp & AUH_TYPEMASK;
597         syncbit = *ucp & AUH_SYNC;
598         ucp++;
599         bytecount--;
600         channel -= AUH_B1CHANNEL;
601         if (channel < 0)
602                 return;         /* unknown data channel, no B1,B2 */
603         if (channel >= AUISDN_BCHANNELS)
604                 return;         /* unknown data channel, no B1,B2 */
605         bc = &cp->isdn.bc[channel];
606         if (!bytecount)
607                 return;
608         /* Calculate amount of bytes which are free in tx device buffer */
609         bc->txfree = ((255 - *ucp++) * bc->ofsize) / 256;
610         /* dbg ("%d Bytes free in TX buffer", bc->txfree); */
611         bytecount--;
612
613         /* Next Byte: TX sync information */
614         if (syncbit) {
615                 if (!bytecount)
616                         goto int_tx;
617                 syncdata = *ucp++;
618                 dbg("Sync data = %d", syncdata);
619                 bytecount--;
620         }
621         /* The rest of the paket is plain data */
622         if (!bytecount)
623                 goto int_tx;
624         /* dump ("RX Data is:", ucp, bytecount); */
625
626         /* Send B channel data to upper layers */
627         while (bytecount > 0) {
628                 if (bc->mode == L1_MODE_NULL) {
629                         /* skip the data. Nobody needs them */
630                         status = 0;
631                         bytecount = 0;
632                 } else if (bc->mode == L1_MODE_TRANS) {
633                         {       /* swap rx bytes */
634                                 register unsigned char *dest = bc->rxbuf;
635                                 status = bytecount;
636                                 for (; bytecount; bytecount--)
637                                         *dest++ =
638                                             isdnhdlc_bit_rev_tab[*ucp++];
639                         }
640
641                 } else {
642                         status = isdnhdlc_decode(&bc->inp_hdlc_state, ucp,
643                                                  bytecount, &count,
644                                                  bc->rxbuf, AUISDN_RXSIZE);
645                         ucp += count;
646                         bytecount -= count;
647                 }
648                 if (status > 0) {
649                         /* Good frame received */
650                         if (!(skb = dev_alloc_skb(status))) {
651                                 warn("receive out of memory");
652                                 break;
653                         }
654                         memcpy(skb_put(skb, status), bc->rxbuf, status);
655                         /* dump ("HDLC Paket", bc->rxbuf, status); */
656                         auerisdn_b_l1l2(bc, PH_DATA | INDICATION, skb);
657                         /* these errors may actually happen at the start of a connection! */
658                 } else if (status == -HDLC_CRC_ERROR) {
659                         dbg("CRC error");
660                 } else if (status == -HDLC_FRAMING_ERROR) {
661                         dbg("framing error");
662                 } else if (status == -HDLC_LENGTH_ERROR) {
663                         dbg("length error");
664                 }
665         }
666
667       int_tx:                   /* serve the outgoing B channel */
668         auerisdn_bserv(&cp->isdn);
669 }
670
671 /* Stop the B channel activity. The device is disconnecting */
672 /* This function is called after cp->disconnecting is true */
673 unsigned int auerisdn_b_disconnect(struct auerswald *cp)
674 {
675         unsigned int u;
676         struct auerisdnbc *bc;
677         unsigned int result = 0;
678
679         /* Close the B channels */
680         for (u = 0; u < AUISDN_BCHANNELS; u++) {
681                 bc = &cp->isdn.bc[u];
682                 if (bc->mode != L1_MODE_NULL) { /* B channel is active */
683                         auerisdn_bmode(bc, L1_MODE_NULL);
684                         result = 1;
685                 }
686         }
687         /* return 1 if there is B channel traffic */
688         return result;
689 }