aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/core/timer.c57
1 files changed, 37 insertions, 20 deletions
diff --git a/sound/core/timer.c b/sound/core/timer.c
index fa762ca439be..be6d37af76d8 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -69,6 +69,7 @@ typedef struct {
69 struct timespec tstamp; /* trigger tstamp */ 69 struct timespec tstamp; /* trigger tstamp */
70 wait_queue_head_t qchange_sleep; 70 wait_queue_head_t qchange_sleep;
71 struct fasync_struct *fasync; 71 struct fasync_struct *fasync;
72 struct semaphore tread_sem;
72} snd_timer_user_t; 73} snd_timer_user_t;
73 74
74/* list of timers */ 75/* list of timers */
@@ -1208,6 +1209,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file)
1208 return -ENOMEM; 1209 return -ENOMEM;
1209 spin_lock_init(&tu->qlock); 1210 spin_lock_init(&tu->qlock);
1210 init_waitqueue_head(&tu->qchange_sleep); 1211 init_waitqueue_head(&tu->qchange_sleep);
1212 init_MUTEX(&tu->tread_sem);
1211 tu->ticks = 1; 1213 tu->ticks = 1;
1212 tu->queue_size = 128; 1214 tu->queue_size = 128;
1213 tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); 1215 tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL);
@@ -1454,18 +1456,23 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user *
1454 snd_timer_user_t *tu; 1456 snd_timer_user_t *tu;
1455 snd_timer_select_t tselect; 1457 snd_timer_select_t tselect;
1456 char str[32]; 1458 char str[32];
1457 int err; 1459 int err = 0;
1458 1460
1459 tu = file->private_data; 1461 tu = file->private_data;
1460 if (tu->timeri) 1462 down(&tu->tread_sem);
1463 if (tu->timeri) {
1461 snd_timer_close(tu->timeri); 1464 snd_timer_close(tu->timeri);
1462 if (copy_from_user(&tselect, _tselect, sizeof(tselect))) 1465 tu->timeri = NULL;
1463 return -EFAULT; 1466 }
1467 if (copy_from_user(&tselect, _tselect, sizeof(tselect))) {
1468 err = -EFAULT;
1469 goto __err;
1470 }
1464 sprintf(str, "application %i", current->pid); 1471 sprintf(str, "application %i", current->pid);
1465 if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE) 1472 if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE)
1466 tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION; 1473 tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION;
1467 if ((err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid)) < 0) 1474 if ((err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid)) < 0)
1468 return err; 1475 goto __err;
1469 1476
1470 if (tu->queue) { 1477 if (tu->queue) {
1471 kfree(tu->queue); 1478 kfree(tu->queue);
@@ -1477,23 +1484,27 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user *
1477 } 1484 }
1478 if (tu->tread) { 1485 if (tu->tread) {
1479 tu->tqueue = (snd_timer_tread_t *)kmalloc(tu->queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL); 1486 tu->tqueue = (snd_timer_tread_t *)kmalloc(tu->queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL);
1480 if (tu->tqueue == NULL) { 1487 if (tu->tqueue == NULL)
1481 snd_timer_close(tu->timeri); 1488 err = -ENOMEM;
1482 return -ENOMEM;
1483 }
1484 } else { 1489 } else {
1485 tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); 1490 tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL);
1486 if (tu->queue == NULL) { 1491 if (tu->queue == NULL)
1487 snd_timer_close(tu->timeri); 1492 err = -ENOMEM;
1488 return -ENOMEM;
1489 }
1490 } 1493 }
1491 1494
1492 tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; 1495 if (err < 0) {
1493 tu->timeri->callback = tu->tread ? snd_timer_user_tinterrupt : snd_timer_user_interrupt; 1496 snd_timer_close(tu->timeri);
1494 tu->timeri->ccallback = snd_timer_user_ccallback; 1497 tu->timeri = NULL;
1495 tu->timeri->callback_data = (void *)tu; 1498 } else {
1496 return 0; 1499 tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST;
1500 tu->timeri->callback = tu->tread ? snd_timer_user_tinterrupt : snd_timer_user_interrupt;
1501 tu->timeri->ccallback = snd_timer_user_ccallback;
1502 tu->timeri->callback_data = (void *)tu;
1503 }
1504
1505 __err:
1506 up(&tu->tread_sem);
1507 return err;
1497} 1508}
1498 1509
1499static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info) 1510static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info)
@@ -1685,11 +1696,17 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned l
1685 { 1696 {
1686 int xarg; 1697 int xarg;
1687 1698
1688 if (tu->timeri) /* too late */ 1699 down(&tu->tread_sem);
1700 if (tu->timeri) { /* too late */
1701 up(&tu->tread_sem);
1689 return -EBUSY; 1702 return -EBUSY;
1690 if (get_user(xarg, p)) 1703 }
1704 if (get_user(xarg, p)) {
1705 up(&tu->tread_sem);
1691 return -EFAULT; 1706 return -EFAULT;
1707 }
1692 tu->tread = xarg ? 1 : 0; 1708 tu->tread = xarg ? 1 : 0;
1709 up(&tu->tread_sem);
1693 return 0; 1710 return 0;
1694 } 1711 }
1695 case SNDRV_TIMER_IOCTL_GINFO: 1712 case SNDRV_TIMER_IOCTL_GINFO: