static irqreturn_t W6692_interrupt(int intno, void *dev_id) { struct IsdnCardState *cs = dev_id; u_char val, exval, v1; struct sk_buff *skb; u_int count; u_long flags; int icnt = 5; spin_lock_irqsave(&cs->lock, flags); val = cs->readW6692(cs, W_ISTA); if (!val) { spin_unlock_irqrestore(&cs->lock, flags); return IRQ_NONE; } StartW6692: if (cs->debug & L1_DEB_ISAC) debugl1(cs, "W6692 ISTA %x", val); if (val & W_INT_D_RME) { /* RME */ exval = cs->readW6692(cs, W_D_RSTA); if (exval & (W_D_RSTA_RDOV | W_D_RSTA_CRCE | W_D_RSTA_RMB)) { if (exval & W_D_RSTA_RDOV) if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692 RDOV"); if (exval & W_D_RSTA_CRCE) if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692 D-channel CRC error"); if (exval & W_D_RSTA_RMB) if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692 D-channel ABORT"); cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST); } else { count = cs->readW6692(cs, W_D_RBCL) & (W_D_FIFO_THRESH - 1); if (count == 0) count = W_D_FIFO_THRESH; W6692_empty_fifo(cs, count); if ((count = cs->rcvidx) > 0) { cs->rcvidx = 0; if (!(skb = alloc_skb(count, GFP_ATOMIC))) printk(KERN_WARNING "HiSax: D receive out of memory\n"); else { memcpy(skb_put(skb, count), cs->rcvbuf, count); skb_queue_tail(&cs->rq, skb); } } } cs->rcvidx = 0; schedule_event(cs, D_RCVBUFREADY); } if (val & W_INT_D_RMR) { /* RMR */ W6692_empty_fifo(cs, W_D_FIFO_THRESH); } if (val & W_INT_D_XFR) { /* XFR */ 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) { W6692_fill_fifo(cs); goto afterXFR; } else { dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } } if ((cs->tx_skb = skb_dequeue(&cs->sq))) { cs->tx_cnt = 0; W6692_fill_fifo(cs); } else schedule_event(cs, D_XMTBUFREADY); } afterXFR: if (val & (W_INT_XINT0 | W_INT_XINT1)) { /* XINT0/1 - never */ if (cs->debug & L1_DEB_ISAC) debugl1(cs, "W6692 spurious XINT!"); } if (val & W_INT_D_EXI) { /* EXI */ exval = cs->readW6692(cs, W_D_EXIR); if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692 D_EXIR %02x", exval); if (exval & (W_D_EXI_XDUN | W_D_EXI_XCOL)) { /* Transmit underrun/collision */ debugl1(cs, "W6692 D-chan underrun/collision"); printk(KERN_WARNING "HiSax: W6692 XDUN/XCOL\n"); 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) { /* Restart frame */ skb_push(cs->tx_skb, cs->tx_cnt); cs->tx_cnt = 0; W6692_fill_fifo(cs); } else { printk(KERN_WARNING "HiSax: W6692 XDUN/XCOL no skb\n"); debugl1(cs, "W6692 XDUN/XCOL no skb"); cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_XRST); } } if (exval & W_D_EXI_RDOV) { /* RDOV */ debugl1(cs, "W6692 D-channel RDOV"); printk(KERN_WARNING "HiSax: W6692 D-RDOV\n"); cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RRST); } if (exval & W_D_EXI_TIN2) { /* TIN2 - never */ debugl1(cs, "W6692 spurious TIN2 interrupt"); } if (exval & W_D_EXI_MOC) { /* MOC - not supported */ debugl1(cs, "W6692 spurious MOC interrupt"); v1 = cs->readW6692(cs, W_MOSR); debugl1(cs, "W6692 MOSR %02x", v1); } if (exval & W_D_EXI_ISC) { /* ISC - Level1 change */ v1 = cs->readW6692(cs, W_CIR); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "W6692 ISC CIR=0x%02X", v1); if (v1 & W_CIR_ICC) { cs->dc.w6692.ph_state = v1 & W_CIR_COD_MASK; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ph_state_change %x", cs->dc.w6692.ph_state); schedule_event(cs, D_L1STATECHANGE); } if (v1 & W_CIR_SCC) { v1 = cs->readW6692(cs, W_SQR); debugl1(cs, "W6692 SCC SQR=0x%02X", v1); } } if (exval & W_D_EXI_WEXP) { debugl1(cs, "W6692 spurious WEXP interrupt!"); } if (exval & W_D_EXI_TEXP) { debugl1(cs, "W6692 spurious TEXP interrupt!"); } } if (val & W_INT_B1_EXI) { debugl1(cs, "W6692 B channel 1 interrupt"); W6692B_interrupt(cs, 0); } if (val & W_INT_B2_EXI) { debugl1(cs, "W6692 B channel 2 interrupt"); W6692B_interrupt(cs, 1); } val = cs->readW6692(cs, W_ISTA); if (val && icnt) { icnt--; goto StartW6692; } if (!icnt) { printk(KERN_WARNING "W6692 IRQ LOOP\n"); cs->writeW6692(cs, W_IMASK, 0xff); } spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; }
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 DC_Close_Amd7930(struct IsdnCardState *cs) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "Amd7930: DC_Close called"); }
static inline void Memhscx_int_main(struct IsdnCardState *cs, u_char val) { u_char exval; struct BCState *bcs; if (val & 0x01) { bcs = cs->bcs + 1; exval = MemReadHSCX(cs, 1, HSCX_EXIR); if (exval & 0x40) { if (bcs->mode == 1) Memhscx_fill_fifo(bcs); else { /* Here we lost an TX interrupt, so * restart transmitting the whole frame. */ if (bcs->tx_skb) { skb_push(bcs->tx_skb, bcs->hw.hscx.count); bcs->tx_cnt += bcs->hw.hscx.count; bcs->hw.hscx.count = 0; } MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); if (cs->debug & L1_DEB_WARN) debugl1(cs, "HSCX B EXIR %x Lost TX", exval); } } else if (cs->debug & L1_DEB_HSCX) debugl1(cs, "HSCX B EXIR %x", exval); } if (val & 0xf8) { if (cs->debug & L1_DEB_HSCX) debugl1(cs, "HSCX B interrupt %x", val); Memhscx_interrupt(cs, val, 1); } if (val & 0x02) { bcs = cs->bcs; exval = MemReadHSCX(cs, 0, HSCX_EXIR); if (exval & 0x40) { if (bcs->mode == L1_MODE_TRANS) Memhscx_fill_fifo(bcs); else { /* Here we lost an TX interrupt, so * restart transmitting the whole frame. */ if (bcs->tx_skb) { skb_push(bcs->tx_skb, bcs->hw.hscx.count); bcs->tx_cnt += bcs->hw.hscx.count; bcs->hw.hscx.count = 0; } MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); if (cs->debug & L1_DEB_WARN) debugl1(cs, "HSCX A EXIR %x Lost TX", exval); } } else if (cs->debug & L1_DEB_HSCX) debugl1(cs, "HSCX A EXIR %x", exval); } if (val & 0x04) { exval = MemReadHSCX(cs, 0, HSCX_ISTA); if (cs->debug & L1_DEB_HSCX) debugl1(cs, "HSCX A interrupt %x", exval); Memhscx_interrupt(cs, exval, 0); } }
static void Amd7930_empty_Dfifo(struct IsdnCardState *cs, int flag) { BYTE stat, der; BYTE *ptr; struct sk_buff *skb; if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) debugl1(cs, "Amd7930: empty_Dfifo"); ptr = cs->rcvbuf + cs->rcvidx; /* AMD interrupts off */ AmdIrqOff(cs); /* read D-Channel-Fifo*/ stat = rByteAMD(cs, 0x07); // DSR2 /* while Data in Fifo ... */ while ( (stat & 2) && ((ptr-cs->rcvbuf) < MAX_DFRAME_LEN_L1) ) { *ptr = rByteAMD(cs, 0x04); // DCRB ptr++; stat = rByteAMD(cs, 0x07); // DSR2 cs->rcvidx = ptr - cs->rcvbuf; /* Paket ready? */ if (stat & 1) { der = rWordAMD(cs, 0x03); /* no errors, packet ok */ if(!der && !flag) { rWordAMD(cs, 0x89); // clear DRCR if ((cs->rcvidx) > 0) { if (!(skb = alloc_skb(cs->rcvidx, GFP_ATOMIC))) printk(KERN_WARNING "HiSax: Amd7930: empty_Dfifo, D receive out of memory!\n"); else { /* Debugging */ if (cs->debug & L1_DEB_ISAC_FIFO) { char *t = cs->dlog; t += sprintf(t, "Amd7930: empty_Dfifo cnt: %d |", cs->rcvidx); QuickHex(t, cs->rcvbuf, cs->rcvidx); debugl1(cs, cs->dlog); } /* moves received data in sk-buffer */ memcpy(skb_put(skb, cs->rcvidx), cs->rcvbuf, cs->rcvidx); skb_queue_tail(&cs->rq, skb); } } } /* throw damaged packets away, reset receive-buffer, indicate RX */ ptr = cs->rcvbuf; cs->rcvidx = 0; schedule_event(cs, D_RCVBUFREADY); } } /* Packet to long, overflow */ if(cs->rcvidx >= MAX_DFRAME_LEN_L1) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "AMD7930: empty_Dfifo L2-Framelength overrun"); cs->rcvidx = 0; return; } /* AMD interrupts on */ AmdIrqOn(cs); }
static void amd7930_Dchan_l2l1(struct PStack *st, int pr, void *arg) { struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; struct sk_buff *skb = arg; char str[64]; switch (pr) { case (PH_DATA_REQ): if (cs->tx_skb) { skb_queue_tail(&cs->sq, skb); #ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA Queued", 0); #endif } else { if ((cs->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */ LogFrame(cs, skb->data, skb->len); sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei); dlogframe(cs, skb->data+4, skb->len-4, str); } cs->tx_skb = skb; cs->tx_cnt = 0; #ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 0); #endif amd7930_dxmit(0, skb->data, skb->len, &amd7930_dxmit_callback, cs); } break; case (PH_PULL_IND): if (cs->tx_skb) { if (cs->debug & L1_DEB_WARN) debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); skb_queue_tail(&cs->sq, skb); break; } if ((cs->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */ LogFrame(cs, skb->data, skb->len); sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei); dlogframe(cs, skb->data + 4, skb->len - 4, str); } cs->tx_skb = skb; cs->tx_cnt = 0; #ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); #endif amd7930_dxmit(0, cs->tx_skb->data, cs->tx_skb->len, &amd7930_dxmit_callback, cs); break; case (PH_PULL_REQ): #ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL"); #endif if (!cs->tx_skb) { test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); st->l1.l1l2(st, PH_PULL_CNF, NULL); } else test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; } }
static irqreturn_t netjet_s_interrupt(int intno, void *dev_id, struct pt_regs *regs) { struct IsdnCardState *cs = dev_id; u_char val, s1val, s0val; u_long flags; spin_lock_irqsave(&cs->lock, flags); s1val = bytein(cs->hw.njet.base + NETJET_IRQSTAT1); if (!(s1val & NETJET_ISACIRQ)) { val = NETjet_ReadIC(cs, ISAC_ISTA); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "tiger: i1 %x %x", s1val, val); if (val) { isac_interrupt(cs, val); NETjet_WriteIC(cs, ISAC_MASK, 0xFF); NETjet_WriteIC(cs, ISAC_MASK, 0x0); } s1val = 1; } else s1val = 0; /* * read/write stat0 is better, because lower IRQ rate * Note the IRQ is on for 125 us if a condition match * thats long on modern CPU and so the IRQ is reentered * all the time. */ s0val = bytein(cs->hw.njet.base + NETJET_IRQSTAT0); if ((s0val | s1val)==0) { // shared IRQ spin_unlock_irqrestore(&cs->lock, flags); return IRQ_NONE; } if (s0val) byteout(cs->hw.njet.base + NETJET_IRQSTAT0, s0val); /* start new code 13/07/00 GE */ /* set bits in sval to indicate which page is free */ if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) < inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ)) /* the 2nd write page is free */ s0val = 0x08; else /* the 1st write page is free */ s0val = 0x04; if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) < inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ)) /* the 2nd read page is free */ s0val |= 0x02; else /* the 1st read page is free */ s0val |= 0x01; if (s0val != cs->hw.njet.last_is0) /* we have a DMA interrupt */ { if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { printk(KERN_WARNING "nj LOCK_ATOMIC s0val %x->%x\n", cs->hw.njet.last_is0, s0val); spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } cs->hw.njet.irqstat0 = s0val; if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) != (cs->hw.njet.last_is0 & NETJET_IRQM0_READ)) /* we have a read dma int */ read_tiger(cs); if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) != (cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE)) /* we have a write dma int */ write_tiger(cs); /* end new code 13/07/00 GE */ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; }
static struct sk_buff * hfc_empty_fifo(struct BCState *bcs, int count) { u_char *ptr; struct sk_buff *skb; struct IsdnCardState *cs = bcs->cs; int idx; int chksum; u_char stat, cip; if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) debugl1(cs, "hfc_empty_fifo"); idx = 0; if (count > HSCX_BUFMAX + 3) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "hfc_empty_fifo: incoming packet too large"); cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); while ((idx++ < count) && WaitNoBusy(cs)) cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); WaitNoBusy(cs); stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | HFC_CHANNEL(bcs->channel)); WaitForBusy(cs); return (NULL); } if ((count < 4) && (bcs->mode != L1_MODE_TRANS)) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "hfc_empty_fifo: incoming packet too small"); cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); while ((idx++ < count) && WaitNoBusy(cs)) cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); WaitNoBusy(cs); stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | HFC_CHANNEL(bcs->channel)); WaitForBusy(cs); #ifdef ERROR_STATISTIC bcs->err_inv++; #endif return (NULL); } if (bcs->mode == L1_MODE_TRANS) count -= 1; else count -= 3; if (!(skb = dev_alloc_skb(count))) printk(KERN_WARNING "HFC: receive out of memory\n"); else { ptr = skb_put(skb, count); idx = 0; cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); while ((idx < count) && WaitNoBusy(cs)) { *ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); idx++; } if (idx != count) { debugl1(cs, "RFIFO BUSY error"); printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel); dev_kfree_skb_any(skb); if (bcs->mode != L1_MODE_TRANS) { WaitNoBusy(cs); stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | HFC_CHANNEL(bcs->channel)); WaitForBusy(cs); } return (NULL); } if (bcs->mode != L1_MODE_TRANS) { WaitNoBusy(cs); chksum = (cs->BC_Read_Reg(cs, HFC_DATA, cip) << 8); WaitNoBusy(cs); chksum += cs->BC_Read_Reg(cs, HFC_DATA, cip); WaitNoBusy(cs); stat = cs->BC_Read_Reg(cs, HFC_DATA, cip); if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x", bcs->channel, chksum, stat); if (stat) { debugl1(cs, "FIFO CRC error"); dev_kfree_skb_any(skb); skb = NULL; #ifdef ERROR_STATISTIC bcs->err_crc++; #endif } WaitNoBusy(cs); stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | HFC_CHANNEL(bcs->channel)); WaitForBusy(cs); } } return (skb); }
static void hfc_fill_fifo(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; int idx, fcnt; int count; int z1, z2; u_char cip; if (!bcs->tx_skb) return; if (bcs->tx_skb->len <= 0) return; cip = HFC_CIP | HFC_F1 | HFC_SEND | HFC_CHANNEL(bcs->channel); if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) { cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip); WaitForBusy(cs); } WaitNoBusy(cs); if (bcs->mode != L1_MODE_TRANS) { bcs->hw.hfc.f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip); cip = HFC_CIP | HFC_F2 | HFC_SEND | HFC_CHANNEL(bcs->channel); WaitNoBusy(cs); bcs->hw.hfc.f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(bcs, HFC_Z1 | HFC_SEND | HFC_CHANNEL(bcs->channel)); if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)", bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2, bcs->hw.hfc.send[bcs->hw.hfc.f1]); fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2; if (fcnt < 0) fcnt += 32; if (fcnt > 30) { if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc_fill_fifo more as 30 frames"); return; } count = GetFreeFifoBytes(bcs); } else { WaitForBusy(cs); z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel)); z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel)); count = z1 - z2; if (count < 0) count += cs->hw.hfc.fifosize; } /* L1_MODE_TRANS */ if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc_fill_fifo %d count(%u/%d)", bcs->channel, bcs->tx_skb->len, count); if (count < bcs->tx_skb->len) { if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc_fill_fifo no fifo mem"); return; } cip = HFC_CIP | HFC_FIFO_IN | HFC_SEND | HFC_CHANNEL(bcs->channel); idx = 0; while ((idx < bcs->tx_skb->len) && WaitNoBusy(cs)) cs->BC_Write_Reg(cs, HFC_DATA_NODEB, cip, bcs->tx_skb->data[idx++]); if (idx != bcs->tx_skb->len) { debugl1(cs, "FIFO Send BUSY error"); printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel); } else { count = bcs->tx_skb->len; bcs->tx_cnt -= count; if (PACKET_NOACK == bcs->tx_skb->pkt_type) count = -1; dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; if (bcs->mode != L1_MODE_TRANS) { WaitForBusy(cs); WaitNoBusy(cs); cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel)); } if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && (count >= 0)) { u_long flags; spin_lock_irqsave(&bcs->aclock, flags); bcs->ackcnt += count; spin_unlock_irqrestore(&bcs->aclock, flags); schedule_event(bcs, B_ACKPENDING); } test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } return; }
int arcofi_fsm(struct IsdnCardState *cs, int event, void *data) { if (cs->debug & L1_DEB_MONITOR) { debugl1(cs, "arcofi state %d event %d", cs->dc.isac.arcofi_state, event); } if (event == ARCOFI_TIMEOUT) { cs->dc.isac.arcofi_state = ARCOFI_NOP; test_and_set_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags); wake_up(&cs->dc.isac.arcofi_wait); return(1); } switch (cs->dc.isac.arcofi_state) { case ARCOFI_NOP: if (event == ARCOFI_START) { cs->dc.isac.arcofi_list = data; cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT; send_arcofi(cs); } break; case ARCOFI_TRANSMIT: if (event == ARCOFI_TX_END) { if (cs->dc.isac.arcofi_list->receive) { add_arcofi_timer(cs); cs->dc.isac.arcofi_state = ARCOFI_RECEIVE; } else { if (cs->dc.isac.arcofi_list->next) { cs->dc.isac.arcofi_list = cs->dc.isac.arcofi_list->next; send_arcofi(cs); } else { if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) { del_timer(&cs->dc.isac.arcofitimer); } cs->dc.isac.arcofi_state = ARCOFI_NOP; wake_up(&cs->dc.isac.arcofi_wait); } } } break; case ARCOFI_RECEIVE: if (event == ARCOFI_RX_END) { if (cs->dc.isac.arcofi_list->next) { cs->dc.isac.arcofi_list = cs->dc.isac.arcofi_list->next; cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT; send_arcofi(cs); } else { if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) { del_timer(&cs->dc.isac.arcofitimer); } cs->dc.isac.arcofi_state = ARCOFI_NOP; wake_up(&cs->dc.isac.arcofi_wait); } } break; default: debugl1(cs, "Arcofi unknown state %x", cs->dc.isac.arcofi_state); return(2); } return(0); }
static inline void jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade) { u_char r; struct BCState *bcs = cs->bcs + jade; struct sk_buff *skb; int fifo_size = 32; int count; int i_jade = (int) jade; /* To satisfy the compiler */ if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return; if (val & 0x80) { /* RME */ r = READJADE(cs, i_jade, jade_HDLC_RSTA); if ((r & 0xf0) != 0xa0) { if (!(r & 0x80)) if (cs->debug & L1_DEB_WARN) debugl1(cs, "JADE %s invalid frame", (jade ? "B":"A")); if ((r & 0x40) && bcs->mode) if (cs->debug & L1_DEB_WARN) debugl1(cs, "JADE %c RDO mode=%d", 'A'+jade, bcs->mode); if (!(r & 0x20)) if (cs->debug & L1_DEB_WARN) debugl1(cs, "JADE %c CRC error", 'A'+jade); WriteJADECMDR(cs, jade, jade_HDLC_RCMD, jadeRCMD_RMC); } else { count = READJADE(cs, i_jade, jade_HDLC_RBCL) & 0x1F; if (count == 0) count = fifo_size; jade_empty_fifo(bcs, count); if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { if (cs->debug & L1_DEB_HSCX_FIFO) debugl1(cs, "HX Frame %d", count); if (!(skb = dev_alloc_skb(count))) printk(KERN_WARNING "JADE %s receive out of memory\n", (jade ? "B":"A")); else { memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count); skb_queue_tail(&bcs->rqueue, skb); } } } bcs->hw.hscx.rcvidx = 0; schedule_event(bcs, B_RCVBUFREADY); } if (val & 0x40) { /* RPF */ jade_empty_fifo(bcs, fifo_size); if (bcs->mode == L1_MODE_TRANS) { /* receive audio data */ if (!(skb = dev_alloc_skb(fifo_size))) printk(KERN_WARNING "HiSax: receive out of memory\n"); else { memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size); skb_queue_tail(&bcs->rqueue, skb); } bcs->hw.hscx.rcvidx = 0; schedule_event(bcs, B_RCVBUFREADY); } } if (val & 0x10) { /* XPR */ if (bcs->tx_skb) { if (bcs->tx_skb->len) { jade_fill_fifo(bcs); return; } else { if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && (PACKET_NOACK != bcs->tx_skb->pkt_type)) { u_long flags; spin_lock_irqsave(&bcs->aclock, flags); bcs->ackcnt += bcs->hw.hscx.count; spin_unlock_irqrestore(&bcs->aclock, flags); schedule_event(bcs, B_ACKPENDING); } dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.hscx.count = 0; bcs->tx_skb = NULL; } } if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { bcs->hw.hscx.count = 0; test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); jade_fill_fifo(bcs); } else { test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); schedule_event(bcs, B_XMTBUFREADY); } } }
static inline void hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) { u_char r; struct BCState *bcs = cs->bcs + hscx; struct sk_buff *skb; int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32; int count; if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return; if (val & 0x80) { /* RME */ r = READHSCX(cs, hscx, HSCX_RSTA); if ((r & 0xf0) != 0xa0) { if (!(r & 0x80)) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "HSCX invalid frame"); #ifdef ERROR_STATISTIC bcs->err_inv++; #endif } if ((r & 0x40) && bcs->mode) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "HSCX RDO mode=%d", bcs->mode); #ifdef ERROR_STATISTIC bcs->err_rdo++; #endif } if (!(r & 0x20)) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "HSCX CRC error"); #ifdef ERROR_STATISTIC bcs->err_crc++; #endif } WriteHSCXCMDR(cs, hscx, 0x80); } else { count = READHSCX(cs, hscx, HSCX_RBCL) & ( test_bit(HW_IPAC, &cs->HW_Flags)? 0x3f: 0x1f); if (count == 0) count = fifo_size; hscx_empty_fifo(bcs, count); if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { if (cs->debug & L1_DEB_HSCX_FIFO) debugl1(cs, "HX Frame %d", count); if (!(skb = dev_alloc_skb(count))) printk(KERN_WARNING "HSCX: receive out of memory\n"); else { memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count); skb_queue_tail(&bcs->rqueue, skb); } } } bcs->hw.hscx.rcvidx = 0; schedule_event(bcs, B_RCVBUFREADY); } if (val & 0x40) { /* RPF */ hscx_empty_fifo(bcs, fifo_size); if (bcs->mode == L1_MODE_TRANS) { /* receive audio data */ if (!(skb = dev_alloc_skb(fifo_size))) printk(KERN_WARNING "HiSax: receive out of memory\n"); else { memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size); skb_queue_tail(&bcs->rqueue, skb); } bcs->hw.hscx.rcvidx = 0; schedule_event(bcs, B_RCVBUFREADY); } } if (val & 0x10) { /* XPR */ if (bcs->tx_skb) { if (bcs->tx_skb->len) { hscx_fill_fifo(bcs); return; } else { if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && (PACKET_NOACK != bcs->tx_skb->pkt_type)) { u_long flags; spin_lock_irqsave(&bcs->aclock, flags); bcs->ackcnt += bcs->hw.hscx.count; spin_unlock_irqrestore(&bcs->aclock, flags); schedule_event(bcs, B_ACKPENDING); } dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.hscx.count = 0; bcs->tx_skb = NULL; } } if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { bcs->hw.hscx.count = 0; test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); hscx_fill_fifo(bcs); } else { test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); schedule_event(bcs, B_XMTBUFREADY); } } }
void icc_interrupt(struct IsdnCardState *cs, u_char val) { u_char exval, v1; struct sk_buff *skb; unsigned int count; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ICC interrupt %x", val); if (val & 0x80) { /* RME */ exval = cs->readisac(cs, ICC_RSTA); if ((exval & 0x70) != 0x20) { if (exval & 0x40) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "ICC RDO"); #ifdef ERROR_STATISTIC cs->err_rx++; #endif } if (!(exval & 0x20)) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "ICC CRC error"); #ifdef ERROR_STATISTIC cs->err_crc++; #endif } cs->writeisac(cs, ICC_CMDR, 0x80); } else { count = cs->readisac(cs, ICC_RBCL) & 0x1f; if (count == 0) count = 32; icc_empty_fifo(cs, count); if ((count = cs->rcvidx) > 0) { cs->rcvidx = 0; if (!(skb = alloc_skb(count, GFP_ATOMIC))) printk(KERN_WARNING "HiSax: D receive out of memory\n"); else { memcpy(skb_put(skb, count), cs->rcvbuf, count); skb_queue_tail(&cs->rq, skb); } } } cs->rcvidx = 0; schedule_event(cs, D_RCVBUFREADY); } if (val & 0x40) { /* RPF */ icc_empty_fifo(cs, 32); } if (val & 0x20) { /* RSC */ /* never */ if (cs->debug & L1_DEB_WARN) debugl1(cs, "ICC RSC interrupt"); } if (val & 0x10) { /* XPR */ 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) { icc_fill_fifo(cs); goto afterXPR; } else { dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } } if ((cs->tx_skb = skb_dequeue(&cs->sq))) { cs->tx_cnt = 0; icc_fill_fifo(cs); } else schedule_event(cs, D_XMTBUFREADY); } afterXPR: if (val & 0x04) { /* CISQ */ exval = cs->readisac(cs, ICC_CIR0); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ICC CIR0 %02X", exval ); if (exval & 2) { cs->dc.icc.ph_state = (exval >> 2) & 0xf; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ph_state change %x", cs->dc.icc.ph_state); schedule_event(cs, D_L1STATECHANGE); }
static void W6692_l1hw(struct PStack *st, int pr, void *arg) { struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; struct sk_buff *skb = arg; u_long flags; int val; 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, "PH_DATA Queued", 0); #endif } else { cs->tx_skb = skb; cs->tx_cnt = 0; #ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 0); #endif W6692_fill_fifo(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, " l2l1 tx_skb exist this shouldn't happen"); skb_queue_tail(&cs->sq, skb); spin_unlock_irqrestore(&cs->lock, flags); 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; #ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); #endif W6692_fill_fifo(cs); spin_unlock_irqrestore(&cs->lock, flags); break; case (PH_PULL | REQUEST): #ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL"); #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.w6692.ph_state == W_L1IND_DRD)) { ph_command(cs, W_L1CMD_ECK); spin_unlock_irqrestore(&cs->lock, flags); } else { ph_command(cs, W_L1CMD_RST); cs->dc.w6692.ph_state = W_L1CMD_RST; spin_unlock_irqrestore(&cs->lock, flags); W6692_new_ph(cs); } break; case (HW_ENABLE | REQUEST): spin_lock_irqsave(&cs->lock, flags); ph_command(cs, W_L1CMD_ECK); spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_INFO3 | REQUEST): spin_lock_irqsave(&cs->lock, flags); ph_command(cs, W_L1CMD_AR8); spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_TESTLOOP | REQUEST): val = 0; if (1 & (long) arg) val |= 0x0c; if (2 & (long) arg) val |= 0x3; /* !!! 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_any(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, "W6692_l1hw unknown %04x", pr); break; } }
void hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val) { u_char exval; struct BCState *bcs; int count=15; long flags; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "HFCD irq %x %s", val, test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ? "locked" : "unlocked"); val &= cs->hw.hfcD.int_m1; if (val & 0x40) { /* TE state machine irq */ exval = cs->readisac(cs, HFCD_STATES) & 0xf; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcd.ph_state, exval); cs->dc.hfcd.ph_state = exval; sched_event_D(cs, D_L1STATECHANGE); val &= ~0x40; } while (val) { save_flags(flags); cli(); if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { cs->hw.hfcD.int_s1 |= val; restore_flags(flags); return; } if (cs->hw.hfcD.int_s1 & 0x18) { exval = val; val = cs->hw.hfcD.int_s1; cs->hw.hfcD.int_s1 = exval; } if (val & 0x08) { if (!(bcs=Sel_BCS(cs, 0))) { if (cs->debug) debugl1(cs, "hfcd spurious 0x08 IRQ"); } else main_rec_2bds0(bcs); } if (val & 0x10) { if (!(bcs=Sel_BCS(cs, 1))) { if (cs->debug) debugl1(cs, "hfcd spurious 0x10 IRQ"); } else main_rec_2bds0(bcs); } if (val & 0x01) { if (!(bcs=Sel_BCS(cs, 0))) { if (cs->debug) debugl1(cs, "hfcd spurious 0x01 IRQ"); } else { if (bcs->tx_skb) { if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfc_fill_fifo(bcs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } else debugl1(cs,"fill_data %d blocked", bcs->channel); } else { if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfc_fill_fifo(bcs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } else debugl1(cs,"fill_data %d blocked", bcs->channel); } else { hfc_sched_event(bcs, B_XMTBUFREADY); } } } } if (val & 0x02) { if (!(bcs=Sel_BCS(cs, 1))) { if (cs->debug) debugl1(cs, "hfcd spurious 0x02 IRQ"); } else { if (bcs->tx_skb) { if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfc_fill_fifo(bcs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } else debugl1(cs,"fill_data %d blocked", bcs->channel); } else { if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfc_fill_fifo(bcs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } else debugl1(cs,"fill_data %d blocked", bcs->channel); } else { hfc_sched_event(bcs, B_XMTBUFREADY); } } } } if (val & 0x20) { /* receive dframe */ receive_dmsg(cs); } if (val & 0x04) { /* dframe transmitted */ 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)) sched_event_D(cs, D_CLEARBUSY); if (cs->tx_skb) { if (cs->tx_skb->len) { if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfc_fill_dfifo(cs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } else { debugl1(cs, "hfc_fill_dfifo irq blocked"); } goto afterXPR; } else { dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } } if ((cs->tx_skb = skb_dequeue(&cs->sq))) { cs->tx_cnt = 0; if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfc_fill_dfifo(cs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } else { debugl1(cs, "hfc_fill_dfifo irq blocked"); } } else sched_event_D(cs, D_XMTBUFREADY); } afterXPR: if (cs->hw.hfcD.int_s1 && count--) { val = cs->hw.hfcD.int_s1; cs->hw.hfcD.int_s1 = 0; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "HFCD irq %x loop %d", val, 15-count); } else val = 0; restore_flags(flags); } }
void main_irq_hfc(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; int z1, z2, rcnt; u_char f1, f2, cip; int receive, transmit, count = 5; struct sk_buff *skb; Begin: count--; cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel); if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) { cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip); WaitForBusy(cs); } WaitNoBusy(cs); receive = 0; if (bcs->mode == L1_MODE_HDLC) { f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip); cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel); WaitNoBusy(cs); f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); if (f1 != f2) { if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc rec %d f1(%d) f2(%d)", bcs->channel, f1, f2); receive = 1; } } if (receive || (bcs->mode == L1_MODE_TRANS)) { WaitForBusy(cs); z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel)); z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel)); rcnt = z1 - z2; if (rcnt < 0) rcnt += cs->hw.hfc.fifosize; if ((bcs->mode == L1_MODE_HDLC) || (rcnt)) { rcnt++; if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)", bcs->channel, z1, z2, rcnt); /* sti(); */ if ((skb = hfc_empty_fifo(bcs, rcnt))) { skb_queue_tail(&bcs->rqueue, skb); schedule_event(bcs, B_RCVBUFREADY); } } receive = 1; } if (bcs->tx_skb) { transmit = 1; test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); hfc_fill_fifo(bcs); if (test_bit(BC_FLG_BUSY, &bcs->Flag)) transmit = 0; } else { if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { transmit = 1; test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); hfc_fill_fifo(bcs); if (test_bit(BC_FLG_BUSY, &bcs->Flag)) transmit = 0; } else { transmit = 0; schedule_event(bcs, B_XMTBUFREADY); } } if ((receive || transmit) && count) goto Begin; return; }
static void Bchan_rcv_bh(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; struct amd7930_hw *hw = &bcs->hw.amd7930; struct sk_buff *skb; int len; if (cs->debug & L1_DEB_HSCX) { char tmp[1024]; sprintf(tmp, "amd7930_Bchan_rcv (%d/%d)", hw->rv_buff_in, hw->rv_buff_out); debugl1(cs, tmp); QuickHex(tmp, hw->rv_buff + hw->rv_buff_out, RCV_BUFSIZE/RCV_BUFBLKS); debugl1(cs, tmp); } do { if (bcs->mode == L1_MODE_HDLC) { while ((len = read_raw_hdlc_data(hw->hdlc_state, hw->rv_buff + hw->rv_buff_out, RCV_BUFSIZE/RCV_BUFBLKS, hw->rv_skb->tail, HSCX_BUFMAX))) { if (len > 0 && (cs->debug & L1_DEB_HSCX_FIFO)) { char tmp[1024]; char *t = tmp; t += sprintf(t, "amd7930_Bchan_rcv %c cnt %d", bcs->channel ? 'B' : 'A', len); QuickHex(t, hw->rv_skb->tail, len); debugl1(cs, tmp); } if (len > HSCX_BUFMAX/2) { /* Large packet received */ if (!(skb = dev_alloc_skb(HSCX_BUFMAX))) { printk(KERN_WARNING "amd7930: receive out of memory"); } else { skb_put(hw->rv_skb, len); skb_queue_tail(&bcs->rqueue, hw->rv_skb); hw->rv_skb = skb; bcs->event |= 1 << B_RCVBUFREADY; queue_task(&bcs->tqueue, &tq_immediate); } } else if (len > 0) { /* Small packet received */ if (!(skb = dev_alloc_skb(len))) { printk(KERN_WARNING "amd7930: receive out of memory\n"); } else { memcpy(skb_put(skb, len), hw->rv_skb->tail, len); skb_queue_tail(&bcs->rqueue, skb); bcs->event |= 1 << B_RCVBUFREADY; queue_task(&bcs->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH); } } else { /* Reception Error */ /* printk("amd7930: B channel receive error\n"); */ } } } else if (bcs->mode == L1_MODE_TRANS) { if (!(skb = dev_alloc_skb(RCV_BUFSIZE/RCV_BUFBLKS))) { printk(KERN_WARNING "amd7930: receive out of memory\n"); } else { memcpy(skb_put(skb, RCV_BUFSIZE/RCV_BUFBLKS), hw->rv_buff + hw->rv_buff_out, RCV_BUFSIZE/RCV_BUFBLKS); skb_queue_tail(&bcs->rqueue, skb); bcs->event |= 1 << B_RCVBUFREADY; queue_task(&bcs->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH); } } if (hw->rv_buff_in == hw->rv_buff_out) { /* Buffer was filled up - need to restart receiver */ amd7930_brecv(0, bcs->channel, hw->rv_buff + hw->rv_buff_in, RCV_BUFSIZE/RCV_BUFBLKS, (void *) &Bchan_recv_callback, (void *) bcs); } hw->rv_buff_out += RCV_BUFSIZE/RCV_BUFBLKS; hw->rv_buff_out %= RCV_BUFSIZE; } while (hw->rv_buff_in != hw->rv_buff_out); }
static void HFCD_l1hw(struct PStack *st, int pr, void *arg) { struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; struct sk_buff *skb = arg; 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); if (cs->tx_skb) { skb_queue_tail(&cs->sq, skb); #ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA Queued", 0); #endif } else { cs->tx_skb = skb; cs->tx_cnt = 0; #ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 0); #endif if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfc_fill_dfifo(cs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } else debugl1(cs, "hfc_fill_dfifo blocked"); } break; case (PH_PULL | INDICATION): if (cs->tx_skb) { if (cs->debug & L1_DEB_WARN) debugl1(cs, " 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; #ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); #endif if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfc_fill_dfifo(cs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } else debugl1(cs, "hfc_fill_dfifo blocked"); break; case (PH_PULL | REQUEST): #ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL"); #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): cs->writeisac(cs, HFCD_STATES, HFCD_LOAD_STATE | 3); /* HFC ST 3 */ udelay(6); cs->writeisac(cs, HFCD_STATES, 3); /* HFC ST 2 */ cs->hw.hfcD.mst_m |= HFCD_MASTER; cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION); l1_msg(cs, HW_POWERUP | CONFIRM, NULL); break; case (HW_ENABLE | REQUEST): cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION); break; case (HW_DEACTIVATE | REQUEST): cs->hw.hfcD.mst_m &= ~HFCD_MASTER; cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); break; case (HW_INFO3 | REQUEST): cs->hw.hfcD.mst_m |= HFCD_MASTER; cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); break; default: if (cs->debug & L1_DEB_WARN) debugl1(cs, "hfcd_l1hw unknown pr %4x", pr); break; } }
void DChannel_proc_rcv(struct IsdnCardState *cs) { struct sk_buff *skb, *nskb; struct PStack *stptr = cs->stlist; int found, tei, sapi; if (stptr) if (test_bit(FLG_L1_ACTTIMER, &stptr->l1.Flags)) FsmEvent(&stptr->l1.l1m, EV_TIMER_ACT, NULL); while ((skb = skb_dequeue(&cs->rq))) { #ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 1); #endif stptr = cs->stlist; if (skb->len<3) { debugl1(cs, "D-channel frame too short(%d)",skb->len); dev_kfree_skb(skb); return; } if ((skb->data[0] & 1) || !(skb->data[1] &1)) { debugl1(cs, "D-channel frame wrong EA0/EA1"); dev_kfree_skb(skb); return; } sapi = skb->data[0] >> 2; tei = skb->data[1] >> 1; if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len); if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 1); if (tei == GROUP_TEI) { if (sapi == CTRL_SAPI) { /* sapi 0 */ while (stptr != NULL) { if ((nskb = skb_clone(skb, GFP_ATOMIC))) stptr->l1.l1l2(stptr, PH_DATA | INDICATION, nskb); else printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n"); stptr = stptr->next; } } else if (sapi == TEI_SAPI) { while (stptr != NULL) { if ((nskb = skb_clone(skb, GFP_ATOMIC))) stptr->l1.l1tei(stptr, PH_DATA | INDICATION, nskb); else printk(KERN_WARNING "HiSax: tei broadcast buffer shortage\n"); stptr = stptr->next; } } dev_kfree_skb(skb); } else if (sapi == CTRL_SAPI) { /* sapi 0 */ found = 0; while (stptr != NULL) if (tei == stptr->l2.tei) { stptr->l1.l1l2(stptr, PH_DATA | INDICATION, skb); found = !0; break; } else stptr = stptr->next; if (!found) dev_kfree_skb(skb); } else dev_kfree_skb(skb); } }
static struct sk_buff *hfc_empty_fifo(struct BCState *bcs, int count) { u_char *ptr; struct sk_buff *skb; struct IsdnCardState *cs = bcs->cs; int idx; int chksum; long flags; u_char stat, cip; if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) debugl1(cs, "hfc_empty_fifo"); idx = 0; save_flags(flags); if (count > HSCX_BUFMAX + 3) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "hfc_empty_fifo: incoming packet too large"); cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel); while (idx++ < count) { cli(); WaitNoBusy(cs); ReadReg(cs, HFCD_DATA_NODEB, cip); sti(); } skb = NULL; } else if (count < 4) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "hfc_empty_fifo: incoming packet too small"); cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel); #ifdef ERROR_STATISTIC bcs->err_inv++; #endif cli(); while ((idx++ < count) && WaitNoBusy(cs)) ReadReg(cs, HFCD_DATA_NODEB, cip); skb = NULL; } else if (!(skb = dev_alloc_skb(count - 3))) printk(KERN_WARNING "HFC: receive out of memory\n"); else { ptr = skb_put(skb, count - 3); idx = 0; cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel); cli(); while (idx < (count - 3)) { cli(); if (!WaitNoBusy(cs)) break; *ptr = ReadReg(cs, HFCD_DATA_NODEB, cip); sti(); ptr++; idx++; } if (idx != count - 3) { sti(); debugl1(cs, "RFIFO BUSY error"); printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel); dev_kfree_skb_irq(skb); skb = NULL; } else { cli(); WaitNoBusy(cs); chksum = (ReadReg(cs, HFCD_DATA, cip) << 8); WaitNoBusy(cs); chksum += ReadReg(cs, HFCD_DATA, cip); WaitNoBusy(cs); stat = ReadReg(cs, HFCD_DATA, cip); sti(); if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x", bcs->channel, chksum, stat); if (stat) { debugl1(cs, "FIFO CRC error"); dev_kfree_skb_irq(skb); skb = NULL; #ifdef ERROR_STATISTIC bcs->err_crc++; #endif } } } sti(); WaitForBusy(cs); cli(); WaitNoBusy(cs); stat = ReadReg(cs, HFCD_DATA, HFCB_FIFO | HFCB_F2_INC | HFCB_REC | HFCB_CHANNEL(bcs->channel)); sti(); WaitForBusy(cs); restore_flags(flags); return (skb); }
static inline void Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) { u_char r; struct BCState *bcs = cs->bcs + hscx; struct sk_buff *skb; int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32; int count; if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return; if (val & 0x80) { /* RME */ r = MemReadHSCX(cs, hscx, HSCX_RSTA); if ((r & 0xf0) != 0xa0) { if (!(r & 0x80)) if (cs->debug & L1_DEB_WARN) debugl1(cs, "HSCX invalid frame"); if ((r & 0x40) && bcs->mode) if (cs->debug & L1_DEB_WARN) debugl1(cs, "HSCX RDO mode=%d", bcs->mode); if (!(r & 0x20)) if (cs->debug & L1_DEB_WARN) debugl1(cs, "HSCX CRC error"); MemWriteHSCXCMDR(cs, hscx, 0x80); } else { count = MemReadHSCX(cs, hscx, HSCX_RBCL) & ( test_bit(HW_IPAC, &cs->HW_Flags)? 0x3f: 0x1f); if (count == 0) count = fifo_size; Memhscx_empty_fifo(bcs, count); if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { if (cs->debug & L1_DEB_HSCX_FIFO) debugl1(cs, "HX Frame %d", count); if (!(skb = dev_alloc_skb(count))) printk(KERN_WARNING "HSCX: receive out of memory\n"); else { memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count); skb_queue_tail(&bcs->rqueue, skb); } } } bcs->hw.hscx.rcvidx = 0; hscx_sched_event(bcs, B_RCVBUFREADY); } if (val & 0x40) { /* RPF */ Memhscx_empty_fifo(bcs, fifo_size); if (bcs->mode == L1_MODE_TRANS) { /* receive audio data */ if (!(skb = dev_alloc_skb(fifo_size))) printk(KERN_WARNING "HiSax: receive out of memory\n"); else { memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size); skb_queue_tail(&bcs->rqueue, skb); } bcs->hw.hscx.rcvidx = 0; hscx_sched_event(bcs, B_RCVBUFREADY); } } if (val & 0x10) { /* XPR */ if (bcs->tx_skb) { if (bcs->tx_skb->len) { Memhscx_fill_fifo(bcs); return; } else { if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.hscx.count = 0; bcs->tx_skb = NULL; } } if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { bcs->hw.hscx.count = 0; test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); Memhscx_fill_fifo(bcs); } else { test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); hscx_sched_event(bcs, B_XMTBUFREADY); } } }
static void hfc_fill_fifo(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; long flags; int idx, fcnt; int count; u_char cip; if (!bcs->tx_skb) return; if (bcs->tx_skb->len <= 0) return; save_flags(flags); cli(); SelFiFo(cs, HFCB_SEND | HFCB_CHANNEL(bcs->channel)); cip = HFCB_FIFO | HFCB_F1 | HFCB_SEND | HFCB_CHANNEL(bcs->channel); WaitNoBusy(cs); bcs->hw.hfc.f1 = ReadReg(cs, HFCD_DATA, cip); WaitNoBusy(cs); cip = HFCB_FIFO | HFCB_F2 | HFCB_SEND | HFCB_CHANNEL(bcs->channel); WaitNoBusy(cs); bcs->hw.hfc.f2 = ReadReg(cs, HFCD_DATA, cip); bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_CHANNEL(bcs->channel)); sti(); if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)", bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2, bcs->hw.hfc.send[bcs->hw.hfc.f1]); fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2; if (fcnt < 0) fcnt += 32; if (fcnt > 30) { if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc_fill_fifo more as 30 frames"); restore_flags(flags); return; } count = GetFreeFifoBytes_B(bcs); if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc_fill_fifo %d count(%ld/%d),%lx", bcs->channel, bcs->tx_skb->len, count, current->state); if (count < bcs->tx_skb->len) { if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc_fill_fifo no fifo mem"); restore_flags(flags); return; } cip = HFCB_FIFO | HFCB_FIFO_IN | HFCB_SEND | HFCB_CHANNEL(bcs->channel); idx = 0; cli(); WaitForBusy(cs); WaitNoBusy(cs); WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->tx_skb->data[idx++]); while (idx < bcs->tx_skb->len) { cli(); if (!WaitNoBusy(cs)) break; WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->tx_skb->data[idx]); sti(); idx++; } if (idx != bcs->tx_skb->len) { sti(); debugl1(cs, "FIFO Send BUSY error"); printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel); } else { bcs->tx_cnt -= bcs->tx_skb->len; if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; } WaitForBusy(cs); cli(); WaitNoBusy(cs); ReadReg(cs, HFCD_DATA, HFCB_FIFO | HFCB_F1_INC | HFCB_SEND | HFCB_CHANNEL(bcs->channel)); sti(); WaitForBusy(cs); test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); restore_flags(flags); return; }
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; } }
void main_rec_2bds0(struct BCState *bcs) { long flags; struct IsdnCardState *cs = bcs->cs; int z1, z2, rcnt; u_char f1, f2, cip; int receive, count = 5; struct sk_buff *skb; save_flags(flags); Begin: count--; cli(); if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { debugl1(cs,"rec_data %d blocked", bcs->channel); restore_flags(flags); return; } SelFiFo(cs, HFCB_REC | HFCB_CHANNEL(bcs->channel)); cip = HFCB_FIFO | HFCB_F1 | HFCB_REC | HFCB_CHANNEL(bcs->channel); WaitNoBusy(cs); f1 = ReadReg(cs, HFCD_DATA, cip); cip = HFCB_FIFO | HFCB_F2 | HFCB_REC | HFCB_CHANNEL(bcs->channel); WaitNoBusy(cs); f2 = ReadReg(cs, HFCD_DATA, cip); sti(); if (f1 != f2) { if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc rec %d f1(%d) f2(%d)", bcs->channel, f1, f2); cli(); z1 = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_CHANNEL(bcs->channel)); z2 = ReadZReg(cs, HFCB_FIFO | HFCB_Z2 | HFCB_REC | HFCB_CHANNEL(bcs->channel)); sti(); rcnt = z1 - z2; if (rcnt < 0) rcnt += cs->hw.hfcD.bfifosize; rcnt++; if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)", bcs->channel, z1, z2, rcnt); if ((skb = hfc_empty_fifo(bcs, rcnt))) { cli(); skb_queue_tail(&bcs->rqueue, skb); sti(); hfc_sched_event(bcs, B_RCVBUFREADY); } rcnt = f1 -f2; if (rcnt<0) rcnt += 32; if (rcnt>1) receive = 1; else receive = 0; } else receive = 0; test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); if (count && receive) goto Begin; restore_flags(flags); return; }
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 int receive_dmsg(struct IsdnCardState *cs) { struct sk_buff *skb; long flags; int idx; int rcnt, z1, z2; u_char stat, cip, f1, f2; int chksum; int count=5; u_char *ptr; save_flags(flags); cli(); if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { debugl1(cs, "rec_dmsg blocked"); restore_flags(flags); return(1); } SelFiFo(cs, 4 | HFCD_REC); cip = HFCD_FIFO | HFCD_F1 | HFCD_REC; WaitNoBusy(cs); f1 = cs->readisac(cs, cip) & 0xf; cip = HFCD_FIFO | HFCD_F2 | HFCD_REC; WaitNoBusy(cs); f2 = cs->readisac(cs, cip) & 0xf; while ((f1 != f2) && count--) { z1 = ReadZReg(cs, HFCD_FIFO | HFCD_Z1 | HFCD_REC); z2 = ReadZReg(cs, HFCD_FIFO | HFCD_Z2 | HFCD_REC); rcnt = z1 - z2; if (rcnt < 0) rcnt += cs->hw.hfcD.dfifosize; rcnt++; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "hfcd recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)", f1, f2, z1, z2, rcnt); sti(); idx = 0; cip = HFCD_FIFO | HFCD_FIFO_OUT | HFCD_REC; if (rcnt > MAX_DFRAME_LEN + 3) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "empty_fifo d: incoming packet too large"); while (idx < rcnt) { cli(); if (!(WaitNoBusy(cs))) break; ReadReg(cs, HFCD_DATA_NODEB, cip); sti(); idx++; } } else if (rcnt < 4) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "empty_fifo d: incoming packet too small"); cli(); while ((idx++ < rcnt) && WaitNoBusy(cs)) ReadReg(cs, HFCD_DATA_NODEB, cip); } else if ((skb = dev_alloc_skb(rcnt - 3))) { ptr = skb_put(skb, rcnt - 3); while (idx < (rcnt - 3)) { cli(); if (!(WaitNoBusy(cs))) break; *ptr = ReadReg(cs, HFCD_DATA_NODEB, cip); sti(); idx++; ptr++; } if (idx != (rcnt - 3)) { sti(); debugl1(cs, "RFIFO D BUSY error"); printk(KERN_WARNING "HFC DFIFO channel BUSY Error\n"); dev_kfree_skb_irq(skb); skb = NULL; #ifdef ERROR_STATISTIC cs->err_rx++; #endif } else { cli(); WaitNoBusy(cs); chksum = (ReadReg(cs, HFCD_DATA, cip) << 8); WaitNoBusy(cs); chksum += ReadReg(cs, HFCD_DATA, cip); WaitNoBusy(cs); stat = ReadReg(cs, HFCD_DATA, cip); sti(); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "empty_dfifo chksum %x stat %x", chksum, stat); if (stat) { debugl1(cs, "FIFO CRC error"); dev_kfree_skb_irq(skb); skb = NULL; #ifdef ERROR_STATISTIC cs->err_crc++; #endif } else { skb_queue_tail(&cs->rq, skb); sched_event_D(cs, D_RCVBUFREADY); } } } else printk(KERN_WARNING "HFC: D receive out of memory\n"); sti(); WaitForBusy(cs); cip = HFCD_FIFO | HFCD_F2_INC | HFCD_REC; cli(); WaitNoBusy(cs); stat = ReadReg(cs, HFCD_DATA, cip); sti(); WaitForBusy(cs); cip = HFCD_FIFO | HFCD_F2 | HFCD_REC; cli(); WaitNoBusy(cs); f2 = cs->readisac(cs, cip) & 0xf; } test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); restore_flags(flags); return(1); }
static void Amd7930_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); spin_unlock_irqrestore(&cs->lock, flags); 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 void hfc_fill_dfifo(struct IsdnCardState *cs) { long flags; int idx, fcnt; int count; u_char cip; if (!cs->tx_skb) return; if (cs->tx_skb->len <= 0) return; save_flags(flags); cli(); SelFiFo(cs, 4 | HFCD_SEND); cip = HFCD_FIFO | HFCD_F1 | HFCD_SEND; WaitNoBusy(cs); cs->hw.hfcD.f1 = ReadReg(cs, HFCD_DATA, cip) & 0xf; WaitNoBusy(cs); cip = HFCD_FIFO | HFCD_F2 | HFCD_SEND; cs->hw.hfcD.f2 = ReadReg(cs, HFCD_DATA, cip) & 0xf; cs->hw.hfcD.send[cs->hw.hfcD.f1] = ReadZReg(cs, HFCD_FIFO | HFCD_Z1 | HFCD_SEND); sti(); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "hfc_fill_Dfifo f1(%d) f2(%d) z1(%x)", cs->hw.hfcD.f1, cs->hw.hfcD.f2, cs->hw.hfcD.send[cs->hw.hfcD.f1]); fcnt = cs->hw.hfcD.f1 - cs->hw.hfcD.f2; if (fcnt < 0) fcnt += 16; if (fcnt > 14) { if (cs->debug & L1_DEB_HSCX) debugl1(cs, "hfc_fill_Dfifo more as 14 frames"); restore_flags(flags); return; } count = GetFreeFifoBytes_D(cs); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "hfc_fill_Dfifo count(%ld/%d)", cs->tx_skb->len, count); if (count < cs->tx_skb->len) { if (cs->debug & L1_DEB_ISAC) debugl1(cs, "hfc_fill_Dfifo no fifo mem"); restore_flags(flags); return; } cip = HFCD_FIFO | HFCD_FIFO_IN | HFCD_SEND; idx = 0; cli(); WaitForBusy(cs); WaitNoBusy(cs); WriteReg(cs, HFCD_DATA_NODEB, cip, cs->tx_skb->data[idx++]); while (idx < cs->tx_skb->len) { cli(); if (!(WaitNoBusy(cs))) break; WriteReg(cs, HFCD_DATA_NODEB, cip, cs->tx_skb->data[idx]); sti(); idx++; } if (idx != cs->tx_skb->len) { sti(); debugl1(cs, "DFIFO Send BUSY error"); printk(KERN_WARNING "HFC S DFIFO channel BUSY Error\n"); } WaitForBusy(cs); cli(); WaitNoBusy(cs); ReadReg(cs, HFCD_DATA, HFCD_FIFO | HFCD_F1_INC | HFCD_SEND); dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; sti(); WaitForBusy(cs); restore_flags(flags); return; }
static int enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg) { u_long flags; unsigned char *chan; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "enter:now PCI: card_msg: 0x%04X", mt); switch (mt) { case CARD_RESET: spin_lock_irqsave(&cs->lock, flags); reset_enpci(cs); Amd7930_init(cs); spin_unlock_irqrestore(&cs->lock, flags); break; case CARD_RELEASE: release_io_netjet(cs); break; case CARD_INIT: reset_enpci(cs); inittiger(cs); /* irq must be on here */ Amd7930_init(cs); break; case CARD_TEST: break; case MDL_ASSIGN: /* TEI assigned, LED1 on */ cs->hw.njet.auxd = TJ_AMD_IRQ << 1; outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA); break; case MDL_REMOVE: /* TEI removed, LEDs off */ cs->hw.njet.auxd = 0; outb(0x00, cs->hw.njet.base + NETJET_AUXDATA); break; case MDL_BC_ASSIGN: /* activate B-channel */ chan = (unsigned char *)arg; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "enter:now PCI: assign phys. BC %d in AMD LMR1", *chan); cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 | (*chan + 1)), "MDL_BC_ASSIGN"); /* at least one b-channel in use, LED 2 on */ cs->hw.njet.auxd |= TJ_AMD_IRQ << 2; outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA); break; case MDL_BC_RELEASE: /* deactivate B-channel */ chan = (unsigned char *)arg; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "enter:now PCI: release phys. BC %d in Amd LMR1", *chan); cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 & ~(*chan + 1)), "MDL_BC_RELEASE"); /* no b-channel active -> LED2 off */ if (!(cs->dc.amd7930.lmr1 & 3)) { cs->hw.njet.auxd &= ~(TJ_AMD_IRQ << 2); outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA); } break; default: break; } return(0); }
static void W6692B_interrupt(struct IsdnCardState *cs, u_char bchan) { u_char val; u_char r; struct BCState *bcs; struct sk_buff *skb; int count; bcs = (cs->bcs->channel == bchan) ? cs->bcs : (cs->bcs+1); val = cs->BC_Read_Reg(cs, bchan, W_B_EXIR); debugl1(cs, "W6692B chan %d B_EXIR 0x%02X", bchan, val); if (!test_bit(BC_FLG_INIT, &bcs->Flag)) { debugl1(cs, "W6692B not INIT yet"); return; } if (val & W_B_EXI_RME) { /* RME */ r = cs->BC_Read_Reg(cs, bchan, W_B_STAR); if (r & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692 B STAR %x", r); if ((r & W_B_STAR_RDOV) && bcs->mode) if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692 B RDOV mode=%d", bcs->mode); if (r & W_B_STAR_CRCE) if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692 B CRC error"); cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT); } else { count = cs->BC_Read_Reg(cs, bchan, W_B_RBCL) & (W_B_FIFO_THRESH - 1); if (count == 0) count = W_B_FIFO_THRESH; W6692B_empty_fifo(bcs, count); if ((count = bcs->hw.w6692.rcvidx) > 0) { if (cs->debug & L1_DEB_HSCX_FIFO) debugl1(cs, "W6692 Bchan Frame %d", count); if (!(skb = dev_alloc_skb(count))) printk(KERN_WARNING "W6692: Bchan receive out of memory\n"); else { memcpy(skb_put(skb, count), bcs->hw.w6692.rcvbuf, count); skb_queue_tail(&bcs->rqueue, skb); } } } bcs->hw.w6692.rcvidx = 0; schedule_event(bcs, B_RCVBUFREADY); } if (val & W_B_EXI_RMR) { /* RMR */ W6692B_empty_fifo(bcs, W_B_FIFO_THRESH); r = cs->BC_Read_Reg(cs, bchan, W_B_STAR); if (r & W_B_STAR_RDOV) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692 B RDOV(RMR) mode=%d",bcs->mode); cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT); if (bcs->mode != L1_MODE_TRANS) bcs->hw.w6692.rcvidx = 0; } if (bcs->mode == L1_MODE_TRANS) { /* receive audio data */ if (!(skb = dev_alloc_skb(W_B_FIFO_THRESH))) printk(KERN_WARNING "HiSax: receive out of memory\n"); else { memcpy(skb_put(skb, W_B_FIFO_THRESH), bcs->hw.w6692.rcvbuf, W_B_FIFO_THRESH); skb_queue_tail(&bcs->rqueue, skb); } bcs->hw.w6692.rcvidx = 0; schedule_event(bcs, B_RCVBUFREADY); } } if (val & W_B_EXI_XDUN) { /* XDUN */ cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692 B EXIR %x Lost TX", val); if (bcs->mode == 1) W6692B_fill_fifo(bcs); else { /* Here we lost an TX interrupt, so * restart transmitting the whole frame. */ if (bcs->tx_skb) { skb_push(bcs->tx_skb, bcs->hw.w6692.count); bcs->tx_cnt += bcs->hw.w6692.count; bcs->hw.w6692.count = 0; } } return; } if (val & W_B_EXI_XFR) { /* XFR */ r = cs->BC_Read_Reg(cs, bchan, W_B_STAR); if (r & W_B_STAR_XDOW) { if (cs->debug & L1_DEB_WARN) debugl1(cs, "W6692 B STAR %x XDOW", r); cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); if (bcs->tx_skb && (bcs->mode != 1)) { skb_push(bcs->tx_skb, bcs->hw.w6692.count); bcs->tx_cnt += bcs->hw.w6692.count; bcs->hw.w6692.count = 0; } } if (bcs->tx_skb) { if (bcs->tx_skb->len) { W6692B_fill_fifo(bcs); return; } else { if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && (PACKET_NOACK != bcs->tx_skb->pkt_type)) { u_long flags; spin_lock_irqsave(&bcs->aclock, flags); bcs->ackcnt += bcs->hw.w6692.count; spin_unlock_irqrestore(&bcs->aclock, flags); schedule_event(bcs, B_ACKPENDING); } dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.w6692.count = 0; bcs->tx_skb = NULL; } } if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { bcs->hw.w6692.count = 0; test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); W6692B_fill_fifo(bcs); } else { test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); schedule_event(bcs, B_XMTBUFREADY); } } }