diff options
-rw-r--r-- | sound/core/timer.c | 57 |
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 | ||
1499 | static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info) | 1510 | static 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: |