.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Timers abstract layer |
---|
3 | 4 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
---|
4 | | - * |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License as published by |
---|
8 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
9 | | - * (at your option) any later version. |
---|
10 | | - * |
---|
11 | | - * This program is distributed in the hope that it will be useful, |
---|
12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
14 | | - * GNU General Public License for more details. |
---|
15 | | - * |
---|
16 | | - * You should have received a copy of the GNU General Public License |
---|
17 | | - * along with this program; if not, write to the Free Software |
---|
18 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
19 | | - * |
---|
20 | 5 | */ |
---|
21 | 6 | |
---|
22 | 7 | #include <linux/delay.h> |
---|
.. | .. |
---|
38 | 23 | |
---|
39 | 24 | /* internal flags */ |
---|
40 | 25 | #define SNDRV_TIMER_IFLG_PAUSED 0x00010000 |
---|
| 26 | +#define SNDRV_TIMER_IFLG_DEAD 0x00020000 |
---|
41 | 27 | |
---|
42 | 28 | #if IS_ENABLED(CONFIG_SND_HRTIMER) |
---|
43 | 29 | #define DEFAULT_TIMER_LIMIT 4 |
---|
.. | .. |
---|
58 | 44 | MODULE_ALIAS_CHARDEV(CONFIG_SND_MAJOR, SNDRV_MINOR_TIMER); |
---|
59 | 45 | MODULE_ALIAS("devname:snd/timer"); |
---|
60 | 46 | |
---|
| 47 | +enum timer_tread_format { |
---|
| 48 | + TREAD_FORMAT_NONE = 0, |
---|
| 49 | + TREAD_FORMAT_TIME64, |
---|
| 50 | + TREAD_FORMAT_TIME32, |
---|
| 51 | +}; |
---|
| 52 | + |
---|
| 53 | +struct snd_timer_tread32 { |
---|
| 54 | + int event; |
---|
| 55 | + s32 tstamp_sec; |
---|
| 56 | + s32 tstamp_nsec; |
---|
| 57 | + unsigned int val; |
---|
| 58 | +}; |
---|
| 59 | + |
---|
| 60 | +struct snd_timer_tread64 { |
---|
| 61 | + int event; |
---|
| 62 | + u8 pad1[4]; |
---|
| 63 | + s64 tstamp_sec; |
---|
| 64 | + s64 tstamp_nsec; |
---|
| 65 | + unsigned int val; |
---|
| 66 | + u8 pad2[4]; |
---|
| 67 | +}; |
---|
| 68 | + |
---|
61 | 69 | struct snd_timer_user { |
---|
62 | 70 | struct snd_timer_instance *timeri; |
---|
63 | 71 | int tread; /* enhanced read with timestamps and events */ |
---|
.. | .. |
---|
69 | 77 | int queue_size; |
---|
70 | 78 | bool disconnected; |
---|
71 | 79 | struct snd_timer_read *queue; |
---|
72 | | - struct snd_timer_tread *tqueue; |
---|
| 80 | + struct snd_timer_tread64 *tqueue; |
---|
73 | 81 | spinlock_t qlock; |
---|
74 | 82 | unsigned long last_resolution; |
---|
75 | 83 | unsigned int filter; |
---|
76 | | - struct timespec tstamp; /* trigger tstamp */ |
---|
| 84 | + struct timespec64 tstamp; /* trigger tstamp */ |
---|
77 | 85 | wait_queue_head_t qchange_sleep; |
---|
78 | | - struct fasync_struct *fasync; |
---|
| 86 | + struct snd_fasync *fasync; |
---|
79 | 87 | struct mutex ioctl_lock; |
---|
80 | 88 | }; |
---|
| 89 | + |
---|
| 90 | +struct snd_timer_status32 { |
---|
| 91 | + s32 tstamp_sec; /* Timestamp - last update */ |
---|
| 92 | + s32 tstamp_nsec; |
---|
| 93 | + unsigned int resolution; /* current period resolution in ns */ |
---|
| 94 | + unsigned int lost; /* counter of master tick lost */ |
---|
| 95 | + unsigned int overrun; /* count of read queue overruns */ |
---|
| 96 | + unsigned int queue; /* used queue size */ |
---|
| 97 | + unsigned char reserved[64]; /* reserved */ |
---|
| 98 | +}; |
---|
| 99 | + |
---|
| 100 | +#define SNDRV_TIMER_IOCTL_STATUS32 _IOR('T', 0x14, struct snd_timer_status32) |
---|
| 101 | + |
---|
| 102 | +struct snd_timer_status64 { |
---|
| 103 | + s64 tstamp_sec; /* Timestamp - last update */ |
---|
| 104 | + s64 tstamp_nsec; |
---|
| 105 | + unsigned int resolution; /* current period resolution in ns */ |
---|
| 106 | + unsigned int lost; /* counter of master tick lost */ |
---|
| 107 | + unsigned int overrun; /* count of read queue overruns */ |
---|
| 108 | + unsigned int queue; /* used queue size */ |
---|
| 109 | + unsigned char reserved[64]; /* reserved */ |
---|
| 110 | +}; |
---|
| 111 | + |
---|
| 112 | +#define SNDRV_TIMER_IOCTL_STATUS64 _IOR('T', 0x14, struct snd_timer_status64) |
---|
81 | 113 | |
---|
82 | 114 | /* list of timers */ |
---|
83 | 115 | static LIST_HEAD(snd_timer_list); |
---|
.. | .. |
---|
102 | 134 | |
---|
103 | 135 | /* |
---|
104 | 136 | * create a timer instance with the given owner string. |
---|
105 | | - * when timer is not NULL, increments the module counter |
---|
106 | 137 | */ |
---|
107 | | -static struct snd_timer_instance *snd_timer_instance_new(char *owner, |
---|
108 | | - struct snd_timer *timer) |
---|
| 138 | +struct snd_timer_instance *snd_timer_instance_new(const char *owner) |
---|
109 | 139 | { |
---|
110 | 140 | struct snd_timer_instance *timeri; |
---|
| 141 | + |
---|
111 | 142 | timeri = kzalloc(sizeof(*timeri), GFP_KERNEL); |
---|
112 | 143 | if (timeri == NULL) |
---|
113 | 144 | return NULL; |
---|
.. | .. |
---|
122 | 153 | INIT_LIST_HEAD(&timeri->slave_list_head); |
---|
123 | 154 | INIT_LIST_HEAD(&timeri->slave_active_head); |
---|
124 | 155 | |
---|
125 | | - timeri->timer = timer; |
---|
126 | | - if (timer && !try_module_get(timer->module)) { |
---|
127 | | - kfree(timeri->owner); |
---|
128 | | - kfree(timeri); |
---|
129 | | - return NULL; |
---|
130 | | - } |
---|
131 | | - |
---|
132 | 156 | return timeri; |
---|
133 | 157 | } |
---|
| 158 | +EXPORT_SYMBOL(snd_timer_instance_new); |
---|
| 159 | + |
---|
| 160 | +void snd_timer_instance_free(struct snd_timer_instance *timeri) |
---|
| 161 | +{ |
---|
| 162 | + if (timeri) { |
---|
| 163 | + if (timeri->private_free) |
---|
| 164 | + timeri->private_free(timeri); |
---|
| 165 | + kfree(timeri->owner); |
---|
| 166 | + kfree(timeri); |
---|
| 167 | + } |
---|
| 168 | +} |
---|
| 169 | +EXPORT_SYMBOL(snd_timer_instance_free); |
---|
134 | 170 | |
---|
135 | 171 | /* |
---|
136 | 172 | * find a timer instance from the given timer id |
---|
137 | 173 | */ |
---|
138 | 174 | static struct snd_timer *snd_timer_find(struct snd_timer_id *tid) |
---|
139 | 175 | { |
---|
140 | | - struct snd_timer *timer = NULL; |
---|
| 176 | + struct snd_timer *timer; |
---|
141 | 177 | |
---|
142 | 178 | list_for_each_entry(timer, &snd_timer_list, device_list) { |
---|
143 | 179 | if (timer->tmr_class != tid->dev_class) |
---|
.. | .. |
---|
177 | 213 | |
---|
178 | 214 | #endif |
---|
179 | 215 | |
---|
| 216 | +/* move the slave if it belongs to the master; return 1 if match */ |
---|
| 217 | +static int check_matching_master_slave(struct snd_timer_instance *master, |
---|
| 218 | + struct snd_timer_instance *slave) |
---|
| 219 | +{ |
---|
| 220 | + if (slave->slave_class != master->slave_class || |
---|
| 221 | + slave->slave_id != master->slave_id) |
---|
| 222 | + return 0; |
---|
| 223 | + if (master->timer->num_instances >= master->timer->max_instances) |
---|
| 224 | + return -EBUSY; |
---|
| 225 | + list_move_tail(&slave->open_list, &master->slave_list_head); |
---|
| 226 | + master->timer->num_instances++; |
---|
| 227 | + spin_lock_irq(&slave_active_lock); |
---|
| 228 | + spin_lock(&master->timer->lock); |
---|
| 229 | + slave->master = master; |
---|
| 230 | + slave->timer = master->timer; |
---|
| 231 | + if (slave->flags & SNDRV_TIMER_IFLG_RUNNING) |
---|
| 232 | + list_add_tail(&slave->active_list, &master->slave_active_head); |
---|
| 233 | + spin_unlock(&master->timer->lock); |
---|
| 234 | + spin_unlock_irq(&slave_active_lock); |
---|
| 235 | + return 1; |
---|
| 236 | +} |
---|
| 237 | + |
---|
180 | 238 | /* |
---|
181 | 239 | * look for a master instance matching with the slave id of the given slave. |
---|
182 | 240 | * when found, relink the open_link of the slave. |
---|
.. | .. |
---|
187 | 245 | { |
---|
188 | 246 | struct snd_timer *timer; |
---|
189 | 247 | struct snd_timer_instance *master; |
---|
| 248 | + int err = 0; |
---|
190 | 249 | |
---|
191 | 250 | /* FIXME: it's really dumb to look up all entries.. */ |
---|
192 | 251 | list_for_each_entry(timer, &snd_timer_list, device_list) { |
---|
193 | 252 | list_for_each_entry(master, &timer->open_list_head, open_list) { |
---|
194 | | - if (slave->slave_class == master->slave_class && |
---|
195 | | - slave->slave_id == master->slave_id) { |
---|
196 | | - if (master->timer->num_instances >= |
---|
197 | | - master->timer->max_instances) |
---|
198 | | - return -EBUSY; |
---|
199 | | - list_move_tail(&slave->open_list, |
---|
200 | | - &master->slave_list_head); |
---|
201 | | - master->timer->num_instances++; |
---|
202 | | - spin_lock_irq(&slave_active_lock); |
---|
203 | | - slave->master = master; |
---|
204 | | - slave->timer = master->timer; |
---|
205 | | - spin_unlock_irq(&slave_active_lock); |
---|
206 | | - return 0; |
---|
207 | | - } |
---|
| 253 | + err = check_matching_master_slave(master, slave); |
---|
| 254 | + if (err != 0) /* match found or error */ |
---|
| 255 | + goto out; |
---|
208 | 256 | } |
---|
209 | 257 | } |
---|
210 | | - return 0; |
---|
| 258 | + out: |
---|
| 259 | + return err < 0 ? err : 0; |
---|
211 | 260 | } |
---|
212 | 261 | |
---|
213 | 262 | /* |
---|
.. | .. |
---|
219 | 268 | static int snd_timer_check_master(struct snd_timer_instance *master) |
---|
220 | 269 | { |
---|
221 | 270 | struct snd_timer_instance *slave, *tmp; |
---|
| 271 | + int err = 0; |
---|
222 | 272 | |
---|
223 | 273 | /* check all pending slaves */ |
---|
224 | 274 | list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) { |
---|
225 | | - if (slave->slave_class == master->slave_class && |
---|
226 | | - slave->slave_id == master->slave_id) { |
---|
227 | | - if (master->timer->num_instances >= |
---|
228 | | - master->timer->max_instances) |
---|
229 | | - return -EBUSY; |
---|
230 | | - list_move_tail(&slave->open_list, &master->slave_list_head); |
---|
231 | | - master->timer->num_instances++; |
---|
232 | | - spin_lock_irq(&slave_active_lock); |
---|
233 | | - spin_lock(&master->timer->lock); |
---|
234 | | - slave->master = master; |
---|
235 | | - slave->timer = master->timer; |
---|
236 | | - if (slave->flags & SNDRV_TIMER_IFLG_RUNNING) |
---|
237 | | - list_add_tail(&slave->active_list, |
---|
238 | | - &master->slave_active_head); |
---|
239 | | - spin_unlock(&master->timer->lock); |
---|
240 | | - spin_unlock_irq(&slave_active_lock); |
---|
241 | | - } |
---|
| 275 | + err = check_matching_master_slave(master, slave); |
---|
| 276 | + if (err < 0) |
---|
| 277 | + break; |
---|
242 | 278 | } |
---|
243 | | - return 0; |
---|
| 279 | + return err < 0 ? err : 0; |
---|
244 | 280 | } |
---|
245 | 281 | |
---|
246 | | -static int snd_timer_close_locked(struct snd_timer_instance *timeri, |
---|
247 | | - struct device **card_devp_to_put); |
---|
| 282 | +static void snd_timer_close_locked(struct snd_timer_instance *timeri, |
---|
| 283 | + struct device **card_devp_to_put); |
---|
248 | 284 | |
---|
249 | 285 | /* |
---|
250 | 286 | * open a timer instance |
---|
251 | 287 | * when opening a master, the slave id must be here given. |
---|
252 | 288 | */ |
---|
253 | | -int snd_timer_open(struct snd_timer_instance **ti, |
---|
254 | | - char *owner, struct snd_timer_id *tid, |
---|
| 289 | +int snd_timer_open(struct snd_timer_instance *timeri, |
---|
| 290 | + struct snd_timer_id *tid, |
---|
255 | 291 | unsigned int slave_id) |
---|
256 | 292 | { |
---|
257 | 293 | struct snd_timer *timer; |
---|
258 | | - struct snd_timer_instance *timeri = NULL; |
---|
259 | 294 | struct device *card_dev_to_put = NULL; |
---|
260 | 295 | int err; |
---|
261 | 296 | |
---|
.. | .. |
---|
273 | 308 | err = -EBUSY; |
---|
274 | 309 | goto unlock; |
---|
275 | 310 | } |
---|
276 | | - timeri = snd_timer_instance_new(owner, NULL); |
---|
277 | | - if (!timeri) { |
---|
278 | | - err = -ENOMEM; |
---|
279 | | - goto unlock; |
---|
280 | | - } |
---|
281 | 311 | timeri->slave_class = tid->dev_sclass; |
---|
282 | 312 | timeri->slave_id = tid->device; |
---|
283 | 313 | timeri->flags |= SNDRV_TIMER_IFLG_SLAVE; |
---|
284 | 314 | list_add_tail(&timeri->open_list, &snd_timer_slave_list); |
---|
285 | 315 | num_slaves++; |
---|
286 | 316 | err = snd_timer_check_slave(timeri); |
---|
287 | | - if (err < 0) { |
---|
288 | | - snd_timer_close_locked(timeri, &card_dev_to_put); |
---|
289 | | - timeri = NULL; |
---|
290 | | - } |
---|
291 | | - goto unlock; |
---|
| 317 | + goto list_added; |
---|
292 | 318 | } |
---|
293 | 319 | |
---|
294 | 320 | /* open a master instance */ |
---|
.. | .. |
---|
318 | 344 | err = -EBUSY; |
---|
319 | 345 | goto unlock; |
---|
320 | 346 | } |
---|
321 | | - timeri = snd_timer_instance_new(owner, timer); |
---|
322 | | - if (!timeri) { |
---|
323 | | - err = -ENOMEM; |
---|
| 347 | + if (!try_module_get(timer->module)) { |
---|
| 348 | + err = -EBUSY; |
---|
324 | 349 | goto unlock; |
---|
325 | 350 | } |
---|
326 | 351 | /* take a card refcount for safe disconnection */ |
---|
327 | | - if (timer->card) |
---|
| 352 | + if (timer->card) { |
---|
328 | 353 | get_device(&timer->card->card_dev); |
---|
329 | | - timeri->slave_class = tid->dev_sclass; |
---|
330 | | - timeri->slave_id = slave_id; |
---|
| 354 | + card_dev_to_put = &timer->card->card_dev; |
---|
| 355 | + } |
---|
331 | 356 | |
---|
332 | 357 | if (list_empty(&timer->open_list_head) && timer->hw.open) { |
---|
333 | 358 | err = timer->hw.open(timer); |
---|
334 | 359 | if (err) { |
---|
335 | | - kfree(timeri->owner); |
---|
336 | | - kfree(timeri); |
---|
337 | | - timeri = NULL; |
---|
338 | | - |
---|
339 | | - if (timer->card) |
---|
340 | | - card_dev_to_put = &timer->card->card_dev; |
---|
341 | 360 | module_put(timer->module); |
---|
342 | 361 | goto unlock; |
---|
343 | 362 | } |
---|
344 | 363 | } |
---|
345 | 364 | |
---|
| 365 | + timeri->timer = timer; |
---|
| 366 | + timeri->slave_class = tid->dev_sclass; |
---|
| 367 | + timeri->slave_id = slave_id; |
---|
| 368 | + |
---|
346 | 369 | list_add_tail(&timeri->open_list, &timer->open_list_head); |
---|
347 | 370 | timer->num_instances++; |
---|
348 | 371 | err = snd_timer_check_master(timeri); |
---|
349 | | - if (err < 0) { |
---|
| 372 | +list_added: |
---|
| 373 | + if (err < 0) |
---|
350 | 374 | snd_timer_close_locked(timeri, &card_dev_to_put); |
---|
351 | | - timeri = NULL; |
---|
352 | | - } |
---|
353 | 375 | |
---|
354 | 376 | unlock: |
---|
355 | 377 | mutex_unlock(®ister_mutex); |
---|
356 | 378 | /* put_device() is called after unlock for avoiding deadlock */ |
---|
357 | | - if (card_dev_to_put) |
---|
| 379 | + if (err < 0 && card_dev_to_put) |
---|
358 | 380 | put_device(card_dev_to_put); |
---|
359 | | - *ti = timeri; |
---|
360 | 381 | return err; |
---|
361 | 382 | } |
---|
362 | 383 | EXPORT_SYMBOL(snd_timer_open); |
---|
.. | .. |
---|
365 | 386 | * close a timer instance |
---|
366 | 387 | * call this with register_mutex down. |
---|
367 | 388 | */ |
---|
368 | | -static int snd_timer_close_locked(struct snd_timer_instance *timeri, |
---|
369 | | - struct device **card_devp_to_put) |
---|
| 389 | +static void snd_timer_close_locked(struct snd_timer_instance *timeri, |
---|
| 390 | + struct device **card_devp_to_put) |
---|
370 | 391 | { |
---|
371 | | - struct snd_timer *timer = NULL; |
---|
| 392 | + struct snd_timer *timer = timeri->timer; |
---|
372 | 393 | struct snd_timer_instance *slave, *tmp; |
---|
373 | 394 | |
---|
374 | | - list_del(&timeri->open_list); |
---|
375 | | - if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) |
---|
376 | | - num_slaves--; |
---|
| 395 | + if (timer) { |
---|
| 396 | + spin_lock_irq(&timer->lock); |
---|
| 397 | + timeri->flags |= SNDRV_TIMER_IFLG_DEAD; |
---|
| 398 | + spin_unlock_irq(&timer->lock); |
---|
| 399 | + } |
---|
| 400 | + |
---|
| 401 | + if (!list_empty(&timeri->open_list)) { |
---|
| 402 | + list_del_init(&timeri->open_list); |
---|
| 403 | + if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) |
---|
| 404 | + num_slaves--; |
---|
| 405 | + } |
---|
377 | 406 | |
---|
378 | 407 | /* force to stop the timer */ |
---|
379 | 408 | snd_timer_stop(timeri); |
---|
380 | 409 | |
---|
381 | | - timer = timeri->timer; |
---|
382 | 410 | if (timer) { |
---|
383 | 411 | timer->num_instances--; |
---|
384 | 412 | /* wait, until the active callback is finished */ |
---|
.. | .. |
---|
393 | 421 | /* remove slave links */ |
---|
394 | 422 | spin_lock_irq(&slave_active_lock); |
---|
395 | 423 | spin_lock(&timer->lock); |
---|
| 424 | + timeri->timer = NULL; |
---|
396 | 425 | list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, |
---|
397 | 426 | open_list) { |
---|
398 | 427 | list_move_tail(&slave->open_list, &snd_timer_slave_list); |
---|
.. | .. |
---|
410 | 439 | timer = NULL; |
---|
411 | 440 | } |
---|
412 | 441 | |
---|
413 | | - if (timeri->private_free) |
---|
414 | | - timeri->private_free(timeri); |
---|
415 | | - kfree(timeri->owner); |
---|
416 | | - kfree(timeri); |
---|
417 | | - |
---|
418 | 442 | if (timer) { |
---|
419 | 443 | if (list_empty(&timer->open_list_head) && timer->hw.close) |
---|
420 | 444 | timer->hw.close(timer); |
---|
.. | .. |
---|
423 | 447 | *card_devp_to_put = &timer->card->card_dev; |
---|
424 | 448 | module_put(timer->module); |
---|
425 | 449 | } |
---|
426 | | - |
---|
427 | | - return 0; |
---|
428 | 450 | } |
---|
429 | 451 | |
---|
430 | 452 | /* |
---|
431 | 453 | * close a timer instance |
---|
432 | 454 | */ |
---|
433 | | -int snd_timer_close(struct snd_timer_instance *timeri) |
---|
| 455 | +void snd_timer_close(struct snd_timer_instance *timeri) |
---|
434 | 456 | { |
---|
435 | 457 | struct device *card_dev_to_put = NULL; |
---|
436 | | - int err; |
---|
437 | 458 | |
---|
438 | 459 | if (snd_BUG_ON(!timeri)) |
---|
439 | | - return -ENXIO; |
---|
| 460 | + return; |
---|
440 | 461 | |
---|
441 | 462 | mutex_lock(®ister_mutex); |
---|
442 | | - err = snd_timer_close_locked(timeri, &card_dev_to_put); |
---|
| 463 | + snd_timer_close_locked(timeri, &card_dev_to_put); |
---|
443 | 464 | mutex_unlock(®ister_mutex); |
---|
444 | 465 | /* put_device() is called after unlock for avoiding deadlock */ |
---|
445 | 466 | if (card_dev_to_put) |
---|
446 | 467 | put_device(card_dev_to_put); |
---|
447 | | - return err; |
---|
448 | 468 | } |
---|
449 | 469 | EXPORT_SYMBOL(snd_timer_close); |
---|
450 | 470 | |
---|
.. | .. |
---|
479 | 499 | struct snd_timer *timer = ti->timer; |
---|
480 | 500 | unsigned long resolution = 0; |
---|
481 | 501 | struct snd_timer_instance *ts; |
---|
482 | | - struct timespec tstamp; |
---|
| 502 | + struct timespec64 tstamp; |
---|
483 | 503 | |
---|
484 | 504 | if (timer_tstamp_monotonic) |
---|
485 | | - ktime_get_ts(&tstamp); |
---|
| 505 | + ktime_get_ts64(&tstamp); |
---|
486 | 506 | else |
---|
487 | | - getnstimeofday(&tstamp); |
---|
| 507 | + ktime_get_real_ts64(&tstamp); |
---|
488 | 508 | if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_START || |
---|
489 | 509 | event > SNDRV_TIMER_EVENT_PAUSE)) |
---|
490 | 510 | return; |
---|
.. | .. |
---|
519 | 539 | return -EINVAL; |
---|
520 | 540 | |
---|
521 | 541 | spin_lock_irqsave(&timer->lock, flags); |
---|
| 542 | + if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) { |
---|
| 543 | + result = -EINVAL; |
---|
| 544 | + goto unlock; |
---|
| 545 | + } |
---|
522 | 546 | if (timer->card && timer->card->shutdown) { |
---|
523 | 547 | result = -ENODEV; |
---|
524 | 548 | goto unlock; |
---|
.. | .. |
---|
563 | 587 | bool start) |
---|
564 | 588 | { |
---|
565 | 589 | unsigned long flags; |
---|
| 590 | + int err; |
---|
566 | 591 | |
---|
567 | 592 | spin_lock_irqsave(&slave_active_lock, flags); |
---|
| 593 | + if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) { |
---|
| 594 | + err = -EINVAL; |
---|
| 595 | + goto unlock; |
---|
| 596 | + } |
---|
568 | 597 | if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { |
---|
569 | | - spin_unlock_irqrestore(&slave_active_lock, flags); |
---|
570 | | - return -EBUSY; |
---|
| 598 | + err = -EBUSY; |
---|
| 599 | + goto unlock; |
---|
571 | 600 | } |
---|
572 | 601 | timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; |
---|
573 | 602 | if (timeri->master && timeri->timer) { |
---|
.. | .. |
---|
578 | 607 | SNDRV_TIMER_EVENT_CONTINUE); |
---|
579 | 608 | spin_unlock(&timeri->timer->lock); |
---|
580 | 609 | } |
---|
| 610 | + err = 1; /* delayed start */ |
---|
| 611 | + unlock: |
---|
581 | 612 | spin_unlock_irqrestore(&slave_active_lock, flags); |
---|
582 | | - return 1; /* delayed start */ |
---|
| 613 | + return err; |
---|
583 | 614 | } |
---|
584 | 615 | |
---|
585 | 616 | /* stop/pause a master timer */ |
---|
.. | .. |
---|
741 | 772 | timer->sticks = ticks; |
---|
742 | 773 | } |
---|
743 | 774 | |
---|
744 | | -/* |
---|
745 | | - * timer tasklet |
---|
746 | | - * |
---|
747 | | - */ |
---|
748 | | -static void snd_timer_tasklet(unsigned long arg) |
---|
| 775 | +/* call callbacks in timer ack list */ |
---|
| 776 | +static void snd_timer_process_callbacks(struct snd_timer *timer, |
---|
| 777 | + struct list_head *head) |
---|
749 | 778 | { |
---|
750 | | - struct snd_timer *timer = (struct snd_timer *) arg; |
---|
751 | 779 | struct snd_timer_instance *ti; |
---|
752 | | - struct list_head *p; |
---|
753 | 780 | unsigned long resolution, ticks; |
---|
754 | | - unsigned long flags; |
---|
755 | 781 | |
---|
756 | | - if (timer->card && timer->card->shutdown) |
---|
757 | | - return; |
---|
758 | | - |
---|
759 | | - spin_lock_irqsave(&timer->lock, flags); |
---|
760 | | - /* now process all callbacks */ |
---|
761 | | - while (!list_empty(&timer->sack_list_head)) { |
---|
762 | | - p = timer->sack_list_head.next; /* get first item */ |
---|
763 | | - ti = list_entry(p, struct snd_timer_instance, ack_list); |
---|
| 782 | + while (!list_empty(head)) { |
---|
| 783 | + ti = list_first_entry(head, struct snd_timer_instance, |
---|
| 784 | + ack_list); |
---|
764 | 785 | |
---|
765 | 786 | /* remove from ack_list and make empty */ |
---|
766 | | - list_del_init(p); |
---|
| 787 | + list_del_init(&ti->ack_list); |
---|
767 | 788 | |
---|
768 | | - ticks = ti->pticks; |
---|
769 | | - ti->pticks = 0; |
---|
770 | | - resolution = ti->resolution; |
---|
771 | | - |
---|
772 | | - ti->flags |= SNDRV_TIMER_IFLG_CALLBACK; |
---|
773 | | - spin_unlock(&timer->lock); |
---|
774 | | - if (ti->callback) |
---|
775 | | - ti->callback(ti, resolution, ticks); |
---|
776 | | - spin_lock(&timer->lock); |
---|
777 | | - ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK; |
---|
| 789 | + if (!(ti->flags & SNDRV_TIMER_IFLG_DEAD)) { |
---|
| 790 | + ticks = ti->pticks; |
---|
| 791 | + ti->pticks = 0; |
---|
| 792 | + resolution = ti->resolution; |
---|
| 793 | + ti->flags |= SNDRV_TIMER_IFLG_CALLBACK; |
---|
| 794 | + spin_unlock(&timer->lock); |
---|
| 795 | + if (ti->callback) |
---|
| 796 | + ti->callback(ti, resolution, ticks); |
---|
| 797 | + spin_lock(&timer->lock); |
---|
| 798 | + ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK; |
---|
| 799 | + } |
---|
778 | 800 | } |
---|
| 801 | +} |
---|
| 802 | + |
---|
| 803 | +/* clear pending instances from ack list */ |
---|
| 804 | +static void snd_timer_clear_callbacks(struct snd_timer *timer, |
---|
| 805 | + struct list_head *head) |
---|
| 806 | +{ |
---|
| 807 | + unsigned long flags; |
---|
| 808 | + |
---|
| 809 | + spin_lock_irqsave(&timer->lock, flags); |
---|
| 810 | + while (!list_empty(head)) |
---|
| 811 | + list_del_init(head->next); |
---|
| 812 | + spin_unlock_irqrestore(&timer->lock, flags); |
---|
| 813 | +} |
---|
| 814 | + |
---|
| 815 | +/* |
---|
| 816 | + * timer work |
---|
| 817 | + * |
---|
| 818 | + */ |
---|
| 819 | +static void snd_timer_work(struct work_struct *work) |
---|
| 820 | +{ |
---|
| 821 | + struct snd_timer *timer = container_of(work, struct snd_timer, task_work); |
---|
| 822 | + unsigned long flags; |
---|
| 823 | + |
---|
| 824 | + if (timer->card && timer->card->shutdown) { |
---|
| 825 | + snd_timer_clear_callbacks(timer, &timer->sack_list_head); |
---|
| 826 | + return; |
---|
| 827 | + } |
---|
| 828 | + |
---|
| 829 | + spin_lock_irqsave(&timer->lock, flags); |
---|
| 830 | + snd_timer_process_callbacks(timer, &timer->sack_list_head); |
---|
779 | 831 | spin_unlock_irqrestore(&timer->lock, flags); |
---|
780 | 832 | } |
---|
781 | 833 | |
---|
.. | .. |
---|
788 | 840 | void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) |
---|
789 | 841 | { |
---|
790 | 842 | struct snd_timer_instance *ti, *ts, *tmp; |
---|
791 | | - unsigned long resolution, ticks; |
---|
792 | | - struct list_head *p, *ack_list_head; |
---|
| 843 | + unsigned long resolution; |
---|
| 844 | + struct list_head *ack_list_head; |
---|
793 | 845 | unsigned long flags; |
---|
794 | | - int use_tasklet = 0; |
---|
| 846 | + bool use_work = false; |
---|
795 | 847 | |
---|
796 | 848 | if (timer == NULL) |
---|
797 | 849 | return; |
---|
798 | 850 | |
---|
799 | | - if (timer->card && timer->card->shutdown) |
---|
| 851 | + if (timer->card && timer->card->shutdown) { |
---|
| 852 | + snd_timer_clear_callbacks(timer, &timer->ack_list_head); |
---|
800 | 853 | return; |
---|
| 854 | + } |
---|
801 | 855 | |
---|
802 | 856 | spin_lock_irqsave(&timer->lock, flags); |
---|
803 | 857 | |
---|
.. | .. |
---|
811 | 865 | */ |
---|
812 | 866 | list_for_each_entry_safe(ti, tmp, &timer->active_list_head, |
---|
813 | 867 | active_list) { |
---|
| 868 | + if (ti->flags & SNDRV_TIMER_IFLG_DEAD) |
---|
| 869 | + continue; |
---|
814 | 870 | if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING)) |
---|
815 | 871 | continue; |
---|
816 | 872 | ti->pticks += ticks_left; |
---|
.. | .. |
---|
828 | 884 | --timer->running; |
---|
829 | 885 | list_del_init(&ti->active_list); |
---|
830 | 886 | } |
---|
831 | | - if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || |
---|
| 887 | + if ((timer->hw.flags & SNDRV_TIMER_HW_WORK) || |
---|
832 | 888 | (ti->flags & SNDRV_TIMER_IFLG_FAST)) |
---|
833 | 889 | ack_list_head = &timer->ack_list_head; |
---|
834 | 890 | else |
---|
.. | .. |
---|
860 | 916 | } |
---|
861 | 917 | |
---|
862 | 918 | /* now process all fast callbacks */ |
---|
863 | | - while (!list_empty(&timer->ack_list_head)) { |
---|
864 | | - p = timer->ack_list_head.next; /* get first item */ |
---|
865 | | - ti = list_entry(p, struct snd_timer_instance, ack_list); |
---|
866 | | - |
---|
867 | | - /* remove from ack_list and make empty */ |
---|
868 | | - list_del_init(p); |
---|
869 | | - |
---|
870 | | - ticks = ti->pticks; |
---|
871 | | - ti->pticks = 0; |
---|
872 | | - |
---|
873 | | - ti->flags |= SNDRV_TIMER_IFLG_CALLBACK; |
---|
874 | | - spin_unlock(&timer->lock); |
---|
875 | | - if (ti->callback) |
---|
876 | | - ti->callback(ti, resolution, ticks); |
---|
877 | | - spin_lock(&timer->lock); |
---|
878 | | - ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK; |
---|
879 | | - } |
---|
| 919 | + snd_timer_process_callbacks(timer, &timer->ack_list_head); |
---|
880 | 920 | |
---|
881 | 921 | /* do we have any slow callbacks? */ |
---|
882 | | - use_tasklet = !list_empty(&timer->sack_list_head); |
---|
| 922 | + use_work = !list_empty(&timer->sack_list_head); |
---|
883 | 923 | spin_unlock_irqrestore(&timer->lock, flags); |
---|
884 | 924 | |
---|
885 | | - if (use_tasklet) |
---|
886 | | - tasklet_schedule(&timer->task_queue); |
---|
| 925 | + if (use_work) |
---|
| 926 | + queue_work(system_highpri_wq, &timer->task_work); |
---|
887 | 927 | } |
---|
888 | 928 | EXPORT_SYMBOL(snd_timer_interrupt); |
---|
889 | 929 | |
---|
.. | .. |
---|
896 | 936 | { |
---|
897 | 937 | struct snd_timer *timer; |
---|
898 | 938 | int err; |
---|
899 | | - static struct snd_device_ops ops = { |
---|
| 939 | + static const struct snd_device_ops ops = { |
---|
900 | 940 | .dev_free = snd_timer_dev_free, |
---|
901 | 941 | .dev_register = snd_timer_dev_register, |
---|
902 | 942 | .dev_disconnect = snd_timer_dev_disconnect, |
---|
.. | .. |
---|
927 | 967 | INIT_LIST_HEAD(&timer->ack_list_head); |
---|
928 | 968 | INIT_LIST_HEAD(&timer->sack_list_head); |
---|
929 | 969 | spin_lock_init(&timer->lock); |
---|
930 | | - tasklet_init(&timer->task_queue, snd_timer_tasklet, |
---|
931 | | - (unsigned long)timer); |
---|
| 970 | + INIT_WORK(&timer->task_work, snd_timer_work); |
---|
932 | 971 | timer->max_instances = 1000; /* default limit per timer */ |
---|
933 | 972 | if (card != NULL) { |
---|
934 | 973 | timer->module = card->module; |
---|
.. | .. |
---|
1031 | 1070 | return 0; |
---|
1032 | 1071 | } |
---|
1033 | 1072 | |
---|
1034 | | -void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp) |
---|
| 1073 | +void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tstamp) |
---|
1035 | 1074 | { |
---|
1036 | 1075 | unsigned long flags; |
---|
1037 | 1076 | unsigned long resolution = 0; |
---|
.. | .. |
---|
1159 | 1198 | return 0; |
---|
1160 | 1199 | } |
---|
1161 | 1200 | |
---|
1162 | | -static struct snd_timer_hardware snd_timer_system = |
---|
| 1201 | +static const struct snd_timer_hardware snd_timer_system = |
---|
1163 | 1202 | { |
---|
1164 | | - .flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_TASKLET, |
---|
| 1203 | + .flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_WORK, |
---|
1165 | 1204 | .resolution = 1000000000L / HZ, |
---|
1166 | 1205 | .ticks = 10000000L, |
---|
1167 | 1206 | .close = snd_timer_s_close, |
---|
.. | .. |
---|
1241 | 1280 | list_for_each_entry(ti, &timer->open_list_head, open_list) |
---|
1242 | 1281 | snd_iprintf(buffer, " Client %s : %s\n", |
---|
1243 | 1282 | ti->owner ? ti->owner : "unknown", |
---|
1244 | | - ti->flags & (SNDRV_TIMER_IFLG_START | |
---|
1245 | | - SNDRV_TIMER_IFLG_RUNNING) |
---|
| 1283 | + (ti->flags & (SNDRV_TIMER_IFLG_START | |
---|
| 1284 | + SNDRV_TIMER_IFLG_RUNNING)) |
---|
1246 | 1285 | ? "running" : "stopped"); |
---|
1247 | 1286 | } |
---|
1248 | 1287 | mutex_unlock(®ister_mutex); |
---|
.. | .. |
---|
1306 | 1345 | } |
---|
1307 | 1346 | __wake: |
---|
1308 | 1347 | spin_unlock(&tu->qlock); |
---|
1309 | | - kill_fasync(&tu->fasync, SIGIO, POLL_IN); |
---|
| 1348 | + snd_kill_fasync(tu->fasync, SIGIO, POLL_IN); |
---|
1310 | 1349 | wake_up(&tu->qchange_sleep); |
---|
1311 | 1350 | } |
---|
1312 | 1351 | |
---|
1313 | 1352 | static void snd_timer_user_append_to_tqueue(struct snd_timer_user *tu, |
---|
1314 | | - struct snd_timer_tread *tread) |
---|
| 1353 | + struct snd_timer_tread64 *tread) |
---|
1315 | 1354 | { |
---|
1316 | 1355 | if (tu->qused >= tu->queue_size) { |
---|
1317 | 1356 | tu->overrun++; |
---|
.. | .. |
---|
1324 | 1363 | |
---|
1325 | 1364 | static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, |
---|
1326 | 1365 | int event, |
---|
1327 | | - struct timespec *tstamp, |
---|
| 1366 | + struct timespec64 *tstamp, |
---|
1328 | 1367 | unsigned long resolution) |
---|
1329 | 1368 | { |
---|
1330 | 1369 | struct snd_timer_user *tu = timeri->callback_data; |
---|
1331 | | - struct snd_timer_tread r1; |
---|
| 1370 | + struct snd_timer_tread64 r1; |
---|
1332 | 1371 | unsigned long flags; |
---|
1333 | 1372 | |
---|
1334 | 1373 | if (event >= SNDRV_TIMER_EVENT_START && |
---|
.. | .. |
---|
1338 | 1377 | return; |
---|
1339 | 1378 | memset(&r1, 0, sizeof(r1)); |
---|
1340 | 1379 | r1.event = event; |
---|
1341 | | - r1.tstamp = *tstamp; |
---|
| 1380 | + r1.tstamp_sec = tstamp->tv_sec; |
---|
| 1381 | + r1.tstamp_nsec = tstamp->tv_nsec; |
---|
1342 | 1382 | r1.val = resolution; |
---|
1343 | 1383 | spin_lock_irqsave(&tu->qlock, flags); |
---|
1344 | 1384 | snd_timer_user_append_to_tqueue(tu, &r1); |
---|
1345 | 1385 | spin_unlock_irqrestore(&tu->qlock, flags); |
---|
1346 | | - kill_fasync(&tu->fasync, SIGIO, POLL_IN); |
---|
| 1386 | + snd_kill_fasync(tu->fasync, SIGIO, POLL_IN); |
---|
1347 | 1387 | wake_up(&tu->qchange_sleep); |
---|
1348 | 1388 | } |
---|
1349 | 1389 | |
---|
.. | .. |
---|
1360 | 1400 | unsigned long ticks) |
---|
1361 | 1401 | { |
---|
1362 | 1402 | struct snd_timer_user *tu = timeri->callback_data; |
---|
1363 | | - struct snd_timer_tread *r, r1; |
---|
1364 | | - struct timespec tstamp; |
---|
| 1403 | + struct snd_timer_tread64 *r, r1; |
---|
| 1404 | + struct timespec64 tstamp; |
---|
1365 | 1405 | int prev, append = 0; |
---|
1366 | 1406 | |
---|
1367 | 1407 | memset(&r1, 0, sizeof(r1)); |
---|
.. | .. |
---|
1374 | 1414 | } |
---|
1375 | 1415 | if (tu->last_resolution != resolution || ticks > 0) { |
---|
1376 | 1416 | if (timer_tstamp_monotonic) |
---|
1377 | | - ktime_get_ts(&tstamp); |
---|
| 1417 | + ktime_get_ts64(&tstamp); |
---|
1378 | 1418 | else |
---|
1379 | | - getnstimeofday(&tstamp); |
---|
| 1419 | + ktime_get_real_ts64(&tstamp); |
---|
1380 | 1420 | } |
---|
1381 | 1421 | if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && |
---|
1382 | 1422 | tu->last_resolution != resolution) { |
---|
1383 | 1423 | r1.event = SNDRV_TIMER_EVENT_RESOLUTION; |
---|
1384 | | - r1.tstamp = tstamp; |
---|
| 1424 | + r1.tstamp_sec = tstamp.tv_sec; |
---|
| 1425 | + r1.tstamp_nsec = tstamp.tv_nsec; |
---|
1385 | 1426 | r1.val = resolution; |
---|
1386 | 1427 | snd_timer_user_append_to_tqueue(tu, &r1); |
---|
1387 | 1428 | tu->last_resolution = resolution; |
---|
.. | .. |
---|
1395 | 1436 | prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1; |
---|
1396 | 1437 | r = &tu->tqueue[prev]; |
---|
1397 | 1438 | if (r->event == SNDRV_TIMER_EVENT_TICK) { |
---|
1398 | | - r->tstamp = tstamp; |
---|
| 1439 | + r->tstamp_sec = tstamp.tv_sec; |
---|
| 1440 | + r->tstamp_nsec = tstamp.tv_nsec; |
---|
1399 | 1441 | r->val += ticks; |
---|
1400 | 1442 | append++; |
---|
1401 | 1443 | goto __wake; |
---|
1402 | 1444 | } |
---|
1403 | 1445 | } |
---|
1404 | 1446 | r1.event = SNDRV_TIMER_EVENT_TICK; |
---|
1405 | | - r1.tstamp = tstamp; |
---|
| 1447 | + r1.tstamp_sec = tstamp.tv_sec; |
---|
| 1448 | + r1.tstamp_nsec = tstamp.tv_nsec; |
---|
1406 | 1449 | r1.val = ticks; |
---|
1407 | 1450 | snd_timer_user_append_to_tqueue(tu, &r1); |
---|
1408 | 1451 | append++; |
---|
.. | .. |
---|
1410 | 1453 | spin_unlock(&tu->qlock); |
---|
1411 | 1454 | if (append == 0) |
---|
1412 | 1455 | return; |
---|
1413 | | - kill_fasync(&tu->fasync, SIGIO, POLL_IN); |
---|
| 1456 | + snd_kill_fasync(tu->fasync, SIGIO, POLL_IN); |
---|
1414 | 1457 | wake_up(&tu->qchange_sleep); |
---|
1415 | 1458 | } |
---|
1416 | 1459 | |
---|
1417 | 1460 | static int realloc_user_queue(struct snd_timer_user *tu, int size) |
---|
1418 | 1461 | { |
---|
1419 | 1462 | struct snd_timer_read *queue = NULL; |
---|
1420 | | - struct snd_timer_tread *tqueue = NULL; |
---|
| 1463 | + struct snd_timer_tread64 *tqueue = NULL; |
---|
1421 | 1464 | |
---|
1422 | 1465 | if (tu->tread) { |
---|
1423 | 1466 | tqueue = kcalloc(size, sizeof(*tqueue), GFP_KERNEL); |
---|
.. | .. |
---|
1446 | 1489 | struct snd_timer_user *tu; |
---|
1447 | 1490 | int err; |
---|
1448 | 1491 | |
---|
1449 | | - err = nonseekable_open(inode, file); |
---|
| 1492 | + err = stream_open(inode, file); |
---|
1450 | 1493 | if (err < 0) |
---|
1451 | 1494 | return err; |
---|
1452 | 1495 | |
---|
.. | .. |
---|
1473 | 1516 | tu = file->private_data; |
---|
1474 | 1517 | file->private_data = NULL; |
---|
1475 | 1518 | mutex_lock(&tu->ioctl_lock); |
---|
1476 | | - if (tu->timeri) |
---|
| 1519 | + if (tu->timeri) { |
---|
1477 | 1520 | snd_timer_close(tu->timeri); |
---|
| 1521 | + snd_timer_instance_free(tu->timeri); |
---|
| 1522 | + } |
---|
1478 | 1523 | mutex_unlock(&tu->ioctl_lock); |
---|
| 1524 | + snd_fasync_free(tu->fasync); |
---|
1479 | 1525 | kfree(tu->queue); |
---|
1480 | 1526 | kfree(tu->tqueue); |
---|
1481 | 1527 | kfree(tu); |
---|
.. | .. |
---|
1715 | 1761 | tu = file->private_data; |
---|
1716 | 1762 | if (tu->timeri) { |
---|
1717 | 1763 | snd_timer_close(tu->timeri); |
---|
| 1764 | + snd_timer_instance_free(tu->timeri); |
---|
1718 | 1765 | tu->timeri = NULL; |
---|
1719 | 1766 | } |
---|
1720 | 1767 | if (copy_from_user(&tselect, _tselect, sizeof(tselect))) { |
---|
.. | .. |
---|
1724 | 1771 | sprintf(str, "application %i", current->pid); |
---|
1725 | 1772 | if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE) |
---|
1726 | 1773 | tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION; |
---|
1727 | | - err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid); |
---|
1728 | | - if (err < 0) |
---|
| 1774 | + tu->timeri = snd_timer_instance_new(str); |
---|
| 1775 | + if (!tu->timeri) { |
---|
| 1776 | + err = -ENOMEM; |
---|
1729 | 1777 | goto __err; |
---|
| 1778 | + } |
---|
1730 | 1779 | |
---|
1731 | 1780 | tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; |
---|
1732 | 1781 | tu->timeri->callback = tu->tread |
---|
.. | .. |
---|
1734 | 1783 | tu->timeri->ccallback = snd_timer_user_ccallback; |
---|
1735 | 1784 | tu->timeri->callback_data = (void *)tu; |
---|
1736 | 1785 | tu->timeri->disconnect = snd_timer_user_disconnect; |
---|
| 1786 | + |
---|
| 1787 | + err = snd_timer_open(tu->timeri, &tselect.id, current->pid); |
---|
| 1788 | + if (err < 0) { |
---|
| 1789 | + snd_timer_instance_free(tu->timeri); |
---|
| 1790 | + tu->timeri = NULL; |
---|
| 1791 | + } |
---|
1737 | 1792 | |
---|
1738 | 1793 | __err: |
---|
1739 | 1794 | return err; |
---|
.. | .. |
---|
1845 | 1900 | tu->qhead = tu->qtail = tu->qused = 0; |
---|
1846 | 1901 | if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) { |
---|
1847 | 1902 | if (tu->tread) { |
---|
1848 | | - struct snd_timer_tread tread; |
---|
| 1903 | + struct snd_timer_tread64 tread; |
---|
1849 | 1904 | memset(&tread, 0, sizeof(tread)); |
---|
1850 | 1905 | tread.event = SNDRV_TIMER_EVENT_EARLY; |
---|
1851 | | - tread.tstamp.tv_sec = 0; |
---|
1852 | | - tread.tstamp.tv_nsec = 0; |
---|
| 1906 | + tread.tstamp_sec = 0; |
---|
| 1907 | + tread.tstamp_nsec = 0; |
---|
1853 | 1908 | tread.val = 0; |
---|
1854 | 1909 | snd_timer_user_append_to_tqueue(tu, &tread); |
---|
1855 | 1910 | } else { |
---|
.. | .. |
---|
1870 | 1925 | return err; |
---|
1871 | 1926 | } |
---|
1872 | 1927 | |
---|
1873 | | -static int snd_timer_user_status(struct file *file, |
---|
1874 | | - struct snd_timer_status __user *_status) |
---|
1875 | | -{ |
---|
| 1928 | +static int snd_timer_user_status32(struct file *file, |
---|
| 1929 | + struct snd_timer_status32 __user *_status) |
---|
| 1930 | + { |
---|
1876 | 1931 | struct snd_timer_user *tu; |
---|
1877 | | - struct snd_timer_status status; |
---|
| 1932 | + struct snd_timer_status32 status; |
---|
1878 | 1933 | |
---|
1879 | 1934 | tu = file->private_data; |
---|
1880 | 1935 | if (!tu->timeri) |
---|
1881 | 1936 | return -EBADFD; |
---|
1882 | 1937 | memset(&status, 0, sizeof(status)); |
---|
1883 | | - status.tstamp = tu->tstamp; |
---|
| 1938 | + status.tstamp_sec = tu->tstamp.tv_sec; |
---|
| 1939 | + status.tstamp_nsec = tu->tstamp.tv_nsec; |
---|
| 1940 | + status.resolution = snd_timer_resolution(tu->timeri); |
---|
| 1941 | + status.lost = tu->timeri->lost; |
---|
| 1942 | + status.overrun = tu->overrun; |
---|
| 1943 | + spin_lock_irq(&tu->qlock); |
---|
| 1944 | + status.queue = tu->qused; |
---|
| 1945 | + spin_unlock_irq(&tu->qlock); |
---|
| 1946 | + if (copy_to_user(_status, &status, sizeof(status))) |
---|
| 1947 | + return -EFAULT; |
---|
| 1948 | + return 0; |
---|
| 1949 | +} |
---|
| 1950 | + |
---|
| 1951 | +static int snd_timer_user_status64(struct file *file, |
---|
| 1952 | + struct snd_timer_status64 __user *_status) |
---|
| 1953 | +{ |
---|
| 1954 | + struct snd_timer_user *tu; |
---|
| 1955 | + struct snd_timer_status64 status; |
---|
| 1956 | + |
---|
| 1957 | + tu = file->private_data; |
---|
| 1958 | + if (!tu->timeri) |
---|
| 1959 | + return -EBADFD; |
---|
| 1960 | + memset(&status, 0, sizeof(status)); |
---|
| 1961 | + status.tstamp_sec = tu->tstamp.tv_sec; |
---|
| 1962 | + status.tstamp_nsec = tu->tstamp.tv_nsec; |
---|
1884 | 1963 | status.resolution = snd_timer_resolution(tu->timeri); |
---|
1885 | 1964 | status.lost = tu->timeri->lost; |
---|
1886 | 1965 | status.overrun = tu->overrun; |
---|
.. | .. |
---|
1903 | 1982 | snd_timer_stop(tu->timeri); |
---|
1904 | 1983 | tu->timeri->lost = 0; |
---|
1905 | 1984 | tu->last_resolution = 0; |
---|
1906 | | - return (err = snd_timer_start(tu->timeri, tu->ticks)) < 0 ? err : 0; |
---|
| 1985 | + err = snd_timer_start(tu->timeri, tu->ticks); |
---|
| 1986 | + if (err < 0) |
---|
| 1987 | + return err; |
---|
| 1988 | + return 0; |
---|
1907 | 1989 | } |
---|
1908 | 1990 | |
---|
1909 | 1991 | static int snd_timer_user_stop(struct file *file) |
---|
.. | .. |
---|
1914 | 1996 | tu = file->private_data; |
---|
1915 | 1997 | if (!tu->timeri) |
---|
1916 | 1998 | return -EBADFD; |
---|
1917 | | - return (err = snd_timer_stop(tu->timeri)) < 0 ? err : 0; |
---|
| 1999 | + err = snd_timer_stop(tu->timeri); |
---|
| 2000 | + if (err < 0) |
---|
| 2001 | + return err; |
---|
| 2002 | + return 0; |
---|
1918 | 2003 | } |
---|
1919 | 2004 | |
---|
1920 | 2005 | static int snd_timer_user_continue(struct file *file) |
---|
.. | .. |
---|
1929 | 2014 | if (!(tu->timeri->flags & SNDRV_TIMER_IFLG_PAUSED)) |
---|
1930 | 2015 | return snd_timer_user_start(file); |
---|
1931 | 2016 | tu->timeri->lost = 0; |
---|
1932 | | - return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0; |
---|
| 2017 | + err = snd_timer_continue(tu->timeri); |
---|
| 2018 | + if (err < 0) |
---|
| 2019 | + return err; |
---|
| 2020 | + return 0; |
---|
1933 | 2021 | } |
---|
1934 | 2022 | |
---|
1935 | 2023 | static int snd_timer_user_pause(struct file *file) |
---|
.. | .. |
---|
1940 | 2028 | tu = file->private_data; |
---|
1941 | 2029 | if (!tu->timeri) |
---|
1942 | 2030 | return -EBADFD; |
---|
1943 | | - return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0; |
---|
| 2031 | + err = snd_timer_pause(tu->timeri); |
---|
| 2032 | + if (err < 0) |
---|
| 2033 | + return err; |
---|
| 2034 | + return 0; |
---|
| 2035 | +} |
---|
| 2036 | + |
---|
| 2037 | +static int snd_timer_user_tread(void __user *argp, struct snd_timer_user *tu, |
---|
| 2038 | + unsigned int cmd, bool compat) |
---|
| 2039 | +{ |
---|
| 2040 | + int __user *p = argp; |
---|
| 2041 | + int xarg, old_tread; |
---|
| 2042 | + |
---|
| 2043 | + if (tu->timeri) /* too late */ |
---|
| 2044 | + return -EBUSY; |
---|
| 2045 | + if (get_user(xarg, p)) |
---|
| 2046 | + return -EFAULT; |
---|
| 2047 | + |
---|
| 2048 | + old_tread = tu->tread; |
---|
| 2049 | + |
---|
| 2050 | + if (!xarg) |
---|
| 2051 | + tu->tread = TREAD_FORMAT_NONE; |
---|
| 2052 | + else if (cmd == SNDRV_TIMER_IOCTL_TREAD64 || |
---|
| 2053 | + (IS_ENABLED(CONFIG_64BIT) && !compat)) |
---|
| 2054 | + tu->tread = TREAD_FORMAT_TIME64; |
---|
| 2055 | + else |
---|
| 2056 | + tu->tread = TREAD_FORMAT_TIME32; |
---|
| 2057 | + |
---|
| 2058 | + if (tu->tread != old_tread && |
---|
| 2059 | + realloc_user_queue(tu, tu->queue_size) < 0) { |
---|
| 2060 | + tu->tread = old_tread; |
---|
| 2061 | + return -ENOMEM; |
---|
| 2062 | + } |
---|
| 2063 | + |
---|
| 2064 | + return 0; |
---|
1944 | 2065 | } |
---|
1945 | 2066 | |
---|
1946 | 2067 | enum { |
---|
.. | .. |
---|
1951 | 2072 | }; |
---|
1952 | 2073 | |
---|
1953 | 2074 | static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd, |
---|
1954 | | - unsigned long arg) |
---|
| 2075 | + unsigned long arg, bool compat) |
---|
1955 | 2076 | { |
---|
1956 | 2077 | struct snd_timer_user *tu; |
---|
1957 | 2078 | void __user *argp = (void __user *)arg; |
---|
.. | .. |
---|
1963 | 2084 | return put_user(SNDRV_TIMER_VERSION, p) ? -EFAULT : 0; |
---|
1964 | 2085 | case SNDRV_TIMER_IOCTL_NEXT_DEVICE: |
---|
1965 | 2086 | return snd_timer_user_next_device(argp); |
---|
1966 | | - case SNDRV_TIMER_IOCTL_TREAD: |
---|
1967 | | - { |
---|
1968 | | - int xarg, old_tread; |
---|
1969 | | - |
---|
1970 | | - if (tu->timeri) /* too late */ |
---|
1971 | | - return -EBUSY; |
---|
1972 | | - if (get_user(xarg, p)) |
---|
1973 | | - return -EFAULT; |
---|
1974 | | - old_tread = tu->tread; |
---|
1975 | | - tu->tread = xarg ? 1 : 0; |
---|
1976 | | - if (tu->tread != old_tread && |
---|
1977 | | - realloc_user_queue(tu, tu->queue_size) < 0) { |
---|
1978 | | - tu->tread = old_tread; |
---|
1979 | | - return -ENOMEM; |
---|
1980 | | - } |
---|
1981 | | - return 0; |
---|
1982 | | - } |
---|
| 2087 | + case SNDRV_TIMER_IOCTL_TREAD_OLD: |
---|
| 2088 | + case SNDRV_TIMER_IOCTL_TREAD64: |
---|
| 2089 | + return snd_timer_user_tread(argp, tu, cmd, compat); |
---|
1983 | 2090 | case SNDRV_TIMER_IOCTL_GINFO: |
---|
1984 | 2091 | return snd_timer_user_ginfo(file, argp); |
---|
1985 | 2092 | case SNDRV_TIMER_IOCTL_GPARAMS: |
---|
.. | .. |
---|
1992 | 2099 | return snd_timer_user_info(file, argp); |
---|
1993 | 2100 | case SNDRV_TIMER_IOCTL_PARAMS: |
---|
1994 | 2101 | return snd_timer_user_params(file, argp); |
---|
1995 | | - case SNDRV_TIMER_IOCTL_STATUS: |
---|
1996 | | - return snd_timer_user_status(file, argp); |
---|
| 2102 | + case SNDRV_TIMER_IOCTL_STATUS32: |
---|
| 2103 | + return snd_timer_user_status32(file, argp); |
---|
| 2104 | + case SNDRV_TIMER_IOCTL_STATUS64: |
---|
| 2105 | + return snd_timer_user_status64(file, argp); |
---|
1997 | 2106 | case SNDRV_TIMER_IOCTL_START: |
---|
1998 | 2107 | case SNDRV_TIMER_IOCTL_START_OLD: |
---|
1999 | 2108 | return snd_timer_user_start(file); |
---|
.. | .. |
---|
2017 | 2126 | long ret; |
---|
2018 | 2127 | |
---|
2019 | 2128 | mutex_lock(&tu->ioctl_lock); |
---|
2020 | | - ret = __snd_timer_user_ioctl(file, cmd, arg); |
---|
| 2129 | + ret = __snd_timer_user_ioctl(file, cmd, arg, false); |
---|
2021 | 2130 | mutex_unlock(&tu->ioctl_lock); |
---|
2022 | 2131 | return ret; |
---|
2023 | 2132 | } |
---|
.. | .. |
---|
2027 | 2136 | struct snd_timer_user *tu; |
---|
2028 | 2137 | |
---|
2029 | 2138 | tu = file->private_data; |
---|
2030 | | - return fasync_helper(fd, file, on, &tu->fasync); |
---|
| 2139 | + return snd_fasync_helper(fd, file, on, &tu->fasync); |
---|
2031 | 2140 | } |
---|
2032 | 2141 | |
---|
2033 | 2142 | static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, |
---|
2034 | 2143 | size_t count, loff_t *offset) |
---|
2035 | 2144 | { |
---|
| 2145 | + struct snd_timer_tread64 *tread; |
---|
| 2146 | + struct snd_timer_tread32 tread32; |
---|
2036 | 2147 | struct snd_timer_user *tu; |
---|
2037 | 2148 | long result = 0, unit; |
---|
2038 | 2149 | int qhead; |
---|
2039 | 2150 | int err = 0; |
---|
2040 | 2151 | |
---|
2041 | 2152 | tu = file->private_data; |
---|
2042 | | - unit = tu->tread ? sizeof(struct snd_timer_tread) : sizeof(struct snd_timer_read); |
---|
| 2153 | + switch (tu->tread) { |
---|
| 2154 | + case TREAD_FORMAT_TIME64: |
---|
| 2155 | + unit = sizeof(struct snd_timer_tread64); |
---|
| 2156 | + break; |
---|
| 2157 | + case TREAD_FORMAT_TIME32: |
---|
| 2158 | + unit = sizeof(struct snd_timer_tread32); |
---|
| 2159 | + break; |
---|
| 2160 | + case TREAD_FORMAT_NONE: |
---|
| 2161 | + unit = sizeof(struct snd_timer_read); |
---|
| 2162 | + break; |
---|
| 2163 | + default: |
---|
| 2164 | + WARN_ONCE(1, "Corrupt snd_timer_user\n"); |
---|
| 2165 | + return -ENOTSUPP; |
---|
| 2166 | + } |
---|
| 2167 | + |
---|
2043 | 2168 | mutex_lock(&tu->ioctl_lock); |
---|
2044 | 2169 | spin_lock_irq(&tu->qlock); |
---|
2045 | 2170 | while ((long)count - result >= unit) { |
---|
.. | .. |
---|
2078 | 2203 | tu->qused--; |
---|
2079 | 2204 | spin_unlock_irq(&tu->qlock); |
---|
2080 | 2205 | |
---|
2081 | | - if (tu->tread) { |
---|
2082 | | - if (copy_to_user(buffer, &tu->tqueue[qhead], |
---|
2083 | | - sizeof(struct snd_timer_tread))) |
---|
| 2206 | + tread = &tu->tqueue[qhead]; |
---|
| 2207 | + |
---|
| 2208 | + switch (tu->tread) { |
---|
| 2209 | + case TREAD_FORMAT_TIME64: |
---|
| 2210 | + if (copy_to_user(buffer, tread, |
---|
| 2211 | + sizeof(struct snd_timer_tread64))) |
---|
2084 | 2212 | err = -EFAULT; |
---|
2085 | | - } else { |
---|
| 2213 | + break; |
---|
| 2214 | + case TREAD_FORMAT_TIME32: |
---|
| 2215 | + memset(&tread32, 0, sizeof(tread32)); |
---|
| 2216 | + tread32 = (struct snd_timer_tread32) { |
---|
| 2217 | + .event = tread->event, |
---|
| 2218 | + .tstamp_sec = tread->tstamp_sec, |
---|
| 2219 | + .tstamp_nsec = tread->tstamp_nsec, |
---|
| 2220 | + .val = tread->val, |
---|
| 2221 | + }; |
---|
| 2222 | + |
---|
| 2223 | + if (copy_to_user(buffer, &tread32, sizeof(tread32))) |
---|
| 2224 | + err = -EFAULT; |
---|
| 2225 | + break; |
---|
| 2226 | + case TREAD_FORMAT_NONE: |
---|
2086 | 2227 | if (copy_to_user(buffer, &tu->queue[qhead], |
---|
2087 | 2228 | sizeof(struct snd_timer_read))) |
---|
2088 | 2229 | err = -EFAULT; |
---|
| 2230 | + break; |
---|
| 2231 | + default: |
---|
| 2232 | + err = -ENOTSUPP; |
---|
| 2233 | + break; |
---|
2089 | 2234 | } |
---|
2090 | 2235 | |
---|
2091 | 2236 | spin_lock_irq(&tu->qlock); |
---|