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