aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2006-10-27 04:45:00 -0400
committerJaroslav Kysela <perex@suse.cz>2006-11-28 07:46:33 -0500
commitac5d1a7d253f3c02d1e5c93edfa26e81466ec71e (patch)
tree629e4d8618d11233c2e24daf28aa12f055dc24c3
parent2ea5814472c3c910aed5c5b60f1f3b1000e353f1 (diff)
[ALSA] rtctimer: handle RTC interrupts with a tasklet
The calls to rtc_control() from inside the interrupt handler can upset the RTC code, so move our interrupt handling code to a tasklet. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
-rw-r--r--sound/core/rtctimer.c20
1 files changed, 14 insertions, 6 deletions
diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c
index 412dd62b654e..9f7b32e1ccde 100644
--- a/sound/core/rtctimer.c
+++ b/sound/core/rtctimer.c
@@ -22,13 +22,10 @@
22 22
23#include <sound/driver.h> 23#include <sound/driver.h>
24#include <linux/init.h> 24#include <linux/init.h>
25#include <linux/time.h>
26#include <linux/threads.h>
27#include <linux/interrupt.h> 25#include <linux/interrupt.h>
28#include <linux/moduleparam.h> 26#include <linux/moduleparam.h>
29#include <sound/core.h> 27#include <sound/core.h>
30#include <sound/timer.h> 28#include <sound/timer.h>
31#include <sound/info.h>
32 29
33#if defined(CONFIG_RTC) || defined(CONFIG_RTC_MODULE) 30#if defined(CONFIG_RTC) || defined(CONFIG_RTC_MODULE)
34 31
@@ -50,7 +47,9 @@ static int rtctimer_stop(struct snd_timer *t);
50 * The hardware dependent description for this timer. 47 * The hardware dependent description for this timer.
51 */ 48 */
52static struct snd_timer_hardware rtc_hw = { 49static struct snd_timer_hardware rtc_hw = {
53 .flags = SNDRV_TIMER_HW_FIRST|SNDRV_TIMER_HW_AUTO, 50 .flags = SNDRV_TIMER_HW_AUTO |
51 SNDRV_TIMER_HW_FIRST |
52 SNDRV_TIMER_HW_TASKLET,
54 .ticks = 100000000L, /* FIXME: XXX */ 53 .ticks = 100000000L, /* FIXME: XXX */
55 .open = rtctimer_open, 54 .open = rtctimer_open,
56 .close = rtctimer_close, 55 .close = rtctimer_close,
@@ -60,6 +59,7 @@ static struct snd_timer_hardware rtc_hw = {
60 59
61static int rtctimer_freq = RTC_FREQ; /* frequency */ 60static int rtctimer_freq = RTC_FREQ; /* frequency */
62static struct snd_timer *rtctimer; 61static struct snd_timer *rtctimer;
62static struct tasklet_struct rtc_tasklet;
63static rtc_task_t rtc_task; 63static rtc_task_t rtc_task;
64 64
65 65
@@ -81,6 +81,7 @@ rtctimer_close(struct snd_timer *t)
81 rtc_task_t *rtc = t->private_data; 81 rtc_task_t *rtc = t->private_data;
82 if (rtc) { 82 if (rtc) {
83 rtc_unregister(rtc); 83 rtc_unregister(rtc);
84 tasklet_kill(&rtc_tasklet);
84 t->private_data = NULL; 85 t->private_data = NULL;
85 } 86 }
86 return 0; 87 return 0;
@@ -105,12 +106,17 @@ rtctimer_stop(struct snd_timer *timer)
105 return 0; 106 return 0;
106} 107}
107 108
109static void rtctimer_tasklet(unsigned long data)
110{
111 snd_timer_interrupt((struct snd_timer *)data, 1);
112}
113
108/* 114/*
109 * interrupt 115 * interrupt
110 */ 116 */
111static void rtctimer_interrupt(void *private_data) 117static void rtctimer_interrupt(void *private_data)
112{ 118{
113 snd_timer_interrupt(private_data, 1); 119 tasklet_hi_schedule(private_data);
114} 120}
115 121
116 122
@@ -139,9 +145,11 @@ static int __init rtctimer_init(void)
139 timer->hw = rtc_hw; 145 timer->hw = rtc_hw;
140 timer->hw.resolution = NANO_SEC / rtctimer_freq; 146 timer->hw.resolution = NANO_SEC / rtctimer_freq;
141 147
148 tasklet_init(&rtc_tasklet, rtctimer_tasklet, (unsigned long)timer);
149
142 /* set up RTC callback */ 150 /* set up RTC callback */
143 rtc_task.func = rtctimer_interrupt; 151 rtc_task.func = rtctimer_interrupt;
144 rtc_task.private_data = timer; 152 rtc_task.private_data = &rtc_tasklet;
145 153
146 err = snd_timer_global_register(timer); 154 err = snd_timer_global_register(timer);
147 if (err < 0) { 155 if (err < 0) {