linux/drivers/isdn/hisax/hisax_isac.c
<<
>>
Prefs
   1/*
   2 * Driver for ISAC-S and ISAC-SX 
   3 * ISDN Subscriber Access Controller for Terminals
   4 *
   5 * Author       Kai Germaschewski
   6 * Copyright    2001 by Kai Germaschewski  <kai.germaschewski@gmx.de>
   7 *              2001 by Karsten Keil       <keil@isdn4linux.de>
   8 * 
   9 * based upon Karsten Keil's original isac.c driver
  10 *
  11 * This software may be used and distributed according to the terms
  12 * of the GNU General Public License, incorporated herein by reference.
  13 *
  14 * Thanks to Wizard Computersysteme GmbH, Bremervoerde and
  15 *           SoHaNet Technology GmbH, Berlin
  16 * for supporting the development of this driver
  17 */
  18
  19/* TODO:
  20 * specifically handle level vs edge triggered?
  21 */
  22
  23#include <linux/module.h>
  24#include <linux/init.h>
  25#include <linux/netdevice.h>
  26#include "hisax_isac.h"
  27
  28// debugging cruft
  29
  30#define __debug_variable debug
  31#include "hisax_debug.h"
  32
  33#ifdef CONFIG_HISAX_DEBUG
  34static int debug = 1;
  35module_param(debug, int, 0);
  36
  37static char *ISACVer[] = {
  38  "2086/2186 V1.1", 
  39  "2085 B1", 
  40  "2085 B2",
  41  "2085 V2.3"
  42};
  43#endif
  44
  45MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
  46MODULE_DESCRIPTION("ISAC/ISAC-SX driver");
  47MODULE_LICENSE("GPL");
  48
  49#define DBG_WARN      0x0001
  50#define DBG_IRQ       0x0002
  51#define DBG_L1M       0x0004
  52#define DBG_PR        0x0008
  53#define DBG_RFIFO     0x0100
  54#define DBG_RPACKET   0x0200
  55#define DBG_XFIFO     0x1000
  56#define DBG_XPACKET   0x2000
  57
  58// we need to distinguish ISAC-S and ISAC-SX
  59#define TYPE_ISAC        0x00
  60#define TYPE_ISACSX      0x01
  61
  62// registers etc.
  63#define ISAC_MASK        0x20
  64#define ISAC_ISTA        0x20
  65#define ISAC_ISTA_EXI    0x01
  66#define ISAC_ISTA_SIN    0x02
  67#define ISAC_ISTA_CISQ   0x04
  68#define ISAC_ISTA_XPR    0x10
  69#define ISAC_ISTA_RSC    0x20
  70#define ISAC_ISTA_RPF    0x40
  71#define ISAC_ISTA_RME    0x80
  72
  73#define ISAC_STAR        0x21
  74#define ISAC_CMDR        0x21
  75#define ISAC_CMDR_XRES   0x01
  76#define ISAC_CMDR_XME    0x02
  77#define ISAC_CMDR_XTF    0x08
  78#define ISAC_CMDR_RRES   0x40
  79#define ISAC_CMDR_RMC    0x80
  80
  81#define ISAC_EXIR        0x24
  82#define ISAC_EXIR_MOS    0x04
  83#define ISAC_EXIR_XDU    0x40
  84#define ISAC_EXIR_XMR    0x80
  85
  86#define ISAC_ADF2        0x39
  87#define ISAC_SPCR        0x30
  88#define ISAC_ADF1        0x38
  89
  90#define ISAC_CIR0        0x31
  91#define ISAC_CIX0        0x31
  92#define ISAC_CIR0_CIC0   0x02
  93#define ISAC_CIR0_CIC1   0x01
  94
  95#define ISAC_CIR1        0x33
  96#define ISAC_CIX1        0x33
  97#define ISAC_STCR        0x37
  98#define ISAC_MODE        0x22
  99
 100#define ISAC_RSTA        0x27
 101#define ISAC_RSTA_RDO    0x40
 102#define ISAC_RSTA_CRC    0x20
 103#define ISAC_RSTA_RAB    0x10
 104
 105#define ISAC_RBCL 0x25
 106#define ISAC_RBCH 0x2A
 107#define ISAC_TIMR 0x23
 108#define ISAC_SQXR 0x3b
 109#define ISAC_MOSR 0x3a
 110#define ISAC_MOCR 0x3a
 111#define ISAC_MOR0 0x32
 112#define ISAC_MOX0 0x32
 113#define ISAC_MOR1 0x34
 114#define ISAC_MOX1 0x34
 115
 116#define ISAC_RBCH_XAC 0x80
 117
 118#define ISAC_CMD_TIM    0x0
 119#define ISAC_CMD_RES    0x1
 120#define ISAC_CMD_SSP    0x2
 121#define ISAC_CMD_SCP    0x3
 122#define ISAC_CMD_AR8    0x8
 123#define ISAC_CMD_AR10   0x9
 124#define ISAC_CMD_ARL    0xa
 125#define ISAC_CMD_DI     0xf
 126
 127#define ISACSX_MASK       0x60
 128#define ISACSX_ISTA       0x60
 129#define ISACSX_ISTA_ICD   0x01
 130#define ISACSX_ISTA_CIC   0x10
 131
 132#define ISACSX_MASKD      0x20
 133#define ISACSX_ISTAD      0x20
 134#define ISACSX_ISTAD_XDU  0x04
 135#define ISACSX_ISTAD_XMR  0x08
 136#define ISACSX_ISTAD_XPR  0x10
 137#define ISACSX_ISTAD_RFO  0x20
 138#define ISACSX_ISTAD_RPF  0x40
 139#define ISACSX_ISTAD_RME  0x80
 140
 141#define ISACSX_CMDRD      0x21
 142#define ISACSX_CMDRD_XRES 0x01
 143#define ISACSX_CMDRD_XME  0x02
 144#define ISACSX_CMDRD_XTF  0x08
 145#define ISACSX_CMDRD_RRES 0x40
 146#define ISACSX_CMDRD_RMC  0x80
 147
 148#define ISACSX_MODED      0x22
 149
 150#define ISACSX_RBCLD      0x26
 151
 152#define ISACSX_RSTAD      0x28
 153#define ISACSX_RSTAD_RAB  0x10
 154#define ISACSX_RSTAD_CRC  0x20
 155#define ISACSX_RSTAD_RDO  0x40
 156#define ISACSX_RSTAD_VFR  0x80
 157
 158#define ISACSX_CIR0       0x2e
 159#define ISACSX_CIR0_CIC0  0x08
 160#define ISACSX_CIX0       0x2e
 161
 162#define ISACSX_TR_CONF0   0x30
 163
 164#define ISACSX_TR_CONF2   0x32
 165
 166static struct Fsm l1fsm;
 167
 168enum {
 169        ST_L1_RESET,
 170        ST_L1_F3_PDOWN,
 171        ST_L1_F3_PUP,
 172        ST_L1_F3_PEND_DEACT,
 173        ST_L1_F4,
 174        ST_L1_F5,
 175        ST_L1_F6,
 176        ST_L1_F7,
 177        ST_L1_F8,
 178};
 179
 180#define L1_STATE_COUNT (ST_L1_F8+1)
 181
 182static char *strL1State[] =
 183{
 184        "ST_L1_RESET",
 185        "ST_L1_F3_PDOWN",
 186        "ST_L1_F3_PUP",
 187        "ST_L1_F3_PEND_DEACT",
 188        "ST_L1_F4",
 189        "ST_L1_F5",
 190        "ST_L1_F6",
 191        "ST_L1_F7",
 192        "ST_L1_F8",
 193};
 194
 195enum {
 196        EV_PH_DR,           // 0000
 197        EV_PH_RES,          // 0001
 198        EV_PH_TMA,          // 0010
 199        EV_PH_SLD,          // 0011
 200        EV_PH_RSY,          // 0100
 201        EV_PH_DR6,          // 0101
 202        EV_PH_EI,           // 0110
 203        EV_PH_PU,           // 0111
 204        EV_PH_AR,           // 1000
 205        EV_PH_9,            // 1001
 206        EV_PH_ARL,          // 1010
 207        EV_PH_CVR,          // 1011
 208        EV_PH_AI8,          // 1100
 209        EV_PH_AI10,         // 1101
 210        EV_PH_AIL,          // 1110
 211        EV_PH_DC,           // 1111
 212        EV_PH_ACTIVATE_REQ,
 213        EV_PH_DEACTIVATE_REQ,
 214        EV_TIMER3,
 215};
 216
 217#define L1_EVENT_COUNT (EV_TIMER3 + 1)
 218
 219static char *strL1Event[] =
 220{
 221        "EV_PH_DR",           // 0000
 222        "EV_PH_RES",          // 0001
 223        "EV_PH_TMA",          // 0010
 224        "EV_PH_SLD",          // 0011
 225        "EV_PH_RSY",          // 0100
 226        "EV_PH_DR6",          // 0101
 227        "EV_PH_EI",           // 0110
 228        "EV_PH_PU",           // 0111
 229        "EV_PH_AR",           // 1000
 230        "EV_PH_9",            // 1001
 231        "EV_PH_ARL",          // 1010
 232        "EV_PH_CVR",          // 1011
 233        "EV_PH_AI8",          // 1100
 234        "EV_PH_AI10",         // 1101
 235        "EV_PH_AIL",          // 1110
 236        "EV_PH_DC",           // 1111
 237        "EV_PH_ACTIVATE_REQ",
 238        "EV_PH_DEACTIVATE_REQ",
 239        "EV_TIMER3",
 240};
 241
 242static inline void D_L1L2(struct isac *isac, int pr, void *arg)
 243{
 244        struct hisax_if *ifc = (struct hisax_if *) &isac->hisax_d_if;
 245
 246        DBG(DBG_PR, "pr %#x", pr);
 247        ifc->l1l2(ifc, pr, arg);
 248}
 249
 250static void ph_command(struct isac *isac, unsigned int command)
 251{
 252        DBG(DBG_L1M, "ph_command %#x", command);
 253        switch (isac->type) {
 254        case TYPE_ISAC:
 255                isac->write_isac(isac, ISAC_CIX0, (command << 2) | 3);
 256                break;
 257        case TYPE_ISACSX:
 258                isac->write_isac(isac, ISACSX_CIX0, (command << 4) | (7 << 1));
 259                break;
 260        }
 261}
 262
 263// ----------------------------------------------------------------------
 264
 265static void l1_di(struct FsmInst *fi, int event, void *arg)
 266{
 267        struct isac *isac = fi->userdata;
 268
 269        FsmChangeState(fi, ST_L1_RESET);
 270        ph_command(isac, ISAC_CMD_DI);
 271}
 272
 273static void l1_di_deact_ind(struct FsmInst *fi, int event, void *arg)
 274{
 275        struct isac *isac = fi->userdata;
 276
 277        FsmChangeState(fi, ST_L1_RESET);
 278        D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
 279        ph_command(isac, ISAC_CMD_DI);
 280}
 281
 282static void l1_go_f3pdown(struct FsmInst *fi, int event, void *arg)
 283{
 284        FsmChangeState(fi, ST_L1_F3_PDOWN);
 285}
 286
 287static void l1_go_f3pend_deact_ind(struct FsmInst *fi, int event, void *arg)
 288{
 289        struct isac *isac = fi->userdata;
 290
 291        FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
 292        D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
 293        ph_command(isac, ISAC_CMD_DI);
 294}
 295
 296static void l1_go_f3pend(struct FsmInst *fi, int event, void *arg)
 297{
 298        struct isac *isac = fi->userdata;
 299
 300        FsmChangeState(fi, ST_L1_F3_PEND_DEACT);
 301        ph_command(isac, ISAC_CMD_DI);
 302}
 303
 304static void l1_go_f4(struct FsmInst *fi, int event, void *arg)
 305{
 306        FsmChangeState(fi, ST_L1_F4);
 307}
 308
 309static void l1_go_f5(struct FsmInst *fi, int event, void *arg)
 310{
 311        FsmChangeState(fi, ST_L1_F5);
 312}
 313
 314static void l1_go_f6(struct FsmInst *fi, int event, void *arg)
 315{
 316        FsmChangeState(fi, ST_L1_F6);
 317}
 318
 319static void l1_go_f6_deact_ind(struct FsmInst *fi, int event, void *arg)
 320{
 321        struct isac *isac = fi->userdata;
 322
 323        FsmChangeState(fi, ST_L1_F6);
 324        D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
 325}
 326
 327static void l1_go_f7_act_ind(struct FsmInst *fi, int event, void *arg)
 328{
 329        struct isac *isac = fi->userdata;
 330
 331        FsmDelTimer(&isac->timer, 0);
 332        FsmChangeState(fi, ST_L1_F7);
 333        ph_command(isac, ISAC_CMD_AR8);
 334        D_L1L2(isac, PH_ACTIVATE | INDICATION, NULL);
 335}
 336
 337static void l1_go_f8(struct FsmInst *fi, int event, void *arg)
 338{
 339        FsmChangeState(fi, ST_L1_F8);
 340}
 341
 342static void l1_go_f8_deact_ind(struct FsmInst *fi, int event, void *arg)
 343{
 344        struct isac *isac = fi->userdata;
 345
 346        FsmChangeState(fi, ST_L1_F8);
 347        D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
 348}
 349
 350static void l1_ar8(struct FsmInst *fi, int event, void *arg)
 351{
 352        struct isac *isac = fi->userdata;
 353
 354        FsmRestartTimer(&isac->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
 355        ph_command(isac, ISAC_CMD_AR8);
 356}
 357
 358static void l1_timer3(struct FsmInst *fi, int event, void *arg)
 359{
 360        struct isac *isac = fi->userdata;
 361
 362        ph_command(isac, ISAC_CMD_DI);
 363        D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL);
 364}
 365
 366// state machines according to data sheet PSB 2186 / 3186
 367
 368static struct FsmNode L1FnList[] __initdata =
 369{
 370        {ST_L1_RESET,         EV_PH_RES,            l1_di},
 371        {ST_L1_RESET,         EV_PH_EI,             l1_di},
 372        {ST_L1_RESET,         EV_PH_DC,             l1_go_f3pdown},
 373        {ST_L1_RESET,         EV_PH_AR,             l1_go_f6},
 374        {ST_L1_RESET,         EV_PH_AI8,            l1_go_f7_act_ind},
 375
 376        {ST_L1_F3_PDOWN,      EV_PH_RES,            l1_di},
 377        {ST_L1_F3_PDOWN,      EV_PH_EI,             l1_di},
 378        {ST_L1_F3_PDOWN,      EV_PH_AR,             l1_go_f6},
 379        {ST_L1_F3_PDOWN,      EV_PH_RSY,            l1_go_f5},
 380        {ST_L1_F3_PDOWN,      EV_PH_PU,             l1_go_f4},
 381        {ST_L1_F3_PDOWN,      EV_PH_AI8,            l1_go_f7_act_ind},
 382        {ST_L1_F3_PDOWN,      EV_PH_ACTIVATE_REQ,   l1_ar8},
 383        {ST_L1_F3_PDOWN,      EV_TIMER3,            l1_timer3},
 384        
 385        {ST_L1_F3_PEND_DEACT, EV_PH_RES,            l1_di},
 386        {ST_L1_F3_PEND_DEACT, EV_PH_EI,             l1_di},
 387        {ST_L1_F3_PEND_DEACT, EV_PH_DC,             l1_go_f3pdown},
 388        {ST_L1_F3_PEND_DEACT, EV_PH_RSY,            l1_go_f5},
 389        {ST_L1_F3_PEND_DEACT, EV_PH_AR,             l1_go_f6},
 390        {ST_L1_F3_PEND_DEACT, EV_PH_AI8,            l1_go_f7_act_ind},
 391
 392        {ST_L1_F4,            EV_PH_RES,            l1_di},
 393        {ST_L1_F4,            EV_PH_EI,             l1_di},
 394        {ST_L1_F4,            EV_PH_RSY,            l1_go_f5},
 395        {ST_L1_F4,            EV_PH_AI8,            l1_go_f7_act_ind},
 396        {ST_L1_F4,            EV_TIMER3,            l1_timer3},
 397        {ST_L1_F4,            EV_PH_DC,             l1_go_f3pdown},
 398
 399        {ST_L1_F5,            EV_PH_RES,            l1_di},
 400        {ST_L1_F5,            EV_PH_EI,             l1_di},
 401        {ST_L1_F5,            EV_PH_AR,             l1_go_f6},
 402        {ST_L1_F5,            EV_PH_AI8,            l1_go_f7_act_ind},
 403        {ST_L1_F5,            EV_TIMER3,            l1_timer3},
 404        {ST_L1_F5,            EV_PH_DR,             l1_go_f3pend},
 405        {ST_L1_F5,            EV_PH_DC,             l1_go_f3pdown},
 406
 407        {ST_L1_F6,            EV_PH_RES,            l1_di},
 408        {ST_L1_F6,            EV_PH_EI,             l1_di},
 409        {ST_L1_F6,            EV_PH_RSY,            l1_go_f8},
 410        {ST_L1_F6,            EV_PH_AI8,            l1_go_f7_act_ind},
 411        {ST_L1_F6,            EV_PH_DR6,            l1_go_f3pend},
 412        {ST_L1_F6,            EV_TIMER3,            l1_timer3},
 413        {ST_L1_F6,            EV_PH_DC,             l1_go_f3pdown},
 414
 415        {ST_L1_F7,            EV_PH_RES,            l1_di_deact_ind},
 416        {ST_L1_F7,            EV_PH_EI,             l1_di_deact_ind},
 417        {ST_L1_F7,            EV_PH_AR,             l1_go_f6_deact_ind},
 418        {ST_L1_F7,            EV_PH_RSY,            l1_go_f8_deact_ind},
 419        {ST_L1_F7,            EV_PH_DR,             l1_go_f3pend_deact_ind},
 420
 421        {ST_L1_F8,            EV_PH_RES,            l1_di},
 422        {ST_L1_F8,            EV_PH_EI,             l1_di},
 423        {ST_L1_F8,            EV_PH_AR,             l1_go_f6},
 424        {ST_L1_F8,            EV_PH_DR,             l1_go_f3pend},
 425        {ST_L1_F8,            EV_PH_AI8,            l1_go_f7_act_ind},
 426        {ST_L1_F8,            EV_TIMER3,            l1_timer3},
 427        {ST_L1_F8,            EV_PH_DC,             l1_go_f3pdown},
 428};
 429
 430static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
 431{
 432        va_list args;
 433        char buf[256];
 434        
 435        va_start(args, fmt);
 436        vsnprintf(buf, sizeof(buf), fmt, args);
 437        DBG(DBG_L1M, "%s", buf);
 438        va_end(args);
 439}
 440
 441static void isac_version(struct isac *cs)
 442{
 443        int val;
 444
 445        val = cs->read_isac(cs, ISAC_RBCH);
 446        DBG(1, "ISAC version (%x): %s", val, ISACVer[(val >> 5) & 3]);
 447}
 448
 449static void isac_empty_fifo(struct isac *isac, int count)
 450{
 451        // this also works for isacsx, since
 452        // CMDR(D) register works the same
 453        u_char *ptr;
 454
 455        DBG(DBG_IRQ, "count %d", count);
 456
 457        if ((isac->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
 458                DBG(DBG_WARN, "overrun %d", isac->rcvidx + count);
 459                isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
 460                isac->rcvidx = 0;
 461                return;
 462        }
 463        ptr = isac->rcvbuf + isac->rcvidx;
 464        isac->rcvidx += count;
 465        isac->read_isac_fifo(isac, ptr, count);
 466        isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
 467        DBG_PACKET(DBG_RFIFO, ptr, count);
 468}
 469
 470static void isac_fill_fifo(struct isac *isac)
 471{
 472        // this also works for isacsx, since
 473        // CMDR(D) register works the same
 474
 475        int count;
 476        unsigned char cmd;
 477        u_char *ptr;
 478
 479        BUG_ON(!isac->tx_skb);
 480
 481        count = isac->tx_skb->len;
 482        BUG_ON(count <= 0);
 483
 484        DBG(DBG_IRQ, "count %d", count);
 485
 486        if (count > 0x20) {
 487                count = 0x20;
 488                cmd = ISAC_CMDR_XTF;
 489        } else {
 490                cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME;
 491        }
 492
 493        ptr = isac->tx_skb->data;
 494        skb_pull(isac->tx_skb, count);
 495        isac->tx_cnt += count;
 496        DBG_PACKET(DBG_XFIFO, ptr, count);
 497        isac->write_isac_fifo(isac, ptr, count);
 498        isac->write_isac(isac, ISAC_CMDR, cmd);
 499}
 500
 501static void isac_retransmit(struct isac *isac)
 502{
 503        if (!isac->tx_skb) {
 504                DBG(DBG_WARN, "no skb");
 505                return;
 506        }
 507        skb_push(isac->tx_skb, isac->tx_cnt);
 508        isac->tx_cnt = 0;
 509}
 510
 511
 512static inline void isac_cisq_interrupt(struct isac *isac)
 513{
 514        unsigned char val;
 515
 516        val = isac->read_isac(isac, ISAC_CIR0);
 517        DBG(DBG_IRQ, "CIR0 %#x", val);
 518        if (val & ISAC_CIR0_CIC0) {
 519                DBG(DBG_IRQ, "CODR0 %#x", (val >> 2) & 0xf);
 520                FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
 521        }
 522        if (val & ISAC_CIR0_CIC1) {
 523                val = isac->read_isac(isac, ISAC_CIR1);
 524                DBG(DBG_WARN, "ISAC CIR1 %#x", val );
 525        }
 526}
 527
 528static inline void isac_rme_interrupt(struct isac *isac)
 529{
 530        unsigned char val;
 531        int count;
 532        struct sk_buff *skb;
 533        
 534        val = isac->read_isac(isac, ISAC_RSTA);
 535        if ((val & (ISAC_RSTA_RDO | ISAC_RSTA_CRC | ISAC_RSTA_RAB) )
 536             != ISAC_RSTA_CRC) {
 537                DBG(DBG_WARN, "RSTA %#x, dropped", val);
 538                isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC);
 539                goto out;
 540        }
 541
 542        count = isac->read_isac(isac, ISAC_RBCL) & 0x1f;
 543        DBG(DBG_IRQ, "RBCL %#x", count);
 544        if (count == 0)
 545                count = 0x20;
 546
 547        isac_empty_fifo(isac, count);
 548        count = isac->rcvidx;
 549        if (count < 1) {
 550                DBG(DBG_WARN, "count %d < 1", count);
 551                goto out;
 552        }
 553
 554        skb = alloc_skb(count, GFP_ATOMIC);
 555        if (!skb) {
 556                DBG(DBG_WARN, "no memory, dropping\n");
 557                goto out;
 558        }
 559        memcpy(skb_put(skb, count), isac->rcvbuf, count);
 560        DBG_SKB(DBG_RPACKET, skb);
 561        D_L1L2(isac, PH_DATA | INDICATION, skb);
 562 out:
 563        isac->rcvidx = 0;
 564}
 565
 566static inline void isac_xpr_interrupt(struct isac *isac)
 567{
 568        if (!isac->tx_skb)
 569                return;
 570
 571        if (isac->tx_skb->len > 0) {
 572                isac_fill_fifo(isac);
 573                return;
 574        }
 575        dev_kfree_skb_irq(isac->tx_skb);
 576        isac->tx_cnt = 0;
 577        isac->tx_skb = NULL;
 578        D_L1L2(isac, PH_DATA | CONFIRM, NULL);
 579}
 580
 581static inline void isac_exi_interrupt(struct isac *isac)
 582{
 583        unsigned char val;
 584
 585        val = isac->read_isac(isac, ISAC_EXIR);
 586        DBG(2, "EXIR %#x", val);
 587
 588        if (val & ISAC_EXIR_XMR) {
 589                DBG(DBG_WARN, "ISAC XMR");
 590                isac_retransmit(isac);
 591        }
 592        if (val & ISAC_EXIR_XDU) {
 593                DBG(DBG_WARN, "ISAC XDU");
 594                isac_retransmit(isac);
 595        }
 596        if (val & ISAC_EXIR_MOS) {  /* MOS */
 597                DBG(DBG_WARN, "MOS");
 598                val = isac->read_isac(isac, ISAC_MOSR);
 599                DBG(2, "ISAC MOSR %#x", val);
 600        }
 601}
 602
 603void isac_irq(struct isac *isac)
 604{
 605        unsigned char val;
 606
 607        val = isac->read_isac(isac, ISAC_ISTA);
 608        DBG(DBG_IRQ, "ISTA %#x", val);
 609
 610        if (val & ISAC_ISTA_EXI) {
 611                DBG(DBG_IRQ, "EXI");
 612                isac_exi_interrupt(isac);
 613        }
 614        if (val & ISAC_ISTA_XPR) {
 615                DBG(DBG_IRQ, "XPR");
 616                isac_xpr_interrupt(isac);
 617        }
 618        if (val & ISAC_ISTA_RME) {
 619                DBG(DBG_IRQ, "RME");
 620                isac_rme_interrupt(isac);
 621        }
 622        if (val & ISAC_ISTA_RPF) {
 623                DBG(DBG_IRQ, "RPF");
 624                isac_empty_fifo(isac, 0x20);
 625        }
 626        if (val & ISAC_ISTA_CISQ) {
 627                DBG(DBG_IRQ, "CISQ");
 628                isac_cisq_interrupt(isac);
 629        }
 630        if (val & ISAC_ISTA_RSC) {
 631                DBG(DBG_WARN, "RSC");
 632        }
 633        if (val & ISAC_ISTA_SIN) {
 634                DBG(DBG_WARN, "SIN");
 635        }
 636        isac->write_isac(isac, ISAC_MASK, 0xff);
 637        isac->write_isac(isac, ISAC_MASK, 0x00);
 638}
 639
 640// ======================================================================
 641
 642static inline void isacsx_cic_interrupt(struct isac *isac)
 643{
 644        unsigned char val;
 645
 646        val = isac->read_isac(isac, ISACSX_CIR0);
 647        DBG(DBG_IRQ, "CIR0 %#x", val);
 648        if (val & ISACSX_CIR0_CIC0) {
 649                DBG(DBG_IRQ, "CODR0 %#x", val >> 4);
 650                FsmEvent(&isac->l1m, val >> 4, NULL);
 651        }
 652}
 653
 654static inline void isacsx_rme_interrupt(struct isac *isac)
 655{
 656        int count;
 657        struct sk_buff *skb;
 658        unsigned char val;
 659
 660        val = isac->read_isac(isac, ISACSX_RSTAD);
 661        if ((val & (ISACSX_RSTAD_VFR | 
 662                    ISACSX_RSTAD_RDO | 
 663                    ISACSX_RSTAD_CRC | 
 664                    ISACSX_RSTAD_RAB)) 
 665            != (ISACSX_RSTAD_VFR | ISACSX_RSTAD_CRC)) {
 666                DBG(DBG_WARN, "RSTAD %#x, dropped", val);
 667                isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
 668                goto out;
 669        }
 670
 671        count = isac->read_isac(isac, ISACSX_RBCLD) & 0x1f;
 672        DBG(DBG_IRQ, "RBCLD %#x", count);
 673        if (count == 0)
 674                count = 0x20;
 675
 676        isac_empty_fifo(isac, count);
 677        // strip trailing status byte
 678        count = isac->rcvidx - 1;
 679        if (count < 1) {
 680                DBG(DBG_WARN, "count %d < 1", count);
 681                goto out;
 682        }
 683
 684        skb = dev_alloc_skb(count);
 685        if (!skb) {
 686                DBG(DBG_WARN, "no memory, dropping");
 687                goto out;
 688        }
 689        memcpy(skb_put(skb, count), isac->rcvbuf, count);
 690        DBG_SKB(DBG_RPACKET, skb);
 691        D_L1L2(isac, PH_DATA | INDICATION, skb);
 692 out:
 693        isac->rcvidx = 0;
 694}
 695
 696static inline void isacsx_xpr_interrupt(struct isac *isac)
 697{
 698        if (!isac->tx_skb)
 699                return;
 700
 701        if (isac->tx_skb->len > 0) {
 702                isac_fill_fifo(isac);
 703                return;
 704        }
 705        dev_kfree_skb_irq(isac->tx_skb);
 706        isac->tx_skb = NULL;
 707        isac->tx_cnt = 0;
 708        D_L1L2(isac, PH_DATA | CONFIRM, NULL);
 709}
 710
 711static inline void isacsx_icd_interrupt(struct isac *isac)
 712{
 713        unsigned char val;
 714
 715        val = isac->read_isac(isac, ISACSX_ISTAD);
 716        DBG(DBG_IRQ, "ISTAD %#x", val);
 717        if (val & ISACSX_ISTAD_XDU) {
 718                DBG(DBG_WARN, "ISTAD XDU");
 719                isac_retransmit(isac);
 720        }
 721        if (val & ISACSX_ISTAD_XMR) {
 722                DBG(DBG_WARN, "ISTAD XMR");
 723                isac_retransmit(isac);
 724        }
 725        if (val & ISACSX_ISTAD_XPR) {
 726                DBG(DBG_IRQ, "ISTAD XPR");
 727                isacsx_xpr_interrupt(isac);
 728        }
 729        if (val & ISACSX_ISTAD_RFO) {
 730                DBG(DBG_WARN, "ISTAD RFO");
 731                isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
 732        }
 733        if (val & ISACSX_ISTAD_RME) {
 734                DBG(DBG_IRQ, "ISTAD RME");
 735                isacsx_rme_interrupt(isac);
 736        }
 737        if (val & ISACSX_ISTAD_RPF) {
 738                DBG(DBG_IRQ, "ISTAD RPF");
 739                isac_empty_fifo(isac, 0x20);
 740        }
 741}
 742
 743void isacsx_irq(struct isac *isac)
 744{
 745        unsigned char val;
 746
 747        val = isac->read_isac(isac, ISACSX_ISTA);
 748        DBG(DBG_IRQ, "ISTA %#x", val);
 749
 750        if (val & ISACSX_ISTA_ICD)
 751                isacsx_icd_interrupt(isac);
 752        if (val & ISACSX_ISTA_CIC)
 753                isacsx_cic_interrupt(isac);
 754}
 755
 756void isac_init(struct isac *isac)
 757{
 758        isac->tx_skb = NULL;
 759        isac->l1m.fsm = &l1fsm;
 760        isac->l1m.state = ST_L1_RESET;
 761#ifdef CONFIG_HISAX_DEBUG
 762        isac->l1m.debug = 1;
 763#else
 764        isac->l1m.debug = 0;
 765#endif
 766        isac->l1m.userdata = isac;
 767        isac->l1m.printdebug = l1m_debug;
 768        FsmInitTimer(&isac->l1m, &isac->timer);
 769}
 770
 771void isac_setup(struct isac *isac)
 772{
 773        int val, eval;
 774
 775        isac->type = TYPE_ISAC;
 776        isac_version(isac);
 777
 778        ph_command(isac, ISAC_CMD_RES);
 779
 780        isac->write_isac(isac, ISAC_MASK, 0xff);
 781        isac->mocr = 0xaa;
 782        if (test_bit(ISAC_IOM1, &isac->flags)) {
 783                /* IOM 1 Mode */
 784                isac->write_isac(isac, ISAC_ADF2, 0x0);
 785                isac->write_isac(isac, ISAC_SPCR, 0xa);
 786                isac->write_isac(isac, ISAC_ADF1, 0x2);
 787                isac->write_isac(isac, ISAC_STCR, 0x70);
 788                isac->write_isac(isac, ISAC_MODE, 0xc9);
 789        } else {
 790                /* IOM 2 Mode */
 791                if (!isac->adf2)
 792                        isac->adf2 = 0x80;
 793                isac->write_isac(isac, ISAC_ADF2, isac->adf2);
 794                isac->write_isac(isac, ISAC_SQXR, 0x2f);
 795                isac->write_isac(isac, ISAC_SPCR, 0x00);
 796                isac->write_isac(isac, ISAC_STCR, 0x70);
 797                isac->write_isac(isac, ISAC_MODE, 0xc9);
 798                isac->write_isac(isac, ISAC_TIMR, 0x00);
 799                isac->write_isac(isac, ISAC_ADF1, 0x00);
 800        }
 801        val = isac->read_isac(isac, ISAC_STAR);
 802        DBG(2, "ISAC STAR %x", val);
 803        val = isac->read_isac(isac, ISAC_MODE);
 804        DBG(2, "ISAC MODE %x", val);
 805        val = isac->read_isac(isac, ISAC_ADF2);
 806        DBG(2, "ISAC ADF2 %x", val);
 807        val = isac->read_isac(isac, ISAC_ISTA);
 808        DBG(2, "ISAC ISTA %x", val);
 809        if (val & 0x01) {
 810                eval = isac->read_isac(isac, ISAC_EXIR);
 811                DBG(2, "ISAC EXIR %x", eval);
 812        }
 813        val = isac->read_isac(isac, ISAC_CIR0);
 814        DBG(2, "ISAC CIR0 %x", val);
 815        FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
 816
 817        isac->write_isac(isac, ISAC_MASK, 0x0);
 818        // RESET Receiver and Transmitter
 819        isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_XRES | ISAC_CMDR_RRES);
 820}
 821
 822void isacsx_setup(struct isac *isac)
 823{
 824        isac->type = TYPE_ISACSX;
 825        // clear LDD
 826        isac->write_isac(isac, ISACSX_TR_CONF0, 0x00);
 827        // enable transmitter
 828        isac->write_isac(isac, ISACSX_TR_CONF2, 0x00);
 829        // transparent mode 0, RAC, stop/go
 830        isac->write_isac(isac, ISACSX_MODED,    0xc9);
 831        // all HDLC IRQ unmasked
 832        isac->write_isac(isac, ISACSX_MASKD,    0x03);
 833        // unmask ICD, CID IRQs
 834        isac->write_isac(isac, ISACSX_MASK,            
 835                         ~(ISACSX_ISTA_ICD | ISACSX_ISTA_CIC));
 836}
 837
 838void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg)
 839{
 840        struct isac *isac = hisax_d_if->priv;
 841        struct sk_buff *skb = arg;
 842
 843        DBG(DBG_PR, "pr %#x", pr);
 844
 845        switch (pr) {
 846        case PH_ACTIVATE | REQUEST:
 847                FsmEvent(&isac->l1m, EV_PH_ACTIVATE_REQ, NULL);
 848                break;
 849        case PH_DEACTIVATE | REQUEST:
 850                FsmEvent(&isac->l1m, EV_PH_DEACTIVATE_REQ, NULL);
 851                break;
 852        case PH_DATA | REQUEST:
 853                DBG(DBG_PR, "PH_DATA REQUEST len %d", skb->len);
 854                DBG_SKB(DBG_XPACKET, skb);
 855                if (isac->l1m.state != ST_L1_F7) {
 856                        DBG(1, "L1 wrong state %d\n", isac->l1m.state);
 857                        dev_kfree_skb(skb);
 858                        break;
 859                }
 860                BUG_ON(isac->tx_skb);
 861
 862                isac->tx_skb = skb;
 863                isac_fill_fifo(isac);
 864                break;
 865        }
 866}
 867
 868static int __init hisax_isac_init(void)
 869{
 870        printk(KERN_INFO "hisax_isac: ISAC-S/ISAC-SX ISDN driver v0.1.0\n");
 871
 872        l1fsm.state_count = L1_STATE_COUNT;
 873        l1fsm.event_count = L1_EVENT_COUNT;
 874        l1fsm.strState = strL1State;
 875        l1fsm.strEvent = strL1Event;
 876        return FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList));
 877}
 878
 879static void __exit hisax_isac_exit(void)
 880{
 881        FsmFree(&l1fsm);
 882}
 883
 884EXPORT_SYMBOL(isac_init);
 885EXPORT_SYMBOL(isac_d_l2l1);
 886
 887EXPORT_SYMBOL(isacsx_setup);
 888EXPORT_SYMBOL(isacsx_irq);
 889
 890EXPORT_SYMBOL(isac_setup);
 891EXPORT_SYMBOL(isac_irq);
 892
 893module_init(hisax_isac_init);
 894module_exit(hisax_isac_exit);
 895