diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2006-10-27 04:45:00 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-11-28 07:46:33 -0500 |
commit | ac5d1a7d253f3c02d1e5c93edfa26e81466ec71e (patch) | |
tree | 629e4d8618d11233c2e24daf28aa12f055dc24c3 | |
parent | 2ea5814472c3c910aed5c5b60f1f3b1000e353f1 (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.c | 20 |
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 | */ |
52 | static struct snd_timer_hardware rtc_hw = { | 49 | static 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 | ||
61 | static int rtctimer_freq = RTC_FREQ; /* frequency */ | 60 | static int rtctimer_freq = RTC_FREQ; /* frequency */ |
62 | static struct snd_timer *rtctimer; | 61 | static struct snd_timer *rtctimer; |
62 | static struct tasklet_struct rtc_tasklet; | ||
63 | static rtc_task_t rtc_task; | 63 | static 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 | ||
109 | static 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 | */ |
111 | static void rtctimer_interrupt(void *private_data) | 117 | static 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) { |