linux/drivers/isdn/hisax/isac.c
<<
>>
Prefs
   1/* $Id: isac.c,v 1.31.2.3 2004/01/13 14:31:25 keil Exp $
   2 *
   3 * ISAC specific routines
   4 *
   5 * Author       Karsten Keil
   6 * Copyright    by Karsten Keil      <keil@isdn4linux.de>
   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 * For changes and modifications please read
  12 * Documentation/isdn/HiSax.cert
  13 *
  14 */
  15
  16#include "hisax.h"
  17#include "isac.h"
  18#include "arcofi.h"
  19#include "isdnl1.h"
  20#include <linux/interrupt.h>
  21#include <linux/init.h>
  22
  23#define DBUSY_TIMER_VALUE 80
  24#define ARCOFI_USE 1
  25
  26static char *ISACVer[] __devinitdata =
  27{"2086/2186 V1.1", "2085 B1", "2085 B2",
  28 "2085 V2.3"};
  29
  30void __devinit ISACVersion(struct IsdnCardState *cs, char *s)
  31{
  32        int val;
  33
  34        val = cs->readisac(cs, ISAC_RBCH);
  35        printk(KERN_INFO "%s ISAC version (%x): %s\n", s, val, ISACVer[(val >> 5) & 3]);
  36}
  37
  38static void
  39ph_command(struct IsdnCardState *cs, unsigned int command)
  40{
  41        if (cs->debug & L1_DEB_ISAC)
  42                debugl1(cs, "ph_command %x", command);
  43        cs->writeisac(cs, ISAC_CIX0, (command << 2) | 3);
  44}
  45
  46
  47static void
  48isac_new_ph(struct IsdnCardState *cs)
  49{
  50        switch (cs->dc.isac.ph_state) {
  51                case (ISAC_IND_RS):
  52                case (ISAC_IND_EI):
  53                        ph_command(cs, ISAC_CMD_DUI);
  54                        l1_msg(cs, HW_RESET | INDICATION, NULL);
  55                        break;
  56                case (ISAC_IND_DID):
  57                        l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
  58                        break;
  59                case (ISAC_IND_DR):
  60                        l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
  61                        break;
  62                case (ISAC_IND_PU):
  63                        l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
  64                        break;
  65                case (ISAC_IND_RSY):
  66                        l1_msg(cs, HW_RSYNC | INDICATION, NULL);
  67                        break;
  68                case (ISAC_IND_ARD):
  69                        l1_msg(cs, HW_INFO2 | INDICATION, NULL);
  70                        break;
  71                case (ISAC_IND_AI8):
  72                        l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
  73                        break;
  74                case (ISAC_IND_AI10):
  75                        l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL);
  76                        break;
  77                default:
  78                        break;
  79        }
  80}
  81
  82static void
  83isac_bh(struct work_struct *work)
  84{
  85        struct IsdnCardState *cs =
  86                container_of(work, struct IsdnCardState, tqueue);
  87        struct PStack *stptr;
  88        
  89        if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
  90                if (cs->debug)
  91                        debugl1(cs, "D-Channel Busy cleared");
  92                stptr = cs->stlist;
  93                while (stptr != NULL) {
  94                        stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
  95                        stptr = stptr->next;
  96                }
  97        }
  98        if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
  99                isac_new_ph(cs);                
 100        if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
 101                DChannel_proc_rcv(cs);
 102        if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
 103                DChannel_proc_xmt(cs);
 104#if ARCOFI_USE
 105        if (!test_bit(HW_ARCOFI, &cs->HW_Flags))
 106                return;
 107        if (test_and_clear_bit(D_RX_MON1, &cs->event))
 108                arcofi_fsm(cs, ARCOFI_RX_END, NULL);
 109        if (test_and_clear_bit(D_TX_MON1, &cs->event))
 110                arcofi_fsm(cs, ARCOFI_TX_END, NULL);
 111#endif
 112}
 113
 114static void
 115isac_empty_fifo(struct IsdnCardState *cs, int count)
 116{
 117        u_char *ptr;
 118
 119        if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
 120                debugl1(cs, "isac_empty_fifo");
 121
 122        if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
 123                if (cs->debug & L1_DEB_WARN)
 124                        debugl1(cs, "isac_empty_fifo overrun %d",
 125                                cs->rcvidx + count);
 126                cs->writeisac(cs, ISAC_CMDR, 0x80);
 127                cs->rcvidx = 0;
 128                return;
 129        }
 130        ptr = cs->rcvbuf + cs->rcvidx;
 131        cs->rcvidx += count;
 132        cs->readisacfifo(cs, ptr, count);
 133        cs->writeisac(cs, ISAC_CMDR, 0x80);
 134        if (cs->debug & L1_DEB_ISAC_FIFO) {
 135                char *t = cs->dlog;
 136
 137                t += sprintf(t, "isac_empty_fifo cnt %d", count);
 138                QuickHex(t, ptr, count);
 139                debugl1(cs, cs->dlog);
 140        }
 141}
 142
 143static void
 144isac_fill_fifo(struct IsdnCardState *cs)
 145{
 146        int count, more;
 147        u_char *ptr;
 148
 149        if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
 150                debugl1(cs, "isac_fill_fifo");
 151
 152        if (!cs->tx_skb)
 153                return;
 154
 155        count = cs->tx_skb->len;
 156        if (count <= 0)
 157                return;
 158
 159        more = 0;
 160        if (count > 32) {
 161                more = !0;
 162                count = 32;
 163        }
 164        ptr = cs->tx_skb->data;
 165        skb_pull(cs->tx_skb, count);
 166        cs->tx_cnt += count;
 167        cs->writeisacfifo(cs, ptr, count);
 168        cs->writeisac(cs, ISAC_CMDR, more ? 0x8 : 0xa);
 169        if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
 170                debugl1(cs, "isac_fill_fifo dbusytimer running");
 171                del_timer(&cs->dbusytimer);
 172        }
 173        init_timer(&cs->dbusytimer);
 174        cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
 175        add_timer(&cs->dbusytimer);
 176        if (cs->debug & L1_DEB_ISAC_FIFO) {
 177                char *t = cs->dlog;
 178
 179                t += sprintf(t, "isac_fill_fifo cnt %d", count);
 180                QuickHex(t, ptr, count);
 181                debugl1(cs, cs->dlog);
 182        }
 183}
 184
 185void
 186isac_interrupt(struct IsdnCardState *cs, u_char val)
 187{
 188        u_char exval, v1;
 189        struct sk_buff *skb;
 190        unsigned int count;
 191
 192        if (cs->debug & L1_DEB_ISAC)
 193                debugl1(cs, "ISAC interrupt %x", val);
 194        if (val & 0x80) {       /* RME */
 195                exval = cs->readisac(cs, ISAC_RSTA);
 196                if ((exval & 0x70) != 0x20) {
 197                        if (exval & 0x40) {
 198                                if (cs->debug & L1_DEB_WARN)
 199                                        debugl1(cs, "ISAC RDO");
 200#ifdef ERROR_STATISTIC
 201                                cs->err_rx++;
 202#endif
 203                        }
 204                        if (!(exval & 0x20)) {
 205                                if (cs->debug & L1_DEB_WARN)
 206                                        debugl1(cs, "ISAC CRC error");
 207#ifdef ERROR_STATISTIC
 208                                cs->err_crc++;
 209#endif
 210                        }
 211                        cs->writeisac(cs, ISAC_CMDR, 0x80);
 212                } else {
 213                        count = cs->readisac(cs, ISAC_RBCL) & 0x1f;
 214                        if (count == 0)
 215                                count = 32;
 216                        isac_empty_fifo(cs, count);
 217                        if ((count = cs->rcvidx) > 0) {
 218                                cs->rcvidx = 0;
 219                                if (!(skb = alloc_skb(count, GFP_ATOMIC)))
 220                                        printk(KERN_WARNING "HiSax: D receive out of memory\n");
 221                                else {
 222                                        memcpy(skb_put(skb, count), cs->rcvbuf, count);
 223                                        skb_queue_tail(&cs->rq, skb);
 224                                }
 225                        }
 226                }
 227                cs->rcvidx = 0;
 228                schedule_event(cs, D_RCVBUFREADY);
 229        }
 230        if (val & 0x40) {       /* RPF */
 231                isac_empty_fifo(cs, 32);
 232        }
 233        if (val & 0x20) {       /* RSC */
 234                /* never */
 235                if (cs->debug & L1_DEB_WARN)
 236                        debugl1(cs, "ISAC RSC interrupt");
 237        }
 238        if (val & 0x10) {       /* XPR */
 239                if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 240                        del_timer(&cs->dbusytimer);
 241                if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
 242                        schedule_event(cs, D_CLEARBUSY);
 243                if (cs->tx_skb) {
 244                        if (cs->tx_skb->len) {
 245                                isac_fill_fifo(cs);
 246                                goto afterXPR;
 247                        } else {
 248                                dev_kfree_skb_irq(cs->tx_skb);
 249                                cs->tx_cnt = 0;
 250                                cs->tx_skb = NULL;
 251                        }
 252                }
 253                if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
 254                        cs->tx_cnt = 0;
 255                        isac_fill_fifo(cs);
 256                } else
 257                        schedule_event(cs, D_XMTBUFREADY);
 258        }
 259      afterXPR:
 260        if (val & 0x04) {       /* CISQ */
 261                exval = cs->readisac(cs, ISAC_CIR0);
 262                if (cs->debug & L1_DEB_ISAC)
 263                        debugl1(cs, "ISAC CIR0 %02X", exval );
 264                if (exval & 2) {
 265                        cs->dc.isac.ph_state = (exval >> 2) & 0xf;
 266                        if (cs->debug & L1_DEB_ISAC)
 267                                debugl1(cs, "ph_state change %x", cs->dc.isac.ph_state);
 268                        schedule_event(cs, D_L1STATECHANGE);
 269                }
 270                if (exval & 1) {
 271                        exval = cs->readisac(cs, ISAC_CIR1);
 272                        if (cs->debug & L1_DEB_ISAC)
 273                                debugl1(cs, "ISAC CIR1 %02X", exval );
 274                }
 275        }
 276        if (val & 0x02) {       /* SIN */
 277                /* never */
 278                if (cs->debug & L1_DEB_WARN)
 279                        debugl1(cs, "ISAC SIN interrupt");
 280        }
 281        if (val & 0x01) {       /* EXI */
 282                exval = cs->readisac(cs, ISAC_EXIR);
 283                if (cs->debug & L1_DEB_WARN)
 284                        debugl1(cs, "ISAC EXIR %02x", exval);
 285                if (exval & 0x80) {  /* XMR */
 286                        debugl1(cs, "ISAC XMR");
 287                        printk(KERN_WARNING "HiSax: ISAC XMR\n");
 288                }
 289                if (exval & 0x40) {  /* XDU */
 290                        debugl1(cs, "ISAC XDU");
 291                        printk(KERN_WARNING "HiSax: ISAC XDU\n");
 292#ifdef ERROR_STATISTIC
 293                        cs->err_tx++;
 294#endif
 295                        if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 296                                del_timer(&cs->dbusytimer);
 297                        if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
 298                                schedule_event(cs, D_CLEARBUSY);
 299                        if (cs->tx_skb) { /* Restart frame */
 300                                skb_push(cs->tx_skb, cs->tx_cnt);
 301                                cs->tx_cnt = 0;
 302                                isac_fill_fifo(cs);
 303                        } else {
 304                                printk(KERN_WARNING "HiSax: ISAC XDU no skb\n");
 305                                debugl1(cs, "ISAC XDU no skb");
 306                        }
 307                }
 308                if (exval & 0x04) {  /* MOS */
 309                        v1 = cs->readisac(cs, ISAC_MOSR);
 310                        if (cs->debug & L1_DEB_MONITOR)
 311                                debugl1(cs, "ISAC MOSR %02x", v1);
 312#if ARCOFI_USE
 313                        if (v1 & 0x08) {
 314                                if (!cs->dc.isac.mon_rx) {
 315                                        if (!(cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
 316                                                if (cs->debug & L1_DEB_WARN)
 317                                                        debugl1(cs, "ISAC MON RX out of memory!");
 318                                                cs->dc.isac.mocr &= 0xf0;
 319                                                cs->dc.isac.mocr |= 0x0a;
 320                                                cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 321                                                goto afterMONR0;
 322                                        } else
 323                                                cs->dc.isac.mon_rxp = 0;
 324                                }
 325                                if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) {
 326                                        cs->dc.isac.mocr &= 0xf0;
 327                                        cs->dc.isac.mocr |= 0x0a;
 328                                        cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 329                                        cs->dc.isac.mon_rxp = 0;
 330                                        if (cs->debug & L1_DEB_WARN)
 331                                                debugl1(cs, "ISAC MON RX overflow!");
 332                                        goto afterMONR0;
 333                                }
 334                                cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR0);
 335                                if (cs->debug & L1_DEB_MONITOR)
 336                                        debugl1(cs, "ISAC MOR0 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp -1]);
 337                                if (cs->dc.isac.mon_rxp == 1) {
 338                                        cs->dc.isac.mocr |= 0x04;
 339                                        cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 340                                }
 341                        }
 342                      afterMONR0:
 343                        if (v1 & 0x80) {
 344                                if (!cs->dc.isac.mon_rx) {
 345                                        if (!(cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
 346                                                if (cs->debug & L1_DEB_WARN)
 347                                                        debugl1(cs, "ISAC MON RX out of memory!");
 348                                                cs->dc.isac.mocr &= 0x0f;
 349                                                cs->dc.isac.mocr |= 0xa0;
 350                                                cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 351                                                goto afterMONR1;
 352                                        } else
 353                                                cs->dc.isac.mon_rxp = 0;
 354                                }
 355                                if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) {
 356                                        cs->dc.isac.mocr &= 0x0f;
 357                                        cs->dc.isac.mocr |= 0xa0;
 358                                        cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 359                                        cs->dc.isac.mon_rxp = 0;
 360                                        if (cs->debug & L1_DEB_WARN)
 361                                                debugl1(cs, "ISAC MON RX overflow!");
 362                                        goto afterMONR1;
 363                                }
 364                                cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR1);
 365                                if (cs->debug & L1_DEB_MONITOR)
 366                                        debugl1(cs, "ISAC MOR1 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp -1]);
 367                                cs->dc.isac.mocr |= 0x40;
 368                                cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 369                        }
 370                      afterMONR1:
 371                        if (v1 & 0x04) {
 372                                cs->dc.isac.mocr &= 0xf0;
 373                                cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 374                                cs->dc.isac.mocr |= 0x0a;
 375                                cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 376                                schedule_event(cs, D_RX_MON0);
 377                        }
 378                        if (v1 & 0x40) {
 379                                cs->dc.isac.mocr &= 0x0f;
 380                                cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 381                                cs->dc.isac.mocr |= 0xa0;
 382                                cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 383                                schedule_event(cs, D_RX_MON1);
 384                        }
 385                        if (v1 & 0x02) {
 386                                if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc && 
 387                                        (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) && 
 388                                        !(v1 & 0x08))) {
 389                                        cs->dc.isac.mocr &= 0xf0;
 390                                        cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 391                                        cs->dc.isac.mocr |= 0x0a;
 392                                        cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 393                                        if (cs->dc.isac.mon_txc &&
 394                                                (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc))
 395                                                schedule_event(cs, D_TX_MON0);
 396                                        goto AfterMOX0;
 397                                }
 398                                if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) {
 399                                        schedule_event(cs, D_TX_MON0);
 400                                        goto AfterMOX0;
 401                                }
 402                                cs->writeisac(cs, ISAC_MOX0,
 403                                        cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
 404                                if (cs->debug & L1_DEB_MONITOR)
 405                                        debugl1(cs, "ISAC %02x -> MOX0", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp -1]);
 406                        }
 407                      AfterMOX0:
 408                        if (v1 & 0x20) {
 409                                if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc && 
 410                                        (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) && 
 411                                        !(v1 & 0x80))) {
 412                                        cs->dc.isac.mocr &= 0x0f;
 413                                        cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 414                                        cs->dc.isac.mocr |= 0xa0;
 415                                        cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 416                                        if (cs->dc.isac.mon_txc &&
 417                                                (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc))
 418                                                schedule_event(cs, D_TX_MON1);
 419                                        goto AfterMOX1;
 420                                }
 421                                if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) {
 422                                        schedule_event(cs, D_TX_MON1);
 423                                        goto AfterMOX1;
 424                                }
 425                                cs->writeisac(cs, ISAC_MOX1,
 426                                        cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
 427                                if (cs->debug & L1_DEB_MONITOR)
 428                                        debugl1(cs, "ISAC %02x -> MOX1", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp -1]);
 429                        }
 430                      AfterMOX1:;
 431#endif
 432                }
 433        }
 434}
 435
 436static void
 437ISAC_l1hw(struct PStack *st, int pr, void *arg)
 438{
 439        struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
 440        struct sk_buff *skb = arg;
 441        u_long flags;
 442        int  val;
 443
 444        switch (pr) {
 445                case (PH_DATA |REQUEST):
 446                        if (cs->debug & DEB_DLOG_HEX)
 447                                LogFrame(cs, skb->data, skb->len);
 448                        if (cs->debug & DEB_DLOG_VERBOSE)
 449                                dlogframe(cs, skb, 0);
 450                        spin_lock_irqsave(&cs->lock, flags);
 451                        if (cs->tx_skb) {
 452                                skb_queue_tail(&cs->sq, skb);
 453#ifdef L2FRAME_DEBUG            /* psa */
 454                                if (cs->debug & L1_DEB_LAPD)
 455                                        Logl2Frame(cs, skb, "PH_DATA Queued", 0);
 456#endif
 457                        } else {
 458                                cs->tx_skb = skb;
 459                                cs->tx_cnt = 0;
 460#ifdef L2FRAME_DEBUG            /* psa */
 461                                if (cs->debug & L1_DEB_LAPD)
 462                                        Logl2Frame(cs, skb, "PH_DATA", 0);
 463#endif
 464                                isac_fill_fifo(cs);
 465                        }
 466                        spin_unlock_irqrestore(&cs->lock, flags);
 467                        break;
 468                case (PH_PULL |INDICATION):
 469                        spin_lock_irqsave(&cs->lock, flags);
 470                        if (cs->tx_skb) {
 471                                if (cs->debug & L1_DEB_WARN)
 472                                        debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
 473                                skb_queue_tail(&cs->sq, skb);
 474                        } else {
 475                                if (cs->debug & DEB_DLOG_HEX)
 476                                        LogFrame(cs, skb->data, skb->len);
 477                                if (cs->debug & DEB_DLOG_VERBOSE)
 478                                        dlogframe(cs, skb, 0);
 479                                cs->tx_skb = skb;
 480                                cs->tx_cnt = 0;
 481#ifdef L2FRAME_DEBUG            /* psa */
 482                                if (cs->debug & L1_DEB_LAPD)
 483                                        Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
 484#endif
 485                                isac_fill_fifo(cs);
 486                        }
 487                        spin_unlock_irqrestore(&cs->lock, flags);
 488                        break;
 489                case (PH_PULL | REQUEST):
 490#ifdef L2FRAME_DEBUG            /* psa */
 491                        if (cs->debug & L1_DEB_LAPD)
 492                                debugl1(cs, "-> PH_REQUEST_PULL");
 493#endif
 494                        if (!cs->tx_skb) {
 495                                test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 496                                st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
 497                        } else
 498                                test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 499                        break;
 500                case (HW_RESET | REQUEST):
 501                        spin_lock_irqsave(&cs->lock, flags);
 502                        if ((cs->dc.isac.ph_state == ISAC_IND_EI) ||
 503                                (cs->dc.isac.ph_state == ISAC_IND_DR) ||
 504                                (cs->dc.isac.ph_state == ISAC_IND_RS))
 505                                ph_command(cs, ISAC_CMD_TIM);
 506                        else
 507                                ph_command(cs, ISAC_CMD_RS);
 508                        spin_unlock_irqrestore(&cs->lock, flags);
 509                        break;
 510                case (HW_ENABLE | REQUEST):
 511                        spin_lock_irqsave(&cs->lock, flags);
 512                        ph_command(cs, ISAC_CMD_TIM);
 513                        spin_unlock_irqrestore(&cs->lock, flags);
 514                        break;
 515                case (HW_INFO3 | REQUEST):
 516                        spin_lock_irqsave(&cs->lock, flags);
 517                        ph_command(cs, ISAC_CMD_AR8);
 518                        spin_unlock_irqrestore(&cs->lock, flags);
 519                        break;
 520                case (HW_TESTLOOP | REQUEST):
 521                        spin_lock_irqsave(&cs->lock, flags);
 522                        val = 0;
 523                        if (1 & (long) arg)
 524                                val |= 0x0c;
 525                        if (2 & (long) arg)
 526                                val |= 0x3;
 527                        if (test_bit(HW_IOM1, &cs->HW_Flags)) {
 528                                /* IOM 1 Mode */
 529                                if (!val) {
 530                                        cs->writeisac(cs, ISAC_SPCR, 0xa);
 531                                        cs->writeisac(cs, ISAC_ADF1, 0x2);
 532                                } else {
 533                                        cs->writeisac(cs, ISAC_SPCR, val);
 534                                        cs->writeisac(cs, ISAC_ADF1, 0xa);
 535                                }
 536                        } else {
 537                                /* IOM 2 Mode */
 538                                cs->writeisac(cs, ISAC_SPCR, val);
 539                                if (val)
 540                                        cs->writeisac(cs, ISAC_ADF1, 0x8);
 541                                else
 542                                        cs->writeisac(cs, ISAC_ADF1, 0x0);
 543                        }
 544                        spin_unlock_irqrestore(&cs->lock, flags);
 545                        break;
 546                case (HW_DEACTIVATE | RESPONSE):
 547                        skb_queue_purge(&cs->rq);
 548                        skb_queue_purge(&cs->sq);
 549                        if (cs->tx_skb) {
 550                                dev_kfree_skb_any(cs->tx_skb);
 551                                cs->tx_skb = NULL;
 552                        }
 553                        if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 554                                del_timer(&cs->dbusytimer);
 555                        if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
 556                                schedule_event(cs, D_CLEARBUSY);
 557                        break;
 558                default:
 559                        if (cs->debug & L1_DEB_WARN)
 560                                debugl1(cs, "isac_l1hw unknown %04x", pr);
 561                        break;
 562        }
 563}
 564
 565static void
 566setstack_isac(struct PStack *st, struct IsdnCardState *cs)
 567{
 568        st->l1.l1hw = ISAC_l1hw;
 569}
 570
 571static void
 572DC_Close_isac(struct IsdnCardState *cs)
 573{
 574        kfree(cs->dc.isac.mon_rx);
 575        cs->dc.isac.mon_rx = NULL;
 576        kfree(cs->dc.isac.mon_tx);
 577        cs->dc.isac.mon_tx = NULL;
 578}
 579
 580static void
 581dbusy_timer_handler(struct IsdnCardState *cs)
 582{
 583        struct PStack *stptr;
 584        int     rbch, star;
 585
 586        if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
 587                rbch = cs->readisac(cs, ISAC_RBCH);
 588                star = cs->readisac(cs, ISAC_STAR);
 589                if (cs->debug) 
 590                        debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x",
 591                                rbch, star);
 592                if (rbch & ISAC_RBCH_XAC) { /* D-Channel Busy */
 593                        test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
 594                        stptr = cs->stlist;
 595                        while (stptr != NULL) {
 596                                stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
 597                                stptr = stptr->next;
 598                        }
 599                } else {
 600                        /* discard frame; reset transceiver */
 601                        test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
 602                        if (cs->tx_skb) {
 603                                dev_kfree_skb_any(cs->tx_skb);
 604                                cs->tx_cnt = 0;
 605                                cs->tx_skb = NULL;
 606                        } else {
 607                                printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");
 608                                debugl1(cs, "D-Channel Busy no skb");
 609                        }
 610                        cs->writeisac(cs, ISAC_CMDR, 0x01); /* Transmitter reset */
 611                        cs->irq_func(cs->irq, cs);
 612                }
 613        }
 614}
 615
 616void initisac(struct IsdnCardState *cs)
 617{
 618        cs->setstack_d = setstack_isac;
 619        cs->DC_Close = DC_Close_isac;
 620        cs->dc.isac.mon_tx = NULL;
 621        cs->dc.isac.mon_rx = NULL;
 622        cs->writeisac(cs, ISAC_MASK, 0xff);
 623        cs->dc.isac.mocr = 0xaa;
 624        if (test_bit(HW_IOM1, &cs->HW_Flags)) {
 625                /* IOM 1 Mode */
 626                cs->writeisac(cs, ISAC_ADF2, 0x0);
 627                cs->writeisac(cs, ISAC_SPCR, 0xa);
 628                cs->writeisac(cs, ISAC_ADF1, 0x2);
 629                cs->writeisac(cs, ISAC_STCR, 0x70);
 630                cs->writeisac(cs, ISAC_MODE, 0xc9);
 631        } else {
 632                /* IOM 2 Mode */
 633                if (!cs->dc.isac.adf2)
 634                        cs->dc.isac.adf2 = 0x80;
 635                cs->writeisac(cs, ISAC_ADF2, cs->dc.isac.adf2);
 636                cs->writeisac(cs, ISAC_SQXR, 0x2f);
 637                cs->writeisac(cs, ISAC_SPCR, 0x00);
 638                cs->writeisac(cs, ISAC_STCR, 0x70);
 639                cs->writeisac(cs, ISAC_MODE, 0xc9);
 640                cs->writeisac(cs, ISAC_TIMR, 0x00);
 641                cs->writeisac(cs, ISAC_ADF1, 0x00);
 642        }
 643        ph_command(cs, ISAC_CMD_RS);
 644        cs->writeisac(cs, ISAC_MASK, 0x0);
 645}
 646
 647void clear_pending_isac_ints(struct IsdnCardState *cs)
 648{
 649        int val, eval;
 650
 651        val = cs->readisac(cs, ISAC_STAR);
 652        debugl1(cs, "ISAC STAR %x", val);
 653        val = cs->readisac(cs, ISAC_MODE);
 654        debugl1(cs, "ISAC MODE %x", val);
 655        val = cs->readisac(cs, ISAC_ADF2);
 656        debugl1(cs, "ISAC ADF2 %x", val);
 657        val = cs->readisac(cs, ISAC_ISTA);
 658        debugl1(cs, "ISAC ISTA %x", val);
 659        if (val & 0x01) {
 660                eval = cs->readisac(cs, ISAC_EXIR);
 661                debugl1(cs, "ISAC EXIR %x", eval);
 662        }
 663        val = cs->readisac(cs, ISAC_CIR0);
 664        debugl1(cs, "ISAC CIR0 %x", val);
 665        cs->dc.isac.ph_state = (val >> 2) & 0xf;
 666        schedule_event(cs, D_L1STATECHANGE);
 667        /* Disable all IRQ */
 668        cs->writeisac(cs, ISAC_MASK, 0xFF);
 669}
 670
 671void __devinit
 672setup_isac(struct IsdnCardState *cs)
 673{
 674        INIT_WORK(&cs->tqueue, isac_bh);
 675        cs->dbusytimer.function = (void *) dbusy_timer_handler;
 676        cs->dbusytimer.data = (long) cs;
 677        init_timer(&cs->dbusytimer);
 678}
 679