mISDN: Implement MISDN_CTRL_RX_OFF for more drivers
authorKarsten Keil <kkeil@linux-pingi.de>
Tue, 15 May 2012 23:51:08 +0000 (23:51 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 16 May 2012 19:24:36 +0000 (15:24 -0400)
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: Karsten Keil <kkeil@linux-pingi.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/isdn/hardware/mISDN/avmfritz.c
drivers/isdn/hardware/mISDN/hfcmulti.c
drivers/isdn/hardware/mISDN/hfcpci.c
drivers/isdn/hardware/mISDN/hfcsusb.c
drivers/isdn/hardware/mISDN/mISDNipac.c
drivers/isdn/hardware/mISDN/mISDNisar.c
drivers/isdn/hardware/mISDN/netjet.c
drivers/isdn/hardware/mISDN/w6692.c
drivers/isdn/mISDN/hwchannel.c
include/linux/mISDNhw.h

index c6fa505..c08fc60 100644 (file)
@@ -408,13 +408,18 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
        struct fritzcard *fc = bch->hw;
 
        pr_debug("%s: %s %d\n", fc->name, __func__, count);
-       cnt = bchannel_get_rxbuf(bch, count);
-       if (cnt < 0) {
-               pr_warning("%s.B%d: No bufferspace for %d bytes\n",
-                          fc->name, bch->nr, count);
-               return;
+       if (test_bit(FLG_RX_OFF, &bch->Flags)) {
+               p = NULL;
+               bch->dropcnt += count;
+       } else {
+               cnt = bchannel_get_rxbuf(bch, count);
+               if (cnt < 0) {
+                       pr_warning("%s.B%d: No bufferspace for %d bytes\n",
+                                  fc->name, bch->nr, count);
+                       return;
+               }
+               p = skb_put(bch->rx_skb, count);
        }
-       p = skb_put(bch->rx_skb, count);
        ptr = (u32 *)p;
        if (fc->type == AVM_FRITZ_PCIV2)
                addr = fc->addr + (bch->nr == 2 ?
@@ -426,11 +431,13 @@ hdlc_empty_fifo(struct bchannel *bch, int count)
        cnt = 0;
        while (cnt < count) {
                val = le32_to_cpu(inl(addr));
-               put_unaligned(val, ptr);
-               ptr++;
+               if (p) {
+                       put_unaligned(val, ptr);
+                       ptr++;
+               }
                cnt += 4;
        }
-       if (debug & DEBUG_HW_BFIFO) {
+       if (p && (debug & DEBUG_HW_BFIFO)) {
                snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ",
                         bch->nr, fc->name, count);
                print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count);
index db9b045..5e402cf 100644 (file)
@@ -2224,8 +2224,11 @@ next_frame:
        HFC_wait_nodebug(hc);
 
        /* 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;
+       }
 
        if (dch || test_bit(FLG_HDLC, &bch->Flags)) {
                f1 = HFC_inb_nodebug(hc, A_F1);
@@ -3575,10 +3578,10 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
        switch (cq->op) {
        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;
+               cq->op |= MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP;
                break;
        case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */
+               ret = mISDN_ctrl_bchannel(bch, cq);
                hc->chan[bch->slot].rx_off = !!cq->p1;
                if (!hc->chan[bch->slot].rx_off) {
                        /* reset fifo on rx on */
index 1bd8bc7..81363ff 100644 (file)
@@ -572,6 +572,11 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *rxbz,
        fcnt_tx = B_FIFO_SIZE - fcnt_tx;
        /* 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);
        if (maxlen < 0) {
                pr_warning("B%d: No bufferspace for %d bytes\n",
index b539b10..83206e4 100644 (file)
@@ -842,6 +842,11 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
                hdlc = 1;
        }
        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);
                rx_skb = fifo->bch->rx_skb;
                if (maxlen < 0) {
index 374a177..752e082 100644 (file)
@@ -936,6 +936,11 @@ hscx_empty_fifo(struct hscx_hw *hscx, u8 count)
        int maxlen;
 
        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);
        if (maxlen < 0) {
                hscx_cmdr(hscx, 0x80); /* RMC */
index 901be32..be5973d 100644 (file)
@@ -429,6 +429,11 @@ isar_rcv_frame(struct isar_ch *ch)
                ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
                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) {
        case ISDN_P_NONE:
                pr_debug("%s: ISAR protocol 0 spurious IIS_RDATA %x/%x/%x\n",
index aa95cc7..c3e3e76 100644 (file)
@@ -386,6 +386,10 @@ read_dma(struct tiger_ch *bc, u32 idx, int cnt)
                        bc->bch.nr, 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);
        /* only transparent use the count here, HDLC overun is detected later */
        if (stat == ENOMEM) {
index 183181f..26a86b8 100644 (file)
@@ -475,6 +475,11 @@ W6692_empty_Bfifo(struct w6692_ch *wch, int count)
                        skb_trim(wch->bch.rx_skb, 0);
                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);
        if (maxlen < 0) {
                WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
index e541b65..ef34fd4 100644 (file)
@@ -142,6 +142,8 @@ mISDN_clear_bchannel(struct bchannel *ch)
        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);
+       test_and_clear_bit(FLG_RX_OFF, &ch->Flags);
+       ch->dropcnt = 0;
        ch->minlen = ch->init_minlen;
        ch->next_minlen = ch->init_minlen;
        ch->maxlen = ch->init_maxlen;
@@ -167,7 +169,8 @@ mISDN_ctrl_bchannel(struct bchannel *bch, struct mISDN_ctrl_req *cq)
 
        switch (cq->op) {
        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;
        case MISDN_CTRL_FILL_EMPTY:
                if (cq->p1) {
@@ -177,6 +180,15 @@ mISDN_ctrl_bchannel(struct bchannel *bch, struct mISDN_ctrl_req *cq)
                        test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
                }
                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:
                if (cq->p2 > MISDN_CTRL_RX_SIZE_IGNORE)
                        bch->next_maxlen = cq->p2;
index 6211842..d0752ec 100644 (file)
@@ -73,6 +73,8 @@
 #define FLG_LL_CONN            25
 #define FLG_DTMFSEND           26
 #define FLG_TX_EMPTY           27
+/* stop sending received data upstream */
+#define FLG_RX_OFF             28
 /* workq events */
 #define FLG_RECVQUEUE          30
 #define        FLG_PHCHANGE            31
@@ -173,6 +175,7 @@ struct bchannel {
        int                     err_crc;
        int                     err_tx;
        int                     err_rx;
+       int                     dropcnt;
 };
 
 extern int     mISDN_initdchannel(struct dchannel *, int, void *);