aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/hrtimer.c
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/core/hrtimer.c
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/core/hrtimer.c')
-rw-r--r--sound/core/hrtimer.c140
1 files changed, 140 insertions, 0 deletions
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);