Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d1ee48f authored by Karsten Keil's avatar Karsten Keil Committed by David S. Miller
Browse files

mISDN: Implement MISDN_CTRL_FILL_EMPTY for more drivers



MISDN_CTRL_FILL_EMPTY is a meachanism to send a fixed value (normally silence)
as long no data from upper layers is available. It can be used when recording
voice messages or with unidirectional protocols.

Signed-off-by: default avatarKarsten Keil <kkeil@linux-pingi.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 034005a0
Loading
Loading
Loading
Loading
+44 −20
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@
#include "ipac.h"


#define AVMFRITZ_REV	"2.2"
#define AVMFRITZ_REV	"2.3"

static int AVM_cnt;
static int debug;
@@ -442,19 +442,26 @@ hdlc_fill_fifo(struct bchannel *bch)
{
	struct fritzcard *fc = bch->hw;
	struct hdlc_hw *hdlc;
	int count, fs, cnt = 0;
	int count, fs, cnt = 0, idx, fillempty = 0;
	u8 *p;
	u32 *ptr, val, addr;

	hdlc = &fc->hdlc[(bch->nr - 1) & 1];
	if (!bch->tx_skb)
	idx = (bch->nr - 1) & 1;
	hdlc = &fc->hdlc[idx];
	fs = (fc->type == AVM_FRITZ_PCIV2) ?
		HDLC_FIFO_SIZE_V2 : HDLC_FIFO_SIZE_V1;
	if (!bch->tx_skb) {
		if (!test_bit(FLG_TX_EMPTY, &bch->Flags))
			return;
		count = fs;
		p = bch->fill;
		fillempty = 1;
	} else {
		count = bch->tx_skb->len - bch->tx_idx;
		if (count <= 0)
			return;
	fs = (fc->type == AVM_FRITZ_PCIV2) ?
		HDLC_FIFO_SIZE_V2 : HDLC_FIFO_SIZE_V1;
		p = bch->tx_skb->data + bch->tx_idx;
	}
	hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME;
	if (count > fs) {
		count = fs;
@@ -462,10 +469,14 @@ hdlc_fill_fifo(struct bchannel *bch)
		if (test_bit(FLG_HDLC, &bch->Flags))
			hdlc->ctrl.sr.cmd |= HDLC_CMD_XME;
	}
	pr_debug("%s: %s %d/%d/%d", fc->name, __func__, count,
		 bch->tx_idx, bch->tx_skb->len);
	ptr = (u32 *)p;
	if (fillempty) {
		pr_debug("%s.B%d: %d/%d/%d", fc->name, bch->nr, count,
			 bch->tx_idx, bch->tx_skb->len);
		bch->tx_idx += count;
	} else {
		pr_debug("%s.B%d: fillempty %d\n", fc->name, bch->nr, count);
	}
	hdlc->ctrl.sr.xml = ((count == fs) ? 0 : count);
	if (fc->type == AVM_FRITZ_PCIV2) {
		__write_ctrl_pciv2(fc, hdlc, bch->nr);
@@ -475,13 +486,21 @@ hdlc_fill_fifo(struct bchannel *bch)
		__write_ctrl_pci(fc, hdlc, bch->nr);
		addr = fc->addr + CHIP_WINDOW;
	}
	if (fillempty) {
		while (cnt < count) {
			/* all bytes the same - no worry about endian */
			outl(*ptr, addr);
			cnt += 4;
		}
	} else {
		while (cnt < count) {
			val = get_unaligned(ptr);
			outl(cpu_to_le32(val), addr);
			ptr++;
			cnt += 4;
		}
	if (debug & DEBUG_HW_BFIFO) {
	}
	if ((debug & DEBUG_HW_BFIFO) && !fillempty) {
		snprintf(fc->log, LOG_SIZE, "B%1d-send %s %d ",
			 bch->nr, fc->name, count);
		print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count);
@@ -496,8 +515,12 @@ HDLC_irq_xpr(struct bchannel *bch)
	} else {
		if (bch->tx_skb)
			dev_kfree_skb(bch->tx_skb);
		if (get_next_bframe(bch))
		if (get_next_bframe(bch)) {
			hdlc_fill_fifo(bch);
			test_and_clear_bit(FLG_TX_EMPTY, &bch->Flags);
		} else if (test_bit(FLG_TX_EMPTY, &bch->Flags)) {
			hdlc_fill_fifo(bch);
		}
	}
}

@@ -561,6 +584,8 @@ HDLC_irq(struct bchannel *bch, u32 stat)
		if (bch->tx_skb && bch->tx_skb->len) {
			if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
				bch->tx_idx = 0;
		} else if (test_bit(FLG_FILLEMPTY, &bch->Flags)) {
			test_and_set_bit(FLG_TX_EMPTY, &bch->Flags);
		}
		hdlc->ctrl.sr.xml = 0;
		hdlc->ctrl.sr.cmd |= HDLC_CMD_XRS;
@@ -882,7 +907,6 @@ open_bchannel(struct fritzcard *fc, struct channel_req *rq)
	bch = &fc->bch[rq->adr.channel - 1];
	if (test_and_set_bit(FLG_OPEN, &bch->Flags))
		return -EBUSY; /* b-channel can be only open once */
	test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
	bch->ch.protocol = rq->protocol;
	rq->ch = &bch->ch;
	return 0;
+5 −7
Original line number Diff line number Diff line
@@ -3576,7 +3576,7 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
	case MISDN_CTRL_GETOP:
		ret = mISDN_ctrl_bchannel(bch, cq);
		cq->op |= MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP |
			  MISDN_CTRL_RX_OFF | MISDN_CTRL_FILL_EMPTY;
			  MISDN_CTRL_RX_OFF;
		break;
	case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */
		hc->chan[bch->slot].rx_off = !!cq->p1;
@@ -3591,11 +3591,10 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
			printk(KERN_DEBUG "%s: RX_OFF request (nr=%d off=%d)\n",
			       __func__, bch->nr, hc->chan[bch->slot].rx_off);
		break;
	case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */
		test_and_set_bit(FLG_FILLEMPTY, &bch->Flags);
		if (debug & DEBUG_HFCMULTI_MSG)
			printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d "
			       "off=%d)\n", __func__, bch->nr, !!cq->p1);
	case MISDN_CTRL_FILL_EMPTY:
		ret = mISDN_ctrl_bchannel(bch, cq);
		hc->silence = bch->fill[0];
		memset(hc->silence_data, hc->silence, sizeof(hc->silence_data));
		break;
	case MISDN_CTRL_HW_FEATURES: /* fill features structure */
		if (debug & DEBUG_HFCMULTI_MSG)
@@ -4118,7 +4117,6 @@ open_bchannel(struct hfc_multi *hc, struct dchannel *dch,
	}
	if (test_and_set_bit(FLG_OPEN, &bch->Flags))
		return -EBUSY; /* b-channel can be only open once */
	test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
	bch->ch.protocol = rq->protocol;
	hc->chan[ch].rx_off = 0;
	rq->ch = &bch->ch;
+19 −40
Original line number Diff line number Diff line
@@ -565,11 +565,6 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz,
	if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
		new_z2 -= B_FIFO_SIZE;	/* buffer wrap */

	if (fcnt_rx > MAX_DATA_SIZE) {	/* flush, if oversized */
		*z2r = cpu_to_le16(new_z2);		/* new position */
		return;
	}

	fcnt_tx = le16_to_cpu(*z2t) - le16_to_cpu(*z1t);
	if (fcnt_tx <= 0)
		fcnt_tx += B_FIFO_SIZE;
@@ -761,9 +756,14 @@ hfcpci_fill_fifo(struct bchannel *bch)

	if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO))
		printk(KERN_DEBUG "%s\n", __func__);
	if ((!bch->tx_skb) || bch->tx_skb->len <= 0)
	if ((!bch->tx_skb) || bch->tx_skb->len == 0) {
		if (!test_bit(FLG_FILLEMPTY, &bch->Flags) &&
		    !test_bit(FLG_TRANSPARENT, &bch->Flags))
			return;
		count = HFCPCI_FILLEMPTY;
	} else {
		count = bch->tx_skb->len - bch->tx_idx;
	}
	if ((bch->nr & 2) && (!hc->hw.bswapped)) {
		bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.txbz_b2;
		bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.txdat_b2;
@@ -782,16 +782,10 @@ hfcpci_fill_fifo(struct bchannel *bch)
		fcnt = le16_to_cpu(*z2t) - le16_to_cpu(*z1t);
		if (fcnt <= 0)
			fcnt += B_FIFO_SIZE;
		if (test_bit(FLG_FILLEMPTY, &bch->Flags)) {
			/* fcnt contains available bytes in fifo */
		fcnt = B_FIFO_SIZE - fcnt;
		/* remaining bytes to send (bytes in fifo) */

		/* "fill fifo if empty" feature */
		if (test_bit(FLG_FILLEMPTY, &bch->Flags) && !fcnt) {
			/* printk(KERN_DEBUG "%s: buffer empty, so we have "
			   "underrun\n", __func__); */
			/* fill buffer, to prevent future underrun */
			count = HFCPCI_FILLEMPTY;
			if (count > fcnt)
				count = fcnt;
			new_z1 = le16_to_cpu(*z1t) + count;
			/* new buffer Position */
			if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
@@ -803,17 +797,20 @@ hfcpci_fill_fifo(struct bchannel *bch)
				printk(KERN_DEBUG "hfcpci_FFt fillempty "
				       "fcnt(%d) maxl(%d) nz1(%x) dst(%p)\n",
				       fcnt, maxlen, new_z1, dst);
			fcnt += count;
			if (maxlen > count)
				maxlen = count;		/* limit size */
			memset(dst, 0x2a, maxlen);	/* first copy */
			memset(dst, bch->fill[0], maxlen); /* first copy */
			count -= maxlen;		/* remaining bytes */
			if (count) {
				dst = bdata;		/* start of buffer */
				memset(dst, 0x2a, count);
				memset(dst, bch->fill[0], count);
			}
			*z1t = cpu_to_le16(new_z1);	/* now send data */
			return;
		}
		/* fcnt contains available bytes in fifo */
		fcnt = B_FIFO_SIZE - fcnt;
		/* remaining bytes to send (bytes in fifo) */

	next_t_frame:
		count = bch->tx_skb->len - bch->tx_idx;
@@ -1531,24 +1528,7 @@ deactivate_bchannel(struct bchannel *bch)
static int
channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
{
	int	ret = 0;

	switch (cq->op) {
	case MISDN_CTRL_GETOP:
		ret = mISDN_ctrl_bchannel(bch, cq);
		cq->op |= MISDN_CTRL_FILL_EMPTY;
		break;
	case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */
		test_and_set_bit(FLG_FILLEMPTY, &bch->Flags);
		if (debug & DEBUG_HW_OPEN)
			printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d "
			       "off=%d)\n", __func__, bch->nr, !!cq->p1);
		break;
	default:
		ret = mISDN_ctrl_bchannel(bch, cq);
		break;
	}
	return ret;
	return mISDN_ctrl_bchannel(bch, cq);
}
static int
hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
@@ -1964,7 +1944,6 @@ open_bchannel(struct hfc_pci *hc, struct channel_req *rq)
	bch = &hc->bch[rq->adr.channel - 1];
	if (test_and_set_bit(FLG_OPEN, &bch->Flags))
		return -EBUSY; /* b-channel can be only open once */
	test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
	bch->ch.protocol = rq->protocol;
	rq->ch = &bch->ch; /* TODO: E-channel */
	if (!try_module_get(THIS_MODULE))
+18 −26
Original line number Diff line number Diff line
@@ -491,7 +491,6 @@ open_bchannel(struct hfcsusb *hw, struct channel_req *rq)
	bch = &hw->bch[rq->adr.channel - 1];
	if (test_and_set_bit(FLG_OPEN, &bch->Flags))
		return -EBUSY; /* b-channel can be only open once */
	test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
	bch->ch.protocol = rq->protocol;
	rq->ch = &bch->ch;

@@ -806,24 +805,7 @@ hfcsusb_ph_command(struct hfcsusb *hw, u_char command)
static int
channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
{
	int	ret = 0;

	switch (cq->op) {
	case MISDN_CTRL_GETOP:
		ret = mISDN_ctrl_bchannel(bch, cq);
		cq->op |= MISDN_CTRL_FILL_EMPTY;
		break;
	case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */
		test_and_set_bit(FLG_FILLEMPTY, &bch->Flags);
		if (debug & DEBUG_HW_OPEN)
			printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d "
			       "off=%d)\n", __func__, bch->nr, !!cq->p1);
		break;
	default:
		ret = mISDN_ctrl_bchannel(bch, cq);
		break;
	}
	return ret;
	return mISDN_ctrl_bchannel(bch, cq);
}

/* collect data from incoming interrupt or isochron USB data */
@@ -1183,8 +1165,8 @@ tx_iso_complete(struct urb *urb)
	int k, tx_offset, num_isoc_packets, sink, remain, current_len,
		errcode, hdlc, i;
	int *tx_idx;
	int frame_complete, fifon, status;
	__u8 threshbit;
	int frame_complete, fifon, status, fillempty = 0;
	__u8 threshbit, *p;

	spin_lock(&hw->lock);
	if (fifo->stop_gracefull) {
@@ -1202,6 +1184,9 @@ tx_iso_complete(struct urb *urb)
		tx_skb = fifo->bch->tx_skb;
		tx_idx = &fifo->bch->tx_idx;
		hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags);
		if (!tx_skb && !hdlc &&
		    test_bit(FLG_FILLEMPTY, &fifo->bch->Flags))
			fillempty = 1;
	} else {
		printk(KERN_DEBUG "%s: %s: neither BCH nor DCH\n",
		       hw->name, __func__);
@@ -1260,6 +1245,8 @@ tx_iso_complete(struct urb *urb)
			/* Generate next ISO Packets */
			if (tx_skb)
				remain = tx_skb->len - *tx_idx;
			else if (fillempty)
				remain = 15; /* > not complete */
			else
				remain = 0;

@@ -1290,15 +1277,20 @@ tx_iso_complete(struct urb *urb)
				}

				/* copy tx data to iso-urb buffer */
				memcpy(context_iso_urb->buffer + tx_offset + 1,
				       (tx_skb->data + *tx_idx), current_len);
				p = context_iso_urb->buffer + tx_offset + 1;
				if (fillempty) {
					memset(p, fifo->bch->fill[0],
					       current_len);
				} else {
					memcpy(p, (tx_skb->data + *tx_idx),
					       current_len);
					*tx_idx += current_len;

				}
				urb->iso_frame_desc[k].offset = tx_offset;
				urb->iso_frame_desc[k].length = current_len + 1;

				/* USB data log for every D ISO out */
				if ((fifon == HFCUSB_D_RX) &&
				if ((fifon == HFCUSB_D_RX) && !fillempty &&
				    (debug & DBG_HFC_USB_VERBOSE)) {
					printk(KERN_DEBUG
					       "%s: %s (%d/%d) offs(%d) len(%d) ",
+28 −16
Original line number Diff line number Diff line
@@ -969,8 +969,14 @@ hscx_fill_fifo(struct hscx_hw *hscx)
	int count, more;
	u8 *p;

	if (!hscx->bch.tx_skb)
	if (!hscx->bch.tx_skb) {
		if (!test_bit(FLG_TX_EMPTY, &hscx->bch.Flags))
			return;
		count = hscx->fifo_size;
		more = 1;
		p = hscx->log;
		memset(p, hscx->bch.fill[0], count);
	} else {
		count = hscx->bch.tx_skb->len - hscx->bch.tx_idx;
		if (count <= 0)
			return;
@@ -981,10 +987,10 @@ hscx_fill_fifo(struct hscx_hw *hscx)
			count = hscx->fifo_size;
			more = 1;
		}
	pr_debug("%s: B%1d %d/%d/%d\n", hscx->ip->name, hscx->bch.nr, count,
		 hscx->bch.tx_idx, hscx->bch.tx_skb->len);
		pr_debug("%s: B%1d %d/%d/%d\n", hscx->ip->name, hscx->bch.nr,
			 count, hscx->bch.tx_idx, hscx->bch.tx_skb->len);
		hscx->bch.tx_idx += count;

	}
	if (hscx->ip->type & IPAC_TYPE_IPACX)
		hscx->ip->write_fifo(hscx->ip->hw,
				     hscx->off + IPACX_XFIFOB, p, count);
@@ -995,7 +1001,7 @@ hscx_fill_fifo(struct hscx_hw *hscx)
	}
	hscx_cmdr(hscx, more ? 0x08 : 0x0a);

	if (hscx->bch.debug & DEBUG_HW_BFIFO) {
	if (hscx->bch.tx_skb && (hscx->bch.debug & DEBUG_HW_BFIFO)) {
		snprintf(hscx->log, 64, "B%1d-send %s %d ",
			 hscx->bch.nr, hscx->ip->name, count);
		print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count);
@@ -1010,10 +1016,14 @@ hscx_xpr(struct hscx_hw *hx)
	} else {
		if (hx->bch.tx_skb)
			dev_kfree_skb(hx->bch.tx_skb);
		if (get_next_bframe(&hx->bch))
		if (get_next_bframe(&hx->bch)) {
			hscx_fill_fifo(hx);
			test_and_clear_bit(FLG_TX_EMPTY, &hx->bch.Flags);
		} else if (test_bit(FLG_TX_EMPTY, &hx->bch.Flags)) {
			hscx_fill_fifo(hx);
		}
	}
}

static void
ipac_rme(struct hscx_hw *hx)
@@ -1128,7 +1138,9 @@ ipac_irq(struct hscx_hw *hx, u8 ista)

	if (istab & IPACX_B_XDU) {
		if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) {
			hscx_fill_fifo(hx);
			if (test_bit(FLG_FILLEMPTY, &hx->bch.Flags))
				test_and_set_bit(FLG_TX_EMPTY, &hx->bch.Flags);
			hscx_xpr(hx);
			return;
		}
		pr_debug("%s: B%1d XDU error at len %d\n", hx->ip->name,
Loading