Commit ac5d1a7d253f3c02d1e5c93edfa26e81466ec71e

Authored by Clemens Ladisch
Committed by Jaroslav Kysela
1 parent 2ea5814472

[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>

Showing 1 changed file with 14 additions and 6 deletions Side-by-side Diff

sound/core/rtctimer.c
... ... @@ -22,13 +22,10 @@
22 22  
23 23 #include <sound/driver.h>
24 24 #include <linux/init.h>
25   -#include <linux/time.h>
26   -#include <linux/threads.h>
27 25 #include <linux/interrupt.h>
28 26 #include <linux/moduleparam.h>
29 27 #include <sound/core.h>
30 28 #include <sound/timer.h>
31   -#include <sound/info.h>
32 29  
33 30 #if defined(CONFIG_RTC) || defined(CONFIG_RTC_MODULE)
34 31  
... ... @@ -50,7 +47,9 @@
50 47 * The hardware dependent description for this timer.
51 48 */
52 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 53 .ticks = 100000000L, /* FIXME: XXX */
55 54 .open = rtctimer_open,
56 55 .close = rtctimer_close,
... ... @@ -60,6 +59,7 @@
60 59  
61 60 static int rtctimer_freq = RTC_FREQ; /* frequency */
62 61 static struct snd_timer *rtctimer;
  62 +static struct tasklet_struct rtc_tasklet;
63 63 static rtc_task_t rtc_task;
64 64  
65 65  
... ... @@ -81,6 +81,7 @@
81 81 rtc_task_t *rtc = t->private_data;
82 82 if (rtc) {
83 83 rtc_unregister(rtc);
  84 + tasklet_kill(&rtc_tasklet);
84 85 t->private_data = NULL;
85 86 }
86 87 return 0;
87 88  
... ... @@ -105,12 +106,17 @@
105 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 115 * interrupt
110 116 */
111 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  
117 123  
... ... @@ -139,9 +145,11 @@
139 145 timer->hw = rtc_hw;
140 146 timer->hw.resolution = NANO_SEC / rtctimer_freq;
141 147  
  148 + tasklet_init(&rtc_tasklet, rtctimer_tasklet, (unsigned long)timer);
  149 +
142 150 /* set up RTC callback */
143 151 rtc_task.func = rtctimer_interrupt;
144   - rtc_task.private_data = timer;
  152 + rtc_task.private_data = &rtc_tasklet;
145 153  
146 154 err = snd_timer_global_register(timer);
147 155 if (err < 0) {