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, 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, 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                        if ((count = cs->rcvidx) > 0) {
 219                                cs->rcvidx = 0;
 220                                if (!(skb = alloc_skb(count, GFP_ATOMIC)))
 221                                        printk(KERN_WARNING "HiSax: D receive out of memory\n");
 222                                else {
 223                                        memcpy(skb_put(skb, count), cs->rcvbuf, count);
 224                                        skb_queue_tail(&cs->rq, skb);
 225                                }
 226                        }
 227                }
 228                cs->rcvidx = 0;
 229                schedule_event(cs, D_RCVBUFREADY);
 230        }
 231        if (val & 0x40) {       /* RPF */
 232                isac_empty_fifo(cs, 32);
 233        }
 234        if (val & 0x20) {       /* RSC */
 235                /* never */
 236                if (cs->debug & L1_DEB_WARN)
 237                        debugl1(cs, "ISAC RSC interrupt");
 238        }
 239        if (val & 0x10) {       /* XPR */
 240                if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 241                        del_timer(&cs->dbusytimer);
 242                if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
 243                        schedule_event(cs, D_CLEARBUSY);
 244                if (cs->tx_skb) {
 245                        if (cs->tx_skb->len) {
 246                                isac_fill_fifo(cs);
 247                                goto afterXPR;
 248                        } else {
 249                                dev_kfree_skb_irq(cs->tx_skb);
 250                                cs->tx_cnt = 0;
 251                                cs->tx_skb = NULL;
 252                        }
 253                }
 254                if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
 255                        cs->tx_cnt = 0;
 256                        isac_fill_fifo(cs);
 257                } else
 258                        schedule_event(cs, D_XMTBUFREADY);
 259        }
 260afterXPR:
 261        if (val & 0x04) {       /* CISQ */
 262                exval = cs->readisac(cs, ISAC_CIR0);
 263                if (cs->debug & L1_DEB_ISAC)
 264                        debugl1(cs, "ISAC CIR0 %02X", exval);
 265                if (exval & 2) {
 266                        cs->dc.isac.ph_state = (exval >> 2) & 0xf;
 267                        if (cs->debug & L1_DEB_ISAC)
 268                                debugl1(cs, "ph_state change %x", cs->dc.isac.ph_state);
 269                        schedule_event(cs, D_L1STATECHANGE);
 270                }
 271                if (exval & 1) {
 272                        exval = cs->readisac(cs, ISAC_CIR1);
 273                        if (cs->debug & L1_DEB_ISAC)
 274                                debugl1(cs, "ISAC CIR1 %02X", exval);
 275                }
 276        }
 277        if (val & 0x02) {       /* SIN */
 278                /* never */
 279                if (cs->debug & L1_DEB_WARN)
 280                        debugl1(cs, "ISAC SIN interrupt");
 281        }
 282        if (val & 0x01) {       /* EXI */
 283                exval = cs->readisac(cs, ISAC_EXIR);
 284                if (cs->debug & L1_DEB_WARN)
 285                        debugl1(cs, "ISAC EXIR %02x", exval);
 286                if (exval & 0x80) {  /* XMR */
 287                        debugl1(cs, "ISAC XMR");
 288                        printk(KERN_WARNING "HiSax: ISAC XMR\n");
 289                }
 290                if (exval & 0x40) {  /* XDU */
 291                        debugl1(cs, "ISAC XDU");
 292                        printk(KERN_WARNING "HiSax: ISAC XDU\n");
 293#ifdef ERROR_STATISTIC
 294                        cs->err_tx++;
 295#endif
 296                        if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 297                                del_timer(&cs->dbusytimer);
 298                        if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
 299                                schedule_event(cs, D_CLEARBUSY);
 300                        if (cs->tx_skb) { /* Restart frame */
 301                                skb_push(cs->tx_skb, cs->tx_cnt);
 302                                cs->tx_cnt = 0;
 303                                isac_fill_fifo(cs);
 304                        } else {
 305                                printk(KERN_WARNING "HiSax: ISAC XDU no skb\n");
 306                                debugl1(cs, "ISAC XDU no skb");
 307                        }
 308                }
 309                if (exval & 0x04) {  /* MOS */
 310                        v1 = cs->readisac(cs, ISAC_MOSR);
 311                        if (cs->debug & L1_DEB_MONITOR)
 312                                debugl1(cs, "ISAC MOSR %02x", v1);
 313#if ARCOFI_USE
 314                        if (v1 & 0x08) {
 315                                if (!cs->dc.isac.mon_rx) {
 316                                        if (!(cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
 317                                                if (cs->debug & L1_DEB_WARN)
 318                                                        debugl1(cs, "ISAC MON RX out of memory!");
 319                                                cs->dc.isac.mocr &= 0xf0;
 320                                                cs->dc.isac.mocr |= 0x0a;
 321                                                cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 322                                                goto afterMONR0;
 323                                        } else
 324                                                cs->dc.isac.mon_rxp = 0;
 325                                }
 326                                if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) {
 327                                        cs->dc.isac.mocr &= 0xf0;
 328                                        cs->dc.isac.mocr |= 0x0a;
 329                                        cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 330                                        cs->dc.isac.mon_rxp = 0;
 331                                        if (cs->debug & L1_DEB_WARN)
 332                                                debugl1(cs, "ISAC MON RX overflow!");
 333                                        goto afterMONR0;
 334                                }
 335                                cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR0);
 336                                if (cs->debug & L1_DEB_MONITOR)
 337                                        debugl1(cs, "ISAC MOR0 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp - 1]);
 338                                if (cs->dc.isac.mon_rxp == 1) {
 339                                        cs->dc.isac.mocr |= 0x04;
 340                                        cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 341                                }
 342                        }
 343                afterMONR0:
 344                        if (v1 & 0x80) {
 345                                if (!cs->dc.isac.mon_rx) {
 346                                        if (!(cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
 347                                                if (cs->debug & L1_DEB_WARN)
 348                                                        debugl1(cs, "ISAC MON RX out of memory!");
 349                                                cs->dc.isac.mocr &= 0x0f;
 350                                                cs->dc.isac.mocr |= 0xa0;
 351                                                cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 352                                                goto afterMONR1;
 353                                        } else
 354                                                cs->dc.isac.mon_rxp = 0;
 355                                }
 356                                if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) {
 357                                        cs->dc.isac.mocr &= 0x0f;
 358                                        cs->dc.isac.mocr |= 0xa0;
 359                                        cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 360                                        cs->dc.isac.mon_rxp = 0;
 361                                        if (cs->debug & L1_DEB_WARN)
 362                                                debugl1(cs, "ISAC MON RX overflow!");
 363                                        goto afterMONR1;
 364                                }
 365                                cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR1);
 366                                if (cs->debug & L1_DEB_MONITOR)
 367                                        debugl1(cs, "ISAC MOR1 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp - 1]);
 368                                cs->dc.isac.mocr |= 0x40;
 369                                cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 370                        }
 371                afterMONR1:
 372                        if (v1 & 0x04) {
 373                                cs->dc.isac.mocr &= 0xf0;
 374                                cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 375                                cs->dc.isac.mocr |= 0x0a;
 376                                cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 377                                schedule_event(cs, D_RX_MON0);
 378                        }
 379                        if (v1 & 0x40) {
 380                                cs->dc.isac.mocr &= 0x0f;
 381                                cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 382                                cs->dc.isac.mocr |= 0xa0;
 383                                cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 384                                schedule_event(cs, D_RX_MON1);
 385                        }
 386                        if (v1 & 0x02) {
 387                                if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc &&
 388                                                              (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) &&
 389                                                              !(v1 & 0x08))) {
 390                                        cs->dc.isac.mocr &= 0xf0;
 391                                        cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 392                                        cs->dc.isac.mocr |= 0x0a;
 393                                        cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 394                                        if (cs->dc.isac.mon_txc &&
 395                                            (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc))
 396                                                schedule_event(cs, D_TX_MON0);
 397                                        goto AfterMOX0;
 398                                }
 399                                if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) {
 400                                        schedule_event(cs, D_TX_MON0);
 401                                        goto AfterMOX0;
 402                                }
 403                                cs->writeisac(cs, ISAC_MOX0,
 404                                              cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
 405                                if (cs->debug & L1_DEB_MONITOR)
 406                                        debugl1(cs, "ISAC %02x -> MOX0", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp - 1]);
 407                        }
 408                AfterMOX0:
 409                        if (v1 & 0x20) {
 410                                if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc &&
 411                                                              (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) &&
 412                                                              !(v1 & 0x80))) {
 413                                        cs->dc.isac.mocr &= 0x0f;
 414                                        cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 415                                        cs->dc.isac.mocr |= 0xa0;
 416                                        cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
 417                                        if (cs->dc.isac.mon_txc &&
 418                                            (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc))
 419                                                schedule_event(cs, D_TX_MON1);
 420                                        goto AfterMOX1;
 421                                }
 422                                if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) {
 423                                        schedule_event(cs, D_TX_MON1);
 424                                        goto AfterMOX1;
 425                                }
 426                                cs->writeisac(cs, ISAC_MOX1,
 427                                              cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
 428                                if (cs->debug & L1_DEB_MONITOR)
 429                                        debugl1(cs, "ISAC %02x -> MOX1", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp - 1]);
 430                        }
 431                AfterMOX1:;
 432#endif
 433                }
 434        }
 435}
 436
 437static void
 438ISAC_l1hw(struct PStack *st, int pr, void *arg)
 439{
 440        struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
 441        struct sk_buff *skb = arg;
 442        u_long flags;
 443        int  val;
 444
 445        switch (pr) {
 446        case (PH_DATA | REQUEST):
 447                if (cs->debug & DEB_DLOG_HEX)
 448                        LogFrame(cs, skb->data, skb->len);
 449                if (cs->debug & DEB_DLOG_VERBOSE)
 450                        dlogframe(cs, skb, 0);
 451                spin_lock_irqsave(&cs->lock, flags);
 452                if (cs->tx_skb) {
 453                        skb_queue_tail(&cs->sq, skb);
 454#ifdef L2FRAME_DEBUG            /* psa */
 455                        if (cs->debug & L1_DEB_LAPD)
 456                                Logl2Frame(cs, skb, "PH_DATA Queued", 0);
 457#endif
 458                } else {
 459                        cs->tx_skb = skb;
 460                        cs->tx_cnt = 0;
 461#ifdef L2FRAME_DEBUG            /* psa */
 462                        if (cs->debug & L1_DEB_LAPD)
 463                                Logl2Frame(cs, skb, "PH_DATA", 0);
 464#endif
 465                        isac_fill_fifo(cs);
 466                }
 467                spin_unlock_irqrestore(&cs->lock, flags);
 468                break;
 469        case (PH_PULL | INDICATION):
 470                spin_lock_irqsave(&cs->lock, flags);
 471                if (cs->tx_skb) {
 472                        if (cs->debug & L1_DEB_WARN)
 473                                debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
 474                        skb_queue_tail(&cs->sq, skb);
 475                } else {
 476                        if (cs->debug & DEB_DLOG_HEX)
 477                                LogFrame(cs, skb->data, skb->len);
 478                        if (cs->debug & DEB_DLOG_VERBOSE)
 479                                dlogframe(cs, skb, 0);
 480                        cs->tx_skb = skb;
 481                        cs->tx_cnt = 0;
 482#ifdef L2FRAME_DEBUG            /* psa */
 483                        if (cs->debug & L1_DEB_LAPD)
 484                                Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
 485#endif
 486                        isac_fill_fifo(cs);
 487                }
 488                spin_unlock_irqrestore(&cs->lock, flags);
 489                break;
 490        case (PH_PULL | REQUEST):
 491#ifdef L2FRAME_DEBUG            /* psa */
 492                if (cs->debug & L1_DEB_LAPD)
 493                        debugl1(cs, "-> PH_REQUEST_PULL");
 494#endif
 495                if (!cs->tx_skb) {
 496                        test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 497                        st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
 498                } else
 499                        test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 500                break;
 501        case (HW_RESET | REQUEST):
 502                spin_lock_irqsave(&cs->lock, flags);
 503                if ((cs->dc.isac.ph_state == ISAC_IND_EI) ||
 504                    (cs->dc.isac.ph_state == ISAC_IND_DR) ||
 505                    (cs->dc.isac.ph_state == ISAC_IND_RS))
 506                        ph_command(cs, ISAC_CMD_TIM);
 507                else
 508                        ph_command(cs, ISAC_CMD_RS);
 509                spin_unlock_irqrestore(&cs->lock, flags);
 510                break;
 511        case (HW_ENABLE | REQUEST):
 512                spin_lock_irqsave(&cs->lock, flags);
 513                ph_command(cs, ISAC_CMD_TIM);
 514                spin_unlock_irqrestore(&cs->lock, flags);
 515                break;
 516        case (HW_INFO3 | REQUEST):
 517                spin_lock_irqsave(&cs->lock, flags);
 518                ph_command(cs, ISAC_CMD_AR8);
 519                spin_unlock_irqrestore(&cs->lock, flags);
 520                break;
 521        case (HW_TESTLOOP | REQUEST):
 522                spin_lock_irqsave(&cs->lock, flags);
 523                val = 0;
 524                if (1 & (long) arg)
 525                        val |= 0x0c;
 526                if (2 & (long) arg)
 527                        val |= 0x3;
 528                if (test_bit(HW_IOM1, &cs->HW_Flags)) {
 529                        /* IOM 1 Mode */
 530                        if (!val) {
 531                                cs->writeisac(cs, ISAC_SPCR, 0xa);
 532                                cs->writeisac(cs, ISAC_ADF1, 0x2);
 533                        } else {
 534                                cs->writeisac(cs, ISAC_SPCR, val);
 535                                cs->writeisac(cs, ISAC_ADF1, 0xa);
 536                        }
 537                } else {
 538                        /* IOM 2 Mode */
 539                        cs->writeisac(cs, ISAC_SPCR, val);
 540                        if (val)
 541                                cs->writeisac(cs, ISAC_ADF1, 0x8);
 542                        else
 543                                cs->writeisac(cs, ISAC_ADF1, 0x0);
 544                }
 545                spin_unlock_irqrestore(&cs->lock, flags);
 546                break;
 547        case (HW_DEACTIVATE | RESPONSE):
 548                skb_queue_purge(&cs->rq);
 549                skb_queue_purge(&cs->sq);
 550                if (cs->tx_skb) {
 551                        dev_kfree_skb_any(cs->tx_skb);
 552                        cs->tx_skb = NULL;
 553                }
 554                if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 555                        del_timer(&cs->dbusytimer);
 556                if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
 557                        schedule_event(cs, D_CLEARBUSY);
 558                break;
 559        default:
 560                if (cs->debug & L1_DEB_WARN)
 561                        debugl1(cs, "isac_l1hw unknown %04x", pr);
 562                break;
 563        }
 564}
 565
 566static void
 567setstack_isac(struct PStack *st, struct IsdnCardState *cs)
 568{
 569        st->l1.l1hw = ISAC_l1hw;
 570}
 571
 572static void
 573DC_Close_isac(struct IsdnCardState *cs)
 574{
 575        kfree(cs->dc.isac.mon_rx);
 576        cs->dc.isac.mon_rx = NULL;
 577        kfree(cs->dc.isac.mon_tx);
 578        cs->dc.isac.mon_tx = NULL;
 579}
 580
 581static void
 582dbusy_timer_handler(struct IsdnCardState *cs)
 583{
 584        struct PStack *stptr;
 585        int     rbch, star;
 586
 587        if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
 588                rbch = cs->readisac(cs, ISAC_RBCH);
 589                star = cs->readisac(cs, ISAC_STAR);
 590                if (cs->debug)
 591                        debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x",
 592                                rbch, star);
 593                if (rbch & ISAC_RBCH_XAC) { /* D-Channel Busy */
 594                        test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
 595                        stptr = cs->stlist;
 596                        while (stptr != NULL) {
 597                                stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
 598                                stptr = stptr->next;
 599                        }
 600                } else {
 601                        /* discard frame; reset transceiver */
 602                        test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
 603                        if (cs->tx_skb) {
 604                                dev_kfree_skb_any(cs->tx_skb);
 605                                cs->tx_cnt = 0;
 606                                cs->tx_skb = NULL;
 607                        } else {
 608                                printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");
 609                                debugl1(cs, "D-Channel Busy no skb");
 610                        }
 611                        cs->writeisac(cs, ISAC_CMDR, 0x01); /* Transmitter reset */
 612                        cs->irq_func(cs->irq, cs);
 613                }
 614        }
 615}
 616
 617void initisac(struct IsdnCardState *cs)
 618{
 619        cs->setstack_d = setstack_isac;
 620        cs->DC_Close = DC_Close_isac;
 621        cs->dc.isac.mon_tx = NULL;
 622        cs->dc.isac.mon_rx = NULL;
 623        cs->writeisac(cs, ISAC_MASK, 0xff);
 624        cs->dc.isac.mocr = 0xaa;
 625        if (test_bit(HW_IOM1, &cs->HW_Flags)) {
 626                /* IOM 1 Mode */
 627                cs->writeisac(cs, ISAC_ADF2, 0x0);
 628                cs->writeisac(cs, ISAC_SPCR, 0xa);
 629                cs->writeisac(cs, ISAC_ADF1, 0x2);
 630                cs->writeisac(cs, ISAC_STCR, 0x70);
 631                cs->writeisac(cs, ISAC_MODE, 0xc9);
 632        } else {
 633                /* IOM 2 Mode */
 634                if (!cs->dc.isac.adf2)
 635                        cs->dc.isac.adf2 = 0x80;
 636                cs->writeisac(cs, ISAC_ADF2, cs->dc.isac.adf2);
 637                cs->writeisac(cs, ISAC_SQXR, 0x2f);
 638                cs->writeisac(cs, ISAC_SPCR, 0x00);
 639                cs->writeisac(cs, ISAC_STCR, 0x70);
 640                cs->writeisac(cs, ISAC_MODE, 0xc9);
 641                cs->writeisac(cs, ISAC_TIMR, 0x00);
 642                cs->writeisac(cs, ISAC_ADF1, 0x00);
 643        }
 644        ph_command(cs, ISAC_CMD_RS);
 645        cs->writeisac(cs, ISAC_MASK, 0x0);
 646}
 647
 648void clear_pending_isac_ints(struct IsdnCardState *cs)
 649{
 650        int val, eval;
 651
 652        val = cs->readisac(cs, ISAC_STAR);
 653        debugl1(cs, "ISAC STAR %x", val);
 654        val = cs->readisac(cs, ISAC_MODE);
 655        debugl1(cs, "ISAC MODE %x", val);
 656        val = cs->readisac(cs, ISAC_ADF2);
 657        debugl1(cs, "ISAC ADF2 %x", val);
 658        val = cs->readisac(cs, ISAC_ISTA);
 659        debugl1(cs, "ISAC ISTA %x", val);
 660        if (val & 0x01) {
 661                eval = cs->readisac(cs, ISAC_EXIR);
 662                debugl1(cs, "ISAC EXIR %x", eval);
 663        }
 664        val = cs->readisac(cs, ISAC_CIR0);
 665        debugl1(cs, "ISAC CIR0 %x", val);
 666        cs->dc.isac.ph_state = (val >> 2) & 0xf;
 667        schedule_event(cs, D_L1STATECHANGE);
 668        /* Disable all IRQ */
 669        cs->writeisac(cs, ISAC_MASK, 0xFF);
 670}
 671
 672void setup_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