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