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

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
......@@ -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;
......
......@@ -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)
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))
......
......@@ -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) ",
......
......@@ -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,9 +1016,13 @@ 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
......@@ -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)
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 (!(ch->is->bstat &
(ch->dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2)))
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;
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);
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,18 +568,34 @@ fill_dma(struct tiger_ch *bc)
} else {
if (count > bc->free)
count = bc->free;
if (!fillempty)
bc->bch.tx_idx += count;
bc->free -= count;
}
m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff;
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 |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8;
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 ",
bc->bch.nr, card->name, count);
......@@ -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)
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;
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,9 +650,13 @@ 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);
}
}
}
static void
......@@ -727,7 +744,7 @@ 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,
pr_warning("%s: B%d XDOW proto=%x\n", card->name,
wch->bch.nr, wch->bch.state);
#ifdef ERROR_STATISTIC
wch->bch.err_xdu++;
......@@ -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,
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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment