~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/core/hrtimer.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * ALSA timer back-end using hrtimer
  4  * Copyright (C) 2008 Takashi Iwai
  5  */
  6 
  7 #include <linux/init.h>
  8 #include <linux/slab.h>
  9 #include <linux/module.h>
 10 #include <linux/moduleparam.h>
 11 #include <linux/hrtimer.h>
 12 #include <sound/core.h>
 13 #include <sound/timer.h>
 14 
 15 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 16 MODULE_DESCRIPTION("ALSA hrtimer backend");
 17 MODULE_LICENSE("GPL");
 18 
 19 MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_HRTIMER));
 20 
 21 #define NANO_SEC        1000000000UL    /* 10^9 in sec */
 22 static unsigned int resolution;
 23 
 24 struct snd_hrtimer {
 25         struct snd_timer *timer;
 26         struct hrtimer hrt;
 27         bool in_callback;
 28 };
 29 
 30 static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
 31 {
 32         struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt);
 33         struct snd_timer *t = stime->timer;
 34         ktime_t delta;
 35         unsigned long ticks;
 36         enum hrtimer_restart ret = HRTIMER_NORESTART;
 37 
 38         scoped_guard(spinlock, &t->lock) {
 39                 if (!t->running)
 40                         return HRTIMER_NORESTART; /* fast path */
 41                 stime->in_callback = true;
 42                 ticks = t->sticks;
 43         }
 44 
 45         /* calculate the drift */
 46         delta = ktime_sub(hrt->base->get_time(), hrtimer_get_expires(hrt));
 47         if (delta > 0)
 48                 ticks += ktime_divns(delta, ticks * resolution);
 49 
 50         snd_timer_interrupt(stime->timer, ticks);
 51 
 52         guard(spinlock)(&t->lock);
 53         if (t->running) {
 54                 hrtimer_add_expires_ns(hrt, t->sticks * resolution);
 55                 ret = HRTIMER_RESTART;
 56         }
 57 
 58         stime->in_callback = false;
 59         return ret;
 60 }
 61 
 62 static int snd_hrtimer_open(struct snd_timer *t)
 63 {
 64         struct snd_hrtimer *stime;
 65 
 66         stime = kzalloc(sizeof(*stime), GFP_KERNEL);
 67         if (!stime)
 68                 return -ENOMEM;
 69         hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 70         stime->timer = t;
 71         stime->hrt.function = snd_hrtimer_callback;
 72         t->private_data = stime;
 73         return 0;
 74 }
 75 
 76 static int snd_hrtimer_close(struct snd_timer *t)
 77 {
 78         struct snd_hrtimer *stime = t->private_data;
 79 
 80         if (stime) {
 81                 scoped_guard(spinlock_irq, &t->lock) {
 82                         t->running = 0; /* just to be sure */
 83                         stime->in_callback = 1; /* skip start/stop */
 84                 }
 85 
 86                 hrtimer_cancel(&stime->hrt);
 87                 kfree(stime);
 88                 t->private_data = NULL;
 89         }
 90         return 0;
 91 }
 92 
 93 static int snd_hrtimer_start(struct snd_timer *t)
 94 {
 95         struct snd_hrtimer *stime = t->private_data;
 96 
 97         if (stime->in_callback)
 98                 return 0;
 99         hrtimer_start(&stime->hrt, ns_to_ktime(t->sticks * resolution),
100                       HRTIMER_MODE_REL);
101         return 0;
102 }
103 
104 static int snd_hrtimer_stop(struct snd_timer *t)
105 {
106         struct snd_hrtimer *stime = t->private_data;
107 
108         if (stime->in_callback)
109                 return 0;
110         hrtimer_try_to_cancel(&stime->hrt);
111         return 0;
112 }
113 
114 static const struct snd_timer_hardware hrtimer_hw __initconst = {
115         .flags =        SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_WORK,
116         .open =         snd_hrtimer_open,
117         .close =        snd_hrtimer_close,
118         .start =        snd_hrtimer_start,
119         .stop =         snd_hrtimer_stop,
120 };
121 
122 /*
123  * entry functions
124  */
125 
126 static struct snd_timer *mytimer;
127 
128 static int __init snd_hrtimer_init(void)
129 {
130         struct snd_timer *timer;
131         int err;
132 
133         resolution = hrtimer_resolution;
134 
135         /* Create a new timer and set up the fields */
136         err = snd_timer_global_new("hrtimer", SNDRV_TIMER_GLOBAL_HRTIMER,
137                                    &timer);
138         if (err < 0)
139                 return err;
140 
141         timer->module = THIS_MODULE;
142         strcpy(timer->name, "HR timer");
143         timer->hw = hrtimer_hw;
144         timer->hw.resolution = resolution;
145         timer->hw.ticks = NANO_SEC / resolution;
146         timer->max_instances = 100; /* lower the limit */
147 
148         err = snd_timer_global_register(timer);
149         if (err < 0) {
150                 snd_timer_global_free(timer);
151                 return err;
152         }
153         mytimer = timer; /* remember this */
154 
155         return 0;
156 }
157 
158 static void __exit snd_hrtimer_exit(void)
159 {
160         if (mytimer) {
161                 snd_timer_global_free(mytimer);
162                 mytimer = NULL;
163         }
164 }
165 
166 module_init(snd_hrtimer_init);
167 module_exit(snd_hrtimer_exit);
168 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php