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: Karsten Keil <kkeil@linux-pingi.de> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
034005a011
commit
6d1ee48fd0
|
@ -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)
|
||||
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;
|
||||
|
@ -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;
|
||||
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);
|
||||
|
@ -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);
|
||||
|
@ -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 @@ handle_tx:
|
|||
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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
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;
|
||||
|
@ -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))
|
||||
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
*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) ",
|
||||
|
|
|
@ -969,22 +969,28 @@ hscx_fill_fifo(struct hscx_hw *hscx)
|
|||
int count, more;
|
||||
u8 *p;
|
||||
|
||||
if (!hscx->bch.tx_skb)
|
||||
return;
|
||||
count = hscx->bch.tx_skb->len - hscx->bch.tx_idx;
|
||||
if (count <= 0)
|
||||
return;
|
||||
p = hscx->bch.tx_skb->data + hscx->bch.tx_idx;
|
||||
|
||||
more = test_bit(FLG_TRANSPARENT, &hscx->bch.Flags) ? 1 : 0;
|
||||
if (count > hscx->fifo_size) {
|
||||
if (!hscx->bch.tx_skb) {
|
||||
if (!test_bit(FLG_TX_EMPTY, &hscx->bch.Flags))
|
||||
return;
|
||||
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);
|
||||
hscx->bch.tx_idx += count;
|
||||
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;
|
||||
p = hscx->bch.tx_skb->data + hscx->bch.tx_idx;
|
||||
|
||||
more = test_bit(FLG_TRANSPARENT, &hscx->bch.Flags) ? 1 : 0;
|
||||
if (count > hscx->fifo_size) {
|
||||
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);
|
||||
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,8 +1016,12 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
|
|
@ -585,16 +585,25 @@ isar_fill_fifo(struct isar_ch *ch)
|
|||
u8 msb;
|
||||
u8 *ptr;
|
||||
|
||||
pr_debug("%s: ch%d tx_skb %p tx_idx %d\n",
|
||||
ch->is->name, ch->bch.nr, ch->bch.tx_skb, ch->bch.tx_idx);
|
||||
if (!ch->bch.tx_skb)
|
||||
return;
|
||||
count = ch->bch.tx_skb->len - ch->bch.tx_idx;
|
||||
if (count <= 0)
|
||||
return;
|
||||
pr_debug("%s: ch%d tx_skb %d tx_idx %d\n", ch->is->name, ch->bch.nr,
|
||||
ch->bch.tx_skb ? ch->bch.tx_skb->len : -1, ch->bch.tx_idx);
|
||||
if (!(ch->is->bstat &
|
||||
(ch->dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2)))
|
||||
return;
|
||||
if (!ch->bch.tx_skb) {
|
||||
if (!test_bit(FLG_TX_EMPTY, &ch->bch.Flags) ||
|
||||
(ch->bch.state != ISDN_P_B_RAW))
|
||||
return;
|
||||
count = ch->mml;
|
||||
/* use the card buffer */
|
||||
memset(ch->is->buf, ch->bch.fill[0], count);
|
||||
send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA,
|
||||
0, count, ch->is->buf);
|
||||
return;
|
||||
}
|
||||
count = ch->bch.tx_skb->len - ch->bch.tx_idx;
|
||||
if (count <= 0)
|
||||
return;
|
||||
if (count > ch->mml) {
|
||||
msb = 0;
|
||||
count = ch->mml;
|
||||
|
@ -673,9 +682,9 @@ sel_bch_isar(struct isar_hw *isar, u8 dpath)
|
|||
static void
|
||||
send_next(struct isar_ch *ch)
|
||||
{
|
||||
pr_debug("%s: %s ch%d tx_skb %p tx_idx %d\n",
|
||||
ch->is->name, __func__, ch->bch.nr,
|
||||
ch->bch.tx_skb, ch->bch.tx_idx);
|
||||
pr_debug("%s: %s ch%d tx_skb %d tx_idx %d\n", ch->is->name, __func__,
|
||||
ch->bch.nr, ch->bch.tx_skb ? ch->bch.tx_skb->len : -1,
|
||||
ch->bch.tx_idx);
|
||||
if (ch->bch.state == ISDN_P_B_T30_FAX) {
|
||||
if (ch->cmd == PCTRL_CMD_FTH) {
|
||||
if (test_bit(FLG_LASTDATA, &ch->bch.Flags)) {
|
||||
|
@ -693,6 +702,9 @@ send_next(struct isar_ch *ch)
|
|||
dev_kfree_skb(ch->bch.tx_skb);
|
||||
if (get_next_bframe(&ch->bch)) {
|
||||
isar_fill_fifo(ch);
|
||||
test_and_clear_bit(FLG_TX_EMPTY, &ch->bch.Flags);
|
||||
} else if (test_bit(FLG_TX_EMPTY, &ch->bch.Flags)) {
|
||||
isar_fill_fifo(ch);
|
||||
} else {
|
||||
if (test_and_clear_bit(FLG_DLEETX, &ch->bch.Flags)) {
|
||||
if (test_and_clear_bit(FLG_LASTDATA,
|
||||
|
@ -707,6 +719,8 @@ send_next(struct isar_ch *ch)
|
|||
} else {
|
||||
deliver_status(ch, HW_MOD_CONNECT);
|
||||
}
|
||||
} else if (test_bit(FLG_FILLEMPTY, &ch->bch.Flags)) {
|
||||
test_and_set_bit(FLG_TX_EMPTY, &ch->bch.Flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1638,7 +1652,6 @@ isar_open(struct isar_hw *isar, struct channel_req *rq)
|
|||
bch = &isar->ch[rq->adr.channel - 1].bch;
|
||||
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;
|
||||
|
|
|
@ -533,22 +533,31 @@ static void
|
|||
fill_dma(struct tiger_ch *bc)
|
||||
{
|
||||
struct tiger_hw *card = bc->bch.hw;
|
||||
int count, i;
|
||||
u32 m, v;
|
||||
int count, i, fillempty = 0;
|
||||
u32 m, v, n = 0;
|
||||
u8 *p;
|
||||
|
||||
if (bc->free == 0)
|
||||
return;
|
||||
count = bc->bch.tx_skb->len - bc->bch.tx_idx;
|
||||
if (count <= 0)
|
||||
return;
|
||||
pr_debug("%s: %s B%1d %d/%d/%d/%d state %x idx %d/%d\n", card->name,
|
||||
__func__, bc->bch.nr, count, bc->free, bc->bch.tx_idx,
|
||||
bc->bch.tx_skb->len, bc->txstate, bc->idx, card->send.idx);
|
||||
if (!bc->bch.tx_skb) {
|
||||
if (!test_bit(FLG_TX_EMPTY, &bc->bch.Flags))
|
||||
return;
|
||||
fillempty = 1;
|
||||
count = card->send.size >> 1;
|
||||
p = bc->bch.fill;
|
||||
} else {
|
||||
count = bc->bch.tx_skb->len - bc->bch.tx_idx;
|
||||
if (count <= 0)
|
||||
return;
|
||||
pr_debug("%s: %s B%1d %d/%d/%d/%d state %x idx %d/%d\n",
|
||||
card->name, __func__, bc->bch.nr, count, bc->free,
|
||||
bc->bch.tx_idx, bc->bch.tx_skb->len, bc->txstate,
|
||||
bc->idx, card->send.idx);
|
||||
p = bc->bch.tx_skb->data + bc->bch.tx_idx;
|
||||
}
|
||||
if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN))
|
||||
resync(bc, card);
|
||||
p = bc->bch.tx_skb->data + bc->bch.tx_idx;
|
||||
if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
|
||||
if (test_bit(FLG_HDLC, &bc->bch.Flags) && !fillempty) {
|
||||
count = isdnhdlc_encode(&bc->hsend, p, count, &i,
|
||||
bc->hsbuf, bc->free);
|
||||
pr_debug("%s: B%1d hdlc encoded %d in %d\n", card->name,
|
||||
|
@ -559,17 +568,33 @@ fill_dma(struct tiger_ch *bc)
|
|||
} else {
|
||||
if (count > bc->free)
|
||||
count = bc->free;
|
||||
bc->bch.tx_idx += count;
|
||||
if (!fillempty)
|
||||
bc->bch.tx_idx += count;
|
||||
bc->free -= count;
|
||||
}
|
||||
m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff;
|
||||
for (i = 0; i < count; i++) {
|
||||
if (bc->idx >= card->send.size)
|
||||
bc->idx = 0;
|
||||
v = card->send.start[bc->idx];
|
||||
v &= m;
|
||||
v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8;
|
||||
card->send.start[bc->idx++] = v;
|
||||
if (fillempty) {
|
||||
n = p[0];
|
||||
if (!(bc->bch.nr & 1))
|
||||
n <<= 8;
|
||||
for (i = 0; i < count; i++) {
|
||||
if (bc->idx >= card->send.size)
|
||||
bc->idx = 0;
|
||||
v = card->send.start[bc->idx];
|
||||
v &= m;
|
||||
v |= n;
|
||||
card->send.start[bc->idx++] = v;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < count; i++) {
|
||||
if (bc->idx >= card->send.size)
|
||||
bc->idx = 0;
|
||||
v = card->send.start[bc->idx];
|
||||
v &= m;
|
||||
n = p[i];
|
||||
v |= (bc->bch.nr & 1) ? n : n << 8;
|
||||
card->send.start[bc->idx++] = v;
|
||||
}
|
||||
}
|
||||
if (debug & DEBUG_HW_BFIFO) {
|
||||
snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ",
|
||||
|
@ -584,17 +609,26 @@ fill_dma(struct tiger_ch *bc)
|
|||
static int
|
||||
bc_next_frame(struct tiger_ch *bc)
|
||||
{
|
||||
int ret = 1;
|
||||
|
||||
if (bc->bch.tx_skb && bc->bch.tx_idx < bc->bch.tx_skb->len) {
|
||||
fill_dma(bc);
|
||||
} else {
|
||||
if (bc->bch.tx_skb)
|
||||
dev_kfree_skb(bc->bch.tx_skb);
|
||||
if (get_next_bframe(&bc->bch))
|
||||
if (get_next_bframe(&bc->bch)) {
|
||||
fill_dma(bc);
|
||||
else
|
||||
return 0;
|
||||
test_and_clear_bit(FLG_TX_EMPTY, &bc->bch.Flags);
|
||||
} else if (test_bit(FLG_TX_EMPTY, &bc->bch.Flags)) {
|
||||
fill_dma(bc);
|
||||
} else if (test_bit(FLG_FILLEMPTY, &bc->bch.Flags)) {
|
||||
test_and_set_bit(FLG_TX_EMPTY, &bc->bch.Flags);
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -498,16 +498,22 @@ static void
|
|||
W6692_fill_Bfifo(struct w6692_ch *wch)
|
||||
{
|
||||
struct w6692_hw *card = wch->bch.hw;
|
||||
int count;
|
||||
int count, fillempty = 0;
|
||||
u8 *ptr, cmd = W_B_CMDR_RACT | W_B_CMDR_XMS;
|
||||
|
||||
pr_debug("%s: fill Bfifo\n", card->name);
|
||||
if (!wch->bch.tx_skb)
|
||||
return;
|
||||
count = wch->bch.tx_skb->len - wch->bch.tx_idx;
|
||||
if (count <= 0)
|
||||
return;
|
||||
ptr = wch->bch.tx_skb->data + wch->bch.tx_idx;
|
||||
if (!wch->bch.tx_skb) {
|
||||
if (!test_bit(FLG_TX_EMPTY, &wch->bch.Flags))
|
||||
return;
|
||||
ptr = wch->bch.fill;
|
||||
count = W_B_FIFO_THRESH;
|
||||
fillempty = 1;
|
||||
} else {
|
||||
count = wch->bch.tx_skb->len - wch->bch.tx_idx;
|
||||
if (count <= 0)
|
||||
return;
|
||||
ptr = wch->bch.tx_skb->data + wch->bch.tx_idx;
|
||||
}
|
||||
if (count > W_B_FIFO_THRESH)
|
||||
count = W_B_FIFO_THRESH;
|
||||
else if (test_bit(FLG_HDLC, &wch->bch.Flags))
|
||||
|
@ -516,9 +522,16 @@ W6692_fill_Bfifo(struct w6692_ch *wch)
|
|||
pr_debug("%s: fill Bfifo%d/%d\n", card->name,
|
||||
count, wch->bch.tx_idx);
|
||||
wch->bch.tx_idx += count;
|
||||
outsb(wch->addr + W_B_XFIFO, ptr, count);
|
||||
if (fillempty) {
|
||||
while (count > 0) {
|
||||
outsb(wch->addr + W_B_XFIFO, ptr, MISDN_BCH_FILL_SIZE);
|
||||
count -= MISDN_BCH_FILL_SIZE;
|
||||
}
|
||||
} else {
|
||||
outsb(wch->addr + W_B_XFIFO, ptr, count);
|
||||
}
|
||||
WriteW6692B(wch, W_B_CMDR, cmd);
|
||||
if (debug & DEBUG_HW_DFIFO) {
|
||||
if ((debug & DEBUG_HW_BFIFO) && !fillempty) {
|
||||
snprintf(card->log, 63, "B%1d-send %s %d ",
|
||||
wch->bch.nr, card->name, count);
|
||||
print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count);
|
||||
|
@ -637,8 +650,12 @@ send_next(struct w6692_ch *wch)
|
|||
} else {
|
||||
if (wch->bch.tx_skb)
|
||||
dev_kfree_skb(wch->bch.tx_skb);
|
||||
if (get_next_bframe(&wch->bch))
|
||||
if (get_next_bframe(&wch->bch)) {
|
||||
W6692_fill_Bfifo(wch);
|
||||
test_and_clear_bit(FLG_TX_EMPTY, &wch->bch.Flags);
|
||||
} else if (test_bit(FLG_TX_EMPTY, &wch->bch.Flags)) {
|
||||
W6692_fill_Bfifo(wch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -727,8 +744,8 @@ W6692B_interrupt(struct w6692_hw *card, int ch)
|
|||
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);
|
||||
pr_warning("%s: B%d XDOW proto=%x\n", card->name,
|
||||
wch->bch.nr, wch->bch.state);
|
||||
#ifdef ERROR_STATISTIC
|
||||
wch->bch.err_xdu++;
|
||||
#endif
|
||||
|
@ -741,20 +758,21 @@ W6692B_interrupt(struct w6692_hw *card, int ch)
|
|||
}
|
||||
}
|
||||
send_next(wch);
|
||||
if (stat & W_B_EXI_XDUN)
|
||||
if (star & W_B_STAR_XDOW)
|
||||
return; /* handle XDOW only once */
|
||||
}
|
||||
if (stat & W_B_EXI_XDUN) {
|
||||
pr_debug("%s: B%d XDUN proto=%x\n", card->name,
|
||||
wch->bch.nr, wch->bch.state);
|
||||
pr_warning("%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);
|
||||
/* resend */
|
||||
/* resend - no XRST needed */
|
||||
if (wch->bch.tx_skb) {
|
||||
if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags))
|
||||
wch->bch.tx_idx = 0;
|
||||
} else if (test_bit(FLG_FILLEMPTY, &wch->bch.Flags)) {
|
||||
test_and_set_bit(FLG_TX_EMPTY, &wch->bch.Flags);
|
||||
}
|
||||
send_next(wch);
|
||||
}
|
||||
|
@ -993,7 +1011,6 @@ open_bchannel(struct w6692_hw *card, struct channel_req *rq)
|
|||
bch = &card->bc[rq->adr.channel - 1].bch;
|
||||
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;
|
||||
|
|
|
@ -268,6 +268,7 @@ dsp_fill_empty(struct dsp *dsp)
|
|||
}
|
||||
cq.op = MISDN_CTRL_FILL_EMPTY;
|
||||
cq.p1 = 1;
|
||||
cq.p2 = dsp_silence;
|
||||
if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) {
|
||||
printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n",
|
||||
__func__);
|
||||
|
|
|
@ -140,6 +140,8 @@ mISDN_clear_bchannel(struct bchannel *ch)
|
|||
test_and_clear_bit(FLG_TX_BUSY, &ch->Flags);
|
||||
test_and_clear_bit(FLG_TX_NEXT, &ch->Flags);
|
||||
test_and_clear_bit(FLG_ACTIVE, &ch->Flags);
|
||||
test_and_clear_bit(FLG_FILLEMPTY, &ch->Flags);
|
||||
test_and_clear_bit(FLG_TX_EMPTY, &ch->Flags);
|
||||
ch->minlen = ch->init_minlen;
|
||||
ch->next_minlen = ch->init_minlen;
|
||||
ch->maxlen = ch->init_maxlen;
|
||||
|
@ -165,7 +167,15 @@ mISDN_ctrl_bchannel(struct bchannel *bch, struct mISDN_ctrl_req *cq)
|
|||
|
||||
switch (cq->op) {
|
||||
case MISDN_CTRL_GETOP:
|
||||
cq->op = MISDN_CTRL_RX_BUFFER;
|
||||
cq->op = MISDN_CTRL_RX_BUFFER | MISDN_CTRL_FILL_EMPTY;
|
||||
break;
|
||||
case MISDN_CTRL_FILL_EMPTY:
|
||||
if (cq->p1) {
|
||||
memset(bch->fill, cq->p2 & 0xff, MISDN_BCH_FILL_SIZE);
|
||||
test_and_set_bit(FLG_FILLEMPTY, &bch->Flags);
|
||||
} else {
|
||||
test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
|
||||
}
|
||||
break;
|
||||
case MISDN_CTRL_RX_BUFFER:
|
||||
if (cq->p2 > MISDN_CTRL_RX_SIZE_IGNORE)
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
#define FLG_LL_OK 24
|
||||
#define FLG_LL_CONN 25
|
||||
#define FLG_DTMFSEND 26
|
||||
|
||||
#define FLG_TX_EMPTY 27
|
||||
/* workq events */
|
||||
#define FLG_RECVQUEUE 30
|
||||
#define FLG_PHCHANGE 31
|
||||
|
@ -142,6 +142,7 @@ extern int create_l1(struct dchannel *, dchannel_l1callback *);
|
|||
struct layer1;
|
||||
extern int l1_event(struct layer1 *, u_int);
|
||||
|
||||
#define MISDN_BCH_FILL_SIZE 4
|
||||
|
||||
struct bchannel {
|
||||
struct mISDNchannel ch;
|
||||
|
@ -153,6 +154,7 @@ struct bchannel {
|
|||
int slot; /* multiport card channel slot */
|
||||
struct timer_list timer;
|
||||
/* receive data */
|
||||
u8 fill[MISDN_BCH_FILL_SIZE];
|
||||
struct sk_buff *rx_skb;
|
||||
unsigned short maxlen;
|
||||
unsigned short init_maxlen; /* initial value */
|
||||
|
|
Loading…
Reference in a new issue