| .. | .. |
|---|
| 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); |
|---|