Merge branch 'topic/hda' into for-linus
This commit is contained in:
		
						commit
						e7bfbb0215
					
				| @ -741,6 +741,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | ||||
|     model	- force the model name | ||||
|     position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF) | ||||
|     probe_mask  - Bitmask to probe codecs (default = -1, meaning all slots) | ||||
|     		  When the bit 8 (0x100) is set, the lower 8 bits are used | ||||
| 		  as the "fixed" codec slots; i.e. the driver probes the | ||||
| 		  slots regardless what hardware reports back | ||||
|     probe_only	- Only probing and no codec initialization (default=off); | ||||
| 		  Useful to check the initial codec status for debugging | ||||
|     bdl_pos_adj	- Specifies the DMA IRQ timing delay in samples. | ||||
|  | ||||
| @ -56,6 +56,7 @@ ALC262 | ||||
|   sony-assamd	Sony ASSAMD | ||||
|   toshiba-s06	Toshiba S06 | ||||
|   toshiba-rx1	Toshiba RX1 | ||||
|   tyan		Tyan Thunder n6650W (S2915-E) | ||||
|   ultra		Samsung Q1 Ultra Vista model | ||||
|   lenovo-3000	Lenovo 3000 y410 | ||||
|   nec		NEC Versa S9100 | ||||
| @ -261,6 +262,8 @@ Conexant 5051 | ||||
| ============= | ||||
|   laptop	Basic Laptop config (default) | ||||
|   hp		HP Spartan laptop | ||||
|   hp-dv6736	HP dv6736 | ||||
|   lenovo-x200	Lenovo X200 laptop | ||||
| 
 | ||||
| STAC9200 | ||||
| ======== | ||||
| @ -278,6 +281,7 @@ STAC9200 | ||||
|   gateway-m4	Gateway laptops with EAPD control | ||||
|   gateway-m4-2	Gateway laptops with EAPD control | ||||
|   panasonic	Panasonic CF-74 | ||||
|   auto		BIOS setup (default) | ||||
| 
 | ||||
| STAC9205/9254 | ||||
| ============= | ||||
| @ -285,6 +289,8 @@ STAC9205/9254 | ||||
|   dell-m42	Dell (unknown) | ||||
|   dell-m43	Dell Precision | ||||
|   dell-m44	Dell Inspiron | ||||
|   eapd		Keep EAPD on (e.g. Gateway T1616) | ||||
|   auto		BIOS setup (default) | ||||
| 
 | ||||
| STAC9220/9221 | ||||
| ============= | ||||
| @ -308,6 +314,7 @@ STAC9220/9221 | ||||
|   dell-d82	Dell (unknown) | ||||
|   dell-m81	Dell (unknown) | ||||
|   dell-m82	Dell XPS M1210 | ||||
|   auto		BIOS setup (default) | ||||
| 
 | ||||
| STAC9202/9250/9251 | ||||
| ================== | ||||
| @ -319,6 +326,7 @@ STAC9202/9250/9251 | ||||
|   m3		Some Gateway MX series laptops | ||||
|   m5		Some Gateway MX series laptops (MP6954) | ||||
|   m6		Some Gateway NX series laptops | ||||
|   auto		BIOS setup (default) | ||||
| 
 | ||||
| STAC9227/9228/9229/927x | ||||
| ======================= | ||||
| @ -328,6 +336,7 @@ STAC9227/9228/9229/927x | ||||
|   5stack	D965 5stack + SPDIF | ||||
|   dell-3stack	Dell Dimension E520 | ||||
|   dell-bios	Fixes with Dell BIOS setup | ||||
|   auto		BIOS setup (default) | ||||
| 
 | ||||
| STAC92HD71B* | ||||
| ============ | ||||
| @ -335,7 +344,10 @@ STAC92HD71B* | ||||
|   dell-m4-1	Dell desktops | ||||
|   dell-m4-2	Dell desktops | ||||
|   dell-m4-3	Dell desktops | ||||
|   hp-m4		HP dv laptops | ||||
|   hp-m4		HP mini 1000 | ||||
|   hp-dv5	HP dv series | ||||
|   hp-hdx	HP HDX series | ||||
|   auto		BIOS setup (default) | ||||
| 
 | ||||
| STAC92HD73* | ||||
| =========== | ||||
| @ -345,13 +357,16 @@ STAC92HD73* | ||||
|   dell-m6-dmic	Dell desktops/laptops with digital mics | ||||
|   dell-m6	Dell desktops/laptops with both type of mics | ||||
|   dell-eq	Dell desktops/laptops | ||||
|   auto		BIOS setup (default) | ||||
| 
 | ||||
| STAC92HD83* | ||||
| =========== | ||||
|   ref		Reference board | ||||
|   mic-ref	Reference board with power managment for ports | ||||
|   dell-s14	Dell laptop | ||||
|   auto		BIOS setup (default) | ||||
| 
 | ||||
| STAC9872 | ||||
| ======== | ||||
|   vaio		Setup for VAIO FE550G/SZ110 | ||||
|   vaio-ar Setup for VAIO AR | ||||
|   vaio		VAIO laptop without SPDIF | ||||
|   auto		BIOS setup (default) | ||||
|  | ||||
| @ -109,6 +109,13 @@ slot, pass `probe_mask=1`.  For the first and the third slots, pass | ||||
| Since 2.6.29 kernel, the driver has a more robust probing method, so | ||||
| this error might happen rarely, though. | ||||
| 
 | ||||
| On a machine with a broken BIOS, sometimes you need to force the | ||||
| driver to probe the codec slots the hardware doesn't report for use. | ||||
| In such a case, turn the bit 8 (0x100) of `probe_mask` option on. | ||||
| Then the rest 8 bits are passed as the codec slots to probe | ||||
| unconditionally.  For example, `probe_mask=0x103` will force to probe | ||||
| the codec slots 0 and 1 no matter what the hardware reports. | ||||
| 
 | ||||
| 
 | ||||
| Interrupt Handling | ||||
| ~~~~~~~~~~~~~~~~~~ | ||||
| @ -358,10 +365,26 @@ modelname:: | ||||
|   to this file. | ||||
| init_verbs:: | ||||
|   The extra verbs to execute at initialization.  You can add a verb by | ||||
|   writing to this file.  Pass tree numbers, nid, verb and parameter. | ||||
|   writing to this file.  Pass three numbers: nid, verb and parameter | ||||
|   (separated with a space). | ||||
| hints:: | ||||
|   Shows hint strings for codec parsers for any use.  Right now it's | ||||
|   not used. | ||||
|   Shows / stores hint strings for codec parsers for any use. | ||||
|   Its format is `key = value`.  For example, passing `hp_detect = yes` | ||||
|   to IDT/STAC codec parser will result in the disablement of the | ||||
|   headphone detection. | ||||
| init_pin_configs:: | ||||
|   Shows the initial pin default config values set by BIOS. | ||||
| driver_pin_configs:: | ||||
|   Shows the pin default values set by the codec parser explicitly. | ||||
|   This doesn't show all pin values but only the changed values by | ||||
|   the parser.  That is, if the parser doesn't change the pin default | ||||
|   config values by itself, this will contain nothing. | ||||
| user_pin_configs:: | ||||
|   Shows the pin default config values to override the BIOS setup. | ||||
|   Writing this (with two numbers, NID and value) appends the new | ||||
|   value.  The given will be used instead of the initial BIOS value at | ||||
|   the next reconfiguration time.  Note that this config will override | ||||
|   even the driver pin configs, too. | ||||
| reconfig:: | ||||
|   Triggers the codec re-configuration.  When any value is written to | ||||
|   this file, the driver re-initialize and parses the codec tree | ||||
| @ -371,6 +394,14 @@ clear:: | ||||
|   Resets the codec, removes the mixer elements and PCM stuff of the | ||||
|   specified codec, and clear all init verbs and hints. | ||||
| 
 | ||||
| For example, when you want to change the pin default configuration | ||||
| value of the pin widget 0x14 to 0x9993013f, and let the driver | ||||
| re-configure based on that state, run like below: | ||||
| ------------------------------------------------------------------------ | ||||
|   # echo 0x14 0x9993013f > /sys/class/sound/hwC0D0/user_pin_configs | ||||
|   # echo 1 > /sys/class/sound/hwC0D0/reconfig   | ||||
| ------------------------------------------------------------------------ | ||||
| 
 | ||||
| 
 | ||||
| Power-Saving | ||||
| ~~~~~~~~~~~~ | ||||
| @ -461,6 +492,16 @@ run with `--no-upload` option, and attach the generated file. | ||||
| There are some other useful options.  See `--help` option output for | ||||
| details. | ||||
| 
 | ||||
| When a probe error occurs or when the driver obviously assigns a | ||||
| mismatched model, it'd be helpful to load the driver with | ||||
| `probe_only=1` option (at best after the cold reboot) and run | ||||
| alsa-info at this state.  With this option, the driver won't configure | ||||
| the mixer and PCM but just tries to probe the codec slot.  After | ||||
| probing, the proc file is available, so you can get the raw codec | ||||
| information before modified by the driver.  Of course, the driver | ||||
| isn't usable with `probe_only=1`.  But you can continue the | ||||
| configuration via hwdep sysfs file if hda-reconfig option is enabled. | ||||
| 
 | ||||
| 
 | ||||
| hda-verb | ||||
| ~~~~~~~~ | ||||
|  | ||||
| @ -2112,6 +2112,8 @@ | ||||
| #define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c | ||||
| #define PCI_DEVICE_ID_MELLANOX_SINAI	0x6274 | ||||
| 
 | ||||
| #define PCI_VENDOR_ID_DFI		0x15bd | ||||
| 
 | ||||
| #define PCI_VENDOR_ID_QUICKNET		0x15e2 | ||||
| #define PCI_DEVICE_ID_QUICKNET_XJ	0x0500 | ||||
| 
 | ||||
|  | ||||
| @ -138,6 +138,7 @@ void snd_hda_detach_beep_device(struct hda_codec *codec) | ||||
| 
 | ||||
| 		input_unregister_device(beep->dev); | ||||
| 		kfree(beep); | ||||
| 		codec->beep = NULL; | ||||
| 	} | ||||
| } | ||||
| EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device); | ||||
|  | ||||
| @ -39,7 +39,7 @@ struct hda_beep { | ||||
| int snd_hda_attach_beep_device(struct hda_codec *codec, int nid); | ||||
| void snd_hda_detach_beep_device(struct hda_codec *codec); | ||||
| #else | ||||
| #define snd_hda_attach_beep_device(...) | ||||
| #define snd_hda_attach_beep_device(...)		0 | ||||
| #define snd_hda_detach_beep_device(...) | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| @ -647,9 +647,9 @@ static void /*__devinit*/ setup_fg_nodes(struct hda_codec *codec) | ||||
| 
 | ||||
| 	total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid); | ||||
| 	for (i = 0; i < total_nodes; i++, nid++) { | ||||
| 		unsigned int func; | ||||
| 		func = snd_hda_param_read(codec, nid, AC_PAR_FUNCTION_TYPE); | ||||
| 		switch (func & 0xff) { | ||||
| 		codec->function_id = snd_hda_param_read(codec, nid, | ||||
| 						AC_PAR_FUNCTION_TYPE) & 0xff; | ||||
| 		switch (codec->function_id) { | ||||
| 		case AC_GRP_AUDIO_FUNCTION: | ||||
| 			codec->afg = nid; | ||||
| 			break; | ||||
| @ -682,11 +682,140 @@ static int read_widget_caps(struct hda_codec *codec, hda_nid_t fg_node) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* read all pin default configurations and save codec->init_pins */ | ||||
| static int read_pin_defaults(struct hda_codec *codec) | ||||
| { | ||||
| 	int i; | ||||
| 	hda_nid_t nid = codec->start_nid; | ||||
| 
 | ||||
| 	for (i = 0; i < codec->num_nodes; i++, nid++) { | ||||
| 		struct hda_pincfg *pin; | ||||
| 		unsigned int wcaps = get_wcaps(codec, nid); | ||||
| 		unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >> | ||||
| 				AC_WCAP_TYPE_SHIFT; | ||||
| 		if (wid_type != AC_WID_PIN) | ||||
| 			continue; | ||||
| 		pin = snd_array_new(&codec->init_pins); | ||||
| 		if (!pin) | ||||
| 			return -ENOMEM; | ||||
| 		pin->nid = nid; | ||||
| 		pin->cfg = snd_hda_codec_read(codec, nid, 0, | ||||
| 					      AC_VERB_GET_CONFIG_DEFAULT, 0); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* look up the given pin config list and return the item matching with NID */ | ||||
| static struct hda_pincfg *look_up_pincfg(struct hda_codec *codec, | ||||
| 					 struct snd_array *array, | ||||
| 					 hda_nid_t nid) | ||||
| { | ||||
| 	int i; | ||||
| 	for (i = 0; i < array->used; i++) { | ||||
| 		struct hda_pincfg *pin = snd_array_elem(array, i); | ||||
| 		if (pin->nid == nid) | ||||
| 			return pin; | ||||
| 	} | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| /* write a config value for the given NID */ | ||||
| static void set_pincfg(struct hda_codec *codec, hda_nid_t nid, | ||||
| 		       unsigned int cfg) | ||||
| { | ||||
| 	int i; | ||||
| 	for (i = 0; i < 4; i++) { | ||||
| 		snd_hda_codec_write(codec, nid, 0, | ||||
| 				    AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i, | ||||
| 				    cfg & 0xff); | ||||
| 		cfg >>= 8; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* set the current pin config value for the given NID.
 | ||||
|  * the value is cached, and read via snd_hda_codec_get_pincfg() | ||||
|  */ | ||||
| int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, | ||||
| 		       hda_nid_t nid, unsigned int cfg) | ||||
| { | ||||
| 	struct hda_pincfg *pin; | ||||
| 	unsigned int oldcfg; | ||||
| 
 | ||||
| 	oldcfg = snd_hda_codec_get_pincfg(codec, nid); | ||||
| 	pin = look_up_pincfg(codec, list, nid); | ||||
| 	if (!pin) { | ||||
| 		pin = snd_array_new(list); | ||||
| 		if (!pin) | ||||
| 			return -ENOMEM; | ||||
| 		pin->nid = nid; | ||||
| 	} | ||||
| 	pin->cfg = cfg; | ||||
| 
 | ||||
| 	/* change only when needed; e.g. if the pincfg is already present
 | ||||
| 	 * in user_pins[], don't write it | ||||
| 	 */ | ||||
| 	cfg = snd_hda_codec_get_pincfg(codec, nid); | ||||
| 	if (oldcfg != cfg) | ||||
| 		set_pincfg(codec, nid, cfg); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int snd_hda_codec_set_pincfg(struct hda_codec *codec, | ||||
| 			     hda_nid_t nid, unsigned int cfg) | ||||
| { | ||||
| 	return snd_hda_add_pincfg(codec, &codec->driver_pins, nid, cfg); | ||||
| } | ||||
| EXPORT_SYMBOL_HDA(snd_hda_codec_set_pincfg); | ||||
| 
 | ||||
| /* get the current pin config value of the given pin NID */ | ||||
| unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid) | ||||
| { | ||||
| 	struct hda_pincfg *pin; | ||||
| 
 | ||||
| #ifdef CONFIG_SND_HDA_HWDEP | ||||
| 	pin = look_up_pincfg(codec, &codec->user_pins, nid); | ||||
| 	if (pin) | ||||
| 		return pin->cfg; | ||||
| #endif | ||||
| 	pin = look_up_pincfg(codec, &codec->driver_pins, nid); | ||||
| 	if (pin) | ||||
| 		return pin->cfg; | ||||
| 	pin = look_up_pincfg(codec, &codec->init_pins, nid); | ||||
| 	if (pin) | ||||
| 		return pin->cfg; | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_HDA(snd_hda_codec_get_pincfg); | ||||
| 
 | ||||
| /* restore all current pin configs */ | ||||
| static void restore_pincfgs(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); | ||||
| 		set_pincfg(codec, pin->nid, | ||||
| 			   snd_hda_codec_get_pincfg(codec, pin->nid)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void init_hda_cache(struct hda_cache_rec *cache, | ||||
| 			   unsigned int record_size); | ||||
| static void free_hda_cache(struct hda_cache_rec *cache); | ||||
| 
 | ||||
| /* restore the initial pin cfgs and release all pincfg lists */ | ||||
| static void restore_init_pincfgs(struct hda_codec *codec) | ||||
| { | ||||
| 	/* first free driver_pins and user_pins, then call restore_pincfg
 | ||||
| 	 * so that only the values in init_pins are restored | ||||
| 	 */ | ||||
| 	snd_array_free(&codec->driver_pins); | ||||
| #ifdef CONFIG_SND_HDA_HWDEP | ||||
| 	snd_array_free(&codec->user_pins); | ||||
| #endif | ||||
| 	restore_pincfgs(codec); | ||||
| 	snd_array_free(&codec->init_pins); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * codec destructor | ||||
|  */ | ||||
| @ -694,6 +823,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) | ||||
| { | ||||
| 	if (!codec) | ||||
| 		return; | ||||
| 	restore_init_pincfgs(codec); | ||||
| #ifdef CONFIG_SND_HDA_POWER_SAVE | ||||
| 	cancel_delayed_work(&codec->power_work); | ||||
| 	flush_workqueue(codec->bus->workq); | ||||
| @ -712,6 +842,9 @@ static void snd_hda_codec_free(struct hda_codec *codec) | ||||
| 	kfree(codec); | ||||
| } | ||||
| 
 | ||||
| static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | ||||
| 				unsigned int power_state); | ||||
| 
 | ||||
| /**
 | ||||
|  * snd_hda_codec_new - create a HDA codec | ||||
|  * @bus: the bus to assign | ||||
| @ -751,6 +884,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr | ||||
| 	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 snd_kcontrol *), 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) { | ||||
| 		codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); | ||||
| 		if (!codec->modelname) { | ||||
| @ -787,15 +922,18 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr | ||||
| 	setup_fg_nodes(codec); | ||||
| 	if (!codec->afg && !codec->mfg) { | ||||
| 		snd_printdd("hda_codec: no AFG or MFG node found\n"); | ||||
| 		snd_hda_codec_free(codec); | ||||
| 		return -ENODEV; | ||||
| 		err = -ENODEV; | ||||
| 		goto error; | ||||
| 	} | ||||
| 
 | ||||
| 	if (read_widget_caps(codec, codec->afg ? codec->afg : codec->mfg) < 0) { | ||||
| 	err = read_widget_caps(codec, codec->afg ? codec->afg : codec->mfg); | ||||
| 	if (err < 0) { | ||||
| 		snd_printk(KERN_ERR "hda_codec: cannot malloc\n"); | ||||
| 		snd_hda_codec_free(codec); | ||||
| 		return -ENOMEM; | ||||
| 		goto error; | ||||
| 	} | ||||
| 	err = read_pin_defaults(codec); | ||||
| 	if (err < 0) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	if (!codec->subsystem_id) { | ||||
| 		hda_nid_t nid = codec->afg ? codec->afg : codec->mfg; | ||||
| @ -806,12 +944,15 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr | ||||
| 	if (bus->modelname) | ||||
| 		codec->modelname = kstrdup(bus->modelname, GFP_KERNEL); | ||||
| 
 | ||||
| 	/* power-up all before initialization */ | ||||
| 	hda_set_power_state(codec, | ||||
| 			    codec->afg ? codec->afg : codec->mfg, | ||||
| 			    AC_PWRST_D0); | ||||
| 
 | ||||
| 	if (do_init) { | ||||
| 		err = snd_hda_codec_configure(codec); | ||||
| 		if (err < 0) { | ||||
| 			snd_hda_codec_free(codec); | ||||
| 			return err; | ||||
| 		} | ||||
| 		if (err < 0) | ||||
| 			goto error; | ||||
| 	} | ||||
| 	snd_hda_codec_proc_new(codec); | ||||
| 
 | ||||
| @ -824,6 +965,10 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr | ||||
| 	if (codecp) | ||||
| 		*codecp = codec; | ||||
| 	return 0; | ||||
| 
 | ||||
|  error: | ||||
| 	snd_hda_codec_free(codec); | ||||
| 	return err; | ||||
| } | ||||
| EXPORT_SYMBOL_HDA(snd_hda_codec_new); | ||||
| 
 | ||||
| @ -907,6 +1052,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream); | ||||
| 
 | ||||
| /* FIXME: more better hash key? */ | ||||
| #define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) | ||||
| #define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24)) | ||||
| #define INFO_AMP_CAPS	(1<<0) | ||||
| #define INFO_AMP_VOL(ch)	(1 << (1 + (ch))) | ||||
| 
 | ||||
| @ -997,6 +1143,21 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, | ||||
| } | ||||
| EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps); | ||||
| 
 | ||||
| u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) | ||||
| { | ||||
| 	struct hda_amp_info *info; | ||||
| 
 | ||||
| 	info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid)); | ||||
| 	if (!info) | ||||
| 		return 0; | ||||
| 	if (!info->head.val) { | ||||
| 		info->amp_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | ||||
| 		info->head.val |= INFO_AMP_CAPS; | ||||
| 	} | ||||
| 	return info->amp_caps; | ||||
| } | ||||
| EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); | ||||
| 
 | ||||
| /*
 | ||||
|  * read the current volume to info | ||||
|  * if the cache exists, read the cache value. | ||||
| @ -1120,6 +1281,7 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, | ||||
| 	u16 nid = get_amp_nid(kcontrol); | ||||
| 	u8 chs = get_amp_channels(kcontrol); | ||||
| 	int dir = get_amp_direction(kcontrol); | ||||
| 	unsigned int ofs = get_amp_offset(kcontrol); | ||||
| 	u32 caps; | ||||
| 
 | ||||
| 	caps = query_amp_caps(codec, nid, dir); | ||||
| @ -1131,6 +1293,8 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, | ||||
| 		       kcontrol->id.name); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	if (ofs < caps) | ||||
| 		caps -= ofs; | ||||
| 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||||
| 	uinfo->count = chs == 3 ? 2 : 1; | ||||
| 	uinfo->value.integer.min = 0; | ||||
| @ -1139,6 +1303,32 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, | ||||
| } | ||||
| EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info); | ||||
| 
 | ||||
| 
 | ||||
| static inline unsigned int | ||||
| read_amp_value(struct hda_codec *codec, hda_nid_t nid, | ||||
| 	       int ch, int dir, int idx, unsigned int ofs) | ||||
| { | ||||
| 	unsigned int val; | ||||
| 	val = snd_hda_codec_amp_read(codec, nid, ch, dir, idx); | ||||
| 	val &= HDA_AMP_VOLMASK; | ||||
| 	if (val >= ofs) | ||||
| 		val -= ofs; | ||||
| 	else | ||||
| 		val = 0; | ||||
| 	return val; | ||||
| } | ||||
| 
 | ||||
| static inline int | ||||
| update_amp_value(struct hda_codec *codec, hda_nid_t nid, | ||||
| 		 int ch, int dir, int idx, unsigned int ofs, | ||||
| 		 unsigned int val) | ||||
| { | ||||
| 	if (val > 0) | ||||
| 		val += ofs; | ||||
| 	return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, | ||||
| 					HDA_AMP_VOLMASK, val); | ||||
| } | ||||
| 
 | ||||
| int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, | ||||
| 				 struct snd_ctl_elem_value *ucontrol) | ||||
| { | ||||
| @ -1147,14 +1337,13 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, | ||||
| 	int chs = get_amp_channels(kcontrol); | ||||
| 	int dir = get_amp_direction(kcontrol); | ||||
| 	int idx = get_amp_index(kcontrol); | ||||
| 	unsigned int ofs = get_amp_offset(kcontrol); | ||||
| 	long *valp = ucontrol->value.integer.value; | ||||
| 
 | ||||
| 	if (chs & 1) | ||||
| 		*valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) | ||||
| 			& HDA_AMP_VOLMASK; | ||||
| 		*valp++ = read_amp_value(codec, nid, 0, dir, idx, ofs); | ||||
| 	if (chs & 2) | ||||
| 		*valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) | ||||
| 			& HDA_AMP_VOLMASK; | ||||
| 		*valp = read_amp_value(codec, nid, 1, dir, idx, ofs); | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get); | ||||
| @ -1167,18 +1356,17 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, | ||||
| 	int chs = get_amp_channels(kcontrol); | ||||
| 	int dir = get_amp_direction(kcontrol); | ||||
| 	int idx = get_amp_index(kcontrol); | ||||
| 	unsigned int ofs = get_amp_offset(kcontrol); | ||||
| 	long *valp = ucontrol->value.integer.value; | ||||
| 	int change = 0; | ||||
| 
 | ||||
| 	snd_hda_power_up(codec); | ||||
| 	if (chs & 1) { | ||||
| 		change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, | ||||
| 						  0x7f, *valp); | ||||
| 		change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp); | ||||
| 		valp++; | ||||
| 	} | ||||
| 	if (chs & 2) | ||||
| 		change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, | ||||
| 						   0x7f, *valp); | ||||
| 		change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp); | ||||
| 	snd_hda_power_down(codec); | ||||
| 	return change; | ||||
| } | ||||
| @ -1190,6 +1378,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, | ||||
| 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||||
| 	hda_nid_t nid = get_amp_nid(kcontrol); | ||||
| 	int dir = get_amp_direction(kcontrol); | ||||
| 	unsigned int ofs = get_amp_offset(kcontrol); | ||||
| 	u32 caps, val1, val2; | ||||
| 
 | ||||
| 	if (size < 4 * sizeof(unsigned int)) | ||||
| @ -1198,6 +1387,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, | ||||
| 	val2 = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; | ||||
| 	val2 = (val2 + 1) * 25; | ||||
| 	val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT); | ||||
| 	val1 += ofs; | ||||
| 	val1 = ((int)val1) * ((int)val2); | ||||
| 	if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv)) | ||||
| 		return -EFAULT; | ||||
| @ -1268,7 +1458,6 @@ int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl) | ||||
| } | ||||
| EXPORT_SYMBOL_HDA(snd_hda_ctl_add); | ||||
| 
 | ||||
| #ifdef CONFIG_SND_HDA_RECONFIG | ||||
| /* Clear all controls assigned to the given codec */ | ||||
| void snd_hda_ctls_clear(struct hda_codec *codec) | ||||
| { | ||||
| @ -1279,9 +1468,52 @@ void snd_hda_ctls_clear(struct hda_codec *codec) | ||||
| 	snd_array_free(&codec->mixers); | ||||
| } | ||||
| 
 | ||||
| void snd_hda_codec_reset(struct hda_codec *codec) | ||||
| /* pseudo device locking
 | ||||
|  * toggle card->shutdown to allow/disallow the device access (as a hack) | ||||
|  */ | ||||
| static int hda_lock_devices(struct snd_card *card) | ||||
| { | ||||
| 	int i; | ||||
| 	spin_lock(&card->files_lock); | ||||
| 	if (card->shutdown) { | ||||
| 		spin_unlock(&card->files_lock); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	card->shutdown = 1; | ||||
| 	spin_unlock(&card->files_lock); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void hda_unlock_devices(struct snd_card *card) | ||||
| { | ||||
| 	spin_lock(&card->files_lock); | ||||
| 	card->shutdown = 0; | ||||
| 	spin_unlock(&card->files_lock); | ||||
| } | ||||
| 
 | ||||
| int snd_hda_codec_reset(struct hda_codec *codec) | ||||
| { | ||||
| 	struct snd_card *card = codec->bus->card; | ||||
| 	int i, pcm; | ||||
| 
 | ||||
| 	if (hda_lock_devices(card) < 0) | ||||
| 		return -EBUSY; | ||||
| 	/* check whether the codec isn't used by any mixer or PCM streams */ | ||||
| 	if (!list_empty(&card->ctl_files)) { | ||||
| 		hda_unlock_devices(card); | ||||
| 		return -EBUSY; | ||||
| 	} | ||||
| 	for (pcm = 0; pcm < codec->num_pcms; pcm++) { | ||||
| 		struct hda_pcm *cpcm = &codec->pcm_info[pcm]; | ||||
| 		if (!cpcm->pcm) | ||||
| 			continue; | ||||
| 		if (cpcm->pcm->streams[0].substream_opened || | ||||
| 		    cpcm->pcm->streams[1].substream_opened) { | ||||
| 			hda_unlock_devices(card); | ||||
| 			return -EBUSY; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* OK, let it free */ | ||||
| 
 | ||||
| #ifdef CONFIG_SND_HDA_POWER_SAVE | ||||
| 	cancel_delayed_work(&codec->power_work); | ||||
| @ -1291,8 +1523,7 @@ void snd_hda_codec_reset(struct hda_codec *codec) | ||||
| 	/* relase PCMs */ | ||||
| 	for (i = 0; i < codec->num_pcms; i++) { | ||||
| 		if (codec->pcm_info[i].pcm) { | ||||
| 			snd_device_free(codec->bus->card, | ||||
| 					codec->pcm_info[i].pcm); | ||||
| 			snd_device_free(card, codec->pcm_info[i].pcm); | ||||
| 			clear_bit(codec->pcm_info[i].device, | ||||
| 				  codec->bus->pcm_dev_bits); | ||||
| 		} | ||||
| @ -1305,13 +1536,22 @@ void snd_hda_codec_reset(struct hda_codec *codec) | ||||
| 	free_hda_cache(&codec->cmd_cache); | ||||
| 	init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); | ||||
| 	init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); | ||||
| 	/* free only driver_pins so that init_pins + user_pins are restored */ | ||||
| 	snd_array_free(&codec->driver_pins); | ||||
| 	restore_pincfgs(codec); | ||||
| 	codec->num_pcms = 0; | ||||
| 	codec->pcm_info = NULL; | ||||
| 	codec->preset = NULL; | ||||
| 	memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); | ||||
| 	codec->slave_dig_outs = NULL; | ||||
| 	codec->spdif_status_reset = 0; | ||||
| 	module_put(codec->owner); | ||||
| 	codec->owner = NULL; | ||||
| 
 | ||||
| 	/* allow device access again */ | ||||
| 	hda_unlock_devices(card); | ||||
| 	return 0; | ||||
| } | ||||
| #endif /* CONFIG_SND_HDA_RECONFIG */ | ||||
| 
 | ||||
| /* create a virtual master control and add slaves */ | ||||
| int snd_hda_add_vmaster(struct hda_codec *codec, char *name, | ||||
| @ -1336,15 +1576,20 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, | ||||
| 	 | ||||
| 	for (s = slaves; *s; s++) { | ||||
| 		struct snd_kcontrol *sctl; | ||||
| 
 | ||||
| 		sctl = snd_hda_find_mixer_ctl(codec, *s); | ||||
| 		if (!sctl) { | ||||
| 			snd_printdd("Cannot find slave %s, skipped\n", *s); | ||||
| 			continue; | ||||
| 		int i = 0; | ||||
| 		for (;;) { | ||||
| 			sctl = _snd_hda_find_mixer_ctl(codec, *s, i); | ||||
| 			if (!sctl) { | ||||
| 				if (!i) | ||||
| 					snd_printdd("Cannot find slave %s, " | ||||
| 						    "skipped\n", *s); | ||||
| 				break; | ||||
| 			} | ||||
| 			err = snd_ctl_add_slave(kctl, sctl); | ||||
| 			if (err < 0) | ||||
| 				return err; | ||||
| 			i++; | ||||
| 		} | ||||
| 		err = snd_ctl_add_slave(kctl, sctl); | ||||
| 		if (err < 0) | ||||
| 			return err; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| @ -1955,6 +2200,8 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) | ||||
| 	} | ||||
| 	for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) { | ||||
| 		kctl = snd_ctl_new1(dig_mix, codec); | ||||
| 		if (!kctl) | ||||
| 			return -ENOMEM; | ||||
| 		kctl->private_value = nid; | ||||
| 		err = snd_hda_ctl_add(codec, kctl); | ||||
| 		if (err < 0) | ||||
| @ -2074,8 +2321,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | ||||
| 				 * don't power down the widget if it controls | ||||
| 				 * eapd and EAPD_BTLENABLE is set. | ||||
| 				 */ | ||||
| 				pincap = snd_hda_param_read(codec, nid, | ||||
| 							    AC_PAR_PIN_CAP); | ||||
| 				pincap = snd_hda_query_pin_caps(codec, nid); | ||||
| 				if (pincap & AC_PINCAP_EAPD) { | ||||
| 					int eapd = snd_hda_codec_read(codec, | ||||
| 						nid, 0, | ||||
| @ -2144,6 +2390,7 @@ static void hda_call_codec_resume(struct hda_codec *codec) | ||||
| 	hda_set_power_state(codec, | ||||
| 			    codec->afg ? codec->afg : codec->mfg, | ||||
| 			    AC_PWRST_D0); | ||||
| 	restore_pincfgs(codec); /* restore all current pin configs */ | ||||
| 	hda_exec_init_verbs(codec); | ||||
| 	if (codec->patch_ops.resume) | ||||
| 		codec->patch_ops.resume(codec); | ||||
| @ -2171,8 +2418,16 @@ int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus) | ||||
| 
 | ||||
| 	list_for_each_entry(codec, &bus->codec_list, list) { | ||||
| 		int err = snd_hda_codec_build_controls(codec); | ||||
| 		if (err < 0) | ||||
| 			return err; | ||||
| 		if (err < 0) { | ||||
| 			printk(KERN_ERR "hda_codec: cannot build controls" | ||||
| 			       "for #%d (error %d)\n", codec->addr, err);  | ||||
| 			err = snd_hda_codec_reset(codec); | ||||
| 			if (err < 0) { | ||||
| 				printk(KERN_ERR | ||||
| 				       "hda_codec: cannot revert codec\n"); | ||||
| 				return err; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| @ -2181,19 +2436,12 @@ EXPORT_SYMBOL_HDA(snd_hda_build_controls); | ||||
| int snd_hda_codec_build_controls(struct hda_codec *codec) | ||||
| { | ||||
| 	int err = 0; | ||||
| 	/* fake as if already powered-on */ | ||||
| 	hda_keep_power_on(codec); | ||||
| 	/* then fire up */ | ||||
| 	hda_set_power_state(codec, | ||||
| 			    codec->afg ? codec->afg : codec->mfg, | ||||
| 			    AC_PWRST_D0); | ||||
| 	hda_exec_init_verbs(codec); | ||||
| 	/* continue to initialize... */ | ||||
| 	if (codec->patch_ops.init) | ||||
| 		err = codec->patch_ops.init(codec); | ||||
| 	if (!err && codec->patch_ops.build_controls) | ||||
| 		err = codec->patch_ops.build_controls(codec); | ||||
| 	snd_hda_power_down(codec); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
| 	return 0; | ||||
| @ -2306,12 +2554,11 @@ EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); | ||||
| static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, | ||||
| 				u32 *ratesp, u64 *formatsp, unsigned int *bpsp) | ||||
| { | ||||
| 	int i; | ||||
| 	unsigned int val, streams; | ||||
| 	unsigned int i, val, wcaps; | ||||
| 
 | ||||
| 	val = 0; | ||||
| 	if (nid != codec->afg && | ||||
| 	    (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) { | ||||
| 	wcaps = get_wcaps(codec, nid); | ||||
| 	if (nid != codec->afg && (wcaps & AC_WCAP_FORMAT_OVRD)) { | ||||
| 		val = snd_hda_param_read(codec, nid, AC_PAR_PCM); | ||||
| 		if (val == -1) | ||||
| 			return -EIO; | ||||
| @ -2325,15 +2572,20 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, | ||||
| 			if (val & (1 << i)) | ||||
| 				rates |= rate_bits[i].alsa_bits; | ||||
| 		} | ||||
| 		if (rates == 0) { | ||||
| 			snd_printk(KERN_ERR "hda_codec: rates == 0 " | ||||
| 				   "(nid=0x%x, val=0x%x, ovrd=%i)\n", | ||||
| 					nid, val, | ||||
| 					(wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0); | ||||
| 			return -EIO; | ||||
| 		} | ||||
| 		*ratesp = rates; | ||||
| 	} | ||||
| 
 | ||||
| 	if (formatsp || bpsp) { | ||||
| 		u64 formats = 0; | ||||
| 		unsigned int bps; | ||||
| 		unsigned int wcaps; | ||||
| 		unsigned int streams, bps; | ||||
| 
 | ||||
| 		wcaps = get_wcaps(codec, nid); | ||||
| 		streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); | ||||
| 		if (streams == -1) | ||||
| 			return -EIO; | ||||
| @ -2386,6 +2638,15 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, | ||||
| 			formats |= SNDRV_PCM_FMTBIT_U8; | ||||
| 			bps = 8; | ||||
| 		} | ||||
| 		if (formats == 0) { | ||||
| 			snd_printk(KERN_ERR "hda_codec: formats == 0 " | ||||
| 				   "(nid=0x%x, val=0x%x, ovrd=%i, " | ||||
| 				   "streams=0x%x)\n", | ||||
| 					nid, val, | ||||
| 					(wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0, | ||||
| 					streams); | ||||
| 			return -EIO; | ||||
| 		} | ||||
| 		if (formatsp) | ||||
| 			*formatsp = formats; | ||||
| 		if (bpsp) | ||||
| @ -2501,12 +2762,16 @@ static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo, | ||||
| static int set_pcm_default_values(struct hda_codec *codec, | ||||
| 				  struct hda_pcm_stream *info) | ||||
| { | ||||
| 	int err; | ||||
| 
 | ||||
| 	/* query support PCM information from the given NID */ | ||||
| 	if (info->nid && (!info->rates || !info->formats)) { | ||||
| 		snd_hda_query_supported_pcm(codec, info->nid, | ||||
| 		err = snd_hda_query_supported_pcm(codec, info->nid, | ||||
| 				info->rates ? NULL : &info->rates, | ||||
| 				info->formats ? NULL : &info->formats, | ||||
| 				info->maxbps ? NULL : &info->maxbps); | ||||
| 		if (err < 0) | ||||
| 			return err; | ||||
| 	} | ||||
| 	if (info->ops.open == NULL) | ||||
| 		info->ops.open = hda_pcm_default_open_close; | ||||
| @ -2549,13 +2814,10 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type) | ||||
| 		for (i = 0; i < ARRAY_SIZE(audio_idx); i++) { | ||||
| 			dev = audio_idx[i]; | ||||
| 			if (!test_bit(dev, bus->pcm_dev_bits)) | ||||
| 				break; | ||||
| 				goto ok; | ||||
| 		} | ||||
| 		if (i >= ARRAY_SIZE(audio_idx)) { | ||||
| 			snd_printk(KERN_WARNING "Too many audio devices\n"); | ||||
| 			return -EAGAIN; | ||||
| 		} | ||||
| 		break; | ||||
| 		snd_printk(KERN_WARNING "Too many audio devices\n"); | ||||
| 		return -EAGAIN; | ||||
| 	case HDA_PCM_TYPE_SPDIF: | ||||
| 	case HDA_PCM_TYPE_HDMI: | ||||
| 	case HDA_PCM_TYPE_MODEM: | ||||
| @ -2570,6 +2832,7 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type) | ||||
| 		snd_printk(KERN_WARNING "Invalid PCM type %d\n", type); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  ok: | ||||
| 	set_bit(dev, bus->pcm_dev_bits); | ||||
| 	return dev; | ||||
| } | ||||
| @ -2606,24 +2869,36 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec) | ||||
| 		if (!codec->patch_ops.build_pcms) | ||||
| 			return 0; | ||||
| 		err = codec->patch_ops.build_pcms(codec); | ||||
| 		if (err < 0) | ||||
| 			return err; | ||||
| 		if (err < 0) { | ||||
| 			printk(KERN_ERR "hda_codec: cannot build PCMs" | ||||
| 			       "for #%d (error %d)\n", codec->addr, err);  | ||||
| 			err = snd_hda_codec_reset(codec); | ||||
| 			if (err < 0) { | ||||
| 				printk(KERN_ERR | ||||
| 				       "hda_codec: cannot revert codec\n"); | ||||
| 				return err; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	for (pcm = 0; pcm < codec->num_pcms; pcm++) { | ||||
| 		struct hda_pcm *cpcm = &codec->pcm_info[pcm]; | ||||
| 		int dev; | ||||
| 
 | ||||
| 		if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams) | ||||
| 			return 0; /* no substreams assigned */ | ||||
| 			continue; /* no substreams assigned */ | ||||
| 
 | ||||
| 		if (!cpcm->pcm) { | ||||
| 			dev = get_empty_pcm_device(codec->bus, cpcm->pcm_type); | ||||
| 			if (dev < 0) | ||||
| 				return 0; | ||||
| 				continue; /* no fatal error */ | ||||
| 			cpcm->device = dev; | ||||
| 			err = snd_hda_attach_pcm(codec, cpcm); | ||||
| 			if (err < 0) | ||||
| 				return err; | ||||
| 			if (err < 0) { | ||||
| 				printk(KERN_ERR "hda_codec: cannot attach " | ||||
| 				       "PCM stream %d for codec #%d\n", | ||||
| 				       dev, codec->addr); | ||||
| 				continue; /* no fatal error */ | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| @ -3324,8 +3599,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, | ||||
| 		if (ignore_nids && is_in_nid_list(nid, ignore_nids)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		def_conf = snd_hda_codec_read(codec, nid, 0, | ||||
| 					      AC_VERB_GET_CONFIG_DEFAULT, 0); | ||||
| 		def_conf = snd_hda_codec_get_pincfg(codec, nid); | ||||
| 		if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) | ||||
| 			continue; | ||||
| 		loc = get_defcfg_location(def_conf); | ||||
| @ -3401,10 +3675,22 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, | ||||
| 			cfg->input_pins[AUTO_PIN_AUX] = nid; | ||||
| 			break; | ||||
| 		case AC_JACK_SPDIF_OUT: | ||||
| 			cfg->dig_out_pin = nid; | ||||
| 		case AC_JACK_DIG_OTHER_OUT: | ||||
| 			if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins)) | ||||
| 				continue; | ||||
| 			cfg->dig_out_pins[cfg->dig_outs] = nid; | ||||
| 			cfg->dig_out_type[cfg->dig_outs] = | ||||
| 				(loc == AC_JACK_LOC_HDMI) ? | ||||
| 				HDA_PCM_TYPE_HDMI : HDA_PCM_TYPE_SPDIF; | ||||
| 			cfg->dig_outs++; | ||||
| 			break; | ||||
| 		case AC_JACK_SPDIF_IN: | ||||
| 		case AC_JACK_DIG_OTHER_IN: | ||||
| 			cfg->dig_in_pin = nid; | ||||
| 			if (loc == AC_JACK_LOC_HDMI) | ||||
| 				cfg->dig_in_type = HDA_PCM_TYPE_HDMI; | ||||
| 			else | ||||
| 				cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| @ -3510,6 +3796,9 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, | ||||
| 		   cfg->hp_pins[1], cfg->hp_pins[2], | ||||
| 		   cfg->hp_pins[3], cfg->hp_pins[4]); | ||||
| 	snd_printd("   mono: mono_out=0x%x\n", cfg->mono_out_pin); | ||||
| 	if (cfg->dig_outs) | ||||
| 		snd_printd("   dig-out=0x%x/0x%x\n", | ||||
| 			   cfg->dig_out_pins[0], cfg->dig_out_pins[1]); | ||||
| 	snd_printd("   inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x," | ||||
| 		   " cd=0x%x, aux=0x%x\n", | ||||
| 		   cfg->input_pins[AUTO_PIN_MIC], | ||||
| @ -3518,6 +3807,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, | ||||
| 		   cfg->input_pins[AUTO_PIN_FRONT_LINE], | ||||
| 		   cfg->input_pins[AUTO_PIN_CD], | ||||
| 		   cfg->input_pins[AUTO_PIN_AUX]); | ||||
| 	if (cfg->dig_in_pin) | ||||
| 		snd_printd("   dig-in=0x%x\n", cfg->dig_in_pin); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| @ -739,6 +739,7 @@ struct hda_codec { | ||||
| 	hda_nid_t mfg;	/* MFG node id */ | ||||
| 
 | ||||
| 	/* ids */ | ||||
| 	u32 function_id; | ||||
| 	u32 vendor_id; | ||||
| 	u32 subsystem_id; | ||||
| 	u32 revision_id; | ||||
| @ -778,11 +779,14 @@ struct hda_codec { | ||||
| 	unsigned short spdif_ctls;	/* SPDIF control bits */ | ||||
| 	unsigned int spdif_in_enable;	/* SPDIF input enable? */ | ||||
| 	hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ | ||||
| 	struct snd_array init_pins;	/* initial (BIOS) pin configurations */ | ||||
| 	struct snd_array driver_pins;	/* pin configs set by codec parser */ | ||||
| 
 | ||||
| #ifdef CONFIG_SND_HDA_HWDEP | ||||
| 	struct snd_hwdep *hwdep;	/* assigned hwdep device */ | ||||
| 	struct snd_array init_verbs;	/* additional init verbs */ | ||||
| 	struct snd_array hints;		/* additional hints */ | ||||
| 	struct snd_array user_pins;	/* default pin configs to override */ | ||||
| #endif | ||||
| 
 | ||||
| 	/* misc flags */ | ||||
| @ -790,6 +794,9 @@ struct hda_codec { | ||||
| 					     * status change | ||||
| 					     * (e.g. Realtek codecs) | ||||
| 					     */ | ||||
| 	unsigned int pin_amp_workaround:1; /* pin out-amp takes index
 | ||||
| 					    * (e.g. Conexant codecs) | ||||
| 					    */ | ||||
| #ifdef CONFIG_SND_HDA_POWER_SAVE | ||||
| 	unsigned int power_on :1;	/* current (global) power-state */ | ||||
| 	unsigned int power_transition :1; /* power-state in transition */ | ||||
| @ -855,6 +862,18 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec); | ||||
| #define snd_hda_sequence_write_cache	snd_hda_sequence_write | ||||
| #endif | ||||
| 
 | ||||
| /* the struct for codec->pin_configs */ | ||||
| struct hda_pincfg { | ||||
| 	hda_nid_t nid; | ||||
| 	unsigned int cfg; | ||||
| }; | ||||
| 
 | ||||
| unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid); | ||||
| int snd_hda_codec_set_pincfg(struct hda_codec *codec, hda_nid_t nid, | ||||
| 			     unsigned int cfg); | ||||
| int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, | ||||
| 		       hda_nid_t nid, unsigned int cfg); /* for hwdep */ | ||||
| 
 | ||||
| /*
 | ||||
|  * Mixer | ||||
|  */ | ||||
|  | ||||
| @ -144,9 +144,9 @@ static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid | ||||
| 	node->type = (node->wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | ||||
| 
 | ||||
| 	if (node->type == AC_WID_PIN) { | ||||
| 		node->pin_caps = snd_hda_param_read(codec, node->nid, AC_PAR_PIN_CAP); | ||||
| 		node->pin_caps = snd_hda_query_pin_caps(codec, node->nid); | ||||
| 		node->pin_ctl = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||||
| 		node->def_cfg = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||||
| 		node->def_cfg = snd_hda_codec_get_pincfg(codec, node->nid); | ||||
| 	} | ||||
| 
 | ||||
| 	if (node->wid_caps & AC_WCAP_OUT_AMP) { | ||||
|  | ||||
| @ -30,6 +30,12 @@ | ||||
| #include <sound/hda_hwdep.h> | ||||
| #include <sound/minors.h> | ||||
| 
 | ||||
| /* hint string pair */ | ||||
| struct hda_hint { | ||||
| 	const char *key; | ||||
| 	const char *val;	/* contained in the same alloc as key */ | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * write/read an out-of-bound verb | ||||
|  */ | ||||
| @ -99,16 +105,17 @@ static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file) | ||||
| 
 | ||||
| static void clear_hwdep_elements(struct hda_codec *codec) | ||||
| { | ||||
| 	char **head; | ||||
| 	int i; | ||||
| 
 | ||||
| 	/* clear init verbs */ | ||||
| 	snd_array_free(&codec->init_verbs); | ||||
| 	/* clear hints */ | ||||
| 	head = codec->hints.list; | ||||
| 	for (i = 0; i < codec->hints.used; i++, head++) | ||||
| 		kfree(*head); | ||||
| 	for (i = 0; i < codec->hints.used; i++) { | ||||
| 		struct hda_hint *hint = snd_array_elem(&codec->hints, i); | ||||
| 		kfree(hint->key); /* we don't need to free hint->val */ | ||||
| 	} | ||||
| 	snd_array_free(&codec->hints); | ||||
| 	snd_array_free(&codec->user_pins); | ||||
| } | ||||
| 
 | ||||
| static void hwdep_free(struct snd_hwdep *hwdep) | ||||
| @ -140,7 +147,8 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec) | ||||
| #endif | ||||
| 
 | ||||
| 	snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32); | ||||
| 	snd_array_init(&codec->hints, sizeof(char *), 32); | ||||
| 	snd_array_init(&codec->hints, sizeof(struct hda_hint), 32); | ||||
| 	snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| @ -153,7 +161,13 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec) | ||||
| 
 | ||||
| static int clear_codec(struct hda_codec *codec) | ||||
| { | ||||
| 	snd_hda_codec_reset(codec); | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = snd_hda_codec_reset(codec); | ||||
| 	if (err < 0) { | ||||
| 		snd_printk(KERN_ERR "The codec is being used, can't free.\n"); | ||||
| 		return err; | ||||
| 	} | ||||
| 	clear_hwdep_elements(codec); | ||||
| 	return 0; | ||||
| } | ||||
| @ -162,20 +176,29 @@ static int reconfig_codec(struct hda_codec *codec) | ||||
| { | ||||
| 	int err; | ||||
| 
 | ||||
| 	snd_hda_power_up(codec); | ||||
| 	snd_printk(KERN_INFO "hda-codec: reconfiguring\n"); | ||||
| 	snd_hda_codec_reset(codec); | ||||
| 	err = snd_hda_codec_reset(codec); | ||||
| 	if (err < 0) { | ||||
| 		snd_printk(KERN_ERR | ||||
| 			   "The codec is being used, can't reconfigure.\n"); | ||||
| 		goto error; | ||||
| 	} | ||||
| 	err = snd_hda_codec_configure(codec); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
| 		goto error; | ||||
| 	/* rebuild PCMs */ | ||||
| 	err = snd_hda_codec_build_pcms(codec); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
| 		goto error; | ||||
| 	/* rebuild mixers */ | ||||
| 	err = snd_hda_codec_build_controls(codec); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
| 	return snd_card_register(codec->bus->card); | ||||
| 		goto error; | ||||
| 	err = snd_card_register(codec->bus->card); | ||||
|  error: | ||||
| 	snd_hda_power_down(codec); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -271,6 +294,22 @@ static ssize_t type##_store(struct device *dev,			\ | ||||
| CODEC_ACTION_STORE(reconfig); | ||||
| CODEC_ACTION_STORE(clear); | ||||
| 
 | ||||
| static ssize_t init_verbs_show(struct device *dev, | ||||
| 			       struct device_attribute *attr, | ||||
| 			       char *buf) | ||||
| { | ||||
| 	struct snd_hwdep *hwdep = dev_get_drvdata(dev); | ||||
| 	struct hda_codec *codec = hwdep->private_data; | ||||
| 	int i, len = 0; | ||||
| 	for (i = 0; i < codec->init_verbs.used; i++) { | ||||
| 		struct hda_verb *v = snd_array_elem(&codec->init_verbs, i); | ||||
| 		len += snprintf(buf + len, PAGE_SIZE - len, | ||||
| 				"0x%02x 0x%03x 0x%04x\n", | ||||
| 				v->nid, v->verb, v->param); | ||||
| 	} | ||||
| 	return len; | ||||
| } | ||||
| 
 | ||||
| static ssize_t init_verbs_store(struct device *dev, | ||||
| 				struct device_attribute *attr, | ||||
| 				const char *buf, size_t count) | ||||
| @ -293,26 +332,157 @@ static ssize_t init_verbs_store(struct device *dev, | ||||
| 	return count; | ||||
| } | ||||
| 
 | ||||
| static ssize_t hints_show(struct device *dev, | ||||
| 			  struct device_attribute *attr, | ||||
| 			  char *buf) | ||||
| { | ||||
| 	struct snd_hwdep *hwdep = dev_get_drvdata(dev); | ||||
| 	struct hda_codec *codec = hwdep->private_data; | ||||
| 	int i, len = 0; | ||||
| 	for (i = 0; i < codec->hints.used; i++) { | ||||
| 		struct hda_hint *hint = snd_array_elem(&codec->hints, i); | ||||
| 		len += snprintf(buf + len, PAGE_SIZE - len, | ||||
| 				"%s = %s\n", hint->key, hint->val); | ||||
| 	} | ||||
| 	return len; | ||||
| } | ||||
| 
 | ||||
| static struct hda_hint *get_hint(struct hda_codec *codec, const char *key) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < codec->hints.used; i++) { | ||||
| 		struct hda_hint *hint = snd_array_elem(&codec->hints, i); | ||||
| 		if (!strcmp(hint->key, key)) | ||||
| 			return hint; | ||||
| 	} | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static void remove_trail_spaces(char *str) | ||||
| { | ||||
| 	char *p; | ||||
| 	if (!*str) | ||||
| 		return; | ||||
| 	p = str + strlen(str) - 1; | ||||
| 	for (; isspace(*p); p--) { | ||||
| 		*p = 0; | ||||
| 		if (p == str) | ||||
| 			return; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #define MAX_HINTS	1024 | ||||
| 
 | ||||
| static ssize_t hints_store(struct device *dev, | ||||
| 			   struct device_attribute *attr, | ||||
| 			   const char *buf, size_t count) | ||||
| { | ||||
| 	struct snd_hwdep *hwdep = dev_get_drvdata(dev); | ||||
| 	struct hda_codec *codec = hwdep->private_data; | ||||
| 	char *p; | ||||
| 	char **hint; | ||||
| 	char *key, *val; | ||||
| 	struct hda_hint *hint; | ||||
| 
 | ||||
| 	if (!*buf || isspace(*buf) || *buf == '#' || *buf == '\n') | ||||
| 	while (isspace(*buf)) | ||||
| 		buf++; | ||||
| 	if (!*buf || *buf == '#' || *buf == '\n') | ||||
| 		return count; | ||||
| 	p = kstrndup_noeol(buf, 1024); | ||||
| 	if (!p) | ||||
| 	if (*buf == '=') | ||||
| 		return -EINVAL; | ||||
| 	key = kstrndup_noeol(buf, 1024); | ||||
| 	if (!key) | ||||
| 		return -ENOMEM; | ||||
| 	hint = snd_array_new(&codec->hints); | ||||
| 	/* extract key and val */ | ||||
| 	val = strchr(key, '='); | ||||
| 	if (!val) { | ||||
| 		kfree(key); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	*val++ = 0; | ||||
| 	while (isspace(*val)) | ||||
| 		val++; | ||||
| 	remove_trail_spaces(key); | ||||
| 	remove_trail_spaces(val); | ||||
| 	hint = get_hint(codec, key); | ||||
| 	if (hint) { | ||||
| 		/* replace */ | ||||
| 		kfree(hint->key); | ||||
| 		hint->key = key; | ||||
| 		hint->val = val; | ||||
| 		return count; | ||||
| 	} | ||||
| 	/* allocate a new hint entry */ | ||||
| 	if (codec->hints.used >= MAX_HINTS) | ||||
| 		hint = NULL; | ||||
| 	else | ||||
| 		hint = snd_array_new(&codec->hints); | ||||
| 	if (!hint) { | ||||
| 		kfree(p); | ||||
| 		kfree(key); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 	*hint = p; | ||||
| 	hint->key = key; | ||||
| 	hint->val = val; | ||||
| 	return count; | ||||
| } | ||||
| 
 | ||||
| static ssize_t pin_configs_show(struct hda_codec *codec, | ||||
| 				struct snd_array *list, | ||||
| 				char *buf) | ||||
| { | ||||
| 	int i, len = 0; | ||||
| 	for (i = 0; i < list->used; i++) { | ||||
| 		struct hda_pincfg *pin = snd_array_elem(list, i); | ||||
| 		len += sprintf(buf + len, "0x%02x 0x%08x\n", | ||||
| 			       pin->nid, pin->cfg); | ||||
| 	} | ||||
| 	return len; | ||||
| } | ||||
| 
 | ||||
| static ssize_t init_pin_configs_show(struct device *dev, | ||||
| 				     struct device_attribute *attr, | ||||
| 				     char *buf) | ||||
| { | ||||
| 	struct snd_hwdep *hwdep = dev_get_drvdata(dev); | ||||
| 	struct hda_codec *codec = hwdep->private_data; | ||||
| 	return pin_configs_show(codec, &codec->init_pins, buf); | ||||
| } | ||||
| 
 | ||||
| static ssize_t user_pin_configs_show(struct device *dev, | ||||
| 				     struct device_attribute *attr, | ||||
| 				     char *buf) | ||||
| { | ||||
| 	struct snd_hwdep *hwdep = dev_get_drvdata(dev); | ||||
| 	struct hda_codec *codec = hwdep->private_data; | ||||
| 	return pin_configs_show(codec, &codec->user_pins, buf); | ||||
| } | ||||
| 
 | ||||
| static ssize_t driver_pin_configs_show(struct device *dev, | ||||
| 				       struct device_attribute *attr, | ||||
| 				       char *buf) | ||||
| { | ||||
| 	struct snd_hwdep *hwdep = dev_get_drvdata(dev); | ||||
| 	struct hda_codec *codec = hwdep->private_data; | ||||
| 	return pin_configs_show(codec, &codec->driver_pins, buf); | ||||
| } | ||||
| 
 | ||||
| #define MAX_PIN_CONFIGS		32 | ||||
| 
 | ||||
| static ssize_t user_pin_configs_store(struct device *dev, | ||||
| 				      struct device_attribute *attr, | ||||
| 				      const char *buf, size_t count) | ||||
| { | ||||
| 	struct snd_hwdep *hwdep = dev_get_drvdata(dev); | ||||
| 	struct hda_codec *codec = hwdep->private_data; | ||||
| 	int nid, cfg; | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (sscanf(buf, "%i %i", &nid, &cfg) != 2) | ||||
| 		return -EINVAL; | ||||
| 	if (!nid) | ||||
| 		return -EINVAL; | ||||
| 	err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
| 	return count; | ||||
| } | ||||
| 
 | ||||
| @ -331,8 +501,11 @@ static struct device_attribute codec_attrs[] = { | ||||
| 	CODEC_ATTR_RO(mfg), | ||||
| 	CODEC_ATTR_RW(name), | ||||
| 	CODEC_ATTR_RW(modelname), | ||||
| 	CODEC_ATTR_WO(init_verbs), | ||||
| 	CODEC_ATTR_WO(hints), | ||||
| 	CODEC_ATTR_RW(init_verbs), | ||||
| 	CODEC_ATTR_RW(hints), | ||||
| 	CODEC_ATTR_RO(init_pin_configs), | ||||
| 	CODEC_ATTR_RW(user_pin_configs), | ||||
| 	CODEC_ATTR_RO(driver_pin_configs), | ||||
| 	CODEC_ATTR_WO(reconfig), | ||||
| 	CODEC_ATTR_WO(clear), | ||||
| }; | ||||
| @ -351,4 +524,29 @@ int snd_hda_hwdep_add_sysfs(struct hda_codec *codec) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Look for hint string | ||||
|  */ | ||||
| const char *snd_hda_get_hint(struct hda_codec *codec, const char *key) | ||||
| { | ||||
| 	struct hda_hint *hint = get_hint(codec, key); | ||||
| 	return hint ? hint->val : NULL; | ||||
| } | ||||
| EXPORT_SYMBOL_HDA(snd_hda_get_hint); | ||||
| 
 | ||||
| int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key) | ||||
| { | ||||
| 	const char *p = snd_hda_get_hint(codec, key); | ||||
| 	if (!p || !*p) | ||||
| 		return -ENOENT; | ||||
| 	switch (toupper(*p)) { | ||||
| 	case 'T': /* true */ | ||||
| 	case 'Y': /* yes */ | ||||
| 	case '1': | ||||
| 		return 1; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint); | ||||
| 
 | ||||
| #endif /* CONFIG_SND_HDA_RECONFIG */ | ||||
|  | ||||
| @ -381,6 +381,7 @@ struct azx { | ||||
| 
 | ||||
| 	/* HD codec */ | ||||
| 	unsigned short codec_mask; | ||||
| 	int  codec_probe_mask; /* copied from probe_mask option */ | ||||
| 	struct hda_bus *bus; | ||||
| 
 | ||||
| 	/* CORB/RIRB */ | ||||
| @ -858,13 +859,18 @@ static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev) | ||||
| 		      SD_CTL_DMA_START | SD_INT_MASK); | ||||
| } | ||||
| 
 | ||||
| /* stop a stream */ | ||||
| static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) | ||||
| /* stop DMA */ | ||||
| static void azx_stream_clear(struct azx *chip, struct azx_dev *azx_dev) | ||||
| { | ||||
| 	/* stop DMA */ | ||||
| 	azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & | ||||
| 		      ~(SD_CTL_DMA_START | SD_INT_MASK)); | ||||
| 	azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ | ||||
| } | ||||
| 
 | ||||
| /* stop a stream */ | ||||
| static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) | ||||
| { | ||||
| 	azx_stream_clear(chip, azx_dev); | ||||
| 	/* disable SIE */ | ||||
| 	azx_writeb(chip, INTCTL, | ||||
| 		   azx_readb(chip, INTCTL) & ~(1 << azx_dev->index)); | ||||
| @ -1075,8 +1081,7 @@ static int azx_setup_periods(struct azx *chip, | ||||
| 	azx_sd_writel(azx_dev, SD_BDLPL, 0); | ||||
| 	azx_sd_writel(azx_dev, SD_BDLPU, 0); | ||||
| 
 | ||||
| 	period_bytes = snd_pcm_lib_period_bytes(substream); | ||||
| 	azx_dev->period_bytes = period_bytes; | ||||
| 	period_bytes = azx_dev->period_bytes; | ||||
| 	periods = azx_dev->bufsize / period_bytes; | ||||
| 
 | ||||
| 	/* program the initial BDL entries */ | ||||
| @ -1123,24 +1128,17 @@ static int azx_setup_periods(struct azx *chip, | ||||
|  error: | ||||
| 	snd_printk(KERN_ERR "Too many BDL entries: buffer=%d, period=%d\n", | ||||
| 		   azx_dev->bufsize, period_bytes); | ||||
| 	/* reset */ | ||||
| 	azx_sd_writel(azx_dev, SD_BDLPL, 0); | ||||
| 	azx_sd_writel(azx_dev, SD_BDLPU, 0); | ||||
| 	return -EINVAL; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * set up the SD for streaming | ||||
|  */ | ||||
| static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) | ||||
| /* reset stream */ | ||||
| static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev) | ||||
| { | ||||
| 	unsigned char val; | ||||
| 	int timeout; | ||||
| 
 | ||||
| 	/* make sure the run bit is zero for SD */ | ||||
| 	azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & | ||||
| 		      ~SD_CTL_DMA_START); | ||||
| 	/* reset stream */ | ||||
| 	azx_stream_clear(chip, azx_dev); | ||||
| 
 | ||||
| 	azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | | ||||
| 		      SD_CTL_STREAM_RESET); | ||||
| 	udelay(3); | ||||
| @ -1157,7 +1155,15 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) | ||||
| 	while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) && | ||||
| 	       --timeout) | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * set up the SD for streaming | ||||
|  */ | ||||
| static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) | ||||
| { | ||||
| 	/* make sure the run bit is zero for SD */ | ||||
| 	azx_stream_clear(chip, azx_dev); | ||||
| 	/* program the stream_tag */ | ||||
| 	azx_sd_writel(azx_dev, SD_CTL, | ||||
| 		      (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK)| | ||||
| @ -1228,7 +1234,6 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = { | ||||
| }; | ||||
| 
 | ||||
| static int __devinit azx_codec_create(struct azx *chip, const char *model, | ||||
| 				      unsigned int codec_probe_mask, | ||||
| 				      int no_init) | ||||
| { | ||||
| 	struct hda_bus_template bus_temp; | ||||
| @ -1261,7 +1266,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, | ||||
| 
 | ||||
| 	/* First try to probe all given codec slots */ | ||||
| 	for (c = 0; c < max_slots; c++) { | ||||
| 		if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { | ||||
| 		if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { | ||||
| 			if (probe_codec(chip, c) < 0) { | ||||
| 				/* Some BIOSen give you wrong codec addresses
 | ||||
| 				 * that don't exist | ||||
| @ -1285,7 +1290,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, | ||||
| 
 | ||||
| 	/* Then create codec instances */ | ||||
| 	for (c = 0; c < max_slots; c++) { | ||||
| 		if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { | ||||
| 		if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { | ||||
| 			struct hda_codec *codec; | ||||
| 			err = snd_hda_codec_new(chip->bus, c, !no_init, &codec); | ||||
| 			if (err < 0) | ||||
| @ -1403,6 +1408,8 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) | ||||
| 	runtime->private_data = azx_dev; | ||||
| 	snd_pcm_set_sync(substream); | ||||
| 	mutex_unlock(&chip->open_mutex); | ||||
| 
 | ||||
| 	azx_stream_reset(chip, azx_dev); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -1429,6 +1436,11 @@ static int azx_pcm_close(struct snd_pcm_substream *substream) | ||||
| static int azx_pcm_hw_params(struct snd_pcm_substream *substream, | ||||
| 			     struct snd_pcm_hw_params *hw_params) | ||||
| { | ||||
| 	struct azx_dev *azx_dev = get_azx_dev(substream); | ||||
| 
 | ||||
| 	azx_dev->bufsize = 0; | ||||
| 	azx_dev->period_bytes = 0; | ||||
| 	azx_dev->format_val = 0; | ||||
| 	return snd_pcm_lib_malloc_pages(substream, | ||||
| 					params_buffer_bytes(hw_params)); | ||||
| } | ||||
| @ -1443,6 +1455,9 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream) | ||||
| 	azx_sd_writel(azx_dev, SD_BDLPL, 0); | ||||
| 	azx_sd_writel(azx_dev, SD_BDLPU, 0); | ||||
| 	azx_sd_writel(azx_dev, SD_CTL, 0); | ||||
| 	azx_dev->bufsize = 0; | ||||
| 	azx_dev->period_bytes = 0; | ||||
| 	azx_dev->format_val = 0; | ||||
| 
 | ||||
| 	hinfo->ops.cleanup(hinfo, apcm->codec, substream); | ||||
| 
 | ||||
| @ -1456,23 +1471,37 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) | ||||
| 	struct azx_dev *azx_dev = get_azx_dev(substream); | ||||
| 	struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; | ||||
| 	struct snd_pcm_runtime *runtime = substream->runtime; | ||||
| 	unsigned int bufsize, period_bytes, format_val; | ||||
| 	int err; | ||||
| 
 | ||||
| 	azx_dev->bufsize = snd_pcm_lib_buffer_bytes(substream); | ||||
| 	azx_dev->format_val = snd_hda_calc_stream_format(runtime->rate, | ||||
| 							 runtime->channels, | ||||
| 							 runtime->format, | ||||
| 							 hinfo->maxbps); | ||||
| 	if (!azx_dev->format_val) { | ||||
| 	format_val = snd_hda_calc_stream_format(runtime->rate, | ||||
| 						runtime->channels, | ||||
| 						runtime->format, | ||||
| 						hinfo->maxbps); | ||||
| 	if (!format_val) { | ||||
| 		snd_printk(KERN_ERR SFX | ||||
| 			   "invalid format_val, rate=%d, ch=%d, format=%d\n", | ||||
| 			   runtime->rate, runtime->channels, runtime->format); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	bufsize = snd_pcm_lib_buffer_bytes(substream); | ||||
| 	period_bytes = snd_pcm_lib_period_bytes(substream); | ||||
| 
 | ||||
| 	snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", | ||||
| 		    azx_dev->bufsize, azx_dev->format_val); | ||||
| 	if (azx_setup_periods(chip, substream, azx_dev) < 0) | ||||
| 		return -EINVAL; | ||||
| 		    bufsize, format_val); | ||||
| 
 | ||||
| 	if (bufsize != azx_dev->bufsize || | ||||
| 	    period_bytes != azx_dev->period_bytes || | ||||
| 	    format_val != azx_dev->format_val) { | ||||
| 		azx_dev->bufsize = bufsize; | ||||
| 		azx_dev->period_bytes = period_bytes; | ||||
| 		azx_dev->format_val = format_val; | ||||
| 		err = azx_setup_periods(chip, substream, azx_dev); | ||||
| 		if (err < 0) | ||||
| 			return err; | ||||
| 	} | ||||
| 
 | ||||
| 	azx_setup_controller(chip, azx_dev); | ||||
| 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||||
| 		azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1; | ||||
| @ -2100,25 +2129,36 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = { | ||||
| 	SND_PCI_QUIRK(0x1028, 0x20ac, "Dell Studio Desktop", 0x01), | ||||
| 	/* including bogus ALC268 in slot#2 that conflicts with ALC888 */ | ||||
| 	SND_PCI_QUIRK(0x17c0, 0x4085, "Medion MD96630", 0x01), | ||||
| 	/* conflict of ALC268 in slot#3 (digital I/O); a temporary fix */ | ||||
| 	SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba laptop", 0x03), | ||||
| 	/* forced codec slots */ | ||||
| 	SND_PCI_QUIRK(0x1046, 0x1262, "ASUS W5F", 0x103), | ||||
| 	{} | ||||
| }; | ||||
| 
 | ||||
| #define AZX_FORCE_CODEC_MASK	0x100 | ||||
| 
 | ||||
| static void __devinit check_probe_mask(struct azx *chip, int dev) | ||||
| { | ||||
| 	const struct snd_pci_quirk *q; | ||||
| 
 | ||||
| 	if (probe_mask[dev] == -1) { | ||||
| 	chip->codec_probe_mask = probe_mask[dev]; | ||||
| 	if (chip->codec_probe_mask == -1) { | ||||
| 		q = snd_pci_quirk_lookup(chip->pci, probe_mask_list); | ||||
| 		if (q) { | ||||
| 			printk(KERN_INFO | ||||
| 			       "hda_intel: probe_mask set to 0x%x " | ||||
| 			       "for device %04x:%04x\n", | ||||
| 			       q->value, q->subvendor, q->subdevice); | ||||
| 			probe_mask[dev] = q->value; | ||||
| 			chip->codec_probe_mask = q->value; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* check forced option */ | ||||
| 	if (chip->codec_probe_mask != -1 && | ||||
| 	    (chip->codec_probe_mask & AZX_FORCE_CODEC_MASK)) { | ||||
| 		chip->codec_mask = chip->codec_probe_mask & 0xff; | ||||
| 		printk(KERN_INFO "hda_intel: codec_mask forced to 0x%x\n", | ||||
| 		       chip->codec_mask); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -2359,8 +2399,7 @@ static int __devinit azx_probe(struct pci_dev *pci, | ||||
| 	card->private_data = chip; | ||||
| 
 | ||||
| 	/* create codec instances */ | ||||
| 	err = azx_codec_create(chip, model[dev], probe_mask[dev], | ||||
| 			       probe_only[dev]); | ||||
| 	err = azx_codec_create(chip, model[dev], probe_only[dev]); | ||||
| 	if (err < 0) | ||||
| 		goto out_free; | ||||
| 
 | ||||
| @ -2457,10 +2496,10 @@ static struct pci_device_id azx_ids[] = { | ||||
| 	{ PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA }, | ||||
| 	{ PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA }, | ||||
| 	{ PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA }, | ||||
| 	{ PCI_DEVICE(0x10de, 0x0bd4), .driver_data = AZX_DRIVER_NVIDIA }, | ||||
| 	{ PCI_DEVICE(0x10de, 0x0bd5), .driver_data = AZX_DRIVER_NVIDIA }, | ||||
| 	{ PCI_DEVICE(0x10de, 0x0bd6), .driver_data = AZX_DRIVER_NVIDIA }, | ||||
| 	{ PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA }, | ||||
| 	{ PCI_DEVICE(0x10de, 0x0d94), .driver_data = AZX_DRIVER_NVIDIA }, | ||||
| 	{ PCI_DEVICE(0x10de, 0x0d95), .driver_data = AZX_DRIVER_NVIDIA }, | ||||
| 	{ PCI_DEVICE(0x10de, 0x0d96), .driver_data = AZX_DRIVER_NVIDIA }, | ||||
| 	{ PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA }, | ||||
| 	/* Teradici */ | ||||
| 	{ PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, | ||||
| 	/* AMD Generic, PCI class code and Vendor ID for HD Audio */ | ||||
|  | ||||
| @ -26,8 +26,10 @@ | ||||
| /*
 | ||||
|  * for mixer controls | ||||
|  */ | ||||
| #define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs)		\ | ||||
| 	((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23)) | ||||
| #define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \ | ||||
| 	((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19)) | ||||
| 	HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0) | ||||
| /* mono volume with index (index=0,1,...) (channel=1,2) */ | ||||
| #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ | ||||
| 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx,  \ | ||||
| @ -96,7 +98,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, | ||||
| 					    const char *name); | ||||
| int snd_hda_add_vmaster(struct hda_codec *codec, char *name, | ||||
| 			unsigned int *tlv, const char **slaves); | ||||
| void snd_hda_codec_reset(struct hda_codec *codec); | ||||
| int snd_hda_codec_reset(struct hda_codec *codec); | ||||
| int snd_hda_codec_configure(struct hda_codec *codec); | ||||
| 
 | ||||
| /* amp value bits */ | ||||
| @ -134,7 +136,7 @@ extern struct hda_ctl_ops snd_hda_bind_sw;	/* for bind-switch */ | ||||
| 
 | ||||
| struct hda_bind_ctls { | ||||
| 	struct hda_ctl_ops *ops; | ||||
| 	long values[]; | ||||
| 	unsigned long values[]; | ||||
| }; | ||||
| 
 | ||||
| int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, | ||||
| @ -227,6 +229,7 @@ struct hda_multi_out { | ||||
| 	hda_nid_t hp_nid;	/* optional DAC for HP, 0 when not exists */ | ||||
| 	hda_nid_t extra_out_nid[3];	/* optional DACs, 0 when not exists */ | ||||
| 	hda_nid_t dig_out_nid;	/* digital out audio widget */ | ||||
| 	hda_nid_t *slave_dig_outs; | ||||
| 	int max_channels;	/* currently supported analog channels */ | ||||
| 	int dig_out_used;	/* current usage of digital out (HDA_DIG_XXX) */ | ||||
| 	int no_share_stream;	/* don't share a stream with multiple pins */ | ||||
| @ -354,9 +357,12 @@ struct auto_pin_cfg { | ||||
| 	int line_out_type;	/* AUTO_PIN_XXX_OUT */ | ||||
| 	hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS]; | ||||
| 	hda_nid_t input_pins[AUTO_PIN_LAST]; | ||||
| 	hda_nid_t dig_out_pin; | ||||
| 	int dig_outs; | ||||
| 	hda_nid_t dig_out_pins[2]; | ||||
| 	hda_nid_t dig_in_pin; | ||||
| 	hda_nid_t mono_out_pin; | ||||
| 	int dig_out_type[2]; /* HDA_PCM_TYPE_XXX */ | ||||
| 	int dig_in_type; /* HDA_PCM_TYPE_XXX */ | ||||
| }; | ||||
| 
 | ||||
| #define get_defcfg_connect(cfg) \ | ||||
| @ -405,6 +411,7 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid) | ||||
| u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction); | ||||
| int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, | ||||
| 			      unsigned int caps); | ||||
| u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid); | ||||
| 
 | ||||
| int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl); | ||||
| void snd_hda_ctls_clear(struct hda_codec *codec); | ||||
| @ -427,6 +434,23 @@ static inline int snd_hda_hwdep_add_sysfs(struct hda_codec *codec) | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_SND_HDA_RECONFIG | ||||
| const char *snd_hda_get_hint(struct hda_codec *codec, const char *key); | ||||
| int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key); | ||||
| #else | ||||
| static inline | ||||
| const char *snd_hda_get_hint(struct hda_codec *codec, const char *key) | ||||
| { | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static inline | ||||
| int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key) | ||||
| { | ||||
| 	return -ENOENT; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  * power-management | ||||
|  */ | ||||
| @ -458,6 +482,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, | ||||
| #define get_amp_channels(kc)	(((kc)->private_value >> 16) & 0x3) | ||||
| #define get_amp_direction(kc)	(((kc)->private_value >> 18) & 0x1) | ||||
| #define get_amp_index(kc)	(((kc)->private_value >> 19) & 0xf) | ||||
| #define get_amp_offset(kc)	(((kc)->private_value >> 23) & 0x3f) | ||||
| 
 | ||||
| /*
 | ||||
|  * CEA Short Audio Descriptor data | ||||
|  | ||||
| @ -399,8 +399,10 @@ static void print_conn_list(struct snd_info_buffer *buffer, | ||||
| { | ||||
| 	int c, curr = -1; | ||||
| 
 | ||||
| 	if (conn_len > 1 && wid_type != AC_WID_AUD_MIX && | ||||
| 	    wid_type != AC_WID_VOL_KNB) | ||||
| 	if (conn_len > 1 && | ||||
| 	    wid_type != AC_WID_AUD_MIX && | ||||
| 	    wid_type != AC_WID_VOL_KNB && | ||||
| 	    wid_type != AC_WID_POWER) | ||||
| 		curr = snd_hda_codec_read(codec, nid, 0, | ||||
| 					  AC_VERB_GET_CONNECT_SEL, 0); | ||||
| 	snd_iprintf(buffer, "  Connection: %d\n", conn_len); | ||||
| @ -467,8 +469,9 @@ static void print_codec_info(struct snd_info_entry *entry, | ||||
| 	snd_iprintf(buffer, "Codec: %s\n", | ||||
| 		    codec->name ? codec->name : "Not Set"); | ||||
| 	snd_iprintf(buffer, "Address: %d\n", codec->addr); | ||||
| 	snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id); | ||||
| 	snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id); | ||||
| 	snd_iprintf(buffer, "Function Id: 0x%x\n", codec->function_id); | ||||
| 	snd_iprintf(buffer, "Vendor Id: 0x%08x\n", codec->vendor_id); | ||||
| 	snd_iprintf(buffer, "Subsystem Id: 0x%08x\n", codec->subsystem_id); | ||||
| 	snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id); | ||||
| 
 | ||||
| 	if (codec->mfg) | ||||
| @ -554,8 +557,14 @@ static void print_codec_info(struct snd_info_entry *entry, | ||||
| 			snd_iprintf(buffer, "  Amp-Out caps: "); | ||||
| 			print_amp_caps(buffer, codec, nid, HDA_OUTPUT); | ||||
| 			snd_iprintf(buffer, "  Amp-Out vals: "); | ||||
| 			print_amp_vals(buffer, codec, nid, HDA_OUTPUT, | ||||
| 				       wid_caps & AC_WCAP_STEREO, 1); | ||||
| 			if (wid_type == AC_WID_PIN && | ||||
| 			    codec->pin_amp_workaround) | ||||
| 				print_amp_vals(buffer, codec, nid, HDA_OUTPUT, | ||||
| 					       wid_caps & AC_WCAP_STEREO, | ||||
| 					       conn_len); | ||||
| 			else | ||||
| 				print_amp_vals(buffer, codec, nid, HDA_OUTPUT, | ||||
| 					       wid_caps & AC_WCAP_STEREO, 1); | ||||
| 		} | ||||
| 
 | ||||
| 		switch (wid_type) { | ||||
|  | ||||
| @ -27,11 +27,12 @@ | ||||
| #include <sound/core.h> | ||||
| #include "hda_codec.h" | ||||
| #include "hda_local.h" | ||||
| #include "hda_beep.h" | ||||
| 
 | ||||
| struct ad198x_spec { | ||||
| 	struct snd_kcontrol_new *mixers[5]; | ||||
| 	int num_mixers; | ||||
| 
 | ||||
| 	unsigned int beep_amp;	/* beep amp value, set via set_beep_amp() */ | ||||
| 	const struct hda_verb *init_verbs[5];	/* initialization verbs
 | ||||
| 						 * don't forget NULL termination! | ||||
| 						 */ | ||||
| @ -154,6 +155,16 @@ static const char *ad_slave_sws[] = { | ||||
| 
 | ||||
| static void ad198x_free_kctls(struct hda_codec *codec); | ||||
| 
 | ||||
| /* additional beep mixers; the actual parameters are overwritten at build */ | ||||
| static struct snd_kcontrol_new ad_beep_mixer[] = { | ||||
| 	HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Beep Playback Switch", 0, 0, HDA_OUTPUT), | ||||
| 	{ } /* end */ | ||||
| }; | ||||
| 
 | ||||
| #define set_beep_amp(spec, nid, idx, dir) \ | ||||
| 	((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */ | ||||
| 
 | ||||
| static int ad198x_build_controls(struct hda_codec *codec) | ||||
| { | ||||
| 	struct ad198x_spec *spec = codec->spec; | ||||
| @ -181,6 +192,21 @@ static int ad198x_build_controls(struct hda_codec *codec) | ||||
| 			return err; | ||||
| 	} | ||||
| 
 | ||||
| 	/* create beep controls if needed */ | ||||
| 	if (spec->beep_amp) { | ||||
| 		struct snd_kcontrol_new *knew; | ||||
| 		for (knew = ad_beep_mixer; knew->name; knew++) { | ||||
| 			struct snd_kcontrol *kctl; | ||||
| 			kctl = snd_ctl_new1(knew, codec); | ||||
| 			if (!kctl) | ||||
| 				return -ENOMEM; | ||||
| 			kctl->private_value = spec->beep_amp; | ||||
| 			err = snd_hda_ctl_add(codec, kctl); | ||||
| 			if (err < 0) | ||||
| 				return err; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* if we have no master control, let's create it */ | ||||
| 	if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { | ||||
| 		unsigned int vmaster_tlv[4]; | ||||
| @ -406,7 +432,8 @@ static void ad198x_free(struct hda_codec *codec) | ||||
| 		return; | ||||
| 
 | ||||
| 	ad198x_free_kctls(codec); | ||||
| 	kfree(codec->spec); | ||||
| 	kfree(spec); | ||||
| 	snd_hda_detach_beep_device(codec); | ||||
| } | ||||
| 
 | ||||
| static struct hda_codec_ops ad198x_patch_ops = { | ||||
| @ -545,8 +572,6 @@ static struct snd_kcontrol_new ad1986a_mixers[] = { | ||||
| 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x18, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x18, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), | ||||
| @ -610,8 +635,7 @@ static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { | ||||
| 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), | ||||
| 	/* HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x18, 0x0, HDA_OUTPUT),
 | ||||
| 	   HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x18, 0x0, HDA_OUTPUT), | ||||
| 	/* 
 | ||||
| 	   HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT), | ||||
| 	   HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */ | ||||
| 	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), | ||||
| @ -809,8 +833,6 @@ static struct snd_kcontrol_new ad1986a_laptop_automute_mixers[] = { | ||||
| 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME("Beep Playback Volume", 0x18, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Beep Playback Switch", 0x18, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), | ||||
| 	{ | ||||
| @ -1002,10 +1024,8 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = { | ||||
| 	SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD), | ||||
| 	SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), | ||||
| 	SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), | ||||
| 	SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_SAMSUNG), | ||||
| 	SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_SAMSUNG), | ||||
| 	SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_SAMSUNG), | ||||
| 	SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), | ||||
| 	SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG), | ||||
| 	SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), | ||||
| 	SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), | ||||
| 	SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), | ||||
| @ -1027,15 +1047,14 @@ static struct hda_amp_list ad1986a_loopbacks[] = { | ||||
| 
 | ||||
| static int is_jack_available(struct hda_codec *codec, hda_nid_t nid) | ||||
| { | ||||
| 	unsigned int conf = snd_hda_codec_read(codec, nid, 0, | ||||
| 					       AC_VERB_GET_CONFIG_DEFAULT, 0); | ||||
| 	unsigned int conf = snd_hda_codec_get_pincfg(codec, nid); | ||||
| 	return get_defcfg_connect(conf) != AC_JACK_PORT_NONE; | ||||
| } | ||||
| 
 | ||||
| static int patch_ad1986a(struct hda_codec *codec) | ||||
| { | ||||
| 	struct ad198x_spec *spec; | ||||
| 	int board_config; | ||||
| 	int err, board_config; | ||||
| 
 | ||||
| 	spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||||
| 	if (spec == NULL) | ||||
| @ -1043,6 +1062,13 @@ static int patch_ad1986a(struct hda_codec *codec) | ||||
| 
 | ||||
| 	codec->spec = spec; | ||||
| 
 | ||||
| 	err = snd_hda_attach_beep_device(codec, 0x19); | ||||
| 	if (err < 0) { | ||||
| 		ad198x_free(codec); | ||||
| 		return err; | ||||
| 	} | ||||
| 	set_beep_amp(spec, 0x18, 0, HDA_OUTPUT); | ||||
| 
 | ||||
| 	spec->multiout.max_channels = 6; | ||||
| 	spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids); | ||||
| 	spec->multiout.dac_nids = ad1986a_dac_nids; | ||||
| @ -1222,8 +1248,6 @@ static struct snd_kcontrol_new ad1983_mixers[] = { | ||||
| 	HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x10, 1, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x10, 1, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME("Mic Boost", 0x0c, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), | ||||
| @ -1294,6 +1318,7 @@ static struct hda_amp_list ad1983_loopbacks[] = { | ||||
| static int patch_ad1983(struct hda_codec *codec) | ||||
| { | ||||
| 	struct ad198x_spec *spec; | ||||
| 	int err; | ||||
| 
 | ||||
| 	spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||||
| 	if (spec == NULL) | ||||
| @ -1301,6 +1326,13 @@ static int patch_ad1983(struct hda_codec *codec) | ||||
| 
 | ||||
| 	codec->spec = spec; | ||||
| 
 | ||||
| 	err = snd_hda_attach_beep_device(codec, 0x10); | ||||
| 	if (err < 0) { | ||||
| 		ad198x_free(codec); | ||||
| 		return err; | ||||
| 	} | ||||
| 	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||||
| 
 | ||||
| 	spec->multiout.max_channels = 2; | ||||
| 	spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids); | ||||
| 	spec->multiout.dac_nids = ad1983_dac_nids; | ||||
| @ -1370,8 +1402,6 @@ static struct snd_kcontrol_new ad1981_mixers[] = { | ||||
| 	HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x0d, 1, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME("Front Mic Boost", 0x08, 0x0, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x0, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||||
| @ -1416,8 +1446,8 @@ static struct hda_verb ad1981_init_verbs[] = { | ||||
| 	{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||||
| 	{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||||
| 	/* Mic boost: 0dB */ | ||||
| 	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||||
| 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||||
| 	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||||
| 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||||
| 	/* Record selector: Front mic */ | ||||
| 	{0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||||
| 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||||
| @ -1682,10 +1712,10 @@ static struct snd_pci_quirk ad1981_cfg_tbl[] = { | ||||
| 	SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), | ||||
| 	SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD), | ||||
| 	/* All HP models */ | ||||
| 	SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP), | ||||
| 	SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP), | ||||
| 	SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA), | ||||
| 	/* Lenovo Thinkpad T60/X60/Z6xx */ | ||||
| 	SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD), | ||||
| 	SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD), | ||||
| 	/* HP nx6320 (reversed SSID, H/W bug) */ | ||||
| 	SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP), | ||||
| 	{} | ||||
| @ -1694,7 +1724,7 @@ static struct snd_pci_quirk ad1981_cfg_tbl[] = { | ||||
| static int patch_ad1981(struct hda_codec *codec) | ||||
| { | ||||
| 	struct ad198x_spec *spec; | ||||
| 	int board_config; | ||||
| 	int err, board_config; | ||||
| 
 | ||||
| 	spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||||
| 	if (spec == NULL) | ||||
| @ -1702,6 +1732,13 @@ static int patch_ad1981(struct hda_codec *codec) | ||||
| 
 | ||||
| 	codec->spec = spec; | ||||
| 
 | ||||
| 	err = snd_hda_attach_beep_device(codec, 0x10); | ||||
| 	if (err < 0) { | ||||
| 		ad198x_free(codec); | ||||
| 		return err; | ||||
| 	} | ||||
| 	set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT); | ||||
| 
 | ||||
| 	spec->multiout.max_channels = 2; | ||||
| 	spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids); | ||||
| 	spec->multiout.dac_nids = ad1981_dac_nids; | ||||
| @ -1988,9 +2025,6 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = { | ||||
| 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), | ||||
| 
 | ||||
| 	HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT), | ||||
| 
 | ||||
| 	HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||||
| 
 | ||||
| @ -2034,9 +2068,6 @@ static struct snd_kcontrol_new ad1988_3stack_mixers2[] = { | ||||
| 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), | ||||
| 
 | ||||
| 	HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT), | ||||
| 
 | ||||
| 	HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||||
| 
 | ||||
| @ -2066,9 +2097,6 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = { | ||||
| 	HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), | ||||
| 
 | ||||
| 	HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT), | ||||
| 
 | ||||
| 	HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||||
| 
 | ||||
| @ -2297,10 +2325,6 @@ static struct hda_verb ad1988_capture_init_verbs[] = { | ||||
| 	{0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||||
| 	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||||
| 	{0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||||
| 	/* ADCs; muted */ | ||||
| 	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||||
| 	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||||
| 	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||||
| 
 | ||||
| 	{ } | ||||
| }; | ||||
| @ -2408,10 +2432,6 @@ static struct hda_verb ad1988_3stack_init_verbs[] = { | ||||
| 	{0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||||
| 	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||||
| 	{0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||||
| 	/* ADCs; muted */ | ||||
| 	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||||
| 	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||||
| 	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||||
| 	/* Analog Mix output amp */ | ||||
| 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ | ||||
| 	{ } | ||||
| @ -2483,10 +2503,6 @@ static struct hda_verb ad1988_laptop_init_verbs[] = { | ||||
| 	{0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||||
| 	{0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||||
| 	{0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||||
| 	/* ADCs; muted */ | ||||
| 	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||||
| 	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||||
| 	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||||
| 	/* Analog Mix output amp */ | ||||
| 	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ | ||||
| 	{ } | ||||
| @ -2890,7 +2906,7 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) | ||||
| 
 | ||||
| 	spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||||
| 
 | ||||
| 	if (spec->autocfg.dig_out_pin) | ||||
| 	if (spec->autocfg.dig_outs) | ||||
| 		spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; | ||||
| 	if (spec->autocfg.dig_in_pin) | ||||
| 		spec->dig_in_nid = AD1988_SPDIF_IN; | ||||
| @ -2940,7 +2956,7 @@ static struct snd_pci_quirk ad1988_cfg_tbl[] = { | ||||
| static int patch_ad1988(struct hda_codec *codec) | ||||
| { | ||||
| 	struct ad198x_spec *spec; | ||||
| 	int board_config; | ||||
| 	int err, board_config; | ||||
| 
 | ||||
| 	spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||||
| 	if (spec == NULL) | ||||
| @ -2960,7 +2976,7 @@ static int patch_ad1988(struct hda_codec *codec) | ||||
| 
 | ||||
| 	if (board_config == AD1988_AUTO) { | ||||
| 		/* automatic parse from the BIOS config */ | ||||
| 		int err = ad1988_parse_auto_config(codec); | ||||
| 		err = ad1988_parse_auto_config(codec); | ||||
| 		if (err < 0) { | ||||
| 			ad198x_free(codec); | ||||
| 			return err; | ||||
| @ -2970,6 +2986,13 @@ static int patch_ad1988(struct hda_codec *codec) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	err = snd_hda_attach_beep_device(codec, 0x10); | ||||
| 	if (err < 0) { | ||||
| 		ad198x_free(codec); | ||||
| 		return err; | ||||
| 	} | ||||
| 	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||||
| 
 | ||||
| 	switch (board_config) { | ||||
| 	case AD1988_6STACK: | ||||
| 	case AD1988_6STACK_DIG: | ||||
| @ -3126,12 +3149,6 @@ static struct snd_kcontrol_new ad1884_base_mixers[] = { | ||||
| 	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT), | ||||
| 	/*
 | ||||
| 	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x20, 0x03, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x20, 0x03, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Digital Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT), | ||||
| 	*/ | ||||
| 	HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||||
| @ -3204,10 +3221,10 @@ static struct hda_verb ad1884_init_verbs[] = { | ||||
| 	{0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||||
| 	/* Port-B (front mic) pin */ | ||||
| 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||||
| 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||||
| 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||||
| 	/* Port-C (rear mic) pin */ | ||||
| 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||||
| 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||||
| 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||||
| 	/* Analog mixer; mute as default */ | ||||
| 	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||||
| 	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||||
| @ -3240,7 +3257,7 @@ static const char *ad1884_slave_vols[] = { | ||||
| 	"CD Playback Volume", | ||||
| 	"Internal Mic Playback Volume", | ||||
| 	"Docking Mic Playback Volume" | ||||
| 	"Beep Playback Volume", | ||||
| 	/* "Beep Playback Volume", */ | ||||
| 	"IEC958 Playback Volume", | ||||
| 	NULL | ||||
| }; | ||||
| @ -3248,6 +3265,7 @@ static const char *ad1884_slave_vols[] = { | ||||
| static int patch_ad1884(struct hda_codec *codec) | ||||
| { | ||||
| 	struct ad198x_spec *spec; | ||||
| 	int err; | ||||
| 
 | ||||
| 	spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||||
| 	if (spec == NULL) | ||||
| @ -3255,6 +3273,13 @@ static int patch_ad1884(struct hda_codec *codec) | ||||
| 
 | ||||
| 	codec->spec = spec; | ||||
| 
 | ||||
| 	err = snd_hda_attach_beep_device(codec, 0x10); | ||||
| 	if (err < 0) { | ||||
| 		ad198x_free(codec); | ||||
| 		return err; | ||||
| 	} | ||||
| 	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||||
| 
 | ||||
| 	spec->multiout.max_channels = 2; | ||||
| 	spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids); | ||||
| 	spec->multiout.dac_nids = ad1884_dac_nids; | ||||
| @ -3321,8 +3346,6 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { | ||||
| 	HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Docking Mic Boost", 0x25, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||||
| @ -3358,7 +3381,7 @@ static struct hda_verb ad1984_thinkpad_init_verbs[] = { | ||||
| 	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||||
| 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||||
| 	/* docking mic boost */ | ||||
| 	{0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||||
| 	{0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||||
| 	/* Analog mixer - docking mic; mute as default */ | ||||
| 	{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||||
| 	/* enable EAPD bit */ | ||||
| @ -3379,10 +3402,6 @@ static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = { | ||||
| 	HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT), | ||||
| 	/*
 | ||||
| 	HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x20, 0x03, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x20, 0x03, HDA_INPUT), | ||||
| 	*/ | ||||
| 	HDA_CODEC_VOLUME("Line-In Boost", 0x15, 0x0, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||||
| @ -3468,7 +3487,7 @@ static const char *ad1984_models[AD1984_MODELS] = { | ||||
| 
 | ||||
| static struct snd_pci_quirk ad1984_cfg_tbl[] = { | ||||
| 	/* Lenovo Thinkpad T61/X61 */ | ||||
| 	SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1984_THINKPAD), | ||||
| 	SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD), | ||||
| 	SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP), | ||||
| 	{} | ||||
| }; | ||||
| @ -3561,8 +3580,6 @@ static struct snd_kcontrol_new ad1884a_base_mixers[] = { | ||||
| 	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Line Boost", 0x15, 0x0, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT), | ||||
| @ -3622,10 +3639,10 @@ static struct hda_verb ad1884a_init_verbs[] = { | ||||
| 	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||||
| 	/* Port-B (front mic) pin */ | ||||
| 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||||
| 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||||
| 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||||
| 	/* Port-C (rear line-in) pin */ | ||||
| 	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||||
| 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||||
| 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||||
| 	/* Port-E (rear mic) pin */ | ||||
| 	{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||||
| 	{0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||||
| @ -3695,8 +3712,6 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { | ||||
| 	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT), | ||||
| @ -3724,8 +3739,6 @@ static struct snd_kcontrol_new ad1884a_mobile_mixers[] = { | ||||
| 	HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||||
| @ -3836,8 +3849,6 @@ static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = { | ||||
| 	HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||||
| @ -3911,9 +3922,9 @@ static struct snd_pci_quirk ad1884a_cfg_tbl[] = { | ||||
| 	SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), | ||||
| 	SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP), | ||||
| 	SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE), | ||||
| 	SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP), | ||||
| 	SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP), | ||||
| 	SND_PCI_QUIRK(0x103c, 0x3614, "HP 6730s", AD1884A_LAPTOP), | ||||
| 	SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE), | ||||
| 	SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP), | ||||
| 	SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP), | ||||
| 	SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD), | ||||
| 	{} | ||||
| }; | ||||
| @ -3921,7 +3932,7 @@ static struct snd_pci_quirk ad1884a_cfg_tbl[] = { | ||||
| static int patch_ad1884a(struct hda_codec *codec) | ||||
| { | ||||
| 	struct ad198x_spec *spec; | ||||
| 	int board_config; | ||||
| 	int err, board_config; | ||||
| 
 | ||||
| 	spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||||
| 	if (spec == NULL) | ||||
| @ -3929,6 +3940,13 @@ static int patch_ad1884a(struct hda_codec *codec) | ||||
| 
 | ||||
| 	codec->spec = spec; | ||||
| 
 | ||||
| 	err = snd_hda_attach_beep_device(codec, 0x10); | ||||
| 	if (err < 0) { | ||||
| 		ad198x_free(codec); | ||||
| 		return err; | ||||
| 	} | ||||
| 	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||||
| 
 | ||||
| 	spec->multiout.max_channels = 2; | ||||
| 	spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids); | ||||
| 	spec->multiout.dac_nids = ad1884a_dac_nids; | ||||
| @ -3966,6 +3984,14 @@ static int patch_ad1884a(struct hda_codec *codec) | ||||
| 		spec->multiout.dig_out_nid = 0; | ||||
| 		codec->patch_ops.unsol_event = ad1884a_hp_unsol_event; | ||||
| 		codec->patch_ops.init = ad1884a_hp_init; | ||||
| 		/* set the upper-limit for mixer amp to 0dB for avoiding the
 | ||||
| 		 * possible damage by overloading | ||||
| 		 */ | ||||
| 		snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, | ||||
| 					  (0x17 << AC_AMPCAP_OFFSET_SHIFT) | | ||||
| 					  (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||||
| 					  (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||||
| 					  (1 << AC_AMPCAP_MUTE_SHIFT)); | ||||
| 		break; | ||||
| 	case AD1884A_THINKPAD: | ||||
| 		spec->mixers[0] = ad1984a_thinkpad_mixers; | ||||
| @ -4083,8 +4109,6 @@ static struct snd_kcontrol_new ad1882_loopback_mixers[] = { | ||||
| 	HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT), | ||||
| 	{ } /* end */ | ||||
| }; | ||||
| 
 | ||||
| @ -4097,8 +4121,6 @@ static struct snd_kcontrol_new ad1882a_loopback_mixers[] = { | ||||
| 	HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Digital Mic Boost", 0x1f, 0x0, HDA_INPUT), | ||||
| 	{ } /* end */ | ||||
| }; | ||||
| @ -4257,7 +4279,7 @@ static const char *ad1882_models[AD1986A_MODELS] = { | ||||
| static int patch_ad1882(struct hda_codec *codec) | ||||
| { | ||||
| 	struct ad198x_spec *spec; | ||||
| 	int board_config; | ||||
| 	int err, board_config; | ||||
| 
 | ||||
| 	spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||||
| 	if (spec == NULL) | ||||
| @ -4265,6 +4287,13 @@ static int patch_ad1882(struct hda_codec *codec) | ||||
| 
 | ||||
| 	codec->spec = spec; | ||||
| 
 | ||||
| 	err = snd_hda_attach_beep_device(codec, 0x10); | ||||
| 	if (err < 0) { | ||||
| 		ad198x_free(codec); | ||||
| 		return err; | ||||
| 	} | ||||
| 	set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | ||||
| 
 | ||||
| 	spec->multiout.max_channels = 6; | ||||
| 	spec->multiout.num_dacs = 3; | ||||
| 	spec->multiout.dac_nids = ad1882_dac_nids; | ||||
|  | ||||
| @ -680,13 +680,13 @@ static int patch_cmi9880(struct hda_codec *codec) | ||||
| 		struct auto_pin_cfg cfg; | ||||
| 
 | ||||
| 		/* collect pin default configuration */ | ||||
| 		port_e = snd_hda_codec_read(codec, 0x0f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||||
| 		port_f = snd_hda_codec_read(codec, 0x10, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||||
| 		port_e = snd_hda_codec_get_pincfg(codec, 0x0f); | ||||
| 		port_f = snd_hda_codec_get_pincfg(codec, 0x10); | ||||
| 		spec->front_panel = 1; | ||||
| 		if (get_defcfg_connect(port_e) == AC_JACK_PORT_NONE || | ||||
| 		    get_defcfg_connect(port_f) == AC_JACK_PORT_NONE) { | ||||
| 			port_g = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||||
| 			port_h = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||||
| 			port_g = snd_hda_codec_get_pincfg(codec, 0x1f); | ||||
| 			port_h = snd_hda_codec_get_pincfg(codec, 0x20); | ||||
| 			spec->channel_modes = cmi9880_channel_modes; | ||||
| 			/* no front panel */ | ||||
| 			if (get_defcfg_connect(port_g) == AC_JACK_PORT_NONE || | ||||
| @ -703,8 +703,8 @@ static int patch_cmi9880(struct hda_codec *codec) | ||||
| 			spec->multiout.max_channels = cmi9880_channel_modes[0].channels; | ||||
| 		} else { | ||||
| 			spec->input_mux = &cmi9880_basic_mux; | ||||
| 			port_spdifi = snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||||
| 			port_spdifo = snd_hda_codec_read(codec, 0x12, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||||
| 			port_spdifi = snd_hda_codec_get_pincfg(codec, 0x13); | ||||
| 			port_spdifo = snd_hda_codec_get_pincfg(codec, 0x12); | ||||
| 			if (get_defcfg_connect(port_spdifo) != AC_JACK_PORT_NONE) | ||||
| 				spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; | ||||
| 			if (get_defcfg_connect(port_spdifi) != AC_JACK_PORT_NONE) | ||||
|  | ||||
| @ -58,6 +58,7 @@ struct conexant_spec { | ||||
| 
 | ||||
| 	struct snd_kcontrol_new *mixers[5]; | ||||
| 	int num_mixers; | ||||
| 	hda_nid_t vmaster_nid; | ||||
| 
 | ||||
| 	const struct hda_verb *init_verbs[5];	/* initialization verbs
 | ||||
| 						 * don't forget NULL | ||||
| @ -72,6 +73,7 @@ struct conexant_spec { | ||||
| 					 */ | ||||
| 	unsigned int cur_eapd; | ||||
| 	unsigned int hp_present; | ||||
| 	unsigned int no_auto_mic; | ||||
| 	unsigned int need_dac_fix; | ||||
| 
 | ||||
| 	/* capture */ | ||||
| @ -461,6 +463,29 @@ static void conexant_free(struct hda_codec *codec) | ||||
| 	kfree(codec->spec); | ||||
| } | ||||
| 
 | ||||
| static struct snd_kcontrol_new cxt_capture_mixers[] = { | ||||
| 	{ | ||||
| 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||||
| 		.name = "Capture Source", | ||||
| 		.info = conexant_mux_enum_info, | ||||
| 		.get = conexant_mux_enum_get, | ||||
| 		.put = conexant_mux_enum_put | ||||
| 	}, | ||||
| 	{} | ||||
| }; | ||||
| 
 | ||||
| static const char *slave_vols[] = { | ||||
| 	"Headphone Playback Volume", | ||||
| 	"Speaker Playback Volume", | ||||
| 	NULL | ||||
| }; | ||||
| 
 | ||||
| static const char *slave_sws[] = { | ||||
| 	"Headphone Playback Switch", | ||||
| 	"Speaker Playback Switch", | ||||
| 	NULL | ||||
| }; | ||||
| 
 | ||||
| static int conexant_build_controls(struct hda_codec *codec) | ||||
| { | ||||
| 	struct conexant_spec *spec = codec->spec; | ||||
| @ -488,6 +513,32 @@ static int conexant_build_controls(struct hda_codec *codec) | ||||
| 		if (err < 0) | ||||
| 			return err; | ||||
| 	} | ||||
| 
 | ||||
| 	/* if we have no master control, let's create it */ | ||||
| 	if (spec->vmaster_nid && | ||||
| 	    !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { | ||||
| 		unsigned int vmaster_tlv[4]; | ||||
| 		snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, | ||||
| 					HDA_OUTPUT, vmaster_tlv); | ||||
| 		err = snd_hda_add_vmaster(codec, "Master Playback Volume", | ||||
| 					  vmaster_tlv, slave_vols); | ||||
| 		if (err < 0) | ||||
| 			return err; | ||||
| 	} | ||||
| 	if (spec->vmaster_nid && | ||||
| 	    !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { | ||||
| 		err = snd_hda_add_vmaster(codec, "Master Playback Switch", | ||||
| 					  NULL, slave_sws); | ||||
| 		if (err < 0) | ||||
| 			return err; | ||||
| 	} | ||||
| 
 | ||||
| 	if (spec->input_mux) { | ||||
| 		err = snd_hda_add_new_ctls(codec, cxt_capture_mixers); | ||||
| 		if (err < 0) | ||||
| 			return err; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -719,13 +770,6 @@ static void cxt5045_hp_unsol_event(struct hda_codec *codec, | ||||
| } | ||||
| 
 | ||||
| static struct snd_kcontrol_new cxt5045_mixers[] = { | ||||
| 	{ | ||||
| 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||||
| 		.name = "Capture Source", | ||||
| 		.info = conexant_mux_enum_info, | ||||
| 		.get = conexant_mux_enum_get, | ||||
| 		.put = conexant_mux_enum_put | ||||
| 	}, | ||||
| 	HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x01, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), | ||||
| @ -759,13 +803,6 @@ static struct snd_kcontrol_new cxt5045_benq_mixers[] = { | ||||
| }; | ||||
| 
 | ||||
| static struct snd_kcontrol_new cxt5045_mixers_hp530[] = { | ||||
| 	{ | ||||
| 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||||
| 		.name = "Capture Source", | ||||
| 		.info = conexant_mux_enum_info, | ||||
| 		.get = conexant_mux_enum_get, | ||||
| 		.put = conexant_mux_enum_put | ||||
| 	}, | ||||
| 	HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x02, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), | ||||
| @ -1002,15 +1039,9 @@ static const char *cxt5045_models[CXT5045_MODELS] = { | ||||
| }; | ||||
| 
 | ||||
| static struct snd_pci_quirk cxt5045_cfg_tbl[] = { | ||||
| 	SND_PCI_QUIRK(0x103c, 0x30a5, "HP", CXT5045_LAPTOP_HPSENSE), | ||||
| 	SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV Series", CXT5045_LAPTOP_HPSENSE), | ||||
| 	SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2120", CXT5045_LAPTOP_HPSENSE), | ||||
| 	SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP_HPSENSE), | ||||
| 	SND_PCI_QUIRK(0x103c, 0x30bb, "HP DV8000", CXT5045_LAPTOP_HPSENSE), | ||||
| 	SND_PCI_QUIRK(0x103c, 0x30cd, "HP DV Series", CXT5045_LAPTOP_HPSENSE), | ||||
| 	SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV9533EG", CXT5045_LAPTOP_HPSENSE), | ||||
| 	SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530), | ||||
| 	SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP_HPSENSE), | ||||
| 	SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", | ||||
| 			   CXT5045_LAPTOP_HPSENSE), | ||||
| 	SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT5045_LAPTOP_MICSENSE), | ||||
| 	SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ), | ||||
| 	SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE), | ||||
| @ -1020,8 +1051,8 @@ static struct snd_pci_quirk cxt5045_cfg_tbl[] = { | ||||
| 	SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE), | ||||
| 	SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE), | ||||
| 	SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE), | ||||
| 	SND_PCI_QUIRK(0x1631, 0xc106, "Packard Bell", CXT5045_LAPTOP_HPMICSENSE), | ||||
| 	SND_PCI_QUIRK(0x1631, 0xc107, "Packard Bell", CXT5045_LAPTOP_HPMICSENSE), | ||||
| 	SND_PCI_QUIRK_MASK(0x1631, 0xff00, 0xc100, "Packard Bell", | ||||
| 			   CXT5045_LAPTOP_HPMICSENSE), | ||||
| 	SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP_HPSENSE), | ||||
| 	{} | ||||
| }; | ||||
| @ -1035,6 +1066,7 @@ static int patch_cxt5045(struct hda_codec *codec) | ||||
| 	if (!spec) | ||||
| 		return -ENOMEM; | ||||
| 	codec->spec = spec; | ||||
| 	codec->pin_amp_workaround = 1; | ||||
| 
 | ||||
| 	spec->multiout.max_channels = 2; | ||||
| 	spec->multiout.num_dacs = ARRAY_SIZE(cxt5045_dac_nids); | ||||
| @ -1134,7 +1166,7 @@ static int patch_cxt5045(struct hda_codec *codec) | ||||
| /* Conexant 5047 specific */ | ||||
| #define CXT5047_SPDIF_OUT	0x11 | ||||
| 
 | ||||
| static hda_nid_t cxt5047_dac_nids[2] = { 0x10, 0x1c }; | ||||
| static hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */ | ||||
| static hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; | ||||
| static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; | ||||
| 
 | ||||
| @ -1142,20 +1174,6 @@ static struct hda_channel_mode cxt5047_modes[1] = { | ||||
| 	{ 2, NULL }, | ||||
| }; | ||||
| 
 | ||||
| static struct hda_input_mux cxt5047_capture_source = { | ||||
| 	.num_items = 1, | ||||
| 	.items = { | ||||
| 		{ "Mic", 0x2 }, | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| static struct hda_input_mux cxt5047_hp_capture_source = { | ||||
| 	.num_items = 1, | ||||
| 	.items = { | ||||
| 		{ "ExtMic", 0x2 }, | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| static struct hda_input_mux cxt5047_toshiba_capture_source = { | ||||
| 	.num_items = 2, | ||||
| 	.items = { | ||||
| @ -1179,7 +1197,11 @@ static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||||
| 	 * the headphone jack | ||||
| 	 */ | ||||
| 	bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE; | ||||
| 	snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0, | ||||
| 	/* NOTE: Conexat codec needs the index for *OUTPUT* amp of
 | ||||
| 	 * pin widgets unlike other codecs.  In this case, we need to | ||||
| 	 * set index 0x01 for the volume from the mixer amp 0x19. | ||||
| 	 */ | ||||
| 	snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0x01, | ||||
| 				 HDA_AMP_MUTE, bits); | ||||
| 	bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE; | ||||
| 	snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0, | ||||
| @ -1187,16 +1209,6 @@ static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| /* bind volumes of both NID 0x13 (Headphones) and 0x1d (Speakers) */ | ||||
| static struct hda_bind_ctls cxt5047_bind_master_vol = { | ||||
| 	.ops = &snd_hda_bind_vol, | ||||
| 	.values = { | ||||
| 		HDA_COMPOSE_AMP_VAL(0x13, 3, 0, HDA_OUTPUT), | ||||
| 		HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), | ||||
| 		0 | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| /* mute internal speaker if HP is plugged */ | ||||
| static void cxt5047_hp_automute(struct hda_codec *codec) | ||||
| { | ||||
| @ -1207,27 +1219,8 @@ static void cxt5047_hp_automute(struct hda_codec *codec) | ||||
| 				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||||
| 
 | ||||
| 	bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; | ||||
| 	snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0, | ||||
| 				 HDA_AMP_MUTE, bits); | ||||
| 	/* Mute/Unmute PCM 2 for good measure - some systems need this */ | ||||
| 	snd_hda_codec_amp_stereo(codec, 0x1c, HDA_OUTPUT, 0, | ||||
| 				 HDA_AMP_MUTE, bits); | ||||
| } | ||||
| 
 | ||||
| /* mute internal speaker if HP is plugged */ | ||||
| static void cxt5047_hp2_automute(struct hda_codec *codec) | ||||
| { | ||||
| 	struct conexant_spec *spec = codec->spec; | ||||
| 	unsigned int bits; | ||||
| 
 | ||||
| 	spec->hp_present = snd_hda_codec_read(codec, 0x13, 0, | ||||
| 				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||||
| 
 | ||||
| 	bits = spec->hp_present ? HDA_AMP_MUTE : 0; | ||||
| 	snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0, | ||||
| 				 HDA_AMP_MUTE, bits); | ||||
| 	/* Mute/Unmute PCM 2 for good measure - some systems need this */ | ||||
| 	snd_hda_codec_amp_stereo(codec, 0x1c, HDA_OUTPUT, 0, | ||||
| 	/* See the note in cxt5047_hp_master_sw_put */ | ||||
| 	snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0x01, | ||||
| 				 HDA_AMP_MUTE, bits); | ||||
| } | ||||
| 
 | ||||
| @ -1268,90 +1261,35 @@ static void cxt5047_hp_unsol_event(struct hda_codec *codec, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* unsolicited event for HP jack sensing - non-EAPD systems */ | ||||
| static void cxt5047_hp2_unsol_event(struct hda_codec *codec, | ||||
| 				  unsigned int res) | ||||
| { | ||||
| 	res >>= 26; | ||||
| 	switch (res) { | ||||
| 	case CONEXANT_HP_EVENT: | ||||
| 		cxt5047_hp2_automute(codec); | ||||
| 		break; | ||||
| 	case CONEXANT_MIC_EVENT: | ||||
| 		cxt5047_hp_automic(codec); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static struct snd_kcontrol_new cxt5047_mixers[] = { | ||||
| 	HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19, 0x02, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Mic Gain Volume", 0x1a, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Mic Gain Switch", 0x1a, 0x0, HDA_OUTPUT), | ||||
| static struct snd_kcontrol_new cxt5047_base_mixers[] = { | ||||
| 	HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Mic Boost", 0x1a, 0x0, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME("PCM-2 Volume", 0x1c, 0x00, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("PCM-2 Switch", 0x1c, 0x00, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x00, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Speaker Playback Switch", 0x1d, 0x00, HDA_OUTPUT), | ||||
| 	{ | ||||
| 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||||
| 		.name = "Master Playback Switch", | ||||
| 		.info = cxt_eapd_info, | ||||
| 		.get = cxt_eapd_get, | ||||
| 		.put = cxt5047_hp_master_sw_put, | ||||
| 		.private_value = 0x13, | ||||
| 	}, | ||||
| 
 | ||||
| 	{} | ||||
| }; | ||||
| 
 | ||||
| static struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = { | ||||
| 	/* See the note in cxt5047_hp_master_sw_put */ | ||||
| 	HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x01, HDA_OUTPUT), | ||||
| 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x13, 0x00, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x13, 0x00, HDA_OUTPUT), | ||||
| 
 | ||||
| 	{} | ||||
| }; | ||||
| 
 | ||||
| static struct snd_kcontrol_new cxt5047_toshiba_mixers[] = { | ||||
| 	{ | ||||
| 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||||
| 		.name = "Capture Source", | ||||
| 		.info = conexant_mux_enum_info, | ||||
| 		.get = conexant_mux_enum_get, | ||||
| 		.put = conexant_mux_enum_put | ||||
| 	}, | ||||
| 	HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19, 0x02, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), | ||||
| 	HDA_BIND_VOL("Master Playback Volume", &cxt5047_bind_master_vol), | ||||
| 	{ | ||||
| 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||||
| 		.name = "Master Playback Switch", | ||||
| 		.info = cxt_eapd_info, | ||||
| 		.get = cxt_eapd_get, | ||||
| 		.put = cxt5047_hp_master_sw_put, | ||||
| 		.private_value = 0x13, | ||||
| 	}, | ||||
| 
 | ||||
| 	{} | ||||
| }; | ||||
| 
 | ||||
| static struct snd_kcontrol_new cxt5047_hp_mixers[] = { | ||||
| 	{ | ||||
| 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||||
| 		.name = "Capture Source", | ||||
| 		.info = conexant_mux_enum_info, | ||||
| 		.get = conexant_mux_enum_get, | ||||
| 		.put = conexant_mux_enum_put | ||||
| 	}, | ||||
| 	HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19,0x02,HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), | ||||
| 	HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), | ||||
| static struct snd_kcontrol_new cxt5047_hp_only_mixers[] = { | ||||
| 	HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), | ||||
| 	{ | ||||
| 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||||
| 		.name = "Master Playback Switch", | ||||
| 		.info = cxt_eapd_info, | ||||
| 		.get = cxt_eapd_get, | ||||
| 		.put = cxt5047_hp_master_sw_put, | ||||
| 		.private_value = 0x13, | ||||
| 	}, | ||||
| 	{ } /* end */ | ||||
| }; | ||||
| 
 | ||||
| @ -1362,8 +1300,8 @@ static struct hda_verb cxt5047_init_verbs[] = { | ||||
| 	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, | ||||
| 	/* HP, Speaker  */ | ||||
| 	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, | ||||
| 	{0x13, AC_VERB_SET_CONNECT_SEL,0x1}, | ||||
| 	{0x1d, AC_VERB_SET_CONNECT_SEL,0x0}, | ||||
| 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, /* mixer(0x19) */ | ||||
| 	{0x1d, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mixer(0x19) */ | ||||
| 	/* Record selector: Mic */ | ||||
| 	{0x12, AC_VERB_SET_CONNECT_SEL,0x03}, | ||||
| 	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, | ||||
| @ -1383,30 +1321,7 @@ static struct hda_verb cxt5047_init_verbs[] = { | ||||
| 
 | ||||
| /* configuration for Toshiba Laptops */ | ||||
| static struct hda_verb cxt5047_toshiba_init_verbs[] = { | ||||
| 	{0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0 }, /* default on */ | ||||
| 	/* pin sensing on HP and Mic jacks */ | ||||
| 	{0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, | ||||
| 	{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, | ||||
| 	/* Speaker routing */ | ||||
| 	{0x1d, AC_VERB_SET_CONNECT_SEL,0x1}, | ||||
| 	{} | ||||
| }; | ||||
| 
 | ||||
| /* configuration for HP Laptops */ | ||||
| static struct hda_verb cxt5047_hp_init_verbs[] = { | ||||
| 	/* pin sensing on HP jack */ | ||||
| 	{0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, | ||||
| 	/* 0x13 is actually shared by both HP and speaker;
 | ||||
| 	 * setting the connection to 0 (=0x19) makes the master volume control | ||||
| 	 * working mysteriouslly... | ||||
| 	 */ | ||||
| 	{0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||||
| 	/* Record selector: Ext Mic */ | ||||
| 	{0x12, AC_VERB_SET_CONNECT_SEL,0x03}, | ||||
| 	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, | ||||
| 	 AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, | ||||
| 	/* Speaker routing */ | ||||
| 	{0x1d, AC_VERB_SET_CONNECT_SEL,0x1}, | ||||
| 	{0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0}, /* default off */ | ||||
| 	{} | ||||
| }; | ||||
| 
 | ||||
| @ -1571,11 +1486,9 @@ static const char *cxt5047_models[CXT5047_MODELS] = { | ||||
| }; | ||||
| 
 | ||||
| static struct snd_pci_quirk cxt5047_cfg_tbl[] = { | ||||
| 	SND_PCI_QUIRK(0x103c, 0x30a0, "HP DV1000", CXT5047_LAPTOP), | ||||
| 	SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), | ||||
| 	SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP), | ||||
| 	SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2000Z", CXT5047_LAPTOP), | ||||
| 	SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6700", CXT5047_LAPTOP), | ||||
| 	SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", | ||||
| 			   CXT5047_LAPTOP), | ||||
| 	SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD), | ||||
| 	{} | ||||
| }; | ||||
| @ -1589,6 +1502,7 @@ static int patch_cxt5047(struct hda_codec *codec) | ||||
| 	if (!spec) | ||||
| 		return -ENOMEM; | ||||
| 	codec->spec = spec; | ||||
| 	codec->pin_amp_workaround = 1; | ||||
| 
 | ||||
| 	spec->multiout.max_channels = 2; | ||||
| 	spec->multiout.num_dacs = ARRAY_SIZE(cxt5047_dac_nids); | ||||
| @ -1597,9 +1511,8 @@ static int patch_cxt5047(struct hda_codec *codec) | ||||
| 	spec->num_adc_nids = 1; | ||||
| 	spec->adc_nids = cxt5047_adc_nids; | ||||
| 	spec->capsrc_nids = cxt5047_capsrc_nids; | ||||
| 	spec->input_mux = &cxt5047_capture_source; | ||||
| 	spec->num_mixers = 1; | ||||
| 	spec->mixers[0] = cxt5047_mixers; | ||||
| 	spec->mixers[0] = cxt5047_base_mixers; | ||||
| 	spec->num_init_verbs = 1; | ||||
| 	spec->init_verbs[0] = cxt5047_init_verbs; | ||||
| 	spec->spdif_route = 0; | ||||
| @ -1613,21 +1526,22 @@ static int patch_cxt5047(struct hda_codec *codec) | ||||
| 						  cxt5047_cfg_tbl); | ||||
| 	switch (board_config) { | ||||
| 	case CXT5047_LAPTOP: | ||||
| 		codec->patch_ops.unsol_event = cxt5047_hp2_unsol_event; | ||||
| 		spec->num_mixers = 2; | ||||
| 		spec->mixers[1] = cxt5047_hp_spk_mixers; | ||||
| 		codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; | ||||
| 		break; | ||||
| 	case CXT5047_LAPTOP_HP: | ||||
| 		spec->input_mux = &cxt5047_hp_capture_source; | ||||
| 		spec->num_init_verbs = 2; | ||||
| 		spec->init_verbs[1] = cxt5047_hp_init_verbs; | ||||
| 		spec->mixers[0] = cxt5047_hp_mixers; | ||||
| 		spec->num_mixers = 2; | ||||
| 		spec->mixers[1] = cxt5047_hp_only_mixers; | ||||
| 		codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; | ||||
| 		codec->patch_ops.init = cxt5047_hp_init; | ||||
| 		break; | ||||
| 	case CXT5047_LAPTOP_EAPD: | ||||
| 		spec->input_mux = &cxt5047_toshiba_capture_source; | ||||
| 		spec->num_mixers = 2; | ||||
| 		spec->mixers[1] = cxt5047_hp_spk_mixers; | ||||
| 		spec->num_init_verbs = 2; | ||||
| 		spec->init_verbs[1] = cxt5047_toshiba_init_verbs; | ||||
| 		spec->mixers[0] = cxt5047_toshiba_mixers; | ||||
| 		codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; | ||||
| 		break; | ||||
| #ifdef CONFIG_SND_DEBUG | ||||
| @ -1638,6 +1552,7 @@ static int patch_cxt5047(struct hda_codec *codec) | ||||
| 		codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; | ||||
| #endif	 | ||||
| 	} | ||||
| 	spec->vmaster_nid = 0x13; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -1673,8 +1588,11 @@ static int cxt5051_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||||
| /* toggle input of built-in and mic jack appropriately */ | ||||
| static void cxt5051_portb_automic(struct hda_codec *codec) | ||||
| { | ||||
| 	struct conexant_spec *spec = codec->spec; | ||||
| 	unsigned int present; | ||||
| 
 | ||||
| 	if (spec->no_auto_mic) | ||||
| 		return; | ||||
| 	present = snd_hda_codec_read(codec, 0x17, 0, | ||||
| 				     AC_VERB_GET_PIN_SENSE, 0) & | ||||
| 		AC_PINSENSE_PRESENCE; | ||||
| @ -1690,6 +1608,8 @@ static void cxt5051_portc_automic(struct hda_codec *codec) | ||||
| 	unsigned int present; | ||||
| 	hda_nid_t new_adc; | ||||
| 
 | ||||
| 	if (spec->no_auto_mic) | ||||
| 		return; | ||||
| 	present = snd_hda_codec_read(codec, 0x18, 0, | ||||
| 				     AC_VERB_GET_PIN_SENSE, 0) & | ||||
| 		AC_PINSENSE_PRESENCE; | ||||
| @ -1776,6 +1696,22 @@ static struct snd_kcontrol_new cxt5051_hp_mixers[] = { | ||||
| 	{} | ||||
| }; | ||||
| 
 | ||||
| static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { | ||||
| 	HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x00, HDA_INPUT), | ||||
| 	HDA_CODEC_MUTE("Mic Switch", 0x14, 0x00, HDA_INPUT), | ||||
| 	HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | ||||
| 	{ | ||||
| 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||||
| 		.name = "Master Playback Switch", | ||||
| 		.info = cxt_eapd_info, | ||||
| 		.get = cxt_eapd_get, | ||||
| 		.put = cxt5051_hp_master_sw_put, | ||||
| 		.private_value = 0x1a, | ||||
| 	}, | ||||
| 
 | ||||
| 	{} | ||||
| }; | ||||
| 
 | ||||
| static struct hda_verb cxt5051_init_verbs[] = { | ||||
| 	/* Line in, Mic */ | ||||
| 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | ||||
| @ -1806,6 +1742,66 @@ static struct hda_verb cxt5051_init_verbs[] = { | ||||
| 	{ } /* end */ | ||||
| }; | ||||
| 
 | ||||
| static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { | ||||
| 	/* Line in, Mic */ | ||||
| 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | ||||
| 	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||||
| 	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, | ||||
| 	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, | ||||
| 	/* SPK  */ | ||||
| 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||||
| 	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||||
| 	/* HP, Amp  */ | ||||
| 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||||
| 	{0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||||
| 	/* DAC1 */ | ||||
| 	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||||
| 	/* Record selector: Int mic */ | ||||
| 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, | ||||
| 	{0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||||
| 	/* SPDIF route: PCM */ | ||||
| 	{0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||||
| 	/* EAPD */ | ||||
| 	{0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | ||||
| 	{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, | ||||
| 	{0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, | ||||
| 	{ } /* end */ | ||||
| }; | ||||
| 
 | ||||
| static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { | ||||
| 	/* Line in, Mic */ | ||||
| 	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | ||||
| 	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||||
| 	{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | ||||
| 	{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||||
| 	{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||||
| 	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | ||||
| 	/* SPK  */ | ||||
| 	{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||||
| 	{0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||||
| 	/* HP, Amp  */ | ||||
| 	{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||||
| 	{0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||||
| 	/* Docking HP */ | ||||
| 	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||||
| 	{0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||||
| 	/* DAC1 */ | ||||
| 	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||||
| 	/* Record selector: Int mic */ | ||||
| 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, | ||||
| 	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, | ||||
| 	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, | ||||
| 	/* SPDIF route: PCM */ | ||||
| 	{0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||||
| 	/* EAPD */ | ||||
| 	{0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | ||||
| 	{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, | ||||
| 	{0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, | ||||
| 	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT}, | ||||
| 	{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, | ||||
| 	{ } /* end */ | ||||
| }; | ||||
| 
 | ||||
| /* initialize jack-sensing, too */ | ||||
| static int cxt5051_init(struct hda_codec *codec) | ||||
| { | ||||
| @ -1823,18 +1819,24 @@ static int cxt5051_init(struct hda_codec *codec) | ||||
| enum { | ||||
| 	CXT5051_LAPTOP,	 /* Laptops w/ EAPD support */ | ||||
| 	CXT5051_HP,	/* no docking */ | ||||
| 	CXT5051_HP_DV6736,	/* HP without mic switch */ | ||||
| 	CXT5051_LENOVO_X200,	/* Lenovo X200 laptop */ | ||||
| 	CXT5051_MODELS | ||||
| }; | ||||
| 
 | ||||
| static const char *cxt5051_models[CXT5051_MODELS] = { | ||||
| 	[CXT5051_LAPTOP]	= "laptop", | ||||
| 	[CXT5051_HP]		= "hp", | ||||
| 	[CXT5051_HP_DV6736]	= "hp-dv6736", | ||||
| 	[CXT5051_LENOVO_X200]	= "lenovo-x200", | ||||
| }; | ||||
| 
 | ||||
| static struct snd_pci_quirk cxt5051_cfg_tbl[] = { | ||||
| 	SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), | ||||
| 	SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", | ||||
| 		      CXT5051_LAPTOP), | ||||
| 	SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), | ||||
| 	SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200), | ||||
| 	{} | ||||
| }; | ||||
| 
 | ||||
| @ -1847,6 +1849,7 @@ static int patch_cxt5051(struct hda_codec *codec) | ||||
| 	if (!spec) | ||||
| 		return -ENOMEM; | ||||
| 	codec->spec = spec; | ||||
| 	codec->pin_amp_workaround = 1; | ||||
| 
 | ||||
| 	codec->patch_ops = conexant_patch_ops; | ||||
| 	codec->patch_ops.init = cxt5051_init; | ||||
| @ -1867,17 +1870,22 @@ static int patch_cxt5051(struct hda_codec *codec) | ||||
| 	spec->cur_adc = 0; | ||||
| 	spec->cur_adc_idx = 0; | ||||
| 
 | ||||
| 	codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; | ||||
| 
 | ||||
| 	board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, | ||||
| 						  cxt5051_models, | ||||
| 						  cxt5051_cfg_tbl); | ||||
| 	switch (board_config) { | ||||
| 	case CXT5051_HP: | ||||
| 		codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; | ||||
| 		spec->mixers[0] = cxt5051_hp_mixers; | ||||
| 		break; | ||||
| 	default: | ||||
| 	case CXT5051_LAPTOP: | ||||
| 		codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; | ||||
| 	case CXT5051_HP_DV6736: | ||||
| 		spec->init_verbs[0] = cxt5051_hp_dv6736_init_verbs; | ||||
| 		spec->mixers[0] = cxt5051_hp_dv6736_mixers; | ||||
| 		spec->no_auto_mic = 1; | ||||
| 		break; | ||||
| 	case CXT5051_LENOVO_X200: | ||||
| 		spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1308,16 +1308,13 @@ static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid) | ||||
| 	unsigned int def_conf; | ||||
| 	unsigned char seqassoc; | ||||
| 
 | ||||
| 	def_conf = snd_hda_codec_read(codec, nid, 0, | ||||
| 				      AC_VERB_GET_CONFIG_DEFAULT, 0); | ||||
| 	def_conf = snd_hda_codec_get_pincfg(codec, nid); | ||||
| 	seqassoc = (unsigned char) get_defcfg_association(def_conf); | ||||
| 	seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf); | ||||
| 	if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) { | ||||
| 		if (seqassoc == 0xff) { | ||||
| 			def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30)); | ||||
| 			snd_hda_codec_write(codec, nid, 0, | ||||
| 					    AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, | ||||
| 					    def_conf >> 24); | ||||
| 			snd_hda_codec_set_pincfg(codec, nid, def_conf); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -1354,7 +1351,7 @@ static int vt1708_parse_auto_config(struct hda_codec *codec) | ||||
| 
 | ||||
| 	spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||||
| 
 | ||||
| 	if (spec->autocfg.dig_out_pin) | ||||
| 	if (spec->autocfg.dig_outs) | ||||
| 		spec->multiout.dig_out_nid = VT1708_DIGOUT_NID; | ||||
| 	if (spec->autocfg.dig_in_pin) | ||||
| 		spec->dig_in_nid = VT1708_DIGIN_NID; | ||||
| @ -1827,7 +1824,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) | ||||
| 
 | ||||
| 	spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||||
| 
 | ||||
| 	if (spec->autocfg.dig_out_pin) | ||||
| 	if (spec->autocfg.dig_outs) | ||||
| 		spec->multiout.dig_out_nid = VT1709_DIGOUT_NID; | ||||
| 	if (spec->autocfg.dig_in_pin) | ||||
| 		spec->dig_in_nid = VT1709_DIGIN_NID; | ||||
| @ -2371,7 +2368,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec) | ||||
| 
 | ||||
| 	spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||||
| 
 | ||||
| 	if (spec->autocfg.dig_out_pin) | ||||
| 	if (spec->autocfg.dig_outs) | ||||
| 		spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID; | ||||
| 	if (spec->autocfg.dig_in_pin) | ||||
| 		spec->dig_in_nid = VT1708B_DIGIN_NID; | ||||
| @ -2836,7 +2833,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) | ||||
| 
 | ||||
| 	spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||||
| 
 | ||||
| 	if (spec->autocfg.dig_out_pin) | ||||
| 	if (spec->autocfg.dig_outs) | ||||
| 		spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID; | ||||
| 
 | ||||
| 	spec->extra_dig_out_nid = 0x15; | ||||
| @ -3155,7 +3152,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) | ||||
| 
 | ||||
| 	spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||||
| 
 | ||||
| 	if (spec->autocfg.dig_out_pin) | ||||
| 	if (spec->autocfg.dig_outs) | ||||
| 		spec->multiout.dig_out_nid = VT1702_DIGOUT_NID; | ||||
| 
 | ||||
| 	spec->extra_dig_out_nid = 0x1B; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user