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) { |
