Merge remote branch 'alsa/devel' into topic/misc
This commit is contained in:
Коммит
e799d0bce6
|
@ -618,8 +618,10 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
|
||||||
if (numid == ID_UNKNOWN)
|
if (numid == ID_UNKNOWN)
|
||||||
return;
|
return;
|
||||||
down_read(&card->controls_rwsem);
|
down_read(&card->controls_rwsem);
|
||||||
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL)
|
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
|
||||||
|
up_read(&card->controls_rwsem);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
||||||
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
||||||
if (uinfo == NULL || uctl == NULL)
|
if (uinfo == NULL || uctl == NULL)
|
||||||
|
@ -658,7 +660,7 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
|
||||||
return;
|
return;
|
||||||
down_read(&card->controls_rwsem);
|
down_read(&card->controls_rwsem);
|
||||||
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
|
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
|
||||||
up_read(&fmixer->card->controls_rwsem);
|
up_read(&card->controls_rwsem);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
|
||||||
|
@ -797,7 +799,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
||||||
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
||||||
if (uinfo == NULL || uctl == NULL) {
|
if (uinfo == NULL || uctl == NULL) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto __unlock;
|
goto __free_only;
|
||||||
}
|
}
|
||||||
down_read(&card->controls_rwsem);
|
down_read(&card->controls_rwsem);
|
||||||
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
|
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
|
||||||
|
@ -826,6 +828,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
||||||
err = 0;
|
err = 0;
|
||||||
__unlock:
|
__unlock:
|
||||||
up_read(&card->controls_rwsem);
|
up_read(&card->controls_rwsem);
|
||||||
|
__free_only:
|
||||||
kfree(uctl);
|
kfree(uctl);
|
||||||
kfree(uinfo);
|
kfree(uinfo);
|
||||||
return err;
|
return err;
|
||||||
|
@ -847,7 +850,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
||||||
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
|
||||||
if (uinfo == NULL || uctl == NULL) {
|
if (uinfo == NULL || uctl == NULL) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto __unlock;
|
goto __free_only;
|
||||||
}
|
}
|
||||||
down_read(&card->controls_rwsem);
|
down_read(&card->controls_rwsem);
|
||||||
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
|
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
|
||||||
|
@ -880,6 +883,7 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
|
||||||
err = 0;
|
err = 0;
|
||||||
__unlock:
|
__unlock:
|
||||||
up_read(&card->controls_rwsem);
|
up_read(&card->controls_rwsem);
|
||||||
|
__free_only:
|
||||||
kfree(uctl);
|
kfree(uctl);
|
||||||
kfree(uinfo);
|
kfree(uinfo);
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -188,7 +188,7 @@ static inline void loopback_timer_stop(struct loopback_pcm *dpcm)
|
||||||
|
|
||||||
static int loopback_check_format(struct loopback_cable *cable, int stream)
|
static int loopback_check_format(struct loopback_cable *cable, int stream)
|
||||||
{
|
{
|
||||||
struct snd_pcm_runtime *runtime;
|
struct snd_pcm_runtime *runtime, *cruntime;
|
||||||
struct loopback_setup *setup;
|
struct loopback_setup *setup;
|
||||||
struct snd_card *card;
|
struct snd_card *card;
|
||||||
int check;
|
int check;
|
||||||
|
@ -200,11 +200,11 @@ static int loopback_check_format(struct loopback_cable *cable, int stream)
|
||||||
}
|
}
|
||||||
runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
|
runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
|
||||||
substream->runtime;
|
substream->runtime;
|
||||||
check = cable->hw.formats != (1ULL << runtime->format) ||
|
cruntime = cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
|
||||||
cable->hw.rate_min != runtime->rate ||
|
substream->runtime;
|
||||||
cable->hw.rate_max != runtime->rate ||
|
check = runtime->format != cruntime->format ||
|
||||||
cable->hw.channels_min != runtime->channels ||
|
runtime->rate != cruntime->rate ||
|
||||||
cable->hw.channels_max != runtime->channels;
|
runtime->channels != cruntime->channels;
|
||||||
if (!check)
|
if (!check)
|
||||||
return 0;
|
return 0;
|
||||||
if (stream == SNDRV_PCM_STREAM_CAPTURE) {
|
if (stream == SNDRV_PCM_STREAM_CAPTURE) {
|
||||||
|
@ -274,12 +274,42 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void params_change_substream(struct loopback_pcm *dpcm,
|
||||||
|
struct snd_pcm_runtime *runtime)
|
||||||
|
{
|
||||||
|
struct snd_pcm_runtime *dst_runtime;
|
||||||
|
|
||||||
|
if (dpcm == NULL || dpcm->substream == NULL)
|
||||||
|
return;
|
||||||
|
dst_runtime = dpcm->substream->runtime;
|
||||||
|
if (dst_runtime == NULL)
|
||||||
|
return;
|
||||||
|
dst_runtime->hw = dpcm->cable->hw;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void params_change(struct snd_pcm_substream *substream)
|
||||||
|
{
|
||||||
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
|
struct loopback_pcm *dpcm = runtime->private_data;
|
||||||
|
struct loopback_cable *cable = dpcm->cable;
|
||||||
|
|
||||||
|
cable->hw.formats = (1ULL << runtime->format);
|
||||||
|
cable->hw.rate_min = runtime->rate;
|
||||||
|
cable->hw.rate_max = runtime->rate;
|
||||||
|
cable->hw.channels_min = runtime->channels;
|
||||||
|
cable->hw.channels_max = runtime->channels;
|
||||||
|
params_change_substream(cable->streams[SNDRV_PCM_STREAM_PLAYBACK],
|
||||||
|
runtime);
|
||||||
|
params_change_substream(cable->streams[SNDRV_PCM_STREAM_CAPTURE],
|
||||||
|
runtime);
|
||||||
|
}
|
||||||
|
|
||||||
static int loopback_prepare(struct snd_pcm_substream *substream)
|
static int loopback_prepare(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
struct loopback_pcm *dpcm = runtime->private_data;
|
struct loopback_pcm *dpcm = runtime->private_data;
|
||||||
struct loopback_cable *cable = dpcm->cable;
|
struct loopback_cable *cable = dpcm->cable;
|
||||||
unsigned int bps, salign;
|
int bps, salign;
|
||||||
|
|
||||||
salign = (snd_pcm_format_width(runtime->format) *
|
salign = (snd_pcm_format_width(runtime->format) *
|
||||||
runtime->channels) / 8;
|
runtime->channels) / 8;
|
||||||
|
@ -303,13 +333,10 @@ static int loopback_prepare(struct snd_pcm_substream *substream)
|
||||||
dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size);
|
dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size);
|
||||||
|
|
||||||
mutex_lock(&dpcm->loopback->cable_lock);
|
mutex_lock(&dpcm->loopback->cable_lock);
|
||||||
if (!(cable->valid & ~(1 << substream->stream))) {
|
if (!(cable->valid & ~(1 << substream->stream)) ||
|
||||||
cable->hw.formats = (1ULL << runtime->format);
|
(get_setup(dpcm)->notify &&
|
||||||
cable->hw.rate_min = runtime->rate;
|
substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
|
||||||
cable->hw.rate_max = runtime->rate;
|
params_change(substream);
|
||||||
cable->hw.channels_min = runtime->channels;
|
|
||||||
cable->hw.channels_max = runtime->channels;
|
|
||||||
}
|
|
||||||
cable->valid |= 1 << substream->stream;
|
cable->valid |= 1 << substream->stream;
|
||||||
mutex_unlock(&dpcm->loopback->cable_lock);
|
mutex_unlock(&dpcm->loopback->cable_lock);
|
||||||
|
|
||||||
|
@ -542,6 +569,47 @@ static unsigned int get_cable_index(struct snd_pcm_substream *substream)
|
||||||
return !substream->stream;
|
return !substream->stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rule_format(struct snd_pcm_hw_params *params,
|
||||||
|
struct snd_pcm_hw_rule *rule)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct snd_pcm_hardware *hw = rule->private;
|
||||||
|
struct snd_mask *maskp = hw_param_mask(params, rule->var);
|
||||||
|
|
||||||
|
maskp->bits[0] &= (u_int32_t)hw->formats;
|
||||||
|
maskp->bits[1] &= (u_int32_t)(hw->formats >> 32);
|
||||||
|
memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */
|
||||||
|
if (! maskp->bits[0] && ! maskp->bits[1])
|
||||||
|
return -EINVAL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rule_rate(struct snd_pcm_hw_params *params,
|
||||||
|
struct snd_pcm_hw_rule *rule)
|
||||||
|
{
|
||||||
|
struct snd_pcm_hardware *hw = rule->private;
|
||||||
|
struct snd_interval t;
|
||||||
|
|
||||||
|
t.min = hw->rate_min;
|
||||||
|
t.max = hw->rate_max;
|
||||||
|
t.openmin = t.openmax = 0;
|
||||||
|
t.integer = 0;
|
||||||
|
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rule_channels(struct snd_pcm_hw_params *params,
|
||||||
|
struct snd_pcm_hw_rule *rule)
|
||||||
|
{
|
||||||
|
struct snd_pcm_hardware *hw = rule->private;
|
||||||
|
struct snd_interval t;
|
||||||
|
|
||||||
|
t.min = hw->channels_min;
|
||||||
|
t.max = hw->channels_max;
|
||||||
|
t.openmin = t.openmax = 0;
|
||||||
|
t.integer = 0;
|
||||||
|
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
|
||||||
|
}
|
||||||
|
|
||||||
static int loopback_open(struct snd_pcm_substream *substream)
|
static int loopback_open(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
|
@ -579,14 +647,34 @@ static int loopback_open(struct snd_pcm_substream *substream)
|
||||||
|
|
||||||
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
|
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
|
||||||
|
|
||||||
|
/* use dynamic rules based on actual runtime->hw values */
|
||||||
|
/* note that the default rules created in the PCM midlevel code */
|
||||||
|
/* are cached -> they do not reflect the actual state */
|
||||||
|
err = snd_pcm_hw_rule_add(runtime, 0,
|
||||||
|
SNDRV_PCM_HW_PARAM_FORMAT,
|
||||||
|
rule_format, &runtime->hw,
|
||||||
|
SNDRV_PCM_HW_PARAM_FORMAT, -1);
|
||||||
|
if (err < 0)
|
||||||
|
goto unlock;
|
||||||
|
err = snd_pcm_hw_rule_add(runtime, 0,
|
||||||
|
SNDRV_PCM_HW_PARAM_RATE,
|
||||||
|
rule_rate, &runtime->hw,
|
||||||
|
SNDRV_PCM_HW_PARAM_RATE, -1);
|
||||||
|
if (err < 0)
|
||||||
|
goto unlock;
|
||||||
|
err = snd_pcm_hw_rule_add(runtime, 0,
|
||||||
|
SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||||
|
rule_channels, &runtime->hw,
|
||||||
|
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
|
||||||
|
if (err < 0)
|
||||||
|
goto unlock;
|
||||||
|
|
||||||
runtime->private_data = dpcm;
|
runtime->private_data = dpcm;
|
||||||
runtime->private_free = loopback_runtime_free;
|
runtime->private_free = loopback_runtime_free;
|
||||||
if (get_notify(dpcm) &&
|
if (get_notify(dpcm))
|
||||||
substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
|
||||||
runtime->hw = loopback_pcm_hardware;
|
runtime->hw = loopback_pcm_hardware;
|
||||||
} else {
|
else
|
||||||
runtime->hw = cable->hw;
|
runtime->hw = cable->hw;
|
||||||
}
|
|
||||||
unlock:
|
unlock:
|
||||||
mutex_unlock(&loopback->cable_lock);
|
mutex_unlock(&loopback->cable_lock);
|
||||||
return err;
|
return err;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче