summaryrefslogtreecommitdiff
path: root/drivers/dahdi/dahdi-base.c
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2009-09-07 21:40:22 +0000
committerShaun Ruffell <sruffell@digium.com>2009-09-07 21:40:22 +0000
commitde8dd71cbb0cbaff9edad8a005bc60b47843da52 (patch)
treea8e4d17081c9e647eeec86cc66bda765f1e17021 /drivers/dahdi/dahdi-base.c
parent8337f8159e0c46fc38d527966996b19d87097aee (diff)
dahdi-base: Reduce the stack usage of dahdi_common_ioctl.
Split the DAHDI_GETGAINS and DAHDI_SETGAINS ioctls into their own functions and dynamically allocate the 'struct dahdi_gains' structure to reduce the pressure on the stack. git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@7095 a0bf4364-ded3-4de4-8d8a-66a801d63aff
Diffstat (limited to 'drivers/dahdi/dahdi-base.c')
-rw-r--r--drivers/dahdi/dahdi-base.c187
1 files changed, 124 insertions, 63 deletions
diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c
index 359458a..8a8c470 100644
--- a/drivers/dahdi/dahdi-base.c
+++ b/drivers/dahdi/dahdi-base.c
@@ -3510,16 +3510,136 @@ static int dahdi_timer_ioctl(struct inode *node, struct file *file, unsigned int
return 0;
}
+static int dahdi_ioctl_getgains(struct inode *node, struct file *file,
+ unsigned int cmd, unsigned long data, int unit)
+{
+ int res = 0;
+ struct dahdi_gains *gain;
+ int i, j;
+
+ gain = kzalloc(sizeof(*gain), GFP_KERNEL);
+ if (!gain)
+ return -ENOMEM;
+
+ if (copy_from_user(gain, (struct dahdi_gains *)data, sizeof(*gain))) {
+ res = -EFAULT;
+ goto cleanup;
+ }
+ i = gain->chan; /* get channel no */
+ /* if zero, use current channel no */
+ if (!i)
+ i = unit;
+
+ /* make sure channel number makes sense */
+ if ((i < 0) || (i > DAHDI_MAX_CHANNELS) || !chans[i]) {
+ res = -EINVAL;
+ goto cleanup;
+ }
+
+ if (!(chans[i]->flags & DAHDI_FLAG_AUDIO)) {
+ res = -EINVAL;
+ goto cleanup;
+ }
+ gain->chan = i; /* put the span # in here */
+ for (j = 0; j < 256; ++j) {
+ gain->txgain[j] = chans[i]->txgain[j];
+ gain->rxgain[j] = chans[i]->rxgain[j];
+ }
+ if (copy_to_user((struct dahdi_gains *)data, gain, sizeof(*gain))) {
+ res = -EFAULT;
+ goto cleanup;
+ }
+cleanup:
+
+ kfree(gain);
+ return 0;
+}
+
+static int dahdi_ioctl_setgains(struct inode *node, struct file *file,
+ unsigned int cmd, unsigned long data, int unit)
+{
+ int res = 0;
+ struct dahdi_gains *gain;
+ unsigned char *txgain, *rxgain;
+ int i, j;
+ unsigned long flags;
+ const int GAIN_TABLE_SIZE = sizeof(defgain);
+
+ gain = kzalloc(sizeof(*gain), GFP_KERNEL);
+ if (!gain)
+ return -ENOMEM;
+
+ if (copy_from_user(gain, (struct dahdi_gains *)data, sizeof(*gain))) {
+ res = -EFAULT;
+ goto cleanup;
+ }
+ i = gain->chan; /* get channel no */
+ /* if zero, use current channel no */
+ if (!i)
+ i = unit;
+ /* make sure channel number makes sense */
+ if ((i < 0) || (i > DAHDI_MAX_CHANNELS) || !chans[i]) {
+ res = -EINVAL;
+ goto cleanup;
+ }
+ if (!(chans[i]->flags & DAHDI_FLAG_AUDIO)) {
+ res = -EINVAL;
+ goto cleanup;
+ }
+
+ rxgain = kzalloc(GAIN_TABLE_SIZE*2, GFP_KERNEL);
+ if (!rxgain) {
+ res = -ENOMEM;
+ goto cleanup;
+ }
+
+ gain->chan = i; /* put the span # in here */
+ txgain = rxgain + GAIN_TABLE_SIZE;
+
+ for (j = 0; j < GAIN_TABLE_SIZE; ++j) {
+ rxgain[j] = gain->rxgain[j];
+ txgain[j] = gain->txgain[j];
+ }
+
+ if (!memcmp(rxgain, defgain, GAIN_TABLE_SIZE) &&
+ !memcmp(txgain, defgain, GAIN_TABLE_SIZE)) {
+ kfree(rxgain);
+ spin_lock_irqsave(&chans[i]->lock, flags);
+ if (chans[i]->gainalloc)
+ kfree(chans[i]->rxgain);
+ chans[i]->gainalloc = 0;
+ chans[i]->rxgain = defgain;
+ chans[i]->txgain = defgain;
+ spin_unlock_irqrestore(&chans[i]->lock, flags);
+ } else {
+ /* This is a custom gain setting */
+ spin_lock_irqsave(&chans[i]->lock, flags);
+ if (chans[i]->gainalloc)
+ kfree(chans[i]->rxgain);
+ chans[i]->gainalloc = 1;
+ chans[i]->rxgain = rxgain;
+ chans[i]->txgain = txgain;
+ spin_unlock_irqrestore(&chans[i]->lock, flags);
+ }
+
+ if (copy_to_user((struct dahdi_gains *)data, gain, sizeof(*gain))) {
+ res = -EFAULT;
+ goto cleanup;
+ }
+cleanup:
+
+ kfree(gain);
+ return 0;
+}
+
static int dahdi_common_ioctl(struct inode *node, struct file *file, unsigned int cmd, unsigned long data, int unit)
{
union {
- struct dahdi_gains gain;
struct dahdi_spaninfo spaninfo;
struct dahdi_params param;
} stack;
struct dahdi_chan *chan;
unsigned long flags;
- unsigned char *txgain, *rxgain;
int i,j;
int return_master = 0;
size_t size_to_copy;
@@ -3645,68 +3765,9 @@ static int dahdi_common_ioctl(struct inode *node, struct file *file, unsigned in
break;
case DAHDI_GETGAINS_V1: /* Intentional drop through. */
case DAHDI_GETGAINS: /* get gain stuff */
- if (copy_from_user(&stack.gain,(struct dahdi_gains *) data,sizeof(stack.gain)))
- return -EFAULT;
- i = stack.gain.chan; /* get channel no */
- /* if zero, use current channel no */
- if (!i) i = unit;
- /* make sure channel number makes sense */
- if ((i < 0) || (i > DAHDI_MAX_CHANNELS) || !chans[i]) return(-EINVAL);
-
- if (!(chans[i]->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL);
- stack.gain.chan = i; /* put the span # in here */
- for (j=0;j<256;j++) {
- stack.gain.txgain[j] = chans[i]->txgain[j];
- stack.gain.rxgain[j] = chans[i]->rxgain[j];
- }
- if (copy_to_user((struct dahdi_gains *) data,&stack.gain,sizeof(stack.gain)))
- return -EFAULT;
- break;
+ return dahdi_ioctl_getgains(node, file, cmd, data, unit);
case DAHDI_SETGAINS: /* set gain stuff */
- if (copy_from_user(&stack.gain,(struct dahdi_gains *) data,sizeof(stack.gain)))
- return -EFAULT;
- i = stack.gain.chan; /* get channel no */
- /* if zero, use current channel no */
- if (!i) i = unit;
- /* make sure channel number makes sense */
- if ((i < 0) || (i > DAHDI_MAX_CHANNELS) || !chans[i]) return(-EINVAL);
- if (!(chans[i]->flags & DAHDI_FLAG_AUDIO)) return (-EINVAL);
-
- if (!(rxgain = kmalloc(512, GFP_KERNEL)))
- return -ENOMEM;
-
- stack.gain.chan = i; /* put the span # in here */
- txgain = rxgain + 256;
-
- for (j=0;j<256;j++) {
- rxgain[j] = stack.gain.rxgain[j];
- txgain[j] = stack.gain.txgain[j];
- }
-
- if (!memcmp(rxgain, defgain, 256) &&
- !memcmp(txgain, defgain, 256)) {
- if (rxgain)
- kfree(rxgain);
- spin_lock_irqsave(&chans[i]->lock, flags);
- if (chans[i]->gainalloc)
- kfree(chans[i]->rxgain);
- chans[i]->gainalloc = 0;
- chans[i]->rxgain = defgain;
- chans[i]->txgain = defgain;
- spin_unlock_irqrestore(&chans[i]->lock, flags);
- } else {
- /* This is a custom gain setting */
- spin_lock_irqsave(&chans[i]->lock, flags);
- if (chans[i]->gainalloc)
- kfree(chans[i]->rxgain);
- chans[i]->gainalloc = 1;
- chans[i]->rxgain = rxgain;
- chans[i]->txgain = txgain;
- spin_unlock_irqrestore(&chans[i]->lock, flags);
- }
- if (copy_to_user((struct dahdi_gains *) data,&stack.gain,sizeof(stack.gain)))
- return -EFAULT;
- break;
+ return dahdi_ioctl_setgains(node, file, cmd, data, unit);
case DAHDI_SPANSTAT:
size_to_copy = sizeof(struct dahdi_spaninfo);
if (copy_from_user(&stack.spaninfo, (struct dahdi_spaninfo *) data, size_to_copy))