/* The function allocates a new receive skb on demand with a size for the * requirements of the current protocol. It returns the tailroom of the * receive skb or an error. */ int bchannel_get_rxbuf(struct bchannel *bch, int reqlen) { int len; if (bch->rx_skb) { len = skb_tailroom(bch->rx_skb); if (len < reqlen) { pr_warning("B%d no space for %d (only %d) bytes\n", bch->nr, reqlen, len); if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { /* send what we have now and try a new buffer */ recv_Bchannel(bch, 0, true); } else { /* on HDLC we have to drop too big frames */ return -EMSGSIZE; } } else { return len; } } /* update current min/max length first */ if (unlikely(bch->maxlen != bch->next_maxlen)) bch->maxlen = bch->next_maxlen; if (unlikely(bch->minlen != bch->next_minlen)) bch->minlen = bch->next_minlen; if (unlikely(reqlen > bch->maxlen)) return -EMSGSIZE; if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { if (reqlen >= bch->minlen) { len = reqlen; } else { len = 2 * bch->minlen; if (len > bch->maxlen) len = bch->maxlen; } } else { /* with HDLC we do not know the length yet */ len = bch->maxlen; } bch->rx_skb = mI_alloc_skb(len, GFP_ATOMIC); if (!bch->rx_skb) { pr_warning("B%d receive no memory for %d bytes\n", bch->nr, len); len = -ENOMEM; } return len; }
static void W6692B_interrupt(struct w6692_hw *card, int ch) { struct w6692_ch *wch = &card->bc[ch]; int count; u8 stat, star = 0; stat = ReadW6692B(wch, W_B_EXIR); pr_debug("%s: B%d EXIR %02x\n", card->name, wch->bch.nr, stat); if (stat & W_B_EXI_RME) { star = ReadW6692B(wch, W_B_STAR); if (star & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) { if ((star & W_B_STAR_RDOV) && test_bit(FLG_ACTIVE, &wch->bch.Flags)) { pr_debug("%s: B%d RDOV proto=%x\n", card->name, wch->bch.nr, wch->bch.state); #ifdef ERROR_STATISTIC wch->bch.err_rdo++; #endif } if (test_bit(FLG_HDLC, &wch->bch.Flags)) { if (star & W_B_STAR_CRCE) { pr_debug("%s: B%d CRC error\n", card->name, wch->bch.nr); #ifdef ERROR_STATISTIC wch->bch.err_crc++; #endif } if (star & W_B_STAR_RMB) { pr_debug("%s: B%d message abort\n", card->name, wch->bch.nr); #ifdef ERROR_STATISTIC wch->bch.err_inv++; #endif } } WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT); if (wch->bch.rx_skb) skb_trim(wch->bch.rx_skb, 0); } else { count = ReadW6692B(wch, W_B_RBCL) & (W_B_FIFO_THRESH - 1); if (count == 0) count = W_B_FIFO_THRESH; W6692_empty_Bfifo(wch, count); recv_Bchannel(&wch->bch, 0); } } if (stat & W_B_EXI_RMR) { if (!(stat & W_B_EXI_RME)) star = ReadW6692B(wch, W_B_STAR); if (star & W_B_STAR_RDOV) { pr_debug("%s: B%d RDOV proto=%x\n", card->name, wch->bch.nr, wch->bch.state); #ifdef ERROR_STATISTIC wch->bch.err_rdo++; #endif WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT); } else { W6692_empty_Bfifo(wch, W_B_FIFO_THRESH); if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags) && wch->bch.rx_skb && (wch->bch.rx_skb->len > 0)) recv_Bchannel(&wch->bch, 0); } } if (stat & W_B_EXI_RDOV) { if (!(star & W_B_STAR_RDOV)) { pr_debug("%s: B%d RDOV IRQ proto=%x\n", card->name, wch->bch.nr, wch->bch.state); #ifdef ERROR_STATISTIC wch->bch.err_rdo++; #endif WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT); } } if (stat & W_B_EXI_XFR) { if (!(stat & (W_B_EXI_RME | W_B_EXI_RMR))) { star = ReadW6692B(wch, W_B_STAR); pr_debug("%s: B%d star %02x\n", card->name, wch->bch.nr, star); } if (star & W_B_STAR_XDOW) { pr_debug("%s: B%d XDOW proto=%x\n", card->name, wch->bch.nr, wch->bch.state); #ifdef ERROR_STATISTIC wch->bch.err_xdu++; #endif WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); if (wch->bch.tx_skb) { if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) wch->bch.tx_idx = 0; } } send_next(wch); if (stat & W_B_EXI_XDUN) return; } if (stat & W_B_EXI_XDUN) { pr_debug("%s: B%d XDUN proto=%x\n", card->name, wch->bch.nr, wch->bch.state); #ifdef ERROR_STATISTIC wch->bch.err_xdu++; #endif WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); if (wch->bch.tx_skb) { if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags)) wch->bch.tx_idx = 0; } send_next(wch); } }
static void hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, int finish) { struct hfcsusb *hw = fifo->hw; struct sk_buff *rx_skb = NULL; int maxlen = 0; int fifon = fifo->fifonum; int i; int hdlc = 0; if (debug & DBG_HFC_CALL_TRACE) printk(KERN_DEBUG "%s: %s: fifo(%i) len(%i) " "dch(%p) bch(%p) ech(%p)\n", hw->name, __func__, fifon, len, fifo->dch, fifo->bch, fifo->ech); if (!len) return; if ((!!fifo->dch + !!fifo->bch + !!fifo->ech) != 1) { printk(KERN_DEBUG "%s: %s: undefined channel\n", hw->name, __func__); return; } spin_lock(&hw->lock); if (fifo->dch) { rx_skb = fifo->dch->rx_skb; maxlen = fifo->dch->maxlen; hdlc = 1; } if (fifo->bch) { rx_skb = fifo->bch->rx_skb; maxlen = fifo->bch->maxlen; hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags); } if (fifo->ech) { rx_skb = fifo->ech->rx_skb; maxlen = fifo->ech->maxlen; hdlc = 1; } if (!rx_skb) { rx_skb = mI_alloc_skb(maxlen, GFP_ATOMIC); if (rx_skb) { if (fifo->dch) fifo->dch->rx_skb = rx_skb; if (fifo->bch) fifo->bch->rx_skb = rx_skb; if (fifo->ech) fifo->ech->rx_skb = rx_skb; skb_trim(rx_skb, 0); } else { printk(KERN_DEBUG "%s: %s: No mem for rx_skb\n", hw->name, __func__); spin_unlock(&hw->lock); return; } } if (fifo->dch || fifo->ech) { if ((rx_skb->len + len) >= MAX_DFRAME_LEN_L1) { printk(KERN_DEBUG "%s: %s: sbk mem exceeded " "for fifo(%d) HFCUSB_D_RX\n", hw->name, __func__, fifon); skb_trim(rx_skb, 0); spin_unlock(&hw->lock); return; } } else if (fifo->bch) { if ((rx_skb->len + len) >= (MAX_BCH_SIZE + 3)) { printk(KERN_DEBUG "%s: %s: sbk mem exceeded " "for fifo(%d) HFCUSB_B_RX\n", hw->name, __func__, fifon); skb_trim(rx_skb, 0); spin_unlock(&hw->lock); return; } } memcpy(skb_put(rx_skb, len), data, len); if (hdlc) { if (finish) { if ((rx_skb->len > 3) && (!(rx_skb->data[rx_skb->len - 1]))) { if (debug & DBG_HFC_FIFO_VERBOSE) { printk(KERN_DEBUG "%s: %s: fifon(%i)" " new RX len(%i): ", hw->name, __func__, fifon, rx_skb->len); i = 0; while (i < rx_skb->len) printk("%02x ", rx_skb->data[i++]); printk("\n"); } skb_trim(rx_skb, rx_skb->len - 3); if (fifo->dch) recv_Dchannel(fifo->dch); if (fifo->bch) recv_Bchannel(fifo->bch, MISDN_ID_ANY); if (fifo->ech) recv_Echannel(fifo->ech, &hw->dch); } else { if (debug & DBG_HFC_FIFO_VERBOSE) { printk(KERN_DEBUG "%s: CRC or minlen ERROR fifon(%i) " "RX len(%i): ", hw->name, fifon, rx_skb->len); i = 0; while (i < rx_skb->len) printk("%02x ", rx_skb->data[i++]); printk("\n"); } skb_trim(rx_skb, 0); } } } else { if (rx_skb->len >= poll) recv_Bchannel(fifo->bch, MISDN_ID_ANY); } spin_unlock(&hw->lock); }
static inline void isar_rcv_frame(struct isar_ch *ch) { u8 *ptr; if (!ch->is->clsb) { pr_debug("%s; ISAR zero len frame\n", ch->is->name); ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); return; } switch (ch->bch.state) { case ISDN_P_NONE: pr_debug("%s: ISAR protocol 0 spurious IIS_RDATA %x/%x/%x\n", ch->is->name, ch->is->iis, ch->is->cmsb, ch->is->clsb); ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); break; case ISDN_P_B_RAW: case ISDN_P_B_L2DTMF: case ISDN_P_B_MODEM_ASYNC: if (!ch->bch.rx_skb) { ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, GFP_ATOMIC); if (unlikely(!ch->bch.rx_skb)) { pr_info("%s: B receive out of memory\n", ch->is->name); ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); break; } } rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); recv_Bchannel(&ch->bch, 0); break; case ISDN_P_B_HDLC: if (!ch->bch.rx_skb) { ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, GFP_ATOMIC); if (unlikely(!ch->bch.rx_skb)) { pr_info("%s: B receive out of memory\n", ch->is->name); ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); break; } } if ((ch->bch.rx_skb->len + ch->is->clsb) > (ch->bch.maxlen + 2)) { pr_debug("%s: incoming packet too large\n", ch->is->name); ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); skb_trim(ch->bch.rx_skb, 0); break; } if (ch->is->cmsb & HDLC_ERROR) { pr_debug("%s: ISAR frame error %x len %d\n", ch->is->name, ch->is->cmsb, ch->is->clsb); #ifdef ERROR_STATISTIC if (ch->is->cmsb & HDLC_ERR_RER) ch->bch.err_inv++; if (ch->is->cmsb & HDLC_ERR_CER) ch->bch.err_crc++; #endif skb_trim(ch->bch.rx_skb, 0); ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); break; } if (ch->is->cmsb & HDLC_FSD) skb_trim(ch->bch.rx_skb, 0); ptr = skb_put(ch->bch.rx_skb, ch->is->clsb); rcv_mbox(ch->is, ptr); if (ch->is->cmsb & HDLC_FED) { if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */ pr_debug("%s: ISAR frame to short %d\n", ch->is->name, ch->bch.rx_skb->len); skb_trim(ch->bch.rx_skb, 0); break; } skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); recv_Bchannel(&ch->bch, 0); } break; case ISDN_P_B_T30_FAX: if (ch->state != STFAX_ACTIV) { pr_debug("%s: isar_rcv_frame: not ACTIV\n", ch->is->name); ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); if (ch->bch.rx_skb) skb_trim(ch->bch.rx_skb, 0); break; } if (!ch->bch.rx_skb) { ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen, GFP_ATOMIC); if (unlikely(!ch->bch.rx_skb)) { pr_info("%s: B receive out of memory\n", __func__); ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); break; } } if (ch->cmd == PCTRL_CMD_FRM) { rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb)); pr_debug("%s: isar_rcv_frame: %d\n", ch->is->name, ch->bch.rx_skb->len); if (ch->is->cmsb & SART_NMD) { /* ABORT */ pr_debug("%s: isar_rcv_frame: no more data\n", ch->is->name); ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); ch->state = STFAX_ESCAPE; /* set_skb_flag(skb, DF_NOMOREDATA); */ } recv_Bchannel(&ch->bch, 0); if (ch->is->cmsb & SART_NMD) deliver_status(ch, HW_MOD_NOCARR); break; } if (ch->cmd != PCTRL_CMD_FRH) { pr_debug("%s: isar_rcv_frame: unknown fax mode %x\n", ch->is->name, ch->cmd); ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); if (ch->bch.rx_skb) skb_trim(ch->bch.rx_skb, 0); break; } /* PCTRL_CMD_FRH */ if ((ch->bch.rx_skb->len + ch->is->clsb) > (ch->bch.maxlen + 2)) { pr_info("%s: %s incoming packet too large\n", ch->is->name, __func__); ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); skb_trim(ch->bch.rx_skb, 0); break; } else if (ch->is->cmsb & HDLC_ERROR) { pr_info("%s: ISAR frame error %x len %d\n", ch->is->name, ch->is->cmsb, ch->is->clsb); skb_trim(ch->bch.rx_skb, 0); ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); break; } if (ch->is->cmsb & HDLC_FSD) skb_trim(ch->bch.rx_skb, 0); ptr = skb_put(ch->bch.rx_skb, ch->is->clsb); rcv_mbox(ch->is, ptr); if (ch->is->cmsb & HDLC_FED) { if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */ pr_info("%s: ISAR frame to short %d\n", ch->is->name, ch->bch.rx_skb->len); skb_trim(ch->bch.rx_skb, 0); break; } skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2); recv_Bchannel(&ch->bch, 0); } if (ch->is->cmsb & SART_NMD) { /* ABORT */ pr_debug("%s: isar_rcv_frame: no more data\n", ch->is->name); ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); if (ch->bch.rx_skb) skb_trim(ch->bch.rx_skb, 0); send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); ch->state = STFAX_ESCAPE; deliver_status(ch, HW_MOD_NOCARR); } break; default: pr_info("isar_rcv_frame protocol (%x)error\n", ch->bch.state); ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); break; } }