📄 amd7930_fn.c
字号:
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);}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 voidAmd7930_l1hw(struct PStack *st, int pr, void *arg){ struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; struct sk_buff *skb = arg; u_long flags; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Amd7930: l1hw called, pr: 0x%04X", pr); switch (pr) { case (PH_DATA | REQUEST): if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len); if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0); spin_lock_irqsave(&cs->lock, flags); if (cs->tx_skb) { skb_queue_tail(&cs->sq, skb);#ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA Queued", 0);#endif } else { cs->tx_skb = skb; cs->tx_cnt = 0; cs->dc.amd7930.tx_xmtlen=0;#ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA", 0);#endif Amd7930_fill_Dfifo(cs); } spin_unlock_irqrestore(&cs->lock, flags); break; case (PH_PULL | INDICATION): spin_lock_irqsave(&cs->lock, flags); if (cs->tx_skb) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "Amd7930: l1hw: l2l1 tx_skb exist this shouldn't happen"); skb_queue_tail(&cs->sq, skb); break; } if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len); if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0); cs->tx_skb = skb; cs->tx_cnt = 0; cs->dc.amd7930.tx_xmtlen=0;#ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA_PULLED", 0);#endif Amd7930_fill_Dfifo(cs); spin_unlock_irqrestore(&cs->lock, flags); break; case (PH_PULL | REQUEST):#ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) debugl1(cs, "Amd7930: l1hw: -> PH_REQUEST_PULL, skb: %s", (cs->tx_skb)? "yes":"no");#endif if (!cs->tx_skb) { test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); } else test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (HW_RESET | REQUEST): spin_lock_irqsave(&cs->lock, flags); if ((cs->dc.amd7930.ph_state == 8)) { /* b-channels off, PH-AR cleared * change to F3 */ Amd7930_ph_command(cs, 0x20, "HW_RESET REQEST"); //LMR1 bit 5 spin_unlock_irqrestore(&cs->lock, flags); } else { Amd7930_ph_command(cs, 0x40, "HW_RESET REQUEST"); cs->dc.amd7930.ph_state = 2; spin_unlock_irqrestore(&cs->lock, flags); Amd7930_new_ph(cs); } break; case (HW_ENABLE | REQUEST): cs->dc.amd7930.ph_state = 9; Amd7930_new_ph(cs); break; case (HW_INFO3 | REQUEST): // automatic break; case (HW_TESTLOOP | REQUEST): /* not implemented yet */ break; case (HW_DEACTIVATE | RESPONSE): skb_queue_purge(&cs->rq); skb_queue_purge(&cs->sq); if (cs->tx_skb) { dev_kfree_skb(cs->tx_skb); cs->tx_skb = NULL; } 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); break; default: if (cs->debug & L1_DEB_WARN) debugl1(cs, "Amd7930: l1hw: unknown %04x", pr); break; }}static voidsetstack_Amd7930(struct PStack *st, struct IsdnCardState *cs){ if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Amd7930: setstack called"); st->l1.l1hw = Amd7930_l1hw;}static voidDC_Close_Amd7930(struct IsdnCardState *cs) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Amd7930: DC_Close called");}static voiddbusy_timer_handler(struct IsdnCardState *cs){ u_long flags; struct PStack *stptr; WORD dtcr, der; BYTE dsr1, dsr2; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Amd7930: dbusy_timer expired!"); if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { spin_lock_irqsave(&cs->lock, flags); /* D Transmit Byte Count Register: * Counts down packet's number of Bytes, 0 if packet ready */ dtcr = rWordAMD(cs, 0x85); dsr1 = rByteAMD(cs, 0x02); dsr2 = rByteAMD(cs, 0x07); der = rWordAMD(cs, 0x03); if (cs->debug & L1_DEB_ISAC) 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); if ((cs->dc.amd7930.tx_xmtlen - dtcr) < cs->tx_cnt) { /* D-Channel Busy */ test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); stptr = cs->stlist; spin_unlock_irqrestore(&cs->lock, flags); while (stptr != NULL) { stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); stptr = stptr->next; } } else { /* discard frame; reset transceiver */ test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); if (cs->tx_skb) { dev_kfree_skb_any(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; cs->dc.amd7930.tx_xmtlen = 0; } else { printk(KERN_WARNING "HiSax: Amd7930: D-Channel Busy no skb\n"); debugl1(cs, "Amd7930: D-Channel Busy no skb"); } /* Transmitter reset, abort transmit */ wByteAMD(cs, 0x21, 0x82); wByteAMD(cs, 0x21, 0x02); spin_unlock_irqrestore(&cs->lock, flags); cs->irq_func(cs->irq, cs, NULL); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset"); } }}void __devinitAmd7930_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點k */ 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++)); } }}void __devinitsetup_Amd7930(struct IsdnCardState *cs){ INIT_WORK(&cs->tqueue, (void *)(void *) Amd7930_bh, cs); cs->dbusytimer.function = (void *) dbusy_timer_handler; cs->dbusytimer.data = (long) cs; init_timer(&cs->dbusytimer);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -