From e08995ee066063a3db960046bc5b6c0543db0444 Mon Sep 17 00:00:00 2001 From: Shaun Ruffell Date: Wed, 9 Jul 2008 21:27:07 +0000 Subject: Saving off some work in progress on half-full buffering. Still needs a method for dumping half the buffer on tx overrun from the user side. Also, the behavior of half-full on the rx side has not been checked. git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@4589 a0bf4364-ded3-4de4-8d8a-66a801d63aff --- drivers/dahdi/dahdi-base.c | 139 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 106 insertions(+), 33 deletions(-) (limited to 'drivers/dahdi') diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c index 5f9de80..e69b2fb 100644 --- a/drivers/dahdi/dahdi-base.c +++ b/drivers/dahdi/dahdi-base.c @@ -850,15 +850,17 @@ static int dahdi_reallocbufs(struct dahdi_chan *ss, int j, int numbufs) ss->outreadbuf = -1; ss->outwritebuf = -1; ss->numbufs = numbufs; - if (ss->txbufpolicy == DAHDI_POLICY_WHEN_FULL) + if (DAHDI_POLICY_IMMEDIATE != ss->txbufpolicy) { ss->txdisable = 1; - else + } else { ss->txdisable = 0; + } - if (ss->rxbufpolicy == DAHDI_POLICY_WHEN_FULL) + if (DAHDI_POLICY_IMMEDIATE != ss->rxbufpolicy) { ss->rxdisable = 1; - else + } else { ss->rxdisable = 0; + } spin_unlock_irqrestore(&ss->lock, flags); if (oldbuf) @@ -1448,8 +1450,8 @@ static int dahdi_net_open(hdlc_device *hdlc) module_printk(KERN_NOTICE, "%s is not a net device!\n", ms->name); return -EINVAL; } - ms->txbufpolicy = DAHDI_POLICY_IMMEDIATE; - ms->rxbufpolicy = DAHDI_POLICY_IMMEDIATE; + ms->txbufpolicy = DAHDI_POLICY_DEFAULT; + ms->rxbufpolicy = DAHDI_POLICY_DEFAULT; res = dahdi_reallocbufs(ms, DAHDI_DEFAULT_MTU_MRU, DAHDI_DEFAULT_NUM_BUFS); if (res) @@ -1894,8 +1896,9 @@ static ssize_t dahdi_chan_read(struct file *file, char *usrbuf, size_t count, in if (chan->outreadbuf == chan->inreadbuf) { /* Out of stuff */ chan->outreadbuf = -1; - if (chan->rxbufpolicy == DAHDI_POLICY_WHEN_FULL) + if (DAHDI_POLICY_IMMEDIATE != chan->rxbufpolicy) { chan->rxdisable = 1; + } } if (chan->inreadbuf < 0) { /* Notify interrupt handler that we have some space now */ @@ -1906,6 +1909,35 @@ static ssize_t dahdi_chan_read(struct file *file, char *usrbuf, size_t count, in return amnt; } +static int __attribute__((const)) buffers_half_full(int hp, int tp, int length) +{ + if (hp < 0) { + /* We're full... */ + return 1; + } + if (tp < 0) { + /* We're empty ... */ + return 0; + } + if (hp > tp) { + return ((hp - tp) > length / 2) ? 1 : 0; + } else { + return (((length - tp) + hp) > length/2 ) ? 1 : 0; + } +} + +static int tx_buffers_half_full(struct dahdi_chan *chan) +{ + return buffers_half_full(chan->inwritebuf, chan->outwritebuf, + chan->numbufs); +} + +static int rx_buffers_half_full(struct dahdi_chan *chan) +{ + return buffers_half_full(chan->inreadbuf, chan->outreadbuf, + chan->numbufs); +} + static ssize_t dahdi_chan_write(struct file *file, const char *usrbuf, size_t count, int unit) { unsigned long flags; @@ -1934,7 +1966,14 @@ static ssize_t dahdi_chan_write(struct file *file, const char *usrbuf, size_t co spin_unlock_irqrestore(&chan->lock, flags); if (res >= 0) break; - if (file->f_flags & O_NONBLOCK) + + if (DAHDI_POLICY_HALF_FULL == chan->txbufpolicy) { + if (chan->flags & DAHDI_FLAG_AUDIO) { + /* dahdi_flush_half_tx_buffers(chan); */ + ; + } + } + if (file->f_flags & O_NONBLOCK) return -EAGAIN; /* Wait for something to be available */ rv = schluffen(&chan->writebufq); @@ -2002,6 +2041,14 @@ static ssize_t dahdi_chan_write(struct file *file, const char *usrbuf, size_t co chan->inwritebuf = -1; /* Make sure the transmitter is transmitting in case of POLICY_WHEN_FULL */ chan->txdisable = 0; + } else if (chan->txdisable) { + /* We might need to enable the transmitter again if the + * policy is set to half full. */ + if (DAHDI_POLICY_HALF_FULL == chan->txbufpolicy) { + if (tx_buffers_half_full(chan)) { + chan->txdisable = 0; + } + } } if (chan->outwritebuf < 0) { /* Okay, the interrupt handler has been waiting for us. Give them a buffer */ @@ -2242,8 +2289,8 @@ static int initialize_channel(struct dahdi_chan *chan) spin_lock_irqsave(&chan->lock, flags); - chan->rxbufpolicy = DAHDI_POLICY_IMMEDIATE; - chan->txbufpolicy = DAHDI_POLICY_IMMEDIATE; + chan->rxbufpolicy = DAHDI_POLICY_DEFAULT; + chan->txbufpolicy = DAHDI_POLICY_DEFAULT; ec_state = chan->ec_state; chan->ec_state = NULL; @@ -4101,6 +4148,29 @@ static int ioctl_dahdi_dial(struct dahdi_chan *chan, unsigned long data) return rv; } +static void dahdi_flush_tx_buffers(struct dahdi_chan *chan) +{ + int j; + /* initialize write buffers and pointers */ + chan->outwritebuf = -1; + chan->inwritebuf = 0; + for (j=0;jnumbufs;j++) { + /* Do we need this? */ + chan->writen[j] = 0; + chan->writeidx[j] = 0; + } + wake_up_interruptible(&chan->writebufq); /* wake_up_interruptible waiting on write */ + wake_up_interruptible(&chan->sel); /* wake_up_interruptible waiting on select */ + /* if IO MUX wait on write empty, well, this + certainly *did* empty the write */ + if (chan->iomask & DAHDI_IOMUX_WRITEEMPTY) + wake_up_interruptible(&chan->eventbufq); /* wake_up_interruptible waiting on IOMUX */ + + if (DAHDI_POLICY_IMMEDIATE != chan->txbufpolicy) { + chan->txdisable = 1; + } +} + static int dahdi_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data, int unit) { struct dahdi_chan *chan = chans[unit]; @@ -4145,8 +4215,11 @@ static int dahdi_chanandpseudo_ioctl(struct inode *inode, struct file *file, uns return -EINVAL; if (stack.bi.bufsize * stack.bi.numbufs > DAHDI_MAX_BUF_SPACE) return -EINVAL; - chan->rxbufpolicy = stack.bi.rxbufpolicy & 0x1; - chan->txbufpolicy = stack.bi.txbufpolicy & 0x1; + /* TODO: Change mask to inline function to validate the policy. */ + chan->rxbufpolicy = stack.bi.rxbufpolicy & 0x3; + chan->txbufpolicy = stack.bi.txbufpolicy & 0x3; + /* !!!SRR!!! */ + printk(KERN_DEBUG "txpolicy: %d rxpolicy: %d\n", chan->txbufpolicy, chan->rxbufpolicy); if ((rv = dahdi_reallocbufs(chan, stack.bi.bufsize, stack.bi.numbufs))) return (rv); break; @@ -4179,24 +4252,14 @@ static int dahdi_chanandpseudo_ioctl(struct inode *inode, struct file *file, uns } wake_up_interruptible(&chan->readbufq); /* wake_up_interruptible waiting on read */ wake_up_interruptible(&chan->sel); /* wake_up_interruptible waiting on select */ - } - if (i & DAHDI_FLUSH_WRITE) /* if for write (output) */ - { - /* initialize write buffers and pointers */ - chan->outwritebuf = -1; - chan->inwritebuf = 0; - for (j=0;jnumbufs;j++) { - /* Do we need this? */ - chan->writen[j] = 0; - chan->writeidx[j] = 0; + + if (DAHDI_POLICY_IMMEDIATE != chan->rxbufpolicy) { + chan->txdisable = 1; } - wake_up_interruptible(&chan->writebufq); /* wake_up_interruptible waiting on write */ - wake_up_interruptible(&chan->sel); /* wake_up_interruptible waiting on select */ - /* if IO MUX wait on write empty, well, this - certainly *did* empty the write */ - if (chan->iomask & DAHDI_IOMUX_WRITEEMPTY) - wake_up_interruptible(&chan->eventbufq); /* wake_up_interruptible waiting on IOMUX */ } + if (i & DAHDI_FLUSH_WRITE) { /* if for write (output) */ + dahdi_flush_tx_buffers(chan); + } if (i & DAHDI_FLUSH_EVENT) /* if for events */ { /* initialize the event pointers */ @@ -5753,18 +5816,20 @@ static inline void __dahdi_getbuf_chunk(struct dahdi_chan *ss, unsigned char *tx ms->outwritebuf = -1; if (ms->iomask & (DAHDI_IOMUX_WRITE | DAHDI_IOMUX_WRITEEMPTY)) wake_up_interruptible(&ms->eventbufq); - /* If we're only supposed to start when full, disable the transmitter */ - if (ms->txbufpolicy == DAHDI_POLICY_WHEN_FULL) + /* If we're only supposed to start when not empty, disable the transmitter */ + if (DAHDI_POLICY_IMMEDIATE != ms->txbufpolicy) { ms->txdisable = 1; + } } } else { if (ms->outwritebuf == ms->inwritebuf) { ms->outwritebuf = oldbuf; if (ms->iomask & (DAHDI_IOMUX_WRITE | DAHDI_IOMUX_WRITEEMPTY)) wake_up_interruptible(&ms->eventbufq); - /* If we're only supposed to start when full, disable the transmitter */ - if (ms->txbufpolicy == DAHDI_POLICY_WHEN_FULL) + /* If we're only supposed to start when not empty, disable the transmitter */ + if (DAHDI_POLICY_IMMEDIATE != ms->txbufpolicy) { ms->txdisable = 1; + } } } if (ms->inwritebuf < 0) { @@ -6827,7 +6892,14 @@ static inline void __putbuf_chunk(struct dahdi_chan *ss, unsigned char *rxb, int ms->inreadbuf = -1; /* Enable the receiver in case they've got POLICY_WHEN_FULL */ ms->rxdisable = 0; + } else if (ms->rxdisable) { + if (DAHDI_POLICY_HALF_FULL == ms->rxbufpolicy) { + if (rx_buffers_half_full(ms)) { + ms->rxdisable = 0; + } + } } + if (ms->outreadbuf < 0) { /* start out buffer if not already */ ms->outreadbuf = oldbuf; } @@ -7066,8 +7138,9 @@ extern int dahdi_hdlc_getbuf(struct dahdi_chan *ss, unsigned char *bufptr, unsig if (ss->iomask & (DAHDI_IOMUX_WRITE | DAHDI_IOMUX_WRITEEMPTY)) wake_up_interruptible(&ss->eventbufq); /* If we're only supposed to start when full, disable the transmitter */ - if (ss->txbufpolicy == DAHDI_POLICY_WHEN_FULL) + if (DAHDI_POLICY_IMMEDIATE != ss->txbufpolicy) { ss->txdisable = 1; + } res = -1; } -- cgit v1.2.3