Skip to content

Commit

Permalink
mISDN: Implement MISDN_CTRL_FILL_EMPTY for more drivers
Browse files Browse the repository at this point in the history
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: Karsten Keil <kkeil@linux-pingi.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Karsten Keil authored and David S. Miller committed May 16, 2012
1 parent 034005a commit 6d1ee48
Show file tree
Hide file tree
Showing 11 changed files with 243 additions and 161 deletions.
64 changes: 44 additions & 20 deletions drivers/isdn/hardware/mISDN/avmfritz.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
#include "ipac.h"


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

static int AVM_cnt;
static int debug;
Expand Down Expand Up @@ -442,30 +442,41 @@ 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)
return;
count = bch->tx_skb->len - bch->tx_idx;
if (count <= 0)
return;
idx = (bch->nr - 1) & 1;
hdlc = &fc->hdlc[idx];
fs = (fc->type == AVM_FRITZ_PCIV2) ?
HDLC_FIFO_SIZE_V2 : HDLC_FIFO_SIZE_V1;
p = bch->tx_skb->data + bch->tx_idx;
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;
p = bch->tx_skb->data + bch->tx_idx;
}
hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME;
if (count > fs) {
count = fs;
} else {
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;
bch->tx_idx += count;
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);
Expand All @@ -475,13 +486,21 @@ hdlc_fill_fifo(struct bchannel *bch)
__write_ctrl_pci(fc, hdlc, bch->nr);
addr = fc->addr + CHIP_WINDOW;
}
while (cnt < count) {
val = get_unaligned(ptr);
outl(cpu_to_le32(val), addr);
ptr++;
cnt += 4;
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);
Expand All @@ -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);
}
}
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
12 changes: 5 additions & 7 deletions drivers/isdn/hardware/mISDN/hfcmulti.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand Down
59 changes: 19 additions & 40 deletions drivers/isdn/hardware/mISDN/hfcpci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
return;
count = bch->tx_skb->len - bch->tx_idx;
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;
Expand All @@ -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;
/* 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 (test_bit(FLG_FILLEMPTY, &bch->Flags)) {
/* fcnt contains available bytes in fifo */
if (count > fcnt)
count = fcnt;
new_z1 = le16_to_cpu(*z1t) + count;
/* new buffer Position */
if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
Expand All @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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))
Expand Down
44 changes: 18 additions & 26 deletions drivers/isdn/hardware/mISDN/hfcsusb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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) {
Expand All @@ -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__);
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
*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) ",
Expand Down
Loading

0 comments on commit 6d1ee48

Please sign in to comment.