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, "%s", cs->dlog);
 318                                                }
 319                                                /* moves received data in sk-buffer */
 320                                                skb_put_data(skb, cs->rcvbuf,
 321                                                             cs->rcvidx);
 322                                                skb_queue_tail(&cs->rq, skb);
 323                                        }
 324                                }
 325
 326                        }
 327                        /* throw damaged packets away, reset receive-buffer, indicate RX */
 328                        ptr = cs->rcvbuf;
 329                        cs->rcvidx = 0;
 330                        schedule_event(cs, D_RCVBUFREADY);
 331                }
 332        }
 333        /* Packet to long, overflow */
 334        if (cs->rcvidx >= MAX_DFRAME_LEN_L1) {
 335                if (cs->debug & L1_DEB_WARN)
 336                        debugl1(cs, "AMD7930: empty_Dfifo L2-Framelength overrun");
 337                cs->rcvidx = 0;
 338                return;
 339        }
 340        /* AMD interrupts on */
 341        AmdIrqOn(cs);
 342}
 343
 344
 345static void
 346Amd7930_fill_Dfifo(struct IsdnCardState *cs)
 347{
 348
 349        WORD dtcrr, dtcrw, len, count;
 350        BYTE txstat, dmr3;
 351        BYTE *ptr, *deb_ptr;
 352
 353        if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
 354                debugl1(cs, "Amd7930: fill_Dfifo");
 355
 356        if ((!cs->tx_skb) || (cs->tx_skb->len <= 0))
 357                return;
 358
 359        dtcrw = 0;
 360        if (!cs->dc.amd7930.tx_xmtlen)
 361                /* new Frame */
 362                len = dtcrw = cs->tx_skb->len;
 363        /* continue frame */
 364        else len = cs->dc.amd7930.tx_xmtlen;
 365
 366
 367        /* AMD interrupts off */
 368        AmdIrqOff(cs);
 369
 370        deb_ptr = ptr = cs->tx_skb->data;
 371
 372        /* while free place in tx-fifo available and data in sk-buffer */
 373        txstat = 0x10;
 374        while ((txstat & 0x10) && (cs->tx_cnt < len)) {
 375                wByteAMD(cs, 0x04, *ptr);
 376                ptr++;
 377                cs->tx_cnt++;
 378                txstat = rByteAMD(cs, 0x07);
 379        }
 380        count = ptr - cs->tx_skb->data;
 381        skb_pull(cs->tx_skb, count);
 382
 383
 384        dtcrr = rWordAMD(cs, 0x85); // DTCR
 385        dmr3  = rByteAMD(cs, 0x8E);
 386
 387        if (cs->debug & L1_DEB_ISAC) {
 388                debugl1(cs, "Amd7930: fill_Dfifo, DMR3: 0x%02X, DTCR read: 0x%04X write: 0x%02X 0x%02X", dmr3, dtcrr, LOBYTE(dtcrw), HIBYTE(dtcrw));
 389        }
 390
 391        /* writeing of dtcrw starts transmit */
 392        if (!cs->dc.amd7930.tx_xmtlen) {
 393                wWordAMD(cs, 0x85, dtcrw);
 394                cs->dc.amd7930.tx_xmtlen = dtcrw;
 395        }
 396
 397        if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
 398                debugl1(cs, "Amd7930: fill_Dfifo dbusytimer running");
 399                del_timer(&cs->dbusytimer);
 400        }
 401        init_timer(&cs->dbusytimer);
 402        cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000);
 403        add_timer(&cs->dbusytimer);
 404
 405        if (cs->debug & L1_DEB_ISAC_FIFO) {
 406                char *t = cs->dlog;
 407
 408                t += sprintf(t, "Amd7930: fill_Dfifo cnt: %d |", count);
 409                QuickHex(t, deb_ptr, count);
 410                debugl1(cs, "%s", cs->dlog);
 411        }
 412        /* AMD interrupts on */
 413        AmdIrqOn(cs);
 414}
 415
 416
 417void Amd7930_interrupt(struct IsdnCardState *cs, BYTE irflags)
 418{
 419        BYTE dsr1, dsr2, lsr;
 420        WORD der;
 421
 422        while (irflags)
 423        {
 424
 425                dsr1 = rByteAMD(cs, 0x02);
 426                der  = rWordAMD(cs, 0x03);
 427                dsr2 = rByteAMD(cs, 0x07);
 428                lsr  = rByteAMD(cs, 0xA1);
 429
 430                if (cs->debug & L1_DEB_ISAC)
 431                        debugl1(cs, "Amd7930: interrupt: flags: 0x%02X, DSR1: 0x%02X, DSR2: 0x%02X, LSR: 0x%02X, DER=0x%04X", irflags, dsr1, dsr2, lsr, der);
 432
 433                /* D error -> read DER and DSR2 bit 2 */
 434                if (der || (dsr2 & 4)) {
 435
 436                        if (cs->debug & L1_DEB_WARN)
 437                                debugl1(cs, "Amd7930: interrupt: D error DER=0x%04X", der);
 438
 439                        /* RX, TX abort if collision detected */
 440                        if (der & 2) {
 441                                wByteAMD(cs, 0x21, 0xC2);
 442                                wByteAMD(cs, 0x21, 0x02);
 443                                if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 444                                        del_timer(&cs->dbusytimer);
 445                                if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
 446                                        schedule_event(cs, D_CLEARBUSY);
 447                                /* restart frame */
 448                                if (cs->tx_skb) {
 449                                        skb_push(cs->tx_skb, cs->tx_cnt);
 450                                        cs->tx_cnt = 0;
 451                                        cs->dc.amd7930.tx_xmtlen = 0;
 452                                        Amd7930_fill_Dfifo(cs);
 453                                } else {
 454                                        printk(KERN_WARNING "HiSax: Amd7930 D-Collision, no skb\n");
 455                                        debugl1(cs, "Amd7930: interrupt: D-Collision, no skb");
 456                                }
 457                        }
 458                        /* remove damaged data from fifo */
 459                        Amd7930_empty_Dfifo(cs, 1);
 460
 461                        if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 462                                del_timer(&cs->dbusytimer);
 463                        if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
 464                                schedule_event(cs, D_CLEARBUSY);
 465                        /* restart TX-Frame */
 466                        if (cs->tx_skb) {
 467                                skb_push(cs->tx_skb, cs->tx_cnt);
 468                                cs->tx_cnt = 0;
 469                                cs->dc.amd7930.tx_xmtlen = 0;
 470                                Amd7930_fill_Dfifo(cs);
 471                        }
 472                }
 473
 474                /* D TX FIFO empty -> fill */
 475                if (irflags & 1) {
 476                        if (cs->debug & L1_DEB_ISAC)
 477                                debugl1(cs, "Amd7930: interrupt: clear Timer and fill D-TX-FIFO if data");
 478
 479                        /* AMD interrupts off */
 480                        AmdIrqOff(cs);
 481
 482                        if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 483                                del_timer(&cs->dbusytimer);
 484                        if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
 485                                schedule_event(cs, D_CLEARBUSY);
 486                        if (cs->tx_skb) {
 487                                if (cs->tx_skb->len)
 488                                        Amd7930_fill_Dfifo(cs);
 489                        }
 490                        /* AMD interrupts on */
 491                        AmdIrqOn(cs);
 492                }
 493
 494
 495                /* D RX FIFO full or tiny packet in Fifo -> empty */
 496                if ((irflags & 2) || (dsr1 & 2)) {
 497                        if (cs->debug & L1_DEB_ISAC)
 498                                debugl1(cs, "Amd7930: interrupt: empty D-FIFO");
 499                        Amd7930_empty_Dfifo(cs, 0);
 500                }
 501
 502
 503                /* D-Frame transmit complete */
 504                if (dsr1 & 64) {
 505                        if (cs->debug & L1_DEB_ISAC) {
 506                                debugl1(cs, "Amd7930: interrupt: transmit packet ready");
 507                        }
 508                        /* AMD interrupts off */
 509                        AmdIrqOff(cs);
 510
 511                        if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 512                                del_timer(&cs->dbusytimer);
 513                        if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
 514                                schedule_event(cs, D_CLEARBUSY);
 515
 516                        if (cs->tx_skb) {
 517                                if (cs->debug & L1_DEB_ISAC)
 518                                        debugl1(cs, "Amd7930: interrupt: TX-Packet ready, freeing skb");
 519                                dev_kfree_skb_irq(cs->tx_skb);
 520                                cs->tx_cnt = 0;
 521                                cs->dc.amd7930.tx_xmtlen = 0;
 522                                cs->tx_skb = NULL;
 523                        }
 524                        if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
 525                                if (cs->debug & L1_DEB_ISAC)
 526                                        debugl1(cs, "Amd7930: interrupt: TX-Packet ready, next packet dequeued");
 527                                cs->tx_cnt = 0;
 528                                cs->dc.amd7930.tx_xmtlen = 0;
 529                                Amd7930_fill_Dfifo(cs);
 530                        }
 531                        else
 532                                schedule_event(cs, D_XMTBUFREADY);
 533                        /* AMD interrupts on */
 534                        AmdIrqOn(cs);
 535                }
 536
 537                /* LIU status interrupt -> read LSR, check statechanges */
 538                if (lsr & 0x38) {
 539                        /* AMD interrupts off */
 540                        AmdIrqOff(cs);
 541
 542                        if (cs->debug & L1_DEB_ISAC)
 543                                debugl1(cs, "Amd: interrupt: LSR=0x%02X, LIU is in state %d", lsr, ((lsr & 0x7) + 2));
 544
 545                        cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
 546
 547                        schedule_event(cs, D_L1STATECHANGE);
 548                        /* AMD interrupts on */
 549                        AmdIrqOn(cs);
 550                }
 551
 552                /* reads Interrupt-Register again. If there is a new interrupt-flag: restart handler */
 553                irflags = rByteAMD(cs, 0x00);
 554        }
 555
 556}
 557
 558static void
 559Amd7930_l1hw(struct PStack *st, int pr, void *arg)
 560{
 561        struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
 562        struct sk_buff *skb = arg;
 563        u_long flags;
 564
 565        if (cs->debug & L1_DEB_ISAC)
 566                debugl1(cs, "Amd7930: l1hw called, pr: 0x%04X", pr);
 567
 568        switch (pr) {
 569        case (PH_DATA | REQUEST):
 570                if (cs->debug & DEB_DLOG_HEX)
 571                        LogFrame(cs, skb->data, skb->len);
 572                if (cs->debug & DEB_DLOG_VERBOSE)
 573                        dlogframe(cs, skb, 0);
 574                spin_lock_irqsave(&cs->lock, flags);
 575                if (cs->tx_skb) {
 576                        skb_queue_tail(&cs->sq, skb);
 577#ifdef L2FRAME_DEBUG            /* psa */
 578                        if (cs->debug & L1_DEB_LAPD)
 579                                Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA Queued", 0);
 580#endif
 581                } else {
 582                        cs->tx_skb = skb;
 583                        cs->tx_cnt = 0;
 584                        cs->dc.amd7930.tx_xmtlen = 0;
 585#ifdef L2FRAME_DEBUG            /* psa */
 586                        if (cs->debug & L1_DEB_LAPD)
 587                                Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA", 0);
 588#endif
 589                        Amd7930_fill_Dfifo(cs);
 590                }
 591                spin_unlock_irqrestore(&cs->lock, flags);
 592                break;
 593        case (PH_PULL | INDICATION):
 594                spin_lock_irqsave(&cs->lock, flags);
 595                if (cs->tx_skb) {
 596                        if (cs->debug & L1_DEB_WARN)
 597                                debugl1(cs, "Amd7930: l1hw: l2l1 tx_skb exist this shouldn't happen");
 598                        skb_queue_tail(&cs->sq, skb);
 599                        spin_unlock_irqrestore(&cs->lock, flags);
 600                        break;
 601                }
 602                if (cs->debug & DEB_DLOG_HEX)
 603                        LogFrame(cs, skb->data, skb->len);
 604                if (cs->debug & DEB_DLOG_VERBOSE)
 605                        dlogframe(cs, skb, 0);
 606                cs->tx_skb = skb;
 607                cs->tx_cnt = 0;
 608                cs->dc.amd7930.tx_xmtlen = 0;
 609#ifdef L2FRAME_DEBUG            /* psa */
 610                if (cs->debug & L1_DEB_LAPD)
 611                        Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA_PULLED", 0);
 612#endif
 613                Amd7930_fill_Dfifo(cs);
 614                spin_unlock_irqrestore(&cs->lock, flags);
 615                break;
 616        case (PH_PULL | REQUEST):
 617#ifdef L2FRAME_DEBUG            /* psa */
 618                if (cs->debug & L1_DEB_LAPD)
 619                        debugl1(cs, "Amd7930: l1hw: -> PH_REQUEST_PULL, skb: %s", (cs->tx_skb) ? "yes" : "no");
 620#endif
 621                if (!cs->tx_skb) {
 622                        test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 623                        st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
 624                } else
 625                        test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
 626                break;
 627        case (HW_RESET | REQUEST):
 628                spin_lock_irqsave(&cs->lock, flags);
 629                if ((cs->dc.amd7930.ph_state == 8)) {
 630                        /* b-channels off, PH-AR cleared
 631                         * change to F3 */
 632                        Amd7930_ph_command(cs, 0x20, "HW_RESET REQUEST"); //LMR1 bit 5
 633                        spin_unlock_irqrestore(&cs->lock, flags);
 634                } else {
 635                        Amd7930_ph_command(cs, 0x40, "HW_RESET REQUEST");
 636                        cs->dc.amd7930.ph_state = 2;
 637                        spin_unlock_irqrestore(&cs->lock, flags);
 638                        Amd7930_new_ph(cs);
 639                }
 640                break;
 641        case (HW_ENABLE | REQUEST):
 642                cs->dc.amd7930.ph_state = 9;
 643                Amd7930_new_ph(cs);
 644                break;
 645        case (HW_INFO3 | REQUEST):
 646                // automatic
 647                break;
 648        case (HW_TESTLOOP | REQUEST):
 649                /* not implemented yet */
 650                break;
 651        case (HW_DEACTIVATE | RESPONSE):
 652                skb_queue_purge(&cs->rq);
 653                skb_queue_purge(&cs->sq);
 654                if (cs->tx_skb) {
 655                        dev_kfree_skb(cs->tx_skb);
 656                        cs->tx_skb = NULL;
 657                }
 658                if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
 659                        del_timer(&cs->dbusytimer);
 660                if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
 661                        schedule_event(cs, D_CLEARBUSY);
 662                break;
 663        default:
 664                if (cs->debug & L1_DEB_WARN)
 665                        debugl1(cs, "Amd7930: l1hw: unknown %04x", pr);
 666                break;
 667        }
 668}
 669
 670static void
 671setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs)
 672{
 673
 674        if (cs->debug & L1_DEB_ISAC)
 675                debugl1(cs, "Amd7930: setstack called");
 676
 677        st->l1.l1hw = Amd7930_l1hw;
 678}
 679
 680
 681static void
 682DC_Close_Amd7930(struct IsdnCardState *cs) {
 683        if (cs->debug & L1_DEB_ISAC)
 684                debugl1(cs, "Amd7930: DC_Close called");
 685}
 686
 687
 688static void
 689dbusy_timer_handler(struct IsdnCardState *cs)
 690{
 691        u_long flags;
 692        struct PStack *stptr;
 693        WORD dtcr, der;
 694        BYTE dsr1, dsr2;
 695
 696
 697        if (cs->debug & L1_DEB_ISAC)
 698                debugl1(cs, "Amd7930: dbusy_timer expired!");
 699
 700        if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
 701                spin_lock_irqsave(&cs->lock, flags);
 702                /* D Transmit Byte Count Register:
 703                 * Counts down packet's number of Bytes, 0 if packet ready */
 704                dtcr = rWordAMD(cs, 0x85);
 705                dsr1 = rByteAMD(cs, 0x02);
 706                dsr2 = rByteAMD(cs, 0x07);
 707                der  = rWordAMD(cs, 0x03);
 708
 709                if (cs->debug & L1_DEB_ISAC)
 710                        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);
 711
 712                if ((cs->dc.amd7930.tx_xmtlen - dtcr) < cs->tx_cnt) {   /* D-Channel Busy */
 713                        test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
 714                        stptr = cs->stlist;
 715                        spin_unlock_irqrestore(&cs->lock, flags);
 716                        while (stptr != NULL) {
 717                                stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
 718                                stptr = stptr->next;
 719                        }
 720
 721                } else {
 722                        /* discard frame; reset transceiver */
 723                        test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
 724                        if (cs->tx_skb) {
 725                                dev_kfree_skb_any(cs->tx_skb);
 726                                cs->tx_cnt = 0;
 727                                cs->tx_skb = NULL;
 728                                cs->dc.amd7930.tx_xmtlen = 0;
 729                        } else {
 730                                printk(KERN_WARNING "HiSax: Amd7930: D-Channel Busy no skb\n");
 731                                debugl1(cs, "Amd7930: D-Channel Busy no skb");
 732
 733                        }
 734                        /* Transmitter reset, abort transmit */
 735                        wByteAMD(cs, 0x21, 0x82);
 736                        wByteAMD(cs, 0x21, 0x02);
 737                        spin_unlock_irqrestore(&cs->lock, flags);
 738                        cs->irq_func(cs->irq, cs);
 739
 740                        if (cs->debug & L1_DEB_ISAC)
 741                                debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset");
 742                }
 743        }
 744}
 745
 746
 747
 748void Amd7930_init(struct IsdnCardState *cs)
 749{
 750        WORD *ptr;
 751        BYTE cmd, cnt;
 752
 753        if (cs->debug & L1_DEB_ISAC)
 754                debugl1(cs, "Amd7930: initamd called");
 755
 756        cs->dc.amd7930.tx_xmtlen = 0;
 757        cs->dc.amd7930.old_state = 0;
 758        cs->dc.amd7930.lmr1 = 0x40;
 759        cs->dc.amd7930.ph_command = Amd7930_ph_command;
 760        cs->setstack_d = setstack_Amd7930;
 761        cs->DC_Close = DC_Close_Amd7930;
 762
 763        /* AMD Initialisation */
 764        for (ptr = initAMD; *ptr != 0xFFFF; ) {
 765                cmd = LOBYTE(*ptr);
 766
 767                /* read */
 768                if (*ptr++ >= 0x100) {
 769                        if (cmd < 8)
 770                                /* reset register */
 771                                rByteAMD(cs, cmd);
 772                        else {
 773                                wByteAMD(cs, 0x00, cmd);
 774                                for (cnt = *ptr++; cnt > 0; cnt--)
 775                                        rByteAMD(cs, 0x01);
 776                        }
 777                }
 778                /* write */
 779                else if (cmd < 8)
 780                        wByteAMD(cs, cmd, LOBYTE(*ptr++));
 781
 782                else {
 783                        wByteAMD(cs, 0x00, cmd);
 784                        for (cnt = *ptr++; cnt > 0; cnt--)
 785                                wByteAMD(cs, 0x01, LOBYTE(*ptr++));
 786                }
 787        }
 788}
 789
 790void setup_Amd7930(struct IsdnCardState *cs)
 791{
 792        INIT_WORK(&cs->tqueue, Amd7930_bh);
 793        setup_timer(&cs->dbusytimer, (void *)dbusy_timer_handler, (long)cs);
 794}
 795