linux/drivers/isdn/hisax/amd7930_fn.c
<<
>>
Prefs
   1/* gerdes_amd7930.c,v 0.99 2001/10/02
   2 *
   3 * gerdes_amd7930.c     Amd 79C30A and 79C32A specific routines
   4 *                      (based on HiSax driver by Karsten Keil)
   5 *
   6 * Author               Christoph Ersfeld <info@formula-n.de>
   7 *                      Formula-n Europe AG (www.formula-n.com)
   8 *                      previously Gerdes AG
   9 *
  10 *
  11 *                      This file is (c) under GNU PUBLIC LICENSE
  12 *
  13 *
  14 * Notes:
  15 * Version 0.99 is the first release of this driver and there are
  16 * certainly a few bugs.
  17 *
  18 * Please don't report any malfunction to me without sending
  19 * (compressed) debug-logs.
  20 * It would be nearly impossible to retrace it.
  21 *
  22 * Log D-channel-processing as follows:
  23 *
  24 * 1. Load hisax with card-specific parameters, this example ist for
  25 *    Formula-n enter:now ISDN PCI and compatible
  26 *    (f.e. Gerdes Power ISDN PCI)
  27 *
  28 *    modprobe hisax type=41 protocol=2 id=gerdes
  29 *
  30 *    if you chose an other value for id, you need to modify the
  31 *    code below, too.
  32 *
  33 * 2. set debug-level
  34 *
  35 *    hisaxctrl gerdes 1 0x3ff
  36 *    hisaxctrl gerdes 11 0x4f
  37 *    cat /dev/isdnctrl >> ~/log &
  38 *
  39 * Please take also a look into /var/log/messages if there is
  40 * anything importand concerning HISAX.
  41 *
  42 *
  43 * Credits:
  44 * Programming the driver for Formula-n enter:now ISDN PCI and
  45 * necessary this driver for the used Amd 7930 D-channel-controller
  46 * was spnsored by Formula-n Europe AG.
  47 * Thanks to Karsten Keil and Petr Novak, who gave me support in
  48 * Hisax-specific questions.
  49 * I want so say special thanks to Carl-Friedrich Braun, who had to
  50 * answer a lot of questions about generally ISDN and about handling
  51 * of the Amd-Chip.
  52 *
  53 */
  54
  55
  56#include "hisax.h"
  57#include "isdnl1.h"
  58#include "isac.h"
  59#include "amd7930_fn.h"
  60#include <linux/interrupt.h>
  61#include <linux/init.h>
  62#include <linux/gfp.h>
  63
  64static void Amd7930_new_ph(struct IsdnCardState *cs);
  65
  66static WORD initAMD[] = {
  67        0x0100,
  68
  69        0x00A5, 3, 0x01, 0x40, 0x58,                            // LPR, LMR1, LMR2
  70        0x0086, 1, 0x0B,                                        // DMR1 (D-Buffer TH-Interrupts on)
  71        0x0087, 1, 0xFF,                                        // DMR2
  72        0x0092, 1, 0x03,                                        // EFCR (extended mode d-channel-fifo on)
  73        0x0090, 4, 0xFE, 0xFF, 0x02, 0x0F,                      // FRAR4, SRAR4, DMR3, DMR4 (address recognition )
  74        0x0084, 2, 0x80, 0x00,                                  // DRLR
  75        0x00C0, 1, 0x47,                                        // PPCR1
  76        0x00C8, 1, 0x01,                                        // PPCR2
  77
  78        0x0102,
  79        0x0107,
  80        0x01A1, 1,
  81        0x0121, 1,
  82        0x0189, 2,
  83
  84        0x0045, 4, 0x61, 0x72, 0x00, 0x00,                      // MCR1, MCR2, MCR3, MCR4
  85        0x0063, 2, 0x08, 0x08,                                  // GX
  86        0x0064, 2, 0x08, 0x08,                                  // GR
  87        0x0065, 2, 0x99, 0x00,                                  // GER
  88        0x0066, 2, 0x7C, 0x8B,                                  // STG
  89        0x0067, 2, 0x00, 0x00,                                  // FTGR1, FTGR2
  90        0x0068, 2, 0x20, 0x20,                                  // ATGR1, ATGR2
  91        0x0069, 1, 0x4F,                                        // MMR1
  92        0x006A, 1, 0x00,                                        // MMR2
  93        0x006C, 1, 0x40,                                        // MMR3
  94        0x0021, 1, 0x02,                                        // INIT
  95        0x00A3, 1, 0x40,                                        // LMR1
  96
  97        0xFFFF
  98};
  99
 100
 101static void /* macro wWordAMD */
 102WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val)
 103{
 104        wByteAMD(cs, 0x00, reg);
 105        wByteAMD(cs, 0x01, LOBYTE(val));
 106        wByteAMD(cs, 0x01, HIBYTE(val));
 107}
 108
 109static WORD /* macro rWordAMD */
 110ReadWordAmd7930(struct IsdnCardState *cs, BYTE reg)
 111{
 112        WORD res;
 113        /* direct access register */
 114        if (reg < 8) {
 115                res = rByteAMD(cs, reg);
 116                res += 256 * rByteAMD(cs, reg);
 117        }
 118        /* indirect access register */
 119        else {
 120                wByteAMD(cs, 0x00, reg);
 121                res = rByteAMD(cs, 0x01);
 122                res += 256 * rByteAMD(cs, 0x01);
 123        }
 124        return (res);
 125}
 126
 127
 128static void
 129Amd7930_ph_command(struct IsdnCardState *cs, u_char command, char *s)
 130{
 131        if (cs->debug & L1_DEB_ISAC)
 132                debugl1(cs, "AMD7930: %s: ph_command 0x%02X", s, command);
 133
 134        cs->dc.amd7930.lmr1 = command;
 135        wByteAMD(cs, 0xA3, command);
 136}
 137
 138
 139
 140static BYTE i430States[] = {
 141// to   reset  F3    F4    F5    F6    F7    F8    AR     from
 142        0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00,   // init
 143        0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00,   // reset
 144        0x01, 0x02, 0x00, 0x00, 0x00, 0x09, 0x05, 0x04,   // F3
 145        0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,   // F4
 146        0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,   // F5
 147        0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x05, 0x00,   // F6
 148        0x11, 0x13, 0x00, 0x00, 0x1B, 0x00, 0x15, 0x00,   // F7
 149        0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,   // F8
 150        0x01, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0A};  // AR
 151
 152
 153/*                    Row     init    -   reset  F3    F4    F5    F6    F7    F8    AR */
 154static BYTE stateHelper[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
 155
 156
 157
 158
 159static void
 160Amd7930_get_state(struct IsdnCardState *cs) {
 161        BYTE lsr = rByteAMD(cs, 0xA1);
 162        cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
 163        Amd7930_new_ph(cs);
 164}
 165
 166
 167
 168static void
 169Amd7930_new_ph(struct IsdnCardState *cs)
 170{
 171        u_char index = stateHelper[cs->dc.amd7930.old_state] * 8 + stateHelper[cs->dc.amd7930.ph_state] - 1;
 172        u_char message = i430States[index];
 173
 174        if (cs->debug & L1_DEB_ISAC)
 175                debugl1(cs, "AMD7930: new_ph %d, old_ph %d, message %d, index %d",
 176                        cs->dc.amd7930.ph_state, cs->dc.amd7930.old_state, message & 0x0f, index);
 177
 178        cs->dc.amd7930.old_state = cs->dc.amd7930.ph_state;
 179
 180        /* abort transmit if nessesary */
 181        if ((message & 0xf0) && (cs->tx_skb)) {
 182                wByteAMD(cs, 0x21, 0xC2);
 183                wByteAMD(cs, 0x21, 0x02);
 184        }
 185
 186        switch (message & 0x0f) {
 187
 188        case (1):
 189                l1_msg(cs, HW_RESET | INDICATION, NULL);
 190                Amd7930_get_state(cs);
 191                break;
 192        case (2): /* init, Card starts in F3 */
 193                l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
 194                break;
 195        case (3):
 196                l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
 197                break;
 198        case (4):
 199                l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
 200                Amd7930_ph_command(cs, 0x50, "HW_ENABLE REQUEST");
 201                break;
 202        case (5):
 203                l1_msg(cs, HW_RSYNC | INDICATION, NULL);
 204                break;
 205        case (6):
 206                l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
 207                break;
 208        case (7): /* init, Card starts in F7 */
 209                l1_msg(cs, HW_RSYNC | INDICATION, NULL);
 210                l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
 211                break;
 212        case (8):
 213                l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
 214                /* fall through */
 215        case (9):
 216                Amd7930_ph_command(cs, 0x40, "HW_ENABLE REQ cleared if set");
 217                l1_msg(cs, HW_RSYNC | INDICATION, NULL);
 218                l1_msg(cs, HW_INFO2 | INDICATION, NULL);
 219                l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
 220                break;
 221        case (10):
 222                Amd7930_ph_command(cs, 0x40, "T3 expired, HW_ENABLE REQ cleared");
 223                cs->dc.amd7930.old_state = 3;
 224                break;
 225        case (11):
 226                l1_msg(cs, HW_INFO2 | INDICATION, NULL);
 227                break;
 228        default:
 229                break;
 230        }
 231}
 232
 233
 234
 235static void
 236Amd7930_bh(struct work_struct *work)
 237{
 238        struct IsdnCardState *cs =
 239                container_of(work, struct IsdnCardState, tqueue);
 240        struct PStack *stptr;
 241
 242        if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
 243                if (cs->debug)
 244                        debugl1(cs, "Amd7930: bh, D-Channel Busy cleared");
 245                stptr = cs->stlist;
 246                while (stptr != NULL) {
 247                        stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
 248                        stptr = stptr->next;
 249                }
 250        }
 251        if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
 252                if (cs->debug & L1_DEB_ISAC)
 253                        debugl1(cs, "AMD7930: bh, D_L1STATECHANGE");
 254                Amd7930_new_ph(cs);
 255        }
 256
 257        if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) {
 258                if (cs->debug & L1_DEB_ISAC)
 259                        debugl1(cs, "AMD7930: bh, D_RCVBUFREADY");
 260                DChannel_proc_rcv(cs);
 261        }
 262
 263        if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) {
 264                if (cs->debug & L1_DEB_ISAC)
 265                        debugl1(cs, "AMD7930: bh, D_XMTBUFREADY");
 266                DChannel_proc_xmt(cs);
 267        }
 268}
 269
 270static void
 271Amd7930_empty_Dfifo(struct IsdnCardState *cs, int flag)
 272{
 273
 274        BYTE stat, der;
 275        BYTE *ptr;
 276        struct sk_buff *skb;
 277
 278
 279        if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
 280                debugl1(cs, "Amd7930: empty_Dfifo");
 281
 282
 283        ptr = cs->rcvbuf + cs->rcvidx;
 284
 285        /* AMD interrupts off */
 286        AmdIrqOff(cs);
 287
 288        /* read D-Channel-Fifo*/
 289        stat = rByteAMD(cs, 0x07); // DSR2
 290
 291        /* while Data in Fifo ... */
 292        while ((stat & 2) && ((ptr-cs->rcvbuf) < MAX_DFRAME_LEN_L1)) {
 293                *ptr = rByteAMD(cs, 0x04); // DCRB
 294                ptr++;
 295                stat = rByteAMD(cs, 0x07); // DSR2
 296                cs->rcvidx = ptr - cs->rcvbuf;
 297
 298                /* Paket ready? */
 299                if (stat & 1) {
 300
 301                        der = rWordAMD(cs, 0x03);
 302
 303                        /* no errors, packet ok */
 304                        if (!der && !flag) {
 305                                rWordAMD(cs, 0x89); // clear DRCR
 306
 307                                if ((cs->rcvidx) > 0) {
 308                                        if (!(skb = alloc_skb(cs->rcvidx, GFP_ATOMIC)))
 309                                                printk(KERN_WARNING "HiSax: Amd7930: empty_Dfifo, D receive out of memory!\n");
 310                                        else {
 311                                                /* Debugging */
 312                                                if (cs->debug & L1_DEB_ISAC_FIFO) {
 313                                                        char *t = cs->dlog;
 314
 315                                                        t += sprintf(t, "Amd7930: empty_Dfifo cnt: %d |", cs->rcvidx);
 316                                                        QuickHex(t, cs->rcvbuf, cs->rcvidx);
 317                                                        debugl1(cs, cs->dlog);
 318                                                }
 319                                                /* moves received data in sk-buffer */
 320                                                memcpy(skb_put(skb, cs->rcvidx), cs->rcvbuf, cs->rcvidx);
 321                                                skb_queue_tail(&cs->rq, skb);
 322                                        }
 323                                }
 324
 325                        }
 326                        /* throw damaged packets away, reset receive-buffer, indicate RX */
 327                        ptr = cs->rcvbuf;
 328                        cs->rcvidx = 0;
 329                        schedule_event(cs, D_RCVBUFREADY);
 330                }
 331        }
 332        /* Packet to long, overflow */
 333        if (cs->rcvidx >= MAX_DFRAME_LEN_L1) {
 334                if (cs->debug & L1_DEB_WARN)
 335                        debugl1(cs, "AMD7930: empty_Dfifo L2-Framelength overrun");
 336                cs->rcvidx = 0;
 337                return;
 338        }
 339        /* AMD interrupts on */
 340        AmdIrqOn(cs);
 341}
 342
 343
 344static void
 345Amd7930_fill_Dfifo(struct IsdnCardState *cs)
 346{
 347
 348        WORD dtcrr, dtcrw, len, count;
 349        BYTE txstat, dmr3;
 350        BYTE *ptr, *deb_ptr;
 351
 352        if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
 353                debugl1(cs, "Amd7930: fill_Dfifo");
 354
 355        if ((!cs->tx_skb) || (cs->tx_skb->len <= 0))
 356                return;
 357
 358        dtcrw = 0;
 359        if (!cs->dc.amd7930.tx_xmtlen)
 360                /* new Frame */
 361                len = dtcrw = cs->tx_skb->len;
 362        /* continue frame */
 363        else len = cs->dc.amd7930.tx_xmtlen;
 364
 365
 366        /* AMD interrupts off */
 367        AmdIrqOff(cs);
 368
 369        deb_ptr = ptr = cs->tx_skb->data;
 370
 371        /* while free place in tx-fifo available and data in sk-buffer */
 372        txstat = 0x10;
 373        while ((txstat & 0x10) && (cs->tx_cnt < len)) {
 374                wByteAMD(cs, 0x04, *ptr);
 375                ptr++;
 376                cs->tx_cnt++;
 377                txstat = rByteAMD(cs, 0x07);
 378        }
 379        count = ptr - cs->tx_skb->data;
 380        skb_pull(cs->tx_skb, count);
 381
 382
 383        dtcrr = rWordAMD(cs, 0x85); // DTCR
 384        dmr3  = rByteAMD(cs, 0x8E);
 385
 386        if (cs->debug & L1_DEB_ISAC) {
 387                debugl1(cs, "Amd7930: fill_Dfifo, DMR3: 0x%02X, DTCR read: 0x%04X write: 0x%02X 0x%02X", dmr3, dtcrr, LOBYTE(dtcrw), HIBYTE(dtcrw));
 388        }
 389
 390        /* writeing of dtcrw starts transmit */
 391        if (!cs->dc.amd7930.tx_xmtlen) {
 392                wWordAMD(cs, 0x85, dtcrw);
 393                cs->dc.amd7930.tx_xmtlen = dtcrw;
 394        }
 395
 396        if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
 397                debugl1(cs, "Amd7930: fill_Dfifo dbusytimer running");
 398                del_timer(&cs->dbusytimer);
 399        }
 400        init_timer(&cs->dbusytimer);
 401        cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000);
 402        add_timer(&cs->dbusytimer);
 403
 404        if (cs->debug & L1_DEB_ISAC_FIFO) {
 405                char *t = cs->dlog;
 406
 407                t += sprintf(t, "Amd7930: fill_Dfifo cnt: %d |", count);
 408                QuickHex(t, deb_ptr, count);
 409                debugl1(cs, cs->dlog);
 410        }
 411        /* AMD interrupts on */
 412        AmdIrqOn(cs);
 413}
 414
 415
 416void Amd7930_interrupt(struct IsdnCardState *cs, BYTE irflags)
 417{
 418        BYTE dsr1, dsr2, lsr;
 419        WORD der;
 420
 421        while (irflags)
 422        {
 423
 424                dsr1 = rByteAMD(cs, 0x02);
 425                der  = rWordAMD(cs, 0x03);
 426                dsr2 = rByteAMD(cs, 0x07);
 427                lsr  = rByteAMD(cs, 0xA1);
 428
 429                if (cs->debug & L1_DEB_ISAC)
 430                        debugl1(cs, "Amd7930: interrupt: flags: 0x%02X, DSR1: 0x%02X, DSR2: 0x%02X, LSR: 0x%02X, DER=0x%04X", irflags, dsr1, dsr2, lsr, der);
 431
 432                /* D error -> read DER and DSR2 bit 2 */
 433                if (der || (dsr2 & 4)) {
 434
 435                        if (cs->debug & L1_DEB_WARN)
 436                                debugl1(cs, "Amd7930: interrupt: D error DER=0x%04X", der);
 437
 438                        /* RX, TX abort if collision detected */
 439                        if (der & 2) {
 440                                wByteAMD(cs, 0x21, 0xC2);
 441                                wByteAMD(cs, 0x21, 0x02);
 442                                if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 443                                        del_timer(&cs->dbusytimer);
 444                                if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
 445                                        schedule_event(cs, D_CLEARBUSY);
 446                                /* restart frame */
 447                                if (cs->tx_skb) {
 448                                        skb_push(cs->tx_skb, cs->tx_cnt);
 449                                        cs->tx_cnt = 0;
 450                                        cs->dc.amd7930.tx_xmtlen = 0;
 451                                        Amd7930_fill_Dfifo(cs);
 452                                } else {
 453                                        printk(KERN_WARNING "HiSax: Amd7930 D-Collision, no skb\n");
 454                                        debugl1(cs, "Amd7930: interrupt: D-Collision, no skb");
 455                                }
 456                        }
 457                        /* remove damaged data from fifo */
 458                        Amd7930_empty_Dfifo(cs, 1);
 459
 460                        if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 461                                del_timer(&cs->dbusytimer);
 462                        if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
 463                                schedule_event(cs, D_CLEARBUSY);
 464                        /* restart TX-Frame */
 465                        if (cs->tx_skb) {
 466                                skb_push(cs->tx_skb, cs->tx_cnt);
 467                                cs->tx_cnt = 0;
 468                                cs->dc.amd7930.tx_xmtlen = 0;
 469                                Amd7930_fill_Dfifo(cs);
 470                        }
 471                }
 472
 473                /* D TX FIFO empty -> fill */
 474                if (irflags & 1) {
 475                        if (cs->debug & L1_DEB_ISAC)
 476                                debugl1(cs, "Amd7930: interrupt: clear Timer and fill D-TX-FIFO if data");
 477
 478                        /* AMD interrupts off */
 479                        AmdIrqOff(cs);
 480
 481                        if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 482                                del_timer(&cs->dbusytimer);
 483                        if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
 484                                schedule_event(cs, D_CLEARBUSY);
 485                        if (cs->tx_skb) {
 486                                if (cs->tx_skb->len)
 487                                        Amd7930_fill_Dfifo(cs);
 488                        }
 489                        /* AMD interrupts on */
 490                        AmdIrqOn(cs);
 491                }
 492
 493
 494                /* D RX FIFO full or tiny packet in Fifo -> empty */
 495                if ((irflags & 2) || (dsr1 & 2)) {
 496                        if (cs->debug & L1_DEB_ISAC)
 497                                debugl1(cs, "Amd7930: interrupt: empty D-FIFO");
 498                        Amd7930_empty_Dfifo(cs, 0);
 499                }
 500
 501
 502                /* D-Frame transmit complete */
 503                if (dsr1 & 64) {
 504                        if (cs->debug & L1_DEB_ISAC) {
 505                                debugl1(cs, "Amd7930: interrupt: transmit packet ready");
 506                        }
 507                        /* AMD interrupts off */
 508                        AmdIrqOff(cs);
 509
 510                        if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 511                                del_timer(&cs->dbusytimer);
 512                        if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
 513                                schedule_event(cs, D_CLEARBUSY);
 514
 515                        if (cs->tx_skb) {
 516                                if (cs->debug & L1_DEB_ISAC)
 517                                        debugl1(cs, "Amd7930: interrupt: TX-Packet ready, freeing skb");
 518                                dev_kfree_skb_irq(cs->tx_skb);
 519                                cs->tx_cnt = 0;
 520                                cs->dc.amd7930.tx_xmtlen = 0;
 521                                cs->tx_skb = NULL;
 522                        }
 523                        if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
 524                                if (cs->debug & L1_DEB_ISAC)
 525                                        debugl1(cs, "Amd7930: interrupt: TX-Packet ready, next packet dequeued");
 526                                cs->tx_cnt = 0;
 527                                cs->dc.amd7930.tx_xmtlen = 0;
 528                                Amd7930_fill_Dfifo(cs);
 529                        }
 530                        else
 531                                schedule_event(cs, D_XMTBUFREADY);
 532                        /* AMD interrupts on */
 533                        AmdIrqOn(cs);
 534                }
 535
 536                /* LIU status interrupt -> read LSR, check statechanges */
 537                if (lsr & 0x38) {
 538                        /* AMD interrupts off */
 539                        AmdIrqOff(cs);
 540
 541                        if (cs->debug & L1_DEB_ISAC)
 542                                debugl1(cs, "Amd: interrupt: LSR=0x%02X, LIU is in state %d", lsr, ((lsr & 0x7) + 2));
 543
 544                        cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
 545
 546                        schedule_event(cs, D_L1STATECHANGE);
 547                        /* AMD interrupts on */
 548                        AmdIrqOn(cs);
 549                }
 550
 551                /* reads Interrupt-Register again. If there is a new interrupt-flag: restart handler */
 552                irflags = rByteAMD(cs, 0x00);
 553        }
 554
 555}
 556
 557static void
 558Amd7930_l1hw(struct PStack *st, int pr, void *arg)
 559{
 560        struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
 561        struct sk_buff *skb = arg;
 562        u_long flags;
 563
 564        if (cs->debug & L1_DEB_ISAC)
 565                debugl1(cs, "Amd7930: l1hw called, pr: 0x%04X", pr);
 566
 567        switch (pr) {
 568        case (PH_DATA | REQUEST):
 569                if (cs->debug & DEB_DLOG_HEX)
 570                        LogFrame(cs, skb->data, skb->len);
 571                if (cs->debug & DEB_DLOG_VERBOSE)
 572                        dlogframe(cs, skb, 0);
 573                spin_lock_irqsave(&cs->lock, flags);
 574                if (cs->tx_skb) {
 575                        skb_queue_tail(&cs->sq, skb);
 576#ifdef L2FRAME_DEBUG            /* psa */
 577                        if (cs->debug & L1_DEB_LAPD)
 578                                Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA Queued", 0);
 579#endif
 580                } else {
 581                        cs->tx_skb = skb;
 582                        cs->tx_cnt = 0;
 583                        cs->dc.amd7930.tx_xmtlen = 0;
 584#ifdef L2FRAME_DEBUG            /* psa */
 585                        if (cs->debug & L1_DEB_LAPD)
 586                                Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA", 0);
 587#endif
 588                        Amd7930_fill_Dfifo(cs);
 589                }
 590                spin_unlock_irqrestore(&cs->lock, flags);
 591                break;
 592        case (PH_PULL | INDICATION):
 593                spin_lock_irqsave(&cs->lock, flags);
 594                if (cs->tx_skb) {
 595                        if (cs->debug & L1_DEB_WARN)
 596                                debugl1(cs, "Amd7930: l1hw: l2l1 tx_skb exist this shouldn't happen");
 597                        skb_queue_tail(&cs->sq, skb);
 598                        spin_unlock_irqrestore(&cs->lock, flags);
 599                        break;
 600                }
 601                if (cs->debug & DEB_DLOG_HEX)
 602                        LogFrame(cs, skb->data, skb->len);
 603                if (cs->debug & DEB_DLOG_VERBOSE)
 604                        dlogframe(cs, skb, 0);
 605                cs->tx_skb = skb;
 606                cs->tx_cnt = 0;
 607                cs->dc.amd7930.tx_xmtlen = 0;
 608#ifdef L2FRAME_DEBUG            /* psa */
 609                if (cs->debug & L1_DEB_LAPD)
 610                        Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA_PULLED", 0);
 611#endif
 612                Amd7930_fill_Dfifo(cs);
 613                spin_unlock_irqrestore(&cs->lock, flags);
 614                break;
 615        case (PH_PULL | REQUEST):
 616#ifdef L2FRAME_DEBUG            /* psa */
 617                if (cs->debug & L1_DEB_LAPD)
 618                        debugl1(cs, "Amd7930: l1hw: -> PH_REQUEST_PULL, skb: %s", (cs->tx_skb) ? "yes" : "no");
 619#endif
 620                if (!cs->tx_skb) {
 621                        test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 622                        st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
 623                } else
 624                        test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 625                break;
 626        case (HW_RESET | REQUEST):
 627                spin_lock_irqsave(&cs->lock, flags);
 628                if ((cs->dc.amd7930.ph_state == 8)) {
 629                        /* b-channels off, PH-AR cleared
 630                         * change to F3 */
 631                        Amd7930_ph_command(cs, 0x20, "HW_RESET REQUEST"); //LMR1 bit 5
 632                        spin_unlock_irqrestore(&cs->lock, flags);
 633                } else {
 634                        Amd7930_ph_command(cs, 0x40, "HW_RESET REQUEST");
 635                        cs->dc.amd7930.ph_state = 2;
 636                        spin_unlock_irqrestore(&cs->lock, flags);
 637                        Amd7930_new_ph(cs);
 638                }
 639                break;
 640        case (HW_ENABLE | REQUEST):
 641                cs->dc.amd7930.ph_state = 9;
 642                Amd7930_new_ph(cs);
 643                break;
 644        case (HW_INFO3 | REQUEST):
 645                // automatic
 646                break;
 647        case (HW_TESTLOOP | REQUEST):
 648                /* not implemented yet */
 649                break;
 650        case (HW_DEACTIVATE | RESPONSE):
 651                skb_queue_purge(&cs->rq);
 652                skb_queue_purge(&cs->sq);
 653                if (cs->tx_skb) {
 654                        dev_kfree_skb(cs->tx_skb);
 655                        cs->tx_skb = NULL;
 656                }
 657                if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 658                        del_timer(&cs->dbusytimer);
 659                if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
 660                        schedule_event(cs, D_CLEARBUSY);
 661                break;
 662        default:
 663                if (cs->debug & L1_DEB_WARN)
 664                        debugl1(cs, "Amd7930: l1hw: unknown %04x", pr);
 665                break;
 666        }
 667}
 668
 669static void
 670setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs)
 671{
 672
 673        if (cs->debug & L1_DEB_ISAC)
 674                debugl1(cs, "Amd7930: setstack called");
 675
 676        st->l1.l1hw = Amd7930_l1hw;
 677}
 678
 679
 680static void
 681DC_Close_Amd7930(struct IsdnCardState *cs) {
 682        if (cs->debug & L1_DEB_ISAC)
 683                debugl1(cs, "Amd7930: DC_Close called");
 684}
 685
 686
 687static void
 688dbusy_timer_handler(struct IsdnCardState *cs)
 689{
 690        u_long flags;
 691        struct PStack *stptr;
 692        WORD dtcr, der;
 693        BYTE dsr1, dsr2;
 694
 695
 696        if (cs->debug & L1_DEB_ISAC)
 697                debugl1(cs, "Amd7930: dbusy_timer expired!");
 698
 699        if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
 700                spin_lock_irqsave(&cs->lock, flags);
 701                /* D Transmit Byte Count Register:
 702                 * Counts down packet's number of Bytes, 0 if packet ready */
 703                dtcr = rWordAMD(cs, 0x85);
 704                dsr1 = rByteAMD(cs, 0x02);
 705                dsr2 = rByteAMD(cs, 0x07);
 706                der  = rWordAMD(cs, 0x03);
 707
 708                if (cs->debug & L1_DEB_ISAC)
 709                        debugl1(cs, "Amd7930: dbusy_timer_handler: DSR1=0x%02X, DSR2=0x%02X, DER=0x%04X, cs->tx_skb->len=%u, tx_stat=%u, dtcr=%u, cs->tx_cnt=%u", dsr1, dsr2, der, cs->tx_skb->len, cs->dc.amd7930.tx_xmtlen, dtcr, cs->tx_cnt);
 710
 711                if ((cs->dc.amd7930.tx_xmtlen - dtcr) < cs->tx_cnt) {   /* D-Channel Busy */
 712                        test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
 713                        stptr = cs->stlist;
 714                        spin_unlock_irqrestore(&cs->lock, flags);
 715                        while (stptr != NULL) {
 716                                stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
 717                                stptr = stptr->next;
 718                        }
 719
 720                } else {
 721                        /* discard frame; reset transceiver */
 722                        test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
 723                        if (cs->tx_skb) {
 724                                dev_kfree_skb_any(cs->tx_skb);
 725                                cs->tx_cnt = 0;
 726                                cs->tx_skb = NULL;
 727                                cs->dc.amd7930.tx_xmtlen = 0;
 728                        } else {
 729                                printk(KERN_WARNING "HiSax: Amd7930: D-Channel Busy no skb\n");
 730                                debugl1(cs, "Amd7930: D-Channel Busy no skb");
 731
 732                        }
 733                        /* Transmitter reset, abort transmit */
 734                        wByteAMD(cs, 0x21, 0x82);
 735                        wByteAMD(cs, 0x21, 0x02);
 736                        spin_unlock_irqrestore(&cs->lock, flags);
 737                        cs->irq_func(cs->irq, cs);
 738
 739                        if (cs->debug & L1_DEB_ISAC)
 740                                debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset");
 741                }
 742        }
 743}
 744
 745
 746
 747void Amd7930_init(struct IsdnCardState *cs)
 748{
 749        WORD *ptr;
 750        BYTE cmd, cnt;
 751
 752        if (cs->debug & L1_DEB_ISAC)
 753                debugl1(cs, "Amd7930: initamd called");
 754
 755        cs->dc.amd7930.tx_xmtlen = 0;
 756        cs->dc.amd7930.old_state = 0;
 757        cs->dc.amd7930.lmr1 = 0x40;
 758        cs->dc.amd7930.ph_command = Amd7930_ph_command;
 759        cs->setstack_d = setstack_Amd7930;
 760        cs->DC_Close = DC_Close_Amd7930;
 761
 762        /* AMD Initialisation */
 763        for (ptr = initAMD; *ptr != 0xFFFF; ) {
 764                cmd = LOBYTE(*ptr);
 765
 766                /* read */
 767                if (*ptr++ >= 0x100) {
 768                        if (cmd < 8)
 769                                /* reset register */
 770                                rByteAMD(cs, cmd);
 771                        else {
 772                                wByteAMD(cs, 0x00, cmd);
 773                                for (cnt = *ptr++; cnt > 0; cnt--)
 774                                        rByteAMD(cs, 0x01);
 775                        }
 776                }
 777                /* write */
 778                else if (cmd < 8)
 779                        wByteAMD(cs, cmd, LOBYTE(*ptr++));
 780
 781                else {
 782                        wByteAMD(cs, 0x00, cmd);
 783                        for (cnt = *ptr++; cnt > 0; cnt--)
 784                                wByteAMD(cs, 0x01, LOBYTE(*ptr++));
 785                }
 786        }
 787}
 788
 789void setup_Amd7930(struct IsdnCardState *cs)
 790{
 791        INIT_WORK(&cs->tqueue, Amd7930_bh);
 792        cs->dbusytimer.function = (void *) dbusy_timer_handler;
 793        cs->dbusytimer.data = (long) cs;
 794        init_timer(&cs->dbusytimer);
 795}
 796