Beispiel #1
0
/* 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;
}
Beispiel #2
0
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);
}
Beispiel #4
0
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;
	}
}