static void Amd7930_ph_command(struct IsdnCardState *cs, u_char command, char *s) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "AMD7930: %s: ph_command 0x%02X", s, command); cs->dc.amd7930.lmr1 = command; wByteAMD(cs, 0xA3, command); }
void __devinit Amd7930_init(struct IsdnCardState *cs) { WORD *ptr; BYTE cmd, cnt; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Amd7930: initamd called"); cs->dc.amd7930.tx_xmtlen = 0; cs->dc.amd7930.old_state = 0; cs->dc.amd7930.lmr1 = 0x40; cs->dc.amd7930.ph_command = Amd7930_ph_command; cs->setstack_d = setstack_Amd7930; cs->DC_Close = DC_Close_Amd7930; /* AMD Initialisation */ for (ptr = initAMD; *ptr != 0xFFFF; ) { cmd = LOBYTE(*ptr); /* read */ if (*ptr++ >= 0x100) { if (cmd < 8) /* setzt Register zurück */ rByteAMD(cs, cmd); else { wByteAMD(cs, 0x00, cmd); for (cnt = *ptr++; cnt > 0; cnt--) rByteAMD(cs, 0x01); } } /* write */ else if (cmd < 8) wByteAMD(cs, cmd, LOBYTE(*ptr++)); else { wByteAMD(cs, 0x00, cmd); for (cnt = *ptr++; cnt > 0; cnt--) wByteAMD(cs, 0x01, LOBYTE(*ptr++)); } } }
static WORD /* macro rWordAMD */ ReadWordAmd7930(struct IsdnCardState *cs, BYTE reg) { WORD res; /* direct access register */ if(reg < 8) { res = rByteAMD(cs, reg); res += 256*rByteAMD(cs, reg); } /* indirect access register */ else { wByteAMD(cs, 0x00, reg); res = rByteAMD(cs, 0x01); res += 256*rByteAMD(cs, 0x01); } return (res); }
void Amd7930_interrupt(struct IsdnCardState *cs, BYTE irflags) { BYTE dsr1, dsr2, lsr; WORD der; while (irflags) { dsr1 = rByteAMD(cs, 0x02); der = rWordAMD(cs, 0x03); dsr2 = rByteAMD(cs, 0x07); lsr = rByteAMD(cs, 0xA1); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Amd7930: interrupt: flags: 0x%02X, DSR1: 0x%02X, DSR2: 0x%02X, LSR: 0x%02X, DER=0x%04X", irflags, dsr1, dsr2, lsr, der); /* D error -> read DER and DSR2 bit 2 */ if (der || (dsr2 & 4)) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "Amd7930: interrupt: D error DER=0x%04X", der); /* RX, TX abort if collision detected */ if (der & 2) { wByteAMD(cs, 0x21, 0xC2); wByteAMD(cs, 0x21, 0x02); if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) del_timer(&cs->dbusytimer); if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) schedule_event(cs, D_CLEARBUSY); /* restart frame */ if (cs->tx_skb) { skb_push(cs->tx_skb, cs->tx_cnt); cs->tx_cnt = 0; cs->dc.amd7930.tx_xmtlen = 0; Amd7930_fill_Dfifo(cs); } else { printk(KERN_WARNING "HiSax: Amd7930 D-Collision, no skb\n"); debugl1(cs, "Amd7930: interrupt: D-Collision, no skb"); } } /* remove damaged data from fifo */ Amd7930_empty_Dfifo(cs, 1); if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) del_timer(&cs->dbusytimer); if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) schedule_event(cs, D_CLEARBUSY); /* restart TX-Frame */ if (cs->tx_skb) { skb_push(cs->tx_skb, cs->tx_cnt); cs->tx_cnt = 0; cs->dc.amd7930.tx_xmtlen = 0; Amd7930_fill_Dfifo(cs); } } /* D TX FIFO empty -> fill */ if (irflags & 1) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Amd7930: interrupt: clear Timer and fill D-TX-FIFO if data"); /* AMD interrupts off */ AmdIrqOff(cs); if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) del_timer(&cs->dbusytimer); if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) schedule_event(cs, D_CLEARBUSY); if (cs->tx_skb) { if (cs->tx_skb->len) Amd7930_fill_Dfifo(cs); } /* AMD interrupts on */ AmdIrqOn(cs); } /* D RX FIFO full or tiny packet in Fifo -> empty */ if ((irflags & 2) || (dsr1 & 2)) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Amd7930: interrupt: empty D-FIFO"); Amd7930_empty_Dfifo(cs, 0); } /* D-Frame transmit complete */ if (dsr1 & 64) { if (cs->debug & L1_DEB_ISAC) { debugl1(cs, "Amd7930: interrupt: transmit packet ready"); } /* AMD interrupts off */ AmdIrqOff(cs); if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) del_timer(&cs->dbusytimer); if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) schedule_event(cs, D_CLEARBUSY); if (cs->tx_skb) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Amd7930: interrupt: TX-Packet ready, freeing skb"); dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->dc.amd7930.tx_xmtlen=0; cs->tx_skb = NULL; } if ((cs->tx_skb = skb_dequeue(&cs->sq))) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Amd7930: interrupt: TX-Packet ready, next packet dequeued"); cs->tx_cnt = 0; cs->dc.amd7930.tx_xmtlen=0; Amd7930_fill_Dfifo(cs); } else schedule_event(cs, D_XMTBUFREADY); /* AMD interrupts on */ AmdIrqOn(cs); } /* LIU status interrupt -> read LSR, check statechanges */ if (lsr & 0x38) { /* AMD interrupts off */ AmdIrqOff(cs); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Amd: interrupt: LSR=0x%02X, LIU is in state %d", lsr, ((lsr & 0x7) +2)); cs->dc.amd7930.ph_state = (lsr & 0x7) + 2; schedule_event(cs, D_L1STATECHANGE); /* AMD interrupts on */ AmdIrqOn(cs); } /* reads Interrupt-Register again. If there is a new interrupt-flag: restart handler */ irflags = rByteAMD(cs, 0x00); } }
static void Amd7930_fill_Dfifo(struct IsdnCardState *cs) { WORD dtcrr, dtcrw, len, count; BYTE txstat, dmr3; BYTE *ptr, *deb_ptr; if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) debugl1(cs, "Amd7930: fill_Dfifo"); if ((!cs->tx_skb) || (cs->tx_skb->len <= 0)) return; dtcrw = 0; if(!cs->dc.amd7930.tx_xmtlen) /* new Frame */ len = dtcrw = cs->tx_skb->len; /* continue frame */ else len = cs->dc.amd7930.tx_xmtlen; /* AMD interrupts off */ AmdIrqOff(cs); deb_ptr = ptr = cs->tx_skb->data; /* while free place in tx-fifo available and data in sk-buffer */ txstat = 0x10; while((txstat & 0x10) && (cs->tx_cnt < len)) { wByteAMD(cs, 0x04, *ptr); ptr++; cs->tx_cnt++; txstat= rByteAMD(cs, 0x07); } count = ptr - cs->tx_skb->data; skb_pull(cs->tx_skb, count); dtcrr = rWordAMD(cs, 0x85); // DTCR dmr3 = rByteAMD(cs, 0x8E); if (cs->debug & L1_DEB_ISAC) { debugl1(cs, "Amd7930: fill_Dfifo, DMR3: 0x%02X, DTCR read: 0x%04X write: 0x%02X 0x%02X", dmr3, dtcrr, LOBYTE(dtcrw), HIBYTE(dtcrw)); } /* writeing of dtcrw starts transmit */ if(!cs->dc.amd7930.tx_xmtlen) { wWordAMD(cs, 0x85, dtcrw); cs->dc.amd7930.tx_xmtlen = dtcrw; } if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { debugl1(cs, "Amd7930: fill_Dfifo dbusytimer running"); del_timer(&cs->dbusytimer); } init_timer(&cs->dbusytimer); cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000); add_timer(&cs->dbusytimer); if (cs->debug & L1_DEB_ISAC_FIFO) { char *t = cs->dlog; t += sprintf(t, "Amd7930: fill_Dfifo cnt: %d |", count); QuickHex(t, deb_ptr, count); debugl1(cs, cs->dlog); } /* AMD interrupts on */ AmdIrqOn(cs); }
static void Amd7930_new_ph(struct IsdnCardState *cs) { u_char index = stateHelper[cs->dc.amd7930.old_state]*8 + stateHelper[cs->dc.amd7930.ph_state]-1; u_char message = i430States[index]; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "AMD7930: new_ph %d, old_ph %d, message %d, index %d", cs->dc.amd7930.ph_state, cs->dc.amd7930.old_state, message & 0x0f, index); cs->dc.amd7930.old_state = cs->dc.amd7930.ph_state; /* abort transmit if nessesary */ if ((message & 0xf0) && (cs->tx_skb)) { wByteAMD(cs, 0x21, 0xC2); wByteAMD(cs, 0x21, 0x02); } switch (message & 0x0f) { case (1): l1_msg(cs, HW_RESET | INDICATION, NULL); Amd7930_get_state(cs); break; case (2): /* init, Card starts in F3 */ l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); break; case (3): l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); break; case (4): l1_msg(cs, HW_POWERUP | CONFIRM, NULL); Amd7930_ph_command(cs, 0x50, "HW_ENABLE REQUEST"); break; case (5): l1_msg(cs, HW_RSYNC | INDICATION, NULL); break; case (6): l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); break; case (7): /* init, Card starts in F7 */ l1_msg(cs, HW_RSYNC | INDICATION, NULL); l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); break; case (8): l1_msg(cs, HW_POWERUP | CONFIRM, NULL); /* fall through */ case (9): Amd7930_ph_command(cs, 0x40, "HW_ENABLE REQ cleared if set"); l1_msg(cs, HW_RSYNC | INDICATION, NULL); l1_msg(cs, HW_INFO2 | INDICATION, NULL); l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); break; case (10): Amd7930_ph_command(cs, 0x40, "T3 expired, HW_ENABLE REQ cleared"); cs->dc.amd7930.old_state = 3; break; case (11): l1_msg(cs, HW_INFO2 | INDICATION, NULL); break; default: break; } }