0001
0002
0003
0004
0005
0006
0007 #include <linux/init.h>
0008 #include <linux/slab.h>
0009 #include <linux/module.h>
0010 #include <linux/moduleparam.h>
0011 #include <linux/hrtimer.h>
0012 #include <sound/core.h>
0013 #include <sound/timer.h>
0014
0015 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
0016 MODULE_DESCRIPTION("ALSA hrtimer backend");
0017 MODULE_LICENSE("GPL");
0018
0019 MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_HRTIMER));
0020
0021 #define NANO_SEC 1000000000UL
0022 static unsigned int resolution;
0023
0024 struct snd_hrtimer {
0025 struct snd_timer *timer;
0026 struct hrtimer hrt;
0027 bool in_callback;
0028 };
0029
0030 static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
0031 {
0032 struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt);
0033 struct snd_timer *t = stime->timer;
0034 ktime_t delta;
0035 unsigned long ticks;
0036 enum hrtimer_restart ret = HRTIMER_NORESTART;
0037
0038 spin_lock(&t->lock);
0039 if (!t->running)
0040 goto out;
0041 stime->in_callback = true;
0042 ticks = t->sticks;
0043 spin_unlock(&t->lock);
0044
0045
0046 delta = ktime_sub(hrt->base->get_time(), hrtimer_get_expires(hrt));
0047 if (delta > 0)
0048 ticks += ktime_divns(delta, ticks * resolution);
0049
0050 snd_timer_interrupt(stime->timer, ticks);
0051
0052 spin_lock(&t->lock);
0053 if (t->running) {
0054 hrtimer_add_expires_ns(hrt, t->sticks * resolution);
0055 ret = HRTIMER_RESTART;
0056 }
0057
0058 stime->in_callback = false;
0059 out:
0060 spin_unlock(&t->lock);
0061 return ret;
0062 }
0063
0064 static int snd_hrtimer_open(struct snd_timer *t)
0065 {
0066 struct snd_hrtimer *stime;
0067
0068 stime = kzalloc(sizeof(*stime), GFP_KERNEL);
0069 if (!stime)
0070 return -ENOMEM;
0071 hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
0072 stime->timer = t;
0073 stime->hrt.function = snd_hrtimer_callback;
0074 t->private_data = stime;
0075 return 0;
0076 }
0077
0078 static int snd_hrtimer_close(struct snd_timer *t)
0079 {
0080 struct snd_hrtimer *stime = t->private_data;
0081
0082 if (stime) {
0083 spin_lock_irq(&t->lock);
0084 t->running = 0;
0085 stime->in_callback = 1;
0086 spin_unlock_irq(&t->lock);
0087
0088 hrtimer_cancel(&stime->hrt);
0089 kfree(stime);
0090 t->private_data = NULL;
0091 }
0092 return 0;
0093 }
0094
0095 static int snd_hrtimer_start(struct snd_timer *t)
0096 {
0097 struct snd_hrtimer *stime = t->private_data;
0098
0099 if (stime->in_callback)
0100 return 0;
0101 hrtimer_start(&stime->hrt, ns_to_ktime(t->sticks * resolution),
0102 HRTIMER_MODE_REL);
0103 return 0;
0104 }
0105
0106 static int snd_hrtimer_stop(struct snd_timer *t)
0107 {
0108 struct snd_hrtimer *stime = t->private_data;
0109
0110 if (stime->in_callback)
0111 return 0;
0112 hrtimer_try_to_cancel(&stime->hrt);
0113 return 0;
0114 }
0115
0116 static const struct snd_timer_hardware hrtimer_hw __initconst = {
0117 .flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_WORK,
0118 .open = snd_hrtimer_open,
0119 .close = snd_hrtimer_close,
0120 .start = snd_hrtimer_start,
0121 .stop = snd_hrtimer_stop,
0122 };
0123
0124
0125
0126
0127
0128 static struct snd_timer *mytimer;
0129
0130 static int __init snd_hrtimer_init(void)
0131 {
0132 struct snd_timer *timer;
0133 int err;
0134
0135 resolution = hrtimer_resolution;
0136
0137
0138 err = snd_timer_global_new("hrtimer", SNDRV_TIMER_GLOBAL_HRTIMER,
0139 &timer);
0140 if (err < 0)
0141 return err;
0142
0143 timer->module = THIS_MODULE;
0144 strcpy(timer->name, "HR timer");
0145 timer->hw = hrtimer_hw;
0146 timer->hw.resolution = resolution;
0147 timer->hw.ticks = NANO_SEC / resolution;
0148 timer->max_instances = 100;
0149
0150 err = snd_timer_global_register(timer);
0151 if (err < 0) {
0152 snd_timer_global_free(timer);
0153 return err;
0154 }
0155 mytimer = timer;
0156
0157 return 0;
0158 }
0159
0160 static void __exit snd_hrtimer_exit(void)
0161 {
0162 if (mytimer) {
0163 snd_timer_global_free(mytimer);
0164 mytimer = NULL;
0165 }
0166 }
0167
0168 module_init(snd_hrtimer_init);
0169 module_exit(snd_hrtimer_exit);