linux/drivers/isdn/hisax/ipacx.c
<<
>>
Prefs
   1/*
   2 *
   3 * IPACX specific routines
   4 *
   5 * Author       Joerg Petersohn
   6 * Derived from hisax_isac.c, isac.c, hscx.c and others
   7 *
   8 * This software may be used and distributed according to the terms
   9 * of the GNU General Public License, incorporated herein by reference.
  10 *
  11 */
  12#include <linux/kernel.h>
  13#include <linux/slab.h>
  14#include <linux/init.h>
  15#include "hisax_if.h"
  16#include "hisax.h"
  17#include "isdnl1.h"
  18#include "ipacx.h"
  19
  20#define DBUSY_TIMER_VALUE 80
  21#define TIMER3_VALUE      7000
  22#define MAX_DFRAME_LEN_L1 300
  23#define B_FIFO_SIZE       64
  24#define D_FIFO_SIZE       32
  25
  26
  27// ipacx interrupt mask values
  28#define _MASK_IMASK     0x2E  // global mask
  29#define _MASKB_IMASK    0x0B
  30#define _MASKD_IMASK    0x03  // all on
  31
  32//----------------------------------------------------------
  33// local function declarations
  34//----------------------------------------------------------
  35static void ph_command(struct IsdnCardState *cs, unsigned int command);
  36static inline void cic_int(struct IsdnCardState *cs);
  37static void dch_l2l1(struct PStack *st, int pr, void *arg);
  38static void dbusy_timer_handler(struct timer_list *t);
  39static void dch_empty_fifo(struct IsdnCardState *cs, int count);
  40static void dch_fill_fifo(struct IsdnCardState *cs);
  41static inline void dch_int(struct IsdnCardState *cs);
  42static void dch_setstack(struct PStack *st, struct IsdnCardState *cs);
  43static void dch_init(struct IsdnCardState *cs);
  44static void bch_l2l1(struct PStack *st, int pr, void *arg);
  45static void bch_empty_fifo(struct BCState *bcs, int count);
  46static void bch_fill_fifo(struct BCState *bcs);
  47static void bch_int(struct IsdnCardState *cs, u_char hscx);
  48static void bch_mode(struct BCState *bcs, int mode, int bc);
  49static void bch_close_state(struct BCState *bcs);
  50static int bch_open_state(struct IsdnCardState *cs, struct BCState *bcs);
  51static int bch_setstack(struct PStack *st, struct BCState *bcs);
  52static void bch_init(struct IsdnCardState *cs, int hscx);
  53static void clear_pending_ints(struct IsdnCardState *cs);
  54
  55//----------------------------------------------------------
  56// Issue Layer 1 command to chip
  57//----------------------------------------------------------
  58static void
  59ph_command(struct IsdnCardState *cs, unsigned int command)
  60{
  61        if (cs->debug & L1_DEB_ISAC)
  62                debugl1(cs, "ph_command (%#x) in (%#x)", command,
  63                        cs->dc.isac.ph_state);
  64//###################################
  65//      printk(KERN_INFO "ph_command (%#x)\n", command);
  66//###################################
  67        cs->writeisac(cs, IPACX_CIX0, (command << 4) | 0x0E);
  68}
  69
  70//----------------------------------------------------------
  71// Transceiver interrupt handler
  72//----------------------------------------------------------
  73static inline void
  74cic_int(struct IsdnCardState *cs)
  75{
  76        u_char event;
  77
  78        event = cs->readisac(cs, IPACX_CIR0) >> 4;
  79        if (cs->debug & L1_DEB_ISAC) debugl1(cs, "cic_int(event=%#x)", event);
  80//#########################################
  81//      printk(KERN_INFO "cic_int(%x)\n", event);
  82//#########################################
  83        cs->dc.isac.ph_state = event;
  84        schedule_event(cs, D_L1STATECHANGE);
  85}
  86
  87//==========================================================
  88// D channel functions
  89//==========================================================
  90
  91//----------------------------------------------------------
  92// Command entry point
  93//----------------------------------------------------------
  94static void
  95dch_l2l1(struct PStack *st, int pr, void *arg)
  96{
  97        struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
  98        struct sk_buff *skb = arg;
  99        u_char cda1_cr;
 100
 101        switch (pr) {
 102        case (PH_DATA | REQUEST):
 103                if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len);
 104                if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);
 105                if (cs->tx_skb) {
 106                        skb_queue_tail(&cs->sq, skb);
 107#ifdef L2FRAME_DEBUG
 108                        if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA Queued", 0);
 109#endif
 110                } else {
 111                        cs->tx_skb = skb;
 112                        cs->tx_cnt = 0;
 113#ifdef L2FRAME_DEBUG
 114                        if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 0);
 115#endif
 116                        dch_fill_fifo(cs);
 117                }
 118                break;
 119
 120        case (PH_PULL | INDICATION):
 121                if (cs->tx_skb) {
 122                        if (cs->debug & L1_DEB_WARN)
 123                                debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
 124                        skb_queue_tail(&cs->sq, skb);
 125                        break;
 126                }
 127                if (cs->debug & DEB_DLOG_HEX)     LogFrame(cs, skb->data, skb->len);
 128                if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);
 129                cs->tx_skb = skb;
 130                cs->tx_cnt = 0;
 131#ifdef L2FRAME_DEBUG
 132                if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
 133#endif
 134                dch_fill_fifo(cs);
 135                break;
 136
 137        case (PH_PULL | REQUEST):
 138#ifdef L2FRAME_DEBUG
 139                if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL");
 140#endif
 141                if (!cs->tx_skb) {
 142                        clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 143                        st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
 144                } else
 145                        set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 146                break;
 147
 148        case (HW_RESET | REQUEST):
 149        case (HW_ENABLE | REQUEST):
 150                if ((cs->dc.isac.ph_state == IPACX_IND_RES) ||
 151                    (cs->dc.isac.ph_state == IPACX_IND_DR) ||
 152                    (cs->dc.isac.ph_state == IPACX_IND_DC))
 153                        ph_command(cs, IPACX_CMD_TIM);
 154                else
 155                        ph_command(cs, IPACX_CMD_RES);
 156                break;
 157
 158        case (HW_INFO3 | REQUEST):
 159                ph_command(cs, IPACX_CMD_AR8);
 160                break;
 161
 162        case (HW_TESTLOOP | REQUEST):
 163                cs->writeisac(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1
 164                cs->writeisac(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1
 165                cda1_cr = cs->readisac(cs, IPACX_CDA1_CR);
 166                (void) cs->readisac(cs, IPACX_CDA2_CR);
 167                if ((long)arg & 1) { // loop B1
 168                        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr | 0x0a);
 169                }
 170                else {  // B1 off
 171                        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr & ~0x0a);
 172                }
 173                if ((long)arg & 2) { // loop B2
 174                        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr | 0x14);
 175                }
 176                else {  // B2 off
 177                        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr & ~0x14);
 178                }
 179                break;
 180
 181        case (HW_DEACTIVATE | RESPONSE):
 182                skb_queue_purge(&cs->rq);
 183                skb_queue_purge(&cs->sq);
 184                if (cs->tx_skb) {
 185                        dev_kfree_skb_any(cs->tx_skb);
 186                        cs->tx_skb = NULL;
 187                }
 188                if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 189                        del_timer(&cs->dbusytimer);
 190                break;
 191
 192        default:
 193                if (cs->debug & L1_DEB_WARN) debugl1(cs, "dch_l2l1 unknown %04x", pr);
 194                break;
 195        }
 196}
 197
 198//----------------------------------------------------------
 199//----------------------------------------------------------
 200static void
 201dbusy_timer_handler(struct timer_list *t)
 202{
 203        struct IsdnCardState *cs = from_timer(cs, t, dbusytimer);
 204        struct PStack *st;
 205        int     rbchd, stard;
 206
 207        if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
 208                rbchd = cs->readisac(cs, IPACX_RBCHD);
 209                stard = cs->readisac(cs, IPACX_STARD);
 210                if (cs->debug)
 211                        debugl1(cs, "D-Channel Busy RBCHD %02x STARD %02x", rbchd, stard);
 212                if (!(stard & 0x40)) { // D-Channel Busy
 213                        set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
 214                        for (st = cs->stlist; st; st = st->next) {
 215                                st->l1.l1l2(st, PH_PAUSE | INDICATION, NULL); // flow control on
 216                        }
 217                } else {
 218                        // seems we lost an interrupt; reset transceiver */
 219                        clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
 220                        if (cs->tx_skb) {
 221                                dev_kfree_skb_any(cs->tx_skb);
 222                                cs->tx_cnt = 0;
 223                                cs->tx_skb = NULL;
 224                        } else {
 225                                printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");
 226                                debugl1(cs, "D-Channel Busy no skb");
 227                        }
 228                        cs->writeisac(cs, IPACX_CMDRD, 0x01); // Tx reset, generates XPR
 229                }
 230        }
 231}
 232
 233//----------------------------------------------------------
 234// Fill buffer from receive FIFO
 235//----------------------------------------------------------
 236static void
 237dch_empty_fifo(struct IsdnCardState *cs, int count)
 238{
 239        u_char *ptr;
 240
 241        if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
 242                debugl1(cs, "dch_empty_fifo()");
 243
 244        // message too large, remove
 245        if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
 246                if (cs->debug & L1_DEB_WARN)
 247                        debugl1(cs, "dch_empty_fifo() incoming message too large");
 248                cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
 249                cs->rcvidx = 0;
 250                return;
 251        }
 252
 253        ptr = cs->rcvbuf + cs->rcvidx;
 254        cs->rcvidx += count;
 255
 256        cs->readisacfifo(cs, ptr, count);
 257        cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
 258
 259        if (cs->debug & L1_DEB_ISAC_FIFO) {
 260                char *t = cs->dlog;
 261
 262                t += sprintf(t, "dch_empty_fifo() cnt %d", count);
 263                QuickHex(t, ptr, count);
 264                debugl1(cs, "%s", cs->dlog);
 265        }
 266}
 267
 268//----------------------------------------------------------
 269// Fill transmit FIFO
 270//----------------------------------------------------------
 271static void
 272dch_fill_fifo(struct IsdnCardState *cs)
 273{
 274        int count;
 275        u_char cmd, *ptr;
 276
 277        if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
 278                debugl1(cs, "dch_fill_fifo()");
 279
 280        if (!cs->tx_skb) return;
 281        count = cs->tx_skb->len;
 282        if (count <= 0) return;
 283
 284        if (count > D_FIFO_SIZE) {
 285                count = D_FIFO_SIZE;
 286                cmd   = 0x08; // XTF
 287        } else {
 288                cmd   = 0x0A; // XTF | XME
 289        }
 290
 291        ptr = cs->tx_skb->data;
 292        skb_pull(cs->tx_skb, count);
 293        cs->tx_cnt += count;
 294        cs->writeisacfifo(cs, ptr, count);
 295        cs->writeisac(cs, IPACX_CMDRD, cmd);
 296
 297        // set timeout for transmission contol
 298        if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
 299                debugl1(cs, "dch_fill_fifo dbusytimer running");
 300                del_timer(&cs->dbusytimer);
 301        }
 302        cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
 303        add_timer(&cs->dbusytimer);
 304
 305        if (cs->debug & L1_DEB_ISAC_FIFO) {
 306                char *t = cs->dlog;
 307
 308                t += sprintf(t, "dch_fill_fifo() cnt %d", count);
 309                QuickHex(t, ptr, count);
 310                debugl1(cs, "%s", cs->dlog);
 311        }
 312}
 313
 314//----------------------------------------------------------
 315// D channel interrupt handler
 316//----------------------------------------------------------
 317static inline void
 318dch_int(struct IsdnCardState *cs)
 319{
 320        struct sk_buff *skb;
 321        u_char istad, rstad;
 322        int count;
 323
 324        istad = cs->readisac(cs, IPACX_ISTAD);
 325//##############################################
 326//      printk(KERN_WARNING "dch_int(istad=%02x)\n", istad);
 327//##############################################
 328
 329        if (istad & 0x80) {  // RME
 330                rstad = cs->readisac(cs, IPACX_RSTAD);
 331                if ((rstad & 0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)
 332                        if (!(rstad & 0x80))
 333                                if (cs->debug & L1_DEB_WARN)
 334                                        debugl1(cs, "dch_int(): invalid frame");
 335                        if ((rstad & 0x40))
 336                                if (cs->debug & L1_DEB_WARN)
 337                                        debugl1(cs, "dch_int(): RDO");
 338                        if (!(rstad & 0x20))
 339                                if (cs->debug & L1_DEB_WARN)
 340                                        debugl1(cs, "dch_int(): CRC error");
 341                        cs->writeisac(cs, IPACX_CMDRD, 0x80);  // RMC
 342                } else {  // received frame ok
 343                        count = cs->readisac(cs, IPACX_RBCLD);
 344                        if (count) count--; // RSTAB is last byte
 345                        count &= D_FIFO_SIZE - 1;
 346                        if (count == 0) count = D_FIFO_SIZE;
 347                        dch_empty_fifo(cs, count);
 348                        if ((count = cs->rcvidx) > 0) {
 349                                cs->rcvidx = 0;
 350                                if (!(skb = dev_alloc_skb(count)))
 351                                        printk(KERN_WARNING "HiSax dch_int(): receive out of memory\n");
 352                                else {
 353                                        skb_put_data(skb, cs->rcvbuf, count);
 354                                        skb_queue_tail(&cs->rq, skb);
 355                                }
 356                        }
 357                }
 358                cs->rcvidx = 0;
 359                schedule_event(cs, D_RCVBUFREADY);
 360        }
 361
 362        if (istad & 0x40) {  // RPF
 363                dch_empty_fifo(cs, D_FIFO_SIZE);
 364        }
 365
 366        if (istad & 0x20) {  // RFO
 367                if (cs->debug & L1_DEB_WARN) debugl1(cs, "dch_int(): RFO");
 368                cs->writeisac(cs, IPACX_CMDRD, 0x40); //RRES
 369        }
 370
 371        if (istad & 0x10) {  // XPR
 372                if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 373                        del_timer(&cs->dbusytimer);
 374                if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
 375                        schedule_event(cs, D_CLEARBUSY);
 376                if (cs->tx_skb) {
 377                        if (cs->tx_skb->len) {
 378                                dch_fill_fifo(cs);
 379                                goto afterXPR;
 380                        }
 381                        else {
 382                                dev_kfree_skb_irq(cs->tx_skb);
 383                                cs->tx_skb = NULL;
 384                                cs->tx_cnt = 0;
 385                        }
 386                }
 387                if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
 388                        cs->tx_cnt = 0;
 389                        dch_fill_fifo(cs);
 390                }
 391                else {
 392                        schedule_event(cs, D_XMTBUFREADY);
 393                }
 394        }
 395afterXPR:
 396
 397        if (istad & 0x0C) {  // XDU or XMR
 398                if (cs->debug & L1_DEB_WARN) debugl1(cs, "dch_int(): XDU");
 399                if (cs->tx_skb) {
 400                        skb_push(cs->tx_skb, cs->tx_cnt); // retransmit
 401                        cs->tx_cnt = 0;
 402                        dch_fill_fifo(cs);
 403                } else {
 404                        printk(KERN_WARNING "HiSax: ISAC XDU no skb\n");
 405                        debugl1(cs, "ISAC XDU no skb");
 406                }
 407        }
 408}
 409
 410//----------------------------------------------------------
 411//----------------------------------------------------------
 412static void
 413dch_setstack(struct PStack *st, struct IsdnCardState *cs)
 414{
 415        st->l1.l1hw = dch_l2l1;
 416}
 417
 418//----------------------------------------------------------
 419//----------------------------------------------------------
 420static void
 421dch_init(struct IsdnCardState *cs)
 422{
 423        printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n");
 424
 425        cs->setstack_d      = dch_setstack;
 426
 427        timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0);
 428
 429        cs->writeisac(cs, IPACX_TR_CONF0, 0x00);  // clear LDD
 430        cs->writeisac(cs, IPACX_TR_CONF2, 0x00);  // enable transmitter
 431        cs->writeisac(cs, IPACX_MODED,    0xC9);  // transparent mode 0, RAC, stop/go
 432        cs->writeisac(cs, IPACX_MON_CR,   0x00);  // disable monitor channel
 433}
 434
 435
 436//==========================================================
 437// B channel functions
 438//==========================================================
 439
 440//----------------------------------------------------------
 441// Entry point for commands
 442//----------------------------------------------------------
 443static void
 444bch_l2l1(struct PStack *st, int pr, void *arg)
 445{
 446        struct BCState *bcs = st->l1.bcs;
 447        struct sk_buff *skb = arg;
 448        u_long flags;
 449
 450        switch (pr) {
 451        case (PH_DATA | REQUEST):
 452                spin_lock_irqsave(&bcs->cs->lock, flags);
 453                if (bcs->tx_skb) {
 454                        skb_queue_tail(&bcs->squeue, skb);
 455                } else {
 456                        bcs->tx_skb = skb;
 457                        set_bit(BC_FLG_BUSY, &bcs->Flag);
 458                        bcs->hw.hscx.count = 0;
 459                        bch_fill_fifo(bcs);
 460                }
 461                spin_unlock_irqrestore(&bcs->cs->lock, flags);
 462                break;
 463        case (PH_PULL | INDICATION):
 464                spin_lock_irqsave(&bcs->cs->lock, flags);
 465                if (bcs->tx_skb) {
 466                        printk(KERN_WARNING "HiSax bch_l2l1(): this shouldn't happen\n");
 467                } else {
 468                        set_bit(BC_FLG_BUSY, &bcs->Flag);
 469                        bcs->tx_skb = skb;
 470                        bcs->hw.hscx.count = 0;
 471                        bch_fill_fifo(bcs);
 472                }
 473                spin_unlock_irqrestore(&bcs->cs->lock, flags);
 474                break;
 475        case (PH_PULL | REQUEST):
 476                if (!bcs->tx_skb) {
 477                        clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 478                        st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
 479                } else
 480                        set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 481                break;
 482        case (PH_ACTIVATE | REQUEST):
 483                spin_lock_irqsave(&bcs->cs->lock, flags);
 484                set_bit(BC_FLG_ACTIV, &bcs->Flag);
 485                bch_mode(bcs, st->l1.mode, st->l1.bc);
 486                spin_unlock_irqrestore(&bcs->cs->lock, flags);
 487                l1_msg_b(st, pr, arg);
 488                break;
 489        case (PH_DEACTIVATE | REQUEST):
 490                l1_msg_b(st, pr, arg);
 491                break;
 492        case (PH_DEACTIVATE | CONFIRM):
 493                spin_lock_irqsave(&bcs->cs->lock, flags);
 494                clear_bit(BC_FLG_ACTIV, &bcs->Flag);
 495                clear_bit(BC_FLG_BUSY, &bcs->Flag);
 496                bch_mode(bcs, 0, st->l1.bc);
 497                spin_unlock_irqrestore(&bcs->cs->lock, flags);
 498                st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
 499                break;
 500        }
 501}
 502
 503//----------------------------------------------------------
 504// Read B channel fifo to receive buffer
 505//----------------------------------------------------------
 506static void
 507bch_empty_fifo(struct BCState *bcs, int count)
 508{
 509        u_char *ptr, hscx;
 510        struct IsdnCardState *cs;
 511        int cnt;
 512
 513        cs = bcs->cs;
 514        hscx = bcs->hw.hscx.hscx;
 515        if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
 516                debugl1(cs, "bch_empty_fifo()");
 517
 518        // message too large, remove
 519        if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
 520                if (cs->debug & L1_DEB_WARN)
 521                        debugl1(cs, "bch_empty_fifo() incoming packet too large");
 522                cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80);  // RMC
 523                bcs->hw.hscx.rcvidx = 0;
 524                return;
 525        }
 526
 527        ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
 528        cnt = count;
 529        while (cnt--) *ptr++ = cs->BC_Read_Reg(cs, hscx, IPACX_RFIFOB);
 530        cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80);  // RMC
 531
 532        ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
 533        bcs->hw.hscx.rcvidx += count;
 534
 535        if (cs->debug & L1_DEB_HSCX_FIFO) {
 536                char *t = bcs->blog;
 537
 538                t += sprintf(t, "bch_empty_fifo() B-%d cnt %d", hscx, count);
 539                QuickHex(t, ptr, count);
 540                debugl1(cs, "%s", bcs->blog);
 541        }
 542}
 543
 544//----------------------------------------------------------
 545// Fill buffer to transmit FIFO
 546//----------------------------------------------------------
 547static void
 548bch_fill_fifo(struct BCState *bcs)
 549{
 550        struct IsdnCardState *cs;
 551        int more, count, cnt;
 552        u_char *ptr, *p, hscx;
 553
 554        cs = bcs->cs;
 555        if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
 556                debugl1(cs, "bch_fill_fifo()");
 557
 558        if (!bcs->tx_skb)           return;
 559        if (bcs->tx_skb->len <= 0)  return;
 560
 561        hscx = bcs->hw.hscx.hscx;
 562        more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
 563        if (bcs->tx_skb->len > B_FIFO_SIZE) {
 564                more  = 1;
 565                count = B_FIFO_SIZE;
 566        } else {
 567                count = bcs->tx_skb->len;
 568        }
 569        cnt = count;
 570
 571        p = ptr = bcs->tx_skb->data;
 572        skb_pull(bcs->tx_skb, count);
 573        bcs->tx_cnt -= count;
 574        bcs->hw.hscx.count += count;
 575        while (cnt--) cs->BC_Write_Reg(cs, hscx, IPACX_XFIFOB, *p++);
 576        cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, (more ? 0x08 : 0x0a));
 577
 578        if (cs->debug & L1_DEB_HSCX_FIFO) {
 579                char *t = bcs->blog;
 580
 581                t += sprintf(t, "%s() B-%d cnt %d", __func__, hscx, count);
 582                QuickHex(t, ptr, count);
 583                debugl1(cs, "%s", bcs->blog);
 584        }
 585}
 586
 587//----------------------------------------------------------
 588// B channel interrupt handler
 589//----------------------------------------------------------
 590static void
 591bch_int(struct IsdnCardState *cs, u_char hscx)
 592{
 593        u_char istab;
 594        struct BCState *bcs;
 595        struct sk_buff *skb;
 596        int count;
 597        u_char rstab;
 598
 599        bcs = cs->bcs + hscx;
 600        istab = cs->BC_Read_Reg(cs, hscx, IPACX_ISTAB);
 601//##############################################
 602//      printk(KERN_WARNING "bch_int(istab=%02x)\n", istab);
 603//##############################################
 604        if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return;
 605
 606        if (istab & 0x80) {     // RME
 607                rstab = cs->BC_Read_Reg(cs, hscx, IPACX_RSTAB);
 608                if ((rstab & 0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)
 609                        if (!(rstab & 0x80))
 610                                if (cs->debug & L1_DEB_WARN)
 611                                        debugl1(cs, "bch_int() B-%d: invalid frame", hscx);
 612                        if ((rstab & 0x40) && (bcs->mode != L1_MODE_NULL))
 613                                if (cs->debug & L1_DEB_WARN)
 614                                        debugl1(cs, "bch_int() B-%d: RDO mode=%d", hscx, bcs->mode);
 615                        if (!(rstab & 0x20))
 616                                if (cs->debug & L1_DEB_WARN)
 617                                        debugl1(cs, "bch_int() B-%d: CRC error", hscx);
 618                        cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80);  // RMC
 619                }
 620                else {  // received frame ok
 621                        count = cs->BC_Read_Reg(cs, hscx, IPACX_RBCLB) & (B_FIFO_SIZE - 1);
 622                        if (count == 0) count = B_FIFO_SIZE;
 623                        bch_empty_fifo(bcs, count);
 624                        if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
 625                                if (cs->debug & L1_DEB_HSCX_FIFO)
 626                                        debugl1(cs, "bch_int Frame %d", count);
 627                                if (!(skb = dev_alloc_skb(count)))
 628                                        printk(KERN_WARNING "HiSax bch_int(): receive frame out of memory\n");
 629                                else {
 630                                        skb_put_data(skb, bcs->hw.hscx.rcvbuf,
 631                                                     count);
 632                                        skb_queue_tail(&bcs->rqueue, skb);
 633                                }
 634                        }
 635                }
 636                bcs->hw.hscx.rcvidx = 0;
 637                schedule_event(bcs, B_RCVBUFREADY);
 638        }
 639
 640        if (istab & 0x40) {     // RPF
 641                bch_empty_fifo(bcs, B_FIFO_SIZE);
 642
 643                if (bcs->mode == L1_MODE_TRANS) { // queue every chunk
 644                        // receive transparent audio data
 645                        if (!(skb = dev_alloc_skb(B_FIFO_SIZE)))
 646                                printk(KERN_WARNING "HiSax bch_int(): receive transparent out of memory\n");
 647                        else {
 648                                skb_put_data(skb, bcs->hw.hscx.rcvbuf,
 649                                             B_FIFO_SIZE);
 650                                skb_queue_tail(&bcs->rqueue, skb);
 651                        }
 652                        bcs->hw.hscx.rcvidx = 0;
 653                        schedule_event(bcs, B_RCVBUFREADY);
 654                }
 655        }
 656
 657        if (istab & 0x20) {     // RFO
 658                if (cs->debug & L1_DEB_WARN)
 659                        debugl1(cs, "bch_int() B-%d: RFO error", hscx);
 660                cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x40);  // RRES
 661        }
 662
 663        if (istab & 0x10) {     // XPR
 664                if (bcs->tx_skb) {
 665                        if (bcs->tx_skb->len) {
 666                                bch_fill_fifo(bcs);
 667                                goto afterXPR;
 668                        } else {
 669                                if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) &&
 670                                    (PACKET_NOACK != bcs->tx_skb->pkt_type)) {
 671                                        u_long  flags;
 672                                        spin_lock_irqsave(&bcs->aclock, flags);
 673                                        bcs->ackcnt += bcs->hw.hscx.count;
 674                                        spin_unlock_irqrestore(&bcs->aclock, flags);
 675                                        schedule_event(bcs, B_ACKPENDING);
 676                                }
 677                        }
 678                        dev_kfree_skb_irq(bcs->tx_skb);
 679                        bcs->hw.hscx.count = 0;
 680                        bcs->tx_skb = NULL;
 681                }
 682                if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
 683                        bcs->hw.hscx.count = 0;
 684                        set_bit(BC_FLG_BUSY, &bcs->Flag);
 685                        bch_fill_fifo(bcs);
 686                } else {
 687                        clear_bit(BC_FLG_BUSY, &bcs->Flag);
 688                        schedule_event(bcs, B_XMTBUFREADY);
 689                }
 690        }
 691afterXPR:
 692
 693        if (istab & 0x04) {     // XDU
 694                if (bcs->mode == L1_MODE_TRANS) {
 695                        bch_fill_fifo(bcs);
 696                }
 697                else {
 698                        if (bcs->tx_skb) {  // restart transmitting the whole frame
 699                                skb_push(bcs->tx_skb, bcs->hw.hscx.count);
 700                                bcs->tx_cnt += bcs->hw.hscx.count;
 701                                bcs->hw.hscx.count = 0;
 702                        }
 703                        cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x01);  // XRES
 704                        if (cs->debug & L1_DEB_WARN)
 705                                debugl1(cs, "bch_int() B-%d XDU error", hscx);
 706                }
 707        }
 708}
 709
 710//----------------------------------------------------------
 711//----------------------------------------------------------
 712static void
 713bch_mode(struct BCState *bcs, int mode, int bc)
 714{
 715        struct IsdnCardState *cs = bcs->cs;
 716        int hscx = bcs->hw.hscx.hscx;
 717
 718        bc = bc ? 1 : 0;  // in case bc is greater than 1
 719        if (cs->debug & L1_DEB_HSCX)
 720                debugl1(cs, "mode_bch() switch B-%d mode %d chan %d", hscx, mode, bc);
 721        bcs->mode = mode;
 722        bcs->channel = bc;
 723
 724        // map controller to according timeslot
 725        if (!hscx)
 726        {
 727                cs->writeisac(cs, IPACX_BCHA_TSDP_BC1, 0x80 | bc);
 728                cs->writeisac(cs, IPACX_BCHA_CR,       0x88);
 729        }
 730        else
 731        {
 732                cs->writeisac(cs, IPACX_BCHB_TSDP_BC1, 0x80 | bc);
 733                cs->writeisac(cs, IPACX_BCHB_CR,       0x88);
 734        }
 735
 736        switch (mode) {
 737        case (L1_MODE_NULL):
 738                cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC0);  // rec off
 739                cs->BC_Write_Reg(cs, hscx, IPACX_EXMB,  0x30);  // std adj.
 740                cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, 0xFF);  // ints off
 741                cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41);  // validate adjustments
 742                break;
 743        case (L1_MODE_TRANS):
 744                cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0x88);  // ext transp mode
 745                cs->BC_Write_Reg(cs, hscx, IPACX_EXMB,  0x00);  // xxx00000
 746                cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41);  // validate adjustments
 747                cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK);
 748                break;
 749        case (L1_MODE_HDLC):
 750                cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC8);  // transp mode 0
 751                cs->BC_Write_Reg(cs, hscx, IPACX_EXMB,  0x01);  // idle=hdlc flags crc enabled
 752                cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41);  // validate adjustments
 753                cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK);
 754                break;
 755        }
 756}
 757
 758//----------------------------------------------------------
 759//----------------------------------------------------------
 760static void
 761bch_close_state(struct BCState *bcs)
 762{
 763        bch_mode(bcs, 0, bcs->channel);
 764        if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
 765                kfree(bcs->hw.hscx.rcvbuf);
 766                bcs->hw.hscx.rcvbuf = NULL;
 767                kfree(bcs->blog);
 768                bcs->blog = NULL;
 769                skb_queue_purge(&bcs->rqueue);
 770                skb_queue_purge(&bcs->squeue);
 771                if (bcs->tx_skb) {
 772                        dev_kfree_skb_any(bcs->tx_skb);
 773                        bcs->tx_skb = NULL;
 774                        clear_bit(BC_FLG_BUSY, &bcs->Flag);
 775                }
 776        }
 777}
 778
 779//----------------------------------------------------------
 780//----------------------------------------------------------
 781static int
 782bch_open_state(struct IsdnCardState *cs, struct BCState *bcs)
 783{
 784        if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
 785                if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
 786                        printk(KERN_WARNING
 787                               "HiSax open_bchstate(): No memory for hscx.rcvbuf\n");
 788                        clear_bit(BC_FLG_INIT, &bcs->Flag);
 789                        return (1);
 790                }
 791                if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
 792                        printk(KERN_WARNING
 793                               "HiSax open_bchstate: No memory for bcs->blog\n");
 794                        clear_bit(BC_FLG_INIT, &bcs->Flag);
 795                        kfree(bcs->hw.hscx.rcvbuf);
 796                        bcs->hw.hscx.rcvbuf = NULL;
 797                        return (2);
 798                }
 799                skb_queue_head_init(&bcs->rqueue);
 800                skb_queue_head_init(&bcs->squeue);
 801        }
 802        bcs->tx_skb = NULL;
 803        clear_bit(BC_FLG_BUSY, &bcs->Flag);
 804        bcs->event = 0;
 805        bcs->hw.hscx.rcvidx = 0;
 806        bcs->tx_cnt = 0;
 807        return (0);
 808}
 809
 810//----------------------------------------------------------
 811//----------------------------------------------------------
 812static int
 813bch_setstack(struct PStack *st, struct BCState *bcs)
 814{
 815        bcs->channel = st->l1.bc;
 816        if (bch_open_state(st->l1.hardware, bcs)) return (-1);
 817        st->l1.bcs = bcs;
 818        st->l2.l2l1 = bch_l2l1;
 819        setstack_manager(st);
 820        bcs->st = st;
 821        setstack_l1_B(st);
 822        return (0);
 823}
 824
 825//----------------------------------------------------------
 826//----------------------------------------------------------
 827static void
 828bch_init(struct IsdnCardState *cs, int hscx)
 829{
 830        cs->bcs[hscx].BC_SetStack   = bch_setstack;
 831        cs->bcs[hscx].BC_Close      = bch_close_state;
 832        cs->bcs[hscx].hw.hscx.hscx  = hscx;
 833        cs->bcs[hscx].cs            = cs;
 834        bch_mode(cs->bcs + hscx, 0, hscx);
 835}
 836
 837
 838//==========================================================
 839// Shared functions
 840//==========================================================
 841
 842//----------------------------------------------------------
 843// Main interrupt handler
 844//----------------------------------------------------------
 845void
 846interrupt_ipacx(struct IsdnCardState *cs)
 847{
 848        u_char ista;
 849
 850        while ((ista = cs->readisac(cs, IPACX_ISTA))) {
 851//#################################################
 852//              printk(KERN_WARNING "interrupt_ipacx(ista=%02x)\n", ista);
 853//#################################################
 854                if (ista & 0x80) bch_int(cs, 0); // B channel interrupts
 855                if (ista & 0x40) bch_int(cs, 1);
 856
 857                if (ista & 0x01) dch_int(cs);    // D channel
 858                if (ista & 0x10) cic_int(cs);    // Layer 1 state
 859        }
 860}
 861
 862//----------------------------------------------------------
 863// Clears chip interrupt status
 864//----------------------------------------------------------
 865static void
 866clear_pending_ints(struct IsdnCardState *cs)
 867{
 868        int ista;
 869
 870        // all interrupts off
 871        cs->writeisac(cs, IPACX_MASK, 0xff);
 872        cs->writeisac(cs, IPACX_MASKD, 0xff);
 873        cs->BC_Write_Reg(cs, 0, IPACX_MASKB, 0xff);
 874        cs->BC_Write_Reg(cs, 1, IPACX_MASKB, 0xff);
 875
 876        ista = cs->readisac(cs, IPACX_ISTA);
 877        if (ista & 0x80) cs->BC_Read_Reg(cs, 0, IPACX_ISTAB);
 878        if (ista & 0x40) cs->BC_Read_Reg(cs, 1, IPACX_ISTAB);
 879        if (ista & 0x10) cs->readisac(cs, IPACX_CIR0);
 880        if (ista & 0x01) cs->readisac(cs, IPACX_ISTAD);
 881}
 882
 883//----------------------------------------------------------
 884// Does chip configuration work
 885// Work to do depends on bit mask in part
 886//----------------------------------------------------------
 887void
 888init_ipacx(struct IsdnCardState *cs, int part)
 889{
 890        if (part & 1) {  // initialise chip
 891//##################################################
 892//      printk(KERN_INFO "init_ipacx(%x)\n", part);
 893//##################################################
 894                clear_pending_ints(cs);
 895                bch_init(cs, 0);
 896                bch_init(cs, 1);
 897                dch_init(cs);
 898        }
 899        if (part & 2) {  // reenable all interrupts and start chip
 900                cs->BC_Write_Reg(cs, 0, IPACX_MASKB, _MASKB_IMASK);
 901                cs->BC_Write_Reg(cs, 1, IPACX_MASKB, _MASKB_IMASK);
 902                cs->writeisac(cs, IPACX_MASKD, _MASKD_IMASK);
 903                cs->writeisac(cs, IPACX_MASK, _MASK_IMASK); // global mask register
 904
 905                // reset HDLC Transmitters/receivers
 906                cs->writeisac(cs, IPACX_CMDRD, 0x41);
 907                cs->BC_Write_Reg(cs, 0, IPACX_CMDRB, 0x41);
 908                cs->BC_Write_Reg(cs, 1, IPACX_CMDRB, 0x41);
 909                ph_command(cs, IPACX_CMD_RES);
 910        }
 911}
 912
 913//----------------- end of file -----------------------
 914