mISDN: Implement MISDN_CTRL_FILL_EMPTY for more drivers
authorKarsten Keil <kkeil@linux-pingi.de>
Tue, 15 May 2012 23:51:07 +0000 (23:51 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 16 May 2012 19:24:05 +0000 (15:24 -0400)
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>
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/dsp_core.c
drivers/isdn/mISDN/hwchannel.c
include/linux/mISDNhw.h

index 7cd3a963ed2e70a6595e5672e52bbd111fe66842..c6fa505a1d1b44baf79865fb6f330cd63d361ee2 100644 (file)
@@ -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;
index 3d4b36d2a31afb6f04580cfc2364c04d907c92d9..db9b04519829f39898d6274c46b0f16a719b016c 100644 (file)
@@ -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;
index 27743754ab8132c9d338523fa0a2df22b9f93bcf..1bd8bc7eb5c7cff3889670ac07ef818410e68f66 100644 (file)
@@ -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))
index 9c17473da83b745a6a442bfcdfe559730268b491..b539b10d6f3e1476078db174f6e88eea72a21e87 100644 (file)
@@ -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) ",
index 3e71a5ef4bbca24de59a008c6d53300e2f5019d5..374a17751ffbfe67258e3e865a69dc7a1c7fc3f2 100644 (file)
@@ -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,
index e74ad385e73fe9452236f6dcc65957f089f4be15..901be3257a7b8ce8d2c7050297e30c309cb0ab04 100644 (file)
@@ -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;
index 47d30749d8a75d9d9e16b890d43a706e06188c98..aa95cc7d32f994d2eff9190f5b80ec0bf39ccec6 100644 (file)
@@ -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
index 03fb4a34fd53f71f093ad20868614442a5800750..183181f019272000f56684bbe41541ac0981bc38 100644 (file)
@@ -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;
index 2ac2d7a25a9f53103eb4d95b5e919aaa4067fd1b..28c99c623bcd7f89269944f788ab903f0d0c1ce0 100644 (file)
@@ -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__);
index d42ad0e98de35b274bad13e18ab83a78e5a2bf95..e541b65f68badd836b948c73cff5095919e22721 100644 (file)
@@ -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)
index 226886cf31e7fd74ab94bcf9100750c879e29c81..62118421656630f0829a06584996983edbaf4b75 100644 (file)
@@ -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 */