Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (549 commits) ALSA: hda - Fix ADC input-amp handling for Cx20549 codec ALSA: hda - Keep EAPD turned on for old Conexant chips ALSA: hda/realtek - Fix missing volume controls with ALC260 ASoC: wm8940: Properly set codec->dapm.bias_level ALSA: hda - Fix pin-config for ASUS W90V ALSA: hda - Fix surround/CLFE headphone and speaker pins order ALSA: hda - Fix typo ALSA: Update the sound git tree URL ALSA: HDA: Add new revision for ALC662 ASoC: max98095: Convert codec->hw_write to snd_soc_write ASoC: keep pointer to resource so it can be freed ASoC: sgtl5000: Fix wrong mask in some snd_soc_update_bits calls ASoC: wm8996: Fix wrong mask for setting WM8996_AIF_CLOCKING_2 ASoC: da7210: Add support for line out and DAC ASoC: da7210: Add support for DAPM ALSA: hda/realtek - Fix DAC assignments of multiple speakers ASoC: Use SGTL5000_LINREG_VDDD_MASK instead of hardcoded mask value ASoC: Set sgtl5000->ldo in ldo_regulator_register ASoC: wm8996: Use SND_SOC_DAPM_AIF_OUT for AIF2 Capture ASoC: wm8994: Use SND_SOC_DAPM_AIF_OUT for AIF3 Capture ...
This commit is contained in:
@@ -989,7 +989,6 @@ struct user_element {
|
||||
void *tlv_data; /* TLV data */
|
||||
unsigned long tlv_data_size; /* TLV data size */
|
||||
void *priv_data; /* private data (like strings for enumerated type) */
|
||||
unsigned long priv_data_size; /* size of private data in bytes */
|
||||
};
|
||||
|
||||
static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol,
|
||||
@@ -1001,6 +1000,28 @@ static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ctl_elem_user_enum_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
struct user_element *ue = kcontrol->private_data;
|
||||
const char *names;
|
||||
unsigned int item;
|
||||
|
||||
item = uinfo->value.enumerated.item;
|
||||
|
||||
*uinfo = ue->info;
|
||||
|
||||
item = min(item, uinfo->value.enumerated.items - 1);
|
||||
uinfo->value.enumerated.item = item;
|
||||
|
||||
names = ue->priv_data;
|
||||
for (; item > 0; --item)
|
||||
names += strlen(names) + 1;
|
||||
strcpy(uinfo->value.enumerated.name, names);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
@@ -1055,11 +1076,46 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
|
||||
return change;
|
||||
}
|
||||
|
||||
static int snd_ctl_elem_init_enum_names(struct user_element *ue)
|
||||
{
|
||||
char *names, *p;
|
||||
size_t buf_len, name_len;
|
||||
unsigned int i;
|
||||
|
||||
if (ue->info.value.enumerated.names_length > 64 * 1024)
|
||||
return -EINVAL;
|
||||
|
||||
names = memdup_user(
|
||||
(const void __user *)ue->info.value.enumerated.names_ptr,
|
||||
ue->info.value.enumerated.names_length);
|
||||
if (IS_ERR(names))
|
||||
return PTR_ERR(names);
|
||||
|
||||
/* check that there are enough valid names */
|
||||
buf_len = ue->info.value.enumerated.names_length;
|
||||
p = names;
|
||||
for (i = 0; i < ue->info.value.enumerated.items; ++i) {
|
||||
name_len = strnlen(p, buf_len);
|
||||
if (name_len == 0 || name_len >= 64 || name_len == buf_len) {
|
||||
kfree(names);
|
||||
return -EINVAL;
|
||||
}
|
||||
p += name_len + 1;
|
||||
buf_len -= name_len + 1;
|
||||
}
|
||||
|
||||
ue->priv_data = names;
|
||||
ue->info.value.enumerated.names_ptr = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol)
|
||||
{
|
||||
struct user_element *ue = kcontrol->private_data;
|
||||
if (ue->tlv_data)
|
||||
kfree(ue->tlv_data);
|
||||
|
||||
kfree(ue->tlv_data);
|
||||
kfree(ue->priv_data);
|
||||
kfree(ue);
|
||||
}
|
||||
|
||||
@@ -1072,8 +1128,8 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
||||
long private_size;
|
||||
struct user_element *ue;
|
||||
int idx, err;
|
||||
|
||||
if (card->user_ctl_count >= MAX_USER_CONTROLS)
|
||||
|
||||
if (!replace && card->user_ctl_count >= MAX_USER_CONTROLS)
|
||||
return -ENOMEM;
|
||||
if (info->count < 1)
|
||||
return -EINVAL;
|
||||
@@ -1101,7 +1157,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
||||
memcpy(&kctl.id, &info->id, sizeof(info->id));
|
||||
kctl.count = info->owner ? info->owner : 1;
|
||||
access |= SNDRV_CTL_ELEM_ACCESS_USER;
|
||||
kctl.info = snd_ctl_elem_user_info;
|
||||
if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED)
|
||||
kctl.info = snd_ctl_elem_user_enum_info;
|
||||
else
|
||||
kctl.info = snd_ctl_elem_user_info;
|
||||
if (access & SNDRV_CTL_ELEM_ACCESS_READ)
|
||||
kctl.get = snd_ctl_elem_user_get;
|
||||
if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
|
||||
@@ -1122,6 +1181,11 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
||||
if (info->count > 64)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
|
||||
private_size = sizeof(unsigned int);
|
||||
if (info->count > 128 || info->value.enumerated.items == 0)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case SNDRV_CTL_ELEM_TYPE_BYTES:
|
||||
private_size = sizeof(unsigned char);
|
||||
if (info->count > 512)
|
||||
@@ -1143,9 +1207,17 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
||||
ue->info.access = 0;
|
||||
ue->elem_data = (char *)ue + sizeof(*ue);
|
||||
ue->elem_data_size = private_size;
|
||||
if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
|
||||
err = snd_ctl_elem_init_enum_names(ue);
|
||||
if (err < 0) {
|
||||
kfree(ue);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
kctl.private_free = snd_ctl_elem_user_free;
|
||||
_kctl = snd_ctl_new(&kctl, access);
|
||||
if (_kctl == NULL) {
|
||||
kfree(ue->priv_data);
|
||||
kfree(ue);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@@ -83,6 +83,8 @@ struct snd_ctl_elem_info32 {
|
||||
u32 items;
|
||||
u32 item;
|
||||
char name[64];
|
||||
u64 names_ptr;
|
||||
u32 names_length;
|
||||
} enumerated;
|
||||
unsigned char reserved[128];
|
||||
} value;
|
||||
@@ -372,6 +374,8 @@ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file,
|
||||
&data32->value.enumerated,
|
||||
sizeof(data->value.enumerated)))
|
||||
goto error;
|
||||
data->value.enumerated.names_ptr =
|
||||
(uintptr_t)compat_ptr(data->value.enumerated.names_ptr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@@ -30,6 +30,7 @@ static int jack_switch_types[] = {
|
||||
SW_LINEOUT_INSERT,
|
||||
SW_JACK_PHYSICAL_INSERT,
|
||||
SW_VIDEOOUT_INSERT,
|
||||
SW_LINEIN_INSERT,
|
||||
};
|
||||
|
||||
static int snd_jack_dev_free(struct snd_device *device)
|
||||
|
@@ -499,7 +499,7 @@ static struct snd_kcontrol *snd_mixer_oss_test_id(struct snd_mixer_oss *mixer, c
|
||||
|
||||
memset(&id, 0, sizeof(id));
|
||||
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||
strcpy(id.name, name);
|
||||
strlcpy(id.name, name, sizeof(id.name));
|
||||
id.index = index;
|
||||
return snd_ctl_find_id(card, &id);
|
||||
}
|
||||
|
@@ -1399,6 +1399,32 @@ int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime,
|
||||
|
||||
EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);
|
||||
|
||||
static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params,
|
||||
struct snd_pcm_hw_rule *rule)
|
||||
{
|
||||
unsigned int base_rate = (unsigned int)(uintptr_t)rule->private;
|
||||
struct snd_interval *rate;
|
||||
|
||||
rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
|
||||
return snd_interval_list(rate, 1, &base_rate, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_pcm_hw_rule_noresample - add a rule to allow disabling hw resampling
|
||||
* @runtime: PCM runtime instance
|
||||
* @base_rate: the rate at which the hardware does not resample
|
||||
*/
|
||||
int snd_pcm_hw_rule_noresample(struct snd_pcm_runtime *runtime,
|
||||
unsigned int base_rate)
|
||||
{
|
||||
return snd_pcm_hw_rule_add(runtime, SNDRV_PCM_HW_PARAMS_NORESAMPLE,
|
||||
SNDRV_PCM_HW_PARAM_RATE,
|
||||
snd_pcm_hw_rule_noresample_func,
|
||||
(void *)(uintptr_t)base_rate,
|
||||
SNDRV_PCM_HW_PARAM_RATE, -1);
|
||||
}
|
||||
EXPORT_SYMBOL(snd_pcm_hw_rule_noresample);
|
||||
|
||||
static void _snd_pcm_hw_param_any(struct snd_pcm_hw_params *params,
|
||||
snd_pcm_hw_param_t var)
|
||||
{
|
||||
|
@@ -2058,16 +2058,12 @@ EXPORT_SYMBOL(snd_pcm_open_substream);
|
||||
|
||||
static int snd_pcm_open_file(struct file *file,
|
||||
struct snd_pcm *pcm,
|
||||
int stream,
|
||||
struct snd_pcm_file **rpcm_file)
|
||||
int stream)
|
||||
{
|
||||
struct snd_pcm_file *pcm_file;
|
||||
struct snd_pcm_substream *substream;
|
||||
int err;
|
||||
|
||||
if (rpcm_file)
|
||||
*rpcm_file = NULL;
|
||||
|
||||
err = snd_pcm_open_substream(pcm, stream, file, &substream);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@@ -2083,8 +2079,7 @@ static int snd_pcm_open_file(struct file *file,
|
||||
substream->pcm_release = pcm_release_private;
|
||||
}
|
||||
file->private_data = pcm_file;
|
||||
if (rpcm_file)
|
||||
*rpcm_file = pcm_file;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2113,7 +2108,6 @@ static int snd_pcm_capture_open(struct inode *inode, struct file *file)
|
||||
static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
|
||||
{
|
||||
int err;
|
||||
struct snd_pcm_file *pcm_file;
|
||||
wait_queue_t wait;
|
||||
|
||||
if (pcm == NULL) {
|
||||
@@ -2131,7 +2125,7 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
|
||||
add_wait_queue(&pcm->open_wait, &wait);
|
||||
mutex_lock(&pcm->open_mutex);
|
||||
while (1) {
|
||||
err = snd_pcm_open_file(file, pcm, stream, &pcm_file);
|
||||
err = snd_pcm_open_file(file, pcm, stream);
|
||||
if (err >= 0)
|
||||
break;
|
||||
if (err == -EAGAIN) {
|
||||
@@ -3156,8 +3150,8 @@ static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = {
|
||||
/*
|
||||
* mmap the DMA buffer on RAM
|
||||
*/
|
||||
static int snd_pcm_default_mmap(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *area)
|
||||
int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
|
||||
struct vm_area_struct *area)
|
||||
{
|
||||
area->vm_flags |= VM_RESERVED;
|
||||
#ifdef ARCH_HAS_DMA_MMAP_COHERENT
|
||||
@@ -3177,6 +3171,7 @@ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream,
|
||||
area->vm_ops = &snd_pcm_vm_ops_data_fault;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_pcm_lib_default_mmap);
|
||||
|
||||
/*
|
||||
* mmap the DMA buffer on I/O memory area
|
||||
@@ -3242,7 +3237,7 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
|
||||
if (substream->ops->mmap)
|
||||
err = substream->ops->mmap(substream, area);
|
||||
else
|
||||
err = snd_pcm_default_mmap(substream, area);
|
||||
err = snd_pcm_lib_default_mmap(substream, area);
|
||||
if (!err)
|
||||
atomic_inc(&substream->mmap_count);
|
||||
return err;
|
||||
|
Reference in New Issue
Block a user