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 c6fa505a1d1b44baf79865fb6f330cd63d361ee2..c08fc605e56b1d3f20d22180bc836220cdc718e5 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 db9b04519829f39898d6274c46b0f16a719b016c..5e402cf2e79506b82288140334da60eb4e923e6d 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 1bd8bc7eb5c7cff3889670ac07ef818410e68f66..81363ffa5357f11213c6b87b3dc4b0d80786d6ae 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 b539b10d6f3e1476078db174f6e88eea72a21e87..83206e453d4e84cfab228b2a571ff3a1e2bba0fa 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 374a17751ffbfe67258e3e865a69dc7a1c7fc3f2..752e0825591fbed9e820044495d42b9a80842320 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 901be3257a7b8ce8d2c7050297e30c309cb0ab04..be5973ded6d6e4288fe8fdebd0967150228ff937 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 aa95cc7d32f994d2eff9190f5b80ec0bf39ccec6..c3e3e76862731496b6bea5d35b3ca8ef5662e486 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 183181f019272000f56684bbe41541ac0981bc38..26a86b8460992e5e98c722f8b6487fb8ff1fe932 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 e541b65f68badd836b948c73cff5095919e22721..ef34fd40867cb6b7f5b767542c4da2e173d6b9cc 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 62118421656630f0829a06584996983edbaf4b75..d0752eca9b4495011f6f82b20ba4e487b06ad6da 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 *);