diff options
Diffstat (limited to 'sound/core/timer.c')
-rw-r--r-- | sound/core/timer.c | 125 |
1 files changed, 60 insertions, 65 deletions
diff --git a/sound/core/timer.c b/sound/core/timer.c index 884c3066b028..a9b9a277e00c 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c | |||
@@ -319,6 +319,7 @@ int snd_timer_open(struct snd_timer_instance **ti, | |||
319 | *ti = timeri; | 319 | *ti = timeri; |
320 | return 0; | 320 | return 0; |
321 | } | 321 | } |
322 | EXPORT_SYMBOL(snd_timer_open); | ||
322 | 323 | ||
323 | /* | 324 | /* |
324 | * close a timer instance | 325 | * close a timer instance |
@@ -384,6 +385,7 @@ int snd_timer_close(struct snd_timer_instance *timeri) | |||
384 | mutex_unlock(®ister_mutex); | 385 | mutex_unlock(®ister_mutex); |
385 | return 0; | 386 | return 0; |
386 | } | 387 | } |
388 | EXPORT_SYMBOL(snd_timer_close); | ||
387 | 389 | ||
388 | unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) | 390 | unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) |
389 | { | 391 | { |
@@ -398,6 +400,7 @@ unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) | |||
398 | } | 400 | } |
399 | return 0; | 401 | return 0; |
400 | } | 402 | } |
403 | EXPORT_SYMBOL(snd_timer_resolution); | ||
401 | 404 | ||
402 | static void snd_timer_notify1(struct snd_timer_instance *ti, int event) | 405 | static void snd_timer_notify1(struct snd_timer_instance *ti, int event) |
403 | { | 406 | { |
@@ -589,6 +592,7 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) | |||
589 | else | 592 | else |
590 | return snd_timer_start1(timeri, true, ticks); | 593 | return snd_timer_start1(timeri, true, ticks); |
591 | } | 594 | } |
595 | EXPORT_SYMBOL(snd_timer_start); | ||
592 | 596 | ||
593 | /* | 597 | /* |
594 | * stop the timer instance. | 598 | * stop the timer instance. |
@@ -602,6 +606,7 @@ int snd_timer_stop(struct snd_timer_instance *timeri) | |||
602 | else | 606 | else |
603 | return snd_timer_stop1(timeri, true); | 607 | return snd_timer_stop1(timeri, true); |
604 | } | 608 | } |
609 | EXPORT_SYMBOL(snd_timer_stop); | ||
605 | 610 | ||
606 | /* | 611 | /* |
607 | * start again.. the tick is kept. | 612 | * start again.. the tick is kept. |
@@ -617,6 +622,7 @@ int snd_timer_continue(struct snd_timer_instance *timeri) | |||
617 | else | 622 | else |
618 | return snd_timer_start1(timeri, false, 0); | 623 | return snd_timer_start1(timeri, false, 0); |
619 | } | 624 | } |
625 | EXPORT_SYMBOL(snd_timer_continue); | ||
620 | 626 | ||
621 | /* | 627 | /* |
622 | * pause.. remember the ticks left | 628 | * pause.. remember the ticks left |
@@ -628,6 +634,7 @@ int snd_timer_pause(struct snd_timer_instance * timeri) | |||
628 | else | 634 | else |
629 | return snd_timer_stop1(timeri, false); | 635 | return snd_timer_stop1(timeri, false); |
630 | } | 636 | } |
637 | EXPORT_SYMBOL(snd_timer_pause); | ||
631 | 638 | ||
632 | /* | 639 | /* |
633 | * reschedule the timer | 640 | * reschedule the timer |
@@ -809,6 +816,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) | |||
809 | if (use_tasklet) | 816 | if (use_tasklet) |
810 | tasklet_schedule(&timer->task_queue); | 817 | tasklet_schedule(&timer->task_queue); |
811 | } | 818 | } |
819 | EXPORT_SYMBOL(snd_timer_interrupt); | ||
812 | 820 | ||
813 | /* | 821 | /* |
814 | 822 | ||
@@ -859,6 +867,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, | |||
859 | *rtimer = timer; | 867 | *rtimer = timer; |
860 | return 0; | 868 | return 0; |
861 | } | 869 | } |
870 | EXPORT_SYMBOL(snd_timer_new); | ||
862 | 871 | ||
863 | static int snd_timer_free(struct snd_timer *timer) | 872 | static int snd_timer_free(struct snd_timer *timer) |
864 | { | 873 | { |
@@ -978,6 +987,7 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam | |||
978 | } | 987 | } |
979 | spin_unlock_irqrestore(&timer->lock, flags); | 988 | spin_unlock_irqrestore(&timer->lock, flags); |
980 | } | 989 | } |
990 | EXPORT_SYMBOL(snd_timer_notify); | ||
981 | 991 | ||
982 | /* | 992 | /* |
983 | * exported functions for global timers | 993 | * exported functions for global timers |
@@ -993,11 +1003,13 @@ int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer) | |||
993 | tid.subdevice = 0; | 1003 | tid.subdevice = 0; |
994 | return snd_timer_new(NULL, id, &tid, rtimer); | 1004 | return snd_timer_new(NULL, id, &tid, rtimer); |
995 | } | 1005 | } |
1006 | EXPORT_SYMBOL(snd_timer_global_new); | ||
996 | 1007 | ||
997 | int snd_timer_global_free(struct snd_timer *timer) | 1008 | int snd_timer_global_free(struct snd_timer *timer) |
998 | { | 1009 | { |
999 | return snd_timer_free(timer); | 1010 | return snd_timer_free(timer); |
1000 | } | 1011 | } |
1012 | EXPORT_SYMBOL(snd_timer_global_free); | ||
1001 | 1013 | ||
1002 | int snd_timer_global_register(struct snd_timer *timer) | 1014 | int snd_timer_global_register(struct snd_timer *timer) |
1003 | { | 1015 | { |
@@ -1007,6 +1019,7 @@ int snd_timer_global_register(struct snd_timer *timer) | |||
1007 | dev.device_data = timer; | 1019 | dev.device_data = timer; |
1008 | return snd_timer_dev_register(&dev); | 1020 | return snd_timer_dev_register(&dev); |
1009 | } | 1021 | } |
1022 | EXPORT_SYMBOL(snd_timer_global_register); | ||
1010 | 1023 | ||
1011 | /* | 1024 | /* |
1012 | * System timer | 1025 | * System timer |
@@ -1327,6 +1340,33 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, | |||
1327 | wake_up(&tu->qchange_sleep); | 1340 | wake_up(&tu->qchange_sleep); |
1328 | } | 1341 | } |
1329 | 1342 | ||
1343 | static int realloc_user_queue(struct snd_timer_user *tu, int size) | ||
1344 | { | ||
1345 | struct snd_timer_read *queue = NULL; | ||
1346 | struct snd_timer_tread *tqueue = NULL; | ||
1347 | |||
1348 | if (tu->tread) { | ||
1349 | tqueue = kcalloc(size, sizeof(*tqueue), GFP_KERNEL); | ||
1350 | if (!tqueue) | ||
1351 | return -ENOMEM; | ||
1352 | } else { | ||
1353 | queue = kcalloc(size, sizeof(*queue), GFP_KERNEL); | ||
1354 | if (!queue) | ||
1355 | return -ENOMEM; | ||
1356 | } | ||
1357 | |||
1358 | spin_lock_irq(&tu->qlock); | ||
1359 | kfree(tu->queue); | ||
1360 | kfree(tu->tqueue); | ||
1361 | tu->queue_size = size; | ||
1362 | tu->queue = queue; | ||
1363 | tu->tqueue = tqueue; | ||
1364 | tu->qhead = tu->qtail = tu->qused = 0; | ||
1365 | spin_unlock_irq(&tu->qlock); | ||
1366 | |||
1367 | return 0; | ||
1368 | } | ||
1369 | |||
1330 | static int snd_timer_user_open(struct inode *inode, struct file *file) | 1370 | static int snd_timer_user_open(struct inode *inode, struct file *file) |
1331 | { | 1371 | { |
1332 | struct snd_timer_user *tu; | 1372 | struct snd_timer_user *tu; |
@@ -1343,10 +1383,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file) | |||
1343 | init_waitqueue_head(&tu->qchange_sleep); | 1383 | init_waitqueue_head(&tu->qchange_sleep); |
1344 | mutex_init(&tu->ioctl_lock); | 1384 | mutex_init(&tu->ioctl_lock); |
1345 | tu->ticks = 1; | 1385 | tu->ticks = 1; |
1346 | tu->queue_size = 128; | 1386 | if (realloc_user_queue(tu, 128) < 0) { |
1347 | tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read), | ||
1348 | GFP_KERNEL); | ||
1349 | if (tu->queue == NULL) { | ||
1350 | kfree(tu); | 1387 | kfree(tu); |
1351 | return -ENOMEM; | 1388 | return -ENOMEM; |
1352 | } | 1389 | } |
@@ -1618,34 +1655,12 @@ static int snd_timer_user_tselect(struct file *file, | |||
1618 | if (err < 0) | 1655 | if (err < 0) |
1619 | goto __err; | 1656 | goto __err; |
1620 | 1657 | ||
1621 | tu->qhead = tu->qtail = tu->qused = 0; | 1658 | tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; |
1622 | kfree(tu->queue); | 1659 | tu->timeri->callback = tu->tread |
1623 | tu->queue = NULL; | ||
1624 | kfree(tu->tqueue); | ||
1625 | tu->tqueue = NULL; | ||
1626 | if (tu->tread) { | ||
1627 | tu->tqueue = kmalloc(tu->queue_size * sizeof(struct snd_timer_tread), | ||
1628 | GFP_KERNEL); | ||
1629 | if (tu->tqueue == NULL) | ||
1630 | err = -ENOMEM; | ||
1631 | } else { | ||
1632 | tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read), | ||
1633 | GFP_KERNEL); | ||
1634 | if (tu->queue == NULL) | ||
1635 | err = -ENOMEM; | ||
1636 | } | ||
1637 | |||
1638 | if (err < 0) { | ||
1639 | snd_timer_close(tu->timeri); | ||
1640 | tu->timeri = NULL; | ||
1641 | } else { | ||
1642 | tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; | ||
1643 | tu->timeri->callback = tu->tread | ||
1644 | ? snd_timer_user_tinterrupt : snd_timer_user_interrupt; | 1660 | ? snd_timer_user_tinterrupt : snd_timer_user_interrupt; |
1645 | tu->timeri->ccallback = snd_timer_user_ccallback; | 1661 | tu->timeri->ccallback = snd_timer_user_ccallback; |
1646 | tu->timeri->callback_data = (void *)tu; | 1662 | tu->timeri->callback_data = (void *)tu; |
1647 | tu->timeri->disconnect = snd_timer_user_disconnect; | 1663 | tu->timeri->disconnect = snd_timer_user_disconnect; |
1648 | } | ||
1649 | 1664 | ||
1650 | __err: | 1665 | __err: |
1651 | return err; | 1666 | return err; |
@@ -1687,8 +1702,6 @@ static int snd_timer_user_params(struct file *file, | |||
1687 | struct snd_timer_user *tu; | 1702 | struct snd_timer_user *tu; |
1688 | struct snd_timer_params params; | 1703 | struct snd_timer_params params; |
1689 | struct snd_timer *t; | 1704 | struct snd_timer *t; |
1690 | struct snd_timer_read *tr; | ||
1691 | struct snd_timer_tread *ttr; | ||
1692 | int err; | 1705 | int err; |
1693 | 1706 | ||
1694 | tu = file->private_data; | 1707 | tu = file->private_data; |
@@ -1751,24 +1764,11 @@ static int snd_timer_user_params(struct file *file, | |||
1751 | spin_unlock_irq(&t->lock); | 1764 | spin_unlock_irq(&t->lock); |
1752 | if (params.queue_size > 0 && | 1765 | if (params.queue_size > 0 && |
1753 | (unsigned int)tu->queue_size != params.queue_size) { | 1766 | (unsigned int)tu->queue_size != params.queue_size) { |
1754 | if (tu->tread) { | 1767 | err = realloc_user_queue(tu, params.queue_size); |
1755 | ttr = kmalloc(params.queue_size * sizeof(*ttr), | 1768 | if (err < 0) |
1756 | GFP_KERNEL); | 1769 | goto _end; |
1757 | if (ttr) { | ||
1758 | kfree(tu->tqueue); | ||
1759 | tu->queue_size = params.queue_size; | ||
1760 | tu->tqueue = ttr; | ||
1761 | } | ||
1762 | } else { | ||
1763 | tr = kmalloc(params.queue_size * sizeof(*tr), | ||
1764 | GFP_KERNEL); | ||
1765 | if (tr) { | ||
1766 | kfree(tu->queue); | ||
1767 | tu->queue_size = params.queue_size; | ||
1768 | tu->queue = tr; | ||
1769 | } | ||
1770 | } | ||
1771 | } | 1770 | } |
1771 | spin_lock_irq(&tu->qlock); | ||
1772 | tu->qhead = tu->qtail = tu->qused = 0; | 1772 | tu->qhead = tu->qtail = tu->qused = 0; |
1773 | if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) { | 1773 | if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) { |
1774 | if (tu->tread) { | 1774 | if (tu->tread) { |
@@ -1789,6 +1789,7 @@ static int snd_timer_user_params(struct file *file, | |||
1789 | } | 1789 | } |
1790 | tu->filter = params.filter; | 1790 | tu->filter = params.filter; |
1791 | tu->ticks = params.ticks; | 1791 | tu->ticks = params.ticks; |
1792 | spin_unlock_irq(&tu->qlock); | ||
1792 | err = 0; | 1793 | err = 0; |
1793 | _end: | 1794 | _end: |
1794 | if (copy_to_user(_params, ¶ms, sizeof(params))) | 1795 | if (copy_to_user(_params, ¶ms, sizeof(params))) |
@@ -1891,13 +1892,19 @@ static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd, | |||
1891 | return snd_timer_user_next_device(argp); | 1892 | return snd_timer_user_next_device(argp); |
1892 | case SNDRV_TIMER_IOCTL_TREAD: | 1893 | case SNDRV_TIMER_IOCTL_TREAD: |
1893 | { | 1894 | { |
1894 | int xarg; | 1895 | int xarg, old_tread; |
1895 | 1896 | ||
1896 | if (tu->timeri) /* too late */ | 1897 | if (tu->timeri) /* too late */ |
1897 | return -EBUSY; | 1898 | return -EBUSY; |
1898 | if (get_user(xarg, p)) | 1899 | if (get_user(xarg, p)) |
1899 | return -EFAULT; | 1900 | return -EFAULT; |
1901 | old_tread = tu->tread; | ||
1900 | tu->tread = xarg ? 1 : 0; | 1902 | tu->tread = xarg ? 1 : 0; |
1903 | if (tu->tread != old_tread && | ||
1904 | realloc_user_queue(tu, tu->queue_size) < 0) { | ||
1905 | tu->tread = old_tread; | ||
1906 | return -ENOMEM; | ||
1907 | } | ||
1901 | return 0; | 1908 | return 0; |
1902 | } | 1909 | } |
1903 | case SNDRV_TIMER_IOCTL_GINFO: | 1910 | case SNDRV_TIMER_IOCTL_GINFO: |
@@ -2030,10 +2037,12 @@ static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait) | |||
2030 | poll_wait(file, &tu->qchange_sleep, wait); | 2037 | poll_wait(file, &tu->qchange_sleep, wait); |
2031 | 2038 | ||
2032 | mask = 0; | 2039 | mask = 0; |
2040 | spin_lock_irq(&tu->qlock); | ||
2033 | if (tu->qused) | 2041 | if (tu->qused) |
2034 | mask |= POLLIN | POLLRDNORM; | 2042 | mask |= POLLIN | POLLRDNORM; |
2035 | if (tu->disconnected) | 2043 | if (tu->disconnected) |
2036 | mask |= POLLERR; | 2044 | mask |= POLLERR; |
2045 | spin_unlock_irq(&tu->qlock); | ||
2037 | 2046 | ||
2038 | return mask; | 2047 | return mask; |
2039 | } | 2048 | } |
@@ -2117,17 +2126,3 @@ static void __exit alsa_timer_exit(void) | |||
2117 | 2126 | ||
2118 | module_init(alsa_timer_init) | 2127 | module_init(alsa_timer_init) |
2119 | module_exit(alsa_timer_exit) | 2128 | module_exit(alsa_timer_exit) |
2120 | |||
2121 | EXPORT_SYMBOL(snd_timer_open); | ||
2122 | EXPORT_SYMBOL(snd_timer_close); | ||
2123 | EXPORT_SYMBOL(snd_timer_resolution); | ||
2124 | EXPORT_SYMBOL(snd_timer_start); | ||
2125 | EXPORT_SYMBOL(snd_timer_stop); | ||
2126 | EXPORT_SYMBOL(snd_timer_continue); | ||
2127 | EXPORT_SYMBOL(snd_timer_pause); | ||
2128 | EXPORT_SYMBOL(snd_timer_new); | ||
2129 | EXPORT_SYMBOL(snd_timer_notify); | ||
2130 | EXPORT_SYMBOL(snd_timer_global_new); | ||
2131 | EXPORT_SYMBOL(snd_timer_global_free); | ||
2132 | EXPORT_SYMBOL(snd_timer_global_register); | ||
2133 | EXPORT_SYMBOL(snd_timer_interrupt); | ||