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