diff options
Diffstat (limited to 'sound/core/timer.c')
-rw-r--r-- | sound/core/timer.c | 67 |
1 files changed, 54 insertions, 13 deletions
diff --git a/sound/core/timer.c b/sound/core/timer.c index 6cdd04a45962..15e82a656d96 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c | |||
@@ -180,7 +180,7 @@ static void snd_timer_request(struct snd_timer_id *tid) | |||
180 | * | 180 | * |
181 | * call this with register_mutex down. | 181 | * call this with register_mutex down. |
182 | */ | 182 | */ |
183 | static void snd_timer_check_slave(struct snd_timer_instance *slave) | 183 | static int snd_timer_check_slave(struct snd_timer_instance *slave) |
184 | { | 184 | { |
185 | struct snd_timer *timer; | 185 | struct snd_timer *timer; |
186 | struct snd_timer_instance *master; | 186 | struct snd_timer_instance *master; |
@@ -190,16 +190,21 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave) | |||
190 | list_for_each_entry(master, &timer->open_list_head, open_list) { | 190 | list_for_each_entry(master, &timer->open_list_head, open_list) { |
191 | if (slave->slave_class == master->slave_class && | 191 | if (slave->slave_class == master->slave_class && |
192 | slave->slave_id == master->slave_id) { | 192 | slave->slave_id == master->slave_id) { |
193 | if (master->timer->num_instances >= | ||
194 | master->timer->max_instances) | ||
195 | return -EBUSY; | ||
193 | list_move_tail(&slave->open_list, | 196 | list_move_tail(&slave->open_list, |
194 | &master->slave_list_head); | 197 | &master->slave_list_head); |
198 | master->timer->num_instances++; | ||
195 | spin_lock_irq(&slave_active_lock); | 199 | spin_lock_irq(&slave_active_lock); |
196 | slave->master = master; | 200 | slave->master = master; |
197 | slave->timer = master->timer; | 201 | slave->timer = master->timer; |
198 | spin_unlock_irq(&slave_active_lock); | 202 | spin_unlock_irq(&slave_active_lock); |
199 | return; | 203 | return 0; |
200 | } | 204 | } |
201 | } | 205 | } |
202 | } | 206 | } |
207 | return 0; | ||
203 | } | 208 | } |
204 | 209 | ||
205 | /* | 210 | /* |
@@ -208,7 +213,7 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave) | |||
208 | * | 213 | * |
209 | * call this with register_mutex down. | 214 | * call this with register_mutex down. |
210 | */ | 215 | */ |
211 | static void snd_timer_check_master(struct snd_timer_instance *master) | 216 | static int snd_timer_check_master(struct snd_timer_instance *master) |
212 | { | 217 | { |
213 | struct snd_timer_instance *slave, *tmp; | 218 | struct snd_timer_instance *slave, *tmp; |
214 | 219 | ||
@@ -216,7 +221,11 @@ static void snd_timer_check_master(struct snd_timer_instance *master) | |||
216 | list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) { | 221 | list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) { |
217 | if (slave->slave_class == master->slave_class && | 222 | if (slave->slave_class == master->slave_class && |
218 | slave->slave_id == master->slave_id) { | 223 | slave->slave_id == master->slave_id) { |
224 | if (master->timer->num_instances >= | ||
225 | master->timer->max_instances) | ||
226 | return -EBUSY; | ||
219 | list_move_tail(&slave->open_list, &master->slave_list_head); | 227 | list_move_tail(&slave->open_list, &master->slave_list_head); |
228 | master->timer->num_instances++; | ||
220 | spin_lock_irq(&slave_active_lock); | 229 | spin_lock_irq(&slave_active_lock); |
221 | spin_lock(&master->timer->lock); | 230 | spin_lock(&master->timer->lock); |
222 | slave->master = master; | 231 | slave->master = master; |
@@ -228,8 +237,11 @@ static void snd_timer_check_master(struct snd_timer_instance *master) | |||
228 | spin_unlock_irq(&slave_active_lock); | 237 | spin_unlock_irq(&slave_active_lock); |
229 | } | 238 | } |
230 | } | 239 | } |
240 | return 0; | ||
231 | } | 241 | } |
232 | 242 | ||
243 | static int snd_timer_close_locked(struct snd_timer_instance *timeri); | ||
244 | |||
233 | /* | 245 | /* |
234 | * open a timer instance | 246 | * open a timer instance |
235 | * when opening a master, the slave id must be here given. | 247 | * when opening a master, the slave id must be here given. |
@@ -240,6 +252,7 @@ int snd_timer_open(struct snd_timer_instance **ti, | |||
240 | { | 252 | { |
241 | struct snd_timer *timer; | 253 | struct snd_timer *timer; |
242 | struct snd_timer_instance *timeri = NULL; | 254 | struct snd_timer_instance *timeri = NULL; |
255 | int err; | ||
243 | 256 | ||
244 | if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) { | 257 | if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) { |
245 | /* open a slave instance */ | 258 | /* open a slave instance */ |
@@ -259,10 +272,14 @@ int snd_timer_open(struct snd_timer_instance **ti, | |||
259 | timeri->slave_id = tid->device; | 272 | timeri->slave_id = tid->device; |
260 | timeri->flags |= SNDRV_TIMER_IFLG_SLAVE; | 273 | timeri->flags |= SNDRV_TIMER_IFLG_SLAVE; |
261 | list_add_tail(&timeri->open_list, &snd_timer_slave_list); | 274 | list_add_tail(&timeri->open_list, &snd_timer_slave_list); |
262 | snd_timer_check_slave(timeri); | 275 | err = snd_timer_check_slave(timeri); |
276 | if (err < 0) { | ||
277 | snd_timer_close_locked(timeri); | ||
278 | timeri = NULL; | ||
279 | } | ||
263 | mutex_unlock(®ister_mutex); | 280 | mutex_unlock(®ister_mutex); |
264 | *ti = timeri; | 281 | *ti = timeri; |
265 | return 0; | 282 | return err; |
266 | } | 283 | } |
267 | 284 | ||
268 | /* open a master instance */ | 285 | /* open a master instance */ |
@@ -288,6 +305,10 @@ int snd_timer_open(struct snd_timer_instance **ti, | |||
288 | return -EBUSY; | 305 | return -EBUSY; |
289 | } | 306 | } |
290 | } | 307 | } |
308 | if (timer->num_instances >= timer->max_instances) { | ||
309 | mutex_unlock(®ister_mutex); | ||
310 | return -EBUSY; | ||
311 | } | ||
291 | timeri = snd_timer_instance_new(owner, timer); | 312 | timeri = snd_timer_instance_new(owner, timer); |
292 | if (!timeri) { | 313 | if (!timeri) { |
293 | mutex_unlock(®ister_mutex); | 314 | mutex_unlock(®ister_mutex); |
@@ -314,25 +335,27 @@ int snd_timer_open(struct snd_timer_instance **ti, | |||
314 | } | 335 | } |
315 | 336 | ||
316 | list_add_tail(&timeri->open_list, &timer->open_list_head); | 337 | list_add_tail(&timeri->open_list, &timer->open_list_head); |
317 | snd_timer_check_master(timeri); | 338 | timer->num_instances++; |
339 | err = snd_timer_check_master(timeri); | ||
340 | if (err < 0) { | ||
341 | snd_timer_close_locked(timeri); | ||
342 | timeri = NULL; | ||
343 | } | ||
318 | mutex_unlock(®ister_mutex); | 344 | mutex_unlock(®ister_mutex); |
319 | *ti = timeri; | 345 | *ti = timeri; |
320 | return 0; | 346 | return err; |
321 | } | 347 | } |
322 | EXPORT_SYMBOL(snd_timer_open); | 348 | EXPORT_SYMBOL(snd_timer_open); |
323 | 349 | ||
324 | /* | 350 | /* |
325 | * close a timer instance | 351 | * close a timer instance |
352 | * call this with register_mutex down. | ||
326 | */ | 353 | */ |
327 | int snd_timer_close(struct snd_timer_instance *timeri) | 354 | static int snd_timer_close_locked(struct snd_timer_instance *timeri) |
328 | { | 355 | { |
329 | struct snd_timer *timer = NULL; | 356 | struct snd_timer *timer = NULL; |
330 | struct snd_timer_instance *slave, *tmp; | 357 | struct snd_timer_instance *slave, *tmp; |
331 | 358 | ||
332 | if (snd_BUG_ON(!timeri)) | ||
333 | return -ENXIO; | ||
334 | |||
335 | mutex_lock(®ister_mutex); | ||
336 | list_del(&timeri->open_list); | 359 | list_del(&timeri->open_list); |
337 | 360 | ||
338 | /* force to stop the timer */ | 361 | /* force to stop the timer */ |
@@ -340,6 +363,7 @@ int snd_timer_close(struct snd_timer_instance *timeri) | |||
340 | 363 | ||
341 | timer = timeri->timer; | 364 | timer = timeri->timer; |
342 | if (timer) { | 365 | if (timer) { |
366 | timer->num_instances--; | ||
343 | /* wait, until the active callback is finished */ | 367 | /* wait, until the active callback is finished */ |
344 | spin_lock_irq(&timer->lock); | 368 | spin_lock_irq(&timer->lock); |
345 | while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) { | 369 | while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) { |
@@ -355,6 +379,7 @@ int snd_timer_close(struct snd_timer_instance *timeri) | |||
355 | list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, | 379 | list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, |
356 | open_list) { | 380 | open_list) { |
357 | list_move_tail(&slave->open_list, &snd_timer_slave_list); | 381 | list_move_tail(&slave->open_list, &snd_timer_slave_list); |
382 | timer->num_instances--; | ||
358 | slave->master = NULL; | 383 | slave->master = NULL; |
359 | slave->timer = NULL; | 384 | slave->timer = NULL; |
360 | list_del_init(&slave->ack_list); | 385 | list_del_init(&slave->ack_list); |
@@ -382,9 +407,24 @@ int snd_timer_close(struct snd_timer_instance *timeri) | |||
382 | module_put(timer->module); | 407 | module_put(timer->module); |
383 | } | 408 | } |
384 | 409 | ||
385 | mutex_unlock(®ister_mutex); | ||
386 | return 0; | 410 | return 0; |
387 | } | 411 | } |
412 | |||
413 | /* | ||
414 | * close a timer instance | ||
415 | */ | ||
416 | int snd_timer_close(struct snd_timer_instance *timeri) | ||
417 | { | ||
418 | int err; | ||
419 | |||
420 | if (snd_BUG_ON(!timeri)) | ||
421 | return -ENXIO; | ||
422 | |||
423 | mutex_lock(®ister_mutex); | ||
424 | err = snd_timer_close_locked(timeri); | ||
425 | mutex_unlock(®ister_mutex); | ||
426 | return err; | ||
427 | } | ||
388 | EXPORT_SYMBOL(snd_timer_close); | 428 | EXPORT_SYMBOL(snd_timer_close); |
389 | 429 | ||
390 | unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) | 430 | unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) |
@@ -856,6 +896,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, | |||
856 | spin_lock_init(&timer->lock); | 896 | spin_lock_init(&timer->lock); |
857 | tasklet_init(&timer->task_queue, snd_timer_tasklet, | 897 | tasklet_init(&timer->task_queue, snd_timer_tasklet, |
858 | (unsigned long)timer); | 898 | (unsigned long)timer); |
899 | timer->max_instances = 1000; /* default limit per timer */ | ||
859 | if (card != NULL) { | 900 | if (card != NULL) { |
860 | timer->module = card->module; | 901 | timer->module = card->module; |
861 | err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops); | 902 | err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops); |