summaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_generic.h
blob: 00a1eab2c0b266ecd06d1360e5f7c3c81434ddb4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
/*
 * Generic BIOS auto-parser helper functions for HD-audio
 *
 * Copyright (c) 2012 Takashi Iwai <tiwai@suse.de>
 *
 * This driver is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

#ifndef __SOUND_HDA_GENERIC_H
#define __SOUND_HDA_GENERIC_H

/* unsol event tags */
enum {
	HDA_GEN_HP_EVENT = 1, HDA_GEN_FRONT_EVENT, HDA_GEN_MIC_EVENT,
	HDA_GEN_LAST_EVENT = HDA_GEN_MIC_EVENT
};

/* table entry for multi-io paths */
struct hda_multi_io {
	hda_nid_t pin;		/* multi-io widget pin NID */
	hda_nid_t dac;		/* DAC to be connected */
	unsigned int ctl_in;	/* cached input-pin control value */
};

/* Widget connection path
 *
 * For output, stored in the order of DAC -> ... -> pin,
 * for input, pin -> ... -> ADC.
 *
 * idx[i] contains the source index number to select on of the widget path[i];
 * e.g. idx[1] is the index of the DAC (path[0]) selected by path[1] widget
 * multi[] indicates whether it's a selector widget with multi-connectors
 * (i.e. the connection selection is mandatory)
 * vol_ctl and mute_ctl contains the NIDs for the assigned mixers
 */

#define MAX_NID_PATH_DEPTH	10

enum {
	NID_PATH_VOL_CTL,
	NID_PATH_MUTE_CTL,
	NID_PATH_BOOST_CTL,
	NID_PATH_NUM_CTLS
};

struct nid_path {
	int depth;
	hda_nid_t path[MAX_NID_PATH_DEPTH];
	unsigned char idx[MAX_NID_PATH_DEPTH];
	unsigned char multi[MAX_NID_PATH_DEPTH];
	unsigned int ctls[NID_PATH_NUM_CTLS]; /* NID_PATH_XXX_CTL */
	bool active;
	bool with_aa_mix;
};

/* mic/line-in auto switching entry */

#define MAX_AUTO_MIC_PINS	3

struct automic_entry {
	hda_nid_t pin;		/* pin */
	int idx;		/* imux index, -1 = invalid */
	unsigned int attr;	/* pin attribute (INPUT_PIN_ATTR_*) */
};

/* active stream id */
enum { STREAM_MULTI_OUT, STREAM_INDEP_HP };

/* PCM hook action */
enum {
	HDA_GEN_PCM_ACT_OPEN,
	HDA_GEN_PCM_ACT_PREPARE,
	HDA_GEN_PCM_ACT_CLEANUP,
	HDA_GEN_PCM_ACT_CLOSE,
};

struct hda_gen_spec {
	char stream_name_analog[32];	/* analog PCM stream */
	const struct hda_pcm_stream *stream_analog_playback;
	const struct hda_pcm_stream *stream_analog_capture;
	const struct hda_pcm_stream *stream_analog_alt_playback;
	const struct hda_pcm_stream *stream_analog_alt_capture;

	char stream_name_digital[32];	/* digital PCM stream */
	const struct hda_pcm_stream *stream_digital_playback;
	const struct hda_pcm_stream *stream_digital_capture;

	/* PCM */
	unsigned int active_streams;
	struct mutex pcm_mutex;

	/* playback */
	struct hda_multi_out multiout;	/* playback set-up
					 * max_channels, dacs must be set
					 * dig_out_nid and hp_nid are optional
					 */
	hda_nid_t alt_dac_nid;
	hda_nid_t slave_dig_outs[3];	/* optional - for auto-parsing */
	int dig_out_type;

	/* capture */
	unsigned int num_adc_nids;
	hda_nid_t adc_nids[AUTO_CFG_MAX_OUTS];
	hda_nid_t dig_in_nid;		/* digital-in NID; optional */
	hda_nid_t mixer_nid;		/* analog-mixer NID */

	/* capture setup for dynamic dual-adc switch */
	hda_nid_t cur_adc;
	unsigned int cur_adc_stream_tag;
	unsigned int cur_adc_format;

	/* capture source */
	struct hda_input_mux input_mux;
	unsigned int cur_mux[3];

	/* channel model */
	int const_channel_count;	/* min. channel count (for speakers) */
	int ext_channel_count;		/* current channel count for multi-io */

	/* PCM information */
	struct hda_pcm pcm_rec[3];	/* used in build_pcms() */

	/* dynamic controls, init_verbs and input_mux */
	struct auto_pin_cfg autocfg;
	struct snd_array kctls;
	hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
	hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS];
	unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS];
	hda_nid_t shared_mic_vref_pin;

	/* DAC list */
	int num_all_dacs;
	hda_nid_t all_dacs[16];

	/* path list */
	struct snd_array paths;

	/* path indices */
	int out_paths[AUTO_CFG_MAX_OUTS];
	int hp_paths[AUTO_CFG_MAX_OUTS];
	int speaker_paths[AUTO_CFG_MAX_OUTS];
	int aamix_out_paths[3];
	int digout_paths[AUTO_CFG_MAX_OUTS];
	int loopback_paths[HDA_MAX_NUM_INPUTS];
	int digin_path;

	/* auto-mic stuff */
	int am_num_entries;
	struct automic_entry am_entry[MAX_AUTO_MIC_PINS];

	/* for pin sensing */
	unsigned int hp_jack_present:1;
	unsigned int line_jack_present:1;
	unsigned int master_mute:1;
	unsigned int auto_mic:1;
	unsigned int automute_speaker:1; /* automute speaker outputs */
	unsigned int automute_lo:1; /* automute LO outputs */
	unsigned int detect_hp:1;	/* Headphone detection enabled */
	unsigned int detect_lo:1;	/* Line-out detection enabled */
	unsigned int automute_speaker_possible:1; /* there are speakers and either LO or HP */
	unsigned int automute_lo_possible:1;	  /* there are line outs and HP */
	unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */
	unsigned int line_in_auto_switch:1; /* allow line-in auto switch */

	/* other flags */
	unsigned int need_dac_fix:1; /* need to limit DACs for multi channels */
	unsigned int no_analog:1; /* digital I/O only */
	unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */
	unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */
	unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */
	unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */
	unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */
	unsigned int own_eapd_ctl:1; /* set EAPD by own function */
	unsigned int vmaster_mute_enum:1; /* add vmaster mute mode enum */
	unsigned int indep_hp:1; /* independent HP supported */
	unsigned int indep_hp_enabled:1; /* independent HP enabled */

	/* loopback mixing mode */
	bool aamix_mode;

	/* for virtual master */
	hda_nid_t vmaster_nid;
	struct hda_vmaster_mute_hook vmaster_mute;
#ifdef CONFIG_PM
	struct hda_loopback_check loopback;
	int num_loopbacks;
	struct hda_amp_list loopback_list[8];
#endif

	/* multi-io */
	int multi_ios;
	struct hda_multi_io multi_io[4];

	/* hooks */
	void (*init_hook)(struct hda_codec *codec);
	void (*automute_hook)(struct hda_codec *codec);
	void (*cap_sync_hook)(struct hda_codec *codec);

	/* PCM playback hook */
	void (*pcm_playback_hook)(struct hda_pcm_stream *hinfo,
				  struct hda_codec *codec,
				  struct snd_pcm_substream *substream,
				  int action);

	/* automute / autoswitch hooks */
	void (*hp_automute_hook)(struct hda_codec *codec,
				 struct hda_jack_tbl *tbl);
	void (*line_automute_hook)(struct hda_codec *codec,
				   struct hda_jack_tbl *tbl);
	void (*mic_autoswitch_hook)(struct hda_codec *codec,
				    struct hda_jack_tbl *tbl);
};

int snd_hda_gen_spec_init(struct hda_gen_spec *spec);
void snd_hda_gen_spec_free(struct hda_gen_spec *spec);

int snd_hda_gen_init(struct hda_codec *codec);
void snd_hda_gen_free(struct hda_codec *codec);

struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
				      hda_nid_t from_nid, hda_nid_t to_nid);
int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path);
struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx);

enum {
	HDA_PARSE_NO_AAMIX,
	HDA_PARSE_ONLY_AAMIX,
	HDA_PARSE_ALL,
};

bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
			    hda_nid_t to_nid, int with_aa_mix,
			    struct nid_path *path);
struct nid_path *
snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
		     hda_nid_t to_nid, int with_aa_mix);
void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
			   bool enable, bool add_aamix);

struct snd_kcontrol_new *
snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
		     const struct snd_kcontrol_new *temp);

int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
				  struct auto_pin_cfg *cfg);
int snd_hda_gen_build_controls(struct hda_codec *codec);
int snd_hda_gen_build_pcms(struct hda_codec *codec);

/* standard jack event callbacks */
void snd_hda_gen_hp_automute(struct hda_codec *codec,
			     struct hda_jack_tbl *jack);
void snd_hda_gen_line_automute(struct hda_codec *codec,
			       struct hda_jack_tbl *jack);
void snd_hda_gen_mic_autoswitch(struct hda_codec *codec,
				struct hda_jack_tbl *jack);
void snd_hda_gen_update_outputs(struct hda_codec *codec);

#ifdef CONFIG_PM
int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid);
#endif

#endif /* __SOUND_HDA_GENERIC_H */
OpenPOWER on IntegriCloud