dahdi: Move the conferencing ioctls into their own functions.

DAHDI_GETCONF, DAHDI_SETCONF, DAHDI_CONFLINK, and DAHDI_CONFDIAG are all
now in their own functions.

Review: https://reviewboard.asterisk.org/r/905/

Signed-off-by: Shaun Ruffell <sruffell@digium.com>

git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@9358 a0bf4364-ded3-4de4-8d8a-66a801d63aff
This commit is contained in:
Shaun Ruffell
2010-09-20 20:32:51 +00:00
parent 1e068dcf6c
commit b7545e9d0d

View File

@@ -4769,6 +4769,320 @@ static int ioctl_dahdi_dial(struct dahdi_chan *chan, unsigned long data)
return rv;
}
/**
* is_monitor_mode() - true if dahdi_confinfo is putting chan in monitor mode
*
*/
static bool is_monitor_mode(const struct dahdi_confinfo *conf)
{
const int confmode = conf->confmode & DAHDI_CONF_MODE_MASK;
if ((confmode == DAHDI_CONF_MONITOR) ||
(confmode == DAHDI_CONF_MONITORTX) ||
(confmode == DAHDI_CONF_MONITORBOTH) ||
(confmode == DAHDI_CONF_MONITOR_RX_PREECHO) ||
(confmode == DAHDI_CONF_MONITOR_TX_PREECHO) ||
(confmode == DAHDI_CONF_MONITORBOTH_PREECHO)) {
return true;
} else {
return false;
}
}
static int dahdi_ioctl_setconf(struct file *file, unsigned long data)
{
struct dahdi_confinfo conf;
struct dahdi_chan *chan;
unsigned long flags;
unsigned int confmode;
int j;
if (copy_from_user(&conf, (void __user *)data, sizeof(conf)))
return -EFAULT;
confmode = conf.confmode & DAHDI_CONF_MODE_MASK;
if (conf.chan) {
VALID_CHANNEL(conf.chan);
chan = chans[conf.chan];
} else {
if (file->private_data) {
chan = file->private_data;
} else {
VALID_CHANNEL(UNIT(file));
chan = chans[UNIT(file)];
}
}
if (!(chan->flags & DAHDI_FLAG_AUDIO))
return -EINVAL;
if (is_monitor_mode(&conf)) {
/* Monitor mode -- it's a channel */
if ((conf.confno < 0) || (conf.confno >= DAHDI_MAX_CHANNELS) ||
!chans[conf.confno])
return -EINVAL;
} else {
/* make sure conf number makes sense, too */
if ((conf.confno < -1) || (conf.confno > DAHDI_MAX_CONF))
return -EINVAL;
}
/* if taking off of any conf, must have 0 mode */
if ((!conf.confno) && conf.confmode)
return -EINVAL;
/* likewise if 0 mode must have no conf */
if ((!conf.confmode) && conf.confno)
return -EINVAL;
conf.chan = chan->channo; /* return with real channel # */
spin_lock_irqsave(&bigzaplock, flags);
spin_lock(&chan->lock);
if (conf.confno == -1)
conf.confno = dahdi_first_empty_conference();
if ((conf.confno < 1) && (conf.confmode)) {
/* No more empty conferences */
spin_unlock(&chan->lock);
spin_unlock_irqrestore(&bigzaplock, flags);
return -EBUSY;
}
/* if changing confs, clear last added info */
if (conf.confno != chan->confna) {
memset(chan->conflast, 0, DAHDI_MAX_CHUNKSIZE);
memset(chan->conflast1, 0, DAHDI_MAX_CHUNKSIZE);
memset(chan->conflast2, 0, DAHDI_MAX_CHUNKSIZE);
}
j = chan->confna; /* save old conference number */
chan->confna = conf.confno; /* set conference number */
chan->confmode = conf.confmode; /* set conference mode */
chan->_confn = 0; /* Clear confn */
dahdi_check_conf(j);
dahdi_check_conf(conf.confno);
if (chan->span && chan->span->ops->dacs) {
if ((confmode == DAHDI_CONF_DIGITALMON) &&
(chan->txgain == defgain) &&
(chan->rxgain == defgain) &&
(chans[conf.confno]->txgain == defgain) &&
(chans[conf.confno]->rxgain == defgain)) {
dahdi_chan_dacs(chan, chans[conf.confno]);
} else {
dahdi_disable_dacs(chan);
}
}
/* if we are going onto a conf */
if (conf.confno &&
(confmode == DAHDI_CONF_CONF ||
confmode == DAHDI_CONF_CONFANN ||
confmode == DAHDI_CONF_CONFMON ||
confmode == DAHDI_CONF_CONFANNMON ||
confmode == DAHDI_CONF_REALANDPSEUDO)) {
/* Get alias */
chan->_confn = dahdi_get_conf_alias(conf.confno);
}
if (chans[conf.confno]) {
if ((confmode == DAHDI_CONF_MONITOR_RX_PREECHO) ||
(confmode == DAHDI_CONF_MONITOR_TX_PREECHO) ||
(confmode == DAHDI_CONF_MONITORBOTH_PREECHO)) {
void *temp = kmalloc(sizeof(*chan->readchunkpreec) *
DAHDI_CHUNKSIZE, GFP_ATOMIC);
chans[conf.confno]->readchunkpreec = temp;
} else {
kfree(chans[conf.confno]->readchunkpreec);
chans[conf.confno]->readchunkpreec = NULL;
}
}
spin_unlock(&chan->lock);
spin_unlock_irqrestore(&bigzaplock, flags);
if (copy_to_user((void __user *)data, &conf, sizeof(conf)))
return -EFAULT;
return 0;
}
static int dahdi_ioctl_conflink(struct file *file, unsigned long data)
{
struct dahdi_chan *chan;
struct dahdi_confinfo conf;
unsigned long flags;
int res = 0;
int i;
if (file->private_data) {
chan = file->private_data;
} else {
VALID_CHANNEL(UNIT(file));
chan = chans[UNIT(file)];
}
if (!(chan->flags & DAHDI_FLAG_AUDIO))
return -EINVAL;
if (copy_from_user(&conf, (void __user *)data, sizeof(conf)))
return -EFAULT;
/* check sanity of arguments */
if ((conf.chan < 0) || (conf.chan > DAHDI_MAX_CONF))
return -EINVAL;
if ((conf.confno < 0) || (conf.confno > DAHDI_MAX_CONF))
return -EINVAL;
/* cant listen to self!! */
if (conf.chan && (conf.chan == conf.confno))
return -EINVAL;
spin_lock_irqsave(&bigzaplock, flags);
spin_lock(&chan->lock);
/* if to clear all links */
if ((!conf.chan) && (!conf.confno)) {
/* clear all the links */
memset(conf_links, 0, sizeof(conf_links));
recalc_maxlinks();
spin_unlock(&chan->lock);
spin_unlock_irqrestore(&bigzaplock, flags);
return 0;
}
/* look for already existant specified combination */
for (i = 1; i <= DAHDI_MAX_CONF; i++) {
/* if found, exit */
if ((conf_links[i].src == conf.chan) &&
(conf_links[i].dst == conf.confno))
break;
}
if (i <= DAHDI_MAX_CONF) { /* if found */
if (!conf.confmode) { /* if to remove link */
conf_links[i].src = 0;
conf_links[i].dst = 0;
} else { /* if to add and already there, error */
res = -EEXIST;
}
} else { /* if not found */
if (conf.confmode) { /* if to add link */
/* look for empty location */
for (i = 1; i <= DAHDI_MAX_CONF; i++) {
/* if empty, exit loop */
if ((!conf_links[i].src) &&
(!conf_links[i].dst))
break;
}
/* if empty spot found */
if (i <= DAHDI_MAX_CONF) {
conf_links[i].src = conf.chan;
conf_links[i].dst = conf.confno;
} else { /* if no empties -- error */
res = -ENOSPC;
}
} else { /* if to remove, and not found -- error */
res = -ENOENT;
}
}
recalc_maxlinks();
spin_unlock(&chan->lock);
spin_unlock_irqrestore(&bigzaplock, flags);
return res;
}
/**
* dahdi_ioctl_confdiag() - Output debug info about conferences to console.
*
* This is a pure debugging aide since the only result is to the console.
*
* TODO: Does anyone use this anymore? Should it be hidden behind a debug
* compile time option?
*/
static int dahdi_ioctl_confdiag(struct file *file, unsigned long data)
{
struct dahdi_chan *chan;
int rv;
int i;
int j;
int c;
int k;
if (file->private_data) {
chan = file->private_data;
} else {
VALID_CHANNEL(UNIT(file));
chan = chans[UNIT(file)];
}
if (!(chan->flags & DAHDI_FLAG_AUDIO))
return -EINVAL;
get_user(j, (int __user *)data); /* get conf # */
/* loop thru the interesting ones */
for (i = ((j) ? j : 1); i <= ((j) ? j : DAHDI_MAX_CONF); i++) {
c = 0;
for (k = 1; k < DAHDI_MAX_CHANNELS; k++) {
struct dahdi_chan *const pos = chans[k];
/* skip if no pointer */
if (!pos)
continue;
/* skip if not in this conf */
if (pos->confna != i)
continue;
if (!c) {
module_printk(KERN_NOTICE,
"Conf #%d:\n", i);
}
c = 1;
module_printk(KERN_NOTICE, "chan %d, mode %x\n",
k, pos->confmode);
}
rv = 0;
for (k = 1; k <= DAHDI_MAX_CONF; k++) {
if (conf_links[k].dst == i) {
if (!c) {
c = 1;
module_printk(KERN_NOTICE,
"Conf #%d:\n", i);
}
if (!rv) {
rv = 1;
module_printk(KERN_NOTICE,
"Snooping on:\n");
}
module_printk(KERN_NOTICE, "conf %d\n",
conf_links[k].src);
}
}
if (c)
module_printk(KERN_NOTICE, "\n");
}
return 0;
}
static int dahdi_ioctl_getconf(struct file *file, unsigned long data)
{
struct dahdi_confinfo conf;
struct dahdi_chan *chan;
if (copy_from_user(&conf, (void __user *)data, sizeof(conf)))
return -EFAULT;
if (!conf.chan) {
/* If 0, use the current channel. */
if (file->private_data) {
chan = file->private_data;
} else {
VALID_CHANNEL(UNIT(file));
chan = chans[UNIT(file)];
}
} else {
VALID_CHANNEL(conf.chan);
chan = chans[conf.chan];
}
if (!chan)
return -EINVAL;
if (!(chan->flags & DAHDI_FLAG_AUDIO))
return -EINVAL;
conf.chan = chan->channo; /* get channel number */
conf.confno = chan->confna; /* get conference number */
conf.confmode = chan->confmode; /* get conference mode */
if (copy_to_user((void __user *)data, &conf, sizeof(conf)))
return -EFAULT;
return 0;
}
static int
dahdi_chanandpseudo_ioctl(struct file *file, unsigned int cmd,
unsigned long data, int unit)
@@ -4776,12 +5090,11 @@ dahdi_chanandpseudo_ioctl(struct file *file, unsigned int cmd,
struct dahdi_chan *chan = chans[unit];
union {
struct dahdi_bufferinfo bi;
struct dahdi_confinfo conf;
struct dahdi_ring_cadence cad;
} stack;
unsigned long flags;
int i, j, k, rv;
int ret, c;
int i, j, rv;
int ret;
void __user * const user_data = (void __user *)data;
if (!chan)
@@ -4992,214 +5305,19 @@ dahdi_chanandpseudo_ioctl(struct file *file, unsigned int cmd,
return rv;
case DAHDI_GETCONF_V1: /* intentional drop through */
case DAHDI_GETCONF: /* get conf stuff */
if (copy_from_user(&stack.conf, user_data, sizeof(stack.conf)))
return -EFAULT;
i = stack.conf.chan; /* get channel no */
/* if zero, use current channel no */
if (!i) i = chan->channo;
/* make sure channel number makes sense */
if ((i < 0) || (i > DAHDI_MAX_CONF) || (!chans[i])) return(-EINVAL);
if (!(chans[i]->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL);
stack.conf.chan = i; /* get channel number */
stack.conf.confno = chans[i]->confna; /* get conference number */
stack.conf.confmode = chans[i]->confmode; /* get conference mode */
if (copy_to_user(user_data, &stack.conf, sizeof(stack.conf)))
return -EFAULT;
break;
return dahdi_ioctl_getconf(file, data);
case DAHDI_SETCONF_V1: /* Intentional fall through. */
case DAHDI_SETCONF: /* set conf stuff */
if (copy_from_user(&stack.conf, user_data, sizeof(stack.conf)))
return -EFAULT;
i = stack.conf.chan; /* get channel no */
/* if zero, use current channel no */
if (!i) i = chan->channo;
/* make sure channel number makes sense */
if ((i < 1) || (i > DAHDI_MAX_CHANNELS) || (!chans[i])) return(-EINVAL);
if (!(chans[i]->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL);
if ((stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITOR ||
(stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITORTX ||
(stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITORBOTH ||
(stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITOR_RX_PREECHO ||
(stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITOR_TX_PREECHO ||
(stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITORBOTH_PREECHO) {
/* Monitor mode -- it's a channel */
if ((stack.conf.confno < 0) || (stack.conf.confno >= DAHDI_MAX_CHANNELS) || !chans[stack.conf.confno]) return(-EINVAL);
} else {
/* make sure conf number makes sense, too */
if ((stack.conf.confno < -1) || (stack.conf.confno > DAHDI_MAX_CONF)) return(-EINVAL);
}
return dahdi_ioctl_setconf(file, data);
/* if taking off of any conf, must have 0 mode */
if ((!stack.conf.confno) && stack.conf.confmode) return(-EINVAL);
/* likewise if 0 mode must have no conf */
if ((!stack.conf.confmode) && stack.conf.confno) return (-EINVAL);
stack.conf.chan = i; /* return with real channel # */
spin_lock_irqsave(&bigzaplock, flags);
spin_lock(&chan->lock);
if (stack.conf.confno == -1)
stack.conf.confno = dahdi_first_empty_conference();
if ((stack.conf.confno < 1) && (stack.conf.confmode)) {
/* No more empty conferences */
spin_unlock(&chan->lock);
spin_unlock_irqrestore(&bigzaplock, flags);
return -EBUSY;
}
/* if changing confs, clear last added info */
if (stack.conf.confno != chans[i]->confna) {
memset(chans[i]->conflast, 0, DAHDI_MAX_CHUNKSIZE);
memset(chans[i]->conflast1, 0, DAHDI_MAX_CHUNKSIZE);
memset(chans[i]->conflast2, 0, DAHDI_MAX_CHUNKSIZE);
}
j = chans[i]->confna; /* save old conference number */
chans[i]->confna = stack.conf.confno; /* set conference number */
chans[i]->confmode = stack.conf.confmode; /* set conference mode */
chans[i]->_confn = 0; /* Clear confn */
dahdi_check_conf(j);
dahdi_check_conf(stack.conf.confno);
if (chans[i]->span && chans[i]->span->ops->dacs) {
if (((stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_DIGITALMON) &&
chans[i]->txgain == defgain &&
chans[i]->rxgain == defgain &&
chans[stack.conf.confno]->txgain == defgain &&
chans[stack.conf.confno]->rxgain == defgain) {
dahdi_chan_dacs(chans[i], chans[stack.conf.confno]);
} else {
dahdi_disable_dacs(chans[i]);
}
}
/* if we are going onto a conf */
if (stack.conf.confno &&
((stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_CONF ||
(stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_CONFANN ||
(stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_CONFMON ||
(stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_CONFANNMON ||
(stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_REALANDPSEUDO)) {
/* Get alias */
chans[i]->_confn = dahdi_get_conf_alias(stack.conf.confno);
}
if (chans[stack.conf.confno]) {
if ((stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITOR_RX_PREECHO ||
(stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITOR_TX_PREECHO ||
(stack.conf.confmode & DAHDI_CONF_MODE_MASK) == DAHDI_CONF_MONITORBOTH_PREECHO)
chans[stack.conf.confno]->readchunkpreec = kmalloc(sizeof(*chans[stack.conf.confno]->readchunkpreec) * DAHDI_CHUNKSIZE, GFP_ATOMIC);
else {
if (chans[stack.conf.confno]->readchunkpreec) {
kfree(chans[stack.conf.confno]->readchunkpreec);
chans[stack.conf.confno]->readchunkpreec = NULL;
}
}
}
spin_unlock(&chan->lock);
spin_unlock_irqrestore(&bigzaplock, flags);
if (copy_to_user(user_data, &stack.conf, sizeof(stack.conf)))
return -EFAULT;
break;
case DAHDI_CONFLINK: /* do conf link stuff */
if (!(chan->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL);
if (copy_from_user(&stack.conf, user_data, sizeof(stack.conf)))
return -EFAULT;
/* check sanity of arguments */
if ((stack.conf.chan < 0) || (stack.conf.chan > DAHDI_MAX_CONF)) return(-EINVAL);
if ((stack.conf.confno < 0) || (stack.conf.confno > DAHDI_MAX_CONF)) return(-EINVAL);
/* cant listen to self!! */
if (stack.conf.chan && (stack.conf.chan == stack.conf.confno)) return(-EINVAL);
spin_lock_irqsave(&bigzaplock, flags);
spin_lock(&chan->lock);
/* if to clear all links */
if ((!stack.conf.chan) && (!stack.conf.confno))
{
/* clear all the links */
memset(conf_links,0,sizeof(conf_links));
recalc_maxlinks();
spin_unlock(&chan->lock);
spin_unlock_irqrestore(&bigzaplock, flags);
break;
}
rv = 0; /* clear return value */
/* look for already existant specified combination */
for(i = 1; i <= DAHDI_MAX_CONF; i++)
{
/* if found, exit */
if ((conf_links[i].src == stack.conf.chan) &&
(conf_links[i].dst == stack.conf.confno)) break;
}
if (i <= DAHDI_MAX_CONF) /* if found */
{
if (!stack.conf.confmode) /* if to remove link */
{
conf_links[i].src = conf_links[i].dst = 0;
}
else /* if to add and already there, error */
{
rv = -EEXIST;
}
}
else /* if not found */
{
if (stack.conf.confmode) /* if to add link */
{
/* look for empty location */
for(i = 1; i <= DAHDI_MAX_CONF; i++)
{
/* if empty, exit loop */
if ((!conf_links[i].src) &&
(!conf_links[i].dst)) break;
}
/* if empty spot found */
if (i <= DAHDI_MAX_CONF)
{
conf_links[i].src = stack.conf.chan;
conf_links[i].dst = stack.conf.confno;
}
else /* if no empties -- error */
{
rv = -ENOSPC;
}
}
else /* if to remove, and not found -- error */
{
rv = -ENOENT;
}
}
recalc_maxlinks();
spin_unlock(&chan->lock);
spin_unlock_irqrestore(&bigzaplock, flags);
return(rv);
return dahdi_ioctl_conflink(file, data);
case DAHDI_CONFDIAG_V1: /* Intentional fall-through */
case DAHDI_CONFDIAG: /* output diagnostic info to console */
if (!(chan->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL);
get_user(j, (int __user *)data); /* get conf # */
/* loop thru the interesting ones */
for(i = ((j) ? j : 1); i <= ((j) ? j : DAHDI_MAX_CONF); i++)
{
c = 0;
for(k = 1; k < DAHDI_MAX_CHANNELS; k++)
{
/* skip if no pointer */
if (!chans[k]) continue;
/* skip if not in this conf */
if (chans[k]->confna != i) continue;
if (!c) module_printk(KERN_NOTICE, "Conf #%d:\n",i);
c = 1;
module_printk(KERN_NOTICE, "chan %d, mode %x\n", k,chans[k]->confmode);
}
rv = 0;
for(k = 1; k <= DAHDI_MAX_CONF; k++)
{
if (conf_links[k].dst == i)
{
if (!c) module_printk(KERN_NOTICE, "Conf #%d:\n",i);
c = 1;
if (!rv) module_printk(KERN_NOTICE, "Snooping on:\n");
rv = 1;
module_printk(KERN_NOTICE, "conf %d\n",conf_links[k].src);
}
}
if (c) module_printk(KERN_NOTICE, "\n");
}
break;
return dahdi_ioctl_confdiag(file, data);
case DAHDI_CHANNO: /* get channel number of stream */
/* return unit/channel number */
put_user(unit, (int __user *)data);