diff options
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
| -rw-r--r-- | sound/pci/hda/hda_codec.c | 81 | 
1 files changed, 73 insertions, 8 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f98b47cd6cf..76d3c4c049d 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -824,6 +824,9 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list,  	struct hda_pincfg *pin;  	unsigned int oldcfg; +	if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) +		return -EINVAL; +  	oldcfg = snd_hda_codec_get_pincfg(codec, nid);  	pin = look_up_pincfg(codec, list, nid);  	if (!pin) { @@ -899,6 +902,25 @@ static void restore_pincfgs(struct hda_codec *codec)  	}  } +/** + * snd_hda_shutup_pins - Shut up all pins + * @codec: the HDA codec + * + * Clear all pin controls to shup up before suspend for avoiding click noise. + * The controls aren't cached so that they can be resumed properly. + */ +void snd_hda_shutup_pins(struct hda_codec *codec) +{ +	int i; +	for (i = 0; i < codec->init_pins.used; i++) { +		struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); +		/* use read here for syncing after issuing each verb */ +		snd_hda_codec_read(codec, pin->nid, 0, +				   AC_VERB_SET_PIN_WIDGET_CONTROL, 0); +	} +} +EXPORT_SYMBOL_HDA(snd_hda_shutup_pins); +  static void init_hda_cache(struct hda_cache_rec *cache,  			   unsigned int record_size);  static void free_hda_cache(struct hda_cache_rec *cache); @@ -931,6 +953,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)  #endif  	list_del(&codec->list);  	snd_array_free(&codec->mixers); +	snd_array_free(&codec->nids);  	codec->bus->caddr_tbl[codec->addr] = NULL;  	if (codec->patch_ops.free)  		codec->patch_ops.free(codec); @@ -985,7 +1008,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr  	mutex_init(&codec->control_mutex);  	init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));  	init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); -	snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 60); +	snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32); +	snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32);  	snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);  	snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);  	if (codec->bus->modelname) { @@ -1708,7 +1732,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,  EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);  /** - * snd_hda_ctl-add - Add a control element and assign to the codec + * snd_hda_ctl_add - Add a control element and assign to the codec   * @codec: HD-audio codec   * @nid: corresponding NID (optional)   * @kctl: the control element to assign @@ -1723,19 +1747,25 @@ EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);   *   * snd_hda_ctl_add() checks the control subdev id field whether   * #HDA_SUBDEV_NID_FLAG bit is set.  If set (and @nid is zero), the lower - * bits value is taken as the NID to assign. + * bits value is taken as the NID to assign. The #HDA_NID_ITEM_AMP bit + * specifies if kctl->private_value is a HDA amplifier value.   */  int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,  		    struct snd_kcontrol *kctl)  {  	int err; +	unsigned short flags = 0;  	struct hda_nid_item *item; -	if (kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) { +	if (kctl->id.subdevice & HDA_SUBDEV_AMP_FLAG) { +		flags |= HDA_NID_ITEM_AMP;  		if (nid == 0) -			nid = kctl->id.subdevice & 0xffff; -		kctl->id.subdevice = 0; +			nid = get_amp_nid_(kctl->private_value);  	} +	if ((kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) != 0 && nid == 0) +		nid = kctl->id.subdevice & 0xffff; +	if (kctl->id.subdevice & (HDA_SUBDEV_NID_FLAG|HDA_SUBDEV_AMP_FLAG)) +		kctl->id.subdevice = 0;  	err = snd_ctl_add(codec->bus->card, kctl);  	if (err < 0)  		return err; @@ -1744,11 +1774,41 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,  		return -ENOMEM;  	item->kctl = kctl;  	item->nid = nid; +	item->flags = flags;  	return 0;  }  EXPORT_SYMBOL_HDA(snd_hda_ctl_add);  /** + * snd_hda_add_nid - Assign a NID to a control element + * @codec: HD-audio codec + * @nid: corresponding NID (optional) + * @kctl: the control element to assign + * @index: index to kctl + * + * Add the given control element to an array inside the codec instance. + * This function is used when #snd_hda_ctl_add cannot be used for 1:1 + * NID:KCTL mapping - for example "Capture Source" selector. + */ +int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl, +		    unsigned int index, hda_nid_t nid) +{ +	struct hda_nid_item *item; + +	if (nid > 0) { +		item = snd_array_new(&codec->nids); +		if (!item) +			return -ENOMEM; +		item->kctl = kctl; +		item->index = index; +		item->nid = nid; +		return 0; +	} +	return -EINVAL; +} +EXPORT_SYMBOL_HDA(snd_hda_add_nid); + +/**   * snd_hda_ctls_clear - Clear all controls assigned to the given codec   * @codec: HD-audio codec   */ @@ -1759,6 +1819,7 @@ void snd_hda_ctls_clear(struct hda_codec *codec)  	for (i = 0; i < codec->mixers.used; i++)  		snd_ctl_remove(codec->bus->card, items[i].kctl);  	snd_array_free(&codec->mixers); +	snd_array_free(&codec->nids);  }  /* pseudo device locking @@ -2706,7 +2767,8 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,  	snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,  			    power_state);  	/* partial workaround for "azx_get_response timeout" */ -	if (power_state == AC_PWRST_D0) +	if (power_state == AC_PWRST_D0 && +	    (codec->vendor_id & 0xffff0000) == 0x14f10000)  		msleep(10);  	nid = codec->start_nid; @@ -2740,7 +2802,6 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,  	if (power_state == AC_PWRST_D0) {  		unsigned long end_time;  		int state; -		msleep(10);  		/* wait until the codec reachs to D0 */  		end_time = jiffies + msecs_to_jiffies(500);  		do { @@ -3214,6 +3275,8 @@ const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = {  /*   * get the empty PCM device number to assign + * + * note the max device number is limited by HDA_MAX_PCMS, currently 10   */  static int get_empty_pcm_device(struct hda_bus *bus, int type)  { @@ -3478,6 +3541,8 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)  	for (; knew->name; knew++) {  		struct snd_kcontrol *kctl; +		if (knew->iface == -1)	/* skip this codec private value */ +			continue;  		kctl = snd_ctl_new1(knew, codec);  		if (!kctl)  			return -ENOMEM;  |