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

mISDN: Implement MISDN_CTRL_RX_OFF for more drivers

MISDN_CTRL_RX_OFF is a meachanism to discard RX data in the driver if
the data is not needed by the application. It can be used when playing
mesages, but not recording 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 6d1ee48f
...@@ -408,6 +408,10 @@ hdlc_empty_fifo(struct bchannel *bch, int count) ...@@ -408,6 +408,10 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
struct fritzcard *fc = bch->hw; struct fritzcard *fc = bch->hw;
pr_debug("%s: %s %d\n", fc->name, __func__, count); pr_debug("%s: %s %d\n", fc->name, __func__, count);
if (test_bit(FLG_RX_OFF, &bch->Flags)) {
p = NULL;
bch->dropcnt += count;
} else {
cnt = bchannel_get_rxbuf(bch, count); cnt = bchannel_get_rxbuf(bch, count);
if (cnt < 0) { if (cnt < 0) {
pr_warning("%s.B%d: No bufferspace for %d bytes\n", pr_warning("%s.B%d: No bufferspace for %d bytes\n",
...@@ -415,6 +419,7 @@ hdlc_empty_fifo(struct bchannel *bch, int count) ...@@ -415,6 +419,7 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
return; return;
} }
p = skb_put(bch->rx_skb, count); p = skb_put(bch->rx_skb, count);
}
ptr = (u32 *)p; ptr = (u32 *)p;
if (fc->type == AVM_FRITZ_PCIV2) if (fc->type == AVM_FRITZ_PCIV2)
addr = fc->addr + (bch->nr == 2 ? addr = fc->addr + (bch->nr == 2 ?
...@@ -426,11 +431,13 @@ hdlc_empty_fifo(struct bchannel *bch, int count) ...@@ -426,11 +431,13 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
cnt = 0; cnt = 0;
while (cnt < count) { while (cnt < count) {
val = le32_to_cpu(inl(addr)); val = le32_to_cpu(inl(addr));
if (p) {
put_unaligned(val, ptr); put_unaligned(val, ptr);
ptr++; ptr++;
}
cnt += 4; cnt += 4;
} }
if (debug & DEBUG_HW_BFIFO) { if (p && (debug & DEBUG_HW_BFIFO)) {
snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ", snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ",
bch->nr, fc->name, count); bch->nr, fc->name, count);
print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count); print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count);
......
...@@ -2224,8 +2224,11 @@ hfcmulti_rx(struct hfc_multi *hc, int ch) ...@@ -2224,8 +2224,11 @@ hfcmulti_rx(struct hfc_multi *hc, int ch)
HFC_wait_nodebug(hc); HFC_wait_nodebug(hc);
/* ignore if rx is off BUT change fifo (above) to start pending TX */ /* ignore if rx is off BUT change fifo (above) to start pending TX */
if (hc->chan[ch].rx_off) if (hc->chan[ch].rx_off) {
if (bch)
bch->dropcnt += poll; /* not exact but fair enough */
return; return;
}
if (dch || test_bit(FLG_HDLC, &bch->Flags)) { if (dch || test_bit(FLG_HDLC, &bch->Flags)) {
f1 = HFC_inb_nodebug(hc, A_F1); f1 = HFC_inb_nodebug(hc, A_F1);
...@@ -3575,10 +3578,10 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) ...@@ -3575,10 +3578,10 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
switch (cq->op) { switch (cq->op) {
case MISDN_CTRL_GETOP: case MISDN_CTRL_GETOP:
ret = mISDN_ctrl_bchannel(bch, cq); ret = mISDN_ctrl_bchannel(bch, cq);
cq->op |= MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP | cq->op |= MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP;
MISDN_CTRL_RX_OFF;
break; break;
case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */ case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */
ret = mISDN_ctrl_bchannel(bch, cq);
hc->chan[bch->slot].rx_off = !!cq->p1; hc->chan[bch->slot].rx_off = !!cq->p1;
if (!hc->chan[bch->slot].rx_off) { if (!hc->chan[bch->slot].rx_off) {
/* reset fifo on rx on */ /* reset fifo on rx on */
......
...@@ -572,6 +572,11 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz, ...@@ -572,6 +572,11 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz,
fcnt_tx = B_FIFO_SIZE - fcnt_tx; fcnt_tx = B_FIFO_SIZE - fcnt_tx;
/* remaining bytes to send (bytes in tx-fifo) */ /* remaining bytes to send (bytes in tx-fifo) */
if (test_bit(FLG_RX_OFF, &bch->Flags)) {
bch->dropcnt += fcnt_rx;
*z2r = cpu_to_le16(new_z2);
return;
}
maxlen = bchannel_get_rxbuf(bch, fcnt_rx); maxlen = bchannel_get_rxbuf(bch, fcnt_rx);
if (maxlen < 0) { if (maxlen < 0) {
pr_warning("B%d: No bufferspace for %d bytes\n", pr_warning("B%d: No bufferspace for %d bytes\n",
......
...@@ -842,6 +842,11 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, ...@@ -842,6 +842,11 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
hdlc = 1; hdlc = 1;
} }
if (fifo->bch) { if (fifo->bch) {
if (test_bit(FLG_RX_OFF, &fifo->bch->Flags)) {
fifo->bch->dropcnt += len;
spin_unlock(&hw->lock);
return;
}
maxlen = bchannel_get_rxbuf(fifo->bch, len); maxlen = bchannel_get_rxbuf(fifo->bch, len);
rx_skb = fifo->bch->rx_skb; rx_skb = fifo->bch->rx_skb;
if (maxlen < 0) { if (maxlen < 0) {
......
...@@ -936,6 +936,11 @@ hscx_empty_fifo(struct hscx_hw *hscx, u8 count) ...@@ -936,6 +936,11 @@ hscx_empty_fifo(struct hscx_hw *hscx, u8 count)
int maxlen; int maxlen;
pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count); pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count);
if (test_bit(FLG_RX_OFF, &hscx->bch.Flags)) {
hscx->bch.dropcnt += count;
hscx_cmdr(hscx, 0x80); /* RMC */
return;
}
maxlen = bchannel_get_rxbuf(&hscx->bch, count); maxlen = bchannel_get_rxbuf(&hscx->bch, count);
if (maxlen < 0) { if (maxlen < 0) {
hscx_cmdr(hscx, 0x80); /* RMC */ hscx_cmdr(hscx, 0x80); /* RMC */
......
...@@ -429,6 +429,11 @@ isar_rcv_frame(struct isar_ch *ch) ...@@ -429,6 +429,11 @@ isar_rcv_frame(struct isar_ch *ch)
ch->is->write_reg(ch->is->hw, ISAR_IIA, 0); ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
return; return;
} }
if (test_bit(FLG_RX_OFF, &ch->bch.Flags)) {
ch->bch.dropcnt += ch->is->clsb;
ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
return;
}
switch (ch->bch.state) { switch (ch->bch.state) {
case ISDN_P_NONE: case ISDN_P_NONE:
pr_debug("%s: ISAR protocol 0 spurious IIS_RDATA %x/%x/%x\n", pr_debug("%s: ISAR protocol 0 spurious IIS_RDATA %x/%x/%x\n",
......
...@@ -386,6 +386,10 @@ read_dma(struct tiger_ch *bc, u32 idx, int cnt) ...@@ -386,6 +386,10 @@ read_dma(struct tiger_ch *bc, u32 idx, int cnt)
bc->bch.nr, idx); bc->bch.nr, idx);
} }
bc->lastrx = idx; bc->lastrx = idx;
if (test_bit(FLG_RX_OFF, &bc->bch.Flags)) {
bc->bch.dropcnt += cnt;
return;
}
stat = bchannel_get_rxbuf(&bc->bch, cnt); stat = bchannel_get_rxbuf(&bc->bch, cnt);
/* only transparent use the count here, HDLC overun is detected later */ /* only transparent use the count here, HDLC overun is detected later */
if (stat == ENOMEM) { if (stat == ENOMEM) {
......
...@@ -475,6 +475,11 @@ W6692_empty_Bfifo(struct w6692_ch *wch, int count) ...@@ -475,6 +475,11 @@ W6692_empty_Bfifo(struct w6692_ch *wch, int count)
skb_trim(wch->bch.rx_skb, 0); skb_trim(wch->bch.rx_skb, 0);
return; return;
} }
if (test_bit(FLG_RX_OFF, &wch->bch.Flags)) {
wch->bch.dropcnt += count;
WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
return;
}
maxlen = bchannel_get_rxbuf(&wch->bch, count); maxlen = bchannel_get_rxbuf(&wch->bch, count);
if (maxlen < 0) { if (maxlen < 0) {
WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
......
...@@ -142,6 +142,8 @@ mISDN_clear_bchannel(struct bchannel *ch) ...@@ -142,6 +142,8 @@ mISDN_clear_bchannel(struct bchannel *ch)
test_and_clear_bit(FLG_ACTIVE, &ch->Flags); test_and_clear_bit(FLG_ACTIVE, &ch->Flags);
test_and_clear_bit(FLG_FILLEMPTY, &ch->Flags); test_and_clear_bit(FLG_FILLEMPTY, &ch->Flags);
test_and_clear_bit(FLG_TX_EMPTY, &ch->Flags); test_and_clear_bit(FLG_TX_EMPTY, &ch->Flags);
test_and_clear_bit(FLG_RX_OFF, &ch->Flags);
ch->dropcnt = 0;
ch->minlen = ch->init_minlen; ch->minlen = ch->init_minlen;
ch->next_minlen = ch->init_minlen; ch->next_minlen = ch->init_minlen;
ch->maxlen = ch->init_maxlen; ch->maxlen = ch->init_maxlen;
...@@ -167,7 +169,8 @@ mISDN_ctrl_bchannel(struct bchannel *bch, struct mISDN_ctrl_req *cq) ...@@ -167,7 +169,8 @@ mISDN_ctrl_bchannel(struct bchannel *bch, struct mISDN_ctrl_req *cq)
switch (cq->op) { switch (cq->op) {
case MISDN_CTRL_GETOP: case MISDN_CTRL_GETOP:
cq->op = MISDN_CTRL_RX_BUFFER | MISDN_CTRL_FILL_EMPTY; cq->op = MISDN_CTRL_RX_BUFFER | MISDN_CTRL_FILL_EMPTY |
MISDN_CTRL_RX_OFF;
break; break;
case MISDN_CTRL_FILL_EMPTY: case MISDN_CTRL_FILL_EMPTY:
if (cq->p1) { if (cq->p1) {
...@@ -177,6 +180,15 @@ mISDN_ctrl_bchannel(struct bchannel *bch, struct mISDN_ctrl_req *cq) ...@@ -177,6 +180,15 @@ mISDN_ctrl_bchannel(struct bchannel *bch, struct mISDN_ctrl_req *cq)
test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
} }
break; break;
case MISDN_CTRL_RX_OFF:
/* read back dropped byte count */
cq->p2 = bch->dropcnt;
if (cq->p1)
test_and_set_bit(FLG_RX_OFF, &bch->Flags);
else
test_and_clear_bit(FLG_RX_OFF, &bch->Flags);
bch->dropcnt = 0;
break;
case MISDN_CTRL_RX_BUFFER: case MISDN_CTRL_RX_BUFFER:
if (cq->p2 > MISDN_CTRL_RX_SIZE_IGNORE) if (cq->p2 > MISDN_CTRL_RX_SIZE_IGNORE)
bch->next_maxlen = cq->p2; bch->next_maxlen = cq->p2;
......
...@@ -73,6 +73,8 @@ ...@@ -73,6 +73,8 @@
#define FLG_LL_CONN 25 #define FLG_LL_CONN 25
#define FLG_DTMFSEND 26 #define FLG_DTMFSEND 26
#define FLG_TX_EMPTY 27 #define FLG_TX_EMPTY 27
/* stop sending received data upstream */
#define FLG_RX_OFF 28
/* workq events */ /* workq events */
#define FLG_RECVQUEUE 30 #define FLG_RECVQUEUE 30
#define FLG_PHCHANGE 31 #define FLG_PHCHANGE 31
...@@ -173,6 +175,7 @@ struct bchannel { ...@@ -173,6 +175,7 @@ struct bchannel {
int err_crc; int err_crc;
int err_tx; int err_tx;
int err_rx; int err_rx;
int dropcnt;
}; };
extern int mISDN_initdchannel(struct dchannel *, int, void *); extern int mISDN_initdchannel(struct dchannel *, int, void *);
......
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