static int MIXCOM_send_packet(struct net_device *dev, struct sk_buff *skb) { struct comx_channel *ch = dev->priv; struct mixcom_privdata *hw = ch->HW_privdata; unsigned long flags; if (ch->debug_flags & DEBUG_HW_TX) { comx_debug_bytes(dev, skb->data, skb->len, "MIXCOM_send_packet"); } if (!(ch->line_status & LINE_UP)) { return FRAME_DROPPED; } if (skb->len > HSCX_MTU) { ch->stats.tx_errors++; return FRAME_ERROR; } save_flags(flags); cli(); if (test_and_set_bit(0, &hw->txbusy)) { printk(KERN_ERR "%s: transmitter called while busy... dropping frame (length %d)\n", dev->name, skb->len); restore_flags(flags); return FRAME_DROPPED; } hw->sending = skb; hw->tx_ptr = 0; hw->txbusy = 1; // atomic_inc(&skb->users); // save it hscx_fill_fifo(dev); restore_flags(flags); ch->stats.tx_packets++; ch->stats.tx_bytes += skb->len; if (ch->debug_flags & DEBUG_HW_TX) { comx_debug(dev, "MIXCOM_send_packet was successful\n\n"); } return FRAME_ACCEPTED; }
static inline void hscx_int_main(struct IsdnCardState *cs, u_char val) { u_char exval; struct BCState *bcs; if (val & 0x01) { bcs = cs->bcs + 1; exval = READHSCX(cs, 1, HSCX_EXIR); if (exval & 0x40) { if (bcs->mode == 1) hscx_fill_fifo(bcs); else { #ifdef ERROR_STATISTIC bcs->err_tx++; #endif /* 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; } WriteHSCXCMDR(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); hscx_interrupt(cs, val, 1); } if (val & 0x02) { bcs = cs->bcs; exval = READHSCX(cs, 0, HSCX_EXIR); if (exval & 0x40) { if (bcs->mode == L1_MODE_TRANS) hscx_fill_fifo(bcs); else { /* Here we lost an TX interrupt, so * restart transmitting the whole frame. */ #ifdef ERROR_STATISTIC bcs->err_tx++; #endif 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; } WriteHSCXCMDR(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 = READHSCX(cs, 0, HSCX_ISTA); if (cs->debug & L1_DEB_HSCX) debugl1(cs, "HSCX A interrupt %x", exval); hscx_interrupt(cs, exval, 0); } }
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; hscx_sched_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; hscx_sched_event(bcs, B_RCVBUFREADY); } } if (val & 0x10) { /* XPR */ if (bcs->tx_skb) { if (bcs->tx_skb->len) { hscx_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); hscx_fill_fifo(bcs); } else { test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); hscx_sched_event(bcs, B_XMTBUFREADY); } } }
static inline void hscx_interrupt(struct IsdnCardState *sp, u_char val, u_char hscx) { u_char r; struct HscxState *hsp = sp->hs + hscx; struct sk_buff *skb; int count; char tmp[32]; if (!hsp->init) return; if (val & 0x80) { /* RME */ r = HscxReadReg(sp->hscx[hsp->hscx], hscx, HSCX_RSTA); if ((r & 0xf0) != 0xa0) { if (!(r & 0x80)) if (sp->debug & L1_DEB_WARN) debugl1(sp, "HSCX invalid frame"); if ((r & 0x40) && hsp->mode) if (sp->debug & L1_DEB_WARN) { sprintf(tmp, "HSCX RDO mode=%d", hsp->mode); debugl1(sp, tmp); } if (!(r & 0x20)) if (sp->debug & L1_DEB_WARN) debugl1(sp, "HSCX CRC error"); writehscxCMDR(sp->hscx[hsp->hscx], hsp->hscx, 0x80); } else { count = HscxReadReg(sp->hscx[hsp->hscx], hscx, HSCX_RBCL) & 0x1f; if (count == 0) count = 32; hscx_empty_fifo(hsp, count); if ((count = hsp->rcvidx - 1) > 0) { if (sp->debug & L1_DEB_HSCX_FIFO) { sprintf(tmp, "HX Frame %d", count); debugl1(sp, tmp); } if (!(skb = dev_alloc_skb(count))) printk(KERN_WARNING "IX1: receive out of memory\n"); else { memcpy(skb_put(skb, count), hsp->rcvbuf, count); skb_queue_tail(&hsp->rqueue, skb); } } } hsp->rcvidx = 0; hscx_sched_event(hsp, HSCX_RCVBUFREADY); } if (val & 0x40) { /* RPF */ hscx_empty_fifo(hsp, 32); if (hsp->mode == 1) { /* receive audio data */ if (!(skb = dev_alloc_skb(32))) printk(KERN_WARNING "IX1: receive out of memory\n"); else { memcpy(skb_put(skb, 32), hsp->rcvbuf, 32); skb_queue_tail(&hsp->rqueue, skb); } hsp->rcvidx = 0; hscx_sched_event(hsp, HSCX_RCVBUFREADY); } } if (val & 0x10) { /* XPR */ if (hsp->tx_skb) if (hsp->tx_skb->len) { hscx_fill_fifo(hsp); return; } else { dev_kfree_skb(hsp->tx_skb, FREE_WRITE); hsp->count = 0; if (hsp->st->l4.l1writewakeup) hsp->st->l4.l1writewakeup(hsp->st); hsp->tx_skb = NULL; } if ((hsp->tx_skb = skb_dequeue(&hsp->squeue))) { hsp->count = 0; hscx_fill_fifo(hsp); } else hscx_sched_event(hsp, HSCX_XMTBUFREADY); } }
static void MIXCOM_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; struct net_device *dev = (struct net_device *)dev_id; struct comx_channel *ch, *twin_ch; struct mixcom_privdata *hw, *twin_hw; register unsigned char ista; if (dev==NULL) { printk(KERN_ERR "comx_interrupt: irq %d for unknown device\n",irq); return; } ch = dev->priv; hw = ch->HW_privdata; save_flags(flags); cli(); while((ista = (rd_hscx(dev, HSCX_ISTA) & (HSCX_RME | HSCX_RPF | HSCX_XPR | HSCX_EXB | HSCX_EXA | HSCX_ICA)))) { register byte ista2 = 0; if (ista & HSCX_RME) { mixcom_receive_frame(dev); } if (ista & HSCX_RPF) { hscx_empty_fifo(dev, 32); } if (ista & HSCX_XPR) { if (hw->tx_ptr) { hscx_fill_fifo(dev); } else { clear_bit(0, &hw->txbusy); ch->LINE_tx(dev); } } if (ista & HSCX_EXB) { mixcom_extended_interrupt(dev); } if ((ista & HSCX_EXA) && ch->twin) { mixcom_extended_interrupt(ch->twin); } if ((ista & HSCX_ICA) && ch->twin && (ista2 = rd_hscx(ch->twin, HSCX_ISTA) & (HSCX_RME | HSCX_RPF | HSCX_XPR ))) { if (ista2 & HSCX_RME) { mixcom_receive_frame(ch->twin); } if (ista2 & HSCX_RPF) { hscx_empty_fifo(ch->twin, 32); } if (ista2 & HSCX_XPR) { twin_ch=ch->twin->priv; twin_hw=twin_ch->HW_privdata; if (twin_hw->tx_ptr) { hscx_fill_fifo(ch->twin); } else { clear_bit(0, &twin_hw->txbusy); ch->LINE_tx(ch->twin); } } } } restore_flags(flags); return; }