diff options
Diffstat (limited to 'sound/drivers')
-rw-r--r-- | sound/drivers/Kconfig | 1 | ||||
-rw-r--r-- | sound/drivers/aloop.c | 36 | ||||
-rw-r--r-- | sound/drivers/dummy.c | 73 |
3 files changed, 90 insertions, 20 deletions
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index fe5ae09ffccb..5e4384137a76 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -35,7 +35,6 @@ config SND_PCSP tristate "PC-Speaker support (READ HELP!)" depends on PCSPKR_PLATFORM && X86 && HIGH_RES_TIMERS depends on INPUT - depends on EXPERIMENTAL select SND_PCM help If you don't have a sound card in your computer, you can include a diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 0fe6d64ff840..1904046686e2 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -120,7 +120,6 @@ struct loopback_pcm { unsigned int last_drift; unsigned long last_jiffies; struct timer_list timer; - spinlock_t timer_lock; }; static struct platform_device *devices[SNDRV_CARDS]; @@ -166,12 +165,12 @@ static inline unsigned int get_rate_shift(struct loopback_pcm *dpcm) return get_setup(dpcm)->rate_shift; } +/* call in cable->lock */ static void loopback_timer_start(struct loopback_pcm *dpcm) { unsigned long tick; unsigned int rate_shift = get_rate_shift(dpcm); - spin_lock(&dpcm->timer_lock); if (rate_shift != dpcm->pcm_rate_shift) { dpcm->pcm_rate_shift = rate_shift; dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size); @@ -184,15 +183,13 @@ static void loopback_timer_start(struct loopback_pcm *dpcm) tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps; dpcm->timer.expires = jiffies + tick; add_timer(&dpcm->timer); - spin_unlock(&dpcm->timer_lock); } +/* call in cable->lock */ static inline void loopback_timer_stop(struct loopback_pcm *dpcm) { - spin_lock(&dpcm->timer_lock); del_timer(&dpcm->timer); dpcm->timer.expires = 0; - spin_unlock(&dpcm->timer_lock); } #define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK) @@ -274,8 +271,8 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock(&cable->lock); cable->running |= stream; cable->pause &= ~stream; - spin_unlock(&cable->lock); loopback_timer_start(dpcm); + spin_unlock(&cable->lock); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); break; @@ -283,23 +280,23 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock(&cable->lock); cable->running &= ~stream; cable->pause &= ~stream; - spin_unlock(&cable->lock); loopback_timer_stop(dpcm); + spin_unlock(&cable->lock); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: spin_lock(&cable->lock); cable->pause |= stream; - spin_unlock(&cable->lock); loopback_timer_stop(dpcm); + spin_unlock(&cable->lock); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: spin_lock(&cable->lock); dpcm->last_jiffies = jiffies; cable->pause &= ~stream; - spin_unlock(&cable->lock); loopback_timer_start(dpcm); + spin_unlock(&cable->lock); break; default: return -EINVAL; @@ -477,6 +474,7 @@ static inline void bytepos_finish(struct loopback_pcm *dpcm, dpcm->buf_pos %= dpcm->pcm_buffer_size; } +/* call in cable->lock */ static unsigned int loopback_pos_update(struct loopback_cable *cable) { struct loopback_pcm *dpcm_play = @@ -485,9 +483,7 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable) cable->streams[SNDRV_PCM_STREAM_CAPTURE]; unsigned long delta_play = 0, delta_capt = 0; unsigned int running, count1, count2; - unsigned long flags; - spin_lock_irqsave(&cable->lock, flags); running = cable->running ^ cable->pause; if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { delta_play = jiffies - dpcm_play->last_jiffies; @@ -529,32 +525,39 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable) bytepos_finish(dpcm_play, count1); bytepos_finish(dpcm_capt, count1); unlock: - spin_unlock_irqrestore(&cable->lock, flags); return running; } static void loopback_timer_function(unsigned long data) { struct loopback_pcm *dpcm = (struct loopback_pcm *)data; - unsigned int running; + unsigned long flags; - running = loopback_pos_update(dpcm->cable); - if (running & (1 << dpcm->substream->stream)) { + spin_lock_irqsave(&dpcm->cable->lock, flags); + if (loopback_pos_update(dpcm->cable) & (1 << dpcm->substream->stream)) { loopback_timer_start(dpcm); if (dpcm->period_update_pending) { dpcm->period_update_pending = 0; + spin_unlock_irqrestore(&dpcm->cable->lock, flags); + /* need to unlock before calling below */ snd_pcm_period_elapsed(dpcm->substream); + return; } } + spin_unlock_irqrestore(&dpcm->cable->lock, flags); } static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct loopback_pcm *dpcm = runtime->private_data; + snd_pcm_uframes_t pos; + spin_lock(&dpcm->cable->lock); loopback_pos_update(dpcm->cable); - return bytes_to_frames(runtime, dpcm->buf_pos); + pos = dpcm->buf_pos; + spin_unlock(&dpcm->cable->lock); + return bytes_to_frames(runtime, pos); } static struct snd_pcm_hardware loopback_pcm_hardware = @@ -672,7 +675,6 @@ static int loopback_open(struct snd_pcm_substream *substream) dpcm->substream = substream; setup_timer(&dpcm->timer, loopback_timer_function, (unsigned long)dpcm); - spin_lock_init(&dpcm->timer_lock); cable = loopback->cables[substream->number][dev]; if (!cable) { diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 54bb6644a598..4f522cf48455 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -134,6 +134,9 @@ struct snd_dummy { spinlock_t mixer_lock; int mixer_volume[MIXER_ADDR_LAST+1][2]; int capture_source[MIXER_ADDR_LAST+1][2]; + int iobox; + struct snd_kcontrol *cd_volume_ctl; + struct snd_kcontrol *cd_switch_ctl; const struct dummy_timer_ops *timer_ops; }; @@ -817,6 +820,57 @@ static int snd_dummy_capsrc_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el return change; } +static int snd_dummy_iobox_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *info) +{ + const char *const names[] = { "None", "CD Player" }; + + return snd_ctl_enum_info(info, 1, 2, names); +} + +static int snd_dummy_iobox_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol); + + value->value.enumerated.item[0] = dummy->iobox; + return 0; +} + +static int snd_dummy_iobox_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol); + int changed; + + if (value->value.enumerated.item[0] > 1) + return -EINVAL; + + changed = value->value.enumerated.item[0] != dummy->iobox; + if (changed) { + dummy->iobox = value->value.enumerated.item[0]; + + if (dummy->iobox) { + dummy->cd_volume_ctl->vd[0].access &= + ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + dummy->cd_switch_ctl->vd[0].access &= + ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + } else { + dummy->cd_volume_ctl->vd[0].access |= + SNDRV_CTL_ELEM_ACCESS_INACTIVE; + dummy->cd_switch_ctl->vd[0].access |= + SNDRV_CTL_ELEM_ACCESS_INACTIVE; + } + + snd_ctl_notify(dummy->card, SNDRV_CTL_EVENT_MASK_INFO, + &dummy->cd_volume_ctl->id); + snd_ctl_notify(dummy->card, SNDRV_CTL_EVENT_MASK_INFO, + &dummy->cd_switch_ctl->id); + } + + return changed; +} + static struct snd_kcontrol_new snd_dummy_controls[] = { DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER), DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER), @@ -827,22 +881,37 @@ DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_LINE), DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC), DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MIC), DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD), -DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_CD) +DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_CD), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "External I/O Box", + .info = snd_dummy_iobox_info, + .get = snd_dummy_iobox_get, + .put = snd_dummy_iobox_put, +}, }; static int __devinit snd_card_dummy_new_mixer(struct snd_dummy *dummy) { struct snd_card *card = dummy->card; + struct snd_kcontrol *kcontrol; unsigned int idx; int err; spin_lock_init(&dummy->mixer_lock); strcpy(card->mixername, "Dummy Mixer"); + dummy->iobox = 1; for (idx = 0; idx < ARRAY_SIZE(snd_dummy_controls); idx++) { - err = snd_ctl_add(card, snd_ctl_new1(&snd_dummy_controls[idx], dummy)); + kcontrol = snd_ctl_new1(&snd_dummy_controls[idx], dummy); + err = snd_ctl_add(card, kcontrol); if (err < 0) return err; + if (!strcmp(kcontrol->id.name, "CD Volume")) + dummy->cd_volume_ctl = kcontrol; + else if (!strcmp(kcontrol->id.name, "CD Capture Switch")) + dummy->cd_switch_ctl = kcontrol; + } return 0; } |