1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Timers abstract layer
4*4882a593Smuzhiyun * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <linux/delay.h>
8*4882a593Smuzhiyun #include <linux/init.h>
9*4882a593Smuzhiyun #include <linux/slab.h>
10*4882a593Smuzhiyun #include <linux/time.h>
11*4882a593Smuzhiyun #include <linux/mutex.h>
12*4882a593Smuzhiyun #include <linux/device.h>
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/string.h>
15*4882a593Smuzhiyun #include <linux/sched/signal.h>
16*4882a593Smuzhiyun #include <sound/core.h>
17*4882a593Smuzhiyun #include <sound/timer.h>
18*4882a593Smuzhiyun #include <sound/control.h>
19*4882a593Smuzhiyun #include <sound/info.h>
20*4882a593Smuzhiyun #include <sound/minors.h>
21*4882a593Smuzhiyun #include <sound/initval.h>
22*4882a593Smuzhiyun #include <linux/kmod.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun /* internal flags */
25*4882a593Smuzhiyun #define SNDRV_TIMER_IFLG_PAUSED 0x00010000
26*4882a593Smuzhiyun #define SNDRV_TIMER_IFLG_DEAD 0x00020000
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_SND_HRTIMER)
29*4882a593Smuzhiyun #define DEFAULT_TIMER_LIMIT 4
30*4882a593Smuzhiyun #else
31*4882a593Smuzhiyun #define DEFAULT_TIMER_LIMIT 1
32*4882a593Smuzhiyun #endif
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun static int timer_limit = DEFAULT_TIMER_LIMIT;
35*4882a593Smuzhiyun static int timer_tstamp_monotonic = 1;
36*4882a593Smuzhiyun MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>");
37*4882a593Smuzhiyun MODULE_DESCRIPTION("ALSA timer interface");
38*4882a593Smuzhiyun MODULE_LICENSE("GPL");
39*4882a593Smuzhiyun module_param(timer_limit, int, 0444);
40*4882a593Smuzhiyun MODULE_PARM_DESC(timer_limit, "Maximum global timers in system.");
41*4882a593Smuzhiyun module_param(timer_tstamp_monotonic, int, 0444);
42*4882a593Smuzhiyun MODULE_PARM_DESC(timer_tstamp_monotonic, "Use posix monotonic clock source for timestamps (default).");
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun MODULE_ALIAS_CHARDEV(CONFIG_SND_MAJOR, SNDRV_MINOR_TIMER);
45*4882a593Smuzhiyun MODULE_ALIAS("devname:snd/timer");
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun enum timer_tread_format {
48*4882a593Smuzhiyun TREAD_FORMAT_NONE = 0,
49*4882a593Smuzhiyun TREAD_FORMAT_TIME64,
50*4882a593Smuzhiyun TREAD_FORMAT_TIME32,
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun struct snd_timer_tread32 {
54*4882a593Smuzhiyun int event;
55*4882a593Smuzhiyun s32 tstamp_sec;
56*4882a593Smuzhiyun s32 tstamp_nsec;
57*4882a593Smuzhiyun unsigned int val;
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun struct snd_timer_tread64 {
61*4882a593Smuzhiyun int event;
62*4882a593Smuzhiyun u8 pad1[4];
63*4882a593Smuzhiyun s64 tstamp_sec;
64*4882a593Smuzhiyun s64 tstamp_nsec;
65*4882a593Smuzhiyun unsigned int val;
66*4882a593Smuzhiyun u8 pad2[4];
67*4882a593Smuzhiyun };
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun struct snd_timer_user {
70*4882a593Smuzhiyun struct snd_timer_instance *timeri;
71*4882a593Smuzhiyun int tread; /* enhanced read with timestamps and events */
72*4882a593Smuzhiyun unsigned long ticks;
73*4882a593Smuzhiyun unsigned long overrun;
74*4882a593Smuzhiyun int qhead;
75*4882a593Smuzhiyun int qtail;
76*4882a593Smuzhiyun int qused;
77*4882a593Smuzhiyun int queue_size;
78*4882a593Smuzhiyun bool disconnected;
79*4882a593Smuzhiyun struct snd_timer_read *queue;
80*4882a593Smuzhiyun struct snd_timer_tread64 *tqueue;
81*4882a593Smuzhiyun spinlock_t qlock;
82*4882a593Smuzhiyun unsigned long last_resolution;
83*4882a593Smuzhiyun unsigned int filter;
84*4882a593Smuzhiyun struct timespec64 tstamp; /* trigger tstamp */
85*4882a593Smuzhiyun wait_queue_head_t qchange_sleep;
86*4882a593Smuzhiyun struct snd_fasync *fasync;
87*4882a593Smuzhiyun struct mutex ioctl_lock;
88*4882a593Smuzhiyun };
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun struct snd_timer_status32 {
91*4882a593Smuzhiyun s32 tstamp_sec; /* Timestamp - last update */
92*4882a593Smuzhiyun s32 tstamp_nsec;
93*4882a593Smuzhiyun unsigned int resolution; /* current period resolution in ns */
94*4882a593Smuzhiyun unsigned int lost; /* counter of master tick lost */
95*4882a593Smuzhiyun unsigned int overrun; /* count of read queue overruns */
96*4882a593Smuzhiyun unsigned int queue; /* used queue size */
97*4882a593Smuzhiyun unsigned char reserved[64]; /* reserved */
98*4882a593Smuzhiyun };
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun #define SNDRV_TIMER_IOCTL_STATUS32 _IOR('T', 0x14, struct snd_timer_status32)
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun struct snd_timer_status64 {
103*4882a593Smuzhiyun s64 tstamp_sec; /* Timestamp - last update */
104*4882a593Smuzhiyun s64 tstamp_nsec;
105*4882a593Smuzhiyun unsigned int resolution; /* current period resolution in ns */
106*4882a593Smuzhiyun unsigned int lost; /* counter of master tick lost */
107*4882a593Smuzhiyun unsigned int overrun; /* count of read queue overruns */
108*4882a593Smuzhiyun unsigned int queue; /* used queue size */
109*4882a593Smuzhiyun unsigned char reserved[64]; /* reserved */
110*4882a593Smuzhiyun };
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun #define SNDRV_TIMER_IOCTL_STATUS64 _IOR('T', 0x14, struct snd_timer_status64)
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun /* list of timers */
115*4882a593Smuzhiyun static LIST_HEAD(snd_timer_list);
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun /* list of slave instances */
118*4882a593Smuzhiyun static LIST_HEAD(snd_timer_slave_list);
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun /* lock for slave active lists */
121*4882a593Smuzhiyun static DEFINE_SPINLOCK(slave_active_lock);
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun #define MAX_SLAVE_INSTANCES 1000
124*4882a593Smuzhiyun static int num_slaves;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun static DEFINE_MUTEX(register_mutex);
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun static int snd_timer_free(struct snd_timer *timer);
129*4882a593Smuzhiyun static int snd_timer_dev_free(struct snd_device *device);
130*4882a593Smuzhiyun static int snd_timer_dev_register(struct snd_device *device);
131*4882a593Smuzhiyun static int snd_timer_dev_disconnect(struct snd_device *device);
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left);
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun /*
136*4882a593Smuzhiyun * create a timer instance with the given owner string.
137*4882a593Smuzhiyun */
snd_timer_instance_new(const char * owner)138*4882a593Smuzhiyun struct snd_timer_instance *snd_timer_instance_new(const char *owner)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun struct snd_timer_instance *timeri;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun timeri = kzalloc(sizeof(*timeri), GFP_KERNEL);
143*4882a593Smuzhiyun if (timeri == NULL)
144*4882a593Smuzhiyun return NULL;
145*4882a593Smuzhiyun timeri->owner = kstrdup(owner, GFP_KERNEL);
146*4882a593Smuzhiyun if (! timeri->owner) {
147*4882a593Smuzhiyun kfree(timeri);
148*4882a593Smuzhiyun return NULL;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun INIT_LIST_HEAD(&timeri->open_list);
151*4882a593Smuzhiyun INIT_LIST_HEAD(&timeri->active_list);
152*4882a593Smuzhiyun INIT_LIST_HEAD(&timeri->ack_list);
153*4882a593Smuzhiyun INIT_LIST_HEAD(&timeri->slave_list_head);
154*4882a593Smuzhiyun INIT_LIST_HEAD(&timeri->slave_active_head);
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun return timeri;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun EXPORT_SYMBOL(snd_timer_instance_new);
159*4882a593Smuzhiyun
snd_timer_instance_free(struct snd_timer_instance * timeri)160*4882a593Smuzhiyun void snd_timer_instance_free(struct snd_timer_instance *timeri)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun if (timeri) {
163*4882a593Smuzhiyun if (timeri->private_free)
164*4882a593Smuzhiyun timeri->private_free(timeri);
165*4882a593Smuzhiyun kfree(timeri->owner);
166*4882a593Smuzhiyun kfree(timeri);
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun EXPORT_SYMBOL(snd_timer_instance_free);
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /*
172*4882a593Smuzhiyun * find a timer instance from the given timer id
173*4882a593Smuzhiyun */
snd_timer_find(struct snd_timer_id * tid)174*4882a593Smuzhiyun static struct snd_timer *snd_timer_find(struct snd_timer_id *tid)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun struct snd_timer *timer;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun list_for_each_entry(timer, &snd_timer_list, device_list) {
179*4882a593Smuzhiyun if (timer->tmr_class != tid->dev_class)
180*4882a593Smuzhiyun continue;
181*4882a593Smuzhiyun if ((timer->tmr_class == SNDRV_TIMER_CLASS_CARD ||
182*4882a593Smuzhiyun timer->tmr_class == SNDRV_TIMER_CLASS_PCM) &&
183*4882a593Smuzhiyun (timer->card == NULL ||
184*4882a593Smuzhiyun timer->card->number != tid->card))
185*4882a593Smuzhiyun continue;
186*4882a593Smuzhiyun if (timer->tmr_device != tid->device)
187*4882a593Smuzhiyun continue;
188*4882a593Smuzhiyun if (timer->tmr_subdevice != tid->subdevice)
189*4882a593Smuzhiyun continue;
190*4882a593Smuzhiyun return timer;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun return NULL;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun #ifdef CONFIG_MODULES
196*4882a593Smuzhiyun
snd_timer_request(struct snd_timer_id * tid)197*4882a593Smuzhiyun static void snd_timer_request(struct snd_timer_id *tid)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun switch (tid->dev_class) {
200*4882a593Smuzhiyun case SNDRV_TIMER_CLASS_GLOBAL:
201*4882a593Smuzhiyun if (tid->device < timer_limit)
202*4882a593Smuzhiyun request_module("snd-timer-%i", tid->device);
203*4882a593Smuzhiyun break;
204*4882a593Smuzhiyun case SNDRV_TIMER_CLASS_CARD:
205*4882a593Smuzhiyun case SNDRV_TIMER_CLASS_PCM:
206*4882a593Smuzhiyun if (tid->card < snd_ecards_limit)
207*4882a593Smuzhiyun request_module("snd-card-%i", tid->card);
208*4882a593Smuzhiyun break;
209*4882a593Smuzhiyun default:
210*4882a593Smuzhiyun break;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun #endif
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun /* move the slave if it belongs to the master; return 1 if match */
check_matching_master_slave(struct snd_timer_instance * master,struct snd_timer_instance * slave)217*4882a593Smuzhiyun static int check_matching_master_slave(struct snd_timer_instance *master,
218*4882a593Smuzhiyun struct snd_timer_instance *slave)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun if (slave->slave_class != master->slave_class ||
221*4882a593Smuzhiyun slave->slave_id != master->slave_id)
222*4882a593Smuzhiyun return 0;
223*4882a593Smuzhiyun if (master->timer->num_instances >= master->timer->max_instances)
224*4882a593Smuzhiyun return -EBUSY;
225*4882a593Smuzhiyun list_move_tail(&slave->open_list, &master->slave_list_head);
226*4882a593Smuzhiyun master->timer->num_instances++;
227*4882a593Smuzhiyun spin_lock_irq(&slave_active_lock);
228*4882a593Smuzhiyun spin_lock(&master->timer->lock);
229*4882a593Smuzhiyun slave->master = master;
230*4882a593Smuzhiyun slave->timer = master->timer;
231*4882a593Smuzhiyun if (slave->flags & SNDRV_TIMER_IFLG_RUNNING)
232*4882a593Smuzhiyun list_add_tail(&slave->active_list, &master->slave_active_head);
233*4882a593Smuzhiyun spin_unlock(&master->timer->lock);
234*4882a593Smuzhiyun spin_unlock_irq(&slave_active_lock);
235*4882a593Smuzhiyun return 1;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun /*
239*4882a593Smuzhiyun * look for a master instance matching with the slave id of the given slave.
240*4882a593Smuzhiyun * when found, relink the open_link of the slave.
241*4882a593Smuzhiyun *
242*4882a593Smuzhiyun * call this with register_mutex down.
243*4882a593Smuzhiyun */
snd_timer_check_slave(struct snd_timer_instance * slave)244*4882a593Smuzhiyun static int snd_timer_check_slave(struct snd_timer_instance *slave)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun struct snd_timer *timer;
247*4882a593Smuzhiyun struct snd_timer_instance *master;
248*4882a593Smuzhiyun int err = 0;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun /* FIXME: it's really dumb to look up all entries.. */
251*4882a593Smuzhiyun list_for_each_entry(timer, &snd_timer_list, device_list) {
252*4882a593Smuzhiyun list_for_each_entry(master, &timer->open_list_head, open_list) {
253*4882a593Smuzhiyun err = check_matching_master_slave(master, slave);
254*4882a593Smuzhiyun if (err != 0) /* match found or error */
255*4882a593Smuzhiyun goto out;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun out:
259*4882a593Smuzhiyun return err < 0 ? err : 0;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun /*
263*4882a593Smuzhiyun * look for slave instances matching with the slave id of the given master.
264*4882a593Smuzhiyun * when found, relink the open_link of slaves.
265*4882a593Smuzhiyun *
266*4882a593Smuzhiyun * call this with register_mutex down.
267*4882a593Smuzhiyun */
snd_timer_check_master(struct snd_timer_instance * master)268*4882a593Smuzhiyun static int snd_timer_check_master(struct snd_timer_instance *master)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun struct snd_timer_instance *slave, *tmp;
271*4882a593Smuzhiyun int err = 0;
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun /* check all pending slaves */
274*4882a593Smuzhiyun list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) {
275*4882a593Smuzhiyun err = check_matching_master_slave(master, slave);
276*4882a593Smuzhiyun if (err < 0)
277*4882a593Smuzhiyun break;
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun return err < 0 ? err : 0;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun static void snd_timer_close_locked(struct snd_timer_instance *timeri,
283*4882a593Smuzhiyun struct device **card_devp_to_put);
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun /*
286*4882a593Smuzhiyun * open a timer instance
287*4882a593Smuzhiyun * when opening a master, the slave id must be here given.
288*4882a593Smuzhiyun */
snd_timer_open(struct snd_timer_instance * timeri,struct snd_timer_id * tid,unsigned int slave_id)289*4882a593Smuzhiyun int snd_timer_open(struct snd_timer_instance *timeri,
290*4882a593Smuzhiyun struct snd_timer_id *tid,
291*4882a593Smuzhiyun unsigned int slave_id)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun struct snd_timer *timer;
294*4882a593Smuzhiyun struct device *card_dev_to_put = NULL;
295*4882a593Smuzhiyun int err;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun mutex_lock(®ister_mutex);
298*4882a593Smuzhiyun if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) {
299*4882a593Smuzhiyun /* open a slave instance */
300*4882a593Smuzhiyun if (tid->dev_sclass <= SNDRV_TIMER_SCLASS_NONE ||
301*4882a593Smuzhiyun tid->dev_sclass > SNDRV_TIMER_SCLASS_OSS_SEQUENCER) {
302*4882a593Smuzhiyun pr_debug("ALSA: timer: invalid slave class %i\n",
303*4882a593Smuzhiyun tid->dev_sclass);
304*4882a593Smuzhiyun err = -EINVAL;
305*4882a593Smuzhiyun goto unlock;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun if (num_slaves >= MAX_SLAVE_INSTANCES) {
308*4882a593Smuzhiyun err = -EBUSY;
309*4882a593Smuzhiyun goto unlock;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun timeri->slave_class = tid->dev_sclass;
312*4882a593Smuzhiyun timeri->slave_id = tid->device;
313*4882a593Smuzhiyun timeri->flags |= SNDRV_TIMER_IFLG_SLAVE;
314*4882a593Smuzhiyun list_add_tail(&timeri->open_list, &snd_timer_slave_list);
315*4882a593Smuzhiyun num_slaves++;
316*4882a593Smuzhiyun err = snd_timer_check_slave(timeri);
317*4882a593Smuzhiyun goto list_added;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun /* open a master instance */
321*4882a593Smuzhiyun timer = snd_timer_find(tid);
322*4882a593Smuzhiyun #ifdef CONFIG_MODULES
323*4882a593Smuzhiyun if (!timer) {
324*4882a593Smuzhiyun mutex_unlock(®ister_mutex);
325*4882a593Smuzhiyun snd_timer_request(tid);
326*4882a593Smuzhiyun mutex_lock(®ister_mutex);
327*4882a593Smuzhiyun timer = snd_timer_find(tid);
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun #endif
330*4882a593Smuzhiyun if (!timer) {
331*4882a593Smuzhiyun err = -ENODEV;
332*4882a593Smuzhiyun goto unlock;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun if (!list_empty(&timer->open_list_head)) {
335*4882a593Smuzhiyun struct snd_timer_instance *t =
336*4882a593Smuzhiyun list_entry(timer->open_list_head.next,
337*4882a593Smuzhiyun struct snd_timer_instance, open_list);
338*4882a593Smuzhiyun if (t->flags & SNDRV_TIMER_IFLG_EXCLUSIVE) {
339*4882a593Smuzhiyun err = -EBUSY;
340*4882a593Smuzhiyun goto unlock;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun if (timer->num_instances >= timer->max_instances) {
344*4882a593Smuzhiyun err = -EBUSY;
345*4882a593Smuzhiyun goto unlock;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun if (!try_module_get(timer->module)) {
348*4882a593Smuzhiyun err = -EBUSY;
349*4882a593Smuzhiyun goto unlock;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun /* take a card refcount for safe disconnection */
352*4882a593Smuzhiyun if (timer->card) {
353*4882a593Smuzhiyun get_device(&timer->card->card_dev);
354*4882a593Smuzhiyun card_dev_to_put = &timer->card->card_dev;
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun if (list_empty(&timer->open_list_head) && timer->hw.open) {
358*4882a593Smuzhiyun err = timer->hw.open(timer);
359*4882a593Smuzhiyun if (err) {
360*4882a593Smuzhiyun module_put(timer->module);
361*4882a593Smuzhiyun goto unlock;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun timeri->timer = timer;
366*4882a593Smuzhiyun timeri->slave_class = tid->dev_sclass;
367*4882a593Smuzhiyun timeri->slave_id = slave_id;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun list_add_tail(&timeri->open_list, &timer->open_list_head);
370*4882a593Smuzhiyun timer->num_instances++;
371*4882a593Smuzhiyun err = snd_timer_check_master(timeri);
372*4882a593Smuzhiyun list_added:
373*4882a593Smuzhiyun if (err < 0)
374*4882a593Smuzhiyun snd_timer_close_locked(timeri, &card_dev_to_put);
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun unlock:
377*4882a593Smuzhiyun mutex_unlock(®ister_mutex);
378*4882a593Smuzhiyun /* put_device() is called after unlock for avoiding deadlock */
379*4882a593Smuzhiyun if (err < 0 && card_dev_to_put)
380*4882a593Smuzhiyun put_device(card_dev_to_put);
381*4882a593Smuzhiyun return err;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun EXPORT_SYMBOL(snd_timer_open);
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun /*
386*4882a593Smuzhiyun * close a timer instance
387*4882a593Smuzhiyun * call this with register_mutex down.
388*4882a593Smuzhiyun */
snd_timer_close_locked(struct snd_timer_instance * timeri,struct device ** card_devp_to_put)389*4882a593Smuzhiyun static void snd_timer_close_locked(struct snd_timer_instance *timeri,
390*4882a593Smuzhiyun struct device **card_devp_to_put)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun struct snd_timer *timer = timeri->timer;
393*4882a593Smuzhiyun struct snd_timer_instance *slave, *tmp;
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun if (timer) {
396*4882a593Smuzhiyun spin_lock_irq(&timer->lock);
397*4882a593Smuzhiyun timeri->flags |= SNDRV_TIMER_IFLG_DEAD;
398*4882a593Smuzhiyun spin_unlock_irq(&timer->lock);
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun if (!list_empty(&timeri->open_list)) {
402*4882a593Smuzhiyun list_del_init(&timeri->open_list);
403*4882a593Smuzhiyun if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
404*4882a593Smuzhiyun num_slaves--;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun /* force to stop the timer */
408*4882a593Smuzhiyun snd_timer_stop(timeri);
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun if (timer) {
411*4882a593Smuzhiyun timer->num_instances--;
412*4882a593Smuzhiyun /* wait, until the active callback is finished */
413*4882a593Smuzhiyun spin_lock_irq(&timer->lock);
414*4882a593Smuzhiyun while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
415*4882a593Smuzhiyun spin_unlock_irq(&timer->lock);
416*4882a593Smuzhiyun udelay(10);
417*4882a593Smuzhiyun spin_lock_irq(&timer->lock);
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun spin_unlock_irq(&timer->lock);
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun /* remove slave links */
422*4882a593Smuzhiyun spin_lock_irq(&slave_active_lock);
423*4882a593Smuzhiyun spin_lock(&timer->lock);
424*4882a593Smuzhiyun timeri->timer = NULL;
425*4882a593Smuzhiyun list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
426*4882a593Smuzhiyun open_list) {
427*4882a593Smuzhiyun list_move_tail(&slave->open_list, &snd_timer_slave_list);
428*4882a593Smuzhiyun timer->num_instances--;
429*4882a593Smuzhiyun slave->master = NULL;
430*4882a593Smuzhiyun slave->timer = NULL;
431*4882a593Smuzhiyun list_del_init(&slave->ack_list);
432*4882a593Smuzhiyun list_del_init(&slave->active_list);
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun spin_unlock(&timer->lock);
435*4882a593Smuzhiyun spin_unlock_irq(&slave_active_lock);
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun /* slave doesn't need to release timer resources below */
438*4882a593Smuzhiyun if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
439*4882a593Smuzhiyun timer = NULL;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun if (timer) {
443*4882a593Smuzhiyun if (list_empty(&timer->open_list_head) && timer->hw.close)
444*4882a593Smuzhiyun timer->hw.close(timer);
445*4882a593Smuzhiyun /* release a card refcount for safe disconnection */
446*4882a593Smuzhiyun if (timer->card)
447*4882a593Smuzhiyun *card_devp_to_put = &timer->card->card_dev;
448*4882a593Smuzhiyun module_put(timer->module);
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun /*
453*4882a593Smuzhiyun * close a timer instance
454*4882a593Smuzhiyun */
snd_timer_close(struct snd_timer_instance * timeri)455*4882a593Smuzhiyun void snd_timer_close(struct snd_timer_instance *timeri)
456*4882a593Smuzhiyun {
457*4882a593Smuzhiyun struct device *card_dev_to_put = NULL;
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun if (snd_BUG_ON(!timeri))
460*4882a593Smuzhiyun return;
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun mutex_lock(®ister_mutex);
463*4882a593Smuzhiyun snd_timer_close_locked(timeri, &card_dev_to_put);
464*4882a593Smuzhiyun mutex_unlock(®ister_mutex);
465*4882a593Smuzhiyun /* put_device() is called after unlock for avoiding deadlock */
466*4882a593Smuzhiyun if (card_dev_to_put)
467*4882a593Smuzhiyun put_device(card_dev_to_put);
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun EXPORT_SYMBOL(snd_timer_close);
470*4882a593Smuzhiyun
snd_timer_hw_resolution(struct snd_timer * timer)471*4882a593Smuzhiyun static unsigned long snd_timer_hw_resolution(struct snd_timer *timer)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun if (timer->hw.c_resolution)
474*4882a593Smuzhiyun return timer->hw.c_resolution(timer);
475*4882a593Smuzhiyun else
476*4882a593Smuzhiyun return timer->hw.resolution;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun
snd_timer_resolution(struct snd_timer_instance * timeri)479*4882a593Smuzhiyun unsigned long snd_timer_resolution(struct snd_timer_instance *timeri)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun struct snd_timer * timer;
482*4882a593Smuzhiyun unsigned long ret = 0;
483*4882a593Smuzhiyun unsigned long flags;
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun if (timeri == NULL)
486*4882a593Smuzhiyun return 0;
487*4882a593Smuzhiyun timer = timeri->timer;
488*4882a593Smuzhiyun if (timer) {
489*4882a593Smuzhiyun spin_lock_irqsave(&timer->lock, flags);
490*4882a593Smuzhiyun ret = snd_timer_hw_resolution(timer);
491*4882a593Smuzhiyun spin_unlock_irqrestore(&timer->lock, flags);
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun return ret;
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun EXPORT_SYMBOL(snd_timer_resolution);
496*4882a593Smuzhiyun
snd_timer_notify1(struct snd_timer_instance * ti,int event)497*4882a593Smuzhiyun static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
498*4882a593Smuzhiyun {
499*4882a593Smuzhiyun struct snd_timer *timer = ti->timer;
500*4882a593Smuzhiyun unsigned long resolution = 0;
501*4882a593Smuzhiyun struct snd_timer_instance *ts;
502*4882a593Smuzhiyun struct timespec64 tstamp;
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun if (timer_tstamp_monotonic)
505*4882a593Smuzhiyun ktime_get_ts64(&tstamp);
506*4882a593Smuzhiyun else
507*4882a593Smuzhiyun ktime_get_real_ts64(&tstamp);
508*4882a593Smuzhiyun if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_START ||
509*4882a593Smuzhiyun event > SNDRV_TIMER_EVENT_PAUSE))
510*4882a593Smuzhiyun return;
511*4882a593Smuzhiyun if (timer &&
512*4882a593Smuzhiyun (event == SNDRV_TIMER_EVENT_START ||
513*4882a593Smuzhiyun event == SNDRV_TIMER_EVENT_CONTINUE))
514*4882a593Smuzhiyun resolution = snd_timer_hw_resolution(timer);
515*4882a593Smuzhiyun if (ti->ccallback)
516*4882a593Smuzhiyun ti->ccallback(ti, event, &tstamp, resolution);
517*4882a593Smuzhiyun if (ti->flags & SNDRV_TIMER_IFLG_SLAVE)
518*4882a593Smuzhiyun return;
519*4882a593Smuzhiyun if (timer == NULL)
520*4882a593Smuzhiyun return;
521*4882a593Smuzhiyun if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
522*4882a593Smuzhiyun return;
523*4882a593Smuzhiyun event += 10; /* convert to SNDRV_TIMER_EVENT_MXXX */
524*4882a593Smuzhiyun list_for_each_entry(ts, &ti->slave_active_head, active_list)
525*4882a593Smuzhiyun if (ts->ccallback)
526*4882a593Smuzhiyun ts->ccallback(ts, event, &tstamp, resolution);
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun /* start/continue a master timer */
snd_timer_start1(struct snd_timer_instance * timeri,bool start,unsigned long ticks)530*4882a593Smuzhiyun static int snd_timer_start1(struct snd_timer_instance *timeri,
531*4882a593Smuzhiyun bool start, unsigned long ticks)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun struct snd_timer *timer;
534*4882a593Smuzhiyun int result;
535*4882a593Smuzhiyun unsigned long flags;
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun timer = timeri->timer;
538*4882a593Smuzhiyun if (!timer)
539*4882a593Smuzhiyun return -EINVAL;
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun spin_lock_irqsave(&timer->lock, flags);
542*4882a593Smuzhiyun if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) {
543*4882a593Smuzhiyun result = -EINVAL;
544*4882a593Smuzhiyun goto unlock;
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun if (timer->card && timer->card->shutdown) {
547*4882a593Smuzhiyun result = -ENODEV;
548*4882a593Smuzhiyun goto unlock;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
551*4882a593Smuzhiyun SNDRV_TIMER_IFLG_START)) {
552*4882a593Smuzhiyun result = -EBUSY;
553*4882a593Smuzhiyun goto unlock;
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun if (start)
557*4882a593Smuzhiyun timeri->ticks = timeri->cticks = ticks;
558*4882a593Smuzhiyun else if (!timeri->cticks)
559*4882a593Smuzhiyun timeri->cticks = 1;
560*4882a593Smuzhiyun timeri->pticks = 0;
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun list_move_tail(&timeri->active_list, &timer->active_list_head);
563*4882a593Smuzhiyun if (timer->running) {
564*4882a593Smuzhiyun if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
565*4882a593Smuzhiyun goto __start_now;
566*4882a593Smuzhiyun timer->flags |= SNDRV_TIMER_FLG_RESCHED;
567*4882a593Smuzhiyun timeri->flags |= SNDRV_TIMER_IFLG_START;
568*4882a593Smuzhiyun result = 1; /* delayed start */
569*4882a593Smuzhiyun } else {
570*4882a593Smuzhiyun if (start)
571*4882a593Smuzhiyun timer->sticks = ticks;
572*4882a593Smuzhiyun timer->hw.start(timer);
573*4882a593Smuzhiyun __start_now:
574*4882a593Smuzhiyun timer->running++;
575*4882a593Smuzhiyun timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
576*4882a593Smuzhiyun result = 0;
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun snd_timer_notify1(timeri, start ? SNDRV_TIMER_EVENT_START :
579*4882a593Smuzhiyun SNDRV_TIMER_EVENT_CONTINUE);
580*4882a593Smuzhiyun unlock:
581*4882a593Smuzhiyun spin_unlock_irqrestore(&timer->lock, flags);
582*4882a593Smuzhiyun return result;
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun /* start/continue a slave timer */
snd_timer_start_slave(struct snd_timer_instance * timeri,bool start)586*4882a593Smuzhiyun static int snd_timer_start_slave(struct snd_timer_instance *timeri,
587*4882a593Smuzhiyun bool start)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun unsigned long flags;
590*4882a593Smuzhiyun int err;
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun spin_lock_irqsave(&slave_active_lock, flags);
593*4882a593Smuzhiyun if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) {
594*4882a593Smuzhiyun err = -EINVAL;
595*4882a593Smuzhiyun goto unlock;
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) {
598*4882a593Smuzhiyun err = -EBUSY;
599*4882a593Smuzhiyun goto unlock;
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
602*4882a593Smuzhiyun if (timeri->master && timeri->timer) {
603*4882a593Smuzhiyun spin_lock(&timeri->timer->lock);
604*4882a593Smuzhiyun list_add_tail(&timeri->active_list,
605*4882a593Smuzhiyun &timeri->master->slave_active_head);
606*4882a593Smuzhiyun snd_timer_notify1(timeri, start ? SNDRV_TIMER_EVENT_START :
607*4882a593Smuzhiyun SNDRV_TIMER_EVENT_CONTINUE);
608*4882a593Smuzhiyun spin_unlock(&timeri->timer->lock);
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun err = 1; /* delayed start */
611*4882a593Smuzhiyun unlock:
612*4882a593Smuzhiyun spin_unlock_irqrestore(&slave_active_lock, flags);
613*4882a593Smuzhiyun return err;
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun /* stop/pause a master timer */
snd_timer_stop1(struct snd_timer_instance * timeri,bool stop)617*4882a593Smuzhiyun static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop)
618*4882a593Smuzhiyun {
619*4882a593Smuzhiyun struct snd_timer *timer;
620*4882a593Smuzhiyun int result = 0;
621*4882a593Smuzhiyun unsigned long flags;
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun timer = timeri->timer;
624*4882a593Smuzhiyun if (!timer)
625*4882a593Smuzhiyun return -EINVAL;
626*4882a593Smuzhiyun spin_lock_irqsave(&timer->lock, flags);
627*4882a593Smuzhiyun list_del_init(&timeri->ack_list);
628*4882a593Smuzhiyun list_del_init(&timeri->active_list);
629*4882a593Smuzhiyun if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
630*4882a593Smuzhiyun SNDRV_TIMER_IFLG_START))) {
631*4882a593Smuzhiyun result = -EBUSY;
632*4882a593Smuzhiyun goto unlock;
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun if (timer->card && timer->card->shutdown)
635*4882a593Smuzhiyun goto unlock;
636*4882a593Smuzhiyun if (stop) {
637*4882a593Smuzhiyun timeri->cticks = timeri->ticks;
638*4882a593Smuzhiyun timeri->pticks = 0;
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun if ((timeri->flags & SNDRV_TIMER_IFLG_RUNNING) &&
641*4882a593Smuzhiyun !(--timer->running)) {
642*4882a593Smuzhiyun timer->hw.stop(timer);
643*4882a593Smuzhiyun if (timer->flags & SNDRV_TIMER_FLG_RESCHED) {
644*4882a593Smuzhiyun timer->flags &= ~SNDRV_TIMER_FLG_RESCHED;
645*4882a593Smuzhiyun snd_timer_reschedule(timer, 0);
646*4882a593Smuzhiyun if (timer->flags & SNDRV_TIMER_FLG_CHANGE) {
647*4882a593Smuzhiyun timer->flags &= ~SNDRV_TIMER_FLG_CHANGE;
648*4882a593Smuzhiyun timer->hw.start(timer);
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START);
653*4882a593Smuzhiyun if (stop)
654*4882a593Smuzhiyun timeri->flags &= ~SNDRV_TIMER_IFLG_PAUSED;
655*4882a593Smuzhiyun else
656*4882a593Smuzhiyun timeri->flags |= SNDRV_TIMER_IFLG_PAUSED;
657*4882a593Smuzhiyun snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP :
658*4882a593Smuzhiyun SNDRV_TIMER_EVENT_PAUSE);
659*4882a593Smuzhiyun unlock:
660*4882a593Smuzhiyun spin_unlock_irqrestore(&timer->lock, flags);
661*4882a593Smuzhiyun return result;
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun /* stop/pause a slave timer */
snd_timer_stop_slave(struct snd_timer_instance * timeri,bool stop)665*4882a593Smuzhiyun static int snd_timer_stop_slave(struct snd_timer_instance *timeri, bool stop)
666*4882a593Smuzhiyun {
667*4882a593Smuzhiyun unsigned long flags;
668*4882a593Smuzhiyun bool running;
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun spin_lock_irqsave(&slave_active_lock, flags);
671*4882a593Smuzhiyun running = timeri->flags & SNDRV_TIMER_IFLG_RUNNING;
672*4882a593Smuzhiyun timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
673*4882a593Smuzhiyun if (timeri->timer) {
674*4882a593Smuzhiyun spin_lock(&timeri->timer->lock);
675*4882a593Smuzhiyun list_del_init(&timeri->ack_list);
676*4882a593Smuzhiyun list_del_init(&timeri->active_list);
677*4882a593Smuzhiyun if (running)
678*4882a593Smuzhiyun snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP :
679*4882a593Smuzhiyun SNDRV_TIMER_EVENT_PAUSE);
680*4882a593Smuzhiyun spin_unlock(&timeri->timer->lock);
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun spin_unlock_irqrestore(&slave_active_lock, flags);
683*4882a593Smuzhiyun return running ? 0 : -EBUSY;
684*4882a593Smuzhiyun }
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun /*
687*4882a593Smuzhiyun * start the timer instance
688*4882a593Smuzhiyun */
snd_timer_start(struct snd_timer_instance * timeri,unsigned int ticks)689*4882a593Smuzhiyun int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks)
690*4882a593Smuzhiyun {
691*4882a593Smuzhiyun if (timeri == NULL || ticks < 1)
692*4882a593Smuzhiyun return -EINVAL;
693*4882a593Smuzhiyun if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
694*4882a593Smuzhiyun return snd_timer_start_slave(timeri, true);
695*4882a593Smuzhiyun else
696*4882a593Smuzhiyun return snd_timer_start1(timeri, true, ticks);
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun EXPORT_SYMBOL(snd_timer_start);
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun /*
701*4882a593Smuzhiyun * stop the timer instance.
702*4882a593Smuzhiyun *
703*4882a593Smuzhiyun * do not call this from the timer callback!
704*4882a593Smuzhiyun */
snd_timer_stop(struct snd_timer_instance * timeri)705*4882a593Smuzhiyun int snd_timer_stop(struct snd_timer_instance *timeri)
706*4882a593Smuzhiyun {
707*4882a593Smuzhiyun if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
708*4882a593Smuzhiyun return snd_timer_stop_slave(timeri, true);
709*4882a593Smuzhiyun else
710*4882a593Smuzhiyun return snd_timer_stop1(timeri, true);
711*4882a593Smuzhiyun }
712*4882a593Smuzhiyun EXPORT_SYMBOL(snd_timer_stop);
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun /*
715*4882a593Smuzhiyun * start again.. the tick is kept.
716*4882a593Smuzhiyun */
snd_timer_continue(struct snd_timer_instance * timeri)717*4882a593Smuzhiyun int snd_timer_continue(struct snd_timer_instance *timeri)
718*4882a593Smuzhiyun {
719*4882a593Smuzhiyun /* timer can continue only after pause */
720*4882a593Smuzhiyun if (!(timeri->flags & SNDRV_TIMER_IFLG_PAUSED))
721*4882a593Smuzhiyun return -EINVAL;
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
724*4882a593Smuzhiyun return snd_timer_start_slave(timeri, false);
725*4882a593Smuzhiyun else
726*4882a593Smuzhiyun return snd_timer_start1(timeri, false, 0);
727*4882a593Smuzhiyun }
728*4882a593Smuzhiyun EXPORT_SYMBOL(snd_timer_continue);
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun /*
731*4882a593Smuzhiyun * pause.. remember the ticks left
732*4882a593Smuzhiyun */
snd_timer_pause(struct snd_timer_instance * timeri)733*4882a593Smuzhiyun int snd_timer_pause(struct snd_timer_instance * timeri)
734*4882a593Smuzhiyun {
735*4882a593Smuzhiyun if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
736*4882a593Smuzhiyun return snd_timer_stop_slave(timeri, false);
737*4882a593Smuzhiyun else
738*4882a593Smuzhiyun return snd_timer_stop1(timeri, false);
739*4882a593Smuzhiyun }
740*4882a593Smuzhiyun EXPORT_SYMBOL(snd_timer_pause);
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun /*
743*4882a593Smuzhiyun * reschedule the timer
744*4882a593Smuzhiyun *
745*4882a593Smuzhiyun * start pending instances and check the scheduling ticks.
746*4882a593Smuzhiyun * when the scheduling ticks is changed set CHANGE flag to reprogram the timer.
747*4882a593Smuzhiyun */
snd_timer_reschedule(struct snd_timer * timer,unsigned long ticks_left)748*4882a593Smuzhiyun static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left)
749*4882a593Smuzhiyun {
750*4882a593Smuzhiyun struct snd_timer_instance *ti;
751*4882a593Smuzhiyun unsigned long ticks = ~0UL;
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun list_for_each_entry(ti, &timer->active_list_head, active_list) {
754*4882a593Smuzhiyun if (ti->flags & SNDRV_TIMER_IFLG_START) {
755*4882a593Smuzhiyun ti->flags &= ~SNDRV_TIMER_IFLG_START;
756*4882a593Smuzhiyun ti->flags |= SNDRV_TIMER_IFLG_RUNNING;
757*4882a593Smuzhiyun timer->running++;
758*4882a593Smuzhiyun }
759*4882a593Smuzhiyun if (ti->flags & SNDRV_TIMER_IFLG_RUNNING) {
760*4882a593Smuzhiyun if (ticks > ti->cticks)
761*4882a593Smuzhiyun ticks = ti->cticks;
762*4882a593Smuzhiyun }
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun if (ticks == ~0UL) {
765*4882a593Smuzhiyun timer->flags &= ~SNDRV_TIMER_FLG_RESCHED;
766*4882a593Smuzhiyun return;
767*4882a593Smuzhiyun }
768*4882a593Smuzhiyun if (ticks > timer->hw.ticks)
769*4882a593Smuzhiyun ticks = timer->hw.ticks;
770*4882a593Smuzhiyun if (ticks_left != ticks)
771*4882a593Smuzhiyun timer->flags |= SNDRV_TIMER_FLG_CHANGE;
772*4882a593Smuzhiyun timer->sticks = ticks;
773*4882a593Smuzhiyun }
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun /* call callbacks in timer ack list */
snd_timer_process_callbacks(struct snd_timer * timer,struct list_head * head)776*4882a593Smuzhiyun static void snd_timer_process_callbacks(struct snd_timer *timer,
777*4882a593Smuzhiyun struct list_head *head)
778*4882a593Smuzhiyun {
779*4882a593Smuzhiyun struct snd_timer_instance *ti;
780*4882a593Smuzhiyun unsigned long resolution, ticks;
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun while (!list_empty(head)) {
783*4882a593Smuzhiyun ti = list_first_entry(head, struct snd_timer_instance,
784*4882a593Smuzhiyun ack_list);
785*4882a593Smuzhiyun
786*4882a593Smuzhiyun /* remove from ack_list and make empty */
787*4882a593Smuzhiyun list_del_init(&ti->ack_list);
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun if (!(ti->flags & SNDRV_TIMER_IFLG_DEAD)) {
790*4882a593Smuzhiyun ticks = ti->pticks;
791*4882a593Smuzhiyun ti->pticks = 0;
792*4882a593Smuzhiyun resolution = ti->resolution;
793*4882a593Smuzhiyun ti->flags |= SNDRV_TIMER_IFLG_CALLBACK;
794*4882a593Smuzhiyun spin_unlock(&timer->lock);
795*4882a593Smuzhiyun if (ti->callback)
796*4882a593Smuzhiyun ti->callback(ti, resolution, ticks);
797*4882a593Smuzhiyun spin_lock(&timer->lock);
798*4882a593Smuzhiyun ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK;
799*4882a593Smuzhiyun }
800*4882a593Smuzhiyun }
801*4882a593Smuzhiyun }
802*4882a593Smuzhiyun
803*4882a593Smuzhiyun /* clear pending instances from ack list */
snd_timer_clear_callbacks(struct snd_timer * timer,struct list_head * head)804*4882a593Smuzhiyun static void snd_timer_clear_callbacks(struct snd_timer *timer,
805*4882a593Smuzhiyun struct list_head *head)
806*4882a593Smuzhiyun {
807*4882a593Smuzhiyun unsigned long flags;
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun spin_lock_irqsave(&timer->lock, flags);
810*4882a593Smuzhiyun while (!list_empty(head))
811*4882a593Smuzhiyun list_del_init(head->next);
812*4882a593Smuzhiyun spin_unlock_irqrestore(&timer->lock, flags);
813*4882a593Smuzhiyun }
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun /*
816*4882a593Smuzhiyun * timer work
817*4882a593Smuzhiyun *
818*4882a593Smuzhiyun */
snd_timer_work(struct work_struct * work)819*4882a593Smuzhiyun static void snd_timer_work(struct work_struct *work)
820*4882a593Smuzhiyun {
821*4882a593Smuzhiyun struct snd_timer *timer = container_of(work, struct snd_timer, task_work);
822*4882a593Smuzhiyun unsigned long flags;
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun if (timer->card && timer->card->shutdown) {
825*4882a593Smuzhiyun snd_timer_clear_callbacks(timer, &timer->sack_list_head);
826*4882a593Smuzhiyun return;
827*4882a593Smuzhiyun }
828*4882a593Smuzhiyun
829*4882a593Smuzhiyun spin_lock_irqsave(&timer->lock, flags);
830*4882a593Smuzhiyun snd_timer_process_callbacks(timer, &timer->sack_list_head);
831*4882a593Smuzhiyun spin_unlock_irqrestore(&timer->lock, flags);
832*4882a593Smuzhiyun }
833*4882a593Smuzhiyun
834*4882a593Smuzhiyun /*
835*4882a593Smuzhiyun * timer interrupt
836*4882a593Smuzhiyun *
837*4882a593Smuzhiyun * ticks_left is usually equal to timer->sticks.
838*4882a593Smuzhiyun *
839*4882a593Smuzhiyun */
snd_timer_interrupt(struct snd_timer * timer,unsigned long ticks_left)840*4882a593Smuzhiyun void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
841*4882a593Smuzhiyun {
842*4882a593Smuzhiyun struct snd_timer_instance *ti, *ts, *tmp;
843*4882a593Smuzhiyun unsigned long resolution;
844*4882a593Smuzhiyun struct list_head *ack_list_head;
845*4882a593Smuzhiyun unsigned long flags;
846*4882a593Smuzhiyun bool use_work = false;
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun if (timer == NULL)
849*4882a593Smuzhiyun return;
850*4882a593Smuzhiyun
851*4882a593Smuzhiyun if (timer->card && timer->card->shutdown) {
852*4882a593Smuzhiyun snd_timer_clear_callbacks(timer, &timer->ack_list_head);
853*4882a593Smuzhiyun return;
854*4882a593Smuzhiyun }
855*4882a593Smuzhiyun
856*4882a593Smuzhiyun spin_lock_irqsave(&timer->lock, flags);
857*4882a593Smuzhiyun
858*4882a593Smuzhiyun /* remember the current resolution */
859*4882a593Smuzhiyun resolution = snd_timer_hw_resolution(timer);
860*4882a593Smuzhiyun
861*4882a593Smuzhiyun /* loop for all active instances
862*4882a593Smuzhiyun * Here we cannot use list_for_each_entry because the active_list of a
863*4882a593Smuzhiyun * processed instance is relinked to done_list_head before the callback
864*4882a593Smuzhiyun * is called.
865*4882a593Smuzhiyun */
866*4882a593Smuzhiyun list_for_each_entry_safe(ti, tmp, &timer->active_list_head,
867*4882a593Smuzhiyun active_list) {
868*4882a593Smuzhiyun if (ti->flags & SNDRV_TIMER_IFLG_DEAD)
869*4882a593Smuzhiyun continue;
870*4882a593Smuzhiyun if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING))
871*4882a593Smuzhiyun continue;
872*4882a593Smuzhiyun ti->pticks += ticks_left;
873*4882a593Smuzhiyun ti->resolution = resolution;
874*4882a593Smuzhiyun if (ti->cticks < ticks_left)
875*4882a593Smuzhiyun ti->cticks = 0;
876*4882a593Smuzhiyun else
877*4882a593Smuzhiyun ti->cticks -= ticks_left;
878*4882a593Smuzhiyun if (ti->cticks) /* not expired */
879*4882a593Smuzhiyun continue;
880*4882a593Smuzhiyun if (ti->flags & SNDRV_TIMER_IFLG_AUTO) {
881*4882a593Smuzhiyun ti->cticks = ti->ticks;
882*4882a593Smuzhiyun } else {
883*4882a593Smuzhiyun ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
884*4882a593Smuzhiyun --timer->running;
885*4882a593Smuzhiyun list_del_init(&ti->active_list);
886*4882a593Smuzhiyun }
887*4882a593Smuzhiyun if ((timer->hw.flags & SNDRV_TIMER_HW_WORK) ||
888*4882a593Smuzhiyun (ti->flags & SNDRV_TIMER_IFLG_FAST))
889*4882a593Smuzhiyun ack_list_head = &timer->ack_list_head;
890*4882a593Smuzhiyun else
891*4882a593Smuzhiyun ack_list_head = &timer->sack_list_head;
892*4882a593Smuzhiyun if (list_empty(&ti->ack_list))
893*4882a593Smuzhiyun list_add_tail(&ti->ack_list, ack_list_head);
894*4882a593Smuzhiyun list_for_each_entry(ts, &ti->slave_active_head, active_list) {
895*4882a593Smuzhiyun ts->pticks = ti->pticks;
896*4882a593Smuzhiyun ts->resolution = resolution;
897*4882a593Smuzhiyun if (list_empty(&ts->ack_list))
898*4882a593Smuzhiyun list_add_tail(&ts->ack_list, ack_list_head);
899*4882a593Smuzhiyun }
900*4882a593Smuzhiyun }
901*4882a593Smuzhiyun if (timer->flags & SNDRV_TIMER_FLG_RESCHED)
902*4882a593Smuzhiyun snd_timer_reschedule(timer, timer->sticks);
903*4882a593Smuzhiyun if (timer->running) {
904*4882a593Smuzhiyun if (timer->hw.flags & SNDRV_TIMER_HW_STOP) {
905*4882a593Smuzhiyun timer->hw.stop(timer);
906*4882a593Smuzhiyun timer->flags |= SNDRV_TIMER_FLG_CHANGE;
907*4882a593Smuzhiyun }
908*4882a593Smuzhiyun if (!(timer->hw.flags & SNDRV_TIMER_HW_AUTO) ||
909*4882a593Smuzhiyun (timer->flags & SNDRV_TIMER_FLG_CHANGE)) {
910*4882a593Smuzhiyun /* restart timer */
911*4882a593Smuzhiyun timer->flags &= ~SNDRV_TIMER_FLG_CHANGE;
912*4882a593Smuzhiyun timer->hw.start(timer);
913*4882a593Smuzhiyun }
914*4882a593Smuzhiyun } else {
915*4882a593Smuzhiyun timer->hw.stop(timer);
916*4882a593Smuzhiyun }
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun /* now process all fast callbacks */
919*4882a593Smuzhiyun snd_timer_process_callbacks(timer, &timer->ack_list_head);
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun /* do we have any slow callbacks? */
922*4882a593Smuzhiyun use_work = !list_empty(&timer->sack_list_head);
923*4882a593Smuzhiyun spin_unlock_irqrestore(&timer->lock, flags);
924*4882a593Smuzhiyun
925*4882a593Smuzhiyun if (use_work)
926*4882a593Smuzhiyun queue_work(system_highpri_wq, &timer->task_work);
927*4882a593Smuzhiyun }
928*4882a593Smuzhiyun EXPORT_SYMBOL(snd_timer_interrupt);
929*4882a593Smuzhiyun
930*4882a593Smuzhiyun /*
931*4882a593Smuzhiyun
932*4882a593Smuzhiyun */
933*4882a593Smuzhiyun
snd_timer_new(struct snd_card * card,char * id,struct snd_timer_id * tid,struct snd_timer ** rtimer)934*4882a593Smuzhiyun int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
935*4882a593Smuzhiyun struct snd_timer **rtimer)
936*4882a593Smuzhiyun {
937*4882a593Smuzhiyun struct snd_timer *timer;
938*4882a593Smuzhiyun int err;
939*4882a593Smuzhiyun static const struct snd_device_ops ops = {
940*4882a593Smuzhiyun .dev_free = snd_timer_dev_free,
941*4882a593Smuzhiyun .dev_register = snd_timer_dev_register,
942*4882a593Smuzhiyun .dev_disconnect = snd_timer_dev_disconnect,
943*4882a593Smuzhiyun };
944*4882a593Smuzhiyun
945*4882a593Smuzhiyun if (snd_BUG_ON(!tid))
946*4882a593Smuzhiyun return -EINVAL;
947*4882a593Smuzhiyun if (tid->dev_class == SNDRV_TIMER_CLASS_CARD ||
948*4882a593Smuzhiyun tid->dev_class == SNDRV_TIMER_CLASS_PCM) {
949*4882a593Smuzhiyun if (WARN_ON(!card))
950*4882a593Smuzhiyun return -EINVAL;
951*4882a593Smuzhiyun }
952*4882a593Smuzhiyun if (rtimer)
953*4882a593Smuzhiyun *rtimer = NULL;
954*4882a593Smuzhiyun timer = kzalloc(sizeof(*timer), GFP_KERNEL);
955*4882a593Smuzhiyun if (!timer)
956*4882a593Smuzhiyun return -ENOMEM;
957*4882a593Smuzhiyun timer->tmr_class = tid->dev_class;
958*4882a593Smuzhiyun timer->card = card;
959*4882a593Smuzhiyun timer->tmr_device = tid->device;
960*4882a593Smuzhiyun timer->tmr_subdevice = tid->subdevice;
961*4882a593Smuzhiyun if (id)
962*4882a593Smuzhiyun strlcpy(timer->id, id, sizeof(timer->id));
963*4882a593Smuzhiyun timer->sticks = 1;
964*4882a593Smuzhiyun INIT_LIST_HEAD(&timer->device_list);
965*4882a593Smuzhiyun INIT_LIST_HEAD(&timer->open_list_head);
966*4882a593Smuzhiyun INIT_LIST_HEAD(&timer->active_list_head);
967*4882a593Smuzhiyun INIT_LIST_HEAD(&timer->ack_list_head);
968*4882a593Smuzhiyun INIT_LIST_HEAD(&timer->sack_list_head);
969*4882a593Smuzhiyun spin_lock_init(&timer->lock);
970*4882a593Smuzhiyun INIT_WORK(&timer->task_work, snd_timer_work);
971*4882a593Smuzhiyun timer->max_instances = 1000; /* default limit per timer */
972*4882a593Smuzhiyun if (card != NULL) {
973*4882a593Smuzhiyun timer->module = card->module;
974*4882a593Smuzhiyun err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops);
975*4882a593Smuzhiyun if (err < 0) {
976*4882a593Smuzhiyun snd_timer_free(timer);
977*4882a593Smuzhiyun return err;
978*4882a593Smuzhiyun }
979*4882a593Smuzhiyun }
980*4882a593Smuzhiyun if (rtimer)
981*4882a593Smuzhiyun *rtimer = timer;
982*4882a593Smuzhiyun return 0;
983*4882a593Smuzhiyun }
984*4882a593Smuzhiyun EXPORT_SYMBOL(snd_timer_new);
985*4882a593Smuzhiyun
snd_timer_free(struct snd_timer * timer)986*4882a593Smuzhiyun static int snd_timer_free(struct snd_timer *timer)
987*4882a593Smuzhiyun {
988*4882a593Smuzhiyun if (!timer)
989*4882a593Smuzhiyun return 0;
990*4882a593Smuzhiyun
991*4882a593Smuzhiyun mutex_lock(®ister_mutex);
992*4882a593Smuzhiyun if (! list_empty(&timer->open_list_head)) {
993*4882a593Smuzhiyun struct list_head *p, *n;
994*4882a593Smuzhiyun struct snd_timer_instance *ti;
995*4882a593Smuzhiyun pr_warn("ALSA: timer %p is busy?\n", timer);
996*4882a593Smuzhiyun list_for_each_safe(p, n, &timer->open_list_head) {
997*4882a593Smuzhiyun list_del_init(p);
998*4882a593Smuzhiyun ti = list_entry(p, struct snd_timer_instance, open_list);
999*4882a593Smuzhiyun ti->timer = NULL;
1000*4882a593Smuzhiyun }
1001*4882a593Smuzhiyun }
1002*4882a593Smuzhiyun list_del(&timer->device_list);
1003*4882a593Smuzhiyun mutex_unlock(®ister_mutex);
1004*4882a593Smuzhiyun
1005*4882a593Smuzhiyun if (timer->private_free)
1006*4882a593Smuzhiyun timer->private_free(timer);
1007*4882a593Smuzhiyun kfree(timer);
1008*4882a593Smuzhiyun return 0;
1009*4882a593Smuzhiyun }
1010*4882a593Smuzhiyun
snd_timer_dev_free(struct snd_device * device)1011*4882a593Smuzhiyun static int snd_timer_dev_free(struct snd_device *device)
1012*4882a593Smuzhiyun {
1013*4882a593Smuzhiyun struct snd_timer *timer = device->device_data;
1014*4882a593Smuzhiyun return snd_timer_free(timer);
1015*4882a593Smuzhiyun }
1016*4882a593Smuzhiyun
snd_timer_dev_register(struct snd_device * dev)1017*4882a593Smuzhiyun static int snd_timer_dev_register(struct snd_device *dev)
1018*4882a593Smuzhiyun {
1019*4882a593Smuzhiyun struct snd_timer *timer = dev->device_data;
1020*4882a593Smuzhiyun struct snd_timer *timer1;
1021*4882a593Smuzhiyun
1022*4882a593Smuzhiyun if (snd_BUG_ON(!timer || !timer->hw.start || !timer->hw.stop))
1023*4882a593Smuzhiyun return -ENXIO;
1024*4882a593Smuzhiyun if (!(timer->hw.flags & SNDRV_TIMER_HW_SLAVE) &&
1025*4882a593Smuzhiyun !timer->hw.resolution && timer->hw.c_resolution == NULL)
1026*4882a593Smuzhiyun return -EINVAL;
1027*4882a593Smuzhiyun
1028*4882a593Smuzhiyun mutex_lock(®ister_mutex);
1029*4882a593Smuzhiyun list_for_each_entry(timer1, &snd_timer_list, device_list) {
1030*4882a593Smuzhiyun if (timer1->tmr_class > timer->tmr_class)
1031*4882a593Smuzhiyun break;
1032*4882a593Smuzhiyun if (timer1->tmr_class < timer->tmr_class)
1033*4882a593Smuzhiyun continue;
1034*4882a593Smuzhiyun if (timer1->card && timer->card) {
1035*4882a593Smuzhiyun if (timer1->card->number > timer->card->number)
1036*4882a593Smuzhiyun break;
1037*4882a593Smuzhiyun if (timer1->card->number < timer->card->number)
1038*4882a593Smuzhiyun continue;
1039*4882a593Smuzhiyun }
1040*4882a593Smuzhiyun if (timer1->tmr_device > timer->tmr_device)
1041*4882a593Smuzhiyun break;
1042*4882a593Smuzhiyun if (timer1->tmr_device < timer->tmr_device)
1043*4882a593Smuzhiyun continue;
1044*4882a593Smuzhiyun if (timer1->tmr_subdevice > timer->tmr_subdevice)
1045*4882a593Smuzhiyun break;
1046*4882a593Smuzhiyun if (timer1->tmr_subdevice < timer->tmr_subdevice)
1047*4882a593Smuzhiyun continue;
1048*4882a593Smuzhiyun /* conflicts.. */
1049*4882a593Smuzhiyun mutex_unlock(®ister_mutex);
1050*4882a593Smuzhiyun return -EBUSY;
1051*4882a593Smuzhiyun }
1052*4882a593Smuzhiyun list_add_tail(&timer->device_list, &timer1->device_list);
1053*4882a593Smuzhiyun mutex_unlock(®ister_mutex);
1054*4882a593Smuzhiyun return 0;
1055*4882a593Smuzhiyun }
1056*4882a593Smuzhiyun
snd_timer_dev_disconnect(struct snd_device * device)1057*4882a593Smuzhiyun static int snd_timer_dev_disconnect(struct snd_device *device)
1058*4882a593Smuzhiyun {
1059*4882a593Smuzhiyun struct snd_timer *timer = device->device_data;
1060*4882a593Smuzhiyun struct snd_timer_instance *ti;
1061*4882a593Smuzhiyun
1062*4882a593Smuzhiyun mutex_lock(®ister_mutex);
1063*4882a593Smuzhiyun list_del_init(&timer->device_list);
1064*4882a593Smuzhiyun /* wake up pending sleepers */
1065*4882a593Smuzhiyun list_for_each_entry(ti, &timer->open_list_head, open_list) {
1066*4882a593Smuzhiyun if (ti->disconnect)
1067*4882a593Smuzhiyun ti->disconnect(ti);
1068*4882a593Smuzhiyun }
1069*4882a593Smuzhiyun mutex_unlock(®ister_mutex);
1070*4882a593Smuzhiyun return 0;
1071*4882a593Smuzhiyun }
1072*4882a593Smuzhiyun
snd_timer_notify(struct snd_timer * timer,int event,struct timespec64 * tstamp)1073*4882a593Smuzhiyun void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tstamp)
1074*4882a593Smuzhiyun {
1075*4882a593Smuzhiyun unsigned long flags;
1076*4882a593Smuzhiyun unsigned long resolution = 0;
1077*4882a593Smuzhiyun struct snd_timer_instance *ti, *ts;
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun if (timer->card && timer->card->shutdown)
1080*4882a593Smuzhiyun return;
1081*4882a593Smuzhiyun if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE))
1082*4882a593Smuzhiyun return;
1083*4882a593Smuzhiyun if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_MSTART ||
1084*4882a593Smuzhiyun event > SNDRV_TIMER_EVENT_MRESUME))
1085*4882a593Smuzhiyun return;
1086*4882a593Smuzhiyun spin_lock_irqsave(&timer->lock, flags);
1087*4882a593Smuzhiyun if (event == SNDRV_TIMER_EVENT_MSTART ||
1088*4882a593Smuzhiyun event == SNDRV_TIMER_EVENT_MCONTINUE ||
1089*4882a593Smuzhiyun event == SNDRV_TIMER_EVENT_MRESUME)
1090*4882a593Smuzhiyun resolution = snd_timer_hw_resolution(timer);
1091*4882a593Smuzhiyun list_for_each_entry(ti, &timer->active_list_head, active_list) {
1092*4882a593Smuzhiyun if (ti->ccallback)
1093*4882a593Smuzhiyun ti->ccallback(ti, event, tstamp, resolution);
1094*4882a593Smuzhiyun list_for_each_entry(ts, &ti->slave_active_head, active_list)
1095*4882a593Smuzhiyun if (ts->ccallback)
1096*4882a593Smuzhiyun ts->ccallback(ts, event, tstamp, resolution);
1097*4882a593Smuzhiyun }
1098*4882a593Smuzhiyun spin_unlock_irqrestore(&timer->lock, flags);
1099*4882a593Smuzhiyun }
1100*4882a593Smuzhiyun EXPORT_SYMBOL(snd_timer_notify);
1101*4882a593Smuzhiyun
1102*4882a593Smuzhiyun /*
1103*4882a593Smuzhiyun * exported functions for global timers
1104*4882a593Smuzhiyun */
snd_timer_global_new(char * id,int device,struct snd_timer ** rtimer)1105*4882a593Smuzhiyun int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer)
1106*4882a593Smuzhiyun {
1107*4882a593Smuzhiyun struct snd_timer_id tid;
1108*4882a593Smuzhiyun
1109*4882a593Smuzhiyun tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL;
1110*4882a593Smuzhiyun tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
1111*4882a593Smuzhiyun tid.card = -1;
1112*4882a593Smuzhiyun tid.device = device;
1113*4882a593Smuzhiyun tid.subdevice = 0;
1114*4882a593Smuzhiyun return snd_timer_new(NULL, id, &tid, rtimer);
1115*4882a593Smuzhiyun }
1116*4882a593Smuzhiyun EXPORT_SYMBOL(snd_timer_global_new);
1117*4882a593Smuzhiyun
snd_timer_global_free(struct snd_timer * timer)1118*4882a593Smuzhiyun int snd_timer_global_free(struct snd_timer *timer)
1119*4882a593Smuzhiyun {
1120*4882a593Smuzhiyun return snd_timer_free(timer);
1121*4882a593Smuzhiyun }
1122*4882a593Smuzhiyun EXPORT_SYMBOL(snd_timer_global_free);
1123*4882a593Smuzhiyun
snd_timer_global_register(struct snd_timer * timer)1124*4882a593Smuzhiyun int snd_timer_global_register(struct snd_timer *timer)
1125*4882a593Smuzhiyun {
1126*4882a593Smuzhiyun struct snd_device dev;
1127*4882a593Smuzhiyun
1128*4882a593Smuzhiyun memset(&dev, 0, sizeof(dev));
1129*4882a593Smuzhiyun dev.device_data = timer;
1130*4882a593Smuzhiyun return snd_timer_dev_register(&dev);
1131*4882a593Smuzhiyun }
1132*4882a593Smuzhiyun EXPORT_SYMBOL(snd_timer_global_register);
1133*4882a593Smuzhiyun
1134*4882a593Smuzhiyun /*
1135*4882a593Smuzhiyun * System timer
1136*4882a593Smuzhiyun */
1137*4882a593Smuzhiyun
1138*4882a593Smuzhiyun struct snd_timer_system_private {
1139*4882a593Smuzhiyun struct timer_list tlist;
1140*4882a593Smuzhiyun struct snd_timer *snd_timer;
1141*4882a593Smuzhiyun unsigned long last_expires;
1142*4882a593Smuzhiyun unsigned long last_jiffies;
1143*4882a593Smuzhiyun unsigned long correction;
1144*4882a593Smuzhiyun };
1145*4882a593Smuzhiyun
snd_timer_s_function(struct timer_list * t)1146*4882a593Smuzhiyun static void snd_timer_s_function(struct timer_list *t)
1147*4882a593Smuzhiyun {
1148*4882a593Smuzhiyun struct snd_timer_system_private *priv = from_timer(priv, t,
1149*4882a593Smuzhiyun tlist);
1150*4882a593Smuzhiyun struct snd_timer *timer = priv->snd_timer;
1151*4882a593Smuzhiyun unsigned long jiff = jiffies;
1152*4882a593Smuzhiyun if (time_after(jiff, priv->last_expires))
1153*4882a593Smuzhiyun priv->correction += (long)jiff - (long)priv->last_expires;
1154*4882a593Smuzhiyun snd_timer_interrupt(timer, (long)jiff - (long)priv->last_jiffies);
1155*4882a593Smuzhiyun }
1156*4882a593Smuzhiyun
snd_timer_s_start(struct snd_timer * timer)1157*4882a593Smuzhiyun static int snd_timer_s_start(struct snd_timer * timer)
1158*4882a593Smuzhiyun {
1159*4882a593Smuzhiyun struct snd_timer_system_private *priv;
1160*4882a593Smuzhiyun unsigned long njiff;
1161*4882a593Smuzhiyun
1162*4882a593Smuzhiyun priv = (struct snd_timer_system_private *) timer->private_data;
1163*4882a593Smuzhiyun njiff = (priv->last_jiffies = jiffies);
1164*4882a593Smuzhiyun if (priv->correction > timer->sticks - 1) {
1165*4882a593Smuzhiyun priv->correction -= timer->sticks - 1;
1166*4882a593Smuzhiyun njiff++;
1167*4882a593Smuzhiyun } else {
1168*4882a593Smuzhiyun njiff += timer->sticks - priv->correction;
1169*4882a593Smuzhiyun priv->correction = 0;
1170*4882a593Smuzhiyun }
1171*4882a593Smuzhiyun priv->last_expires = njiff;
1172*4882a593Smuzhiyun mod_timer(&priv->tlist, njiff);
1173*4882a593Smuzhiyun return 0;
1174*4882a593Smuzhiyun }
1175*4882a593Smuzhiyun
snd_timer_s_stop(struct snd_timer * timer)1176*4882a593Smuzhiyun static int snd_timer_s_stop(struct snd_timer * timer)
1177*4882a593Smuzhiyun {
1178*4882a593Smuzhiyun struct snd_timer_system_private *priv;
1179*4882a593Smuzhiyun unsigned long jiff;
1180*4882a593Smuzhiyun
1181*4882a593Smuzhiyun priv = (struct snd_timer_system_private *) timer->private_data;
1182*4882a593Smuzhiyun del_timer(&priv->tlist);
1183*4882a593Smuzhiyun jiff = jiffies;
1184*4882a593Smuzhiyun if (time_before(jiff, priv->last_expires))
1185*4882a593Smuzhiyun timer->sticks = priv->last_expires - jiff;
1186*4882a593Smuzhiyun else
1187*4882a593Smuzhiyun timer->sticks = 1;
1188*4882a593Smuzhiyun priv->correction = 0;
1189*4882a593Smuzhiyun return 0;
1190*4882a593Smuzhiyun }
1191*4882a593Smuzhiyun
snd_timer_s_close(struct snd_timer * timer)1192*4882a593Smuzhiyun static int snd_timer_s_close(struct snd_timer *timer)
1193*4882a593Smuzhiyun {
1194*4882a593Smuzhiyun struct snd_timer_system_private *priv;
1195*4882a593Smuzhiyun
1196*4882a593Smuzhiyun priv = (struct snd_timer_system_private *)timer->private_data;
1197*4882a593Smuzhiyun del_timer_sync(&priv->tlist);
1198*4882a593Smuzhiyun return 0;
1199*4882a593Smuzhiyun }
1200*4882a593Smuzhiyun
1201*4882a593Smuzhiyun static const struct snd_timer_hardware snd_timer_system =
1202*4882a593Smuzhiyun {
1203*4882a593Smuzhiyun .flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_WORK,
1204*4882a593Smuzhiyun .resolution = 1000000000L / HZ,
1205*4882a593Smuzhiyun .ticks = 10000000L,
1206*4882a593Smuzhiyun .close = snd_timer_s_close,
1207*4882a593Smuzhiyun .start = snd_timer_s_start,
1208*4882a593Smuzhiyun .stop = snd_timer_s_stop
1209*4882a593Smuzhiyun };
1210*4882a593Smuzhiyun
snd_timer_free_system(struct snd_timer * timer)1211*4882a593Smuzhiyun static void snd_timer_free_system(struct snd_timer *timer)
1212*4882a593Smuzhiyun {
1213*4882a593Smuzhiyun kfree(timer->private_data);
1214*4882a593Smuzhiyun }
1215*4882a593Smuzhiyun
snd_timer_register_system(void)1216*4882a593Smuzhiyun static int snd_timer_register_system(void)
1217*4882a593Smuzhiyun {
1218*4882a593Smuzhiyun struct snd_timer *timer;
1219*4882a593Smuzhiyun struct snd_timer_system_private *priv;
1220*4882a593Smuzhiyun int err;
1221*4882a593Smuzhiyun
1222*4882a593Smuzhiyun err = snd_timer_global_new("system", SNDRV_TIMER_GLOBAL_SYSTEM, &timer);
1223*4882a593Smuzhiyun if (err < 0)
1224*4882a593Smuzhiyun return err;
1225*4882a593Smuzhiyun strcpy(timer->name, "system timer");
1226*4882a593Smuzhiyun timer->hw = snd_timer_system;
1227*4882a593Smuzhiyun priv = kzalloc(sizeof(*priv), GFP_KERNEL);
1228*4882a593Smuzhiyun if (priv == NULL) {
1229*4882a593Smuzhiyun snd_timer_free(timer);
1230*4882a593Smuzhiyun return -ENOMEM;
1231*4882a593Smuzhiyun }
1232*4882a593Smuzhiyun priv->snd_timer = timer;
1233*4882a593Smuzhiyun timer_setup(&priv->tlist, snd_timer_s_function, 0);
1234*4882a593Smuzhiyun timer->private_data = priv;
1235*4882a593Smuzhiyun timer->private_free = snd_timer_free_system;
1236*4882a593Smuzhiyun return snd_timer_global_register(timer);
1237*4882a593Smuzhiyun }
1238*4882a593Smuzhiyun
1239*4882a593Smuzhiyun #ifdef CONFIG_SND_PROC_FS
1240*4882a593Smuzhiyun /*
1241*4882a593Smuzhiyun * Info interface
1242*4882a593Smuzhiyun */
1243*4882a593Smuzhiyun
snd_timer_proc_read(struct snd_info_entry * entry,struct snd_info_buffer * buffer)1244*4882a593Smuzhiyun static void snd_timer_proc_read(struct snd_info_entry *entry,
1245*4882a593Smuzhiyun struct snd_info_buffer *buffer)
1246*4882a593Smuzhiyun {
1247*4882a593Smuzhiyun struct snd_timer *timer;
1248*4882a593Smuzhiyun struct snd_timer_instance *ti;
1249*4882a593Smuzhiyun
1250*4882a593Smuzhiyun mutex_lock(®ister_mutex);
1251*4882a593Smuzhiyun list_for_each_entry(timer, &snd_timer_list, device_list) {
1252*4882a593Smuzhiyun if (timer->card && timer->card->shutdown)
1253*4882a593Smuzhiyun continue;
1254*4882a593Smuzhiyun switch (timer->tmr_class) {
1255*4882a593Smuzhiyun case SNDRV_TIMER_CLASS_GLOBAL:
1256*4882a593Smuzhiyun snd_iprintf(buffer, "G%i: ", timer->tmr_device);
1257*4882a593Smuzhiyun break;
1258*4882a593Smuzhiyun case SNDRV_TIMER_CLASS_CARD:
1259*4882a593Smuzhiyun snd_iprintf(buffer, "C%i-%i: ",
1260*4882a593Smuzhiyun timer->card->number, timer->tmr_device);
1261*4882a593Smuzhiyun break;
1262*4882a593Smuzhiyun case SNDRV_TIMER_CLASS_PCM:
1263*4882a593Smuzhiyun snd_iprintf(buffer, "P%i-%i-%i: ", timer->card->number,
1264*4882a593Smuzhiyun timer->tmr_device, timer->tmr_subdevice);
1265*4882a593Smuzhiyun break;
1266*4882a593Smuzhiyun default:
1267*4882a593Smuzhiyun snd_iprintf(buffer, "?%i-%i-%i-%i: ", timer->tmr_class,
1268*4882a593Smuzhiyun timer->card ? timer->card->number : -1,
1269*4882a593Smuzhiyun timer->tmr_device, timer->tmr_subdevice);
1270*4882a593Smuzhiyun }
1271*4882a593Smuzhiyun snd_iprintf(buffer, "%s :", timer->name);
1272*4882a593Smuzhiyun if (timer->hw.resolution)
1273*4882a593Smuzhiyun snd_iprintf(buffer, " %lu.%03luus (%lu ticks)",
1274*4882a593Smuzhiyun timer->hw.resolution / 1000,
1275*4882a593Smuzhiyun timer->hw.resolution % 1000,
1276*4882a593Smuzhiyun timer->hw.ticks);
1277*4882a593Smuzhiyun if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
1278*4882a593Smuzhiyun snd_iprintf(buffer, " SLAVE");
1279*4882a593Smuzhiyun snd_iprintf(buffer, "\n");
1280*4882a593Smuzhiyun list_for_each_entry(ti, &timer->open_list_head, open_list)
1281*4882a593Smuzhiyun snd_iprintf(buffer, " Client %s : %s\n",
1282*4882a593Smuzhiyun ti->owner ? ti->owner : "unknown",
1283*4882a593Smuzhiyun (ti->flags & (SNDRV_TIMER_IFLG_START |
1284*4882a593Smuzhiyun SNDRV_TIMER_IFLG_RUNNING))
1285*4882a593Smuzhiyun ? "running" : "stopped");
1286*4882a593Smuzhiyun }
1287*4882a593Smuzhiyun mutex_unlock(®ister_mutex);
1288*4882a593Smuzhiyun }
1289*4882a593Smuzhiyun
1290*4882a593Smuzhiyun static struct snd_info_entry *snd_timer_proc_entry;
1291*4882a593Smuzhiyun
snd_timer_proc_init(void)1292*4882a593Smuzhiyun static void __init snd_timer_proc_init(void)
1293*4882a593Smuzhiyun {
1294*4882a593Smuzhiyun struct snd_info_entry *entry;
1295*4882a593Smuzhiyun
1296*4882a593Smuzhiyun entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL);
1297*4882a593Smuzhiyun if (entry != NULL) {
1298*4882a593Smuzhiyun entry->c.text.read = snd_timer_proc_read;
1299*4882a593Smuzhiyun if (snd_info_register(entry) < 0) {
1300*4882a593Smuzhiyun snd_info_free_entry(entry);
1301*4882a593Smuzhiyun entry = NULL;
1302*4882a593Smuzhiyun }
1303*4882a593Smuzhiyun }
1304*4882a593Smuzhiyun snd_timer_proc_entry = entry;
1305*4882a593Smuzhiyun }
1306*4882a593Smuzhiyun
snd_timer_proc_done(void)1307*4882a593Smuzhiyun static void __exit snd_timer_proc_done(void)
1308*4882a593Smuzhiyun {
1309*4882a593Smuzhiyun snd_info_free_entry(snd_timer_proc_entry);
1310*4882a593Smuzhiyun }
1311*4882a593Smuzhiyun #else /* !CONFIG_SND_PROC_FS */
1312*4882a593Smuzhiyun #define snd_timer_proc_init()
1313*4882a593Smuzhiyun #define snd_timer_proc_done()
1314*4882a593Smuzhiyun #endif
1315*4882a593Smuzhiyun
1316*4882a593Smuzhiyun /*
1317*4882a593Smuzhiyun * USER SPACE interface
1318*4882a593Smuzhiyun */
1319*4882a593Smuzhiyun
snd_timer_user_interrupt(struct snd_timer_instance * timeri,unsigned long resolution,unsigned long ticks)1320*4882a593Smuzhiyun static void snd_timer_user_interrupt(struct snd_timer_instance *timeri,
1321*4882a593Smuzhiyun unsigned long resolution,
1322*4882a593Smuzhiyun unsigned long ticks)
1323*4882a593Smuzhiyun {
1324*4882a593Smuzhiyun struct snd_timer_user *tu = timeri->callback_data;
1325*4882a593Smuzhiyun struct snd_timer_read *r;
1326*4882a593Smuzhiyun int prev;
1327*4882a593Smuzhiyun
1328*4882a593Smuzhiyun spin_lock(&tu->qlock);
1329*4882a593Smuzhiyun if (tu->qused > 0) {
1330*4882a593Smuzhiyun prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
1331*4882a593Smuzhiyun r = &tu->queue[prev];
1332*4882a593Smuzhiyun if (r->resolution == resolution) {
1333*4882a593Smuzhiyun r->ticks += ticks;
1334*4882a593Smuzhiyun goto __wake;
1335*4882a593Smuzhiyun }
1336*4882a593Smuzhiyun }
1337*4882a593Smuzhiyun if (tu->qused >= tu->queue_size) {
1338*4882a593Smuzhiyun tu->overrun++;
1339*4882a593Smuzhiyun } else {
1340*4882a593Smuzhiyun r = &tu->queue[tu->qtail++];
1341*4882a593Smuzhiyun tu->qtail %= tu->queue_size;
1342*4882a593Smuzhiyun r->resolution = resolution;
1343*4882a593Smuzhiyun r->ticks = ticks;
1344*4882a593Smuzhiyun tu->qused++;
1345*4882a593Smuzhiyun }
1346*4882a593Smuzhiyun __wake:
1347*4882a593Smuzhiyun spin_unlock(&tu->qlock);
1348*4882a593Smuzhiyun snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
1349*4882a593Smuzhiyun wake_up(&tu->qchange_sleep);
1350*4882a593Smuzhiyun }
1351*4882a593Smuzhiyun
snd_timer_user_append_to_tqueue(struct snd_timer_user * tu,struct snd_timer_tread64 * tread)1352*4882a593Smuzhiyun static void snd_timer_user_append_to_tqueue(struct snd_timer_user *tu,
1353*4882a593Smuzhiyun struct snd_timer_tread64 *tread)
1354*4882a593Smuzhiyun {
1355*4882a593Smuzhiyun if (tu->qused >= tu->queue_size) {
1356*4882a593Smuzhiyun tu->overrun++;
1357*4882a593Smuzhiyun } else {
1358*4882a593Smuzhiyun memcpy(&tu->tqueue[tu->qtail++], tread, sizeof(*tread));
1359*4882a593Smuzhiyun tu->qtail %= tu->queue_size;
1360*4882a593Smuzhiyun tu->qused++;
1361*4882a593Smuzhiyun }
1362*4882a593Smuzhiyun }
1363*4882a593Smuzhiyun
snd_timer_user_ccallback(struct snd_timer_instance * timeri,int event,struct timespec64 * tstamp,unsigned long resolution)1364*4882a593Smuzhiyun static void snd_timer_user_ccallback(struct snd_timer_instance *timeri,
1365*4882a593Smuzhiyun int event,
1366*4882a593Smuzhiyun struct timespec64 *tstamp,
1367*4882a593Smuzhiyun unsigned long resolution)
1368*4882a593Smuzhiyun {
1369*4882a593Smuzhiyun struct snd_timer_user *tu = timeri->callback_data;
1370*4882a593Smuzhiyun struct snd_timer_tread64 r1;
1371*4882a593Smuzhiyun unsigned long flags;
1372*4882a593Smuzhiyun
1373*4882a593Smuzhiyun if (event >= SNDRV_TIMER_EVENT_START &&
1374*4882a593Smuzhiyun event <= SNDRV_TIMER_EVENT_PAUSE)
1375*4882a593Smuzhiyun tu->tstamp = *tstamp;
1376*4882a593Smuzhiyun if ((tu->filter & (1 << event)) == 0 || !tu->tread)
1377*4882a593Smuzhiyun return;
1378*4882a593Smuzhiyun memset(&r1, 0, sizeof(r1));
1379*4882a593Smuzhiyun r1.event = event;
1380*4882a593Smuzhiyun r1.tstamp_sec = tstamp->tv_sec;
1381*4882a593Smuzhiyun r1.tstamp_nsec = tstamp->tv_nsec;
1382*4882a593Smuzhiyun r1.val = resolution;
1383*4882a593Smuzhiyun spin_lock_irqsave(&tu->qlock, flags);
1384*4882a593Smuzhiyun snd_timer_user_append_to_tqueue(tu, &r1);
1385*4882a593Smuzhiyun spin_unlock_irqrestore(&tu->qlock, flags);
1386*4882a593Smuzhiyun snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
1387*4882a593Smuzhiyun wake_up(&tu->qchange_sleep);
1388*4882a593Smuzhiyun }
1389*4882a593Smuzhiyun
snd_timer_user_disconnect(struct snd_timer_instance * timeri)1390*4882a593Smuzhiyun static void snd_timer_user_disconnect(struct snd_timer_instance *timeri)
1391*4882a593Smuzhiyun {
1392*4882a593Smuzhiyun struct snd_timer_user *tu = timeri->callback_data;
1393*4882a593Smuzhiyun
1394*4882a593Smuzhiyun tu->disconnected = true;
1395*4882a593Smuzhiyun wake_up(&tu->qchange_sleep);
1396*4882a593Smuzhiyun }
1397*4882a593Smuzhiyun
snd_timer_user_tinterrupt(struct snd_timer_instance * timeri,unsigned long resolution,unsigned long ticks)1398*4882a593Smuzhiyun static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,
1399*4882a593Smuzhiyun unsigned long resolution,
1400*4882a593Smuzhiyun unsigned long ticks)
1401*4882a593Smuzhiyun {
1402*4882a593Smuzhiyun struct snd_timer_user *tu = timeri->callback_data;
1403*4882a593Smuzhiyun struct snd_timer_tread64 *r, r1;
1404*4882a593Smuzhiyun struct timespec64 tstamp;
1405*4882a593Smuzhiyun int prev, append = 0;
1406*4882a593Smuzhiyun
1407*4882a593Smuzhiyun memset(&r1, 0, sizeof(r1));
1408*4882a593Smuzhiyun memset(&tstamp, 0, sizeof(tstamp));
1409*4882a593Smuzhiyun spin_lock(&tu->qlock);
1410*4882a593Smuzhiyun if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) |
1411*4882a593Smuzhiyun (1 << SNDRV_TIMER_EVENT_TICK))) == 0) {
1412*4882a593Smuzhiyun spin_unlock(&tu->qlock);
1413*4882a593Smuzhiyun return;
1414*4882a593Smuzhiyun }
1415*4882a593Smuzhiyun if (tu->last_resolution != resolution || ticks > 0) {
1416*4882a593Smuzhiyun if (timer_tstamp_monotonic)
1417*4882a593Smuzhiyun ktime_get_ts64(&tstamp);
1418*4882a593Smuzhiyun else
1419*4882a593Smuzhiyun ktime_get_real_ts64(&tstamp);
1420*4882a593Smuzhiyun }
1421*4882a593Smuzhiyun if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) &&
1422*4882a593Smuzhiyun tu->last_resolution != resolution) {
1423*4882a593Smuzhiyun r1.event = SNDRV_TIMER_EVENT_RESOLUTION;
1424*4882a593Smuzhiyun r1.tstamp_sec = tstamp.tv_sec;
1425*4882a593Smuzhiyun r1.tstamp_nsec = tstamp.tv_nsec;
1426*4882a593Smuzhiyun r1.val = resolution;
1427*4882a593Smuzhiyun snd_timer_user_append_to_tqueue(tu, &r1);
1428*4882a593Smuzhiyun tu->last_resolution = resolution;
1429*4882a593Smuzhiyun append++;
1430*4882a593Smuzhiyun }
1431*4882a593Smuzhiyun if ((tu->filter & (1 << SNDRV_TIMER_EVENT_TICK)) == 0)
1432*4882a593Smuzhiyun goto __wake;
1433*4882a593Smuzhiyun if (ticks == 0)
1434*4882a593Smuzhiyun goto __wake;
1435*4882a593Smuzhiyun if (tu->qused > 0) {
1436*4882a593Smuzhiyun prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
1437*4882a593Smuzhiyun r = &tu->tqueue[prev];
1438*4882a593Smuzhiyun if (r->event == SNDRV_TIMER_EVENT_TICK) {
1439*4882a593Smuzhiyun r->tstamp_sec = tstamp.tv_sec;
1440*4882a593Smuzhiyun r->tstamp_nsec = tstamp.tv_nsec;
1441*4882a593Smuzhiyun r->val += ticks;
1442*4882a593Smuzhiyun append++;
1443*4882a593Smuzhiyun goto __wake;
1444*4882a593Smuzhiyun }
1445*4882a593Smuzhiyun }
1446*4882a593Smuzhiyun r1.event = SNDRV_TIMER_EVENT_TICK;
1447*4882a593Smuzhiyun r1.tstamp_sec = tstamp.tv_sec;
1448*4882a593Smuzhiyun r1.tstamp_nsec = tstamp.tv_nsec;
1449*4882a593Smuzhiyun r1.val = ticks;
1450*4882a593Smuzhiyun snd_timer_user_append_to_tqueue(tu, &r1);
1451*4882a593Smuzhiyun append++;
1452*4882a593Smuzhiyun __wake:
1453*4882a593Smuzhiyun spin_unlock(&tu->qlock);
1454*4882a593Smuzhiyun if (append == 0)
1455*4882a593Smuzhiyun return;
1456*4882a593Smuzhiyun snd_kill_fasync(tu->fasync, SIGIO, POLL_IN);
1457*4882a593Smuzhiyun wake_up(&tu->qchange_sleep);
1458*4882a593Smuzhiyun }
1459*4882a593Smuzhiyun
realloc_user_queue(struct snd_timer_user * tu,int size)1460*4882a593Smuzhiyun static int realloc_user_queue(struct snd_timer_user *tu, int size)
1461*4882a593Smuzhiyun {
1462*4882a593Smuzhiyun struct snd_timer_read *queue = NULL;
1463*4882a593Smuzhiyun struct snd_timer_tread64 *tqueue = NULL;
1464*4882a593Smuzhiyun
1465*4882a593Smuzhiyun if (tu->tread) {
1466*4882a593Smuzhiyun tqueue = kcalloc(size, sizeof(*tqueue), GFP_KERNEL);
1467*4882a593Smuzhiyun if (!tqueue)
1468*4882a593Smuzhiyun return -ENOMEM;
1469*4882a593Smuzhiyun } else {
1470*4882a593Smuzhiyun queue = kcalloc(size, sizeof(*queue), GFP_KERNEL);
1471*4882a593Smuzhiyun if (!queue)
1472*4882a593Smuzhiyun return -ENOMEM;
1473*4882a593Smuzhiyun }
1474*4882a593Smuzhiyun
1475*4882a593Smuzhiyun spin_lock_irq(&tu->qlock);
1476*4882a593Smuzhiyun kfree(tu->queue);
1477*4882a593Smuzhiyun kfree(tu->tqueue);
1478*4882a593Smuzhiyun tu->queue_size = size;
1479*4882a593Smuzhiyun tu->queue = queue;
1480*4882a593Smuzhiyun tu->tqueue = tqueue;
1481*4882a593Smuzhiyun tu->qhead = tu->qtail = tu->qused = 0;
1482*4882a593Smuzhiyun spin_unlock_irq(&tu->qlock);
1483*4882a593Smuzhiyun
1484*4882a593Smuzhiyun return 0;
1485*4882a593Smuzhiyun }
1486*4882a593Smuzhiyun
snd_timer_user_open(struct inode * inode,struct file * file)1487*4882a593Smuzhiyun static int snd_timer_user_open(struct inode *inode, struct file *file)
1488*4882a593Smuzhiyun {
1489*4882a593Smuzhiyun struct snd_timer_user *tu;
1490*4882a593Smuzhiyun int err;
1491*4882a593Smuzhiyun
1492*4882a593Smuzhiyun err = stream_open(inode, file);
1493*4882a593Smuzhiyun if (err < 0)
1494*4882a593Smuzhiyun return err;
1495*4882a593Smuzhiyun
1496*4882a593Smuzhiyun tu = kzalloc(sizeof(*tu), GFP_KERNEL);
1497*4882a593Smuzhiyun if (tu == NULL)
1498*4882a593Smuzhiyun return -ENOMEM;
1499*4882a593Smuzhiyun spin_lock_init(&tu->qlock);
1500*4882a593Smuzhiyun init_waitqueue_head(&tu->qchange_sleep);
1501*4882a593Smuzhiyun mutex_init(&tu->ioctl_lock);
1502*4882a593Smuzhiyun tu->ticks = 1;
1503*4882a593Smuzhiyun if (realloc_user_queue(tu, 128) < 0) {
1504*4882a593Smuzhiyun kfree(tu);
1505*4882a593Smuzhiyun return -ENOMEM;
1506*4882a593Smuzhiyun }
1507*4882a593Smuzhiyun file->private_data = tu;
1508*4882a593Smuzhiyun return 0;
1509*4882a593Smuzhiyun }
1510*4882a593Smuzhiyun
snd_timer_user_release(struct inode * inode,struct file * file)1511*4882a593Smuzhiyun static int snd_timer_user_release(struct inode *inode, struct file *file)
1512*4882a593Smuzhiyun {
1513*4882a593Smuzhiyun struct snd_timer_user *tu;
1514*4882a593Smuzhiyun
1515*4882a593Smuzhiyun if (file->private_data) {
1516*4882a593Smuzhiyun tu = file->private_data;
1517*4882a593Smuzhiyun file->private_data = NULL;
1518*4882a593Smuzhiyun mutex_lock(&tu->ioctl_lock);
1519*4882a593Smuzhiyun if (tu->timeri) {
1520*4882a593Smuzhiyun snd_timer_close(tu->timeri);
1521*4882a593Smuzhiyun snd_timer_instance_free(tu->timeri);
1522*4882a593Smuzhiyun }
1523*4882a593Smuzhiyun mutex_unlock(&tu->ioctl_lock);
1524*4882a593Smuzhiyun snd_fasync_free(tu->fasync);
1525*4882a593Smuzhiyun kfree(tu->queue);
1526*4882a593Smuzhiyun kfree(tu->tqueue);
1527*4882a593Smuzhiyun kfree(tu);
1528*4882a593Smuzhiyun }
1529*4882a593Smuzhiyun return 0;
1530*4882a593Smuzhiyun }
1531*4882a593Smuzhiyun
snd_timer_user_zero_id(struct snd_timer_id * id)1532*4882a593Smuzhiyun static void snd_timer_user_zero_id(struct snd_timer_id *id)
1533*4882a593Smuzhiyun {
1534*4882a593Smuzhiyun id->dev_class = SNDRV_TIMER_CLASS_NONE;
1535*4882a593Smuzhiyun id->dev_sclass = SNDRV_TIMER_SCLASS_NONE;
1536*4882a593Smuzhiyun id->card = -1;
1537*4882a593Smuzhiyun id->device = -1;
1538*4882a593Smuzhiyun id->subdevice = -1;
1539*4882a593Smuzhiyun }
1540*4882a593Smuzhiyun
snd_timer_user_copy_id(struct snd_timer_id * id,struct snd_timer * timer)1541*4882a593Smuzhiyun static void snd_timer_user_copy_id(struct snd_timer_id *id, struct snd_timer *timer)
1542*4882a593Smuzhiyun {
1543*4882a593Smuzhiyun id->dev_class = timer->tmr_class;
1544*4882a593Smuzhiyun id->dev_sclass = SNDRV_TIMER_SCLASS_NONE;
1545*4882a593Smuzhiyun id->card = timer->card ? timer->card->number : -1;
1546*4882a593Smuzhiyun id->device = timer->tmr_device;
1547*4882a593Smuzhiyun id->subdevice = timer->tmr_subdevice;
1548*4882a593Smuzhiyun }
1549*4882a593Smuzhiyun
snd_timer_user_next_device(struct snd_timer_id __user * _tid)1550*4882a593Smuzhiyun static int snd_timer_user_next_device(struct snd_timer_id __user *_tid)
1551*4882a593Smuzhiyun {
1552*4882a593Smuzhiyun struct snd_timer_id id;
1553*4882a593Smuzhiyun struct snd_timer *timer;
1554*4882a593Smuzhiyun struct list_head *p;
1555*4882a593Smuzhiyun
1556*4882a593Smuzhiyun if (copy_from_user(&id, _tid, sizeof(id)))
1557*4882a593Smuzhiyun return -EFAULT;
1558*4882a593Smuzhiyun mutex_lock(®ister_mutex);
1559*4882a593Smuzhiyun if (id.dev_class < 0) { /* first item */
1560*4882a593Smuzhiyun if (list_empty(&snd_timer_list))
1561*4882a593Smuzhiyun snd_timer_user_zero_id(&id);
1562*4882a593Smuzhiyun else {
1563*4882a593Smuzhiyun timer = list_entry(snd_timer_list.next,
1564*4882a593Smuzhiyun struct snd_timer, device_list);
1565*4882a593Smuzhiyun snd_timer_user_copy_id(&id, timer);
1566*4882a593Smuzhiyun }
1567*4882a593Smuzhiyun } else {
1568*4882a593Smuzhiyun switch (id.dev_class) {
1569*4882a593Smuzhiyun case SNDRV_TIMER_CLASS_GLOBAL:
1570*4882a593Smuzhiyun id.device = id.device < 0 ? 0 : id.device + 1;
1571*4882a593Smuzhiyun list_for_each(p, &snd_timer_list) {
1572*4882a593Smuzhiyun timer = list_entry(p, struct snd_timer, device_list);
1573*4882a593Smuzhiyun if (timer->tmr_class > SNDRV_TIMER_CLASS_GLOBAL) {
1574*4882a593Smuzhiyun snd_timer_user_copy_id(&id, timer);
1575*4882a593Smuzhiyun break;
1576*4882a593Smuzhiyun }
1577*4882a593Smuzhiyun if (timer->tmr_device >= id.device) {
1578*4882a593Smuzhiyun snd_timer_user_copy_id(&id, timer);
1579*4882a593Smuzhiyun break;
1580*4882a593Smuzhiyun }
1581*4882a593Smuzhiyun }
1582*4882a593Smuzhiyun if (p == &snd_timer_list)
1583*4882a593Smuzhiyun snd_timer_user_zero_id(&id);
1584*4882a593Smuzhiyun break;
1585*4882a593Smuzhiyun case SNDRV_TIMER_CLASS_CARD:
1586*4882a593Smuzhiyun case SNDRV_TIMER_CLASS_PCM:
1587*4882a593Smuzhiyun if (id.card < 0) {
1588*4882a593Smuzhiyun id.card = 0;
1589*4882a593Smuzhiyun } else {
1590*4882a593Smuzhiyun if (id.device < 0) {
1591*4882a593Smuzhiyun id.device = 0;
1592*4882a593Smuzhiyun } else {
1593*4882a593Smuzhiyun if (id.subdevice < 0)
1594*4882a593Smuzhiyun id.subdevice = 0;
1595*4882a593Smuzhiyun else if (id.subdevice < INT_MAX)
1596*4882a593Smuzhiyun id.subdevice++;
1597*4882a593Smuzhiyun }
1598*4882a593Smuzhiyun }
1599*4882a593Smuzhiyun list_for_each(p, &snd_timer_list) {
1600*4882a593Smuzhiyun timer = list_entry(p, struct snd_timer, device_list);
1601*4882a593Smuzhiyun if (timer->tmr_class > id.dev_class) {
1602*4882a593Smuzhiyun snd_timer_user_copy_id(&id, timer);
1603*4882a593Smuzhiyun break;
1604*4882a593Smuzhiyun }
1605*4882a593Smuzhiyun if (timer->tmr_class < id.dev_class)
1606*4882a593Smuzhiyun continue;
1607*4882a593Smuzhiyun if (timer->card->number > id.card) {
1608*4882a593Smuzhiyun snd_timer_user_copy_id(&id, timer);
1609*4882a593Smuzhiyun break;
1610*4882a593Smuzhiyun }
1611*4882a593Smuzhiyun if (timer->card->number < id.card)
1612*4882a593Smuzhiyun continue;
1613*4882a593Smuzhiyun if (timer->tmr_device > id.device) {
1614*4882a593Smuzhiyun snd_timer_user_copy_id(&id, timer);
1615*4882a593Smuzhiyun break;
1616*4882a593Smuzhiyun }
1617*4882a593Smuzhiyun if (timer->tmr_device < id.device)
1618*4882a593Smuzhiyun continue;
1619*4882a593Smuzhiyun if (timer->tmr_subdevice > id.subdevice) {
1620*4882a593Smuzhiyun snd_timer_user_copy_id(&id, timer);
1621*4882a593Smuzhiyun break;
1622*4882a593Smuzhiyun }
1623*4882a593Smuzhiyun if (timer->tmr_subdevice < id.subdevice)
1624*4882a593Smuzhiyun continue;
1625*4882a593Smuzhiyun snd_timer_user_copy_id(&id, timer);
1626*4882a593Smuzhiyun break;
1627*4882a593Smuzhiyun }
1628*4882a593Smuzhiyun if (p == &snd_timer_list)
1629*4882a593Smuzhiyun snd_timer_user_zero_id(&id);
1630*4882a593Smuzhiyun break;
1631*4882a593Smuzhiyun default:
1632*4882a593Smuzhiyun snd_timer_user_zero_id(&id);
1633*4882a593Smuzhiyun }
1634*4882a593Smuzhiyun }
1635*4882a593Smuzhiyun mutex_unlock(®ister_mutex);
1636*4882a593Smuzhiyun if (copy_to_user(_tid, &id, sizeof(*_tid)))
1637*4882a593Smuzhiyun return -EFAULT;
1638*4882a593Smuzhiyun return 0;
1639*4882a593Smuzhiyun }
1640*4882a593Smuzhiyun
snd_timer_user_ginfo(struct file * file,struct snd_timer_ginfo __user * _ginfo)1641*4882a593Smuzhiyun static int snd_timer_user_ginfo(struct file *file,
1642*4882a593Smuzhiyun struct snd_timer_ginfo __user *_ginfo)
1643*4882a593Smuzhiyun {
1644*4882a593Smuzhiyun struct snd_timer_ginfo *ginfo;
1645*4882a593Smuzhiyun struct snd_timer_id tid;
1646*4882a593Smuzhiyun struct snd_timer *t;
1647*4882a593Smuzhiyun struct list_head *p;
1648*4882a593Smuzhiyun int err = 0;
1649*4882a593Smuzhiyun
1650*4882a593Smuzhiyun ginfo = memdup_user(_ginfo, sizeof(*ginfo));
1651*4882a593Smuzhiyun if (IS_ERR(ginfo))
1652*4882a593Smuzhiyun return PTR_ERR(ginfo);
1653*4882a593Smuzhiyun
1654*4882a593Smuzhiyun tid = ginfo->tid;
1655*4882a593Smuzhiyun memset(ginfo, 0, sizeof(*ginfo));
1656*4882a593Smuzhiyun ginfo->tid = tid;
1657*4882a593Smuzhiyun mutex_lock(®ister_mutex);
1658*4882a593Smuzhiyun t = snd_timer_find(&tid);
1659*4882a593Smuzhiyun if (t != NULL) {
1660*4882a593Smuzhiyun ginfo->card = t->card ? t->card->number : -1;
1661*4882a593Smuzhiyun if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
1662*4882a593Smuzhiyun ginfo->flags |= SNDRV_TIMER_FLG_SLAVE;
1663*4882a593Smuzhiyun strlcpy(ginfo->id, t->id, sizeof(ginfo->id));
1664*4882a593Smuzhiyun strlcpy(ginfo->name, t->name, sizeof(ginfo->name));
1665*4882a593Smuzhiyun ginfo->resolution = t->hw.resolution;
1666*4882a593Smuzhiyun if (t->hw.resolution_min > 0) {
1667*4882a593Smuzhiyun ginfo->resolution_min = t->hw.resolution_min;
1668*4882a593Smuzhiyun ginfo->resolution_max = t->hw.resolution_max;
1669*4882a593Smuzhiyun }
1670*4882a593Smuzhiyun list_for_each(p, &t->open_list_head) {
1671*4882a593Smuzhiyun ginfo->clients++;
1672*4882a593Smuzhiyun }
1673*4882a593Smuzhiyun } else {
1674*4882a593Smuzhiyun err = -ENODEV;
1675*4882a593Smuzhiyun }
1676*4882a593Smuzhiyun mutex_unlock(®ister_mutex);
1677*4882a593Smuzhiyun if (err >= 0 && copy_to_user(_ginfo, ginfo, sizeof(*ginfo)))
1678*4882a593Smuzhiyun err = -EFAULT;
1679*4882a593Smuzhiyun kfree(ginfo);
1680*4882a593Smuzhiyun return err;
1681*4882a593Smuzhiyun }
1682*4882a593Smuzhiyun
timer_set_gparams(struct snd_timer_gparams * gparams)1683*4882a593Smuzhiyun static int timer_set_gparams(struct snd_timer_gparams *gparams)
1684*4882a593Smuzhiyun {
1685*4882a593Smuzhiyun struct snd_timer *t;
1686*4882a593Smuzhiyun int err;
1687*4882a593Smuzhiyun
1688*4882a593Smuzhiyun mutex_lock(®ister_mutex);
1689*4882a593Smuzhiyun t = snd_timer_find(&gparams->tid);
1690*4882a593Smuzhiyun if (!t) {
1691*4882a593Smuzhiyun err = -ENODEV;
1692*4882a593Smuzhiyun goto _error;
1693*4882a593Smuzhiyun }
1694*4882a593Smuzhiyun if (!list_empty(&t->open_list_head)) {
1695*4882a593Smuzhiyun err = -EBUSY;
1696*4882a593Smuzhiyun goto _error;
1697*4882a593Smuzhiyun }
1698*4882a593Smuzhiyun if (!t->hw.set_period) {
1699*4882a593Smuzhiyun err = -ENOSYS;
1700*4882a593Smuzhiyun goto _error;
1701*4882a593Smuzhiyun }
1702*4882a593Smuzhiyun err = t->hw.set_period(t, gparams->period_num, gparams->period_den);
1703*4882a593Smuzhiyun _error:
1704*4882a593Smuzhiyun mutex_unlock(®ister_mutex);
1705*4882a593Smuzhiyun return err;
1706*4882a593Smuzhiyun }
1707*4882a593Smuzhiyun
snd_timer_user_gparams(struct file * file,struct snd_timer_gparams __user * _gparams)1708*4882a593Smuzhiyun static int snd_timer_user_gparams(struct file *file,
1709*4882a593Smuzhiyun struct snd_timer_gparams __user *_gparams)
1710*4882a593Smuzhiyun {
1711*4882a593Smuzhiyun struct snd_timer_gparams gparams;
1712*4882a593Smuzhiyun
1713*4882a593Smuzhiyun if (copy_from_user(&gparams, _gparams, sizeof(gparams)))
1714*4882a593Smuzhiyun return -EFAULT;
1715*4882a593Smuzhiyun return timer_set_gparams(&gparams);
1716*4882a593Smuzhiyun }
1717*4882a593Smuzhiyun
snd_timer_user_gstatus(struct file * file,struct snd_timer_gstatus __user * _gstatus)1718*4882a593Smuzhiyun static int snd_timer_user_gstatus(struct file *file,
1719*4882a593Smuzhiyun struct snd_timer_gstatus __user *_gstatus)
1720*4882a593Smuzhiyun {
1721*4882a593Smuzhiyun struct snd_timer_gstatus gstatus;
1722*4882a593Smuzhiyun struct snd_timer_id tid;
1723*4882a593Smuzhiyun struct snd_timer *t;
1724*4882a593Smuzhiyun int err = 0;
1725*4882a593Smuzhiyun
1726*4882a593Smuzhiyun if (copy_from_user(&gstatus, _gstatus, sizeof(gstatus)))
1727*4882a593Smuzhiyun return -EFAULT;
1728*4882a593Smuzhiyun tid = gstatus.tid;
1729*4882a593Smuzhiyun memset(&gstatus, 0, sizeof(gstatus));
1730*4882a593Smuzhiyun gstatus.tid = tid;
1731*4882a593Smuzhiyun mutex_lock(®ister_mutex);
1732*4882a593Smuzhiyun t = snd_timer_find(&tid);
1733*4882a593Smuzhiyun if (t != NULL) {
1734*4882a593Smuzhiyun spin_lock_irq(&t->lock);
1735*4882a593Smuzhiyun gstatus.resolution = snd_timer_hw_resolution(t);
1736*4882a593Smuzhiyun if (t->hw.precise_resolution) {
1737*4882a593Smuzhiyun t->hw.precise_resolution(t, &gstatus.resolution_num,
1738*4882a593Smuzhiyun &gstatus.resolution_den);
1739*4882a593Smuzhiyun } else {
1740*4882a593Smuzhiyun gstatus.resolution_num = gstatus.resolution;
1741*4882a593Smuzhiyun gstatus.resolution_den = 1000000000uL;
1742*4882a593Smuzhiyun }
1743*4882a593Smuzhiyun spin_unlock_irq(&t->lock);
1744*4882a593Smuzhiyun } else {
1745*4882a593Smuzhiyun err = -ENODEV;
1746*4882a593Smuzhiyun }
1747*4882a593Smuzhiyun mutex_unlock(®ister_mutex);
1748*4882a593Smuzhiyun if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus)))
1749*4882a593Smuzhiyun err = -EFAULT;
1750*4882a593Smuzhiyun return err;
1751*4882a593Smuzhiyun }
1752*4882a593Smuzhiyun
snd_timer_user_tselect(struct file * file,struct snd_timer_select __user * _tselect)1753*4882a593Smuzhiyun static int snd_timer_user_tselect(struct file *file,
1754*4882a593Smuzhiyun struct snd_timer_select __user *_tselect)
1755*4882a593Smuzhiyun {
1756*4882a593Smuzhiyun struct snd_timer_user *tu;
1757*4882a593Smuzhiyun struct snd_timer_select tselect;
1758*4882a593Smuzhiyun char str[32];
1759*4882a593Smuzhiyun int err = 0;
1760*4882a593Smuzhiyun
1761*4882a593Smuzhiyun tu = file->private_data;
1762*4882a593Smuzhiyun if (tu->timeri) {
1763*4882a593Smuzhiyun snd_timer_close(tu->timeri);
1764*4882a593Smuzhiyun snd_timer_instance_free(tu->timeri);
1765*4882a593Smuzhiyun tu->timeri = NULL;
1766*4882a593Smuzhiyun }
1767*4882a593Smuzhiyun if (copy_from_user(&tselect, _tselect, sizeof(tselect))) {
1768*4882a593Smuzhiyun err = -EFAULT;
1769*4882a593Smuzhiyun goto __err;
1770*4882a593Smuzhiyun }
1771*4882a593Smuzhiyun sprintf(str, "application %i", current->pid);
1772*4882a593Smuzhiyun if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE)
1773*4882a593Smuzhiyun tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION;
1774*4882a593Smuzhiyun tu->timeri = snd_timer_instance_new(str);
1775*4882a593Smuzhiyun if (!tu->timeri) {
1776*4882a593Smuzhiyun err = -ENOMEM;
1777*4882a593Smuzhiyun goto __err;
1778*4882a593Smuzhiyun }
1779*4882a593Smuzhiyun
1780*4882a593Smuzhiyun tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST;
1781*4882a593Smuzhiyun tu->timeri->callback = tu->tread
1782*4882a593Smuzhiyun ? snd_timer_user_tinterrupt : snd_timer_user_interrupt;
1783*4882a593Smuzhiyun tu->timeri->ccallback = snd_timer_user_ccallback;
1784*4882a593Smuzhiyun tu->timeri->callback_data = (void *)tu;
1785*4882a593Smuzhiyun tu->timeri->disconnect = snd_timer_user_disconnect;
1786*4882a593Smuzhiyun
1787*4882a593Smuzhiyun err = snd_timer_open(tu->timeri, &tselect.id, current->pid);
1788*4882a593Smuzhiyun if (err < 0) {
1789*4882a593Smuzhiyun snd_timer_instance_free(tu->timeri);
1790*4882a593Smuzhiyun tu->timeri = NULL;
1791*4882a593Smuzhiyun }
1792*4882a593Smuzhiyun
1793*4882a593Smuzhiyun __err:
1794*4882a593Smuzhiyun return err;
1795*4882a593Smuzhiyun }
1796*4882a593Smuzhiyun
snd_timer_user_info(struct file * file,struct snd_timer_info __user * _info)1797*4882a593Smuzhiyun static int snd_timer_user_info(struct file *file,
1798*4882a593Smuzhiyun struct snd_timer_info __user *_info)
1799*4882a593Smuzhiyun {
1800*4882a593Smuzhiyun struct snd_timer_user *tu;
1801*4882a593Smuzhiyun struct snd_timer_info *info;
1802*4882a593Smuzhiyun struct snd_timer *t;
1803*4882a593Smuzhiyun int err = 0;
1804*4882a593Smuzhiyun
1805*4882a593Smuzhiyun tu = file->private_data;
1806*4882a593Smuzhiyun if (!tu->timeri)
1807*4882a593Smuzhiyun return -EBADFD;
1808*4882a593Smuzhiyun t = tu->timeri->timer;
1809*4882a593Smuzhiyun if (!t)
1810*4882a593Smuzhiyun return -EBADFD;
1811*4882a593Smuzhiyun
1812*4882a593Smuzhiyun info = kzalloc(sizeof(*info), GFP_KERNEL);
1813*4882a593Smuzhiyun if (! info)
1814*4882a593Smuzhiyun return -ENOMEM;
1815*4882a593Smuzhiyun info->card = t->card ? t->card->number : -1;
1816*4882a593Smuzhiyun if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
1817*4882a593Smuzhiyun info->flags |= SNDRV_TIMER_FLG_SLAVE;
1818*4882a593Smuzhiyun strlcpy(info->id, t->id, sizeof(info->id));
1819*4882a593Smuzhiyun strlcpy(info->name, t->name, sizeof(info->name));
1820*4882a593Smuzhiyun info->resolution = t->hw.resolution;
1821*4882a593Smuzhiyun if (copy_to_user(_info, info, sizeof(*_info)))
1822*4882a593Smuzhiyun err = -EFAULT;
1823*4882a593Smuzhiyun kfree(info);
1824*4882a593Smuzhiyun return err;
1825*4882a593Smuzhiyun }
1826*4882a593Smuzhiyun
snd_timer_user_params(struct file * file,struct snd_timer_params __user * _params)1827*4882a593Smuzhiyun static int snd_timer_user_params(struct file *file,
1828*4882a593Smuzhiyun struct snd_timer_params __user *_params)
1829*4882a593Smuzhiyun {
1830*4882a593Smuzhiyun struct snd_timer_user *tu;
1831*4882a593Smuzhiyun struct snd_timer_params params;
1832*4882a593Smuzhiyun struct snd_timer *t;
1833*4882a593Smuzhiyun int err;
1834*4882a593Smuzhiyun
1835*4882a593Smuzhiyun tu = file->private_data;
1836*4882a593Smuzhiyun if (!tu->timeri)
1837*4882a593Smuzhiyun return -EBADFD;
1838*4882a593Smuzhiyun t = tu->timeri->timer;
1839*4882a593Smuzhiyun if (!t)
1840*4882a593Smuzhiyun return -EBADFD;
1841*4882a593Smuzhiyun if (copy_from_user(¶ms, _params, sizeof(params)))
1842*4882a593Smuzhiyun return -EFAULT;
1843*4882a593Smuzhiyun if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE)) {
1844*4882a593Smuzhiyun u64 resolution;
1845*4882a593Smuzhiyun
1846*4882a593Smuzhiyun if (params.ticks < 1) {
1847*4882a593Smuzhiyun err = -EINVAL;
1848*4882a593Smuzhiyun goto _end;
1849*4882a593Smuzhiyun }
1850*4882a593Smuzhiyun
1851*4882a593Smuzhiyun /* Don't allow resolution less than 1ms */
1852*4882a593Smuzhiyun resolution = snd_timer_resolution(tu->timeri);
1853*4882a593Smuzhiyun resolution *= params.ticks;
1854*4882a593Smuzhiyun if (resolution < 1000000) {
1855*4882a593Smuzhiyun err = -EINVAL;
1856*4882a593Smuzhiyun goto _end;
1857*4882a593Smuzhiyun }
1858*4882a593Smuzhiyun }
1859*4882a593Smuzhiyun if (params.queue_size > 0 &&
1860*4882a593Smuzhiyun (params.queue_size < 32 || params.queue_size > 1024)) {
1861*4882a593Smuzhiyun err = -EINVAL;
1862*4882a593Smuzhiyun goto _end;
1863*4882a593Smuzhiyun }
1864*4882a593Smuzhiyun if (params.filter & ~((1<<SNDRV_TIMER_EVENT_RESOLUTION)|
1865*4882a593Smuzhiyun (1<<SNDRV_TIMER_EVENT_TICK)|
1866*4882a593Smuzhiyun (1<<SNDRV_TIMER_EVENT_START)|
1867*4882a593Smuzhiyun (1<<SNDRV_TIMER_EVENT_STOP)|
1868*4882a593Smuzhiyun (1<<SNDRV_TIMER_EVENT_CONTINUE)|
1869*4882a593Smuzhiyun (1<<SNDRV_TIMER_EVENT_PAUSE)|
1870*4882a593Smuzhiyun (1<<SNDRV_TIMER_EVENT_SUSPEND)|
1871*4882a593Smuzhiyun (1<<SNDRV_TIMER_EVENT_RESUME)|
1872*4882a593Smuzhiyun (1<<SNDRV_TIMER_EVENT_MSTART)|
1873*4882a593Smuzhiyun (1<<SNDRV_TIMER_EVENT_MSTOP)|
1874*4882a593Smuzhiyun (1<<SNDRV_TIMER_EVENT_MCONTINUE)|
1875*4882a593Smuzhiyun (1<<SNDRV_TIMER_EVENT_MPAUSE)|
1876*4882a593Smuzhiyun (1<<SNDRV_TIMER_EVENT_MSUSPEND)|
1877*4882a593Smuzhiyun (1<<SNDRV_TIMER_EVENT_MRESUME))) {
1878*4882a593Smuzhiyun err = -EINVAL;
1879*4882a593Smuzhiyun goto _end;
1880*4882a593Smuzhiyun }
1881*4882a593Smuzhiyun snd_timer_stop(tu->timeri);
1882*4882a593Smuzhiyun spin_lock_irq(&t->lock);
1883*4882a593Smuzhiyun tu->timeri->flags &= ~(SNDRV_TIMER_IFLG_AUTO|
1884*4882a593Smuzhiyun SNDRV_TIMER_IFLG_EXCLUSIVE|
1885*4882a593Smuzhiyun SNDRV_TIMER_IFLG_EARLY_EVENT);
1886*4882a593Smuzhiyun if (params.flags & SNDRV_TIMER_PSFLG_AUTO)
1887*4882a593Smuzhiyun tu->timeri->flags |= SNDRV_TIMER_IFLG_AUTO;
1888*4882a593Smuzhiyun if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE)
1889*4882a593Smuzhiyun tu->timeri->flags |= SNDRV_TIMER_IFLG_EXCLUSIVE;
1890*4882a593Smuzhiyun if (params.flags & SNDRV_TIMER_PSFLG_EARLY_EVENT)
1891*4882a593Smuzhiyun tu->timeri->flags |= SNDRV_TIMER_IFLG_EARLY_EVENT;
1892*4882a593Smuzhiyun spin_unlock_irq(&t->lock);
1893*4882a593Smuzhiyun if (params.queue_size > 0 &&
1894*4882a593Smuzhiyun (unsigned int)tu->queue_size != params.queue_size) {
1895*4882a593Smuzhiyun err = realloc_user_queue(tu, params.queue_size);
1896*4882a593Smuzhiyun if (err < 0)
1897*4882a593Smuzhiyun goto _end;
1898*4882a593Smuzhiyun }
1899*4882a593Smuzhiyun spin_lock_irq(&tu->qlock);
1900*4882a593Smuzhiyun tu->qhead = tu->qtail = tu->qused = 0;
1901*4882a593Smuzhiyun if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) {
1902*4882a593Smuzhiyun if (tu->tread) {
1903*4882a593Smuzhiyun struct snd_timer_tread64 tread;
1904*4882a593Smuzhiyun memset(&tread, 0, sizeof(tread));
1905*4882a593Smuzhiyun tread.event = SNDRV_TIMER_EVENT_EARLY;
1906*4882a593Smuzhiyun tread.tstamp_sec = 0;
1907*4882a593Smuzhiyun tread.tstamp_nsec = 0;
1908*4882a593Smuzhiyun tread.val = 0;
1909*4882a593Smuzhiyun snd_timer_user_append_to_tqueue(tu, &tread);
1910*4882a593Smuzhiyun } else {
1911*4882a593Smuzhiyun struct snd_timer_read *r = &tu->queue[0];
1912*4882a593Smuzhiyun r->resolution = 0;
1913*4882a593Smuzhiyun r->ticks = 0;
1914*4882a593Smuzhiyun tu->qused++;
1915*4882a593Smuzhiyun tu->qtail++;
1916*4882a593Smuzhiyun }
1917*4882a593Smuzhiyun }
1918*4882a593Smuzhiyun tu->filter = params.filter;
1919*4882a593Smuzhiyun tu->ticks = params.ticks;
1920*4882a593Smuzhiyun spin_unlock_irq(&tu->qlock);
1921*4882a593Smuzhiyun err = 0;
1922*4882a593Smuzhiyun _end:
1923*4882a593Smuzhiyun if (copy_to_user(_params, ¶ms, sizeof(params)))
1924*4882a593Smuzhiyun return -EFAULT;
1925*4882a593Smuzhiyun return err;
1926*4882a593Smuzhiyun }
1927*4882a593Smuzhiyun
snd_timer_user_status32(struct file * file,struct snd_timer_status32 __user * _status)1928*4882a593Smuzhiyun static int snd_timer_user_status32(struct file *file,
1929*4882a593Smuzhiyun struct snd_timer_status32 __user *_status)
1930*4882a593Smuzhiyun {
1931*4882a593Smuzhiyun struct snd_timer_user *tu;
1932*4882a593Smuzhiyun struct snd_timer_status32 status;
1933*4882a593Smuzhiyun
1934*4882a593Smuzhiyun tu = file->private_data;
1935*4882a593Smuzhiyun if (!tu->timeri)
1936*4882a593Smuzhiyun return -EBADFD;
1937*4882a593Smuzhiyun memset(&status, 0, sizeof(status));
1938*4882a593Smuzhiyun status.tstamp_sec = tu->tstamp.tv_sec;
1939*4882a593Smuzhiyun status.tstamp_nsec = tu->tstamp.tv_nsec;
1940*4882a593Smuzhiyun status.resolution = snd_timer_resolution(tu->timeri);
1941*4882a593Smuzhiyun status.lost = tu->timeri->lost;
1942*4882a593Smuzhiyun status.overrun = tu->overrun;
1943*4882a593Smuzhiyun spin_lock_irq(&tu->qlock);
1944*4882a593Smuzhiyun status.queue = tu->qused;
1945*4882a593Smuzhiyun spin_unlock_irq(&tu->qlock);
1946*4882a593Smuzhiyun if (copy_to_user(_status, &status, sizeof(status)))
1947*4882a593Smuzhiyun return -EFAULT;
1948*4882a593Smuzhiyun return 0;
1949*4882a593Smuzhiyun }
1950*4882a593Smuzhiyun
snd_timer_user_status64(struct file * file,struct snd_timer_status64 __user * _status)1951*4882a593Smuzhiyun static int snd_timer_user_status64(struct file *file,
1952*4882a593Smuzhiyun struct snd_timer_status64 __user *_status)
1953*4882a593Smuzhiyun {
1954*4882a593Smuzhiyun struct snd_timer_user *tu;
1955*4882a593Smuzhiyun struct snd_timer_status64 status;
1956*4882a593Smuzhiyun
1957*4882a593Smuzhiyun tu = file->private_data;
1958*4882a593Smuzhiyun if (!tu->timeri)
1959*4882a593Smuzhiyun return -EBADFD;
1960*4882a593Smuzhiyun memset(&status, 0, sizeof(status));
1961*4882a593Smuzhiyun status.tstamp_sec = tu->tstamp.tv_sec;
1962*4882a593Smuzhiyun status.tstamp_nsec = tu->tstamp.tv_nsec;
1963*4882a593Smuzhiyun status.resolution = snd_timer_resolution(tu->timeri);
1964*4882a593Smuzhiyun status.lost = tu->timeri->lost;
1965*4882a593Smuzhiyun status.overrun = tu->overrun;
1966*4882a593Smuzhiyun spin_lock_irq(&tu->qlock);
1967*4882a593Smuzhiyun status.queue = tu->qused;
1968*4882a593Smuzhiyun spin_unlock_irq(&tu->qlock);
1969*4882a593Smuzhiyun if (copy_to_user(_status, &status, sizeof(status)))
1970*4882a593Smuzhiyun return -EFAULT;
1971*4882a593Smuzhiyun return 0;
1972*4882a593Smuzhiyun }
1973*4882a593Smuzhiyun
snd_timer_user_start(struct file * file)1974*4882a593Smuzhiyun static int snd_timer_user_start(struct file *file)
1975*4882a593Smuzhiyun {
1976*4882a593Smuzhiyun int err;
1977*4882a593Smuzhiyun struct snd_timer_user *tu;
1978*4882a593Smuzhiyun
1979*4882a593Smuzhiyun tu = file->private_data;
1980*4882a593Smuzhiyun if (!tu->timeri)
1981*4882a593Smuzhiyun return -EBADFD;
1982*4882a593Smuzhiyun snd_timer_stop(tu->timeri);
1983*4882a593Smuzhiyun tu->timeri->lost = 0;
1984*4882a593Smuzhiyun tu->last_resolution = 0;
1985*4882a593Smuzhiyun err = snd_timer_start(tu->timeri, tu->ticks);
1986*4882a593Smuzhiyun if (err < 0)
1987*4882a593Smuzhiyun return err;
1988*4882a593Smuzhiyun return 0;
1989*4882a593Smuzhiyun }
1990*4882a593Smuzhiyun
snd_timer_user_stop(struct file * file)1991*4882a593Smuzhiyun static int snd_timer_user_stop(struct file *file)
1992*4882a593Smuzhiyun {
1993*4882a593Smuzhiyun int err;
1994*4882a593Smuzhiyun struct snd_timer_user *tu;
1995*4882a593Smuzhiyun
1996*4882a593Smuzhiyun tu = file->private_data;
1997*4882a593Smuzhiyun if (!tu->timeri)
1998*4882a593Smuzhiyun return -EBADFD;
1999*4882a593Smuzhiyun err = snd_timer_stop(tu->timeri);
2000*4882a593Smuzhiyun if (err < 0)
2001*4882a593Smuzhiyun return err;
2002*4882a593Smuzhiyun return 0;
2003*4882a593Smuzhiyun }
2004*4882a593Smuzhiyun
snd_timer_user_continue(struct file * file)2005*4882a593Smuzhiyun static int snd_timer_user_continue(struct file *file)
2006*4882a593Smuzhiyun {
2007*4882a593Smuzhiyun int err;
2008*4882a593Smuzhiyun struct snd_timer_user *tu;
2009*4882a593Smuzhiyun
2010*4882a593Smuzhiyun tu = file->private_data;
2011*4882a593Smuzhiyun if (!tu->timeri)
2012*4882a593Smuzhiyun return -EBADFD;
2013*4882a593Smuzhiyun /* start timer instead of continue if it's not used before */
2014*4882a593Smuzhiyun if (!(tu->timeri->flags & SNDRV_TIMER_IFLG_PAUSED))
2015*4882a593Smuzhiyun return snd_timer_user_start(file);
2016*4882a593Smuzhiyun tu->timeri->lost = 0;
2017*4882a593Smuzhiyun err = snd_timer_continue(tu->timeri);
2018*4882a593Smuzhiyun if (err < 0)
2019*4882a593Smuzhiyun return err;
2020*4882a593Smuzhiyun return 0;
2021*4882a593Smuzhiyun }
2022*4882a593Smuzhiyun
snd_timer_user_pause(struct file * file)2023*4882a593Smuzhiyun static int snd_timer_user_pause(struct file *file)
2024*4882a593Smuzhiyun {
2025*4882a593Smuzhiyun int err;
2026*4882a593Smuzhiyun struct snd_timer_user *tu;
2027*4882a593Smuzhiyun
2028*4882a593Smuzhiyun tu = file->private_data;
2029*4882a593Smuzhiyun if (!tu->timeri)
2030*4882a593Smuzhiyun return -EBADFD;
2031*4882a593Smuzhiyun err = snd_timer_pause(tu->timeri);
2032*4882a593Smuzhiyun if (err < 0)
2033*4882a593Smuzhiyun return err;
2034*4882a593Smuzhiyun return 0;
2035*4882a593Smuzhiyun }
2036*4882a593Smuzhiyun
snd_timer_user_tread(void __user * argp,struct snd_timer_user * tu,unsigned int cmd,bool compat)2037*4882a593Smuzhiyun static int snd_timer_user_tread(void __user *argp, struct snd_timer_user *tu,
2038*4882a593Smuzhiyun unsigned int cmd, bool compat)
2039*4882a593Smuzhiyun {
2040*4882a593Smuzhiyun int __user *p = argp;
2041*4882a593Smuzhiyun int xarg, old_tread;
2042*4882a593Smuzhiyun
2043*4882a593Smuzhiyun if (tu->timeri) /* too late */
2044*4882a593Smuzhiyun return -EBUSY;
2045*4882a593Smuzhiyun if (get_user(xarg, p))
2046*4882a593Smuzhiyun return -EFAULT;
2047*4882a593Smuzhiyun
2048*4882a593Smuzhiyun old_tread = tu->tread;
2049*4882a593Smuzhiyun
2050*4882a593Smuzhiyun if (!xarg)
2051*4882a593Smuzhiyun tu->tread = TREAD_FORMAT_NONE;
2052*4882a593Smuzhiyun else if (cmd == SNDRV_TIMER_IOCTL_TREAD64 ||
2053*4882a593Smuzhiyun (IS_ENABLED(CONFIG_64BIT) && !compat))
2054*4882a593Smuzhiyun tu->tread = TREAD_FORMAT_TIME64;
2055*4882a593Smuzhiyun else
2056*4882a593Smuzhiyun tu->tread = TREAD_FORMAT_TIME32;
2057*4882a593Smuzhiyun
2058*4882a593Smuzhiyun if (tu->tread != old_tread &&
2059*4882a593Smuzhiyun realloc_user_queue(tu, tu->queue_size) < 0) {
2060*4882a593Smuzhiyun tu->tread = old_tread;
2061*4882a593Smuzhiyun return -ENOMEM;
2062*4882a593Smuzhiyun }
2063*4882a593Smuzhiyun
2064*4882a593Smuzhiyun return 0;
2065*4882a593Smuzhiyun }
2066*4882a593Smuzhiyun
2067*4882a593Smuzhiyun enum {
2068*4882a593Smuzhiyun SNDRV_TIMER_IOCTL_START_OLD = _IO('T', 0x20),
2069*4882a593Smuzhiyun SNDRV_TIMER_IOCTL_STOP_OLD = _IO('T', 0x21),
2070*4882a593Smuzhiyun SNDRV_TIMER_IOCTL_CONTINUE_OLD = _IO('T', 0x22),
2071*4882a593Smuzhiyun SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23),
2072*4882a593Smuzhiyun };
2073*4882a593Smuzhiyun
__snd_timer_user_ioctl(struct file * file,unsigned int cmd,unsigned long arg,bool compat)2074*4882a593Smuzhiyun static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd,
2075*4882a593Smuzhiyun unsigned long arg, bool compat)
2076*4882a593Smuzhiyun {
2077*4882a593Smuzhiyun struct snd_timer_user *tu;
2078*4882a593Smuzhiyun void __user *argp = (void __user *)arg;
2079*4882a593Smuzhiyun int __user *p = argp;
2080*4882a593Smuzhiyun
2081*4882a593Smuzhiyun tu = file->private_data;
2082*4882a593Smuzhiyun switch (cmd) {
2083*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_PVERSION:
2084*4882a593Smuzhiyun return put_user(SNDRV_TIMER_VERSION, p) ? -EFAULT : 0;
2085*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
2086*4882a593Smuzhiyun return snd_timer_user_next_device(argp);
2087*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_TREAD_OLD:
2088*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_TREAD64:
2089*4882a593Smuzhiyun return snd_timer_user_tread(argp, tu, cmd, compat);
2090*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_GINFO:
2091*4882a593Smuzhiyun return snd_timer_user_ginfo(file, argp);
2092*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_GPARAMS:
2093*4882a593Smuzhiyun return snd_timer_user_gparams(file, argp);
2094*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_GSTATUS:
2095*4882a593Smuzhiyun return snd_timer_user_gstatus(file, argp);
2096*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_SELECT:
2097*4882a593Smuzhiyun return snd_timer_user_tselect(file, argp);
2098*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_INFO:
2099*4882a593Smuzhiyun return snd_timer_user_info(file, argp);
2100*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_PARAMS:
2101*4882a593Smuzhiyun return snd_timer_user_params(file, argp);
2102*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_STATUS32:
2103*4882a593Smuzhiyun return snd_timer_user_status32(file, argp);
2104*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_STATUS64:
2105*4882a593Smuzhiyun return snd_timer_user_status64(file, argp);
2106*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_START:
2107*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_START_OLD:
2108*4882a593Smuzhiyun return snd_timer_user_start(file);
2109*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_STOP:
2110*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_STOP_OLD:
2111*4882a593Smuzhiyun return snd_timer_user_stop(file);
2112*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_CONTINUE:
2113*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_CONTINUE_OLD:
2114*4882a593Smuzhiyun return snd_timer_user_continue(file);
2115*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_PAUSE:
2116*4882a593Smuzhiyun case SNDRV_TIMER_IOCTL_PAUSE_OLD:
2117*4882a593Smuzhiyun return snd_timer_user_pause(file);
2118*4882a593Smuzhiyun }
2119*4882a593Smuzhiyun return -ENOTTY;
2120*4882a593Smuzhiyun }
2121*4882a593Smuzhiyun
snd_timer_user_ioctl(struct file * file,unsigned int cmd,unsigned long arg)2122*4882a593Smuzhiyun static long snd_timer_user_ioctl(struct file *file, unsigned int cmd,
2123*4882a593Smuzhiyun unsigned long arg)
2124*4882a593Smuzhiyun {
2125*4882a593Smuzhiyun struct snd_timer_user *tu = file->private_data;
2126*4882a593Smuzhiyun long ret;
2127*4882a593Smuzhiyun
2128*4882a593Smuzhiyun mutex_lock(&tu->ioctl_lock);
2129*4882a593Smuzhiyun ret = __snd_timer_user_ioctl(file, cmd, arg, false);
2130*4882a593Smuzhiyun mutex_unlock(&tu->ioctl_lock);
2131*4882a593Smuzhiyun return ret;
2132*4882a593Smuzhiyun }
2133*4882a593Smuzhiyun
snd_timer_user_fasync(int fd,struct file * file,int on)2134*4882a593Smuzhiyun static int snd_timer_user_fasync(int fd, struct file * file, int on)
2135*4882a593Smuzhiyun {
2136*4882a593Smuzhiyun struct snd_timer_user *tu;
2137*4882a593Smuzhiyun
2138*4882a593Smuzhiyun tu = file->private_data;
2139*4882a593Smuzhiyun return snd_fasync_helper(fd, file, on, &tu->fasync);
2140*4882a593Smuzhiyun }
2141*4882a593Smuzhiyun
snd_timer_user_read(struct file * file,char __user * buffer,size_t count,loff_t * offset)2142*4882a593Smuzhiyun static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
2143*4882a593Smuzhiyun size_t count, loff_t *offset)
2144*4882a593Smuzhiyun {
2145*4882a593Smuzhiyun struct snd_timer_tread64 *tread;
2146*4882a593Smuzhiyun struct snd_timer_tread32 tread32;
2147*4882a593Smuzhiyun struct snd_timer_user *tu;
2148*4882a593Smuzhiyun long result = 0, unit;
2149*4882a593Smuzhiyun int qhead;
2150*4882a593Smuzhiyun int err = 0;
2151*4882a593Smuzhiyun
2152*4882a593Smuzhiyun tu = file->private_data;
2153*4882a593Smuzhiyun switch (tu->tread) {
2154*4882a593Smuzhiyun case TREAD_FORMAT_TIME64:
2155*4882a593Smuzhiyun unit = sizeof(struct snd_timer_tread64);
2156*4882a593Smuzhiyun break;
2157*4882a593Smuzhiyun case TREAD_FORMAT_TIME32:
2158*4882a593Smuzhiyun unit = sizeof(struct snd_timer_tread32);
2159*4882a593Smuzhiyun break;
2160*4882a593Smuzhiyun case TREAD_FORMAT_NONE:
2161*4882a593Smuzhiyun unit = sizeof(struct snd_timer_read);
2162*4882a593Smuzhiyun break;
2163*4882a593Smuzhiyun default:
2164*4882a593Smuzhiyun WARN_ONCE(1, "Corrupt snd_timer_user\n");
2165*4882a593Smuzhiyun return -ENOTSUPP;
2166*4882a593Smuzhiyun }
2167*4882a593Smuzhiyun
2168*4882a593Smuzhiyun mutex_lock(&tu->ioctl_lock);
2169*4882a593Smuzhiyun spin_lock_irq(&tu->qlock);
2170*4882a593Smuzhiyun while ((long)count - result >= unit) {
2171*4882a593Smuzhiyun while (!tu->qused) {
2172*4882a593Smuzhiyun wait_queue_entry_t wait;
2173*4882a593Smuzhiyun
2174*4882a593Smuzhiyun if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {
2175*4882a593Smuzhiyun err = -EAGAIN;
2176*4882a593Smuzhiyun goto _error;
2177*4882a593Smuzhiyun }
2178*4882a593Smuzhiyun
2179*4882a593Smuzhiyun set_current_state(TASK_INTERRUPTIBLE);
2180*4882a593Smuzhiyun init_waitqueue_entry(&wait, current);
2181*4882a593Smuzhiyun add_wait_queue(&tu->qchange_sleep, &wait);
2182*4882a593Smuzhiyun
2183*4882a593Smuzhiyun spin_unlock_irq(&tu->qlock);
2184*4882a593Smuzhiyun mutex_unlock(&tu->ioctl_lock);
2185*4882a593Smuzhiyun schedule();
2186*4882a593Smuzhiyun mutex_lock(&tu->ioctl_lock);
2187*4882a593Smuzhiyun spin_lock_irq(&tu->qlock);
2188*4882a593Smuzhiyun
2189*4882a593Smuzhiyun remove_wait_queue(&tu->qchange_sleep, &wait);
2190*4882a593Smuzhiyun
2191*4882a593Smuzhiyun if (tu->disconnected) {
2192*4882a593Smuzhiyun err = -ENODEV;
2193*4882a593Smuzhiyun goto _error;
2194*4882a593Smuzhiyun }
2195*4882a593Smuzhiyun if (signal_pending(current)) {
2196*4882a593Smuzhiyun err = -ERESTARTSYS;
2197*4882a593Smuzhiyun goto _error;
2198*4882a593Smuzhiyun }
2199*4882a593Smuzhiyun }
2200*4882a593Smuzhiyun
2201*4882a593Smuzhiyun qhead = tu->qhead++;
2202*4882a593Smuzhiyun tu->qhead %= tu->queue_size;
2203*4882a593Smuzhiyun tu->qused--;
2204*4882a593Smuzhiyun spin_unlock_irq(&tu->qlock);
2205*4882a593Smuzhiyun
2206*4882a593Smuzhiyun tread = &tu->tqueue[qhead];
2207*4882a593Smuzhiyun
2208*4882a593Smuzhiyun switch (tu->tread) {
2209*4882a593Smuzhiyun case TREAD_FORMAT_TIME64:
2210*4882a593Smuzhiyun if (copy_to_user(buffer, tread,
2211*4882a593Smuzhiyun sizeof(struct snd_timer_tread64)))
2212*4882a593Smuzhiyun err = -EFAULT;
2213*4882a593Smuzhiyun break;
2214*4882a593Smuzhiyun case TREAD_FORMAT_TIME32:
2215*4882a593Smuzhiyun memset(&tread32, 0, sizeof(tread32));
2216*4882a593Smuzhiyun tread32 = (struct snd_timer_tread32) {
2217*4882a593Smuzhiyun .event = tread->event,
2218*4882a593Smuzhiyun .tstamp_sec = tread->tstamp_sec,
2219*4882a593Smuzhiyun .tstamp_nsec = tread->tstamp_nsec,
2220*4882a593Smuzhiyun .val = tread->val,
2221*4882a593Smuzhiyun };
2222*4882a593Smuzhiyun
2223*4882a593Smuzhiyun if (copy_to_user(buffer, &tread32, sizeof(tread32)))
2224*4882a593Smuzhiyun err = -EFAULT;
2225*4882a593Smuzhiyun break;
2226*4882a593Smuzhiyun case TREAD_FORMAT_NONE:
2227*4882a593Smuzhiyun if (copy_to_user(buffer, &tu->queue[qhead],
2228*4882a593Smuzhiyun sizeof(struct snd_timer_read)))
2229*4882a593Smuzhiyun err = -EFAULT;
2230*4882a593Smuzhiyun break;
2231*4882a593Smuzhiyun default:
2232*4882a593Smuzhiyun err = -ENOTSUPP;
2233*4882a593Smuzhiyun break;
2234*4882a593Smuzhiyun }
2235*4882a593Smuzhiyun
2236*4882a593Smuzhiyun spin_lock_irq(&tu->qlock);
2237*4882a593Smuzhiyun if (err < 0)
2238*4882a593Smuzhiyun goto _error;
2239*4882a593Smuzhiyun result += unit;
2240*4882a593Smuzhiyun buffer += unit;
2241*4882a593Smuzhiyun }
2242*4882a593Smuzhiyun _error:
2243*4882a593Smuzhiyun spin_unlock_irq(&tu->qlock);
2244*4882a593Smuzhiyun mutex_unlock(&tu->ioctl_lock);
2245*4882a593Smuzhiyun return result > 0 ? result : err;
2246*4882a593Smuzhiyun }
2247*4882a593Smuzhiyun
snd_timer_user_poll(struct file * file,poll_table * wait)2248*4882a593Smuzhiyun static __poll_t snd_timer_user_poll(struct file *file, poll_table * wait)
2249*4882a593Smuzhiyun {
2250*4882a593Smuzhiyun __poll_t mask;
2251*4882a593Smuzhiyun struct snd_timer_user *tu;
2252*4882a593Smuzhiyun
2253*4882a593Smuzhiyun tu = file->private_data;
2254*4882a593Smuzhiyun
2255*4882a593Smuzhiyun poll_wait(file, &tu->qchange_sleep, wait);
2256*4882a593Smuzhiyun
2257*4882a593Smuzhiyun mask = 0;
2258*4882a593Smuzhiyun spin_lock_irq(&tu->qlock);
2259*4882a593Smuzhiyun if (tu->qused)
2260*4882a593Smuzhiyun mask |= EPOLLIN | EPOLLRDNORM;
2261*4882a593Smuzhiyun if (tu->disconnected)
2262*4882a593Smuzhiyun mask |= EPOLLERR;
2263*4882a593Smuzhiyun spin_unlock_irq(&tu->qlock);
2264*4882a593Smuzhiyun
2265*4882a593Smuzhiyun return mask;
2266*4882a593Smuzhiyun }
2267*4882a593Smuzhiyun
2268*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
2269*4882a593Smuzhiyun #include "timer_compat.c"
2270*4882a593Smuzhiyun #else
2271*4882a593Smuzhiyun #define snd_timer_user_ioctl_compat NULL
2272*4882a593Smuzhiyun #endif
2273*4882a593Smuzhiyun
2274*4882a593Smuzhiyun static const struct file_operations snd_timer_f_ops =
2275*4882a593Smuzhiyun {
2276*4882a593Smuzhiyun .owner = THIS_MODULE,
2277*4882a593Smuzhiyun .read = snd_timer_user_read,
2278*4882a593Smuzhiyun .open = snd_timer_user_open,
2279*4882a593Smuzhiyun .release = snd_timer_user_release,
2280*4882a593Smuzhiyun .llseek = no_llseek,
2281*4882a593Smuzhiyun .poll = snd_timer_user_poll,
2282*4882a593Smuzhiyun .unlocked_ioctl = snd_timer_user_ioctl,
2283*4882a593Smuzhiyun .compat_ioctl = snd_timer_user_ioctl_compat,
2284*4882a593Smuzhiyun .fasync = snd_timer_user_fasync,
2285*4882a593Smuzhiyun };
2286*4882a593Smuzhiyun
2287*4882a593Smuzhiyun /* unregister the system timer */
snd_timer_free_all(void)2288*4882a593Smuzhiyun static void snd_timer_free_all(void)
2289*4882a593Smuzhiyun {
2290*4882a593Smuzhiyun struct snd_timer *timer, *n;
2291*4882a593Smuzhiyun
2292*4882a593Smuzhiyun list_for_each_entry_safe(timer, n, &snd_timer_list, device_list)
2293*4882a593Smuzhiyun snd_timer_free(timer);
2294*4882a593Smuzhiyun }
2295*4882a593Smuzhiyun
2296*4882a593Smuzhiyun static struct device timer_dev;
2297*4882a593Smuzhiyun
2298*4882a593Smuzhiyun /*
2299*4882a593Smuzhiyun * ENTRY functions
2300*4882a593Smuzhiyun */
2301*4882a593Smuzhiyun
alsa_timer_init(void)2302*4882a593Smuzhiyun static int __init alsa_timer_init(void)
2303*4882a593Smuzhiyun {
2304*4882a593Smuzhiyun int err;
2305*4882a593Smuzhiyun
2306*4882a593Smuzhiyun snd_device_initialize(&timer_dev, NULL);
2307*4882a593Smuzhiyun dev_set_name(&timer_dev, "timer");
2308*4882a593Smuzhiyun
2309*4882a593Smuzhiyun #ifdef SNDRV_OSS_INFO_DEV_TIMERS
2310*4882a593Smuzhiyun snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1,
2311*4882a593Smuzhiyun "system timer");
2312*4882a593Smuzhiyun #endif
2313*4882a593Smuzhiyun
2314*4882a593Smuzhiyun err = snd_timer_register_system();
2315*4882a593Smuzhiyun if (err < 0) {
2316*4882a593Smuzhiyun pr_err("ALSA: unable to register system timer (%i)\n", err);
2317*4882a593Smuzhiyun goto put_timer;
2318*4882a593Smuzhiyun }
2319*4882a593Smuzhiyun
2320*4882a593Smuzhiyun err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0,
2321*4882a593Smuzhiyun &snd_timer_f_ops, NULL, &timer_dev);
2322*4882a593Smuzhiyun if (err < 0) {
2323*4882a593Smuzhiyun pr_err("ALSA: unable to register timer device (%i)\n", err);
2324*4882a593Smuzhiyun snd_timer_free_all();
2325*4882a593Smuzhiyun goto put_timer;
2326*4882a593Smuzhiyun }
2327*4882a593Smuzhiyun
2328*4882a593Smuzhiyun snd_timer_proc_init();
2329*4882a593Smuzhiyun return 0;
2330*4882a593Smuzhiyun
2331*4882a593Smuzhiyun put_timer:
2332*4882a593Smuzhiyun put_device(&timer_dev);
2333*4882a593Smuzhiyun return err;
2334*4882a593Smuzhiyun }
2335*4882a593Smuzhiyun
alsa_timer_exit(void)2336*4882a593Smuzhiyun static void __exit alsa_timer_exit(void)
2337*4882a593Smuzhiyun {
2338*4882a593Smuzhiyun snd_unregister_device(&timer_dev);
2339*4882a593Smuzhiyun snd_timer_free_all();
2340*4882a593Smuzhiyun put_device(&timer_dev);
2341*4882a593Smuzhiyun snd_timer_proc_done();
2342*4882a593Smuzhiyun #ifdef SNDRV_OSS_INFO_DEV_TIMERS
2343*4882a593Smuzhiyun snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1);
2344*4882a593Smuzhiyun #endif
2345*4882a593Smuzhiyun }
2346*4882a593Smuzhiyun
2347*4882a593Smuzhiyun module_init(alsa_timer_init)
2348*4882a593Smuzhiyun module_exit(alsa_timer_exit)
2349