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 IsdnCardState *cs);
  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, cda2_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      cda2_cr = 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 IsdnCardState *cs)
 202{
 203        struct PStack *st;
 204        int     rbchd, stard;
 205
 206        if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
 207                rbchd = cs->readisac(cs, IPACX_RBCHD);
 208                stard = cs->readisac(cs, IPACX_STARD);
 209                if (cs->debug) 
 210      debugl1(cs, "D-Channel Busy RBCHD %02x STARD %02x", rbchd, stard);
 211                if (!(stard &0x40)) { // D-Channel Busy
 212                        set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
 213      for (st = cs->stlist; st; st = st->next) {
 214                                st->l1.l1l2(st, PH_PAUSE | INDICATION, NULL); // flow control on
 215                        }
 216                } else {
 217                        // seems we lost an interrupt; reset transceiver */
 218                        clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
 219                        if (cs->tx_skb) {
 220                                dev_kfree_skb_any(cs->tx_skb);
 221                                cs->tx_cnt = 0;
 222                                cs->tx_skb = NULL;
 223                        } else {
 224                                printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");
 225                                debugl1(cs, "D-Channel Busy no skb");
 226                        }
 227                        cs->writeisac(cs, IPACX_CMDRD, 0x01); // Tx reset, generates XPR
 228                }
 229        }
 230}
 231
 232//----------------------------------------------------------
 233// Fill buffer from receive FIFO
 234//----------------------------------------------------------
 235static void 
 236dch_empty_fifo(struct IsdnCardState *cs, int count)
 237{
 238        u_char *ptr;
 239
 240        if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO))
 241                debugl1(cs, "dch_empty_fifo()");
 242
 243  // message too large, remove
 244        if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
 245                if (cs->debug &L1_DEB_WARN)
 246                        debugl1(cs, "dch_empty_fifo() incoming message too large");
 247          cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
 248                cs->rcvidx = 0;
 249                return;
 250        }
 251  
 252        ptr = cs->rcvbuf + cs->rcvidx;
 253        cs->rcvidx += count;
 254  
 255        cs->readisacfifo(cs, ptr, count);
 256        cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
 257  
 258        if (cs->debug &L1_DEB_ISAC_FIFO) {
 259                char *t = cs->dlog;
 260
 261                t += sprintf(t, "dch_empty_fifo() cnt %d", count);
 262                QuickHex(t, ptr, count);
 263                debugl1(cs, cs->dlog);
 264        }
 265}
 266
 267//----------------------------------------------------------
 268// Fill transmit FIFO
 269//----------------------------------------------------------
 270static void 
 271dch_fill_fifo(struct IsdnCardState *cs)
 272{
 273        int count;
 274        u_char cmd, *ptr;
 275
 276        if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO))
 277                debugl1(cs, "dch_fill_fifo()");
 278    
 279        if (!cs->tx_skb) return;
 280        count = cs->tx_skb->len;
 281        if (count <= 0) return;
 282
 283        if (count > D_FIFO_SIZE) {
 284                count = D_FIFO_SIZE;
 285                cmd   = 0x08; // XTF
 286        } else {
 287                cmd   = 0x0A; // XTF | XME
 288        }
 289  
 290        ptr = cs->tx_skb->data;
 291        skb_pull(cs->tx_skb, count);
 292        cs->tx_cnt += count;
 293        cs->writeisacfifo(cs, ptr, count);
 294        cs->writeisac(cs, IPACX_CMDRD, cmd);
 295  
 296  // set timeout for transmission contol
 297        if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
 298                debugl1(cs, "dch_fill_fifo dbusytimer running");
 299                del_timer(&cs->dbusytimer);
 300        }
 301        init_timer(&cs->dbusytimer);
 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, 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                                        memcpy(skb_put(skb, count), 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  }  
 395  afterXPR:
 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        cs->dbusytimer.function = (void *) dbusy_timer_handler;
 428        cs->dbusytimer.data = (long) cs;
 429        init_timer(&cs->dbusytimer);
 430
 431  cs->writeisac(cs, IPACX_TR_CONF0, 0x00);  // clear LDD
 432  cs->writeisac(cs, IPACX_TR_CONF2, 0x00);  // enable transmitter
 433  cs->writeisac(cs, IPACX_MODED,    0xC9);  // transparent mode 0, RAC, stop/go
 434  cs->writeisac(cs, IPACX_MON_CR,   0x00);  // disable monitor channel
 435}
 436
 437
 438//==========================================================
 439// B channel functions
 440//==========================================================
 441
 442//----------------------------------------------------------
 443// Entry point for commands
 444//----------------------------------------------------------
 445static void
 446bch_l2l1(struct PStack *st, int pr, void *arg)
 447{
 448        struct BCState *bcs = st->l1.bcs;
 449        struct sk_buff *skb = arg;
 450        u_long flags;
 451
 452        switch (pr) {
 453                case (PH_DATA | REQUEST):
 454                        spin_lock_irqsave(&bcs->cs->lock, flags);
 455                        if (bcs->tx_skb) {
 456                                skb_queue_tail(&bcs->squeue, skb);
 457                        } else {
 458                                bcs->tx_skb = skb;
 459                                set_bit(BC_FLG_BUSY, &bcs->Flag);
 460                                bcs->hw.hscx.count = 0;
 461                                bch_fill_fifo(bcs);
 462                        }
 463                        spin_unlock_irqrestore(&bcs->cs->lock, flags);
 464                        break;
 465                case (PH_PULL | INDICATION):
 466                        spin_lock_irqsave(&bcs->cs->lock, flags);
 467                        if (bcs->tx_skb) {
 468                                printk(KERN_WARNING "HiSax bch_l2l1(): this shouldn't happen\n");
 469                        } else {
 470                                set_bit(BC_FLG_BUSY, &bcs->Flag);
 471                                bcs->tx_skb = skb;
 472                                bcs->hw.hscx.count = 0;
 473                                bch_fill_fifo(bcs);
 474                        }
 475                        spin_unlock_irqrestore(&bcs->cs->lock, flags);
 476                        break;
 477                case (PH_PULL | REQUEST):
 478                        if (!bcs->tx_skb) {
 479                                clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 480                                st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
 481                        } else
 482                                set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 483                        break;
 484                case (PH_ACTIVATE | REQUEST):
 485                        spin_lock_irqsave(&bcs->cs->lock, flags);
 486                        set_bit(BC_FLG_ACTIV, &bcs->Flag);
 487                        bch_mode(bcs, st->l1.mode, st->l1.bc);
 488                        spin_unlock_irqrestore(&bcs->cs->lock, flags);
 489                        l1_msg_b(st, pr, arg);
 490                        break;
 491                case (PH_DEACTIVATE | REQUEST):
 492                        l1_msg_b(st, pr, arg);
 493                        break;
 494                case (PH_DEACTIVATE | CONFIRM):
 495                        spin_lock_irqsave(&bcs->cs->lock, flags);
 496                        clear_bit(BC_FLG_ACTIV, &bcs->Flag);
 497                        clear_bit(BC_FLG_BUSY, &bcs->Flag);
 498                        bch_mode(bcs, 0, st->l1.bc);
 499                        spin_unlock_irqrestore(&bcs->cs->lock, flags);
 500                        st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
 501                        break;
 502        }
 503}
 504
 505//----------------------------------------------------------
 506// Read B channel fifo to receive buffer
 507//----------------------------------------------------------
 508static void
 509bch_empty_fifo(struct BCState *bcs, int count)
 510{
 511        u_char *ptr, hscx;
 512        struct IsdnCardState *cs;
 513        int cnt;
 514
 515        cs = bcs->cs;
 516  hscx = bcs->hw.hscx.hscx;
 517        if ((cs->debug &L1_DEB_HSCX) && !(cs->debug &L1_DEB_HSCX_FIFO))
 518                debugl1(cs, "bch_empty_fifo()");
 519
 520  // message too large, remove
 521        if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
 522                if (cs->debug &L1_DEB_WARN)
 523                        debugl1(cs, "bch_empty_fifo() incoming packet too large");
 524          cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80);  // RMC
 525                bcs->hw.hscx.rcvidx = 0;
 526                return;
 527        }
 528  
 529        ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
 530        cnt = count;
 531        while (cnt--) *ptr++ = cs->BC_Read_Reg(cs, hscx, IPACX_RFIFOB); 
 532        cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80);  // RMC
 533  
 534        ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
 535        bcs->hw.hscx.rcvidx += count;
 536  
 537        if (cs->debug &L1_DEB_HSCX_FIFO) {
 538                char *t = bcs->blog;
 539
 540                t += sprintf(t, "bch_empty_fifo() B-%d cnt %d", hscx, count);
 541                QuickHex(t, ptr, count);
 542                debugl1(cs, bcs->blog);
 543        }
 544}
 545
 546//----------------------------------------------------------
 547// Fill buffer to transmit FIFO
 548//----------------------------------------------------------
 549static void
 550bch_fill_fifo(struct BCState *bcs)
 551{
 552        struct IsdnCardState *cs;
 553        int more, count, cnt;
 554        u_char *ptr, *p, hscx;
 555
 556        cs = bcs->cs;
 557        if ((cs->debug &L1_DEB_HSCX) && !(cs->debug &L1_DEB_HSCX_FIFO))
 558                debugl1(cs, "bch_fill_fifo()");
 559
 560        if (!bcs->tx_skb)           return;
 561        if (bcs->tx_skb->len <= 0)  return;
 562
 563        hscx = bcs->hw.hscx.hscx;
 564        more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
 565        if (bcs->tx_skb->len > B_FIFO_SIZE) {
 566                more  = 1;
 567                count = B_FIFO_SIZE;
 568        } else {
 569                count = bcs->tx_skb->len;
 570        }  
 571        cnt = count;
 572    
 573        p = ptr = bcs->tx_skb->data;
 574        skb_pull(bcs->tx_skb, count);
 575        bcs->tx_cnt -= count;
 576        bcs->hw.hscx.count += count;
 577        while (cnt--) cs->BC_Write_Reg(cs, hscx, IPACX_XFIFOB, *p++); 
 578        cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, (more ? 0x08 : 0x0a));
 579  
 580        if (cs->debug &L1_DEB_HSCX_FIFO) {
 581                char *t = bcs->blog;
 582
 583                t += sprintf(t, "chb_fill_fifo() B-%d cnt %d", hscx, count);
 584                QuickHex(t, ptr, count);
 585                debugl1(cs, bcs->blog);
 586        }
 587}
 588
 589//----------------------------------------------------------
 590// B channel interrupt handler
 591//----------------------------------------------------------
 592static void
 593bch_int(struct IsdnCardState *cs, u_char hscx)
 594{
 595        u_char istab;
 596        struct BCState *bcs;
 597        struct sk_buff *skb;
 598        int count;
 599        u_char rstab;
 600
 601        bcs = cs->bcs + hscx;
 602        istab = cs->BC_Read_Reg(cs, hscx, IPACX_ISTAB);
 603//##############################################  
 604//      printk(KERN_WARNING "bch_int(istab=%02x)\n", istab);
 605//##############################################  
 606        if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return;
 607
 608        if (istab &0x80) {      // RME
 609                rstab = cs->BC_Read_Reg(cs, hscx, IPACX_RSTAB);
 610                if ((rstab &0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)
 611                        if (!(rstab &0x80))
 612                                if (cs->debug &L1_DEB_WARN) 
 613          debugl1(cs, "bch_int() B-%d: invalid frame", hscx);
 614                        if ((rstab &0x40) && (bcs->mode != L1_MODE_NULL))
 615                                if (cs->debug &L1_DEB_WARN) 
 616          debugl1(cs, "bch_int() B-%d: RDO mode=%d", hscx, bcs->mode);
 617                        if (!(rstab &0x20))
 618                                if (cs->debug &L1_DEB_WARN) 
 619          debugl1(cs, "bch_int() B-%d: CRC error", hscx);
 620            cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80);  // RMC
 621                } 
 622    else {  // received frame ok
 623                        count = cs->BC_Read_Reg(cs, hscx, IPACX_RBCLB) &(B_FIFO_SIZE-1);
 624                        if (count == 0) count = B_FIFO_SIZE;
 625                        bch_empty_fifo(bcs, count);
 626                        if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
 627                                if (cs->debug &L1_DEB_HSCX_FIFO)
 628                                        debugl1(cs, "bch_int Frame %d", count);
 629                                if (!(skb = dev_alloc_skb(count)))
 630                                        printk(KERN_WARNING "HiSax bch_int(): receive frame out of memory\n");
 631                                else {
 632                                        memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
 633                                        skb_queue_tail(&bcs->rqueue, skb);
 634                                }
 635                        }
 636                }
 637                bcs->hw.hscx.rcvidx = 0;
 638                schedule_event(bcs, B_RCVBUFREADY);
 639        }
 640  
 641        if (istab &0x40) {      // RPF
 642                bch_empty_fifo(bcs, B_FIFO_SIZE);
 643
 644                if (bcs->mode == L1_MODE_TRANS) { // queue every chunk
 645                        // receive transparent audio data
 646                        if (!(skb = dev_alloc_skb(B_FIFO_SIZE)))
 647                                printk(KERN_WARNING "HiSax bch_int(): receive transparent out of memory\n");
 648                        else {
 649                                memcpy(skb_put(skb, B_FIFO_SIZE), bcs->hw.hscx.rcvbuf, 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        }
 691  afterXPR:
 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
 915