diff options
Diffstat (limited to 'sound/core/timer.c')
-rw-r--r-- | sound/core/timer.c | 44 |
1 files changed, 40 insertions, 4 deletions
diff --git a/sound/core/timer.c b/sound/core/timer.c index af1f68f7e315..9b513a05765a 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c | |||
@@ -451,6 +451,10 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri) | |||
451 | unsigned long flags; | 451 | unsigned long flags; |
452 | 452 | ||
453 | spin_lock_irqsave(&slave_active_lock, flags); | 453 | spin_lock_irqsave(&slave_active_lock, flags); |
454 | if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { | ||
455 | spin_unlock_irqrestore(&slave_active_lock, flags); | ||
456 | return -EBUSY; | ||
457 | } | ||
454 | timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; | 458 | timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; |
455 | if (timeri->master && timeri->timer) { | 459 | if (timeri->master && timeri->timer) { |
456 | spin_lock(&timeri->timer->lock); | 460 | spin_lock(&timeri->timer->lock); |
@@ -475,7 +479,8 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) | |||
475 | return -EINVAL; | 479 | return -EINVAL; |
476 | if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { | 480 | if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { |
477 | result = snd_timer_start_slave(timeri); | 481 | result = snd_timer_start_slave(timeri); |
478 | snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); | 482 | if (result >= 0) |
483 | snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); | ||
479 | return result; | 484 | return result; |
480 | } | 485 | } |
481 | timer = timeri->timer; | 486 | timer = timeri->timer; |
@@ -484,11 +489,18 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) | |||
484 | if (timer->card && timer->card->shutdown) | 489 | if (timer->card && timer->card->shutdown) |
485 | return -ENODEV; | 490 | return -ENODEV; |
486 | spin_lock_irqsave(&timer->lock, flags); | 491 | spin_lock_irqsave(&timer->lock, flags); |
492 | if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | | ||
493 | SNDRV_TIMER_IFLG_START)) { | ||
494 | result = -EBUSY; | ||
495 | goto unlock; | ||
496 | } | ||
487 | timeri->ticks = timeri->cticks = ticks; | 497 | timeri->ticks = timeri->cticks = ticks; |
488 | timeri->pticks = 0; | 498 | timeri->pticks = 0; |
489 | result = snd_timer_start1(timer, timeri, ticks); | 499 | result = snd_timer_start1(timer, timeri, ticks); |
500 | unlock: | ||
490 | spin_unlock_irqrestore(&timer->lock, flags); | 501 | spin_unlock_irqrestore(&timer->lock, flags); |
491 | snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); | 502 | if (result >= 0) |
503 | snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START); | ||
492 | return result; | 504 | return result; |
493 | } | 505 | } |
494 | 506 | ||
@@ -502,6 +514,10 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri, int event) | |||
502 | 514 | ||
503 | if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { | 515 | if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { |
504 | spin_lock_irqsave(&slave_active_lock, flags); | 516 | spin_lock_irqsave(&slave_active_lock, flags); |
517 | if (!(timeri->flags & SNDRV_TIMER_IFLG_RUNNING)) { | ||
518 | spin_unlock_irqrestore(&slave_active_lock, flags); | ||
519 | return -EBUSY; | ||
520 | } | ||
505 | timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; | 521 | timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; |
506 | list_del_init(&timeri->ack_list); | 522 | list_del_init(&timeri->ack_list); |
507 | list_del_init(&timeri->active_list); | 523 | list_del_init(&timeri->active_list); |
@@ -512,6 +528,11 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri, int event) | |||
512 | if (!timer) | 528 | if (!timer) |
513 | return -EINVAL; | 529 | return -EINVAL; |
514 | spin_lock_irqsave(&timer->lock, flags); | 530 | spin_lock_irqsave(&timer->lock, flags); |
531 | if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | | ||
532 | SNDRV_TIMER_IFLG_START))) { | ||
533 | spin_unlock_irqrestore(&timer->lock, flags); | ||
534 | return -EBUSY; | ||
535 | } | ||
515 | list_del_init(&timeri->ack_list); | 536 | list_del_init(&timeri->ack_list); |
516 | list_del_init(&timeri->active_list); | 537 | list_del_init(&timeri->active_list); |
517 | if (timer->card && timer->card->shutdown) { | 538 | if (timer->card && timer->card->shutdown) { |
@@ -581,10 +602,15 @@ int snd_timer_continue(struct snd_timer_instance *timeri) | |||
581 | if (timer->card && timer->card->shutdown) | 602 | if (timer->card && timer->card->shutdown) |
582 | return -ENODEV; | 603 | return -ENODEV; |
583 | spin_lock_irqsave(&timer->lock, flags); | 604 | spin_lock_irqsave(&timer->lock, flags); |
605 | if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { | ||
606 | result = -EBUSY; | ||
607 | goto unlock; | ||
608 | } | ||
584 | if (!timeri->cticks) | 609 | if (!timeri->cticks) |
585 | timeri->cticks = 1; | 610 | timeri->cticks = 1; |
586 | timeri->pticks = 0; | 611 | timeri->pticks = 0; |
587 | result = snd_timer_start1(timer, timeri, timer->sticks); | 612 | result = snd_timer_start1(timer, timeri, timer->sticks); |
613 | unlock: | ||
588 | spin_unlock_irqrestore(&timer->lock, flags); | 614 | spin_unlock_irqrestore(&timer->lock, flags); |
589 | snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_CONTINUE); | 615 | snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_CONTINUE); |
590 | return result; | 616 | return result; |
@@ -718,8 +744,8 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) | |||
718 | ti->cticks = ti->ticks; | 744 | ti->cticks = ti->ticks; |
719 | } else { | 745 | } else { |
720 | ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; | 746 | ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; |
721 | if (--timer->running) | 747 | --timer->running; |
722 | list_del_init(&ti->active_list); | 748 | list_del_init(&ti->active_list); |
723 | } | 749 | } |
724 | if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || | 750 | if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || |
725 | (ti->flags & SNDRV_TIMER_IFLG_FAST)) | 751 | (ti->flags & SNDRV_TIMER_IFLG_FAST)) |
@@ -1032,11 +1058,21 @@ static int snd_timer_s_stop(struct snd_timer * timer) | |||
1032 | return 0; | 1058 | return 0; |
1033 | } | 1059 | } |
1034 | 1060 | ||
1061 | static int snd_timer_s_close(struct snd_timer *timer) | ||
1062 | { | ||
1063 | struct snd_timer_system_private *priv; | ||
1064 | |||
1065 | priv = (struct snd_timer_system_private *)timer->private_data; | ||
1066 | del_timer_sync(&priv->tlist); | ||
1067 | return 0; | ||
1068 | } | ||
1069 | |||
1035 | static struct snd_timer_hardware snd_timer_system = | 1070 | static struct snd_timer_hardware snd_timer_system = |
1036 | { | 1071 | { |
1037 | .flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_TASKLET, | 1072 | .flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_TASKLET, |
1038 | .resolution = 1000000000L / HZ, | 1073 | .resolution = 1000000000L / HZ, |
1039 | .ticks = 10000000L, | 1074 | .ticks = 10000000L, |
1075 | .close = snd_timer_s_close, | ||
1040 | .start = snd_timer_s_start, | 1076 | .start = snd_timer_s_start, |
1041 | .stop = snd_timer_s_stop | 1077 | .stop = snd_timer_s_stop |
1042 | }; | 1078 | }; |