aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/timer.c')
-rw-r--r--sound/core/timer.c100
1 files changed, 65 insertions, 35 deletions
diff --git a/sound/core/timer.c b/sound/core/timer.c
index fa762ca439be..b498e5482d77 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 */
@@ -844,7 +845,7 @@ int snd_timer_dev_register(snd_device_t *dev)
844 return 0; 845 return 0;
845} 846}
846 847
847int snd_timer_unregister(snd_timer_t *timer) 848static int snd_timer_unregister(snd_timer_t *timer)
848{ 849{
849 struct list_head *p, *n; 850 struct list_head *p, *n;
850 snd_timer_instance_t *ti; 851 snd_timer_instance_t *ti;
@@ -945,11 +946,6 @@ struct snd_timer_system_private {
945 unsigned long correction; 946 unsigned long correction;
946}; 947};
947 948
948unsigned int snd_timer_system_resolution(void)
949{
950 return 1000000000L / HZ;
951}
952
953static void snd_timer_s_function(unsigned long data) 949static void snd_timer_s_function(unsigned long data)
954{ 950{
955 snd_timer_t *timer = (snd_timer_t *)data; 951 snd_timer_t *timer = (snd_timer_t *)data;
@@ -1208,6 +1204,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file)
1208 return -ENOMEM; 1204 return -ENOMEM;
1209 spin_lock_init(&tu->qlock); 1205 spin_lock_init(&tu->qlock);
1210 init_waitqueue_head(&tu->qchange_sleep); 1206 init_waitqueue_head(&tu->qchange_sleep);
1207 init_MUTEX(&tu->tread_sem);
1211 tu->ticks = 1; 1208 tu->ticks = 1;
1212 tu->queue_size = 128; 1209 tu->queue_size = 128;
1213 tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); 1210 tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL);
@@ -1454,46 +1451,51 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user *
1454 snd_timer_user_t *tu; 1451 snd_timer_user_t *tu;
1455 snd_timer_select_t tselect; 1452 snd_timer_select_t tselect;
1456 char str[32]; 1453 char str[32];
1457 int err; 1454 int err = 0;
1458 1455
1459 tu = file->private_data; 1456 tu = file->private_data;
1460 if (tu->timeri) 1457 down(&tu->tread_sem);
1458 if (tu->timeri) {
1461 snd_timer_close(tu->timeri); 1459 snd_timer_close(tu->timeri);
1462 if (copy_from_user(&tselect, _tselect, sizeof(tselect))) 1460 tu->timeri = NULL;
1463 return -EFAULT; 1461 }
1462 if (copy_from_user(&tselect, _tselect, sizeof(tselect))) {
1463 err = -EFAULT;
1464 goto __err;
1465 }
1464 sprintf(str, "application %i", current->pid); 1466 sprintf(str, "application %i", current->pid);
1465 if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE) 1467 if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE)
1466 tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION; 1468 tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION;
1467 if ((err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid)) < 0) 1469 if ((err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid)) < 0)
1468 return err; 1470 goto __err;
1469 1471
1470 if (tu->queue) { 1472 kfree(tu->queue);
1471 kfree(tu->queue); 1473 tu->queue = NULL;
1472 tu->queue = NULL; 1474 kfree(tu->tqueue);
1473 } 1475 tu->tqueue = NULL;
1474 if (tu->tqueue) {
1475 kfree(tu->tqueue);
1476 tu->tqueue = NULL;
1477 }
1478 if (tu->tread) { 1476 if (tu->tread) {
1479 tu->tqueue = (snd_timer_tread_t *)kmalloc(tu->queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL); 1477 tu->tqueue = (snd_timer_tread_t *)kmalloc(tu->queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL);
1480 if (tu->tqueue == NULL) { 1478 if (tu->tqueue == NULL)
1481 snd_timer_close(tu->timeri); 1479 err = -ENOMEM;
1482 return -ENOMEM;
1483 }
1484 } else { 1480 } else {
1485 tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); 1481 tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL);
1486 if (tu->queue == NULL) { 1482 if (tu->queue == NULL)
1487 snd_timer_close(tu->timeri); 1483 err = -ENOMEM;
1488 return -ENOMEM;
1489 }
1490 } 1484 }
1491 1485
1492 tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; 1486 if (err < 0) {
1493 tu->timeri->callback = tu->tread ? snd_timer_user_tinterrupt : snd_timer_user_interrupt; 1487 snd_timer_close(tu->timeri);
1494 tu->timeri->ccallback = snd_timer_user_ccallback; 1488 tu->timeri = NULL;
1495 tu->timeri->callback_data = (void *)tu; 1489 } else {
1496 return 0; 1490 tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST;
1491 tu->timeri->callback = tu->tread ? snd_timer_user_tinterrupt : snd_timer_user_interrupt;
1492 tu->timeri->ccallback = snd_timer_user_ccallback;
1493 tu->timeri->callback_data = (void *)tu;
1494 }
1495
1496 __err:
1497 up(&tu->tread_sem);
1498 return err;
1497} 1499}
1498 1500
1499static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info) 1501static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info)
@@ -1669,6 +1671,23 @@ static int snd_timer_user_continue(struct file *file)
1669 return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0; 1671 return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
1670} 1672}
1671 1673
1674static int snd_timer_user_pause(struct file *file)
1675{
1676 int err;
1677 snd_timer_user_t *tu;
1678
1679 tu = file->private_data;
1680 snd_assert(tu->timeri != NULL, return -ENXIO);
1681 return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0;
1682}
1683
1684enum {
1685 SNDRV_TIMER_IOCTL_START_OLD = _IO('T', 0x20),
1686 SNDRV_TIMER_IOCTL_STOP_OLD = _IO('T', 0x21),
1687 SNDRV_TIMER_IOCTL_CONTINUE_OLD = _IO('T', 0x22),
1688 SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23),
1689};
1690
1672static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 1691static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1673{ 1692{
1674 snd_timer_user_t *tu; 1693 snd_timer_user_t *tu;
@@ -1685,11 +1704,17 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned l
1685 { 1704 {
1686 int xarg; 1705 int xarg;
1687 1706
1688 if (tu->timeri) /* too late */ 1707 down(&tu->tread_sem);
1708 if (tu->timeri) { /* too late */
1709 up(&tu->tread_sem);
1689 return -EBUSY; 1710 return -EBUSY;
1690 if (get_user(xarg, p)) 1711 }
1712 if (get_user(xarg, p)) {
1713 up(&tu->tread_sem);
1691 return -EFAULT; 1714 return -EFAULT;
1715 }
1692 tu->tread = xarg ? 1 : 0; 1716 tu->tread = xarg ? 1 : 0;
1717 up(&tu->tread_sem);
1693 return 0; 1718 return 0;
1694 } 1719 }
1695 case SNDRV_TIMER_IOCTL_GINFO: 1720 case SNDRV_TIMER_IOCTL_GINFO:
@@ -1707,11 +1732,17 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned l
1707 case SNDRV_TIMER_IOCTL_STATUS: 1732 case SNDRV_TIMER_IOCTL_STATUS:
1708 return snd_timer_user_status(file, argp); 1733 return snd_timer_user_status(file, argp);
1709 case SNDRV_TIMER_IOCTL_START: 1734 case SNDRV_TIMER_IOCTL_START:
1735 case SNDRV_TIMER_IOCTL_START_OLD:
1710 return snd_timer_user_start(file); 1736 return snd_timer_user_start(file);
1711 case SNDRV_TIMER_IOCTL_STOP: 1737 case SNDRV_TIMER_IOCTL_STOP:
1738 case SNDRV_TIMER_IOCTL_STOP_OLD:
1712 return snd_timer_user_stop(file); 1739 return snd_timer_user_stop(file);
1713 case SNDRV_TIMER_IOCTL_CONTINUE: 1740 case SNDRV_TIMER_IOCTL_CONTINUE:
1741 case SNDRV_TIMER_IOCTL_CONTINUE_OLD:
1714 return snd_timer_user_continue(file); 1742 return snd_timer_user_continue(file);
1743 case SNDRV_TIMER_IOCTL_PAUSE:
1744 case SNDRV_TIMER_IOCTL_PAUSE_OLD:
1745 return snd_timer_user_pause(file);
1715 } 1746 }
1716 return -ENOTTY; 1747 return -ENOTTY;
1717} 1748}
@@ -1898,4 +1929,3 @@ EXPORT_SYMBOL(snd_timer_global_free);
1898EXPORT_SYMBOL(snd_timer_global_register); 1929EXPORT_SYMBOL(snd_timer_global_register);
1899EXPORT_SYMBOL(snd_timer_global_unregister); 1930EXPORT_SYMBOL(snd_timer_global_unregister);
1900EXPORT_SYMBOL(snd_timer_interrupt); 1931EXPORT_SYMBOL(snd_timer_interrupt);
1901EXPORT_SYMBOL(snd_timer_system_resolution);