[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>
This commit is contained in:
parent
2ea5814472
commit
ac5d1a7d25
1 changed files with 14 additions and 6 deletions
|
@ -22,13 +22,10 @@
|
|||
|
||||
#include <sound/driver.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/threads.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/timer.h>
|
||||
#include <sound/info.h>
|
||||
|
||||
#if defined(CONFIG_RTC) || defined(CONFIG_RTC_MODULE)
|
||||
|
||||
|
@ -50,7 +47,9 @@ static int rtctimer_stop(struct snd_timer *t);
|
|||
* The hardware dependent description for this timer.
|
||||
*/
|
||||
static struct snd_timer_hardware rtc_hw = {
|
||||
.flags = SNDRV_TIMER_HW_FIRST|SNDRV_TIMER_HW_AUTO,
|
||||
.flags = SNDRV_TIMER_HW_AUTO |
|
||||
SNDRV_TIMER_HW_FIRST |
|
||||
SNDRV_TIMER_HW_TASKLET,
|
||||
.ticks = 100000000L, /* FIXME: XXX */
|
||||
.open = rtctimer_open,
|
||||
.close = rtctimer_close,
|
||||
|
@ -60,6 +59,7 @@ static struct snd_timer_hardware rtc_hw = {
|
|||
|
||||
static int rtctimer_freq = RTC_FREQ; /* frequency */
|
||||
static struct snd_timer *rtctimer;
|
||||
static struct tasklet_struct rtc_tasklet;
|
||||
static rtc_task_t rtc_task;
|
||||
|
||||
|
||||
|
@ -81,6 +81,7 @@ rtctimer_close(struct snd_timer *t)
|
|||
rtc_task_t *rtc = t->private_data;
|
||||
if (rtc) {
|
||||
rtc_unregister(rtc);
|
||||
tasklet_kill(&rtc_tasklet);
|
||||
t->private_data = NULL;
|
||||
}
|
||||
return 0;
|
||||
|
@ -105,12 +106,17 @@ rtctimer_stop(struct snd_timer *timer)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void rtctimer_tasklet(unsigned long data)
|
||||
{
|
||||
snd_timer_interrupt((struct snd_timer *)data, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* interrupt
|
||||
*/
|
||||
static void rtctimer_interrupt(void *private_data)
|
||||
{
|
||||
snd_timer_interrupt(private_data, 1);
|
||||
tasklet_hi_schedule(private_data);
|
||||
}
|
||||
|
||||
|
||||
|
@ -139,9 +145,11 @@ static int __init rtctimer_init(void)
|
|||
timer->hw = rtc_hw;
|
||||
timer->hw.resolution = NANO_SEC / rtctimer_freq;
|
||||
|
||||
tasklet_init(&rtc_tasklet, rtctimer_tasklet, (unsigned long)timer);
|
||||
|
||||
/* set up RTC callback */
|
||||
rtc_task.func = rtctimer_interrupt;
|
||||
rtc_task.private_data = timer;
|
||||
rtc_task.private_data = &rtc_tasklet;
|
||||
|
||||
err = snd_timer_global_register(timer);
|
||||
if (err < 0) {
|
||||
|
|
Loading…
Reference in a new issue