linux-old/drivers/usb/auerisdn_b.c
<<
>>
Prefs
   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) \
  43do {                    \
  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*/
  63void 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 */
  89static 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 */
 205static 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 */
 243static 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 */
 255static 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 */
 279static 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 */
 305static 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 */
 350static 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 */
 374static 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 */
 413static 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 */
 484void 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 */
 571void 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 */
 673unsigned 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}
 690
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.