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