aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2008-10-24 12:16:50 -0400
committerTakashi Iwai <tiwai@suse.de>2008-10-24 12:16:50 -0400
commitbbaf5e97337287479eb78dbc3822d9560bbfd2e2 (patch)
tree806b5e54038417d55ab2a28bfe4f5f63c4738c20 /sound
parent52948b3f7c481be2cd3a68d1db42dd6906bf853a (diff)
ALSA: Add hrtimer backend for ALSA timer interface
Added the hrtimer backend for ALSA timer interface. It can be used for the sequencer timer source. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/core/Kconfig21
-rw-r--r--sound/core/Makefile2
-rw-r--r--sound/core/hrtimer.c140
-rw-r--r--sound/core/seq/seq.c4
4 files changed, 166 insertions, 1 deletions
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index 66348c92f88d..406a45010985 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -95,6 +95,26 @@ config SND_SEQUENCER_OSS
95 this will be compiled as a module. The module will be called 95 this will be compiled as a module. The module will be called
96 snd-seq-oss. 96 snd-seq-oss.
97 97
98config SND_HRTIMER
99 tristate "HR-timer backend support"
100 depends on HIGH_RES_TIMERS
101 select SND_TIMER
102 help
103 Say Y here to enable HR-timer backend for ALSA timer. ALSA uses
104 the hrtimer as a precise timing source. The ALSA sequencer code
105 also can use this timing source.
106
107 To compile this driver as a module, choose M here: the module
108 will be called snd-hrtimer.
109
110config SND_SEQ_HRTIMER_DEFAULT
111 bool "Use HR-timer as default sequencer timer"
112 depends on SND_HRTIMER && SND_SEQUENCER
113 default y
114 help
115 Say Y here to use the HR-timer backend as the default sequencer
116 timer.
117
98config SND_RTCTIMER 118config SND_RTCTIMER
99 tristate "RTC Timer support" 119 tristate "RTC Timer support"
100 depends on RTC 120 depends on RTC
@@ -114,6 +134,7 @@ config SND_RTCTIMER
114config SND_SEQ_RTCTIMER_DEFAULT 134config SND_SEQ_RTCTIMER_DEFAULT
115 bool "Use RTC as default sequencer timer" 135 bool "Use RTC as default sequencer timer"
116 depends on SND_RTCTIMER && SND_SEQUENCER 136 depends on SND_RTCTIMER && SND_SEQUENCER
137 dpeends on !SND_SEQ_HRTIMER_DEFAULT
117 default y 138 default y
118 help 139 help
119 Say Y here to use the RTC timer as the default sequencer 140 Say Y here to use the RTC timer as the default sequencer
diff --git a/sound/core/Makefile b/sound/core/Makefile
index d57125a5687d..4229052e7b91 100644
--- a/sound/core/Makefile
+++ b/sound/core/Makefile
@@ -17,12 +17,14 @@ snd-page-alloc-$(CONFIG_HAS_DMA) += sgbuf.o
17 17
18snd-rawmidi-objs := rawmidi.o 18snd-rawmidi-objs := rawmidi.o
19snd-timer-objs := timer.o 19snd-timer-objs := timer.o
20snd-hrtimer-objs := hrtimer.o
20snd-rtctimer-objs := rtctimer.o 21snd-rtctimer-objs := rtctimer.o
21snd-hwdep-objs := hwdep.o 22snd-hwdep-objs := hwdep.o
22 23
23obj-$(CONFIG_SND) += snd.o 24obj-$(CONFIG_SND) += snd.o
24obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o 25obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o
25obj-$(CONFIG_SND_TIMER) += snd-timer.o 26obj-$(CONFIG_SND_TIMER) += snd-timer.o
27obj-$(CONFIG_SND_HRTIMER) += snd-hrtimer.o
26obj-$(CONFIG_SND_RTCTIMER) += snd-rtctimer.o 28obj-$(CONFIG_SND_RTCTIMER) += snd-rtctimer.o
27obj-$(CONFIG_SND_PCM) += snd-pcm.o snd-page-alloc.o 29obj-$(CONFIG_SND_PCM) += snd-pcm.o snd-page-alloc.o
28obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o 30obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o
diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c
new file mode 100644
index 000000000000..b712d7f211ff
--- /dev/null
+++ b/sound/core/hrtimer.c
@@ -0,0 +1,140 @@
1/*
2 */
3
4#include <linux/init.h>
5#include <linux/module.h>
6#include <linux/moduleparam.h>
7#include <linux/hrtimer.h>
8#include <sound/core.h>
9#include <sound/timer.h>
10
11MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
12MODULE_DESCRIPTION("ALSA hrtimer backend");
13MODULE_LICENSE("GPL");
14
15MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_HRTIMER));
16
17#define NANO_SEC 1000000000UL /* 10^9 in sec */
18static unsigned int resolution;
19
20struct snd_hrtimer {
21 struct snd_timer *timer;
22 struct hrtimer hrt;
23};
24
25static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
26{
27 struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt);
28 struct snd_timer *t = stime->timer;
29 hrtimer_forward_now(hrt, ktime_set(0, t->sticks * resolution));
30 snd_timer_interrupt(stime->timer, t->sticks);
31 return HRTIMER_RESTART;
32}
33
34static int snd_hrtimer_open(struct snd_timer *t)
35{
36 struct snd_hrtimer *stime;
37
38 stime = kmalloc(sizeof(*stime), GFP_KERNEL);
39 if (!stime)
40 return -ENOMEM;
41 hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
42 stime->timer = t;
43 stime->hrt.cb_mode = HRTIMER_CB_SOFTIRQ;
44 stime->hrt.function = snd_hrtimer_callback;
45 t->private_data = stime;
46 return 0;
47}
48
49static int snd_hrtimer_close(struct snd_timer *t)
50{
51 struct snd_hrtimer *stime = t->private_data;
52
53 if (stime) {
54 hrtimer_cancel(&stime->hrt);
55 kfree(stime);
56 t->private_data = NULL;
57 }
58 return 0;
59}
60
61static int snd_hrtimer_start(struct snd_timer *t)
62{
63 struct snd_hrtimer *stime = t->private_data;
64
65 hrtimer_start(&stime->hrt, ktime_set(0, t->sticks * resolution),
66 HRTIMER_MODE_REL);
67 return 0;
68}
69
70static int snd_hrtimer_stop(struct snd_timer *t)
71{
72 struct snd_hrtimer *stime = t->private_data;
73
74 hrtimer_cancel(&stime->hrt);
75 return 0;
76}
77
78static struct snd_timer_hardware hrtimer_hw = {
79 .flags = (SNDRV_TIMER_HW_AUTO |
80 /*SNDRV_TIMER_HW_FIRST |*/
81 SNDRV_TIMER_HW_TASKLET),
82 .open = snd_hrtimer_open,
83 .close = snd_hrtimer_close,
84 .start = snd_hrtimer_start,
85 .stop = snd_hrtimer_stop,
86};
87
88/*
89 * entry functions
90 */
91
92static struct snd_timer *mytimer;
93
94static int __init snd_hrtimer_init(void)
95{
96 struct snd_timer *timer;
97 struct timespec tp;
98 int err;
99
100 hrtimer_get_res(CLOCK_MONOTONIC, &tp);
101 if (tp.tv_sec > 0 || !tp.tv_nsec) {
102 snd_printk(KERN_ERR
103 "snd-hrtimer: Invalid resolution %u.%09u",
104 (unsigned)tp.tv_sec, (unsigned)tp.tv_nsec);
105 return -EINVAL;
106 }
107 resolution = tp.tv_nsec;
108
109 /* Create a new timer and set up the fields */
110 err = snd_timer_global_new("hrtimer", SNDRV_TIMER_GLOBAL_HRTIMER,
111 &timer);
112 if (err < 0)
113 return err;
114
115 timer->module = THIS_MODULE;
116 strcpy(timer->name, "HR timer");
117 timer->hw = hrtimer_hw;
118 timer->hw.resolution = resolution;
119 timer->hw.ticks = NANO_SEC / resolution;
120
121 err = snd_timer_global_register(timer);
122 if (err < 0) {
123 snd_timer_global_free(timer);
124 return err;
125 }
126 mytimer = timer; /* remember this */
127
128 return 0;
129}
130
131static void __exit snd_hrtimer_exit(void)
132{
133 if (mytimer) {
134 snd_timer_global_free(mytimer);
135 mytimer = NULL;
136 }
137}
138
139module_init(snd_hrtimer_init);
140module_exit(snd_hrtimer_exit);
diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c
index ee0f8405ab35..bf09a5ad1865 100644
--- a/sound/core/seq/seq.c
+++ b/sound/core/seq/seq.c
@@ -43,7 +43,9 @@ int seq_default_timer_class = SNDRV_TIMER_CLASS_GLOBAL;
43int seq_default_timer_sclass = SNDRV_TIMER_SCLASS_NONE; 43int seq_default_timer_sclass = SNDRV_TIMER_SCLASS_NONE;
44int seq_default_timer_card = -1; 44int seq_default_timer_card = -1;
45int seq_default_timer_device = 45int seq_default_timer_device =
46#ifdef CONFIG_SND_SEQ_RTCTIMER_DEFAULT 46#ifdef CONFIG_SND_SEQ_HRTIMER_DEFAULT
47 SNDRV_TIMER_GLOBAL_HRTIMER
48#elif defined(CONFIG_SND_SEQ_RTCTIMER_DEFAULT)
47 SNDRV_TIMER_GLOBAL_RTC 49 SNDRV_TIMER_GLOBAL_RTC
48#else 50#else
49 SNDRV_TIMER_GLOBAL_SYSTEM 51 SNDRV_TIMER_GLOBAL_SYSTEM