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