diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/pci/hda |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'sound/pci/hda')
-rw-r--r-- | sound/pci/hda/Makefile | 7 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 1856 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 604 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.c | 906 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 1449 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 161 | ||||
-rw-r--r-- | sound/pci/hda/hda_patch.h | 17 | ||||
-rw-r--r-- | sound/pci/hda/hda_proc.c | 298 | ||||
-rw-r--r-- | sound/pci/hda/patch_analog.c | 445 | ||||
-rw-r--r-- | sound/pci/hda/patch_cmedia.c | 621 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 1503 |
11 files changed, 7867 insertions, 0 deletions
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile new file mode 100644 index 000000000000..570a59d33b41 --- /dev/null +++ b/sound/pci/hda/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | snd-hda-intel-objs := hda_intel.o | ||
2 | snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o | ||
3 | ifdef CONFIG_PROC_FS | ||
4 | snd-hda-codec-objs += hda_proc.o | ||
5 | endif | ||
6 | |||
7 | obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o snd-hda-codec.o | ||
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c new file mode 100644 index 000000000000..9ed117ac0c09 --- /dev/null +++ b/sound/pci/hda/hda_codec.c | |||
@@ -0,0 +1,1856 @@ | |||
1 | /* | ||
2 | * Universal Interface for Intel High Definition Audio Codec | ||
3 | * | ||
4 | * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> | ||
5 | * | ||
6 | * | ||
7 | * This driver is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This driver is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <linux/moduleparam.h> | ||
28 | #include <sound/core.h> | ||
29 | #include "hda_codec.h" | ||
30 | #include <sound/asoundef.h> | ||
31 | #include <sound/initval.h> | ||
32 | #include "hda_local.h" | ||
33 | |||
34 | |||
35 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); | ||
36 | MODULE_DESCRIPTION("Universal interface for High Definition Audio Codec"); | ||
37 | MODULE_LICENSE("GPL"); | ||
38 | |||
39 | |||
40 | /* | ||
41 | * vendor / preset table | ||
42 | */ | ||
43 | |||
44 | struct hda_vendor_id { | ||
45 | unsigned int id; | ||
46 | const char *name; | ||
47 | }; | ||
48 | |||
49 | /* codec vendor labels */ | ||
50 | static struct hda_vendor_id hda_vendor_ids[] = { | ||
51 | { 0x10ec, "Realtek" }, | ||
52 | { 0x13f6, "C-Media" }, | ||
53 | { 0x434d, "C-Media" }, | ||
54 | {} /* terminator */ | ||
55 | }; | ||
56 | |||
57 | /* codec presets */ | ||
58 | #include "hda_patch.h" | ||
59 | |||
60 | |||
61 | /** | ||
62 | * snd_hda_codec_read - send a command and get the response | ||
63 | * @codec: the HDA codec | ||
64 | * @nid: NID to send the command | ||
65 | * @direct: direct flag | ||
66 | * @verb: the verb to send | ||
67 | * @parm: the parameter for the verb | ||
68 | * | ||
69 | * Send a single command and read the corresponding response. | ||
70 | * | ||
71 | * Returns the obtained response value, or -1 for an error. | ||
72 | */ | ||
73 | unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int direct, | ||
74 | unsigned int verb, unsigned int parm) | ||
75 | { | ||
76 | unsigned int res; | ||
77 | down(&codec->bus->cmd_mutex); | ||
78 | if (! codec->bus->ops.command(codec, nid, direct, verb, parm)) | ||
79 | res = codec->bus->ops.get_response(codec); | ||
80 | else | ||
81 | res = (unsigned int)-1; | ||
82 | up(&codec->bus->cmd_mutex); | ||
83 | return res; | ||
84 | } | ||
85 | |||
86 | /** | ||
87 | * snd_hda_codec_write - send a single command without waiting for response | ||
88 | * @codec: the HDA codec | ||
89 | * @nid: NID to send the command | ||
90 | * @direct: direct flag | ||
91 | * @verb: the verb to send | ||
92 | * @parm: the parameter for the verb | ||
93 | * | ||
94 | * Send a single command without waiting for response. | ||
95 | * | ||
96 | * Returns 0 if successful, or a negative error code. | ||
97 | */ | ||
98 | int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, | ||
99 | unsigned int verb, unsigned int parm) | ||
100 | { | ||
101 | int err; | ||
102 | down(&codec->bus->cmd_mutex); | ||
103 | err = codec->bus->ops.command(codec, nid, direct, verb, parm); | ||
104 | up(&codec->bus->cmd_mutex); | ||
105 | return err; | ||
106 | } | ||
107 | |||
108 | /** | ||
109 | * snd_hda_sequence_write - sequence writes | ||
110 | * @codec: the HDA codec | ||
111 | * @seq: VERB array to send | ||
112 | * | ||
113 | * Send the commands sequentially from the given array. | ||
114 | * The array must be terminated with NID=0. | ||
115 | */ | ||
116 | void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq) | ||
117 | { | ||
118 | for (; seq->nid; seq++) | ||
119 | snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param); | ||
120 | } | ||
121 | |||
122 | /** | ||
123 | * snd_hda_get_sub_nodes - get the range of sub nodes | ||
124 | * @codec: the HDA codec | ||
125 | * @nid: NID to parse | ||
126 | * @start_id: the pointer to store the start NID | ||
127 | * | ||
128 | * Parse the NID and store the start NID of its sub-nodes. | ||
129 | * Returns the number of sub-nodes. | ||
130 | */ | ||
131 | int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *start_id) | ||
132 | { | ||
133 | unsigned int parm; | ||
134 | |||
135 | parm = snd_hda_param_read(codec, nid, AC_PAR_NODE_COUNT); | ||
136 | *start_id = (parm >> 16) & 0x7fff; | ||
137 | return (int)(parm & 0x7fff); | ||
138 | } | ||
139 | |||
140 | /** | ||
141 | * snd_hda_get_connections - get connection list | ||
142 | * @codec: the HDA codec | ||
143 | * @nid: NID to parse | ||
144 | * @conn_list: connection list array | ||
145 | * @max_conns: max. number of connections to store | ||
146 | * | ||
147 | * Parses the connection list of the given widget and stores the list | ||
148 | * of NIDs. | ||
149 | * | ||
150 | * Returns the number of connections, or a negative error code. | ||
151 | */ | ||
152 | int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, | ||
153 | hda_nid_t *conn_list, int max_conns) | ||
154 | { | ||
155 | unsigned int parm; | ||
156 | int i, j, conn_len, num_tupples, conns; | ||
157 | unsigned int shift, num_elems, mask; | ||
158 | |||
159 | snd_assert(conn_list && max_conns > 0, return -EINVAL); | ||
160 | |||
161 | parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN); | ||
162 | if (parm & AC_CLIST_LONG) { | ||
163 | /* long form */ | ||
164 | shift = 16; | ||
165 | num_elems = 2; | ||
166 | } else { | ||
167 | /* short form */ | ||
168 | shift = 8; | ||
169 | num_elems = 4; | ||
170 | } | ||
171 | conn_len = parm & AC_CLIST_LENGTH; | ||
172 | num_tupples = num_elems / 2; | ||
173 | mask = (1 << (shift-1)) - 1; | ||
174 | |||
175 | if (! conn_len) | ||
176 | return 0; /* no connection */ | ||
177 | |||
178 | if (conn_len == 1) { | ||
179 | /* single connection */ | ||
180 | parm = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_LIST, 0); | ||
181 | conn_list[0] = parm & mask; | ||
182 | return 1; | ||
183 | } | ||
184 | |||
185 | /* multi connection */ | ||
186 | conns = 0; | ||
187 | for (i = 0; i < conn_len; i += num_elems) { | ||
188 | parm = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_LIST, i); | ||
189 | for (j = 0; j < num_tupples; j++) { | ||
190 | int range_val; | ||
191 | hda_nid_t val1, val2, n; | ||
192 | range_val = parm & (1 << (shift-1)); /* ranges */ | ||
193 | val1 = parm & mask; | ||
194 | parm >>= shift; | ||
195 | val2 = parm & mask; | ||
196 | parm >>= shift; | ||
197 | if (range_val) { | ||
198 | /* ranges between val1 and val2 */ | ||
199 | if (val1 > val2) { | ||
200 | snd_printk(KERN_WARNING "hda_codec: invalid dep_range_val %x:%x\n", val1, val2); | ||
201 | continue; | ||
202 | } | ||
203 | for (n = val1; n <= val2; n++) { | ||
204 | if (conns >= max_conns) | ||
205 | return -EINVAL; | ||
206 | conn_list[conns++] = n; | ||
207 | } | ||
208 | } else { | ||
209 | if (! val1) | ||
210 | break; | ||
211 | if (conns >= max_conns) | ||
212 | return -EINVAL; | ||
213 | conn_list[conns++] = val1; | ||
214 | if (! val2) | ||
215 | break; | ||
216 | if (conns >= max_conns) | ||
217 | return -EINVAL; | ||
218 | conn_list[conns++] = val2; | ||
219 | } | ||
220 | } | ||
221 | } | ||
222 | return conns; | ||
223 | } | ||
224 | |||
225 | |||
226 | /** | ||
227 | * snd_hda_queue_unsol_event - add an unsolicited event to queue | ||
228 | * @bus: the BUS | ||
229 | * @res: unsolicited event (lower 32bit of RIRB entry) | ||
230 | * @res_ex: codec addr and flags (upper 32bit or RIRB entry) | ||
231 | * | ||
232 | * Adds the given event to the queue. The events are processed in | ||
233 | * the workqueue asynchronously. Call this function in the interrupt | ||
234 | * hanlder when RIRB receives an unsolicited event. | ||
235 | * | ||
236 | * Returns 0 if successful, or a negative error code. | ||
237 | */ | ||
238 | int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) | ||
239 | { | ||
240 | struct hda_bus_unsolicited *unsol; | ||
241 | unsigned int wp; | ||
242 | |||
243 | if ((unsol = bus->unsol) == NULL) | ||
244 | return 0; | ||
245 | |||
246 | wp = (unsol->wp + 1) % HDA_UNSOL_QUEUE_SIZE; | ||
247 | unsol->wp = wp; | ||
248 | |||
249 | wp <<= 1; | ||
250 | unsol->queue[wp] = res; | ||
251 | unsol->queue[wp + 1] = res_ex; | ||
252 | |||
253 | queue_work(unsol->workq, &unsol->work); | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | /* | ||
259 | * process queueud unsolicited events | ||
260 | */ | ||
261 | static void process_unsol_events(void *data) | ||
262 | { | ||
263 | struct hda_bus *bus = data; | ||
264 | struct hda_bus_unsolicited *unsol = bus->unsol; | ||
265 | struct hda_codec *codec; | ||
266 | unsigned int rp, caddr, res; | ||
267 | |||
268 | while (unsol->rp != unsol->wp) { | ||
269 | rp = (unsol->rp + 1) % HDA_UNSOL_QUEUE_SIZE; | ||
270 | unsol->rp = rp; | ||
271 | rp <<= 1; | ||
272 | res = unsol->queue[rp]; | ||
273 | caddr = unsol->queue[rp + 1]; | ||
274 | if (! (caddr & (1 << 4))) /* no unsolicited event? */ | ||
275 | continue; | ||
276 | codec = bus->caddr_tbl[caddr & 0x0f]; | ||
277 | if (codec && codec->patch_ops.unsol_event) | ||
278 | codec->patch_ops.unsol_event(codec, res); | ||
279 | } | ||
280 | } | ||
281 | |||
282 | /* | ||
283 | * initialize unsolicited queue | ||
284 | */ | ||
285 | static int init_unsol_queue(struct hda_bus *bus) | ||
286 | { | ||
287 | struct hda_bus_unsolicited *unsol; | ||
288 | |||
289 | unsol = kcalloc(1, sizeof(*unsol), GFP_KERNEL); | ||
290 | if (! unsol) { | ||
291 | snd_printk(KERN_ERR "hda_codec: can't allocate unsolicited queue\n"); | ||
292 | return -ENOMEM; | ||
293 | } | ||
294 | unsol->workq = create_workqueue("hda_codec"); | ||
295 | if (! unsol->workq) { | ||
296 | snd_printk(KERN_ERR "hda_codec: can't create workqueue\n"); | ||
297 | kfree(unsol); | ||
298 | return -ENOMEM; | ||
299 | } | ||
300 | INIT_WORK(&unsol->work, process_unsol_events, bus); | ||
301 | bus->unsol = unsol; | ||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | * destructor | ||
307 | */ | ||
308 | static void snd_hda_codec_free(struct hda_codec *codec); | ||
309 | |||
310 | static int snd_hda_bus_free(struct hda_bus *bus) | ||
311 | { | ||
312 | struct list_head *p, *n; | ||
313 | |||
314 | if (! bus) | ||
315 | return 0; | ||
316 | if (bus->unsol) { | ||
317 | destroy_workqueue(bus->unsol->workq); | ||
318 | kfree(bus->unsol); | ||
319 | } | ||
320 | list_for_each_safe(p, n, &bus->codec_list) { | ||
321 | struct hda_codec *codec = list_entry(p, struct hda_codec, list); | ||
322 | snd_hda_codec_free(codec); | ||
323 | } | ||
324 | if (bus->ops.private_free) | ||
325 | bus->ops.private_free(bus); | ||
326 | kfree(bus); | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | static int snd_hda_bus_dev_free(snd_device_t *device) | ||
331 | { | ||
332 | struct hda_bus *bus = device->device_data; | ||
333 | return snd_hda_bus_free(bus); | ||
334 | } | ||
335 | |||
336 | /** | ||
337 | * snd_hda_bus_new - create a HDA bus | ||
338 | * @card: the card entry | ||
339 | * @temp: the template for hda_bus information | ||
340 | * @busp: the pointer to store the created bus instance | ||
341 | * | ||
342 | * Returns 0 if successful, or a negative error code. | ||
343 | */ | ||
344 | int snd_hda_bus_new(snd_card_t *card, const struct hda_bus_template *temp, | ||
345 | struct hda_bus **busp) | ||
346 | { | ||
347 | struct hda_bus *bus; | ||
348 | int err; | ||
349 | static snd_device_ops_t dev_ops = { | ||
350 | .dev_free = snd_hda_bus_dev_free, | ||
351 | }; | ||
352 | |||
353 | snd_assert(temp, return -EINVAL); | ||
354 | snd_assert(temp->ops.command && temp->ops.get_response, return -EINVAL); | ||
355 | |||
356 | if (busp) | ||
357 | *busp = NULL; | ||
358 | |||
359 | bus = kcalloc(1, sizeof(*bus), GFP_KERNEL); | ||
360 | if (bus == NULL) { | ||
361 | snd_printk(KERN_ERR "can't allocate struct hda_bus\n"); | ||
362 | return -ENOMEM; | ||
363 | } | ||
364 | |||
365 | bus->card = card; | ||
366 | bus->private_data = temp->private_data; | ||
367 | bus->pci = temp->pci; | ||
368 | bus->modelname = temp->modelname; | ||
369 | bus->ops = temp->ops; | ||
370 | |||
371 | init_MUTEX(&bus->cmd_mutex); | ||
372 | INIT_LIST_HEAD(&bus->codec_list); | ||
373 | |||
374 | init_unsol_queue(bus); | ||
375 | |||
376 | if ((err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops)) < 0) { | ||
377 | snd_hda_bus_free(bus); | ||
378 | return err; | ||
379 | } | ||
380 | if (busp) | ||
381 | *busp = bus; | ||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | |||
386 | /* | ||
387 | * find a matching codec preset | ||
388 | */ | ||
389 | static const struct hda_codec_preset *find_codec_preset(struct hda_codec *codec) | ||
390 | { | ||
391 | const struct hda_codec_preset **tbl, *preset; | ||
392 | |||
393 | for (tbl = hda_preset_tables; *tbl; tbl++) { | ||
394 | for (preset = *tbl; preset->id; preset++) { | ||
395 | u32 mask = preset->mask; | ||
396 | if (! mask) | ||
397 | mask = ~0; | ||
398 | if (preset->id == (codec->vendor_id & mask)) | ||
399 | return preset; | ||
400 | } | ||
401 | } | ||
402 | return NULL; | ||
403 | } | ||
404 | |||
405 | /* | ||
406 | * snd_hda_get_codec_name - store the codec name | ||
407 | */ | ||
408 | void snd_hda_get_codec_name(struct hda_codec *codec, | ||
409 | char *name, int namelen) | ||
410 | { | ||
411 | const struct hda_vendor_id *c; | ||
412 | const char *vendor = NULL; | ||
413 | u16 vendor_id = codec->vendor_id >> 16; | ||
414 | char tmp[16]; | ||
415 | |||
416 | for (c = hda_vendor_ids; c->id; c++) { | ||
417 | if (c->id == vendor_id) { | ||
418 | vendor = c->name; | ||
419 | break; | ||
420 | } | ||
421 | } | ||
422 | if (! vendor) { | ||
423 | sprintf(tmp, "Generic %04x", vendor_id); | ||
424 | vendor = tmp; | ||
425 | } | ||
426 | if (codec->preset && codec->preset->name) | ||
427 | snprintf(name, namelen, "%s %s", vendor, codec->preset->name); | ||
428 | else | ||
429 | snprintf(name, namelen, "%s ID %x", vendor, codec->vendor_id & 0xffff); | ||
430 | } | ||
431 | |||
432 | /* | ||
433 | * look for an AFG node | ||
434 | * | ||
435 | * return 0 if not found | ||
436 | */ | ||
437 | static int look_for_afg_node(struct hda_codec *codec) | ||
438 | { | ||
439 | int i, total_nodes; | ||
440 | hda_nid_t nid; | ||
441 | |||
442 | total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid); | ||
443 | for (i = 0; i < total_nodes; i++, nid++) { | ||
444 | if ((snd_hda_param_read(codec, nid, AC_PAR_FUNCTION_TYPE) & 0xff) == | ||
445 | AC_GRP_AUDIO_FUNCTION) | ||
446 | return nid; | ||
447 | } | ||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | /* | ||
452 | * codec destructor | ||
453 | */ | ||
454 | static void snd_hda_codec_free(struct hda_codec *codec) | ||
455 | { | ||
456 | if (! codec) | ||
457 | return; | ||
458 | list_del(&codec->list); | ||
459 | codec->bus->caddr_tbl[codec->addr] = NULL; | ||
460 | if (codec->patch_ops.free) | ||
461 | codec->patch_ops.free(codec); | ||
462 | kfree(codec); | ||
463 | } | ||
464 | |||
465 | static void init_amp_hash(struct hda_codec *codec); | ||
466 | |||
467 | /** | ||
468 | * snd_hda_codec_new - create a HDA codec | ||
469 | * @bus: the bus to assign | ||
470 | * @codec_addr: the codec address | ||
471 | * @codecp: the pointer to store the generated codec | ||
472 | * | ||
473 | * Returns 0 if successful, or a negative error code. | ||
474 | */ | ||
475 | int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, | ||
476 | struct hda_codec **codecp) | ||
477 | { | ||
478 | struct hda_codec *codec; | ||
479 | char component[13]; | ||
480 | int err; | ||
481 | |||
482 | snd_assert(bus, return -EINVAL); | ||
483 | snd_assert(codec_addr <= HDA_MAX_CODEC_ADDRESS, return -EINVAL); | ||
484 | |||
485 | if (bus->caddr_tbl[codec_addr]) { | ||
486 | snd_printk(KERN_ERR "hda_codec: address 0x%x is already occupied\n", codec_addr); | ||
487 | return -EBUSY; | ||
488 | } | ||
489 | |||
490 | codec = kcalloc(1, sizeof(*codec), GFP_KERNEL); | ||
491 | if (codec == NULL) { | ||
492 | snd_printk(KERN_ERR "can't allocate struct hda_codec\n"); | ||
493 | return -ENOMEM; | ||
494 | } | ||
495 | |||
496 | codec->bus = bus; | ||
497 | codec->addr = codec_addr; | ||
498 | init_MUTEX(&codec->spdif_mutex); | ||
499 | init_amp_hash(codec); | ||
500 | |||
501 | list_add_tail(&codec->list, &bus->codec_list); | ||
502 | bus->caddr_tbl[codec_addr] = codec; | ||
503 | |||
504 | codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_VENDOR_ID); | ||
505 | codec->subsystem_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_SUBSYSTEM_ID); | ||
506 | codec->revision_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_REV_ID); | ||
507 | |||
508 | /* FIXME: support for multiple AFGs? */ | ||
509 | codec->afg = look_for_afg_node(codec); | ||
510 | if (! codec->afg) { | ||
511 | snd_printk(KERN_ERR "hda_codec: no AFG node found\n"); | ||
512 | snd_hda_codec_free(codec); | ||
513 | return -ENODEV; | ||
514 | } | ||
515 | |||
516 | codec->preset = find_codec_preset(codec); | ||
517 | if (! *bus->card->mixername) | ||
518 | snd_hda_get_codec_name(codec, bus->card->mixername, | ||
519 | sizeof(bus->card->mixername)); | ||
520 | |||
521 | if (codec->preset && codec->preset->patch) | ||
522 | err = codec->preset->patch(codec); | ||
523 | else | ||
524 | err = snd_hda_parse_generic_codec(codec); | ||
525 | if (err < 0) { | ||
526 | snd_hda_codec_free(codec); | ||
527 | return err; | ||
528 | } | ||
529 | |||
530 | snd_hda_codec_proc_new(codec); | ||
531 | |||
532 | sprintf(component, "HDA:%08x", codec->vendor_id); | ||
533 | snd_component_add(codec->bus->card, component); | ||
534 | |||
535 | if (codecp) | ||
536 | *codecp = codec; | ||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | /** | ||
541 | * snd_hda_codec_setup_stream - set up the codec for streaming | ||
542 | * @codec: the CODEC to set up | ||
543 | * @nid: the NID to set up | ||
544 | * @stream_tag: stream tag to pass, it's between 0x1 and 0xf. | ||
545 | * @channel_id: channel id to pass, zero based. | ||
546 | * @format: stream format. | ||
547 | */ | ||
548 | void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, | ||
549 | int channel_id, int format) | ||
550 | { | ||
551 | snd_printdd("hda_codec_setup_stream: NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n", | ||
552 | nid, stream_tag, channel_id, format); | ||
553 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, | ||
554 | (stream_tag << 4) | channel_id); | ||
555 | msleep(1); | ||
556 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format); | ||
557 | } | ||
558 | |||
559 | |||
560 | /* | ||
561 | * amp access functions | ||
562 | */ | ||
563 | |||
564 | #define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + (idx) * 32 + (dir) * 64) | ||
565 | #define INFO_AMP_CAPS (1<<0) | ||
566 | #define INFO_AMP_VOL (1<<1) | ||
567 | |||
568 | /* initialize the hash table */ | ||
569 | static void init_amp_hash(struct hda_codec *codec) | ||
570 | { | ||
571 | memset(codec->amp_hash, 0xff, sizeof(codec->amp_hash)); | ||
572 | codec->num_amp_entries = 0; | ||
573 | } | ||
574 | |||
575 | /* query the hash. allocate an entry if not found. */ | ||
576 | static struct hda_amp_info *get_alloc_amp_hash(struct hda_codec *codec, u32 key) | ||
577 | { | ||
578 | u16 idx = key % (u16)ARRAY_SIZE(codec->amp_hash); | ||
579 | u16 cur = codec->amp_hash[idx]; | ||
580 | struct hda_amp_info *info; | ||
581 | |||
582 | while (cur != 0xffff) { | ||
583 | info = &codec->amp_info[cur]; | ||
584 | if (info->key == key) | ||
585 | return info; | ||
586 | cur = info->next; | ||
587 | } | ||
588 | |||
589 | /* add a new hash entry */ | ||
590 | if (codec->num_amp_entries >= ARRAY_SIZE(codec->amp_info)) { | ||
591 | snd_printk(KERN_ERR "hda_codec: Tooooo many amps!\n"); | ||
592 | return NULL; | ||
593 | } | ||
594 | cur = codec->num_amp_entries++; | ||
595 | info = &codec->amp_info[cur]; | ||
596 | info->key = key; | ||
597 | info->status = 0; /* not initialized yet */ | ||
598 | info->next = codec->amp_hash[idx]; | ||
599 | codec->amp_hash[idx] = cur; | ||
600 | |||
601 | return info; | ||
602 | } | ||
603 | |||
604 | /* | ||
605 | * query AMP capabilities for the given widget and direction | ||
606 | */ | ||
607 | static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) | ||
608 | { | ||
609 | struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, 0)); | ||
610 | |||
611 | if (! info) | ||
612 | return 0; | ||
613 | if (! (info->status & INFO_AMP_CAPS)) { | ||
614 | if (!(snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP) & AC_WCAP_AMP_OVRD)) | ||
615 | nid = codec->afg; | ||
616 | info->amp_caps = snd_hda_param_read(codec, nid, direction == HDA_OUTPUT ? | ||
617 | AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP); | ||
618 | info->status |= INFO_AMP_CAPS; | ||
619 | } | ||
620 | return info->amp_caps; | ||
621 | } | ||
622 | |||
623 | /* | ||
624 | * read the current volume to info | ||
625 | * if the cache exists, read from the cache. | ||
626 | */ | ||
627 | static void get_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, | ||
628 | hda_nid_t nid, int ch, int direction, int index) | ||
629 | { | ||
630 | u32 val, parm; | ||
631 | |||
632 | if (info->status & (INFO_AMP_VOL << ch)) | ||
633 | return; | ||
634 | |||
635 | parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT; | ||
636 | parm |= direction == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; | ||
637 | parm |= index; | ||
638 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, parm); | ||
639 | info->vol[ch] = val & 0xff; | ||
640 | info->status |= INFO_AMP_VOL << ch; | ||
641 | } | ||
642 | |||
643 | /* | ||
644 | * write the current volume in info to the h/w | ||
645 | */ | ||
646 | static void put_vol_mute(struct hda_codec *codec, | ||
647 | hda_nid_t nid, int ch, int direction, int index, int val) | ||
648 | { | ||
649 | u32 parm; | ||
650 | |||
651 | parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT; | ||
652 | parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT; | ||
653 | parm |= index << AC_AMP_SET_INDEX_SHIFT; | ||
654 | parm |= val; | ||
655 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm); | ||
656 | } | ||
657 | |||
658 | /* | ||
659 | * read/write AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. | ||
660 | */ | ||
661 | int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index) | ||
662 | { | ||
663 | struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index)); | ||
664 | if (! info) | ||
665 | return 0; | ||
666 | get_vol_mute(codec, info, nid, ch, direction, index); | ||
667 | return info->vol[ch]; | ||
668 | } | ||
669 | |||
670 | int snd_hda_codec_amp_write(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int val) | ||
671 | { | ||
672 | struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx)); | ||
673 | if (! info) | ||
674 | return 0; | ||
675 | get_vol_mute(codec, info, nid, ch, direction, idx); | ||
676 | if (info->vol[ch] == val && ! codec->in_resume) | ||
677 | return 0; | ||
678 | put_vol_mute(codec, nid, ch, direction, idx, val); | ||
679 | info->vol[ch] = val; | ||
680 | return 1; | ||
681 | } | ||
682 | |||
683 | |||
684 | /* | ||
685 | * AMP control callbacks | ||
686 | */ | ||
687 | /* retrieve parameters from private_value */ | ||
688 | #define get_amp_nid(kc) ((kc)->private_value & 0xffff) | ||
689 | #define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3) | ||
690 | #define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) | ||
691 | #define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) | ||
692 | |||
693 | /* volume */ | ||
694 | int snd_hda_mixer_amp_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
695 | { | ||
696 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
697 | u16 nid = get_amp_nid(kcontrol); | ||
698 | u8 chs = get_amp_channels(kcontrol); | ||
699 | int dir = get_amp_direction(kcontrol); | ||
700 | u32 caps; | ||
701 | |||
702 | caps = query_amp_caps(codec, nid, dir); | ||
703 | caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; /* num steps */ | ||
704 | if (! caps) { | ||
705 | printk(KERN_WARNING "hda_codec: num_steps = 0 for NID=0x%x\n", nid); | ||
706 | return -EINVAL; | ||
707 | } | ||
708 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
709 | uinfo->count = chs == 3 ? 2 : 1; | ||
710 | uinfo->value.integer.min = 0; | ||
711 | uinfo->value.integer.max = caps; | ||
712 | return 0; | ||
713 | } | ||
714 | |||
715 | int snd_hda_mixer_amp_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
716 | { | ||
717 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
718 | hda_nid_t nid = get_amp_nid(kcontrol); | ||
719 | int chs = get_amp_channels(kcontrol); | ||
720 | int dir = get_amp_direction(kcontrol); | ||
721 | int idx = get_amp_index(kcontrol); | ||
722 | long *valp = ucontrol->value.integer.value; | ||
723 | |||
724 | if (chs & 1) | ||
725 | *valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x7f; | ||
726 | if (chs & 2) | ||
727 | *valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x7f; | ||
728 | return 0; | ||
729 | } | ||
730 | |||
731 | int snd_hda_mixer_amp_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
732 | { | ||
733 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
734 | hda_nid_t nid = get_amp_nid(kcontrol); | ||
735 | int chs = get_amp_channels(kcontrol); | ||
736 | int dir = get_amp_direction(kcontrol); | ||
737 | int idx = get_amp_index(kcontrol); | ||
738 | int val; | ||
739 | long *valp = ucontrol->value.integer.value; | ||
740 | int change = 0; | ||
741 | |||
742 | if (chs & 1) { | ||
743 | val = *valp & 0x7f; | ||
744 | val |= snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x80; | ||
745 | change = snd_hda_codec_amp_write(codec, nid, 0, dir, idx, val); | ||
746 | valp++; | ||
747 | } | ||
748 | if (chs & 2) { | ||
749 | val = *valp & 0x7f; | ||
750 | val |= snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x80; | ||
751 | change |= snd_hda_codec_amp_write(codec, nid, 1, dir, idx, val); | ||
752 | } | ||
753 | return change; | ||
754 | } | ||
755 | |||
756 | /* switch */ | ||
757 | int snd_hda_mixer_amp_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
758 | { | ||
759 | int chs = get_amp_channels(kcontrol); | ||
760 | |||
761 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
762 | uinfo->count = chs == 3 ? 2 : 1; | ||
763 | uinfo->value.integer.min = 0; | ||
764 | uinfo->value.integer.max = 1; | ||
765 | return 0; | ||
766 | } | ||
767 | |||
768 | int snd_hda_mixer_amp_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
769 | { | ||
770 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
771 | hda_nid_t nid = get_amp_nid(kcontrol); | ||
772 | int chs = get_amp_channels(kcontrol); | ||
773 | int dir = get_amp_direction(kcontrol); | ||
774 | int idx = get_amp_index(kcontrol); | ||
775 | long *valp = ucontrol->value.integer.value; | ||
776 | |||
777 | if (chs & 1) | ||
778 | *valp++ = (snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x80) ? 0 : 1; | ||
779 | if (chs & 2) | ||
780 | *valp = (snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x80) ? 0 : 1; | ||
781 | return 0; | ||
782 | } | ||
783 | |||
784 | int snd_hda_mixer_amp_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
785 | { | ||
786 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
787 | hda_nid_t nid = get_amp_nid(kcontrol); | ||
788 | int chs = get_amp_channels(kcontrol); | ||
789 | int dir = get_amp_direction(kcontrol); | ||
790 | int idx = get_amp_index(kcontrol); | ||
791 | int val; | ||
792 | long *valp = ucontrol->value.integer.value; | ||
793 | int change = 0; | ||
794 | |||
795 | if (chs & 1) { | ||
796 | val = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x7f; | ||
797 | val |= *valp ? 0 : 0x80; | ||
798 | change = snd_hda_codec_amp_write(codec, nid, 0, dir, idx, val); | ||
799 | valp++; | ||
800 | } | ||
801 | if (chs & 2) { | ||
802 | val = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x7f; | ||
803 | val |= *valp ? 0 : 0x80; | ||
804 | change = snd_hda_codec_amp_write(codec, nid, 1, dir, idx, val); | ||
805 | } | ||
806 | return change; | ||
807 | } | ||
808 | |||
809 | /* | ||
810 | * SPDIF out controls | ||
811 | */ | ||
812 | |||
813 | static int snd_hda_spdif_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
814 | { | ||
815 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | ||
816 | uinfo->count = 1; | ||
817 | return 0; | ||
818 | } | ||
819 | |||
820 | static int snd_hda_spdif_cmask_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
821 | { | ||
822 | ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL | | ||
823 | IEC958_AES0_NONAUDIO | | ||
824 | IEC958_AES0_CON_EMPHASIS_5015 | | ||
825 | IEC958_AES0_CON_NOT_COPYRIGHT; | ||
826 | ucontrol->value.iec958.status[1] = IEC958_AES1_CON_CATEGORY | | ||
827 | IEC958_AES1_CON_ORIGINAL; | ||
828 | return 0; | ||
829 | } | ||
830 | |||
831 | static int snd_hda_spdif_pmask_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
832 | { | ||
833 | ucontrol->value.iec958.status[0] = IEC958_AES0_PROFESSIONAL | | ||
834 | IEC958_AES0_NONAUDIO | | ||
835 | IEC958_AES0_PRO_EMPHASIS_5015; | ||
836 | return 0; | ||
837 | } | ||
838 | |||
839 | static int snd_hda_spdif_default_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
840 | { | ||
841 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
842 | |||
843 | ucontrol->value.iec958.status[0] = codec->spdif_status & 0xff; | ||
844 | ucontrol->value.iec958.status[1] = (codec->spdif_status >> 8) & 0xff; | ||
845 | ucontrol->value.iec958.status[2] = (codec->spdif_status >> 16) & 0xff; | ||
846 | ucontrol->value.iec958.status[3] = (codec->spdif_status >> 24) & 0xff; | ||
847 | |||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | /* convert from SPDIF status bits to HDA SPDIF bits | ||
852 | * bit 0 (DigEn) is always set zero (to be filled later) | ||
853 | */ | ||
854 | static unsigned short convert_from_spdif_status(unsigned int sbits) | ||
855 | { | ||
856 | unsigned short val = 0; | ||
857 | |||
858 | if (sbits & IEC958_AES0_PROFESSIONAL) | ||
859 | val |= 1 << 6; | ||
860 | if (sbits & IEC958_AES0_NONAUDIO) | ||
861 | val |= 1 << 5; | ||
862 | if (sbits & IEC958_AES0_PROFESSIONAL) { | ||
863 | if ((sbits & IEC958_AES0_PRO_EMPHASIS) == IEC958_AES0_PRO_EMPHASIS_5015) | ||
864 | val |= 1 << 3; | ||
865 | } else { | ||
866 | if ((sbits & IEC958_AES0_CON_EMPHASIS) == IEC958_AES0_CON_EMPHASIS_5015) | ||
867 | val |= 1 << 3; | ||
868 | if (! (sbits & IEC958_AES0_CON_NOT_COPYRIGHT)) | ||
869 | val |= 1 << 4; | ||
870 | if (sbits & (IEC958_AES1_CON_ORIGINAL << 8)) | ||
871 | val |= 1 << 7; | ||
872 | val |= sbits & (IEC958_AES1_CON_CATEGORY << 8); | ||
873 | } | ||
874 | return val; | ||
875 | } | ||
876 | |||
877 | /* convert to SPDIF status bits from HDA SPDIF bits | ||
878 | */ | ||
879 | static unsigned int convert_to_spdif_status(unsigned short val) | ||
880 | { | ||
881 | unsigned int sbits = 0; | ||
882 | |||
883 | if (val & (1 << 5)) | ||
884 | sbits |= IEC958_AES0_NONAUDIO; | ||
885 | if (val & (1 << 6)) | ||
886 | sbits |= IEC958_AES0_PROFESSIONAL; | ||
887 | if (sbits & IEC958_AES0_PROFESSIONAL) { | ||
888 | if (sbits & (1 << 3)) | ||
889 | sbits |= IEC958_AES0_PRO_EMPHASIS_5015; | ||
890 | } else { | ||
891 | if (val & (1 << 3)) | ||
892 | sbits |= IEC958_AES0_CON_EMPHASIS_5015; | ||
893 | if (! (val & (1 << 4))) | ||
894 | sbits |= IEC958_AES0_CON_NOT_COPYRIGHT; | ||
895 | if (val & (1 << 7)) | ||
896 | sbits |= (IEC958_AES1_CON_ORIGINAL << 8); | ||
897 | sbits |= val & (0x7f << 8); | ||
898 | } | ||
899 | return sbits; | ||
900 | } | ||
901 | |||
902 | static int snd_hda_spdif_default_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
903 | { | ||
904 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
905 | hda_nid_t nid = kcontrol->private_value; | ||
906 | unsigned short val; | ||
907 | int change; | ||
908 | |||
909 | down(&codec->spdif_mutex); | ||
910 | codec->spdif_status = ucontrol->value.iec958.status[0] | | ||
911 | ((unsigned int)ucontrol->value.iec958.status[1] << 8) | | ||
912 | ((unsigned int)ucontrol->value.iec958.status[2] << 16) | | ||
913 | ((unsigned int)ucontrol->value.iec958.status[3] << 24); | ||
914 | val = convert_from_spdif_status(codec->spdif_status); | ||
915 | val |= codec->spdif_ctls & 1; | ||
916 | change = codec->spdif_ctls != val; | ||
917 | codec->spdif_ctls = val; | ||
918 | |||
919 | if (change || codec->in_resume) { | ||
920 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, val & 0xff); | ||
921 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_2, val >> 8); | ||
922 | } | ||
923 | |||
924 | up(&codec->spdif_mutex); | ||
925 | return change; | ||
926 | } | ||
927 | |||
928 | static int snd_hda_spdif_out_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
929 | { | ||
930 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
931 | uinfo->count = 1; | ||
932 | uinfo->value.integer.min = 0; | ||
933 | uinfo->value.integer.max = 1; | ||
934 | return 0; | ||
935 | } | ||
936 | |||
937 | static int snd_hda_spdif_out_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
938 | { | ||
939 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
940 | |||
941 | ucontrol->value.integer.value[0] = codec->spdif_ctls & 1; | ||
942 | return 0; | ||
943 | } | ||
944 | |||
945 | static int snd_hda_spdif_out_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
946 | { | ||
947 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
948 | hda_nid_t nid = kcontrol->private_value; | ||
949 | unsigned short val; | ||
950 | int change; | ||
951 | |||
952 | down(&codec->spdif_mutex); | ||
953 | val = codec->spdif_ctls & ~1; | ||
954 | if (ucontrol->value.integer.value[0]) | ||
955 | val |= 1; | ||
956 | change = codec->spdif_ctls != val; | ||
957 | if (change || codec->in_resume) { | ||
958 | codec->spdif_ctls = val; | ||
959 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, val & 0xff); | ||
960 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
961 | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | | ||
962 | AC_AMP_SET_OUTPUT | ((val & 1) ? 0 : 0x80)); | ||
963 | } | ||
964 | up(&codec->spdif_mutex); | ||
965 | return change; | ||
966 | } | ||
967 | |||
968 | static snd_kcontrol_new_t dig_mixes[] = { | ||
969 | { | ||
970 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
971 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
972 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), | ||
973 | .info = snd_hda_spdif_mask_info, | ||
974 | .get = snd_hda_spdif_cmask_get, | ||
975 | }, | ||
976 | { | ||
977 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
978 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
979 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK), | ||
980 | .info = snd_hda_spdif_mask_info, | ||
981 | .get = snd_hda_spdif_pmask_get, | ||
982 | }, | ||
983 | { | ||
984 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
985 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), | ||
986 | .info = snd_hda_spdif_mask_info, | ||
987 | .get = snd_hda_spdif_default_get, | ||
988 | .put = snd_hda_spdif_default_put, | ||
989 | }, | ||
990 | { | ||
991 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
992 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), | ||
993 | .info = snd_hda_spdif_out_switch_info, | ||
994 | .get = snd_hda_spdif_out_switch_get, | ||
995 | .put = snd_hda_spdif_out_switch_put, | ||
996 | }, | ||
997 | { } /* end */ | ||
998 | }; | ||
999 | |||
1000 | /** | ||
1001 | * snd_hda_create_spdif_out_ctls - create Output SPDIF-related controls | ||
1002 | * @codec: the HDA codec | ||
1003 | * @nid: audio out widget NID | ||
1004 | * | ||
1005 | * Creates controls related with the SPDIF output. | ||
1006 | * Called from each patch supporting the SPDIF out. | ||
1007 | * | ||
1008 | * Returns 0 if successful, or a negative error code. | ||
1009 | */ | ||
1010 | int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) | ||
1011 | { | ||
1012 | int err; | ||
1013 | snd_kcontrol_t *kctl; | ||
1014 | snd_kcontrol_new_t *dig_mix; | ||
1015 | |||
1016 | for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) { | ||
1017 | kctl = snd_ctl_new1(dig_mix, codec); | ||
1018 | kctl->private_value = nid; | ||
1019 | if ((err = snd_ctl_add(codec->bus->card, kctl)) < 0) | ||
1020 | return err; | ||
1021 | } | ||
1022 | codec->spdif_ctls = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0); | ||
1023 | codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls); | ||
1024 | return 0; | ||
1025 | } | ||
1026 | |||
1027 | /* | ||
1028 | * SPDIF input | ||
1029 | */ | ||
1030 | |||
1031 | #define snd_hda_spdif_in_switch_info snd_hda_spdif_out_switch_info | ||
1032 | |||
1033 | static int snd_hda_spdif_in_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
1034 | { | ||
1035 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1036 | |||
1037 | ucontrol->value.integer.value[0] = codec->spdif_in_enable; | ||
1038 | return 0; | ||
1039 | } | ||
1040 | |||
1041 | static int snd_hda_spdif_in_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
1042 | { | ||
1043 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1044 | hda_nid_t nid = kcontrol->private_value; | ||
1045 | unsigned int val = !!ucontrol->value.integer.value[0]; | ||
1046 | int change; | ||
1047 | |||
1048 | down(&codec->spdif_mutex); | ||
1049 | change = codec->spdif_in_enable != val; | ||
1050 | if (change || codec->in_resume) { | ||
1051 | codec->spdif_in_enable = val; | ||
1052 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, val); | ||
1053 | } | ||
1054 | up(&codec->spdif_mutex); | ||
1055 | return change; | ||
1056 | } | ||
1057 | |||
1058 | static int snd_hda_spdif_in_status_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
1059 | { | ||
1060 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1061 | hda_nid_t nid = kcontrol->private_value; | ||
1062 | unsigned short val; | ||
1063 | unsigned int sbits; | ||
1064 | |||
1065 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0); | ||
1066 | sbits = convert_to_spdif_status(val); | ||
1067 | ucontrol->value.iec958.status[0] = sbits; | ||
1068 | ucontrol->value.iec958.status[1] = sbits >> 8; | ||
1069 | ucontrol->value.iec958.status[2] = sbits >> 16; | ||
1070 | ucontrol->value.iec958.status[3] = sbits >> 24; | ||
1071 | return 0; | ||
1072 | } | ||
1073 | |||
1074 | static snd_kcontrol_new_t dig_in_ctls[] = { | ||
1075 | { | ||
1076 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1077 | .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), | ||
1078 | .info = snd_hda_spdif_in_switch_info, | ||
1079 | .get = snd_hda_spdif_in_switch_get, | ||
1080 | .put = snd_hda_spdif_in_switch_put, | ||
1081 | }, | ||
1082 | { | ||
1083 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
1084 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1085 | .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT), | ||
1086 | .info = snd_hda_spdif_mask_info, | ||
1087 | .get = snd_hda_spdif_in_status_get, | ||
1088 | }, | ||
1089 | { } /* end */ | ||
1090 | }; | ||
1091 | |||
1092 | /** | ||
1093 | * snd_hda_create_spdif_in_ctls - create Input SPDIF-related controls | ||
1094 | * @codec: the HDA codec | ||
1095 | * @nid: audio in widget NID | ||
1096 | * | ||
1097 | * Creates controls related with the SPDIF input. | ||
1098 | * Called from each patch supporting the SPDIF in. | ||
1099 | * | ||
1100 | * Returns 0 if successful, or a negative error code. | ||
1101 | */ | ||
1102 | int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) | ||
1103 | { | ||
1104 | int err; | ||
1105 | snd_kcontrol_t *kctl; | ||
1106 | snd_kcontrol_new_t *dig_mix; | ||
1107 | |||
1108 | for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) { | ||
1109 | kctl = snd_ctl_new1(dig_mix, codec); | ||
1110 | kctl->private_value = nid; | ||
1111 | if ((err = snd_ctl_add(codec->bus->card, kctl)) < 0) | ||
1112 | return err; | ||
1113 | } | ||
1114 | codec->spdif_in_enable = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0) & 1; | ||
1115 | return 0; | ||
1116 | } | ||
1117 | |||
1118 | |||
1119 | /** | ||
1120 | * snd_hda_build_controls - build mixer controls | ||
1121 | * @bus: the BUS | ||
1122 | * | ||
1123 | * Creates mixer controls for each codec included in the bus. | ||
1124 | * | ||
1125 | * Returns 0 if successful, otherwise a negative error code. | ||
1126 | */ | ||
1127 | int snd_hda_build_controls(struct hda_bus *bus) | ||
1128 | { | ||
1129 | struct list_head *p; | ||
1130 | |||
1131 | /* build controls */ | ||
1132 | list_for_each(p, &bus->codec_list) { | ||
1133 | struct hda_codec *codec = list_entry(p, struct hda_codec, list); | ||
1134 | int err; | ||
1135 | if (! codec->patch_ops.build_controls) | ||
1136 | continue; | ||
1137 | err = codec->patch_ops.build_controls(codec); | ||
1138 | if (err < 0) | ||
1139 | return err; | ||
1140 | } | ||
1141 | |||
1142 | /* initialize */ | ||
1143 | list_for_each(p, &bus->codec_list) { | ||
1144 | struct hda_codec *codec = list_entry(p, struct hda_codec, list); | ||
1145 | int err; | ||
1146 | if (! codec->patch_ops.init) | ||
1147 | continue; | ||
1148 | err = codec->patch_ops.init(codec); | ||
1149 | if (err < 0) | ||
1150 | return err; | ||
1151 | } | ||
1152 | return 0; | ||
1153 | } | ||
1154 | |||
1155 | |||
1156 | /* | ||
1157 | * stream formats | ||
1158 | */ | ||
1159 | static unsigned int rate_bits[][3] = { | ||
1160 | /* rate in Hz, ALSA rate bitmask, HDA format value */ | ||
1161 | { 8000, SNDRV_PCM_RATE_8000, 0x0500 }, /* 1/6 x 48 */ | ||
1162 | { 11025, SNDRV_PCM_RATE_11025, 0x4300 }, /* 1/4 x 44 */ | ||
1163 | { 16000, SNDRV_PCM_RATE_16000, 0x0200 }, /* 1/3 x 48 */ | ||
1164 | { 22050, SNDRV_PCM_RATE_22050, 0x4100 }, /* 1/2 x 44 */ | ||
1165 | { 32000, SNDRV_PCM_RATE_32000, 0x0a00 }, /* 2/3 x 48 */ | ||
1166 | { 44100, SNDRV_PCM_RATE_44100, 0x4000 }, /* 44 */ | ||
1167 | { 48000, SNDRV_PCM_RATE_48000, 0x0000 }, /* 48 */ | ||
1168 | { 88200, SNDRV_PCM_RATE_88200, 0x4800 }, /* 2 x 44 */ | ||
1169 | { 96000, SNDRV_PCM_RATE_96000, 0x0800 }, /* 2 x 48 */ | ||
1170 | { 176400, SNDRV_PCM_RATE_176400, 0x5800 },/* 4 x 44 */ | ||
1171 | { 192000, SNDRV_PCM_RATE_192000, 0x1800 }, /* 4 x 48 */ | ||
1172 | { 0 } | ||
1173 | }; | ||
1174 | |||
1175 | /** | ||
1176 | * snd_hda_calc_stream_format - calculate format bitset | ||
1177 | * @rate: the sample rate | ||
1178 | * @channels: the number of channels | ||
1179 | * @format: the PCM format (SNDRV_PCM_FORMAT_XXX) | ||
1180 | * @maxbps: the max. bps | ||
1181 | * | ||
1182 | * Calculate the format bitset from the given rate, channels and th PCM format. | ||
1183 | * | ||
1184 | * Return zero if invalid. | ||
1185 | */ | ||
1186 | unsigned int snd_hda_calc_stream_format(unsigned int rate, | ||
1187 | unsigned int channels, | ||
1188 | unsigned int format, | ||
1189 | unsigned int maxbps) | ||
1190 | { | ||
1191 | int i; | ||
1192 | unsigned int val = 0; | ||
1193 | |||
1194 | for (i = 0; rate_bits[i][0]; i++) | ||
1195 | if (rate_bits[i][0] == rate) { | ||
1196 | val = rate_bits[i][2]; | ||
1197 | break; | ||
1198 | } | ||
1199 | if (! rate_bits[i][0]) { | ||
1200 | snd_printdd("invalid rate %d\n", rate); | ||
1201 | return 0; | ||
1202 | } | ||
1203 | |||
1204 | if (channels == 0 || channels > 8) { | ||
1205 | snd_printdd("invalid channels %d\n", channels); | ||
1206 | return 0; | ||
1207 | } | ||
1208 | val |= channels - 1; | ||
1209 | |||
1210 | switch (snd_pcm_format_width(format)) { | ||
1211 | case 8: val |= 0x00; break; | ||
1212 | case 16: val |= 0x10; break; | ||
1213 | case 20: | ||
1214 | case 24: | ||
1215 | case 32: | ||
1216 | if (maxbps >= 32) | ||
1217 | val |= 0x40; | ||
1218 | else if (maxbps >= 24) | ||
1219 | val |= 0x30; | ||
1220 | else | ||
1221 | val |= 0x20; | ||
1222 | break; | ||
1223 | default: | ||
1224 | snd_printdd("invalid format width %d\n", snd_pcm_format_width(format)); | ||
1225 | return 0; | ||
1226 | } | ||
1227 | |||
1228 | return val; | ||
1229 | } | ||
1230 | |||
1231 | /** | ||
1232 | * snd_hda_query_supported_pcm - query the supported PCM rates and formats | ||
1233 | * @codec: the HDA codec | ||
1234 | * @nid: NID to query | ||
1235 | * @ratesp: the pointer to store the detected rate bitflags | ||
1236 | * @formatsp: the pointer to store the detected formats | ||
1237 | * @bpsp: the pointer to store the detected format widths | ||
1238 | * | ||
1239 | * Queries the supported PCM rates and formats. The NULL @ratesp, @formatsp | ||
1240 | * or @bsps argument is ignored. | ||
1241 | * | ||
1242 | * Returns 0 if successful, otherwise a negative error code. | ||
1243 | */ | ||
1244 | int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, | ||
1245 | u32 *ratesp, u64 *formatsp, unsigned int *bpsp) | ||
1246 | { | ||
1247 | int i; | ||
1248 | unsigned int val, streams; | ||
1249 | |||
1250 | val = 0; | ||
1251 | if (nid != codec->afg && | ||
1252 | snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP) & AC_WCAP_FORMAT_OVRD) { | ||
1253 | val = snd_hda_param_read(codec, nid, AC_PAR_PCM); | ||
1254 | if (val == -1) | ||
1255 | return -EIO; | ||
1256 | } | ||
1257 | if (! val) | ||
1258 | val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); | ||
1259 | |||
1260 | if (ratesp) { | ||
1261 | u32 rates = 0; | ||
1262 | for (i = 0; rate_bits[i][0]; i++) { | ||
1263 | if (val & (1 << i)) | ||
1264 | rates |= rate_bits[i][1]; | ||
1265 | } | ||
1266 | *ratesp = rates; | ||
1267 | } | ||
1268 | |||
1269 | if (formatsp || bpsp) { | ||
1270 | u64 formats = 0; | ||
1271 | unsigned int bps; | ||
1272 | unsigned int wcaps; | ||
1273 | |||
1274 | wcaps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); | ||
1275 | streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); | ||
1276 | if (streams == -1) | ||
1277 | return -EIO; | ||
1278 | if (! streams) { | ||
1279 | streams = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); | ||
1280 | if (streams == -1) | ||
1281 | return -EIO; | ||
1282 | } | ||
1283 | |||
1284 | bps = 0; | ||
1285 | if (streams & AC_SUPFMT_PCM) { | ||
1286 | if (val & AC_SUPPCM_BITS_8) { | ||
1287 | formats |= SNDRV_PCM_FMTBIT_U8; | ||
1288 | bps = 8; | ||
1289 | } | ||
1290 | if (val & AC_SUPPCM_BITS_16) { | ||
1291 | formats |= SNDRV_PCM_FMTBIT_S16_LE; | ||
1292 | bps = 16; | ||
1293 | } | ||
1294 | if (wcaps & AC_WCAP_DIGITAL) { | ||
1295 | if (val & AC_SUPPCM_BITS_32) | ||
1296 | formats |= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; | ||
1297 | if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24)) | ||
1298 | formats |= SNDRV_PCM_FMTBIT_S32_LE; | ||
1299 | if (val & AC_SUPPCM_BITS_24) | ||
1300 | bps = 24; | ||
1301 | else if (val & AC_SUPPCM_BITS_20) | ||
1302 | bps = 20; | ||
1303 | } else if (val & (AC_SUPPCM_BITS_20|AC_SUPPCM_BITS_24|AC_SUPPCM_BITS_32)) { | ||
1304 | formats |= SNDRV_PCM_FMTBIT_S32_LE; | ||
1305 | if (val & AC_SUPPCM_BITS_32) | ||
1306 | bps = 32; | ||
1307 | else if (val & AC_SUPPCM_BITS_20) | ||
1308 | bps = 20; | ||
1309 | else if (val & AC_SUPPCM_BITS_24) | ||
1310 | bps = 24; | ||
1311 | } | ||
1312 | } | ||
1313 | else if (streams == AC_SUPFMT_FLOAT32) { /* should be exclusive */ | ||
1314 | formats |= SNDRV_PCM_FMTBIT_FLOAT_LE; | ||
1315 | bps = 32; | ||
1316 | } else if (streams == AC_SUPFMT_AC3) { /* should be exclusive */ | ||
1317 | /* temporary hack: we have still no proper support | ||
1318 | * for the direct AC3 stream... | ||
1319 | */ | ||
1320 | formats |= SNDRV_PCM_FMTBIT_U8; | ||
1321 | bps = 8; | ||
1322 | } | ||
1323 | if (formatsp) | ||
1324 | *formatsp = formats; | ||
1325 | if (bpsp) | ||
1326 | *bpsp = bps; | ||
1327 | } | ||
1328 | |||
1329 | return 0; | ||
1330 | } | ||
1331 | |||
1332 | /** | ||
1333 | * snd_hda_is_supported_format - check whether the given node supports the format val | ||
1334 | * | ||
1335 | * Returns 1 if supported, 0 if not. | ||
1336 | */ | ||
1337 | int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, | ||
1338 | unsigned int format) | ||
1339 | { | ||
1340 | int i; | ||
1341 | unsigned int val = 0, rate, stream; | ||
1342 | |||
1343 | if (nid != codec->afg && | ||
1344 | snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP) & AC_WCAP_FORMAT_OVRD) { | ||
1345 | val = snd_hda_param_read(codec, nid, AC_PAR_PCM); | ||
1346 | if (val == -1) | ||
1347 | return 0; | ||
1348 | } | ||
1349 | if (! val) { | ||
1350 | val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); | ||
1351 | if (val == -1) | ||
1352 | return 0; | ||
1353 | } | ||
1354 | |||
1355 | rate = format & 0xff00; | ||
1356 | for (i = 0; rate_bits[i][0]; i++) | ||
1357 | if (rate_bits[i][2] == rate) { | ||
1358 | if (val & (1 << i)) | ||
1359 | break; | ||
1360 | return 0; | ||
1361 | } | ||
1362 | if (! rate_bits[i][0]) | ||
1363 | return 0; | ||
1364 | |||
1365 | stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM); | ||
1366 | if (stream == -1) | ||
1367 | return 0; | ||
1368 | if (! stream && nid != codec->afg) | ||
1369 | stream = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); | ||
1370 | if (! stream || stream == -1) | ||
1371 | return 0; | ||
1372 | |||
1373 | if (stream & AC_SUPFMT_PCM) { | ||
1374 | switch (format & 0xf0) { | ||
1375 | case 0x00: | ||
1376 | if (! (val & AC_SUPPCM_BITS_8)) | ||
1377 | return 0; | ||
1378 | break; | ||
1379 | case 0x10: | ||
1380 | if (! (val & AC_SUPPCM_BITS_16)) | ||
1381 | return 0; | ||
1382 | break; | ||
1383 | case 0x20: | ||
1384 | if (! (val & AC_SUPPCM_BITS_20)) | ||
1385 | return 0; | ||
1386 | break; | ||
1387 | case 0x30: | ||
1388 | if (! (val & AC_SUPPCM_BITS_24)) | ||
1389 | return 0; | ||
1390 | break; | ||
1391 | case 0x40: | ||
1392 | if (! (val & AC_SUPPCM_BITS_32)) | ||
1393 | return 0; | ||
1394 | break; | ||
1395 | default: | ||
1396 | return 0; | ||
1397 | } | ||
1398 | } else { | ||
1399 | /* FIXME: check for float32 and AC3? */ | ||
1400 | } | ||
1401 | |||
1402 | return 1; | ||
1403 | } | ||
1404 | |||
1405 | /* | ||
1406 | * PCM stuff | ||
1407 | */ | ||
1408 | static int hda_pcm_default_open_close(struct hda_pcm_stream *hinfo, | ||
1409 | struct hda_codec *codec, | ||
1410 | snd_pcm_substream_t *substream) | ||
1411 | { | ||
1412 | return 0; | ||
1413 | } | ||
1414 | |||
1415 | static int hda_pcm_default_prepare(struct hda_pcm_stream *hinfo, | ||
1416 | struct hda_codec *codec, | ||
1417 | unsigned int stream_tag, | ||
1418 | unsigned int format, | ||
1419 | snd_pcm_substream_t *substream) | ||
1420 | { | ||
1421 | snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); | ||
1422 | return 0; | ||
1423 | } | ||
1424 | |||
1425 | static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo, | ||
1426 | struct hda_codec *codec, | ||
1427 | snd_pcm_substream_t *substream) | ||
1428 | { | ||
1429 | snd_hda_codec_setup_stream(codec, hinfo->nid, 0, 0, 0); | ||
1430 | return 0; | ||
1431 | } | ||
1432 | |||
1433 | static int set_pcm_default_values(struct hda_codec *codec, struct hda_pcm_stream *info) | ||
1434 | { | ||
1435 | if (info->nid) { | ||
1436 | /* query support PCM information from the given NID */ | ||
1437 | if (! info->rates || ! info->formats) | ||
1438 | snd_hda_query_supported_pcm(codec, info->nid, | ||
1439 | info->rates ? NULL : &info->rates, | ||
1440 | info->formats ? NULL : &info->formats, | ||
1441 | info->maxbps ? NULL : &info->maxbps); | ||
1442 | } | ||
1443 | if (info->ops.open == NULL) | ||
1444 | info->ops.open = hda_pcm_default_open_close; | ||
1445 | if (info->ops.close == NULL) | ||
1446 | info->ops.close = hda_pcm_default_open_close; | ||
1447 | if (info->ops.prepare == NULL) { | ||
1448 | snd_assert(info->nid, return -EINVAL); | ||
1449 | info->ops.prepare = hda_pcm_default_prepare; | ||
1450 | } | ||
1451 | if (info->ops.prepare == NULL) { | ||
1452 | snd_assert(info->nid, return -EINVAL); | ||
1453 | info->ops.prepare = hda_pcm_default_prepare; | ||
1454 | } | ||
1455 | if (info->ops.cleanup == NULL) { | ||
1456 | snd_assert(info->nid, return -EINVAL); | ||
1457 | info->ops.cleanup = hda_pcm_default_cleanup; | ||
1458 | } | ||
1459 | return 0; | ||
1460 | } | ||
1461 | |||
1462 | /** | ||
1463 | * snd_hda_build_pcms - build PCM information | ||
1464 | * @bus: the BUS | ||
1465 | * | ||
1466 | * Create PCM information for each codec included in the bus. | ||
1467 | * | ||
1468 | * The build_pcms codec patch is requested to set up codec->num_pcms and | ||
1469 | * codec->pcm_info properly. The array is referred by the top-level driver | ||
1470 | * to create its PCM instances. | ||
1471 | * The allocated codec->pcm_info should be released in codec->patch_ops.free | ||
1472 | * callback. | ||
1473 | * | ||
1474 | * At least, substreams, channels_min and channels_max must be filled for | ||
1475 | * each stream. substreams = 0 indicates that the stream doesn't exist. | ||
1476 | * When rates and/or formats are zero, the supported values are queried | ||
1477 | * from the given nid. The nid is used also by the default ops.prepare | ||
1478 | * and ops.cleanup callbacks. | ||
1479 | * | ||
1480 | * The driver needs to call ops.open in its open callback. Similarly, | ||
1481 | * ops.close is supposed to be called in the close callback. | ||
1482 | * ops.prepare should be called in the prepare or hw_params callback | ||
1483 | * with the proper parameters for set up. | ||
1484 | * ops.cleanup should be called in hw_free for clean up of streams. | ||
1485 | * | ||
1486 | * This function returns 0 if successfull, or a negative error code. | ||
1487 | */ | ||
1488 | int snd_hda_build_pcms(struct hda_bus *bus) | ||
1489 | { | ||
1490 | struct list_head *p; | ||
1491 | |||
1492 | list_for_each(p, &bus->codec_list) { | ||
1493 | struct hda_codec *codec = list_entry(p, struct hda_codec, list); | ||
1494 | unsigned int pcm, s; | ||
1495 | int err; | ||
1496 | if (! codec->patch_ops.build_pcms) | ||
1497 | continue; | ||
1498 | err = codec->patch_ops.build_pcms(codec); | ||
1499 | if (err < 0) | ||
1500 | return err; | ||
1501 | for (pcm = 0; pcm < codec->num_pcms; pcm++) { | ||
1502 | for (s = 0; s < 2; s++) { | ||
1503 | struct hda_pcm_stream *info; | ||
1504 | info = &codec->pcm_info[pcm].stream[s]; | ||
1505 | if (! info->substreams) | ||
1506 | continue; | ||
1507 | err = set_pcm_default_values(codec, info); | ||
1508 | if (err < 0) | ||
1509 | return err; | ||
1510 | } | ||
1511 | } | ||
1512 | } | ||
1513 | return 0; | ||
1514 | } | ||
1515 | |||
1516 | |||
1517 | /** | ||
1518 | * snd_hda_check_board_config - compare the current codec with the config table | ||
1519 | * @codec: the HDA codec | ||
1520 | * @tbl: configuration table, terminated by null entries | ||
1521 | * | ||
1522 | * Compares the modelname or PCI subsystem id of the current codec with the | ||
1523 | * given configuration table. If a matching entry is found, returns its | ||
1524 | * config value (supposed to be 0 or positive). | ||
1525 | * | ||
1526 | * If no entries are matching, the function returns a negative value. | ||
1527 | */ | ||
1528 | int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config *tbl) | ||
1529 | { | ||
1530 | struct hda_board_config *c; | ||
1531 | |||
1532 | if (codec->bus->modelname) { | ||
1533 | for (c = tbl; c->modelname || c->pci_vendor; c++) { | ||
1534 | if (c->modelname && | ||
1535 | ! strcmp(codec->bus->modelname, c->modelname)) { | ||
1536 | snd_printd(KERN_INFO "hda_codec: model '%s' is selected\n", c->modelname); | ||
1537 | return c->config; | ||
1538 | } | ||
1539 | } | ||
1540 | } | ||
1541 | |||
1542 | if (codec->bus->pci) { | ||
1543 | u16 subsystem_vendor, subsystem_device; | ||
1544 | pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); | ||
1545 | pci_read_config_word(codec->bus->pci, PCI_SUBSYSTEM_ID, &subsystem_device); | ||
1546 | for (c = tbl; c->modelname || c->pci_vendor; c++) { | ||
1547 | if (c->pci_vendor == subsystem_vendor && | ||
1548 | c->pci_device == subsystem_device) | ||
1549 | return c->config; | ||
1550 | } | ||
1551 | } | ||
1552 | return -1; | ||
1553 | } | ||
1554 | |||
1555 | /** | ||
1556 | * snd_hda_add_new_ctls - create controls from the array | ||
1557 | * @codec: the HDA codec | ||
1558 | * @knew: the array of snd_kcontrol_new_t | ||
1559 | * | ||
1560 | * This helper function creates and add new controls in the given array. | ||
1561 | * The array must be terminated with an empty entry as terminator. | ||
1562 | * | ||
1563 | * Returns 0 if successful, or a negative error code. | ||
1564 | */ | ||
1565 | int snd_hda_add_new_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew) | ||
1566 | { | ||
1567 | int err; | ||
1568 | |||
1569 | for (; knew->name; knew++) { | ||
1570 | err = snd_ctl_add(codec->bus->card, snd_ctl_new1(knew, codec)); | ||
1571 | if (err < 0) | ||
1572 | return err; | ||
1573 | } | ||
1574 | return 0; | ||
1575 | } | ||
1576 | |||
1577 | |||
1578 | /* | ||
1579 | * input MUX helper | ||
1580 | */ | ||
1581 | int snd_hda_input_mux_info(const struct hda_input_mux *imux, snd_ctl_elem_info_t *uinfo) | ||
1582 | { | ||
1583 | unsigned int index; | ||
1584 | |||
1585 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
1586 | uinfo->count = 1; | ||
1587 | uinfo->value.enumerated.items = imux->num_items; | ||
1588 | index = uinfo->value.enumerated.item; | ||
1589 | if (index >= imux->num_items) | ||
1590 | index = imux->num_items - 1; | ||
1591 | strcpy(uinfo->value.enumerated.name, imux->items[index].label); | ||
1592 | return 0; | ||
1593 | } | ||
1594 | |||
1595 | int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, | ||
1596 | snd_ctl_elem_value_t *ucontrol, hda_nid_t nid, | ||
1597 | unsigned int *cur_val) | ||
1598 | { | ||
1599 | unsigned int idx; | ||
1600 | |||
1601 | idx = ucontrol->value.enumerated.item[0]; | ||
1602 | if (idx >= imux->num_items) | ||
1603 | idx = imux->num_items - 1; | ||
1604 | if (*cur_val == idx && ! codec->in_resume) | ||
1605 | return 0; | ||
1606 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, | ||
1607 | imux->items[idx].index); | ||
1608 | *cur_val = idx; | ||
1609 | return 1; | ||
1610 | } | ||
1611 | |||
1612 | |||
1613 | /* | ||
1614 | * Multi-channel / digital-out PCM helper functions | ||
1615 | */ | ||
1616 | |||
1617 | /* | ||
1618 | * open the digital out in the exclusive mode | ||
1619 | */ | ||
1620 | int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout) | ||
1621 | { | ||
1622 | down(&codec->spdif_mutex); | ||
1623 | if (mout->dig_out_used) { | ||
1624 | up(&codec->spdif_mutex); | ||
1625 | return -EBUSY; /* already being used */ | ||
1626 | } | ||
1627 | mout->dig_out_used = HDA_DIG_EXCLUSIVE; | ||
1628 | up(&codec->spdif_mutex); | ||
1629 | return 0; | ||
1630 | } | ||
1631 | |||
1632 | /* | ||
1633 | * release the digital out | ||
1634 | */ | ||
1635 | int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout) | ||
1636 | { | ||
1637 | down(&codec->spdif_mutex); | ||
1638 | mout->dig_out_used = 0; | ||
1639 | up(&codec->spdif_mutex); | ||
1640 | return 0; | ||
1641 | } | ||
1642 | |||
1643 | /* | ||
1644 | * set up more restrictions for analog out | ||
1645 | */ | ||
1646 | int snd_hda_multi_out_analog_open(struct hda_codec *codec, struct hda_multi_out *mout, | ||
1647 | snd_pcm_substream_t *substream) | ||
1648 | { | ||
1649 | substream->runtime->hw.channels_max = mout->max_channels; | ||
1650 | return snd_pcm_hw_constraint_step(substream->runtime, 0, | ||
1651 | SNDRV_PCM_HW_PARAM_CHANNELS, 2); | ||
1652 | } | ||
1653 | |||
1654 | /* | ||
1655 | * set up the i/o for analog out | ||
1656 | * when the digital out is available, copy the front out to digital out, too. | ||
1657 | */ | ||
1658 | int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout, | ||
1659 | unsigned int stream_tag, | ||
1660 | unsigned int format, | ||
1661 | snd_pcm_substream_t *substream) | ||
1662 | { | ||
1663 | hda_nid_t *nids = mout->dac_nids; | ||
1664 | int chs = substream->runtime->channels; | ||
1665 | int i; | ||
1666 | |||
1667 | down(&codec->spdif_mutex); | ||
1668 | if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) { | ||
1669 | if (chs == 2 && | ||
1670 | snd_hda_is_supported_format(codec, mout->dig_out_nid, format) && | ||
1671 | ! (codec->spdif_status & IEC958_AES0_NONAUDIO)) { | ||
1672 | mout->dig_out_used = HDA_DIG_ANALOG_DUP; | ||
1673 | /* setup digital receiver */ | ||
1674 | snd_hda_codec_setup_stream(codec, mout->dig_out_nid, | ||
1675 | stream_tag, 0, format); | ||
1676 | } else { | ||
1677 | mout->dig_out_used = 0; | ||
1678 | snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0); | ||
1679 | } | ||
1680 | } | ||
1681 | up(&codec->spdif_mutex); | ||
1682 | |||
1683 | /* front */ | ||
1684 | snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 0, format); | ||
1685 | if (mout->hp_nid) | ||
1686 | /* headphone out will just decode front left/right (stereo) */ | ||
1687 | snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format); | ||
1688 | /* surrounds */ | ||
1689 | for (i = 1; i < mout->num_dacs; i++) { | ||
1690 | if (i == HDA_REAR && chs == 2) /* copy front to rear */ | ||
1691 | snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 0, format); | ||
1692 | else if (chs >= (i + 1) * 2) /* independent out */ | ||
1693 | snd_hda_codec_setup_stream(codec, nids[i], stream_tag, i * 2, | ||
1694 | format); | ||
1695 | } | ||
1696 | return 0; | ||
1697 | } | ||
1698 | |||
1699 | /* | ||
1700 | * clean up the setting for analog out | ||
1701 | */ | ||
1702 | int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_out *mout) | ||
1703 | { | ||
1704 | hda_nid_t *nids = mout->dac_nids; | ||
1705 | int i; | ||
1706 | |||
1707 | for (i = 0; i < mout->num_dacs; i++) | ||
1708 | snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0); | ||
1709 | if (mout->hp_nid) | ||
1710 | snd_hda_codec_setup_stream(codec, mout->hp_nid, 0, 0, 0); | ||
1711 | down(&codec->spdif_mutex); | ||
1712 | if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) { | ||
1713 | snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0); | ||
1714 | mout->dig_out_used = 0; | ||
1715 | } | ||
1716 | up(&codec->spdif_mutex); | ||
1717 | return 0; | ||
1718 | } | ||
1719 | |||
1720 | #ifdef CONFIG_PM | ||
1721 | /* | ||
1722 | * power management | ||
1723 | */ | ||
1724 | |||
1725 | /** | ||
1726 | * snd_hda_suspend - suspend the codecs | ||
1727 | * @bus: the HDA bus | ||
1728 | * @state: suspsend state | ||
1729 | * | ||
1730 | * Returns 0 if successful. | ||
1731 | */ | ||
1732 | int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) | ||
1733 | { | ||
1734 | struct list_head *p; | ||
1735 | |||
1736 | /* FIXME: should handle power widget capabilities */ | ||
1737 | list_for_each(p, &bus->codec_list) { | ||
1738 | struct hda_codec *codec = list_entry(p, struct hda_codec, list); | ||
1739 | if (codec->patch_ops.suspend) | ||
1740 | codec->patch_ops.suspend(codec, state); | ||
1741 | } | ||
1742 | return 0; | ||
1743 | } | ||
1744 | |||
1745 | /** | ||
1746 | * snd_hda_resume - resume the codecs | ||
1747 | * @bus: the HDA bus | ||
1748 | * @state: resume state | ||
1749 | * | ||
1750 | * Returns 0 if successful. | ||
1751 | */ | ||
1752 | int snd_hda_resume(struct hda_bus *bus) | ||
1753 | { | ||
1754 | struct list_head *p; | ||
1755 | |||
1756 | list_for_each(p, &bus->codec_list) { | ||
1757 | struct hda_codec *codec = list_entry(p, struct hda_codec, list); | ||
1758 | if (codec->patch_ops.resume) | ||
1759 | codec->patch_ops.resume(codec); | ||
1760 | } | ||
1761 | return 0; | ||
1762 | } | ||
1763 | |||
1764 | /** | ||
1765 | * snd_hda_resume_ctls - resume controls in the new control list | ||
1766 | * @codec: the HDA codec | ||
1767 | * @knew: the array of snd_kcontrol_new_t | ||
1768 | * | ||
1769 | * This function resumes the mixer controls in the snd_kcontrol_new_t array, | ||
1770 | * originally for snd_hda_add_new_ctls(). | ||
1771 | * The array must be terminated with an empty entry as terminator. | ||
1772 | */ | ||
1773 | int snd_hda_resume_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew) | ||
1774 | { | ||
1775 | snd_ctl_elem_value_t *val; | ||
1776 | |||
1777 | val = kmalloc(sizeof(*val), GFP_KERNEL); | ||
1778 | if (! val) | ||
1779 | return -ENOMEM; | ||
1780 | codec->in_resume = 1; | ||
1781 | for (; knew->name; knew++) { | ||
1782 | int i, count; | ||
1783 | count = knew->count ? knew->count : 1; | ||
1784 | for (i = 0; i < count; i++) { | ||
1785 | memset(val, 0, sizeof(*val)); | ||
1786 | val->id.iface = knew->iface; | ||
1787 | val->id.device = knew->device; | ||
1788 | val->id.subdevice = knew->subdevice; | ||
1789 | strcpy(val->id.name, knew->name); | ||
1790 | val->id.index = knew->index ? knew->index : i; | ||
1791 | /* Assume that get callback reads only from cache, | ||
1792 | * not accessing to the real hardware | ||
1793 | */ | ||
1794 | if (snd_ctl_elem_read(codec->bus->card, val) < 0) | ||
1795 | continue; | ||
1796 | snd_ctl_elem_write(codec->bus->card, NULL, val); | ||
1797 | } | ||
1798 | } | ||
1799 | codec->in_resume = 0; | ||
1800 | kfree(val); | ||
1801 | return 0; | ||
1802 | } | ||
1803 | |||
1804 | /** | ||
1805 | * snd_hda_resume_spdif_out - resume the digital out | ||
1806 | * @codec: the HDA codec | ||
1807 | */ | ||
1808 | int snd_hda_resume_spdif_out(struct hda_codec *codec) | ||
1809 | { | ||
1810 | return snd_hda_resume_ctls(codec, dig_mixes); | ||
1811 | } | ||
1812 | |||
1813 | /** | ||
1814 | * snd_hda_resume_spdif_in - resume the digital in | ||
1815 | * @codec: the HDA codec | ||
1816 | */ | ||
1817 | int snd_hda_resume_spdif_in(struct hda_codec *codec) | ||
1818 | { | ||
1819 | return snd_hda_resume_ctls(codec, dig_in_ctls); | ||
1820 | } | ||
1821 | #endif | ||
1822 | |||
1823 | /* | ||
1824 | * symbols exported for controller modules | ||
1825 | */ | ||
1826 | EXPORT_SYMBOL(snd_hda_codec_read); | ||
1827 | EXPORT_SYMBOL(snd_hda_codec_write); | ||
1828 | EXPORT_SYMBOL(snd_hda_sequence_write); | ||
1829 | EXPORT_SYMBOL(snd_hda_get_sub_nodes); | ||
1830 | EXPORT_SYMBOL(snd_hda_queue_unsol_event); | ||
1831 | EXPORT_SYMBOL(snd_hda_bus_new); | ||
1832 | EXPORT_SYMBOL(snd_hda_codec_new); | ||
1833 | EXPORT_SYMBOL(snd_hda_codec_setup_stream); | ||
1834 | EXPORT_SYMBOL(snd_hda_calc_stream_format); | ||
1835 | EXPORT_SYMBOL(snd_hda_build_pcms); | ||
1836 | EXPORT_SYMBOL(snd_hda_build_controls); | ||
1837 | #ifdef CONFIG_PM | ||
1838 | EXPORT_SYMBOL(snd_hda_suspend); | ||
1839 | EXPORT_SYMBOL(snd_hda_resume); | ||
1840 | #endif | ||
1841 | |||
1842 | /* | ||
1843 | * INIT part | ||
1844 | */ | ||
1845 | |||
1846 | static int __init alsa_hda_init(void) | ||
1847 | { | ||
1848 | return 0; | ||
1849 | } | ||
1850 | |||
1851 | static void __exit alsa_hda_exit(void) | ||
1852 | { | ||
1853 | } | ||
1854 | |||
1855 | module_init(alsa_hda_init) | ||
1856 | module_exit(alsa_hda_exit) | ||
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h new file mode 100644 index 000000000000..c9e9dc9c7c98 --- /dev/null +++ b/sound/pci/hda/hda_codec.h | |||
@@ -0,0 +1,604 @@ | |||
1 | /* | ||
2 | * Universal Interface for Intel High Definition Audio Codec | ||
3 | * | ||
4 | * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the Free | ||
8 | * Software Foundation; either version 2 of the License, or (at your option) | ||
9 | * any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program; if not, write to the Free Software Foundation, Inc., 59 | ||
18 | * Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef __SOUND_HDA_CODEC_H | ||
22 | #define __SOUND_HDA_CODEC_H | ||
23 | |||
24 | #include <sound/info.h> | ||
25 | #include <sound/control.h> | ||
26 | #include <sound/pcm.h> | ||
27 | |||
28 | /* | ||
29 | * nodes | ||
30 | */ | ||
31 | #define AC_NODE_ROOT 0x00 | ||
32 | |||
33 | /* | ||
34 | * function group types | ||
35 | */ | ||
36 | enum { | ||
37 | AC_GRP_AUDIO_FUNCTION = 0x01, | ||
38 | AC_GRP_MODEM_FUNCTION = 0x02, | ||
39 | }; | ||
40 | |||
41 | /* | ||
42 | * widget types | ||
43 | */ | ||
44 | enum { | ||
45 | AC_WID_AUD_OUT, /* Audio Out */ | ||
46 | AC_WID_AUD_IN, /* Audio In */ | ||
47 | AC_WID_AUD_MIX, /* Audio Mixer */ | ||
48 | AC_WID_AUD_SEL, /* Audio Selector */ | ||
49 | AC_WID_PIN, /* Pin Complex */ | ||
50 | AC_WID_POWER, /* Power */ | ||
51 | AC_WID_VOL_KNB, /* Volume Knob */ | ||
52 | AC_WID_BEEP, /* Beep Generator */ | ||
53 | AC_WID_VENDOR = 0x0f /* Vendor specific */ | ||
54 | }; | ||
55 | |||
56 | /* | ||
57 | * GET verbs | ||
58 | */ | ||
59 | #define AC_VERB_GET_STREAM_FORMAT 0x0a00 | ||
60 | #define AC_VERB_GET_AMP_GAIN_MUTE 0x0b00 | ||
61 | #define AC_VERB_GET_PROC_COEF 0x0c00 | ||
62 | #define AC_VERB_GET_COEF_INDEX 0x0d00 | ||
63 | #define AC_VERB_PARAMETERS 0x0f00 | ||
64 | #define AC_VERB_GET_CONNECT_SEL 0x0f01 | ||
65 | #define AC_VERB_GET_CONNECT_LIST 0x0f02 | ||
66 | #define AC_VERB_GET_PROC_STATE 0x0f03 | ||
67 | #define AC_VERB_GET_SDI_SELECT 0x0f04 | ||
68 | #define AC_VERB_GET_POWER_STATE 0x0f05 | ||
69 | #define AC_VERB_GET_CONV 0x0f06 | ||
70 | #define AC_VERB_GET_PIN_WIDGET_CONTROL 0x0f07 | ||
71 | #define AC_VERB_GET_UNSOLICITED_RESPONSE 0x0f08 | ||
72 | #define AC_VERB_GET_PIN_SENSE 0x0f09 | ||
73 | #define AC_VERB_GET_BEEP_CONTROL 0x0f0a | ||
74 | #define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c | ||
75 | #define AC_VERB_GET_DIGI_CONVERT 0x0f0d | ||
76 | #define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f | ||
77 | /* f10-f1a: GPIO */ | ||
78 | #define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c | ||
79 | |||
80 | /* | ||
81 | * SET verbs | ||
82 | */ | ||
83 | #define AC_VERB_SET_STREAM_FORMAT 0x200 | ||
84 | #define AC_VERB_SET_AMP_GAIN_MUTE 0x300 | ||
85 | #define AC_VERB_SET_PROC_COEF 0x400 | ||
86 | #define AC_VERB_SET_COEF_INDEX 0x500 | ||
87 | #define AC_VERB_SET_CONNECT_SEL 0x701 | ||
88 | #define AC_VERB_SET_PROC_STATE 0x703 | ||
89 | #define AC_VERB_SET_SDI_SELECT 0x704 | ||
90 | #define AC_VERB_SET_POWER_STATE 0x705 | ||
91 | #define AC_VERB_SET_CHANNEL_STREAMID 0x706 | ||
92 | #define AC_VERB_SET_PIN_WIDGET_CONTROL 0x707 | ||
93 | #define AC_VERB_SET_UNSOLICITED_ENABLE 0x708 | ||
94 | #define AC_VERB_SET_PIN_SENSE 0x709 | ||
95 | #define AC_VERB_SET_BEEP_CONTROL 0x70a | ||
96 | #define AC_VERB_SET_EAPD_BTLENALBE 0x70c | ||
97 | #define AC_VERB_SET_DIGI_CONVERT_1 0x70d | ||
98 | #define AC_VERB_SET_DIGI_CONVERT_2 0x70e | ||
99 | #define AC_VERB_SET_VOLUME_KNOB_CONTROL 0x70f | ||
100 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c | ||
101 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d | ||
102 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e | ||
103 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3 0x71f | ||
104 | #define AC_VERB_SET_CODEC_RESET 0x7ff | ||
105 | |||
106 | /* | ||
107 | * Parameter IDs | ||
108 | */ | ||
109 | #define AC_PAR_VENDOR_ID 0x00 | ||
110 | #define AC_PAR_SUBSYSTEM_ID 0x01 | ||
111 | #define AC_PAR_REV_ID 0x02 | ||
112 | #define AC_PAR_NODE_COUNT 0x04 | ||
113 | #define AC_PAR_FUNCTION_TYPE 0x05 | ||
114 | #define AC_PAR_AUDIO_FG_CAP 0x08 | ||
115 | #define AC_PAR_AUDIO_WIDGET_CAP 0x09 | ||
116 | #define AC_PAR_PCM 0x0a | ||
117 | #define AC_PAR_STREAM 0x0b | ||
118 | #define AC_PAR_PIN_CAP 0x0c | ||
119 | #define AC_PAR_AMP_IN_CAP 0x0d | ||
120 | #define AC_PAR_CONNLIST_LEN 0x0e | ||
121 | #define AC_PAR_POWER_STATE 0x0f | ||
122 | #define AC_PAR_PROC_CAP 0x10 | ||
123 | #define AC_PAR_GPIO_CAP 0x11 | ||
124 | #define AC_PAR_AMP_OUT_CAP 0x12 | ||
125 | |||
126 | /* | ||
127 | * AC_VERB_PARAMETERS results (32bit) | ||
128 | */ | ||
129 | |||
130 | /* Function Group Type */ | ||
131 | #define AC_FGT_TYPE (0xff<<0) | ||
132 | #define AC_FGT_TYPE_SHIFT 0 | ||
133 | #define AC_FGT_UNSOL_CAP (1<<8) | ||
134 | |||
135 | /* Audio Function Group Capabilities */ | ||
136 | #define AC_AFG_OUT_DELAY (0xf<<0) | ||
137 | #define AC_AFG_IN_DELAY (0xf<<8) | ||
138 | #define AC_AFG_BEEP_GEN (1<<16) | ||
139 | |||
140 | /* Audio Widget Capabilities */ | ||
141 | #define AC_WCAP_STEREO (1<<0) /* stereo I/O */ | ||
142 | #define AC_WCAP_IN_AMP (1<<1) /* AMP-in present */ | ||
143 | #define AC_WCAP_OUT_AMP (1<<2) /* AMP-out present */ | ||
144 | #define AC_WCAP_AMP_OVRD (1<<3) /* AMP-parameter override */ | ||
145 | #define AC_WCAP_FORMAT_OVRD (1<<4) /* format override */ | ||
146 | #define AC_WCAP_STRIPE (1<<5) /* stripe */ | ||
147 | #define AC_WCAP_PROC_WID (1<<6) /* Proc Widget */ | ||
148 | #define AC_WCAP_UNSOL_CAP (1<<7) /* Unsol capable */ | ||
149 | #define AC_WCAP_CONN_LIST (1<<8) /* connection list */ | ||
150 | #define AC_WCAP_DIGITAL (1<<9) /* digital I/O */ | ||
151 | #define AC_WCAP_POWER (1<<10) /* power control */ | ||
152 | #define AC_WCAP_LR_SWAP (1<<11) /* L/R swap */ | ||
153 | #define AC_WCAP_DELAY (0xf<<16) | ||
154 | #define AC_WCAP_DELAY_SHIFT 16 | ||
155 | #define AC_WCAP_TYPE (0xf<<20) | ||
156 | #define AC_WCAP_TYPE_SHIFT 20 | ||
157 | |||
158 | /* supported PCM rates and bits */ | ||
159 | #define AC_SUPPCM_RATES (0xfff << 0) | ||
160 | #define AC_SUPPCM_BITS_8 (1<<16) | ||
161 | #define AC_SUPPCM_BITS_16 (1<<17) | ||
162 | #define AC_SUPPCM_BITS_20 (1<<18) | ||
163 | #define AC_SUPPCM_BITS_24 (1<<19) | ||
164 | #define AC_SUPPCM_BITS_32 (1<<20) | ||
165 | |||
166 | /* supported PCM stream format */ | ||
167 | #define AC_SUPFMT_PCM (1<<0) | ||
168 | #define AC_SUPFMT_FLOAT32 (1<<1) | ||
169 | #define AC_SUPFMT_AC3 (1<<2) | ||
170 | |||
171 | /* Pin widget capabilies */ | ||
172 | #define AC_PINCAP_IMP_SENSE (1<<0) /* impedance sense capable */ | ||
173 | #define AC_PINCAP_TRIG_REQ (1<<1) /* trigger required */ | ||
174 | #define AC_PINCAP_PRES_DETECT (1<<2) /* presence detect capable */ | ||
175 | #define AC_PINCAP_HP_DRV (1<<3) /* headphone drive capable */ | ||
176 | #define AC_PINCAP_OUT (1<<4) /* output capable */ | ||
177 | #define AC_PINCAP_IN (1<<5) /* input capable */ | ||
178 | #define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */ | ||
179 | #define AC_PINCAP_VREF (7<<8) | ||
180 | #define AC_PINCAP_VREF_SHIFT 8 | ||
181 | #define AC_PINCAP_EAPD (1<<16) /* EAPD capable */ | ||
182 | /* Vref status (used in pin cap and pin ctl) */ | ||
183 | #define AC_PIN_VREF_HIZ (1<<0) /* Hi-Z */ | ||
184 | #define AC_PIN_VREF_50 (1<<1) /* 50% */ | ||
185 | #define AC_PIN_VREF_GRD (1<<2) /* ground */ | ||
186 | #define AC_PIN_VREF_80 (1<<4) /* 80% */ | ||
187 | #define AC_PIN_VREF_100 (1<<5) /* 100% */ | ||
188 | |||
189 | |||
190 | /* Amplifier capabilities */ | ||
191 | #define AC_AMPCAP_OFFSET (0x7f<<0) /* 0dB offset */ | ||
192 | #define AC_AMPCAP_OFFSET_SHIFT 0 | ||
193 | #define AC_AMPCAP_NUM_STEPS (0x7f<<8) /* number of steps */ | ||
194 | #define AC_AMPCAP_NUM_STEPS_SHIFT 8 | ||
195 | #define AC_AMPCAP_STEP_SIZE (0x7f<<16) /* step size 0-32dB in 0.25dB */ | ||
196 | #define AC_AMPCAP_STEP_SIZE_SHIFT 16 | ||
197 | #define AC_AMPCAP_MUTE (1<<31) /* mute capable */ | ||
198 | #define AC_AMPCAP_MUTE_SHIFT 31 | ||
199 | |||
200 | /* Connection list */ | ||
201 | #define AC_CLIST_LENGTH (0x7f<<0) | ||
202 | #define AC_CLIST_LONG (1<<7) | ||
203 | |||
204 | /* Supported power status */ | ||
205 | #define AC_PWRST_D0SUP (1<<0) | ||
206 | #define AC_PWRST_D1SUP (1<<1) | ||
207 | #define AC_PWRST_D2SUP (1<<2) | ||
208 | #define AC_PWRST_D3SUP (1<<3) | ||
209 | |||
210 | /* Processing capabilies */ | ||
211 | #define AC_PCAP_BENIGN (1<<0) | ||
212 | #define AC_PCAP_NUM_COEF (0xff<<8) | ||
213 | |||
214 | /* Volume knobs capabilities */ | ||
215 | #define AC_KNBCAP_NUM_STEPS (0x7f<<0) | ||
216 | #define AC_KNBCAP_DELTA (1<<8) | ||
217 | |||
218 | /* | ||
219 | * Control Parameters | ||
220 | */ | ||
221 | |||
222 | /* Amp gain/mute */ | ||
223 | #define AC_AMP_MUTE (1<<8) | ||
224 | #define AC_AMP_GAIN (0x7f) | ||
225 | #define AC_AMP_GET_INDEX (0xf<<0) | ||
226 | |||
227 | #define AC_AMP_GET_LEFT (1<<13) | ||
228 | #define AC_AMP_GET_RIGHT (0<<13) | ||
229 | #define AC_AMP_GET_OUTPUT (1<<15) | ||
230 | #define AC_AMP_GET_INPUT (0<<15) | ||
231 | |||
232 | #define AC_AMP_SET_INDEX (0xf<<8) | ||
233 | #define AC_AMP_SET_INDEX_SHIFT 8 | ||
234 | #define AC_AMP_SET_RIGHT (1<<12) | ||
235 | #define AC_AMP_SET_LEFT (1<<13) | ||
236 | #define AC_AMP_SET_INPUT (1<<14) | ||
237 | #define AC_AMP_SET_OUTPUT (1<<15) | ||
238 | |||
239 | /* DIGITAL1 bits */ | ||
240 | #define AC_DIG1_ENABLE (1<<0) | ||
241 | #define AC_DIG1_V (1<<1) | ||
242 | #define AC_DIG1_VCFG (1<<2) | ||
243 | #define AC_DIG1_EMPHASIS (1<<3) | ||
244 | #define AC_DIG1_COPYRIGHT (1<<4) | ||
245 | #define AC_DIG1_NONAUDIO (1<<5) | ||
246 | #define AC_DIG1_PROFESSIONAL (1<<6) | ||
247 | #define AC_DIG1_LEVEL (1<<7) | ||
248 | |||
249 | /* Pin widget control - 8bit */ | ||
250 | #define AC_PINCTL_VREFEN (0x7<<0) | ||
251 | #define AC_PINCTL_IN_EN (1<<5) | ||
252 | #define AC_PINCTL_OUT_EN (1<<6) | ||
253 | #define AC_PINCTL_HP_EN (1<<7) | ||
254 | |||
255 | /* configuration default - 32bit */ | ||
256 | #define AC_DEFCFG_SEQUENCE (0xf<<0) | ||
257 | #define AC_DEFCFG_DEF_ASSOC (0xf<<4) | ||
258 | #define AC_DEFCFG_MISC (0xf<<8) | ||
259 | #define AC_DEFCFG_COLOR (0xf<<12) | ||
260 | #define AC_DEFCFG_COLOR_SHIFT 12 | ||
261 | #define AC_DEFCFG_CONN_TYPE (0xf<<16) | ||
262 | #define AC_DEFCFG_CONN_TYPE_SHIFT 16 | ||
263 | #define AC_DEFCFG_DEVICE (0xf<<20) | ||
264 | #define AC_DEFCFG_DEVICE_SHIFT 20 | ||
265 | #define AC_DEFCFG_LOCATION (0x3f<<24) | ||
266 | #define AC_DEFCFG_LOCATION_SHIFT 24 | ||
267 | #define AC_DEFCFG_PORT_CONN (0x3<<30) | ||
268 | #define AC_DEFCFG_PORT_CONN_SHIFT 30 | ||
269 | |||
270 | /* device device types (0x0-0xf) */ | ||
271 | enum { | ||
272 | AC_JACK_LINE_OUT, | ||
273 | AC_JACK_SPEAKER, | ||
274 | AC_JACK_HP_OUT, | ||
275 | AC_JACK_CD, | ||
276 | AC_JACK_SPDIF_OUT, | ||
277 | AC_JACK_DIG_OTHER_OUT, | ||
278 | AC_JACK_MODEM_LINE_SIDE, | ||
279 | AC_JACK_MODEM_HAND_SIDE, | ||
280 | AC_JACK_LINE_IN, | ||
281 | AC_JACK_AUX, | ||
282 | AC_JACK_MIC_IN, | ||
283 | AC_JACK_TELEPHONY, | ||
284 | AC_JACK_SPDIF_IN, | ||
285 | AC_JACK_DIG_OTHER_IN, | ||
286 | AC_JACK_OTHER = 0xf, | ||
287 | }; | ||
288 | |||
289 | /* jack connection types (0x0-0xf) */ | ||
290 | enum { | ||
291 | AC_JACK_CONN_UNKNOWN, | ||
292 | AC_JACK_CONN_1_8, | ||
293 | AC_JACK_CONN_1_4, | ||
294 | AC_JACK_CONN_ATAPI, | ||
295 | AC_JACK_CONN_RCA, | ||
296 | AC_JACK_CONN_OPTICAL, | ||
297 | AC_JACK_CONN_OTHER_DIGITAL, | ||
298 | AC_JACK_CONN_OTHER_ANALOG, | ||
299 | AC_JACK_CONN_DIN, | ||
300 | AC_JACK_CONN_XLR, | ||
301 | AC_JACK_CONN_RJ11, | ||
302 | AC_JACK_CONN_COMB, | ||
303 | AC_JACK_CONN_OTHER = 0xf, | ||
304 | }; | ||
305 | |||
306 | /* jack colors (0x0-0xf) */ | ||
307 | enum { | ||
308 | AC_JACK_COLOR_UNKNOWN, | ||
309 | AC_JACK_COLOR_BLACK, | ||
310 | AC_JACK_COLOR_GREY, | ||
311 | AC_JACK_COLOR_BLUE, | ||
312 | AC_JACK_COLOR_GREEN, | ||
313 | AC_JACK_COLOR_RED, | ||
314 | AC_JACK_COLOR_ORANGE, | ||
315 | AC_JACK_COLOR_YELLOW, | ||
316 | AC_JACK_COLOR_PURPLE, | ||
317 | AC_JACK_COLOR_PINK, | ||
318 | AC_JACK_COLOR_WHITE = 0xe, | ||
319 | AC_JACK_COLOR_OTHER, | ||
320 | }; | ||
321 | |||
322 | /* Jack location (0x0-0x3f) */ | ||
323 | /* common case */ | ||
324 | enum { | ||
325 | AC_JACK_LOC_NONE, | ||
326 | AC_JACK_LOC_REAR, | ||
327 | AC_JACK_LOC_FRONT, | ||
328 | AC_JACK_LOC_LEFT, | ||
329 | AC_JACK_LOC_RIGHT, | ||
330 | AC_JACK_LOC_TOP, | ||
331 | AC_JACK_LOC_BOTTOM, | ||
332 | }; | ||
333 | /* bits 4-5 */ | ||
334 | enum { | ||
335 | AC_JACK_LOC_EXTERNAL = 0x00, | ||
336 | AC_JACK_LOC_INTERNAL = 0x10, | ||
337 | AC_JACK_LOC_SEPARATE = 0x20, | ||
338 | AC_JACK_LOC_OTHER = 0x30, | ||
339 | }; | ||
340 | enum { | ||
341 | /* external on primary chasis */ | ||
342 | AC_JACK_LOC_REAR_PANEL = 0x07, | ||
343 | AC_JACK_LOC_DRIVE_BAY, | ||
344 | /* internal */ | ||
345 | AC_JACK_LOC_RISER = 0x17, | ||
346 | AC_JACK_LOC_HDMI, | ||
347 | AC_JACK_LOC_ATAPI, | ||
348 | /* others */ | ||
349 | AC_JACK_LOC_MOBILE_IN = 0x37, | ||
350 | AC_JACK_LOC_MOBILE_OUT, | ||
351 | }; | ||
352 | |||
353 | /* Port connectivity (0-3) */ | ||
354 | enum { | ||
355 | AC_JACK_PORT_COMPLEX, | ||
356 | AC_JACK_PORT_NONE, | ||
357 | AC_JACK_PORT_FIXED, | ||
358 | AC_JACK_PORT_BOTH, | ||
359 | }; | ||
360 | |||
361 | /* max. connections to a widget */ | ||
362 | #define HDA_MAX_CONNECTIONS 16 | ||
363 | |||
364 | /* max. codec address */ | ||
365 | #define HDA_MAX_CODEC_ADDRESS 0x0f | ||
366 | |||
367 | /* | ||
368 | * Structures | ||
369 | */ | ||
370 | |||
371 | struct hda_bus; | ||
372 | struct hda_codec; | ||
373 | struct hda_pcm; | ||
374 | struct hda_pcm_stream; | ||
375 | struct hda_bus_unsolicited; | ||
376 | |||
377 | /* NID type */ | ||
378 | typedef u16 hda_nid_t; | ||
379 | |||
380 | /* bus operators */ | ||
381 | struct hda_bus_ops { | ||
382 | /* send a single command */ | ||
383 | int (*command)(struct hda_codec *codec, hda_nid_t nid, int direct, | ||
384 | unsigned int verb, unsigned int parm); | ||
385 | /* get a response from the last command */ | ||
386 | unsigned int (*get_response)(struct hda_codec *codec); | ||
387 | /* free the private data */ | ||
388 | void (*private_free)(struct hda_bus *); | ||
389 | }; | ||
390 | |||
391 | /* template to pass to the bus constructor */ | ||
392 | struct hda_bus_template { | ||
393 | void *private_data; | ||
394 | struct pci_dev *pci; | ||
395 | const char *modelname; | ||
396 | struct hda_bus_ops ops; | ||
397 | }; | ||
398 | |||
399 | /* | ||
400 | * codec bus | ||
401 | * | ||
402 | * each controller needs to creata a hda_bus to assign the accessor. | ||
403 | * A hda_bus contains several codecs in the list codec_list. | ||
404 | */ | ||
405 | struct hda_bus { | ||
406 | snd_card_t *card; | ||
407 | |||
408 | /* copied from template */ | ||
409 | void *private_data; | ||
410 | struct pci_dev *pci; | ||
411 | const char *modelname; | ||
412 | struct hda_bus_ops ops; | ||
413 | |||
414 | /* codec linked list */ | ||
415 | struct list_head codec_list; | ||
416 | struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS]; /* caddr -> codec */ | ||
417 | |||
418 | struct semaphore cmd_mutex; | ||
419 | |||
420 | /* unsolicited event queue */ | ||
421 | struct hda_bus_unsolicited *unsol; | ||
422 | |||
423 | snd_info_entry_t *proc; | ||
424 | }; | ||
425 | |||
426 | /* | ||
427 | * codec preset | ||
428 | * | ||
429 | * Known codecs have the patch to build and set up the controls/PCMs | ||
430 | * better than the generic parser. | ||
431 | */ | ||
432 | struct hda_codec_preset { | ||
433 | unsigned int id; | ||
434 | unsigned int mask; | ||
435 | unsigned int subs; | ||
436 | unsigned int subs_mask; | ||
437 | unsigned int rev; | ||
438 | const char *name; | ||
439 | int (*patch)(struct hda_codec *codec); | ||
440 | }; | ||
441 | |||
442 | /* ops set by the preset patch */ | ||
443 | struct hda_codec_ops { | ||
444 | int (*build_controls)(struct hda_codec *codec); | ||
445 | int (*build_pcms)(struct hda_codec *codec); | ||
446 | int (*init)(struct hda_codec *codec); | ||
447 | void (*free)(struct hda_codec *codec); | ||
448 | void (*unsol_event)(struct hda_codec *codec, unsigned int res); | ||
449 | #ifdef CONFIG_PM | ||
450 | int (*suspend)(struct hda_codec *codec, pm_message_t state); | ||
451 | int (*resume)(struct hda_codec *codec); | ||
452 | #endif | ||
453 | }; | ||
454 | |||
455 | /* record for amp information cache */ | ||
456 | struct hda_amp_info { | ||
457 | u32 key; /* hash key */ | ||
458 | u32 amp_caps; /* amp capabilities */ | ||
459 | u16 vol[2]; /* current volume & mute*/ | ||
460 | u16 status; /* update flag */ | ||
461 | u16 next; /* next link */ | ||
462 | }; | ||
463 | |||
464 | /* PCM callbacks */ | ||
465 | struct hda_pcm_ops { | ||
466 | int (*open)(struct hda_pcm_stream *info, struct hda_codec *codec, | ||
467 | snd_pcm_substream_t *substream); | ||
468 | int (*close)(struct hda_pcm_stream *info, struct hda_codec *codec, | ||
469 | snd_pcm_substream_t *substream); | ||
470 | int (*prepare)(struct hda_pcm_stream *info, struct hda_codec *codec, | ||
471 | unsigned int stream_tag, unsigned int format, | ||
472 | snd_pcm_substream_t *substream); | ||
473 | int (*cleanup)(struct hda_pcm_stream *info, struct hda_codec *codec, | ||
474 | snd_pcm_substream_t *substream); | ||
475 | }; | ||
476 | |||
477 | /* PCM information for each substream */ | ||
478 | struct hda_pcm_stream { | ||
479 | unsigned int substreams; /* number of substreams, 0 = not exist */ | ||
480 | unsigned int channels_min; /* min. number of channels */ | ||
481 | unsigned int channels_max; /* max. number of channels */ | ||
482 | hda_nid_t nid; /* default NID to query rates/formats/bps, or set up */ | ||
483 | u32 rates; /* supported rates */ | ||
484 | u64 formats; /* supported formats (SNDRV_PCM_FMTBIT_) */ | ||
485 | unsigned int maxbps; /* supported max. bit per sample */ | ||
486 | struct hda_pcm_ops ops; | ||
487 | }; | ||
488 | |||
489 | /* for PCM creation */ | ||
490 | struct hda_pcm { | ||
491 | char *name; | ||
492 | struct hda_pcm_stream stream[2]; | ||
493 | }; | ||
494 | |||
495 | /* codec information */ | ||
496 | struct hda_codec { | ||
497 | struct hda_bus *bus; | ||
498 | unsigned int addr; /* codec addr*/ | ||
499 | struct list_head list; /* list point */ | ||
500 | |||
501 | hda_nid_t afg; /* AFG node id */ | ||
502 | |||
503 | /* ids */ | ||
504 | u32 vendor_id; | ||
505 | u32 subsystem_id; | ||
506 | u32 revision_id; | ||
507 | |||
508 | /* detected preset */ | ||
509 | const struct hda_codec_preset *preset; | ||
510 | |||
511 | /* set by patch */ | ||
512 | struct hda_codec_ops patch_ops; | ||
513 | |||
514 | /* resume phase - all controls should update even if | ||
515 | * the values are not changed | ||
516 | */ | ||
517 | unsigned int in_resume; | ||
518 | |||
519 | /* PCM to create, set by patch_ops.build_pcms callback */ | ||
520 | unsigned int num_pcms; | ||
521 | struct hda_pcm *pcm_info; | ||
522 | |||
523 | /* codec specific info */ | ||
524 | void *spec; | ||
525 | |||
526 | /* hash for amp access */ | ||
527 | u16 amp_hash[32]; | ||
528 | int num_amp_entries; | ||
529 | struct hda_amp_info amp_info[128]; /* big enough? */ | ||
530 | |||
531 | struct semaphore spdif_mutex; | ||
532 | unsigned int spdif_status; /* IEC958 status bits */ | ||
533 | unsigned short spdif_ctls; /* SPDIF control bits */ | ||
534 | unsigned int spdif_in_enable; /* SPDIF input enable? */ | ||
535 | }; | ||
536 | |||
537 | /* direction */ | ||
538 | enum { | ||
539 | HDA_INPUT, HDA_OUTPUT | ||
540 | }; | ||
541 | |||
542 | |||
543 | /* | ||
544 | * constructors | ||
545 | */ | ||
546 | int snd_hda_bus_new(snd_card_t *card, const struct hda_bus_template *temp, | ||
547 | struct hda_bus **busp); | ||
548 | int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, | ||
549 | struct hda_codec **codecp); | ||
550 | |||
551 | /* | ||
552 | * low level functions | ||
553 | */ | ||
554 | unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int direct, | ||
555 | unsigned int verb, unsigned int parm); | ||
556 | int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, | ||
557 | unsigned int verb, unsigned int parm); | ||
558 | #define snd_hda_param_read(codec, nid, param) snd_hda_codec_read(codec, nid, 0, AC_VERB_PARAMETERS, param) | ||
559 | int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *start_id); | ||
560 | int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *conn_list, int max_conns); | ||
561 | |||
562 | struct hda_verb { | ||
563 | hda_nid_t nid; | ||
564 | u32 verb; | ||
565 | u32 param; | ||
566 | }; | ||
567 | |||
568 | void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq); | ||
569 | |||
570 | /* unsolicited event */ | ||
571 | int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); | ||
572 | |||
573 | /* | ||
574 | * Mixer | ||
575 | */ | ||
576 | int snd_hda_build_controls(struct hda_bus *bus); | ||
577 | |||
578 | /* | ||
579 | * PCM | ||
580 | */ | ||
581 | int snd_hda_build_pcms(struct hda_bus *bus); | ||
582 | void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, | ||
583 | int channel_id, int format); | ||
584 | unsigned int snd_hda_calc_stream_format(unsigned int rate, unsigned int channels, | ||
585 | unsigned int format, unsigned int maxbps); | ||
586 | int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, | ||
587 | u32 *ratesp, u64 *formatsp, unsigned int *bpsp); | ||
588 | int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, | ||
589 | unsigned int format); | ||
590 | |||
591 | /* | ||
592 | * Misc | ||
593 | */ | ||
594 | void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen); | ||
595 | |||
596 | /* | ||
597 | * power management | ||
598 | */ | ||
599 | #ifdef CONFIG_PM | ||
600 | int snd_hda_suspend(struct hda_bus *bus, pm_message_t state); | ||
601 | int snd_hda_resume(struct hda_bus *bus); | ||
602 | #endif | ||
603 | |||
604 | #endif /* __SOUND_HDA_CODEC_H */ | ||
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c new file mode 100644 index 000000000000..69f7b6c4cf83 --- /dev/null +++ b/sound/pci/hda/hda_generic.c | |||
@@ -0,0 +1,906 @@ | |||
1 | /* | ||
2 | * Universal Interface for Intel High Definition Audio Codec | ||
3 | * | ||
4 | * Generic widget tree parser | ||
5 | * | ||
6 | * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> | ||
7 | * | ||
8 | * This driver is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This driver is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <sound/core.h> | ||
28 | #include "hda_codec.h" | ||
29 | #include "hda_local.h" | ||
30 | |||
31 | /* widget node for parsing */ | ||
32 | struct hda_gnode { | ||
33 | hda_nid_t nid; /* NID of this widget */ | ||
34 | unsigned short nconns; /* number of input connections */ | ||
35 | hda_nid_t conn_list[HDA_MAX_CONNECTIONS]; /* input connections */ | ||
36 | unsigned int wid_caps; /* widget capabilities */ | ||
37 | unsigned char type; /* widget type */ | ||
38 | unsigned char pin_ctl; /* pin controls */ | ||
39 | unsigned char checked; /* the flag indicates that the node is already parsed */ | ||
40 | unsigned int pin_caps; /* pin widget capabilities */ | ||
41 | unsigned int def_cfg; /* default configuration */ | ||
42 | unsigned int amp_out_caps; /* AMP out capabilities */ | ||
43 | unsigned int amp_in_caps; /* AMP in capabilities */ | ||
44 | struct list_head list; | ||
45 | }; | ||
46 | |||
47 | /* pathc-specific record */ | ||
48 | struct hda_gspec { | ||
49 | struct hda_gnode *dac_node; /* DAC node */ | ||
50 | struct hda_gnode *out_pin_node; /* Output pin (Line-Out) node */ | ||
51 | struct hda_gnode *pcm_vol_node; /* Node for PCM volume */ | ||
52 | unsigned int pcm_vol_index; /* connection of PCM volume */ | ||
53 | |||
54 | struct hda_gnode *adc_node; /* ADC node */ | ||
55 | struct hda_gnode *cap_vol_node; /* Node for capture volume */ | ||
56 | unsigned int cur_cap_src; /* current capture source */ | ||
57 | struct hda_input_mux input_mux; | ||
58 | char cap_labels[HDA_MAX_NUM_INPUTS][16]; | ||
59 | |||
60 | unsigned int def_amp_in_caps; | ||
61 | unsigned int def_amp_out_caps; | ||
62 | |||
63 | struct hda_pcm pcm_rec; /* PCM information */ | ||
64 | |||
65 | struct list_head nid_list; /* list of widgets */ | ||
66 | }; | ||
67 | |||
68 | /* | ||
69 | * retrieve the default device type from the default config value | ||
70 | */ | ||
71 | #define get_defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) | ||
72 | #define get_defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) | ||
73 | |||
74 | /* | ||
75 | * destructor | ||
76 | */ | ||
77 | static void snd_hda_generic_free(struct hda_codec *codec) | ||
78 | { | ||
79 | struct hda_gspec *spec = codec->spec; | ||
80 | struct list_head *p, *n; | ||
81 | |||
82 | if (! spec) | ||
83 | return; | ||
84 | /* free all widgets */ | ||
85 | list_for_each_safe(p, n, &spec->nid_list) { | ||
86 | struct hda_gnode *node = list_entry(p, struct hda_gnode, list); | ||
87 | kfree(node); | ||
88 | } | ||
89 | kfree(spec); | ||
90 | } | ||
91 | |||
92 | |||
93 | /* | ||
94 | * add a new widget node and read its attributes | ||
95 | */ | ||
96 | static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid_t nid) | ||
97 | { | ||
98 | struct hda_gnode *node; | ||
99 | int nconns; | ||
100 | |||
101 | node = kcalloc(1, sizeof(*node), GFP_KERNEL); | ||
102 | if (node == NULL) | ||
103 | return -ENOMEM; | ||
104 | node->nid = nid; | ||
105 | nconns = snd_hda_get_connections(codec, nid, node->conn_list, HDA_MAX_CONNECTIONS); | ||
106 | if (nconns < 0) { | ||
107 | kfree(node); | ||
108 | return nconns; | ||
109 | } | ||
110 | node->nconns = nconns; | ||
111 | node->wid_caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); | ||
112 | node->type = (node->wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | ||
113 | |||
114 | if (node->type == AC_WID_PIN) { | ||
115 | node->pin_caps = snd_hda_param_read(codec, node->nid, AC_PAR_PIN_CAP); | ||
116 | node->pin_ctl = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
117 | node->def_cfg = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
118 | } | ||
119 | |||
120 | if (node->wid_caps & AC_WCAP_OUT_AMP) { | ||
121 | if (node->wid_caps & AC_WCAP_AMP_OVRD) | ||
122 | node->amp_out_caps = snd_hda_param_read(codec, node->nid, AC_PAR_AMP_OUT_CAP); | ||
123 | if (! node->amp_out_caps) | ||
124 | node->amp_out_caps = spec->def_amp_out_caps; | ||
125 | } | ||
126 | if (node->wid_caps & AC_WCAP_IN_AMP) { | ||
127 | if (node->wid_caps & AC_WCAP_AMP_OVRD) | ||
128 | node->amp_in_caps = snd_hda_param_read(codec, node->nid, AC_PAR_AMP_IN_CAP); | ||
129 | if (! node->amp_in_caps) | ||
130 | node->amp_in_caps = spec->def_amp_in_caps; | ||
131 | } | ||
132 | list_add_tail(&node->list, &spec->nid_list); | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | /* | ||
137 | * build the AFG subtree | ||
138 | */ | ||
139 | static int build_afg_tree(struct hda_codec *codec) | ||
140 | { | ||
141 | struct hda_gspec *spec = codec->spec; | ||
142 | int i, nodes, err; | ||
143 | hda_nid_t nid; | ||
144 | |||
145 | snd_assert(spec, return -EINVAL); | ||
146 | |||
147 | spec->def_amp_out_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_OUT_CAP); | ||
148 | spec->def_amp_in_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_IN_CAP); | ||
149 | |||
150 | nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); | ||
151 | if (! nid || nodes < 0) { | ||
152 | printk(KERN_ERR "Invalid AFG subtree\n"); | ||
153 | return -EINVAL; | ||
154 | } | ||
155 | |||
156 | /* parse all nodes belonging to the AFG */ | ||
157 | for (i = 0; i < nodes; i++, nid++) { | ||
158 | if ((err = add_new_node(codec, spec, nid)) < 0) | ||
159 | return err; | ||
160 | } | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | |||
166 | /* | ||
167 | * look for the node record for the given NID | ||
168 | */ | ||
169 | /* FIXME: should avoid the braindead linear search */ | ||
170 | static struct hda_gnode *hda_get_node(struct hda_gspec *spec, hda_nid_t nid) | ||
171 | { | ||
172 | struct list_head *p; | ||
173 | struct hda_gnode *node; | ||
174 | |||
175 | list_for_each(p, &spec->nid_list) { | ||
176 | node = list_entry(p, struct hda_gnode, list); | ||
177 | if (node->nid == nid) | ||
178 | return node; | ||
179 | } | ||
180 | return NULL; | ||
181 | } | ||
182 | |||
183 | /* | ||
184 | * unmute (and set max vol) the output amplifier | ||
185 | */ | ||
186 | static int unmute_output(struct hda_codec *codec, struct hda_gnode *node) | ||
187 | { | ||
188 | unsigned int val, ofs; | ||
189 | snd_printdd("UNMUTE OUT: NID=0x%x\n", node->nid); | ||
190 | val = (node->amp_out_caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; | ||
191 | ofs = (node->amp_out_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; | ||
192 | if (val >= ofs) | ||
193 | val -= ofs; | ||
194 | val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT; | ||
195 | val |= AC_AMP_SET_OUTPUT; | ||
196 | return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val); | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * unmute (and set max vol) the input amplifier | ||
201 | */ | ||
202 | static int unmute_input(struct hda_codec *codec, struct hda_gnode *node, unsigned int index) | ||
203 | { | ||
204 | unsigned int val, ofs; | ||
205 | snd_printdd("UNMUTE IN: NID=0x%x IDX=0x%x\n", node->nid, index); | ||
206 | val = (node->amp_in_caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; | ||
207 | ofs = (node->amp_in_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; | ||
208 | if (val >= ofs) | ||
209 | val -= ofs; | ||
210 | val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT; | ||
211 | val |= AC_AMP_SET_INPUT; | ||
212 | // awk added - fixed to allow unmuting of indexed amps | ||
213 | val |= index << AC_AMP_SET_INDEX_SHIFT; | ||
214 | return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val); | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * select the input connection of the given node. | ||
219 | */ | ||
220 | static int select_input_connection(struct hda_codec *codec, struct hda_gnode *node, | ||
221 | unsigned int index) | ||
222 | { | ||
223 | snd_printdd("CONNECT: NID=0x%x IDX=0x%x\n", node->nid, index); | ||
224 | return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_CONNECT_SEL, index); | ||
225 | } | ||
226 | |||
227 | /* | ||
228 | * clear checked flag of each node in the node list | ||
229 | */ | ||
230 | static void clear_check_flags(struct hda_gspec *spec) | ||
231 | { | ||
232 | struct list_head *p; | ||
233 | struct hda_gnode *node; | ||
234 | |||
235 | list_for_each(p, &spec->nid_list) { | ||
236 | node = list_entry(p, struct hda_gnode, list); | ||
237 | node->checked = 0; | ||
238 | } | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * parse the output path recursively until reach to an audio output widget | ||
243 | * | ||
244 | * returns 0 if not found, 1 if found, or a negative error code. | ||
245 | */ | ||
246 | static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec, | ||
247 | struct hda_gnode *node) | ||
248 | { | ||
249 | int i, err; | ||
250 | struct hda_gnode *child; | ||
251 | |||
252 | if (node->checked) | ||
253 | return 0; | ||
254 | |||
255 | node->checked = 1; | ||
256 | if (node->type == AC_WID_AUD_OUT) { | ||
257 | if (node->wid_caps & AC_WCAP_DIGITAL) { | ||
258 | snd_printdd("Skip Digital OUT node %x\n", node->nid); | ||
259 | return 0; | ||
260 | } | ||
261 | snd_printdd("AUD_OUT found %x\n", node->nid); | ||
262 | if (spec->dac_node) { | ||
263 | /* already DAC node is assigned, just unmute & connect */ | ||
264 | return node == spec->dac_node; | ||
265 | } | ||
266 | spec->dac_node = node; | ||
267 | if (node->wid_caps & AC_WCAP_OUT_AMP) { | ||
268 | spec->pcm_vol_node = node; | ||
269 | spec->pcm_vol_index = 0; | ||
270 | } | ||
271 | return 1; /* found */ | ||
272 | } | ||
273 | |||
274 | for (i = 0; i < node->nconns; i++) { | ||
275 | child = hda_get_node(spec, node->conn_list[i]); | ||
276 | if (! child) | ||
277 | continue; | ||
278 | err = parse_output_path(codec, spec, child); | ||
279 | if (err < 0) | ||
280 | return err; | ||
281 | else if (err > 0) { | ||
282 | /* found one, | ||
283 | * select the path, unmute both input and output | ||
284 | */ | ||
285 | if (node->nconns > 1) | ||
286 | select_input_connection(codec, node, i); | ||
287 | unmute_input(codec, node, i); | ||
288 | unmute_output(codec, node); | ||
289 | if (! spec->pcm_vol_node) { | ||
290 | if (node->wid_caps & AC_WCAP_IN_AMP) { | ||
291 | spec->pcm_vol_node = node; | ||
292 | spec->pcm_vol_index = i; | ||
293 | } else if (node->wid_caps & AC_WCAP_OUT_AMP) { | ||
294 | spec->pcm_vol_node = node; | ||
295 | spec->pcm_vol_index = 0; | ||
296 | } | ||
297 | } | ||
298 | return 1; | ||
299 | } | ||
300 | } | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | /* | ||
305 | * Look for the output PIN widget with the given jack type | ||
306 | * and parse the output path to that PIN. | ||
307 | * | ||
308 | * Returns the PIN node when the path to DAC is established. | ||
309 | */ | ||
310 | static struct hda_gnode *parse_output_jack(struct hda_codec *codec, | ||
311 | struct hda_gspec *spec, | ||
312 | int jack_type) | ||
313 | { | ||
314 | struct list_head *p; | ||
315 | struct hda_gnode *node; | ||
316 | int err; | ||
317 | |||
318 | list_for_each(p, &spec->nid_list) { | ||
319 | node = list_entry(p, struct hda_gnode, list); | ||
320 | if (node->type != AC_WID_PIN) | ||
321 | continue; | ||
322 | /* output capable? */ | ||
323 | if (! (node->pin_caps & AC_PINCAP_OUT)) | ||
324 | continue; | ||
325 | if (jack_type >= 0) { | ||
326 | if (jack_type != get_defcfg_type(node)) | ||
327 | continue; | ||
328 | if (node->wid_caps & AC_WCAP_DIGITAL) | ||
329 | continue; /* skip SPDIF */ | ||
330 | } else { | ||
331 | /* output as default? */ | ||
332 | if (! (node->pin_ctl & AC_PINCTL_OUT_EN)) | ||
333 | continue; | ||
334 | } | ||
335 | clear_check_flags(spec); | ||
336 | err = parse_output_path(codec, spec, node); | ||
337 | if (err < 0) | ||
338 | return NULL; | ||
339 | else if (err > 0) { | ||
340 | /* unmute the PIN output */ | ||
341 | unmute_output(codec, node); | ||
342 | /* set PIN-Out enable */ | ||
343 | snd_hda_codec_write(codec, node->nid, 0, | ||
344 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
345 | AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); | ||
346 | return node; | ||
347 | } | ||
348 | } | ||
349 | return NULL; | ||
350 | } | ||
351 | |||
352 | |||
353 | /* | ||
354 | * parse outputs | ||
355 | */ | ||
356 | static int parse_output(struct hda_codec *codec) | ||
357 | { | ||
358 | struct hda_gspec *spec = codec->spec; | ||
359 | struct hda_gnode *node; | ||
360 | |||
361 | /* | ||
362 | * Look for the output PIN widget | ||
363 | */ | ||
364 | /* first, look for the line-out pin */ | ||
365 | node = parse_output_jack(codec, spec, AC_JACK_LINE_OUT); | ||
366 | if (node) /* found, remember the PIN node */ | ||
367 | spec->out_pin_node = node; | ||
368 | /* look for the HP-out pin */ | ||
369 | node = parse_output_jack(codec, spec, AC_JACK_HP_OUT); | ||
370 | if (node) { | ||
371 | if (! spec->out_pin_node) | ||
372 | spec->out_pin_node = node; | ||
373 | } | ||
374 | |||
375 | if (! spec->out_pin_node) { | ||
376 | /* no line-out or HP pins found, | ||
377 | * then choose for the first output pin | ||
378 | */ | ||
379 | spec->out_pin_node = parse_output_jack(codec, spec, -1); | ||
380 | if (! spec->out_pin_node) | ||
381 | snd_printd("hda_generic: no proper output path found\n"); | ||
382 | } | ||
383 | |||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | /* | ||
388 | * input MUX | ||
389 | */ | ||
390 | |||
391 | /* control callbacks */ | ||
392 | static int capture_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
393 | { | ||
394 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
395 | struct hda_gspec *spec = codec->spec; | ||
396 | return snd_hda_input_mux_info(&spec->input_mux, uinfo); | ||
397 | } | ||
398 | |||
399 | static int capture_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
400 | { | ||
401 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
402 | struct hda_gspec *spec = codec->spec; | ||
403 | |||
404 | ucontrol->value.enumerated.item[0] = spec->cur_cap_src; | ||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static int capture_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
409 | { | ||
410 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
411 | struct hda_gspec *spec = codec->spec; | ||
412 | return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol, | ||
413 | spec->adc_node->nid, &spec->cur_cap_src); | ||
414 | } | ||
415 | |||
416 | /* | ||
417 | * return the string name of the given input PIN widget | ||
418 | */ | ||
419 | static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl) | ||
420 | { | ||
421 | unsigned int location = get_defcfg_location(node); | ||
422 | switch (get_defcfg_type(node)) { | ||
423 | case AC_JACK_LINE_IN: | ||
424 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) | ||
425 | return "Front Line"; | ||
426 | return "Line"; | ||
427 | case AC_JACK_CD: | ||
428 | if (pinctl) | ||
429 | *pinctl |= AC_PIN_VREF_GRD; | ||
430 | return "CD"; | ||
431 | case AC_JACK_AUX: | ||
432 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) | ||
433 | return "Front Aux"; | ||
434 | return "Aux"; | ||
435 | case AC_JACK_MIC_IN: | ||
436 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) | ||
437 | return "Front Mic"; | ||
438 | return "Mic"; | ||
439 | case AC_JACK_SPDIF_IN: | ||
440 | return "SPDIF"; | ||
441 | case AC_JACK_DIG_OTHER_IN: | ||
442 | return "Digital"; | ||
443 | } | ||
444 | return NULL; | ||
445 | } | ||
446 | |||
447 | /* | ||
448 | * parse the nodes recursively until reach to the input PIN | ||
449 | * | ||
450 | * returns 0 if not found, 1 if found, or a negative error code. | ||
451 | */ | ||
452 | static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, | ||
453 | struct hda_gnode *node) | ||
454 | { | ||
455 | int i, err; | ||
456 | unsigned int pinctl; | ||
457 | char *label; | ||
458 | const char *type; | ||
459 | |||
460 | if (node->checked) | ||
461 | return 0; | ||
462 | |||
463 | node->checked = 1; | ||
464 | if (node->type != AC_WID_PIN) { | ||
465 | for (i = 0; i < node->nconns; i++) { | ||
466 | struct hda_gnode *child; | ||
467 | child = hda_get_node(spec, node->conn_list[i]); | ||
468 | if (! child) | ||
469 | continue; | ||
470 | err = parse_adc_sub_nodes(codec, spec, child); | ||
471 | if (err < 0) | ||
472 | return err; | ||
473 | if (err > 0) { | ||
474 | /* found one, | ||
475 | * select the path, unmute both input and output | ||
476 | */ | ||
477 | if (node->nconns > 1) | ||
478 | select_input_connection(codec, node, i); | ||
479 | unmute_input(codec, node, i); | ||
480 | unmute_output(codec, node); | ||
481 | return err; | ||
482 | } | ||
483 | } | ||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | /* input capable? */ | ||
488 | if (! (node->pin_caps & AC_PINCAP_IN)) | ||
489 | return 0; | ||
490 | |||
491 | if (node->wid_caps & AC_WCAP_DIGITAL) | ||
492 | return 0; /* skip SPDIF */ | ||
493 | |||
494 | if (spec->input_mux.num_items >= HDA_MAX_NUM_INPUTS) { | ||
495 | snd_printk(KERN_ERR "hda_generic: Too many items for capture\n"); | ||
496 | return -EINVAL; | ||
497 | } | ||
498 | |||
499 | pinctl = AC_PINCTL_IN_EN; | ||
500 | /* create a proper capture source label */ | ||
501 | type = get_input_type(node, &pinctl); | ||
502 | if (! type) { | ||
503 | /* input as default? */ | ||
504 | if (! (node->pin_ctl & AC_PINCTL_IN_EN)) | ||
505 | return 0; | ||
506 | type = "Input"; | ||
507 | } | ||
508 | label = spec->cap_labels[spec->input_mux.num_items]; | ||
509 | strcpy(label, type); | ||
510 | spec->input_mux.items[spec->input_mux.num_items].label = label; | ||
511 | |||
512 | /* unmute the PIN external input */ | ||
513 | unmute_input(codec, node, 0); /* index = 0? */ | ||
514 | /* set PIN-In enable */ | ||
515 | snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); | ||
516 | |||
517 | return 1; /* found */ | ||
518 | } | ||
519 | |||
520 | /* | ||
521 | * parse input | ||
522 | */ | ||
523 | static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node) | ||
524 | { | ||
525 | struct hda_gspec *spec = codec->spec; | ||
526 | struct hda_gnode *node; | ||
527 | int i, err; | ||
528 | |||
529 | snd_printdd("AUD_IN = %x\n", adc_node->nid); | ||
530 | clear_check_flags(spec); | ||
531 | |||
532 | // awk added - fixed no recording due to muted widget | ||
533 | unmute_input(codec, adc_node, 0); | ||
534 | |||
535 | /* | ||
536 | * check each connection of the ADC | ||
537 | * if it reaches to a proper input PIN, add the path as the | ||
538 | * input path. | ||
539 | */ | ||
540 | for (i = 0; i < adc_node->nconns; i++) { | ||
541 | node = hda_get_node(spec, adc_node->conn_list[i]); | ||
542 | if (! node) | ||
543 | continue; | ||
544 | err = parse_adc_sub_nodes(codec, spec, node); | ||
545 | if (err < 0) | ||
546 | return err; | ||
547 | else if (err > 0) { | ||
548 | struct hda_input_mux_item *csrc = &spec->input_mux.items[spec->input_mux.num_items]; | ||
549 | char *buf = spec->cap_labels[spec->input_mux.num_items]; | ||
550 | int ocap; | ||
551 | for (ocap = 0; ocap < spec->input_mux.num_items; ocap++) { | ||
552 | if (! strcmp(buf, spec->cap_labels[ocap])) { | ||
553 | /* same label already exists, | ||
554 | * put the index number to be unique | ||
555 | */ | ||
556 | sprintf(buf, "%s %d", spec->cap_labels[ocap], | ||
557 | spec->input_mux.num_items); | ||
558 | } | ||
559 | } | ||
560 | csrc->index = i; | ||
561 | spec->input_mux.num_items++; | ||
562 | } | ||
563 | } | ||
564 | |||
565 | if (! spec->input_mux.num_items) | ||
566 | return 0; /* no input path found... */ | ||
567 | |||
568 | snd_printdd("[Capture Source] NID=0x%x, #SRC=%d\n", adc_node->nid, spec->input_mux.num_items); | ||
569 | for (i = 0; i < spec->input_mux.num_items; i++) | ||
570 | snd_printdd(" [%s] IDX=0x%x\n", spec->input_mux.items[i].label, | ||
571 | spec->input_mux.items[i].index); | ||
572 | |||
573 | spec->adc_node = adc_node; | ||
574 | return 1; | ||
575 | } | ||
576 | |||
577 | /* | ||
578 | * parse input | ||
579 | */ | ||
580 | static int parse_input(struct hda_codec *codec) | ||
581 | { | ||
582 | struct hda_gspec *spec = codec->spec; | ||
583 | struct list_head *p; | ||
584 | struct hda_gnode *node; | ||
585 | int err; | ||
586 | |||
587 | /* | ||
588 | * At first we look for an audio input widget. | ||
589 | * If it reaches to certain input PINs, we take it as the | ||
590 | * input path. | ||
591 | */ | ||
592 | list_for_each(p, &spec->nid_list) { | ||
593 | node = list_entry(p, struct hda_gnode, list); | ||
594 | if (node->wid_caps & AC_WCAP_DIGITAL) | ||
595 | continue; /* skip SPDIF */ | ||
596 | if (node->type == AC_WID_AUD_IN) { | ||
597 | err = parse_input_path(codec, node); | ||
598 | if (err < 0) | ||
599 | return err; | ||
600 | else if (err > 0) | ||
601 | return 0; | ||
602 | } | ||
603 | } | ||
604 | snd_printd("hda_generic: no proper input path found\n"); | ||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | /* | ||
609 | * create mixer controls if possible | ||
610 | */ | ||
611 | #define DIR_OUT 0x1 | ||
612 | #define DIR_IN 0x2 | ||
613 | |||
614 | static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, | ||
615 | unsigned int index, const char *type, const char *dir_sfx) | ||
616 | { | ||
617 | char name[32]; | ||
618 | int err; | ||
619 | int created = 0; | ||
620 | snd_kcontrol_new_t knew; | ||
621 | |||
622 | if (type) | ||
623 | sprintf(name, "%s %s Switch", type, dir_sfx); | ||
624 | else | ||
625 | sprintf(name, "%s Switch", dir_sfx); | ||
626 | if ((node->wid_caps & AC_WCAP_IN_AMP) && | ||
627 | (node->amp_in_caps & AC_AMPCAP_MUTE)) { | ||
628 | knew = (snd_kcontrol_new_t)HDA_CODEC_MUTE(name, node->nid, index, HDA_INPUT); | ||
629 | snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); | ||
630 | if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) | ||
631 | return err; | ||
632 | created = 1; | ||
633 | } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && | ||
634 | (node->amp_out_caps & AC_AMPCAP_MUTE)) { | ||
635 | knew = (snd_kcontrol_new_t)HDA_CODEC_MUTE(name, node->nid, 0, HDA_OUTPUT); | ||
636 | snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); | ||
637 | if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) | ||
638 | return err; | ||
639 | created = 1; | ||
640 | } | ||
641 | |||
642 | if (type) | ||
643 | sprintf(name, "%s %s Volume", type, dir_sfx); | ||
644 | else | ||
645 | sprintf(name, "%s Volume", dir_sfx); | ||
646 | if ((node->wid_caps & AC_WCAP_IN_AMP) && | ||
647 | (node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) { | ||
648 | knew = (snd_kcontrol_new_t)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT); | ||
649 | snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); | ||
650 | if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) | ||
651 | return err; | ||
652 | created = 1; | ||
653 | } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && | ||
654 | (node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) { | ||
655 | knew = (snd_kcontrol_new_t)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT); | ||
656 | snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); | ||
657 | if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) | ||
658 | return err; | ||
659 | created = 1; | ||
660 | } | ||
661 | |||
662 | return created; | ||
663 | } | ||
664 | |||
665 | /* | ||
666 | * check whether the controls with the given name and direction suffix already exist | ||
667 | */ | ||
668 | static int check_existing_control(struct hda_codec *codec, const char *type, const char *dir) | ||
669 | { | ||
670 | snd_ctl_elem_id_t id; | ||
671 | memset(&id, 0, sizeof(id)); | ||
672 | sprintf(id.name, "%s %s Volume", type, dir); | ||
673 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
674 | if (snd_ctl_find_id(codec->bus->card, &id)) | ||
675 | return 1; | ||
676 | sprintf(id.name, "%s %s Switch", type, dir); | ||
677 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
678 | if (snd_ctl_find_id(codec->bus->card, &id)) | ||
679 | return 1; | ||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | /* | ||
684 | * build output mixer controls | ||
685 | */ | ||
686 | static int build_output_controls(struct hda_codec *codec) | ||
687 | { | ||
688 | struct hda_gspec *spec = codec->spec; | ||
689 | int err; | ||
690 | |||
691 | err = create_mixer(codec, spec->pcm_vol_node, spec->pcm_vol_index, | ||
692 | "PCM", "Playback"); | ||
693 | if (err < 0) | ||
694 | return err; | ||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | /* create capture volume/switch */ | ||
699 | static int build_input_controls(struct hda_codec *codec) | ||
700 | { | ||
701 | struct hda_gspec *spec = codec->spec; | ||
702 | struct hda_gnode *adc_node = spec->adc_node; | ||
703 | int err; | ||
704 | |||
705 | if (! adc_node) | ||
706 | return 0; /* not found */ | ||
707 | |||
708 | /* create capture volume and switch controls if the ADC has an amp */ | ||
709 | err = create_mixer(codec, adc_node, 0, NULL, "Capture"); | ||
710 | |||
711 | /* create input MUX if multiple sources are available */ | ||
712 | if (spec->input_mux.num_items > 1) { | ||
713 | static snd_kcontrol_new_t cap_sel = { | ||
714 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
715 | .name = "Capture Source", | ||
716 | .info = capture_source_info, | ||
717 | .get = capture_source_get, | ||
718 | .put = capture_source_put, | ||
719 | }; | ||
720 | if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&cap_sel, codec))) < 0) | ||
721 | return err; | ||
722 | spec->cur_cap_src = 0; | ||
723 | select_input_connection(codec, adc_node, spec->input_mux.items[0].index); | ||
724 | } | ||
725 | return 0; | ||
726 | } | ||
727 | |||
728 | |||
729 | /* | ||
730 | * parse the nodes recursively until reach to the output PIN. | ||
731 | * | ||
732 | * returns 0 - if not found, | ||
733 | * 1 - if found, but no mixer is created | ||
734 | * 2 - if found and mixer was already created, (just skip) | ||
735 | * a negative error code | ||
736 | */ | ||
737 | static int parse_loopback_path(struct hda_codec *codec, struct hda_gspec *spec, | ||
738 | struct hda_gnode *node, struct hda_gnode *dest_node, | ||
739 | const char *type) | ||
740 | { | ||
741 | int i, err; | ||
742 | |||
743 | if (node->checked) | ||
744 | return 0; | ||
745 | |||
746 | node->checked = 1; | ||
747 | if (node == dest_node) { | ||
748 | /* loopback connection found */ | ||
749 | return 1; | ||
750 | } | ||
751 | |||
752 | for (i = 0; i < node->nconns; i++) { | ||
753 | struct hda_gnode *child = hda_get_node(spec, node->conn_list[i]); | ||
754 | if (! child) | ||
755 | continue; | ||
756 | err = parse_loopback_path(codec, spec, child, dest_node, type); | ||
757 | if (err < 0) | ||
758 | return err; | ||
759 | else if (err >= 1) { | ||
760 | if (err == 1) { | ||
761 | err = create_mixer(codec, node, i, type, "Playback"); | ||
762 | if (err < 0) | ||
763 | return err; | ||
764 | if (err > 0) | ||
765 | return 2; /* ok, created */ | ||
766 | /* not created, maybe in the lower path */ | ||
767 | err = 1; | ||
768 | } | ||
769 | /* connect and unmute */ | ||
770 | if (node->nconns > 1) | ||
771 | select_input_connection(codec, node, i); | ||
772 | unmute_input(codec, node, i); | ||
773 | unmute_output(codec, node); | ||
774 | return err; | ||
775 | } | ||
776 | } | ||
777 | return 0; | ||
778 | } | ||
779 | |||
780 | /* | ||
781 | * parse the tree and build the loopback controls | ||
782 | */ | ||
783 | static int build_loopback_controls(struct hda_codec *codec) | ||
784 | { | ||
785 | struct hda_gspec *spec = codec->spec; | ||
786 | struct list_head *p; | ||
787 | struct hda_gnode *node; | ||
788 | int err; | ||
789 | const char *type; | ||
790 | |||
791 | if (! spec->out_pin_node) | ||
792 | return 0; | ||
793 | |||
794 | list_for_each(p, &spec->nid_list) { | ||
795 | node = list_entry(p, struct hda_gnode, list); | ||
796 | if (node->type != AC_WID_PIN) | ||
797 | continue; | ||
798 | /* input capable? */ | ||
799 | if (! (node->pin_caps & AC_PINCAP_IN)) | ||
800 | return 0; | ||
801 | type = get_input_type(node, NULL); | ||
802 | if (type) { | ||
803 | if (check_existing_control(codec, type, "Playback")) | ||
804 | continue; | ||
805 | clear_check_flags(spec); | ||
806 | err = parse_loopback_path(codec, spec, spec->out_pin_node, | ||
807 | node, type); | ||
808 | if (err < 0) | ||
809 | return err; | ||
810 | if (! err) | ||
811 | continue; | ||
812 | } | ||
813 | } | ||
814 | return 0; | ||
815 | } | ||
816 | |||
817 | /* | ||
818 | * build mixer controls | ||
819 | */ | ||
820 | static int build_generic_controls(struct hda_codec *codec) | ||
821 | { | ||
822 | int err; | ||
823 | |||
824 | if ((err = build_input_controls(codec)) < 0 || | ||
825 | (err = build_output_controls(codec)) < 0 || | ||
826 | (err = build_loopback_controls(codec)) < 0) | ||
827 | return err; | ||
828 | |||
829 | return 0; | ||
830 | } | ||
831 | |||
832 | /* | ||
833 | * PCM | ||
834 | */ | ||
835 | static struct hda_pcm_stream generic_pcm_playback = { | ||
836 | .substreams = 1, | ||
837 | .channels_min = 2, | ||
838 | .channels_max = 2, | ||
839 | }; | ||
840 | |||
841 | static int build_generic_pcms(struct hda_codec *codec) | ||
842 | { | ||
843 | struct hda_gspec *spec = codec->spec; | ||
844 | struct hda_pcm *info = &spec->pcm_rec; | ||
845 | |||
846 | if (! spec->dac_node && ! spec->adc_node) { | ||
847 | snd_printd("hda_generic: no PCM found\n"); | ||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | codec->num_pcms = 1; | ||
852 | codec->pcm_info = info; | ||
853 | |||
854 | info->name = "HDA Generic"; | ||
855 | if (spec->dac_node) { | ||
856 | info->stream[0] = generic_pcm_playback; | ||
857 | info->stream[0].nid = spec->dac_node->nid; | ||
858 | } | ||
859 | if (spec->adc_node) { | ||
860 | info->stream[1] = generic_pcm_playback; | ||
861 | info->stream[1].nid = spec->adc_node->nid; | ||
862 | } | ||
863 | |||
864 | return 0; | ||
865 | } | ||
866 | |||
867 | |||
868 | /* | ||
869 | */ | ||
870 | static struct hda_codec_ops generic_patch_ops = { | ||
871 | .build_controls = build_generic_controls, | ||
872 | .build_pcms = build_generic_pcms, | ||
873 | .free = snd_hda_generic_free, | ||
874 | }; | ||
875 | |||
876 | /* | ||
877 | * the generic parser | ||
878 | */ | ||
879 | int snd_hda_parse_generic_codec(struct hda_codec *codec) | ||
880 | { | ||
881 | struct hda_gspec *spec; | ||
882 | int err; | ||
883 | |||
884 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | ||
885 | if (spec == NULL) { | ||
886 | printk(KERN_ERR "hda_generic: can't allocate spec\n"); | ||
887 | return -ENOMEM; | ||
888 | } | ||
889 | codec->spec = spec; | ||
890 | INIT_LIST_HEAD(&spec->nid_list); | ||
891 | |||
892 | if ((err = build_afg_tree(codec)) < 0) | ||
893 | goto error; | ||
894 | |||
895 | if ((err = parse_input(codec)) < 0 || | ||
896 | (err = parse_output(codec)) < 0) | ||
897 | goto error; | ||
898 | |||
899 | codec->patch_ops = generic_patch_ops; | ||
900 | |||
901 | return 0; | ||
902 | |||
903 | error: | ||
904 | snd_hda_generic_free(codec); | ||
905 | return err; | ||
906 | } | ||
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c new file mode 100644 index 000000000000..d89647a3d449 --- /dev/null +++ b/sound/pci/hda/hda_intel.c | |||
@@ -0,0 +1,1449 @@ | |||
1 | /* | ||
2 | * | ||
3 | * hda_intel.c - Implementation of primary alsa driver code base for Intel HD Audio. | ||
4 | * | ||
5 | * Copyright(c) 2004 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> | ||
8 | * PeiSen Hou <pshou@realtek.com.tw> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the Free | ||
12 | * Software Foundation; either version 2 of the License, or (at your option) | ||
13 | * any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
18 | * more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License along with | ||
21 | * this program; if not, write to the Free Software Foundation, Inc., 59 | ||
22 | * Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
23 | * | ||
24 | * CONTACTS: | ||
25 | * | ||
26 | * Matt Jared matt.jared@intel.com | ||
27 | * Andy Kopp andy.kopp@intel.com | ||
28 | * Dan Kogan dan.d.kogan@intel.com | ||
29 | * | ||
30 | * CHANGES: | ||
31 | * | ||
32 | * 2004.12.01 Major rewrite by tiwai, merged the work of pshou | ||
33 | * | ||
34 | */ | ||
35 | |||
36 | #include <sound/driver.h> | ||
37 | #include <asm/io.h> | ||
38 | #include <linux/delay.h> | ||
39 | #include <linux/interrupt.h> | ||
40 | #include <linux/module.h> | ||
41 | #include <linux/moduleparam.h> | ||
42 | #include <linux/init.h> | ||
43 | #include <linux/slab.h> | ||
44 | #include <linux/pci.h> | ||
45 | #include <sound/core.h> | ||
46 | #include <sound/initval.h> | ||
47 | #include "hda_codec.h" | ||
48 | |||
49 | |||
50 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
51 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
52 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
53 | static char *model[SNDRV_CARDS]; | ||
54 | |||
55 | module_param_array(index, int, NULL, 0444); | ||
56 | MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); | ||
57 | module_param_array(id, charp, NULL, 0444); | ||
58 | MODULE_PARM_DESC(id, "ID string for Intel HD audio interface."); | ||
59 | module_param_array(enable, bool, NULL, 0444); | ||
60 | MODULE_PARM_DESC(enable, "Enable Intel HD audio interface."); | ||
61 | module_param_array(model, charp, NULL, 0444); | ||
62 | MODULE_PARM_DESC(model, "Use the given board model."); | ||
63 | |||
64 | MODULE_LICENSE("GPL"); | ||
65 | MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," | ||
66 | "{Intel, ICH6M}," | ||
67 | "{Intel, ICH7}}"); | ||
68 | MODULE_DESCRIPTION("Intel HDA driver"); | ||
69 | |||
70 | #define SFX "hda-intel: " | ||
71 | |||
72 | /* | ||
73 | * registers | ||
74 | */ | ||
75 | #define ICH6_REG_GCAP 0x00 | ||
76 | #define ICH6_REG_VMIN 0x02 | ||
77 | #define ICH6_REG_VMAJ 0x03 | ||
78 | #define ICH6_REG_OUTPAY 0x04 | ||
79 | #define ICH6_REG_INPAY 0x06 | ||
80 | #define ICH6_REG_GCTL 0x08 | ||
81 | #define ICH6_REG_WAKEEN 0x0c | ||
82 | #define ICH6_REG_STATESTS 0x0e | ||
83 | #define ICH6_REG_GSTS 0x10 | ||
84 | #define ICH6_REG_INTCTL 0x20 | ||
85 | #define ICH6_REG_INTSTS 0x24 | ||
86 | #define ICH6_REG_WALCLK 0x30 | ||
87 | #define ICH6_REG_SYNC 0x34 | ||
88 | #define ICH6_REG_CORBLBASE 0x40 | ||
89 | #define ICH6_REG_CORBUBASE 0x44 | ||
90 | #define ICH6_REG_CORBWP 0x48 | ||
91 | #define ICH6_REG_CORBRP 0x4A | ||
92 | #define ICH6_REG_CORBCTL 0x4c | ||
93 | #define ICH6_REG_CORBSTS 0x4d | ||
94 | #define ICH6_REG_CORBSIZE 0x4e | ||
95 | |||
96 | #define ICH6_REG_RIRBLBASE 0x50 | ||
97 | #define ICH6_REG_RIRBUBASE 0x54 | ||
98 | #define ICH6_REG_RIRBWP 0x58 | ||
99 | #define ICH6_REG_RINTCNT 0x5a | ||
100 | #define ICH6_REG_RIRBCTL 0x5c | ||
101 | #define ICH6_REG_RIRBSTS 0x5d | ||
102 | #define ICH6_REG_RIRBSIZE 0x5e | ||
103 | |||
104 | #define ICH6_REG_IC 0x60 | ||
105 | #define ICH6_REG_IR 0x64 | ||
106 | #define ICH6_REG_IRS 0x68 | ||
107 | #define ICH6_IRS_VALID (1<<1) | ||
108 | #define ICH6_IRS_BUSY (1<<0) | ||
109 | |||
110 | #define ICH6_REG_DPLBASE 0x70 | ||
111 | #define ICH6_REG_DPUBASE 0x74 | ||
112 | #define ICH6_DPLBASE_ENABLE 0x1 /* Enable position buffer */ | ||
113 | |||
114 | /* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ | ||
115 | enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | ||
116 | |||
117 | /* stream register offsets from stream base */ | ||
118 | #define ICH6_REG_SD_CTL 0x00 | ||
119 | #define ICH6_REG_SD_STS 0x03 | ||
120 | #define ICH6_REG_SD_LPIB 0x04 | ||
121 | #define ICH6_REG_SD_CBL 0x08 | ||
122 | #define ICH6_REG_SD_LVI 0x0c | ||
123 | #define ICH6_REG_SD_FIFOW 0x0e | ||
124 | #define ICH6_REG_SD_FIFOSIZE 0x10 | ||
125 | #define ICH6_REG_SD_FORMAT 0x12 | ||
126 | #define ICH6_REG_SD_BDLPL 0x18 | ||
127 | #define ICH6_REG_SD_BDLPU 0x1c | ||
128 | |||
129 | /* PCI space */ | ||
130 | #define ICH6_PCIREG_TCSEL 0x44 | ||
131 | |||
132 | /* | ||
133 | * other constants | ||
134 | */ | ||
135 | |||
136 | /* max number of SDs */ | ||
137 | #define MAX_ICH6_DEV 8 | ||
138 | /* max number of fragments - we may use more if allocating more pages for BDL */ | ||
139 | #define AZX_MAX_FRAG (PAGE_SIZE / (MAX_ICH6_DEV * 16)) | ||
140 | /* max buffer size - no h/w limit, you can increase as you like */ | ||
141 | #define AZX_MAX_BUF_SIZE (1024*1024*1024) | ||
142 | /* max number of PCM devics per card */ | ||
143 | #define AZX_MAX_PCMS 8 | ||
144 | |||
145 | /* RIRB int mask: overrun[2], response[0] */ | ||
146 | #define RIRB_INT_RESPONSE 0x01 | ||
147 | #define RIRB_INT_OVERRUN 0x04 | ||
148 | #define RIRB_INT_MASK 0x05 | ||
149 | |||
150 | /* STATESTS int mask: SD2,SD1,SD0 */ | ||
151 | #define STATESTS_INT_MASK 0x07 | ||
152 | #define AZX_MAX_CODECS 3 | ||
153 | |||
154 | /* SD_CTL bits */ | ||
155 | #define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ | ||
156 | #define SD_CTL_DMA_START 0x02 /* stream DMA start bit */ | ||
157 | #define SD_CTL_STREAM_TAG_MASK (0xf << 20) | ||
158 | #define SD_CTL_STREAM_TAG_SHIFT 20 | ||
159 | |||
160 | /* SD_CTL and SD_STS */ | ||
161 | #define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */ | ||
162 | #define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ | ||
163 | #define SD_INT_COMPLETE 0x04 /* completion interrupt */ | ||
164 | #define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|SD_INT_COMPLETE) | ||
165 | |||
166 | /* SD_STS */ | ||
167 | #define SD_STS_FIFO_READY 0x20 /* FIFO ready */ | ||
168 | |||
169 | /* INTCTL and INTSTS */ | ||
170 | #define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */ | ||
171 | #define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ | ||
172 | #define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ | ||
173 | |||
174 | /* GCTL reset bit */ | ||
175 | #define ICH6_GCTL_RESET (1<<0) | ||
176 | |||
177 | /* CORB/RIRB control, read/write pointer */ | ||
178 | #define ICH6_RBCTL_DMA_EN 0x02 /* enable DMA */ | ||
179 | #define ICH6_RBCTL_IRQ_EN 0x01 /* enable IRQ */ | ||
180 | #define ICH6_RBRWP_CLR 0x8000 /* read/write pointer clear */ | ||
181 | /* below are so far hardcoded - should read registers in future */ | ||
182 | #define ICH6_MAX_CORB_ENTRIES 256 | ||
183 | #define ICH6_MAX_RIRB_ENTRIES 256 | ||
184 | |||
185 | |||
186 | /* | ||
187 | * Use CORB/RIRB for communication from/to codecs. | ||
188 | * This is the way recommended by Intel (see below). | ||
189 | */ | ||
190 | #define USE_CORB_RIRB | ||
191 | |||
192 | /* | ||
193 | * Define this if use the position buffer instead of reading SD_LPIB | ||
194 | * It's not used as default since SD_LPIB seems to give more accurate position | ||
195 | */ | ||
196 | /* #define USE_POSBUF */ | ||
197 | |||
198 | /* | ||
199 | */ | ||
200 | |||
201 | typedef struct snd_azx azx_t; | ||
202 | typedef struct snd_azx_rb azx_rb_t; | ||
203 | typedef struct snd_azx_dev azx_dev_t; | ||
204 | |||
205 | struct snd_azx_dev { | ||
206 | u32 *bdl; /* virtual address of the BDL */ | ||
207 | dma_addr_t bdl_addr; /* physical address of the BDL */ | ||
208 | volatile u32 *posbuf; /* position buffer pointer */ | ||
209 | |||
210 | unsigned int bufsize; /* size of the play buffer in bytes */ | ||
211 | unsigned int fragsize; /* size of each period in bytes */ | ||
212 | unsigned int frags; /* number for period in the play buffer */ | ||
213 | unsigned int fifo_size; /* FIFO size */ | ||
214 | |||
215 | void __iomem *sd_addr; /* stream descriptor pointer */ | ||
216 | |||
217 | u32 sd_int_sta_mask; /* stream int status mask */ | ||
218 | |||
219 | /* pcm support */ | ||
220 | snd_pcm_substream_t *substream; /* assigned substream, set in PCM open */ | ||
221 | unsigned int format_val; /* format value to be set in the controller and the codec */ | ||
222 | unsigned char stream_tag; /* assigned stream */ | ||
223 | unsigned char index; /* stream index */ | ||
224 | |||
225 | unsigned int opened: 1; | ||
226 | unsigned int running: 1; | ||
227 | }; | ||
228 | |||
229 | /* CORB/RIRB */ | ||
230 | struct snd_azx_rb { | ||
231 | u32 *buf; /* CORB/RIRB buffer | ||
232 | * Each CORB entry is 4byte, RIRB is 8byte | ||
233 | */ | ||
234 | dma_addr_t addr; /* physical address of CORB/RIRB buffer */ | ||
235 | /* for RIRB */ | ||
236 | unsigned short rp, wp; /* read/write pointers */ | ||
237 | int cmds; /* number of pending requests */ | ||
238 | u32 res; /* last read value */ | ||
239 | }; | ||
240 | |||
241 | struct snd_azx { | ||
242 | snd_card_t *card; | ||
243 | struct pci_dev *pci; | ||
244 | |||
245 | /* pci resources */ | ||
246 | unsigned long addr; | ||
247 | void __iomem *remap_addr; | ||
248 | int irq; | ||
249 | |||
250 | /* locks */ | ||
251 | spinlock_t reg_lock; | ||
252 | struct semaphore open_mutex; | ||
253 | |||
254 | /* streams */ | ||
255 | azx_dev_t azx_dev[MAX_ICH6_DEV]; | ||
256 | |||
257 | /* PCM */ | ||
258 | unsigned int pcm_devs; | ||
259 | snd_pcm_t *pcm[AZX_MAX_PCMS]; | ||
260 | |||
261 | /* HD codec */ | ||
262 | unsigned short codec_mask; | ||
263 | struct hda_bus *bus; | ||
264 | |||
265 | /* CORB/RIRB */ | ||
266 | azx_rb_t corb; | ||
267 | azx_rb_t rirb; | ||
268 | |||
269 | /* BDL, CORB/RIRB and position buffers */ | ||
270 | struct snd_dma_buffer bdl; | ||
271 | struct snd_dma_buffer rb; | ||
272 | struct snd_dma_buffer posbuf; | ||
273 | }; | ||
274 | |||
275 | /* | ||
276 | * macros for easy use | ||
277 | */ | ||
278 | #define azx_writel(chip,reg,value) \ | ||
279 | writel(value, (chip)->remap_addr + ICH6_REG_##reg) | ||
280 | #define azx_readl(chip,reg) \ | ||
281 | readl((chip)->remap_addr + ICH6_REG_##reg) | ||
282 | #define azx_writew(chip,reg,value) \ | ||
283 | writew(value, (chip)->remap_addr + ICH6_REG_##reg) | ||
284 | #define azx_readw(chip,reg) \ | ||
285 | readw((chip)->remap_addr + ICH6_REG_##reg) | ||
286 | #define azx_writeb(chip,reg,value) \ | ||
287 | writeb(value, (chip)->remap_addr + ICH6_REG_##reg) | ||
288 | #define azx_readb(chip,reg) \ | ||
289 | readb((chip)->remap_addr + ICH6_REG_##reg) | ||
290 | |||
291 | #define azx_sd_writel(dev,reg,value) \ | ||
292 | writel(value, (dev)->sd_addr + ICH6_REG_##reg) | ||
293 | #define azx_sd_readl(dev,reg) \ | ||
294 | readl((dev)->sd_addr + ICH6_REG_##reg) | ||
295 | #define azx_sd_writew(dev,reg,value) \ | ||
296 | writew(value, (dev)->sd_addr + ICH6_REG_##reg) | ||
297 | #define azx_sd_readw(dev,reg) \ | ||
298 | readw((dev)->sd_addr + ICH6_REG_##reg) | ||
299 | #define azx_sd_writeb(dev,reg,value) \ | ||
300 | writeb(value, (dev)->sd_addr + ICH6_REG_##reg) | ||
301 | #define azx_sd_readb(dev,reg) \ | ||
302 | readb((dev)->sd_addr + ICH6_REG_##reg) | ||
303 | |||
304 | /* for pcm support */ | ||
305 | #define get_azx_dev(substream) (azx_dev_t*)(substream->runtime->private_data) | ||
306 | |||
307 | /* Get the upper 32bit of the given dma_addr_t | ||
308 | * Compiler should optimize and eliminate the code if dma_addr_t is 32bit | ||
309 | */ | ||
310 | #define upper_32bit(addr) (sizeof(addr) > 4 ? (u32)((addr) >> 32) : (u32)0) | ||
311 | |||
312 | |||
313 | /* | ||
314 | * Interface for HD codec | ||
315 | */ | ||
316 | |||
317 | #ifdef USE_CORB_RIRB | ||
318 | /* | ||
319 | * CORB / RIRB interface | ||
320 | */ | ||
321 | static int azx_alloc_cmd_io(azx_t *chip) | ||
322 | { | ||
323 | int err; | ||
324 | |||
325 | /* single page (at least 4096 bytes) must suffice for both ringbuffes */ | ||
326 | err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), | ||
327 | PAGE_SIZE, &chip->rb); | ||
328 | if (err < 0) { | ||
329 | snd_printk(KERN_ERR SFX "cannot allocate CORB/RIRB\n"); | ||
330 | return err; | ||
331 | } | ||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | static void azx_init_cmd_io(azx_t *chip) | ||
336 | { | ||
337 | /* CORB set up */ | ||
338 | chip->corb.addr = chip->rb.addr; | ||
339 | chip->corb.buf = (u32 *)chip->rb.area; | ||
340 | azx_writel(chip, CORBLBASE, (u32)chip->corb.addr); | ||
341 | azx_writel(chip, CORBUBASE, upper_32bit(chip->corb.addr)); | ||
342 | |||
343 | /* set the corb write pointer to 0 */ | ||
344 | azx_writew(chip, CORBWP, 0); | ||
345 | /* reset the corb hw read pointer */ | ||
346 | azx_writew(chip, CORBRP, ICH6_RBRWP_CLR); | ||
347 | /* enable corb dma */ | ||
348 | azx_writeb(chip, CORBCTL, ICH6_RBCTL_DMA_EN); | ||
349 | |||
350 | /* RIRB set up */ | ||
351 | chip->rirb.addr = chip->rb.addr + 2048; | ||
352 | chip->rirb.buf = (u32 *)(chip->rb.area + 2048); | ||
353 | azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr); | ||
354 | azx_writel(chip, RIRBUBASE, upper_32bit(chip->rirb.addr)); | ||
355 | |||
356 | /* reset the rirb hw write pointer */ | ||
357 | azx_writew(chip, RIRBWP, ICH6_RBRWP_CLR); | ||
358 | /* set N=1, get RIRB response interrupt for new entry */ | ||
359 | azx_writew(chip, RINTCNT, 1); | ||
360 | /* enable rirb dma and response irq */ | ||
361 | #ifdef USE_CORB_RIRB | ||
362 | azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN); | ||
363 | #else | ||
364 | azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN); | ||
365 | #endif | ||
366 | chip->rirb.rp = chip->rirb.cmds = 0; | ||
367 | } | ||
368 | |||
369 | static void azx_free_cmd_io(azx_t *chip) | ||
370 | { | ||
371 | /* disable ringbuffer DMAs */ | ||
372 | azx_writeb(chip, RIRBCTL, 0); | ||
373 | azx_writeb(chip, CORBCTL, 0); | ||
374 | } | ||
375 | |||
376 | /* send a command */ | ||
377 | static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, | ||
378 | unsigned int verb, unsigned int para) | ||
379 | { | ||
380 | azx_t *chip = codec->bus->private_data; | ||
381 | unsigned int wp; | ||
382 | u32 val; | ||
383 | |||
384 | val = (u32)(codec->addr & 0x0f) << 28; | ||
385 | val |= (u32)direct << 27; | ||
386 | val |= (u32)nid << 20; | ||
387 | val |= verb << 8; | ||
388 | val |= para; | ||
389 | |||
390 | /* add command to corb */ | ||
391 | wp = azx_readb(chip, CORBWP); | ||
392 | wp++; | ||
393 | wp %= ICH6_MAX_CORB_ENTRIES; | ||
394 | |||
395 | spin_lock_irq(&chip->reg_lock); | ||
396 | chip->rirb.cmds++; | ||
397 | chip->corb.buf[wp] = cpu_to_le32(val); | ||
398 | azx_writel(chip, CORBWP, wp); | ||
399 | spin_unlock_irq(&chip->reg_lock); | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | #define ICH6_RIRB_EX_UNSOL_EV (1<<4) | ||
405 | |||
406 | /* retrieve RIRB entry - called from interrupt handler */ | ||
407 | static void azx_update_rirb(azx_t *chip) | ||
408 | { | ||
409 | unsigned int rp, wp; | ||
410 | u32 res, res_ex; | ||
411 | |||
412 | wp = azx_readb(chip, RIRBWP); | ||
413 | if (wp == chip->rirb.wp) | ||
414 | return; | ||
415 | chip->rirb.wp = wp; | ||
416 | |||
417 | while (chip->rirb.rp != wp) { | ||
418 | chip->rirb.rp++; | ||
419 | chip->rirb.rp %= ICH6_MAX_RIRB_ENTRIES; | ||
420 | |||
421 | rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */ | ||
422 | res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]); | ||
423 | res = le32_to_cpu(chip->rirb.buf[rp]); | ||
424 | if (res_ex & ICH6_RIRB_EX_UNSOL_EV) | ||
425 | snd_hda_queue_unsol_event(chip->bus, res, res_ex); | ||
426 | else if (chip->rirb.cmds) { | ||
427 | chip->rirb.cmds--; | ||
428 | chip->rirb.res = res; | ||
429 | } | ||
430 | } | ||
431 | } | ||
432 | |||
433 | /* receive a response */ | ||
434 | static unsigned int azx_get_response(struct hda_codec *codec) | ||
435 | { | ||
436 | azx_t *chip = codec->bus->private_data; | ||
437 | int timeout = 50; | ||
438 | |||
439 | while (chip->rirb.cmds) { | ||
440 | if (! --timeout) { | ||
441 | snd_printk(KERN_ERR "azx_get_response timeout\n"); | ||
442 | chip->rirb.rp = azx_readb(chip, RIRBWP); | ||
443 | chip->rirb.cmds = 0; | ||
444 | return -1; | ||
445 | } | ||
446 | msleep(1); | ||
447 | } | ||
448 | return chip->rirb.res; /* the last value */ | ||
449 | } | ||
450 | |||
451 | #else | ||
452 | /* | ||
453 | * Use the single immediate command instead of CORB/RIRB for simplicity | ||
454 | * | ||
455 | * Note: according to Intel, this is not preferred use. The command was | ||
456 | * intended for the BIOS only, and may get confused with unsolicited | ||
457 | * responses. So, we shouldn't use it for normal operation from the | ||
458 | * driver. | ||
459 | * I left the codes, however, for debugging/testing purposes. | ||
460 | */ | ||
461 | |||
462 | #define azx_alloc_cmd_io(chip) 0 | ||
463 | #define azx_init_cmd_io(chip) | ||
464 | #define azx_free_cmd_io(chip) | ||
465 | |||
466 | /* send a command */ | ||
467 | static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, | ||
468 | unsigned int verb, unsigned int para) | ||
469 | { | ||
470 | azx_t *chip = codec->bus->private_data; | ||
471 | u32 val; | ||
472 | int timeout = 50; | ||
473 | |||
474 | val = (u32)(codec->addr & 0x0f) << 28; | ||
475 | val |= (u32)direct << 27; | ||
476 | val |= (u32)nid << 20; | ||
477 | val |= verb << 8; | ||
478 | val |= para; | ||
479 | |||
480 | while (timeout--) { | ||
481 | /* check ICB busy bit */ | ||
482 | if (! (azx_readw(chip, IRS) & ICH6_IRS_BUSY)) { | ||
483 | /* Clear IRV valid bit */ | ||
484 | azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_VALID); | ||
485 | azx_writel(chip, IC, val); | ||
486 | azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_BUSY); | ||
487 | return 0; | ||
488 | } | ||
489 | udelay(1); | ||
490 | } | ||
491 | snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n", azx_readw(chip, IRS), val); | ||
492 | return -EIO; | ||
493 | } | ||
494 | |||
495 | /* receive a response */ | ||
496 | static unsigned int azx_get_response(struct hda_codec *codec) | ||
497 | { | ||
498 | azx_t *chip = codec->bus->private_data; | ||
499 | int timeout = 50; | ||
500 | |||
501 | while (timeout--) { | ||
502 | /* check IRV busy bit */ | ||
503 | if (azx_readw(chip, IRS) & ICH6_IRS_VALID) | ||
504 | return azx_readl(chip, IR); | ||
505 | udelay(1); | ||
506 | } | ||
507 | snd_printd(SFX "get_response timeout: IRS=0x%x\n", azx_readw(chip, IRS)); | ||
508 | return (unsigned int)-1; | ||
509 | } | ||
510 | |||
511 | #define azx_update_rirb(chip) | ||
512 | |||
513 | #endif /* USE_CORB_RIRB */ | ||
514 | |||
515 | /* reset codec link */ | ||
516 | static int azx_reset(azx_t *chip) | ||
517 | { | ||
518 | int count; | ||
519 | |||
520 | /* reset controller */ | ||
521 | azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET); | ||
522 | |||
523 | count = 50; | ||
524 | while (azx_readb(chip, GCTL) && --count) | ||
525 | msleep(1); | ||
526 | |||
527 | /* delay for >= 100us for codec PLL to settle per spec | ||
528 | * Rev 0.9 section 5.5.1 | ||
529 | */ | ||
530 | msleep(1); | ||
531 | |||
532 | /* Bring controller out of reset */ | ||
533 | azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET); | ||
534 | |||
535 | count = 50; | ||
536 | while (! azx_readb(chip, GCTL) && --count) | ||
537 | msleep(1); | ||
538 | |||
539 | /* Brent Chartrand said to wait >= 540us for codecs to intialize */ | ||
540 | msleep(1); | ||
541 | |||
542 | /* check to see if controller is ready */ | ||
543 | if (! azx_readb(chip, GCTL)) { | ||
544 | snd_printd("azx_reset: controller not ready!\n"); | ||
545 | return -EBUSY; | ||
546 | } | ||
547 | |||
548 | /* detect codecs */ | ||
549 | if (! chip->codec_mask) { | ||
550 | chip->codec_mask = azx_readw(chip, STATESTS); | ||
551 | snd_printdd("codec_mask = 0x%x\n", chip->codec_mask); | ||
552 | } | ||
553 | |||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | |||
558 | /* | ||
559 | * Lowlevel interface | ||
560 | */ | ||
561 | |||
562 | /* enable interrupts */ | ||
563 | static void azx_int_enable(azx_t *chip) | ||
564 | { | ||
565 | /* enable controller CIE and GIE */ | ||
566 | azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) | | ||
567 | ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN); | ||
568 | } | ||
569 | |||
570 | /* disable interrupts */ | ||
571 | static void azx_int_disable(azx_t *chip) | ||
572 | { | ||
573 | int i; | ||
574 | |||
575 | /* disable interrupts in stream descriptor */ | ||
576 | for (i = 0; i < MAX_ICH6_DEV; i++) { | ||
577 | azx_dev_t *azx_dev = &chip->azx_dev[i]; | ||
578 | azx_sd_writeb(azx_dev, SD_CTL, | ||
579 | azx_sd_readb(azx_dev, SD_CTL) & ~SD_INT_MASK); | ||
580 | } | ||
581 | |||
582 | /* disable SIE for all streams */ | ||
583 | azx_writeb(chip, INTCTL, 0); | ||
584 | |||
585 | /* disable controller CIE and GIE */ | ||
586 | azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) & | ||
587 | ~(ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN)); | ||
588 | } | ||
589 | |||
590 | /* clear interrupts */ | ||
591 | static void azx_int_clear(azx_t *chip) | ||
592 | { | ||
593 | int i; | ||
594 | |||
595 | /* clear stream status */ | ||
596 | for (i = 0; i < MAX_ICH6_DEV; i++) { | ||
597 | azx_dev_t *azx_dev = &chip->azx_dev[i]; | ||
598 | azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); | ||
599 | } | ||
600 | |||
601 | /* clear STATESTS */ | ||
602 | azx_writeb(chip, STATESTS, STATESTS_INT_MASK); | ||
603 | |||
604 | /* clear rirb status */ | ||
605 | azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); | ||
606 | |||
607 | /* clear int status */ | ||
608 | azx_writel(chip, INTSTS, ICH6_INT_CTRL_EN | ICH6_INT_ALL_STREAM); | ||
609 | } | ||
610 | |||
611 | /* start a stream */ | ||
612 | static void azx_stream_start(azx_t *chip, azx_dev_t *azx_dev) | ||
613 | { | ||
614 | /* enable SIE */ | ||
615 | azx_writeb(chip, INTCTL, | ||
616 | azx_readb(chip, INTCTL) | (1 << azx_dev->index)); | ||
617 | /* set DMA start and interrupt mask */ | ||
618 | azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | | ||
619 | SD_CTL_DMA_START | SD_INT_MASK); | ||
620 | } | ||
621 | |||
622 | /* stop a stream */ | ||
623 | static void azx_stream_stop(azx_t *chip, azx_dev_t *azx_dev) | ||
624 | { | ||
625 | /* stop DMA */ | ||
626 | azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & | ||
627 | ~(SD_CTL_DMA_START | SD_INT_MASK)); | ||
628 | azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ | ||
629 | /* disable SIE */ | ||
630 | azx_writeb(chip, INTCTL, | ||
631 | azx_readb(chip, INTCTL) & ~(1 << azx_dev->index)); | ||
632 | } | ||
633 | |||
634 | |||
635 | /* | ||
636 | * initialize the chip | ||
637 | */ | ||
638 | static void azx_init_chip(azx_t *chip) | ||
639 | { | ||
640 | unsigned char tcsel_reg; | ||
641 | |||
642 | /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) | ||
643 | * TCSEL == Traffic Class Select Register, which sets PCI express QOS | ||
644 | * Ensuring these bits are 0 clears playback static on some HD Audio codecs | ||
645 | */ | ||
646 | pci_read_config_byte (chip->pci, ICH6_PCIREG_TCSEL, &tcsel_reg); | ||
647 | pci_write_config_byte(chip->pci, ICH6_PCIREG_TCSEL, tcsel_reg & 0xf8); | ||
648 | |||
649 | /* reset controller */ | ||
650 | azx_reset(chip); | ||
651 | |||
652 | /* initialize interrupts */ | ||
653 | azx_int_clear(chip); | ||
654 | azx_int_enable(chip); | ||
655 | |||
656 | /* initialize the codec command I/O */ | ||
657 | azx_init_cmd_io(chip); | ||
658 | |||
659 | #ifdef USE_POSBUF | ||
660 | /* program the position buffer */ | ||
661 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); | ||
662 | azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); | ||
663 | #endif | ||
664 | } | ||
665 | |||
666 | |||
667 | /* | ||
668 | * interrupt handler | ||
669 | */ | ||
670 | static irqreturn_t azx_interrupt(int irq, void* dev_id, struct pt_regs *regs) | ||
671 | { | ||
672 | azx_t *chip = dev_id; | ||
673 | azx_dev_t *azx_dev; | ||
674 | u32 status; | ||
675 | int i; | ||
676 | |||
677 | spin_lock(&chip->reg_lock); | ||
678 | |||
679 | status = azx_readl(chip, INTSTS); | ||
680 | if (status == 0) { | ||
681 | spin_unlock(&chip->reg_lock); | ||
682 | return IRQ_NONE; | ||
683 | } | ||
684 | |||
685 | for (i = 0; i < MAX_ICH6_DEV; i++) { | ||
686 | azx_dev = &chip->azx_dev[i]; | ||
687 | if (status & azx_dev->sd_int_sta_mask) { | ||
688 | azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); | ||
689 | if (azx_dev->substream && azx_dev->running) { | ||
690 | spin_unlock(&chip->reg_lock); | ||
691 | snd_pcm_period_elapsed(azx_dev->substream); | ||
692 | spin_lock(&chip->reg_lock); | ||
693 | } | ||
694 | } | ||
695 | } | ||
696 | |||
697 | /* clear rirb int */ | ||
698 | status = azx_readb(chip, RIRBSTS); | ||
699 | if (status & RIRB_INT_MASK) { | ||
700 | if (status & RIRB_INT_RESPONSE) | ||
701 | azx_update_rirb(chip); | ||
702 | azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); | ||
703 | } | ||
704 | |||
705 | #if 0 | ||
706 | /* clear state status int */ | ||
707 | if (azx_readb(chip, STATESTS) & 0x04) | ||
708 | azx_writeb(chip, STATESTS, 0x04); | ||
709 | #endif | ||
710 | spin_unlock(&chip->reg_lock); | ||
711 | |||
712 | return IRQ_HANDLED; | ||
713 | } | ||
714 | |||
715 | |||
716 | /* | ||
717 | * set up BDL entries | ||
718 | */ | ||
719 | static void azx_setup_periods(azx_dev_t *azx_dev) | ||
720 | { | ||
721 | u32 *bdl = azx_dev->bdl; | ||
722 | dma_addr_t dma_addr = azx_dev->substream->runtime->dma_addr; | ||
723 | int idx; | ||
724 | |||
725 | /* reset BDL address */ | ||
726 | azx_sd_writel(azx_dev, SD_BDLPL, 0); | ||
727 | azx_sd_writel(azx_dev, SD_BDLPU, 0); | ||
728 | |||
729 | /* program the initial BDL entries */ | ||
730 | for (idx = 0; idx < azx_dev->frags; idx++) { | ||
731 | unsigned int off = idx << 2; /* 4 dword step */ | ||
732 | dma_addr_t addr = dma_addr + idx * azx_dev->fragsize; | ||
733 | /* program the address field of the BDL entry */ | ||
734 | bdl[off] = cpu_to_le32((u32)addr); | ||
735 | bdl[off+1] = cpu_to_le32(upper_32bit(addr)); | ||
736 | |||
737 | /* program the size field of the BDL entry */ | ||
738 | bdl[off+2] = cpu_to_le32(azx_dev->fragsize); | ||
739 | |||
740 | /* program the IOC to enable interrupt when buffer completes */ | ||
741 | bdl[off+3] = cpu_to_le32(0x01); | ||
742 | } | ||
743 | } | ||
744 | |||
745 | /* | ||
746 | * set up the SD for streaming | ||
747 | */ | ||
748 | static int azx_setup_controller(azx_t *chip, azx_dev_t *azx_dev) | ||
749 | { | ||
750 | unsigned char val; | ||
751 | int timeout; | ||
752 | |||
753 | /* make sure the run bit is zero for SD */ | ||
754 | azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & ~SD_CTL_DMA_START); | ||
755 | /* reset stream */ | ||
756 | azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | SD_CTL_STREAM_RESET); | ||
757 | udelay(3); | ||
758 | timeout = 300; | ||
759 | while (!((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) && | ||
760 | --timeout) | ||
761 | ; | ||
762 | val &= ~SD_CTL_STREAM_RESET; | ||
763 | azx_sd_writeb(azx_dev, SD_CTL, val); | ||
764 | udelay(3); | ||
765 | |||
766 | timeout = 300; | ||
767 | /* waiting for hardware to report that the stream is out of reset */ | ||
768 | while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) && | ||
769 | --timeout) | ||
770 | ; | ||
771 | |||
772 | /* program the stream_tag */ | ||
773 | azx_sd_writel(azx_dev, SD_CTL, | ||
774 | (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK) | | ||
775 | (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT)); | ||
776 | |||
777 | /* program the length of samples in cyclic buffer */ | ||
778 | azx_sd_writel(azx_dev, SD_CBL, azx_dev->bufsize); | ||
779 | |||
780 | /* program the stream format */ | ||
781 | /* this value needs to be the same as the one programmed */ | ||
782 | azx_sd_writew(azx_dev, SD_FORMAT, azx_dev->format_val); | ||
783 | |||
784 | /* program the stream LVI (last valid index) of the BDL */ | ||
785 | azx_sd_writew(azx_dev, SD_LVI, azx_dev->frags - 1); | ||
786 | |||
787 | /* program the BDL address */ | ||
788 | /* lower BDL address */ | ||
789 | azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl_addr); | ||
790 | /* upper BDL address */ | ||
791 | azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr)); | ||
792 | |||
793 | #ifdef USE_POSBUF | ||
794 | /* enable the position buffer */ | ||
795 | if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) | ||
796 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); | ||
797 | #endif | ||
798 | /* set the interrupt enable bits in the descriptor control register */ | ||
799 | azx_sd_writel(azx_dev, SD_CTL, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK); | ||
800 | |||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | |||
805 | /* | ||
806 | * Codec initialization | ||
807 | */ | ||
808 | |||
809 | static int __devinit azx_codec_create(azx_t *chip, const char *model) | ||
810 | { | ||
811 | struct hda_bus_template bus_temp; | ||
812 | int c, codecs, err; | ||
813 | |||
814 | memset(&bus_temp, 0, sizeof(bus_temp)); | ||
815 | bus_temp.private_data = chip; | ||
816 | bus_temp.modelname = model; | ||
817 | bus_temp.pci = chip->pci; | ||
818 | bus_temp.ops.command = azx_send_cmd; | ||
819 | bus_temp.ops.get_response = azx_get_response; | ||
820 | |||
821 | if ((err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus)) < 0) | ||
822 | return err; | ||
823 | |||
824 | codecs = 0; | ||
825 | for (c = 0; c < AZX_MAX_CODECS; c++) { | ||
826 | if (chip->codec_mask & (1 << c)) { | ||
827 | err = snd_hda_codec_new(chip->bus, c, NULL); | ||
828 | if (err < 0) | ||
829 | continue; | ||
830 | codecs++; | ||
831 | } | ||
832 | } | ||
833 | if (! codecs) { | ||
834 | snd_printk(KERN_ERR SFX "no codecs initialized\n"); | ||
835 | return -ENXIO; | ||
836 | } | ||
837 | |||
838 | return 0; | ||
839 | } | ||
840 | |||
841 | |||
842 | /* | ||
843 | * PCM support | ||
844 | */ | ||
845 | |||
846 | /* assign a stream for the PCM */ | ||
847 | static inline azx_dev_t *azx_assign_device(azx_t *chip, int stream) | ||
848 | { | ||
849 | int dev, i; | ||
850 | dev = stream == SNDRV_PCM_STREAM_PLAYBACK ? 4 : 0; | ||
851 | for (i = 0; i < 4; i++, dev++) | ||
852 | if (! chip->azx_dev[dev].opened) { | ||
853 | chip->azx_dev[dev].opened = 1; | ||
854 | return &chip->azx_dev[dev]; | ||
855 | } | ||
856 | return NULL; | ||
857 | } | ||
858 | |||
859 | /* release the assigned stream */ | ||
860 | static inline void azx_release_device(azx_dev_t *azx_dev) | ||
861 | { | ||
862 | azx_dev->opened = 0; | ||
863 | } | ||
864 | |||
865 | static snd_pcm_hardware_t azx_pcm_hw = { | ||
866 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | ||
867 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
868 | SNDRV_PCM_INFO_MMAP_VALID | | ||
869 | SNDRV_PCM_INFO_PAUSE | | ||
870 | SNDRV_PCM_INFO_RESUME), | ||
871 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
872 | .rates = SNDRV_PCM_RATE_48000, | ||
873 | .rate_min = 48000, | ||
874 | .rate_max = 48000, | ||
875 | .channels_min = 2, | ||
876 | .channels_max = 2, | ||
877 | .buffer_bytes_max = AZX_MAX_BUF_SIZE, | ||
878 | .period_bytes_min = 128, | ||
879 | .period_bytes_max = AZX_MAX_BUF_SIZE / 2, | ||
880 | .periods_min = 2, | ||
881 | .periods_max = AZX_MAX_FRAG, | ||
882 | .fifo_size = 0, | ||
883 | }; | ||
884 | |||
885 | struct azx_pcm { | ||
886 | azx_t *chip; | ||
887 | struct hda_codec *codec; | ||
888 | struct hda_pcm_stream *hinfo[2]; | ||
889 | }; | ||
890 | |||
891 | static int azx_pcm_open(snd_pcm_substream_t *substream) | ||
892 | { | ||
893 | struct azx_pcm *apcm = snd_pcm_substream_chip(substream); | ||
894 | struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; | ||
895 | azx_t *chip = apcm->chip; | ||
896 | azx_dev_t *azx_dev; | ||
897 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
898 | unsigned long flags; | ||
899 | int err; | ||
900 | |||
901 | down(&chip->open_mutex); | ||
902 | azx_dev = azx_assign_device(chip, substream->stream); | ||
903 | if (azx_dev == NULL) { | ||
904 | up(&chip->open_mutex); | ||
905 | return -EBUSY; | ||
906 | } | ||
907 | runtime->hw = azx_pcm_hw; | ||
908 | runtime->hw.channels_min = hinfo->channels_min; | ||
909 | runtime->hw.channels_max = hinfo->channels_max; | ||
910 | runtime->hw.formats = hinfo->formats; | ||
911 | runtime->hw.rates = hinfo->rates; | ||
912 | snd_pcm_limit_hw_rates(runtime); | ||
913 | snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); | ||
914 | if ((err = hinfo->ops.open(hinfo, apcm->codec, substream)) < 0) { | ||
915 | azx_release_device(azx_dev); | ||
916 | up(&chip->open_mutex); | ||
917 | return err; | ||
918 | } | ||
919 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
920 | azx_dev->substream = substream; | ||
921 | azx_dev->running = 0; | ||
922 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
923 | |||
924 | runtime->private_data = azx_dev; | ||
925 | up(&chip->open_mutex); | ||
926 | return 0; | ||
927 | } | ||
928 | |||
929 | static int azx_pcm_close(snd_pcm_substream_t *substream) | ||
930 | { | ||
931 | struct azx_pcm *apcm = snd_pcm_substream_chip(substream); | ||
932 | struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; | ||
933 | azx_t *chip = apcm->chip; | ||
934 | azx_dev_t *azx_dev = get_azx_dev(substream); | ||
935 | unsigned long flags; | ||
936 | |||
937 | down(&chip->open_mutex); | ||
938 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
939 | azx_dev->substream = NULL; | ||
940 | azx_dev->running = 0; | ||
941 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
942 | azx_release_device(azx_dev); | ||
943 | hinfo->ops.close(hinfo, apcm->codec, substream); | ||
944 | up(&chip->open_mutex); | ||
945 | return 0; | ||
946 | } | ||
947 | |||
948 | static int azx_pcm_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *hw_params) | ||
949 | { | ||
950 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); | ||
951 | } | ||
952 | |||
953 | static int azx_pcm_hw_free(snd_pcm_substream_t *substream) | ||
954 | { | ||
955 | struct azx_pcm *apcm = snd_pcm_substream_chip(substream); | ||
956 | azx_dev_t *azx_dev = get_azx_dev(substream); | ||
957 | struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; | ||
958 | |||
959 | /* reset BDL address */ | ||
960 | azx_sd_writel(azx_dev, SD_BDLPL, 0); | ||
961 | azx_sd_writel(azx_dev, SD_BDLPU, 0); | ||
962 | azx_sd_writel(azx_dev, SD_CTL, 0); | ||
963 | |||
964 | hinfo->ops.cleanup(hinfo, apcm->codec, substream); | ||
965 | |||
966 | return snd_pcm_lib_free_pages(substream); | ||
967 | } | ||
968 | |||
969 | static int azx_pcm_prepare(snd_pcm_substream_t *substream) | ||
970 | { | ||
971 | struct azx_pcm *apcm = snd_pcm_substream_chip(substream); | ||
972 | azx_t *chip = apcm->chip; | ||
973 | azx_dev_t *azx_dev = get_azx_dev(substream); | ||
974 | struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; | ||
975 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
976 | |||
977 | azx_dev->bufsize = snd_pcm_lib_buffer_bytes(substream); | ||
978 | azx_dev->fragsize = snd_pcm_lib_period_bytes(substream); | ||
979 | azx_dev->frags = azx_dev->bufsize / azx_dev->fragsize; | ||
980 | azx_dev->format_val = snd_hda_calc_stream_format(runtime->rate, | ||
981 | runtime->channels, | ||
982 | runtime->format, | ||
983 | hinfo->maxbps); | ||
984 | if (! azx_dev->format_val) { | ||
985 | snd_printk(KERN_ERR SFX "invalid format_val, rate=%d, ch=%d, format=%d\n", | ||
986 | runtime->rate, runtime->channels, runtime->format); | ||
987 | return -EINVAL; | ||
988 | } | ||
989 | |||
990 | snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, format=0x%x\n", | ||
991 | azx_dev->bufsize, azx_dev->fragsize, azx_dev->format_val); | ||
992 | azx_setup_periods(azx_dev); | ||
993 | azx_setup_controller(chip, azx_dev); | ||
994 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
995 | azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1; | ||
996 | else | ||
997 | azx_dev->fifo_size = 0; | ||
998 | |||
999 | return hinfo->ops.prepare(hinfo, apcm->codec, azx_dev->stream_tag, | ||
1000 | azx_dev->format_val, substream); | ||
1001 | } | ||
1002 | |||
1003 | static int azx_pcm_trigger(snd_pcm_substream_t *substream, int cmd) | ||
1004 | { | ||
1005 | struct azx_pcm *apcm = snd_pcm_substream_chip(substream); | ||
1006 | azx_dev_t *azx_dev = get_azx_dev(substream); | ||
1007 | azx_t *chip = apcm->chip; | ||
1008 | int err = 0; | ||
1009 | |||
1010 | spin_lock(&chip->reg_lock); | ||
1011 | switch (cmd) { | ||
1012 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
1013 | case SNDRV_PCM_TRIGGER_RESUME: | ||
1014 | case SNDRV_PCM_TRIGGER_START: | ||
1015 | azx_stream_start(chip, azx_dev); | ||
1016 | azx_dev->running = 1; | ||
1017 | break; | ||
1018 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
1019 | case SNDRV_PCM_TRIGGER_STOP: | ||
1020 | azx_stream_stop(chip, azx_dev); | ||
1021 | azx_dev->running = 0; | ||
1022 | break; | ||
1023 | default: | ||
1024 | err = -EINVAL; | ||
1025 | } | ||
1026 | spin_unlock(&chip->reg_lock); | ||
1027 | if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH || | ||
1028 | cmd == SNDRV_PCM_TRIGGER_STOP) { | ||
1029 | int timeout = 5000; | ||
1030 | while (azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START && --timeout) | ||
1031 | ; | ||
1032 | } | ||
1033 | return err; | ||
1034 | } | ||
1035 | |||
1036 | static snd_pcm_uframes_t azx_pcm_pointer(snd_pcm_substream_t *substream) | ||
1037 | { | ||
1038 | azx_dev_t *azx_dev = get_azx_dev(substream); | ||
1039 | unsigned int pos; | ||
1040 | |||
1041 | #ifdef USE_POSBUF | ||
1042 | /* use the position buffer */ | ||
1043 | pos = *azx_dev->posbuf; | ||
1044 | #else | ||
1045 | /* read LPIB */ | ||
1046 | pos = azx_sd_readl(azx_dev, SD_LPIB) + azx_dev->fifo_size; | ||
1047 | #endif | ||
1048 | if (pos >= azx_dev->bufsize) | ||
1049 | pos = 0; | ||
1050 | return bytes_to_frames(substream->runtime, pos); | ||
1051 | } | ||
1052 | |||
1053 | static snd_pcm_ops_t azx_pcm_ops = { | ||
1054 | .open = azx_pcm_open, | ||
1055 | .close = azx_pcm_close, | ||
1056 | .ioctl = snd_pcm_lib_ioctl, | ||
1057 | .hw_params = azx_pcm_hw_params, | ||
1058 | .hw_free = azx_pcm_hw_free, | ||
1059 | .prepare = azx_pcm_prepare, | ||
1060 | .trigger = azx_pcm_trigger, | ||
1061 | .pointer = azx_pcm_pointer, | ||
1062 | }; | ||
1063 | |||
1064 | static void azx_pcm_free(snd_pcm_t *pcm) | ||
1065 | { | ||
1066 | kfree(pcm->private_data); | ||
1067 | } | ||
1068 | |||
1069 | static int __devinit create_codec_pcm(azx_t *chip, struct hda_codec *codec, | ||
1070 | struct hda_pcm *cpcm, int pcm_dev) | ||
1071 | { | ||
1072 | int err; | ||
1073 | snd_pcm_t *pcm; | ||
1074 | struct azx_pcm *apcm; | ||
1075 | |||
1076 | snd_assert(cpcm->stream[0].substreams || cpcm->stream[1].substreams, return -EINVAL); | ||
1077 | snd_assert(cpcm->name, return -EINVAL); | ||
1078 | |||
1079 | err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, | ||
1080 | cpcm->stream[0].substreams, cpcm->stream[1].substreams, | ||
1081 | &pcm); | ||
1082 | if (err < 0) | ||
1083 | return err; | ||
1084 | strcpy(pcm->name, cpcm->name); | ||
1085 | apcm = kmalloc(sizeof(*apcm), GFP_KERNEL); | ||
1086 | if (apcm == NULL) | ||
1087 | return -ENOMEM; | ||
1088 | apcm->chip = chip; | ||
1089 | apcm->codec = codec; | ||
1090 | apcm->hinfo[0] = &cpcm->stream[0]; | ||
1091 | apcm->hinfo[1] = &cpcm->stream[1]; | ||
1092 | pcm->private_data = apcm; | ||
1093 | pcm->private_free = azx_pcm_free; | ||
1094 | if (cpcm->stream[0].substreams) | ||
1095 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops); | ||
1096 | if (cpcm->stream[1].substreams) | ||
1097 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops); | ||
1098 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
1099 | snd_dma_pci_data(chip->pci), | ||
1100 | 1024 * 64, 1024 * 128); | ||
1101 | chip->pcm[pcm_dev] = pcm; | ||
1102 | |||
1103 | return 0; | ||
1104 | } | ||
1105 | |||
1106 | static int __devinit azx_pcm_create(azx_t *chip) | ||
1107 | { | ||
1108 | struct list_head *p; | ||
1109 | struct hda_codec *codec; | ||
1110 | int c, err; | ||
1111 | int pcm_dev; | ||
1112 | |||
1113 | if ((err = snd_hda_build_pcms(chip->bus)) < 0) | ||
1114 | return err; | ||
1115 | |||
1116 | pcm_dev = 0; | ||
1117 | list_for_each(p, &chip->bus->codec_list) { | ||
1118 | codec = list_entry(p, struct hda_codec, list); | ||
1119 | for (c = 0; c < codec->num_pcms; c++) { | ||
1120 | if (pcm_dev >= AZX_MAX_PCMS) { | ||
1121 | snd_printk(KERN_ERR SFX "Too many PCMs\n"); | ||
1122 | return -EINVAL; | ||
1123 | } | ||
1124 | err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev); | ||
1125 | if (err < 0) | ||
1126 | return err; | ||
1127 | pcm_dev++; | ||
1128 | } | ||
1129 | } | ||
1130 | return 0; | ||
1131 | } | ||
1132 | |||
1133 | /* | ||
1134 | * mixer creation - all stuff is implemented in hda module | ||
1135 | */ | ||
1136 | static int __devinit azx_mixer_create(azx_t *chip) | ||
1137 | { | ||
1138 | return snd_hda_build_controls(chip->bus); | ||
1139 | } | ||
1140 | |||
1141 | |||
1142 | /* | ||
1143 | * initialize SD streams | ||
1144 | */ | ||
1145 | static int __devinit azx_init_stream(azx_t *chip) | ||
1146 | { | ||
1147 | int i; | ||
1148 | |||
1149 | /* initialize each stream (aka device) | ||
1150 | * assign the starting bdl address to each stream (device) and initialize | ||
1151 | */ | ||
1152 | for (i = 0; i < MAX_ICH6_DEV; i++) { | ||
1153 | unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4); | ||
1154 | azx_dev_t *azx_dev = &chip->azx_dev[i]; | ||
1155 | azx_dev->bdl = (u32 *)(chip->bdl.area + off); | ||
1156 | azx_dev->bdl_addr = chip->bdl.addr + off; | ||
1157 | #ifdef USE_POSBUF | ||
1158 | azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8); | ||
1159 | #endif | ||
1160 | /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ | ||
1161 | azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); | ||
1162 | /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ | ||
1163 | azx_dev->sd_int_sta_mask = 1 << i; | ||
1164 | /* stream tag: must be non-zero and unique */ | ||
1165 | azx_dev->index = i; | ||
1166 | azx_dev->stream_tag = i + 1; | ||
1167 | } | ||
1168 | |||
1169 | return 0; | ||
1170 | } | ||
1171 | |||
1172 | |||
1173 | #ifdef CONFIG_PM | ||
1174 | /* | ||
1175 | * power management | ||
1176 | */ | ||
1177 | static int azx_suspend(snd_card_t *card, pm_message_t state) | ||
1178 | { | ||
1179 | azx_t *chip = card->pm_private_data; | ||
1180 | int i; | ||
1181 | |||
1182 | for (i = 0; i < chip->pcm_devs; i++) | ||
1183 | if (chip->pcm[i]) | ||
1184 | snd_pcm_suspend_all(chip->pcm[i]); | ||
1185 | snd_hda_suspend(chip->bus, state); | ||
1186 | azx_free_cmd_io(chip); | ||
1187 | pci_disable_device(chip->pci); | ||
1188 | return 0; | ||
1189 | } | ||
1190 | |||
1191 | static int azx_resume(snd_card_t *card) | ||
1192 | { | ||
1193 | azx_t *chip = card->pm_private_data; | ||
1194 | |||
1195 | pci_enable_device(chip->pci); | ||
1196 | pci_set_master(chip->pci); | ||
1197 | azx_init_chip(chip); | ||
1198 | snd_hda_resume(chip->bus); | ||
1199 | return 0; | ||
1200 | } | ||
1201 | #endif /* CONFIG_PM */ | ||
1202 | |||
1203 | |||
1204 | /* | ||
1205 | * destructor | ||
1206 | */ | ||
1207 | static int azx_free(azx_t *chip) | ||
1208 | { | ||
1209 | if (chip->remap_addr) { | ||
1210 | int i; | ||
1211 | |||
1212 | for (i = 0; i < MAX_ICH6_DEV; i++) | ||
1213 | azx_stream_stop(chip, &chip->azx_dev[i]); | ||
1214 | |||
1215 | /* disable interrupts */ | ||
1216 | azx_int_disable(chip); | ||
1217 | azx_int_clear(chip); | ||
1218 | |||
1219 | /* disable CORB/RIRB */ | ||
1220 | azx_free_cmd_io(chip); | ||
1221 | |||
1222 | /* disable position buffer */ | ||
1223 | azx_writel(chip, DPLBASE, 0); | ||
1224 | azx_writel(chip, DPUBASE, 0); | ||
1225 | |||
1226 | /* wait a little for interrupts to finish */ | ||
1227 | msleep(1); | ||
1228 | |||
1229 | iounmap(chip->remap_addr); | ||
1230 | } | ||
1231 | |||
1232 | if (chip->irq >= 0) | ||
1233 | free_irq(chip->irq, (void*)chip); | ||
1234 | |||
1235 | if (chip->bdl.area) | ||
1236 | snd_dma_free_pages(&chip->bdl); | ||
1237 | if (chip->rb.area) | ||
1238 | snd_dma_free_pages(&chip->rb); | ||
1239 | #ifdef USE_POSBUF | ||
1240 | if (chip->posbuf.area) | ||
1241 | snd_dma_free_pages(&chip->posbuf); | ||
1242 | #endif | ||
1243 | pci_release_regions(chip->pci); | ||
1244 | pci_disable_device(chip->pci); | ||
1245 | kfree(chip); | ||
1246 | |||
1247 | return 0; | ||
1248 | } | ||
1249 | |||
1250 | static int azx_dev_free(snd_device_t *device) | ||
1251 | { | ||
1252 | return azx_free(device->device_data); | ||
1253 | } | ||
1254 | |||
1255 | /* | ||
1256 | * constructor | ||
1257 | */ | ||
1258 | static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, azx_t **rchip) | ||
1259 | { | ||
1260 | azx_t *chip; | ||
1261 | int err = 0; | ||
1262 | static snd_device_ops_t ops = { | ||
1263 | .dev_free = azx_dev_free, | ||
1264 | }; | ||
1265 | |||
1266 | *rchip = NULL; | ||
1267 | |||
1268 | if ((err = pci_enable_device(pci)) < 0) | ||
1269 | return err; | ||
1270 | |||
1271 | chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); | ||
1272 | |||
1273 | if (NULL == chip) { | ||
1274 | snd_printk(KERN_ERR SFX "cannot allocate chip\n"); | ||
1275 | pci_disable_device(pci); | ||
1276 | return -ENOMEM; | ||
1277 | } | ||
1278 | |||
1279 | spin_lock_init(&chip->reg_lock); | ||
1280 | init_MUTEX(&chip->open_mutex); | ||
1281 | chip->card = card; | ||
1282 | chip->pci = pci; | ||
1283 | chip->irq = -1; | ||
1284 | |||
1285 | if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) { | ||
1286 | kfree(chip); | ||
1287 | pci_disable_device(pci); | ||
1288 | return err; | ||
1289 | } | ||
1290 | |||
1291 | chip->addr = pci_resource_start(pci,0); | ||
1292 | chip->remap_addr = ioremap_nocache(chip->addr, pci_resource_len(pci,0)); | ||
1293 | if (chip->remap_addr == NULL) { | ||
1294 | snd_printk(KERN_ERR SFX "ioremap error\n"); | ||
1295 | err = -ENXIO; | ||
1296 | goto errout; | ||
1297 | } | ||
1298 | |||
1299 | if (request_irq(pci->irq, azx_interrupt, SA_INTERRUPT|SA_SHIRQ, | ||
1300 | "HDA Intel", (void*)chip)) { | ||
1301 | snd_printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq); | ||
1302 | err = -EBUSY; | ||
1303 | goto errout; | ||
1304 | } | ||
1305 | chip->irq = pci->irq; | ||
1306 | |||
1307 | pci_set_master(pci); | ||
1308 | synchronize_irq(chip->irq); | ||
1309 | |||
1310 | /* allocate memory for the BDL for each stream */ | ||
1311 | if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), | ||
1312 | PAGE_SIZE, &chip->bdl)) < 0) { | ||
1313 | snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); | ||
1314 | goto errout; | ||
1315 | } | ||
1316 | #ifdef USE_POSBUF | ||
1317 | /* allocate memory for the position buffer */ | ||
1318 | if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), | ||
1319 | MAX_ICH6_DEV * 8, &chip->posbuf)) < 0) { | ||
1320 | snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); | ||
1321 | goto errout; | ||
1322 | } | ||
1323 | #endif | ||
1324 | /* allocate CORB/RIRB */ | ||
1325 | if ((err = azx_alloc_cmd_io(chip)) < 0) | ||
1326 | goto errout; | ||
1327 | |||
1328 | /* initialize streams */ | ||
1329 | azx_init_stream(chip); | ||
1330 | |||
1331 | /* initialize chip */ | ||
1332 | azx_init_chip(chip); | ||
1333 | |||
1334 | /* codec detection */ | ||
1335 | if (! chip->codec_mask) { | ||
1336 | snd_printk(KERN_ERR SFX "no codecs found!\n"); | ||
1337 | err = -ENODEV; | ||
1338 | goto errout; | ||
1339 | } | ||
1340 | |||
1341 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) <0) { | ||
1342 | snd_printk(KERN_ERR SFX "Error creating device [card]!\n"); | ||
1343 | goto errout; | ||
1344 | } | ||
1345 | |||
1346 | *rchip = chip; | ||
1347 | return 0; | ||
1348 | |||
1349 | errout: | ||
1350 | azx_free(chip); | ||
1351 | return err; | ||
1352 | } | ||
1353 | |||
1354 | static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | ||
1355 | { | ||
1356 | static int dev; | ||
1357 | snd_card_t *card; | ||
1358 | azx_t *chip; | ||
1359 | int err = 0; | ||
1360 | |||
1361 | if (dev >= SNDRV_CARDS) | ||
1362 | return -ENODEV; | ||
1363 | if (! enable[dev]) { | ||
1364 | dev++; | ||
1365 | return -ENOENT; | ||
1366 | } | ||
1367 | |||
1368 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); | ||
1369 | if (NULL == card) { | ||
1370 | snd_printk(KERN_ERR SFX "Error creating card!\n"); | ||
1371 | return -ENOMEM; | ||
1372 | } | ||
1373 | |||
1374 | if ((err = azx_create(card, pci, &chip)) < 0) { | ||
1375 | snd_card_free(card); | ||
1376 | return err; | ||
1377 | } | ||
1378 | |||
1379 | strcpy(card->driver, "HDA-Intel"); | ||
1380 | strcpy(card->shortname, "HDA Intel"); | ||
1381 | sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->addr, chip->irq); | ||
1382 | |||
1383 | /* create codec instances */ | ||
1384 | if ((err = azx_codec_create(chip, model[dev])) < 0) { | ||
1385 | snd_card_free(card); | ||
1386 | return err; | ||
1387 | } | ||
1388 | |||
1389 | /* create PCM streams */ | ||
1390 | if ((err = azx_pcm_create(chip)) < 0) { | ||
1391 | snd_card_free(card); | ||
1392 | return err; | ||
1393 | } | ||
1394 | |||
1395 | /* create mixer controls */ | ||
1396 | if ((err = azx_mixer_create(chip)) < 0) { | ||
1397 | snd_card_free(card); | ||
1398 | return err; | ||
1399 | } | ||
1400 | |||
1401 | snd_card_set_pm_callback(card, azx_suspend, azx_resume, chip); | ||
1402 | snd_card_set_dev(card, &pci->dev); | ||
1403 | |||
1404 | if ((err = snd_card_register(card)) < 0) { | ||
1405 | snd_card_free(card); | ||
1406 | return err; | ||
1407 | } | ||
1408 | |||
1409 | pci_set_drvdata(pci, card); | ||
1410 | dev++; | ||
1411 | |||
1412 | return err; | ||
1413 | } | ||
1414 | |||
1415 | static void __devexit azx_remove(struct pci_dev *pci) | ||
1416 | { | ||
1417 | snd_card_free(pci_get_drvdata(pci)); | ||
1418 | pci_set_drvdata(pci, NULL); | ||
1419 | } | ||
1420 | |||
1421 | /* PCI IDs */ | ||
1422 | static struct pci_device_id azx_ids[] = { | ||
1423 | { 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH6 */ | ||
1424 | { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH7 */ | ||
1425 | { 0, } | ||
1426 | }; | ||
1427 | MODULE_DEVICE_TABLE(pci, azx_ids); | ||
1428 | |||
1429 | /* pci_driver definition */ | ||
1430 | static struct pci_driver driver = { | ||
1431 | .name = "HDA Intel", | ||
1432 | .id_table = azx_ids, | ||
1433 | .probe = azx_probe, | ||
1434 | .remove = __devexit_p(azx_remove), | ||
1435 | SND_PCI_PM_CALLBACKS | ||
1436 | }; | ||
1437 | |||
1438 | static int __init alsa_card_azx_init(void) | ||
1439 | { | ||
1440 | return pci_module_init(&driver); | ||
1441 | } | ||
1442 | |||
1443 | static void __exit alsa_card_azx_exit(void) | ||
1444 | { | ||
1445 | pci_unregister_driver(&driver); | ||
1446 | } | ||
1447 | |||
1448 | module_init(alsa_card_azx_init) | ||
1449 | module_exit(alsa_card_azx_exit) | ||
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h new file mode 100644 index 000000000000..7c7b849875a0 --- /dev/null +++ b/sound/pci/hda/hda_local.h | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | * Universal Interface for Intel High Definition Audio Codec | ||
3 | * | ||
4 | * Local helper functions | ||
5 | * | ||
6 | * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the Free | ||
10 | * Software Foundation; either version 2 of the License, or (at your option) | ||
11 | * any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along with | ||
19 | * this program; if not, write to the Free Software Foundation, Inc., 59 | ||
20 | * Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
21 | */ | ||
22 | |||
23 | #ifndef __SOUND_HDA_LOCAL_H | ||
24 | #define __SOUND_HDA_LOCAL_H | ||
25 | |||
26 | /* | ||
27 | * for mixer controls | ||
28 | */ | ||
29 | #define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19)) | ||
30 | #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ | ||
31 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ | ||
32 | .info = snd_hda_mixer_amp_volume_info, \ | ||
33 | .get = snd_hda_mixer_amp_volume_get, \ | ||
34 | .put = snd_hda_mixer_amp_volume_put, \ | ||
35 | .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) } | ||
36 | #define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \ | ||
37 | HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction) | ||
38 | #define HDA_CODEC_VOLUME_MONO(xname, nid, channel, xindex, direction) \ | ||
39 | HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, channel, xindex, direction) | ||
40 | #define HDA_CODEC_VOLUME(xname, nid, xindex, direction) \ | ||
41 | HDA_CODEC_VOLUME_MONO(xname, nid, 3, xindex, direction) | ||
42 | #define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ | ||
43 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ | ||
44 | .info = snd_hda_mixer_amp_switch_info, \ | ||
45 | .get = snd_hda_mixer_amp_switch_get, \ | ||
46 | .put = snd_hda_mixer_amp_switch_put, \ | ||
47 | .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) } | ||
48 | #define HDA_CODEC_MUTE_IDX(xname, xcidx, nid, xindex, direction) \ | ||
49 | HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, 3, xindex, direction) | ||
50 | #define HDA_CODEC_MUTE_MONO(xname, nid, channel, xindex, direction) \ | ||
51 | HDA_CODEC_MUTE_MONO_IDX(xname, 0, nid, channel, xindex, direction) | ||
52 | #define HDA_CODEC_MUTE(xname, nid, xindex, direction) \ | ||
53 | HDA_CODEC_MUTE_MONO(xname, nid, 3, xindex, direction) | ||
54 | |||
55 | int snd_hda_mixer_amp_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo); | ||
56 | int snd_hda_mixer_amp_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol); | ||
57 | int snd_hda_mixer_amp_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol); | ||
58 | int snd_hda_mixer_amp_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo); | ||
59 | int snd_hda_mixer_amp_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol); | ||
60 | int snd_hda_mixer_amp_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol); | ||
61 | |||
62 | int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid); | ||
63 | int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); | ||
64 | |||
65 | /* | ||
66 | * input MUX helper | ||
67 | */ | ||
68 | #define HDA_MAX_NUM_INPUTS 8 | ||
69 | struct hda_input_mux_item { | ||
70 | const char *label; | ||
71 | unsigned int index; | ||
72 | }; | ||
73 | struct hda_input_mux { | ||
74 | unsigned int num_items; | ||
75 | struct hda_input_mux_item items[HDA_MAX_NUM_INPUTS]; | ||
76 | }; | ||
77 | |||
78 | int snd_hda_input_mux_info(const struct hda_input_mux *imux, snd_ctl_elem_info_t *uinfo); | ||
79 | int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, | ||
80 | snd_ctl_elem_value_t *ucontrol, hda_nid_t nid, | ||
81 | unsigned int *cur_val); | ||
82 | |||
83 | /* | ||
84 | * Multi-channel / digital-out PCM helper | ||
85 | */ | ||
86 | |||
87 | enum { HDA_FRONT, HDA_REAR, HDA_CLFE, HDA_SIDE }; /* index for dac_nidx */ | ||
88 | enum { HDA_DIG_NONE, HDA_DIG_EXCLUSIVE, HDA_DIG_ANALOG_DUP }; /* dig_out_used */ | ||
89 | |||
90 | struct hda_multi_out { | ||
91 | int num_dacs; /* # of DACs, must be more than 1 */ | ||
92 | hda_nid_t *dac_nids; /* DAC list */ | ||
93 | hda_nid_t hp_nid; /* optional DAC for HP, 0 when not exists */ | ||
94 | hda_nid_t dig_out_nid; /* digital out audio widget */ | ||
95 | int max_channels; /* currently supported analog channels */ | ||
96 | int dig_out_used; /* current usage of digital out (HDA_DIG_XXX) */ | ||
97 | }; | ||
98 | |||
99 | int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout); | ||
100 | int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout); | ||
101 | int snd_hda_multi_out_analog_open(struct hda_codec *codec, struct hda_multi_out *mout, | ||
102 | snd_pcm_substream_t *substream); | ||
103 | int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout, | ||
104 | unsigned int stream_tag, | ||
105 | unsigned int format, | ||
106 | snd_pcm_substream_t *substream); | ||
107 | int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_out *mout); | ||
108 | |||
109 | /* | ||
110 | * generic codec parser | ||
111 | */ | ||
112 | int snd_hda_parse_generic_codec(struct hda_codec *codec); | ||
113 | |||
114 | /* | ||
115 | * generic proc interface | ||
116 | */ | ||
117 | #ifdef CONFIG_PROC_FS | ||
118 | int snd_hda_codec_proc_new(struct hda_codec *codec); | ||
119 | #else | ||
120 | static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; } | ||
121 | #endif | ||
122 | |||
123 | /* | ||
124 | * Misc | ||
125 | */ | ||
126 | struct hda_board_config { | ||
127 | const char *modelname; | ||
128 | int config; | ||
129 | unsigned short pci_vendor; | ||
130 | unsigned short pci_device; | ||
131 | }; | ||
132 | |||
133 | int snd_hda_check_board_config(struct hda_codec *codec, struct hda_board_config *tbl); | ||
134 | int snd_hda_add_new_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew); | ||
135 | |||
136 | /* | ||
137 | * power management | ||
138 | */ | ||
139 | #ifdef CONFIG_PM | ||
140 | int snd_hda_resume_ctls(struct hda_codec *codec, snd_kcontrol_new_t *knew); | ||
141 | int snd_hda_resume_spdif_out(struct hda_codec *codec); | ||
142 | int snd_hda_resume_spdif_in(struct hda_codec *codec); | ||
143 | #endif | ||
144 | |||
145 | /* | ||
146 | * unsolicited event handler | ||
147 | */ | ||
148 | |||
149 | #define HDA_UNSOL_QUEUE_SIZE 64 | ||
150 | |||
151 | struct hda_bus_unsolicited { | ||
152 | /* ring buffer */ | ||
153 | u32 queue[HDA_UNSOL_QUEUE_SIZE * 2]; | ||
154 | unsigned int rp, wp; | ||
155 | |||
156 | /* workqueue */ | ||
157 | struct workqueue_struct *workq; | ||
158 | struct work_struct work; | ||
159 | }; | ||
160 | |||
161 | #endif /* __SOUND_HDA_LOCAL_H */ | ||
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h new file mode 100644 index 000000000000..cf6abce42bc9 --- /dev/null +++ b/sound/pci/hda/hda_patch.h | |||
@@ -0,0 +1,17 @@ | |||
1 | /* | ||
2 | * HDA Patches - included by hda_codec.c | ||
3 | */ | ||
4 | |||
5 | /* Realtek codecs */ | ||
6 | extern struct hda_codec_preset snd_hda_preset_realtek[]; | ||
7 | /* C-Media codecs */ | ||
8 | extern struct hda_codec_preset snd_hda_preset_cmedia[]; | ||
9 | /* Analog Devices codecs */ | ||
10 | extern struct hda_codec_preset snd_hda_preset_analog[]; | ||
11 | |||
12 | static const struct hda_codec_preset *hda_preset_tables[] = { | ||
13 | snd_hda_preset_realtek, | ||
14 | snd_hda_preset_cmedia, | ||
15 | snd_hda_preset_analog, | ||
16 | NULL | ||
17 | }; | ||
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c new file mode 100644 index 000000000000..4d5db7faad8d --- /dev/null +++ b/sound/pci/hda/hda_proc.c | |||
@@ -0,0 +1,298 @@ | |||
1 | /* | ||
2 | * Universal Interface for Intel High Definition Audio Codec | ||
3 | * | ||
4 | * Generic proc interface | ||
5 | * | ||
6 | * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> | ||
7 | * | ||
8 | * | ||
9 | * This driver is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This driver is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <sound/core.h> | ||
28 | #include "hda_codec.h" | ||
29 | |||
30 | static const char *get_wid_type_name(unsigned int wid_value) | ||
31 | { | ||
32 | static char *names[16] = { | ||
33 | [AC_WID_AUD_OUT] = "Audio Output", | ||
34 | [AC_WID_AUD_IN] = "Audio Input", | ||
35 | [AC_WID_AUD_MIX] = "Audio Mixer", | ||
36 | [AC_WID_AUD_SEL] = "Audio Selector", | ||
37 | [AC_WID_PIN] = "Pin Complex", | ||
38 | [AC_WID_POWER] = "Power Widget", | ||
39 | [AC_WID_VOL_KNB] = "Volume Knob Widget", | ||
40 | [AC_WID_BEEP] = "Beep Generator Widget", | ||
41 | [AC_WID_VENDOR] = "Vendor Defined Widget", | ||
42 | }; | ||
43 | wid_value &= 0xf; | ||
44 | if (names[wid_value]) | ||
45 | return names[wid_value]; | ||
46 | else | ||
47 | return "UNKOWN Widget"; | ||
48 | } | ||
49 | |||
50 | static void print_amp_caps(snd_info_buffer_t *buffer, | ||
51 | struct hda_codec *codec, hda_nid_t nid, int dir) | ||
52 | { | ||
53 | unsigned int caps; | ||
54 | if (dir == HDA_OUTPUT) | ||
55 | caps = snd_hda_param_read(codec, nid, AC_PAR_AMP_OUT_CAP); | ||
56 | else | ||
57 | caps = snd_hda_param_read(codec, nid, AC_PAR_AMP_IN_CAP); | ||
58 | if (caps == -1 || caps == 0) { | ||
59 | snd_iprintf(buffer, "N/A\n"); | ||
60 | return; | ||
61 | } | ||
62 | snd_iprintf(buffer, "ofs=0x%02x, nsteps=0x%02x, stepsize=0x%02x, mute=%x\n", | ||
63 | caps & AC_AMPCAP_OFFSET, | ||
64 | (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT, | ||
65 | (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT, | ||
66 | (caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT); | ||
67 | } | ||
68 | |||
69 | static void print_amp_vals(snd_info_buffer_t *buffer, | ||
70 | struct hda_codec *codec, hda_nid_t nid, | ||
71 | int dir, int stereo) | ||
72 | { | ||
73 | unsigned int val; | ||
74 | if (stereo) { | ||
75 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, | ||
76 | AC_AMP_GET_LEFT | | ||
77 | (dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : | ||
78 | AC_AMP_GET_INPUT)); | ||
79 | snd_iprintf(buffer, "0x%02x ", val); | ||
80 | } | ||
81 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, | ||
82 | AC_AMP_GET_RIGHT | | ||
83 | (dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : | ||
84 | AC_AMP_GET_INPUT)); | ||
85 | snd_iprintf(buffer, "0x%02x\n", val); | ||
86 | } | ||
87 | |||
88 | static void print_pcm_caps(snd_info_buffer_t *buffer, | ||
89 | struct hda_codec *codec, hda_nid_t nid) | ||
90 | { | ||
91 | unsigned int pcm = snd_hda_param_read(codec, nid, AC_PAR_PCM); | ||
92 | unsigned int stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM); | ||
93 | if (pcm == -1 || stream == -1) { | ||
94 | snd_iprintf(buffer, "N/A\n"); | ||
95 | return; | ||
96 | } | ||
97 | snd_iprintf(buffer, "rates 0x%03x, bits 0x%02x, types 0x%x\n", | ||
98 | pcm & AC_SUPPCM_RATES, (pcm >> 16) & 0xff, stream & 0xf); | ||
99 | } | ||
100 | |||
101 | static const char *get_jack_location(u32 cfg) | ||
102 | { | ||
103 | static char *bases[7] = { | ||
104 | "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom", | ||
105 | }; | ||
106 | static unsigned char specials_idx[] = { | ||
107 | 0x07, 0x08, | ||
108 | 0x17, 0x18, 0x19, | ||
109 | 0x37, 0x38 | ||
110 | }; | ||
111 | static char *specials[] = { | ||
112 | "Rear Panel", "Drive Bar", | ||
113 | "Riser", "HDMI", "ATAPI", | ||
114 | "Mobile-In", "Mobile-Out" | ||
115 | }; | ||
116 | int i; | ||
117 | cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; | ||
118 | if ((cfg & 0x0f) < 7) | ||
119 | return bases[cfg & 0x0f]; | ||
120 | for (i = 0; i < ARRAY_SIZE(specials_idx); i++) { | ||
121 | if (cfg == specials_idx[i]) | ||
122 | return specials[i]; | ||
123 | } | ||
124 | return "UNKNOWN"; | ||
125 | } | ||
126 | |||
127 | static const char *get_jack_connection(u32 cfg) | ||
128 | { | ||
129 | static char *names[16] = { | ||
130 | "Unknown", "1/8", "1/4", "ATAPI", | ||
131 | "RCA", "Optical","Digital", "Analog", | ||
132 | "DIN", "XLR", "RJ11", "Comb", | ||
133 | NULL, NULL, NULL, "Other" | ||
134 | }; | ||
135 | cfg = (cfg & AC_DEFCFG_CONN_TYPE) >> AC_DEFCFG_CONN_TYPE_SHIFT; | ||
136 | if (names[cfg]) | ||
137 | return names[cfg]; | ||
138 | else | ||
139 | return "UNKNOWN"; | ||
140 | } | ||
141 | |||
142 | static const char *get_jack_color(u32 cfg) | ||
143 | { | ||
144 | static char *names[16] = { | ||
145 | "Unknown", "Black", "Grey", "Blue", | ||
146 | "Green", "Red", "Orange", "Yellow", | ||
147 | "Purple", "Pink", NULL, NULL, | ||
148 | NULL, NULL, "White", "Other", | ||
149 | }; | ||
150 | cfg = (cfg & AC_DEFCFG_COLOR) >> AC_DEFCFG_COLOR_SHIFT; | ||
151 | if (names[cfg]) | ||
152 | return names[cfg]; | ||
153 | else | ||
154 | return "UNKNOWN"; | ||
155 | } | ||
156 | |||
157 | static void print_pin_caps(snd_info_buffer_t *buffer, | ||
158 | struct hda_codec *codec, hda_nid_t nid) | ||
159 | { | ||
160 | static char *jack_types[16] = { | ||
161 | "Line Out", "Speaker", "HP Out", "CD", | ||
162 | "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", | ||
163 | "Line In", "Aux", "Mic", "Telephony", | ||
164 | "SPDIF In", "Digitial In", "Reserved", "Other" | ||
165 | }; | ||
166 | static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; | ||
167 | unsigned int caps; | ||
168 | |||
169 | caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | ||
170 | snd_iprintf(buffer, " Pincap 0x08%x:", caps); | ||
171 | if (caps & AC_PINCAP_IN) | ||
172 | snd_iprintf(buffer, " IN"); | ||
173 | if (caps & AC_PINCAP_OUT) | ||
174 | snd_iprintf(buffer, " OUT"); | ||
175 | if (caps & AC_PINCAP_HP_DRV) | ||
176 | snd_iprintf(buffer, " HP"); | ||
177 | snd_iprintf(buffer, "\n"); | ||
178 | caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
179 | snd_iprintf(buffer, " Pin Default 0x%08x: %s at %s %s\n", caps, | ||
180 | jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT], | ||
181 | jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3], | ||
182 | get_jack_location(caps)); | ||
183 | snd_iprintf(buffer, " Conn = %s, Color = %s\n", | ||
184 | get_jack_connection(caps), | ||
185 | get_jack_color(caps)); | ||
186 | } | ||
187 | |||
188 | |||
189 | static void print_codec_info(snd_info_entry_t *entry, snd_info_buffer_t *buffer) | ||
190 | { | ||
191 | struct hda_codec *codec = entry->private_data; | ||
192 | char buf[32]; | ||
193 | hda_nid_t nid; | ||
194 | int i, nodes; | ||
195 | |||
196 | snd_hda_get_codec_name(codec, buf, sizeof(buf)); | ||
197 | snd_iprintf(buffer, "Codec: %s\n", buf); | ||
198 | snd_iprintf(buffer, "Address: %d\n", codec->addr); | ||
199 | snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id); | ||
200 | snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id); | ||
201 | snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id); | ||
202 | snd_iprintf(buffer, "Default PCM: "); | ||
203 | print_pcm_caps(buffer, codec, codec->afg); | ||
204 | snd_iprintf(buffer, "Default Amp-In caps: "); | ||
205 | print_amp_caps(buffer, codec, codec->afg, HDA_INPUT); | ||
206 | snd_iprintf(buffer, "Default Amp-Out caps: "); | ||
207 | print_amp_caps(buffer, codec, codec->afg, HDA_OUTPUT); | ||
208 | |||
209 | nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); | ||
210 | if (! nid || nodes < 0) { | ||
211 | snd_iprintf(buffer, "Invalid AFG subtree\n"); | ||
212 | return; | ||
213 | } | ||
214 | for (i = 0; i < nodes; i++, nid++) { | ||
215 | unsigned int wid_caps = snd_hda_param_read(codec, nid, | ||
216 | AC_PAR_AUDIO_WIDGET_CAP); | ||
217 | unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | ||
218 | snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid, | ||
219 | get_wid_type_name(wid_type), wid_caps); | ||
220 | if (wid_caps & AC_WCAP_STEREO) | ||
221 | snd_iprintf(buffer, " Stereo"); | ||
222 | else | ||
223 | snd_iprintf(buffer, " Mono"); | ||
224 | if (wid_caps & AC_WCAP_DIGITAL) | ||
225 | snd_iprintf(buffer, " Digital"); | ||
226 | if (wid_caps & AC_WCAP_IN_AMP) | ||
227 | snd_iprintf(buffer, " Amp-In"); | ||
228 | if (wid_caps & AC_WCAP_OUT_AMP) | ||
229 | snd_iprintf(buffer, " Amp-Out"); | ||
230 | snd_iprintf(buffer, "\n"); | ||
231 | |||
232 | if (wid_caps & AC_WCAP_IN_AMP) { | ||
233 | snd_iprintf(buffer, " Amp-In caps: "); | ||
234 | print_amp_caps(buffer, codec, nid, HDA_INPUT); | ||
235 | snd_iprintf(buffer, " Amp-In vals: "); | ||
236 | print_amp_vals(buffer, codec, nid, HDA_INPUT, | ||
237 | wid_caps & AC_WCAP_STEREO); | ||
238 | } | ||
239 | if (wid_caps & AC_WCAP_OUT_AMP) { | ||
240 | snd_iprintf(buffer, " Amp-Out caps: "); | ||
241 | print_amp_caps(buffer, codec, nid, HDA_OUTPUT); | ||
242 | snd_iprintf(buffer, " Amp-Out vals: "); | ||
243 | print_amp_vals(buffer, codec, nid, HDA_OUTPUT, | ||
244 | wid_caps & AC_WCAP_STEREO); | ||
245 | } | ||
246 | |||
247 | if (wid_type == AC_WID_PIN) { | ||
248 | unsigned int pinctls; | ||
249 | print_pin_caps(buffer, codec, nid); | ||
250 | pinctls = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
251 | snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls); | ||
252 | if (pinctls & AC_PINCTL_IN_EN) | ||
253 | snd_iprintf(buffer, " IN"); | ||
254 | if (pinctls & AC_PINCTL_OUT_EN) | ||
255 | snd_iprintf(buffer, " OUT"); | ||
256 | if (pinctls & AC_PINCTL_HP_EN) | ||
257 | snd_iprintf(buffer, " HP"); | ||
258 | snd_iprintf(buffer, "\n"); | ||
259 | } | ||
260 | |||
261 | if ((wid_type == AC_WID_AUD_OUT || wid_type == AC_WID_AUD_IN) && | ||
262 | (wid_caps & AC_WCAP_FORMAT_OVRD)) { | ||
263 | snd_iprintf(buffer, " PCM: "); | ||
264 | print_pcm_caps(buffer, codec, nid); | ||
265 | } | ||
266 | |||
267 | if (wid_caps & AC_WCAP_CONN_LIST) { | ||
268 | hda_nid_t conn[HDA_MAX_CONNECTIONS]; | ||
269 | int c, conn_len; | ||
270 | conn_len = snd_hda_get_connections(codec, nid, conn, | ||
271 | HDA_MAX_CONNECTIONS); | ||
272 | snd_iprintf(buffer, " Connection: %d\n", conn_len); | ||
273 | snd_iprintf(buffer, " "); | ||
274 | for (c = 0; c < conn_len; c++) | ||
275 | snd_iprintf(buffer, " 0x%02x", conn[c]); | ||
276 | snd_iprintf(buffer, "\n"); | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * create a proc read | ||
283 | */ | ||
284 | int snd_hda_codec_proc_new(struct hda_codec *codec) | ||
285 | { | ||
286 | char name[32]; | ||
287 | snd_info_entry_t *entry; | ||
288 | int err; | ||
289 | |||
290 | snprintf(name, sizeof(name), "codec#%d", codec->addr); | ||
291 | err = snd_card_proc_new(codec->bus->card, name, &entry); | ||
292 | if (err < 0) | ||
293 | return err; | ||
294 | |||
295 | snd_info_set_text_ops(entry, codec, 32 * 1024, print_codec_info); | ||
296 | return 0; | ||
297 | } | ||
298 | |||
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c new file mode 100644 index 000000000000..75d23849f71a --- /dev/null +++ b/sound/pci/hda/patch_analog.c | |||
@@ -0,0 +1,445 @@ | |||
1 | /* | ||
2 | * HD audio interface patch for AD1986A | ||
3 | * | ||
4 | * Copyright (c) 2005 Takashi Iwai <tiwai@suse.de> | ||
5 | * | ||
6 | * This driver is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This driver is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/pci.h> | ||
26 | #include <sound/core.h> | ||
27 | #include "hda_codec.h" | ||
28 | #include "hda_local.h" | ||
29 | |||
30 | struct ad1986a_spec { | ||
31 | struct semaphore amp_mutex; /* PCM volume/mute control mutex */ | ||
32 | struct hda_multi_out multiout; /* playback */ | ||
33 | unsigned int cur_mux; /* capture source */ | ||
34 | struct hda_pcm pcm_rec[2]; /* PCM information */ | ||
35 | }; | ||
36 | |||
37 | #define AD1986A_SPDIF_OUT 0x02 | ||
38 | #define AD1986A_FRONT_DAC 0x03 | ||
39 | #define AD1986A_SURR_DAC 0x04 | ||
40 | #define AD1986A_CLFE_DAC 0x05 | ||
41 | #define AD1986A_ADC 0x06 | ||
42 | |||
43 | static hda_nid_t ad1986a_dac_nids[3] = { | ||
44 | AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC | ||
45 | }; | ||
46 | |||
47 | static struct hda_input_mux ad1986a_capture_source = { | ||
48 | .num_items = 7, | ||
49 | .items = { | ||
50 | { "Mic", 0x0 }, | ||
51 | { "CD", 0x1 }, | ||
52 | { "Aux", 0x3 }, | ||
53 | { "Line", 0x4 }, | ||
54 | { "Mix", 0x5 }, | ||
55 | { "Mono", 0x6 }, | ||
56 | { "Phone", 0x7 }, | ||
57 | }, | ||
58 | }; | ||
59 | |||
60 | /* | ||
61 | * PCM control | ||
62 | * | ||
63 | * bind volumes/mutes of 3 DACs as a single PCM control for simplicity | ||
64 | */ | ||
65 | |||
66 | #define ad1986a_pcm_amp_vol_info snd_hda_mixer_amp_volume_info | ||
67 | |||
68 | static int ad1986a_pcm_amp_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
69 | { | ||
70 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
71 | struct ad1986a_spec *ad = codec->spec; | ||
72 | |||
73 | down(&ad->amp_mutex); | ||
74 | snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); | ||
75 | up(&ad->amp_mutex); | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static int ad1986a_pcm_amp_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
80 | { | ||
81 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
82 | struct ad1986a_spec *ad = codec->spec; | ||
83 | int i, change = 0; | ||
84 | |||
85 | down(&ad->amp_mutex); | ||
86 | for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { | ||
87 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); | ||
88 | change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); | ||
89 | } | ||
90 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); | ||
91 | up(&ad->amp_mutex); | ||
92 | return change; | ||
93 | } | ||
94 | |||
95 | #define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_volume_info | ||
96 | |||
97 | static int ad1986a_pcm_amp_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
98 | { | ||
99 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
100 | struct ad1986a_spec *ad = codec->spec; | ||
101 | |||
102 | down(&ad->amp_mutex); | ||
103 | snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); | ||
104 | up(&ad->amp_mutex); | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int ad1986a_pcm_amp_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
109 | { | ||
110 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
111 | struct ad1986a_spec *ad = codec->spec; | ||
112 | int i, change = 0; | ||
113 | |||
114 | down(&ad->amp_mutex); | ||
115 | for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { | ||
116 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); | ||
117 | change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | ||
118 | } | ||
119 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); | ||
120 | up(&ad->amp_mutex); | ||
121 | return change; | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * input MUX handling | ||
126 | */ | ||
127 | static int ad1986a_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
128 | { | ||
129 | return snd_hda_input_mux_info(&ad1986a_capture_source, uinfo); | ||
130 | } | ||
131 | |||
132 | static int ad1986a_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
133 | { | ||
134 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
135 | struct ad1986a_spec *spec = codec->spec; | ||
136 | |||
137 | ucontrol->value.enumerated.item[0] = spec->cur_mux; | ||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static int ad1986a_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
142 | { | ||
143 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
144 | struct ad1986a_spec *spec = codec->spec; | ||
145 | |||
146 | return snd_hda_input_mux_put(codec, &ad1986a_capture_source, ucontrol, | ||
147 | AD1986A_ADC, &spec->cur_mux); | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * mixers | ||
152 | */ | ||
153 | static snd_kcontrol_new_t ad1986a_mixers[] = { | ||
154 | { | ||
155 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
156 | .name = "PCM Playback Volume", | ||
157 | .info = ad1986a_pcm_amp_vol_info, | ||
158 | .get = ad1986a_pcm_amp_vol_get, | ||
159 | .put = ad1986a_pcm_amp_vol_put, | ||
160 | .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) | ||
161 | }, | ||
162 | { | ||
163 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
164 | .name = "PCM Playback Switch", | ||
165 | .info = ad1986a_pcm_amp_sw_info, | ||
166 | .get = ad1986a_pcm_amp_sw_get, | ||
167 | .put = ad1986a_pcm_amp_sw_put, | ||
168 | .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) | ||
169 | }, | ||
170 | HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
171 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
172 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT), | ||
173 | HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT), | ||
174 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT), | ||
175 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT), | ||
176 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT), | ||
177 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT), | ||
178 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT), | ||
179 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), | ||
180 | HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), | ||
181 | HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
182 | HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), | ||
183 | HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT), | ||
184 | HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT), | ||
185 | HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT), | ||
186 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), | ||
187 | HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), | ||
188 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x18, 0x0, HDA_OUTPUT), | ||
189 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x18, 0x0, HDA_OUTPUT), | ||
190 | HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT), | ||
191 | HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), | ||
192 | HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), | ||
193 | HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), | ||
194 | { | ||
195 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
196 | .name = "Capture Source", | ||
197 | .info = ad1986a_mux_enum_info, | ||
198 | .get = ad1986a_mux_enum_get, | ||
199 | .put = ad1986a_mux_enum_put, | ||
200 | }, | ||
201 | HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT), | ||
202 | { } /* end */ | ||
203 | }; | ||
204 | |||
205 | /* | ||
206 | * initialization verbs | ||
207 | */ | ||
208 | static struct hda_verb ad1986a_init_verbs[] = { | ||
209 | /* Front, Surround, CLFE DAC; mute as default */ | ||
210 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
211 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
212 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
213 | /* Downmix - off */ | ||
214 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
215 | /* HP, Line-Out, Surround, CLFE selectors */ | ||
216 | {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
217 | {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
218 | {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
219 | {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
220 | /* Mono selector */ | ||
221 | {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
222 | /* Mic selector: Mic 1/2 pin */ | ||
223 | {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
224 | /* Line-in selector: Line-in */ | ||
225 | {0x10, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
226 | /* Mic 1/2 swap */ | ||
227 | {0x11, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
228 | /* Record selector: mic */ | ||
229 | {0x12, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
230 | /* Mic, Phone, CD, Aux, Line-In amp; mute as default */ | ||
231 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
232 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
233 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
234 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
235 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
236 | /* PC beep */ | ||
237 | {0x18, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
238 | /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */ | ||
239 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
240 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
241 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
242 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
243 | {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
244 | { } /* end */ | ||
245 | }; | ||
246 | |||
247 | |||
248 | static int ad1986a_init(struct hda_codec *codec) | ||
249 | { | ||
250 | snd_hda_sequence_write(codec, ad1986a_init_verbs); | ||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static int ad1986a_build_controls(struct hda_codec *codec) | ||
255 | { | ||
256 | int err; | ||
257 | |||
258 | err = snd_hda_add_new_ctls(codec, ad1986a_mixers); | ||
259 | if (err < 0) | ||
260 | return err; | ||
261 | err = snd_hda_create_spdif_out_ctls(codec, AD1986A_SPDIF_OUT); | ||
262 | if (err < 0) | ||
263 | return err; | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | /* | ||
268 | * Analog playback callbacks | ||
269 | */ | ||
270 | static int ad1986a_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
271 | struct hda_codec *codec, | ||
272 | snd_pcm_substream_t *substream) | ||
273 | { | ||
274 | struct ad1986a_spec *spec = codec->spec; | ||
275 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); | ||
276 | } | ||
277 | |||
278 | static int ad1986a_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
279 | struct hda_codec *codec, | ||
280 | unsigned int stream_tag, | ||
281 | unsigned int format, | ||
282 | snd_pcm_substream_t *substream) | ||
283 | { | ||
284 | struct ad1986a_spec *spec = codec->spec; | ||
285 | return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, | ||
286 | format, substream); | ||
287 | } | ||
288 | |||
289 | static int ad1986a_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
290 | struct hda_codec *codec, | ||
291 | snd_pcm_substream_t *substream) | ||
292 | { | ||
293 | struct ad1986a_spec *spec = codec->spec; | ||
294 | return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); | ||
295 | } | ||
296 | |||
297 | /* | ||
298 | * Digital out | ||
299 | */ | ||
300 | static int ad1986a_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
301 | struct hda_codec *codec, | ||
302 | snd_pcm_substream_t *substream) | ||
303 | { | ||
304 | struct ad1986a_spec *spec = codec->spec; | ||
305 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | ||
306 | } | ||
307 | |||
308 | static int ad1986a_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | ||
309 | struct hda_codec *codec, | ||
310 | snd_pcm_substream_t *substream) | ||
311 | { | ||
312 | struct ad1986a_spec *spec = codec->spec; | ||
313 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | ||
314 | } | ||
315 | |||
316 | /* | ||
317 | * Analog capture | ||
318 | */ | ||
319 | static int ad1986a_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
320 | struct hda_codec *codec, | ||
321 | unsigned int stream_tag, | ||
322 | unsigned int format, | ||
323 | snd_pcm_substream_t *substream) | ||
324 | { | ||
325 | snd_hda_codec_setup_stream(codec, AD1986A_ADC, stream_tag, 0, format); | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static int ad1986a_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
330 | struct hda_codec *codec, | ||
331 | snd_pcm_substream_t *substream) | ||
332 | { | ||
333 | snd_hda_codec_setup_stream(codec, AD1986A_ADC, 0, 0, 0); | ||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | |||
338 | /* | ||
339 | */ | ||
340 | static struct hda_pcm_stream ad1986a_pcm_analog_playback = { | ||
341 | .substreams = 1, | ||
342 | .channels_min = 2, | ||
343 | .channels_max = 6, | ||
344 | .nid = AD1986A_FRONT_DAC, /* NID to query formats and rates */ | ||
345 | .ops = { | ||
346 | .open = ad1986a_playback_pcm_open, | ||
347 | .prepare = ad1986a_playback_pcm_prepare, | ||
348 | .cleanup = ad1986a_playback_pcm_cleanup | ||
349 | }, | ||
350 | }; | ||
351 | |||
352 | static struct hda_pcm_stream ad1986a_pcm_analog_capture = { | ||
353 | .substreams = 2, | ||
354 | .channels_min = 2, | ||
355 | .channels_max = 2, | ||
356 | .nid = AD1986A_ADC, /* NID to query formats and rates */ | ||
357 | .ops = { | ||
358 | .prepare = ad1986a_capture_pcm_prepare, | ||
359 | .cleanup = ad1986a_capture_pcm_cleanup | ||
360 | }, | ||
361 | }; | ||
362 | |||
363 | static struct hda_pcm_stream ad1986a_pcm_digital_playback = { | ||
364 | .substreams = 1, | ||
365 | .channels_min = 2, | ||
366 | .channels_max = 2, | ||
367 | .nid = AD1986A_SPDIF_OUT, | ||
368 | .ops = { | ||
369 | .open = ad1986a_dig_playback_pcm_open, | ||
370 | .close = ad1986a_dig_playback_pcm_close | ||
371 | }, | ||
372 | }; | ||
373 | |||
374 | static int ad1986a_build_pcms(struct hda_codec *codec) | ||
375 | { | ||
376 | struct ad1986a_spec *spec = codec->spec; | ||
377 | struct hda_pcm *info = spec->pcm_rec; | ||
378 | |||
379 | codec->num_pcms = 2; | ||
380 | codec->pcm_info = info; | ||
381 | |||
382 | info->name = "AD1986A Analog"; | ||
383 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad1986a_pcm_analog_playback; | ||
384 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1986a_pcm_analog_capture; | ||
385 | info++; | ||
386 | |||
387 | info->name = "AD1986A Digital"; | ||
388 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad1986a_pcm_digital_playback; | ||
389 | |||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static void ad1986a_free(struct hda_codec *codec) | ||
394 | { | ||
395 | kfree(codec->spec); | ||
396 | } | ||
397 | |||
398 | #ifdef CONFIG_PM | ||
399 | static int ad1986a_resume(struct hda_codec *codec) | ||
400 | { | ||
401 | ad1986a_init(codec); | ||
402 | snd_hda_resume_ctls(codec, ad1986a_mixers); | ||
403 | snd_hda_resume_spdif_out(codec); | ||
404 | return 0; | ||
405 | } | ||
406 | #endif | ||
407 | |||
408 | static struct hda_codec_ops ad1986a_patch_ops = { | ||
409 | .build_controls = ad1986a_build_controls, | ||
410 | .build_pcms = ad1986a_build_pcms, | ||
411 | .init = ad1986a_init, | ||
412 | .free = ad1986a_free, | ||
413 | #ifdef CONFIG_PM | ||
414 | .resume = ad1986a_resume, | ||
415 | #endif | ||
416 | }; | ||
417 | |||
418 | static int patch_ad1986a(struct hda_codec *codec) | ||
419 | { | ||
420 | struct ad1986a_spec *spec; | ||
421 | |||
422 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | ||
423 | if (spec == NULL) | ||
424 | return -ENOMEM; | ||
425 | |||
426 | init_MUTEX(&spec->amp_mutex); | ||
427 | codec->spec = spec; | ||
428 | |||
429 | spec->multiout.max_channels = 6; | ||
430 | spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids); | ||
431 | spec->multiout.dac_nids = ad1986a_dac_nids; | ||
432 | spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; | ||
433 | |||
434 | codec->patch_ops = ad1986a_patch_ops; | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | /* | ||
440 | * patch entries | ||
441 | */ | ||
442 | struct hda_codec_preset snd_hda_preset_analog[] = { | ||
443 | { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, | ||
444 | {} /* terminator */ | ||
445 | }; | ||
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c new file mode 100644 index 000000000000..b7cc8e4bffb7 --- /dev/null +++ b/sound/pci/hda/patch_cmedia.c | |||
@@ -0,0 +1,621 @@ | |||
1 | /* | ||
2 | * Universal Interface for Intel High Definition Audio Codec | ||
3 | * | ||
4 | * HD audio interface patch for C-Media CMI9880 | ||
5 | * | ||
6 | * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> | ||
7 | * | ||
8 | * | ||
9 | * This driver is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This driver is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/pci.h> | ||
29 | #include <sound/core.h> | ||
30 | #include "hda_codec.h" | ||
31 | #include "hda_local.h" | ||
32 | |||
33 | |||
34 | /* board config type */ | ||
35 | enum { | ||
36 | CMI_MINIMAL, /* back 3-jack */ | ||
37 | CMI_MIN_FP, /* back 3-jack + front-panel 2-jack */ | ||
38 | CMI_FULL, /* back 6-jack + front-panel 2-jack */ | ||
39 | CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */ | ||
40 | CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */ | ||
41 | }; | ||
42 | |||
43 | struct cmi_spec { | ||
44 | int board_config; | ||
45 | unsigned int surr_switch: 1; /* switchable line,mic */ | ||
46 | unsigned int no_line_in: 1; /* no line-in (5-jack) */ | ||
47 | unsigned int front_panel: 1; /* has front-panel 2-jack */ | ||
48 | |||
49 | /* playback */ | ||
50 | struct hda_multi_out multiout; | ||
51 | |||
52 | /* capture */ | ||
53 | hda_nid_t *adc_nids; | ||
54 | hda_nid_t dig_in_nid; | ||
55 | |||
56 | /* capture source */ | ||
57 | const struct hda_input_mux *input_mux; | ||
58 | unsigned int cur_mux[2]; | ||
59 | |||
60 | /* channel mode */ | ||
61 | unsigned int num_ch_modes; | ||
62 | unsigned int cur_ch_mode; | ||
63 | const struct cmi_channel_mode *channel_modes; | ||
64 | |||
65 | struct hda_pcm pcm_rec[2]; /* PCM information */ | ||
66 | }; | ||
67 | |||
68 | /* | ||
69 | * input MUX | ||
70 | */ | ||
71 | static int cmi_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
72 | { | ||
73 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
74 | struct cmi_spec *spec = codec->spec; | ||
75 | return snd_hda_input_mux_info(spec->input_mux, uinfo); | ||
76 | } | ||
77 | |||
78 | static int cmi_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
79 | { | ||
80 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
81 | struct cmi_spec *spec = codec->spec; | ||
82 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
83 | |||
84 | ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int cmi_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
89 | { | ||
90 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
91 | struct cmi_spec *spec = codec->spec; | ||
92 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
93 | |||
94 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | ||
95 | spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]); | ||
96 | } | ||
97 | |||
98 | /* | ||
99 | * shared line-in, mic for surrounds | ||
100 | */ | ||
101 | |||
102 | /* 3-stack / 2 channel */ | ||
103 | static struct hda_verb cmi9880_ch2_init[] = { | ||
104 | /* set line-in PIN for input */ | ||
105 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
106 | /* set mic PIN for input, also enable vref */ | ||
107 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
108 | /* route front PCM (DAC1) to HP */ | ||
109 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, | ||
110 | {} | ||
111 | }; | ||
112 | |||
113 | /* 3-stack / 6 channel */ | ||
114 | static struct hda_verb cmi9880_ch6_init[] = { | ||
115 | /* set line-in PIN for output */ | ||
116 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
117 | /* set mic PIN for output */ | ||
118 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
119 | /* route front PCM (DAC1) to HP */ | ||
120 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, | ||
121 | {} | ||
122 | }; | ||
123 | |||
124 | /* 3-stack+front / 8 channel */ | ||
125 | static struct hda_verb cmi9880_ch8_init[] = { | ||
126 | /* set line-in PIN for output */ | ||
127 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
128 | /* set mic PIN for output */ | ||
129 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
130 | /* route rear-surround PCM (DAC4) to HP */ | ||
131 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 }, | ||
132 | {} | ||
133 | }; | ||
134 | |||
135 | struct cmi_channel_mode { | ||
136 | unsigned int channels; | ||
137 | const struct hda_verb *sequence; | ||
138 | }; | ||
139 | |||
140 | static struct cmi_channel_mode cmi9880_channel_modes[3] = { | ||
141 | { 2, cmi9880_ch2_init }, | ||
142 | { 6, cmi9880_ch6_init }, | ||
143 | { 8, cmi9880_ch8_init }, | ||
144 | }; | ||
145 | |||
146 | static int cmi_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
147 | { | ||
148 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
149 | struct cmi_spec *spec = codec->spec; | ||
150 | |||
151 | snd_assert(spec->channel_modes, return -EINVAL); | ||
152 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
153 | uinfo->count = 1; | ||
154 | uinfo->value.enumerated.items = spec->num_ch_modes; | ||
155 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
156 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | ||
157 | sprintf(uinfo->value.enumerated.name, "%dch", | ||
158 | spec->channel_modes[uinfo->value.enumerated.item].channels); | ||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | static int cmi_ch_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
163 | { | ||
164 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
165 | struct cmi_spec *spec = codec->spec; | ||
166 | |||
167 | ucontrol->value.enumerated.item[0] = spec->cur_ch_mode; | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static int cmi_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
172 | { | ||
173 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
174 | struct cmi_spec *spec = codec->spec; | ||
175 | |||
176 | snd_assert(spec->channel_modes, return -EINVAL); | ||
177 | if (ucontrol->value.enumerated.item[0] >= spec->num_ch_modes) | ||
178 | ucontrol->value.enumerated.item[0] = spec->num_ch_modes; | ||
179 | if (ucontrol->value.enumerated.item[0] == spec->cur_ch_mode && | ||
180 | ! codec->in_resume) | ||
181 | return 0; | ||
182 | |||
183 | spec->cur_ch_mode = ucontrol->value.enumerated.item[0]; | ||
184 | snd_hda_sequence_write(codec, spec->channel_modes[spec->cur_ch_mode].sequence); | ||
185 | spec->multiout.max_channels = spec->channel_modes[spec->cur_ch_mode].channels; | ||
186 | return 1; | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | */ | ||
191 | static snd_kcontrol_new_t cmi9880_basic_mixer[] = { | ||
192 | /* CMI9880 has no playback volumes! */ | ||
193 | HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), /* front */ | ||
194 | HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0x0, HDA_OUTPUT), | ||
195 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), | ||
196 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), | ||
197 | HDA_CODEC_MUTE("Side Playback Switch", 0x06, 0x0, HDA_OUTPUT), | ||
198 | { | ||
199 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
200 | /* The multiple "Capture Source" controls confuse alsamixer | ||
201 | * So call somewhat different.. | ||
202 | * FIXME: the controls appear in the "playback" view! | ||
203 | */ | ||
204 | /* .name = "Capture Source", */ | ||
205 | .name = "Input Source", | ||
206 | .count = 2, | ||
207 | .info = cmi_mux_enum_info, | ||
208 | .get = cmi_mux_enum_get, | ||
209 | .put = cmi_mux_enum_put, | ||
210 | }, | ||
211 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0, HDA_INPUT), | ||
212 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0, HDA_INPUT), | ||
213 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0, HDA_INPUT), | ||
214 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0, HDA_INPUT), | ||
215 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x23, 0, HDA_OUTPUT), | ||
216 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x23, 0, HDA_OUTPUT), | ||
217 | { } /* end */ | ||
218 | }; | ||
219 | |||
220 | /* | ||
221 | * shared I/O pins | ||
222 | */ | ||
223 | static snd_kcontrol_new_t cmi9880_ch_mode_mixer[] = { | ||
224 | { | ||
225 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
226 | .name = "Channel Mode", | ||
227 | .info = cmi_ch_mode_info, | ||
228 | .get = cmi_ch_mode_get, | ||
229 | .put = cmi_ch_mode_put, | ||
230 | }, | ||
231 | { } /* end */ | ||
232 | }; | ||
233 | |||
234 | /* AUD-in selections: | ||
235 | * 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x1f 0x20 | ||
236 | */ | ||
237 | static struct hda_input_mux cmi9880_basic_mux = { | ||
238 | .num_items = 4, | ||
239 | .items = { | ||
240 | { "Front Mic", 0x5 }, | ||
241 | { "Rear Mic", 0x2 }, | ||
242 | { "Line", 0x1 }, | ||
243 | { "CD", 0x7 }, | ||
244 | } | ||
245 | }; | ||
246 | |||
247 | static struct hda_input_mux cmi9880_no_line_mux = { | ||
248 | .num_items = 3, | ||
249 | .items = { | ||
250 | { "Front Mic", 0x5 }, | ||
251 | { "Rear Mic", 0x2 }, | ||
252 | { "CD", 0x7 }, | ||
253 | } | ||
254 | }; | ||
255 | |||
256 | /* front, rear, clfe, rear_surr */ | ||
257 | static hda_nid_t cmi9880_dac_nids[4] = { | ||
258 | 0x03, 0x04, 0x05, 0x06 | ||
259 | }; | ||
260 | /* ADC0, ADC1 */ | ||
261 | static hda_nid_t cmi9880_adc_nids[2] = { | ||
262 | 0x08, 0x09 | ||
263 | }; | ||
264 | |||
265 | #define CMI_DIG_OUT_NID 0x07 | ||
266 | #define CMI_DIG_IN_NID 0x0a | ||
267 | |||
268 | /* | ||
269 | */ | ||
270 | static struct hda_verb cmi9880_basic_init[] = { | ||
271 | /* port-D for line out (rear panel) */ | ||
272 | { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
273 | /* port-E for HP out (front panel) */ | ||
274 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
275 | /* route front PCM to HP */ | ||
276 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, | ||
277 | /* port-A for surround (rear panel) */ | ||
278 | { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
279 | /* port-G for CLFE (rear panel) */ | ||
280 | { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
281 | /* port-H for side (rear panel) */ | ||
282 | { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
283 | /* port-C for line-in (rear panel) */ | ||
284 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
285 | /* port-B for mic-in (rear panel) with vref */ | ||
286 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
287 | /* port-F for mic-in (front panel) with vref */ | ||
288 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
289 | /* CD-in */ | ||
290 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
291 | /* route front mic to ADC1/2 */ | ||
292 | { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, | ||
293 | { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, | ||
294 | {} /* terminator */ | ||
295 | }; | ||
296 | |||
297 | static struct hda_verb cmi9880_allout_init[] = { | ||
298 | /* port-D for line out (rear panel) */ | ||
299 | { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
300 | /* port-E for HP out (front panel) */ | ||
301 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
302 | /* route front PCM to HP */ | ||
303 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, | ||
304 | /* port-A for side (rear panel) */ | ||
305 | { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
306 | /* port-G for CLFE (rear panel) */ | ||
307 | { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
308 | /* port-C for surround (rear panel) */ | ||
309 | { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, | ||
310 | /* port-B for mic-in (rear panel) with vref */ | ||
311 | { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
312 | /* port-F for mic-in (front panel) with vref */ | ||
313 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
314 | /* CD-in */ | ||
315 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
316 | /* route front mic to ADC1/2 */ | ||
317 | { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, | ||
318 | { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, | ||
319 | {} /* terminator */ | ||
320 | }; | ||
321 | |||
322 | /* | ||
323 | */ | ||
324 | static int cmi9880_build_controls(struct hda_codec *codec) | ||
325 | { | ||
326 | struct cmi_spec *spec = codec->spec; | ||
327 | int err; | ||
328 | |||
329 | err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer); | ||
330 | if (err < 0) | ||
331 | return err; | ||
332 | if (spec->surr_switch) { | ||
333 | err = snd_hda_add_new_ctls(codec, cmi9880_ch_mode_mixer); | ||
334 | if (err < 0) | ||
335 | return err; | ||
336 | } | ||
337 | if (spec->multiout.dig_out_nid) { | ||
338 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); | ||
339 | if (err < 0) | ||
340 | return err; | ||
341 | } | ||
342 | if (spec->dig_in_nid) { | ||
343 | err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); | ||
344 | if (err < 0) | ||
345 | return err; | ||
346 | } | ||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | static int cmi9880_init(struct hda_codec *codec) | ||
351 | { | ||
352 | struct cmi_spec *spec = codec->spec; | ||
353 | if (spec->board_config == CMI_ALLOUT) | ||
354 | snd_hda_sequence_write(codec, cmi9880_allout_init); | ||
355 | else | ||
356 | snd_hda_sequence_write(codec, cmi9880_basic_init); | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | #ifdef CONFIG_PM | ||
361 | /* | ||
362 | * resume | ||
363 | */ | ||
364 | static int cmi9880_resume(struct hda_codec *codec) | ||
365 | { | ||
366 | struct cmi_spec *spec = codec->spec; | ||
367 | |||
368 | cmi9880_init(codec); | ||
369 | snd_hda_resume_ctls(codec, cmi9880_basic_mixer); | ||
370 | if (spec->surr_switch) | ||
371 | snd_hda_resume_ctls(codec, cmi9880_ch_mode_mixer); | ||
372 | if (spec->multiout.dig_out_nid) | ||
373 | snd_hda_resume_spdif_out(codec); | ||
374 | if (spec->dig_in_nid) | ||
375 | snd_hda_resume_spdif_in(codec); | ||
376 | |||
377 | return 0; | ||
378 | } | ||
379 | #endif | ||
380 | |||
381 | /* | ||
382 | * Analog playback callbacks | ||
383 | */ | ||
384 | static int cmi9880_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
385 | struct hda_codec *codec, | ||
386 | snd_pcm_substream_t *substream) | ||
387 | { | ||
388 | struct cmi_spec *spec = codec->spec; | ||
389 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); | ||
390 | } | ||
391 | |||
392 | static int cmi9880_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
393 | struct hda_codec *codec, | ||
394 | unsigned int stream_tag, | ||
395 | unsigned int format, | ||
396 | snd_pcm_substream_t *substream) | ||
397 | { | ||
398 | struct cmi_spec *spec = codec->spec; | ||
399 | return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, | ||
400 | format, substream); | ||
401 | } | ||
402 | |||
403 | static int cmi9880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
404 | struct hda_codec *codec, | ||
405 | snd_pcm_substream_t *substream) | ||
406 | { | ||
407 | struct cmi_spec *spec = codec->spec; | ||
408 | return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); | ||
409 | } | ||
410 | |||
411 | /* | ||
412 | * Digital out | ||
413 | */ | ||
414 | static int cmi9880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
415 | struct hda_codec *codec, | ||
416 | snd_pcm_substream_t *substream) | ||
417 | { | ||
418 | struct cmi_spec *spec = codec->spec; | ||
419 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | ||
420 | } | ||
421 | |||
422 | static int cmi9880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | ||
423 | struct hda_codec *codec, | ||
424 | snd_pcm_substream_t *substream) | ||
425 | { | ||
426 | struct cmi_spec *spec = codec->spec; | ||
427 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | ||
428 | } | ||
429 | |||
430 | /* | ||
431 | * Analog capture | ||
432 | */ | ||
433 | static int cmi9880_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
434 | struct hda_codec *codec, | ||
435 | unsigned int stream_tag, | ||
436 | unsigned int format, | ||
437 | snd_pcm_substream_t *substream) | ||
438 | { | ||
439 | struct cmi_spec *spec = codec->spec; | ||
440 | |||
441 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | ||
442 | stream_tag, 0, format); | ||
443 | return 0; | ||
444 | } | ||
445 | |||
446 | static int cmi9880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
447 | struct hda_codec *codec, | ||
448 | snd_pcm_substream_t *substream) | ||
449 | { | ||
450 | struct cmi_spec *spec = codec->spec; | ||
451 | |||
452 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0); | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | |||
457 | /* | ||
458 | */ | ||
459 | static struct hda_pcm_stream cmi9880_pcm_analog_playback = { | ||
460 | .substreams = 1, | ||
461 | .channels_min = 2, | ||
462 | .channels_max = 8, | ||
463 | .nid = 0x03, /* NID to query formats and rates */ | ||
464 | .ops = { | ||
465 | .open = cmi9880_playback_pcm_open, | ||
466 | .prepare = cmi9880_playback_pcm_prepare, | ||
467 | .cleanup = cmi9880_playback_pcm_cleanup | ||
468 | }, | ||
469 | }; | ||
470 | |||
471 | static struct hda_pcm_stream cmi9880_pcm_analog_capture = { | ||
472 | .substreams = 2, | ||
473 | .channels_min = 2, | ||
474 | .channels_max = 2, | ||
475 | .nid = 0x08, /* NID to query formats and rates */ | ||
476 | .ops = { | ||
477 | .prepare = cmi9880_capture_pcm_prepare, | ||
478 | .cleanup = cmi9880_capture_pcm_cleanup | ||
479 | }, | ||
480 | }; | ||
481 | |||
482 | static struct hda_pcm_stream cmi9880_pcm_digital_playback = { | ||
483 | .substreams = 1, | ||
484 | .channels_min = 2, | ||
485 | .channels_max = 2, | ||
486 | /* NID is set in cmi9880_build_pcms */ | ||
487 | .ops = { | ||
488 | .open = cmi9880_dig_playback_pcm_open, | ||
489 | .close = cmi9880_dig_playback_pcm_close | ||
490 | }, | ||
491 | }; | ||
492 | |||
493 | static struct hda_pcm_stream cmi9880_pcm_digital_capture = { | ||
494 | .substreams = 1, | ||
495 | .channels_min = 2, | ||
496 | .channels_max = 2, | ||
497 | /* NID is set in cmi9880_build_pcms */ | ||
498 | }; | ||
499 | |||
500 | static int cmi9880_build_pcms(struct hda_codec *codec) | ||
501 | { | ||
502 | struct cmi_spec *spec = codec->spec; | ||
503 | struct hda_pcm *info = spec->pcm_rec; | ||
504 | |||
505 | codec->num_pcms = 1; | ||
506 | codec->pcm_info = info; | ||
507 | |||
508 | info->name = "CMI9880"; | ||
509 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_analog_playback; | ||
510 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_analog_capture; | ||
511 | |||
512 | if (spec->multiout.dig_out_nid || spec->dig_in_nid) { | ||
513 | codec->num_pcms++; | ||
514 | info++; | ||
515 | info->name = "CMI9880 Digital"; | ||
516 | if (spec->multiout.dig_out_nid) { | ||
517 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_digital_playback; | ||
518 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; | ||
519 | } | ||
520 | if (spec->dig_in_nid) { | ||
521 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_digital_capture; | ||
522 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; | ||
523 | } | ||
524 | } | ||
525 | |||
526 | return 0; | ||
527 | } | ||
528 | |||
529 | static void cmi9880_free(struct hda_codec *codec) | ||
530 | { | ||
531 | kfree(codec->spec); | ||
532 | } | ||
533 | |||
534 | /* | ||
535 | */ | ||
536 | |||
537 | static struct hda_board_config cmi9880_cfg_tbl[] = { | ||
538 | { .modelname = "minimal", .config = CMI_MINIMAL }, | ||
539 | { .modelname = "min_fp", .config = CMI_MIN_FP }, | ||
540 | { .modelname = "full", .config = CMI_FULL }, | ||
541 | { .modelname = "full_dig", .config = CMI_FULL_DIG }, | ||
542 | { .modelname = "allout", .config = CMI_ALLOUT }, | ||
543 | {} /* terminator */ | ||
544 | }; | ||
545 | |||
546 | static struct hda_codec_ops cmi9880_patch_ops = { | ||
547 | .build_controls = cmi9880_build_controls, | ||
548 | .build_pcms = cmi9880_build_pcms, | ||
549 | .init = cmi9880_init, | ||
550 | .free = cmi9880_free, | ||
551 | #ifdef CONFIG_PM | ||
552 | .resume = cmi9880_resume, | ||
553 | #endif | ||
554 | }; | ||
555 | |||
556 | static int patch_cmi9880(struct hda_codec *codec) | ||
557 | { | ||
558 | struct cmi_spec *spec; | ||
559 | |||
560 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | ||
561 | if (spec == NULL) | ||
562 | return -ENOMEM; | ||
563 | |||
564 | codec->spec = spec; | ||
565 | spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl); | ||
566 | if (spec->board_config < 0) { | ||
567 | snd_printd(KERN_INFO "hda_codec: Unknown model for CMI9880\n"); | ||
568 | spec->board_config = CMI_FULL_DIG; /* try everything */ | ||
569 | } | ||
570 | |||
571 | switch (spec->board_config) { | ||
572 | case CMI_MINIMAL: | ||
573 | case CMI_MIN_FP: | ||
574 | spec->surr_switch = 1; | ||
575 | if (spec->board_config == CMI_MINIMAL) | ||
576 | spec->num_ch_modes = 2; | ||
577 | else { | ||
578 | spec->front_panel = 1; | ||
579 | spec->num_ch_modes = 3; | ||
580 | } | ||
581 | spec->channel_modes = cmi9880_channel_modes; | ||
582 | spec->multiout.max_channels = cmi9880_channel_modes[0].channels; | ||
583 | spec->input_mux = &cmi9880_basic_mux; | ||
584 | break; | ||
585 | case CMI_FULL: | ||
586 | case CMI_FULL_DIG: | ||
587 | spec->front_panel = 1; | ||
588 | spec->multiout.max_channels = 8; | ||
589 | spec->input_mux = &cmi9880_basic_mux; | ||
590 | if (spec->board_config == CMI_FULL_DIG) { | ||
591 | spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; | ||
592 | spec->dig_in_nid = CMI_DIG_IN_NID; | ||
593 | } | ||
594 | break; | ||
595 | case CMI_ALLOUT: | ||
596 | spec->front_panel = 1; | ||
597 | spec->multiout.max_channels = 8; | ||
598 | spec->no_line_in = 1; | ||
599 | spec->input_mux = &cmi9880_no_line_mux; | ||
600 | spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; | ||
601 | break; | ||
602 | } | ||
603 | |||
604 | spec->multiout.num_dacs = 4; | ||
605 | spec->multiout.dac_nids = cmi9880_dac_nids; | ||
606 | |||
607 | spec->adc_nids = cmi9880_adc_nids; | ||
608 | |||
609 | codec->patch_ops = cmi9880_patch_ops; | ||
610 | |||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | /* | ||
615 | * patch entries | ||
616 | */ | ||
617 | struct hda_codec_preset snd_hda_preset_cmedia[] = { | ||
618 | { .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 }, | ||
619 | { .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 }, | ||
620 | {} /* terminator */ | ||
621 | }; | ||
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c new file mode 100644 index 000000000000..17c5062423ae --- /dev/null +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -0,0 +1,1503 @@ | |||
1 | /* | ||
2 | * Universal Interface for Intel High Definition Audio Codec | ||
3 | * | ||
4 | * HD audio interface patch for ALC 260/880/882 codecs | ||
5 | * | ||
6 | * Copyright (c) 2004 PeiSen Hou <pshou@realtek.com.tw> | ||
7 | * Takashi Iwai <tiwai@suse.de> | ||
8 | * | ||
9 | * This driver is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This driver is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/pci.h> | ||
29 | #include <sound/core.h> | ||
30 | #include "hda_codec.h" | ||
31 | #include "hda_local.h" | ||
32 | |||
33 | |||
34 | /* ALC880 board config type */ | ||
35 | enum { | ||
36 | ALC880_MINIMAL, | ||
37 | ALC880_3ST, | ||
38 | ALC880_3ST_DIG, | ||
39 | ALC880_5ST, | ||
40 | ALC880_5ST_DIG, | ||
41 | ALC880_W810, | ||
42 | }; | ||
43 | |||
44 | struct alc_spec { | ||
45 | /* codec parameterization */ | ||
46 | unsigned int front_panel: 1; | ||
47 | |||
48 | snd_kcontrol_new_t* mixers[2]; | ||
49 | unsigned int num_mixers; | ||
50 | |||
51 | struct hda_verb *init_verbs; | ||
52 | |||
53 | char* stream_name_analog; | ||
54 | struct hda_pcm_stream *stream_analog_playback; | ||
55 | struct hda_pcm_stream *stream_analog_capture; | ||
56 | |||
57 | char* stream_name_digital; | ||
58 | struct hda_pcm_stream *stream_digital_playback; | ||
59 | struct hda_pcm_stream *stream_digital_capture; | ||
60 | |||
61 | /* playback */ | ||
62 | struct hda_multi_out multiout; | ||
63 | |||
64 | /* capture */ | ||
65 | unsigned int num_adc_nids; | ||
66 | hda_nid_t *adc_nids; | ||
67 | hda_nid_t dig_in_nid; | ||
68 | |||
69 | /* capture source */ | ||
70 | const struct hda_input_mux *input_mux; | ||
71 | unsigned int cur_mux[3]; | ||
72 | |||
73 | /* channel model */ | ||
74 | const struct alc_channel_mode *channel_mode; | ||
75 | int num_channel_mode; | ||
76 | |||
77 | /* PCM information */ | ||
78 | struct hda_pcm pcm_rec[2]; | ||
79 | }; | ||
80 | |||
81 | /* DAC/ADC assignment */ | ||
82 | |||
83 | static hda_nid_t alc880_dac_nids[4] = { | ||
84 | /* front, rear, clfe, rear_surr */ | ||
85 | 0x02, 0x05, 0x04, 0x03 | ||
86 | }; | ||
87 | |||
88 | static hda_nid_t alc880_w810_dac_nids[3] = { | ||
89 | /* front, rear/surround, clfe */ | ||
90 | 0x02, 0x03, 0x04 | ||
91 | }; | ||
92 | |||
93 | static hda_nid_t alc880_adc_nids[3] = { | ||
94 | /* ADC0-2 */ | ||
95 | 0x07, 0x08, 0x09, | ||
96 | }; | ||
97 | |||
98 | #define ALC880_DIGOUT_NID 0x06 | ||
99 | #define ALC880_DIGIN_NID 0x0a | ||
100 | |||
101 | static hda_nid_t alc260_dac_nids[1] = { | ||
102 | /* front */ | ||
103 | 0x02, | ||
104 | }; | ||
105 | |||
106 | static hda_nid_t alc260_adc_nids[2] = { | ||
107 | /* ADC0-1 */ | ||
108 | 0x04, 0x05, | ||
109 | }; | ||
110 | |||
111 | #define ALC260_DIGOUT_NID 0x03 | ||
112 | #define ALC260_DIGIN_NID 0x06 | ||
113 | |||
114 | static struct hda_input_mux alc880_capture_source = { | ||
115 | .num_items = 4, | ||
116 | .items = { | ||
117 | { "Mic", 0x0 }, | ||
118 | { "Front Mic", 0x3 }, | ||
119 | { "Line", 0x2 }, | ||
120 | { "CD", 0x4 }, | ||
121 | }, | ||
122 | }; | ||
123 | |||
124 | static struct hda_input_mux alc260_capture_source = { | ||
125 | .num_items = 4, | ||
126 | .items = { | ||
127 | { "Mic", 0x0 }, | ||
128 | { "Front Mic", 0x1 }, | ||
129 | { "Line", 0x2 }, | ||
130 | { "CD", 0x4 }, | ||
131 | }, | ||
132 | }; | ||
133 | |||
134 | /* | ||
135 | * input MUX handling | ||
136 | */ | ||
137 | static int alc_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
138 | { | ||
139 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
140 | struct alc_spec *spec = codec->spec; | ||
141 | return snd_hda_input_mux_info(spec->input_mux, uinfo); | ||
142 | } | ||
143 | |||
144 | static int alc_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
145 | { | ||
146 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
147 | struct alc_spec *spec = codec->spec; | ||
148 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
149 | |||
150 | ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int alc_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
155 | { | ||
156 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
157 | struct alc_spec *spec = codec->spec; | ||
158 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
159 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | ||
160 | spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]); | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * channel mode setting | ||
165 | */ | ||
166 | struct alc_channel_mode { | ||
167 | int channels; | ||
168 | const struct hda_verb *sequence; | ||
169 | }; | ||
170 | |||
171 | |||
172 | /* | ||
173 | * channel source setting (2/6 channel selection for 3-stack) | ||
174 | */ | ||
175 | |||
176 | /* | ||
177 | * set the path ways for 2 channel output | ||
178 | * need to set the codec line out and mic 1 pin widgets to inputs | ||
179 | */ | ||
180 | static struct hda_verb alc880_threestack_ch2_init[] = { | ||
181 | /* set pin widget 1Ah (line in) for input */ | ||
182 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
183 | /* set pin widget 18h (mic1) for input, for mic also enable the vref */ | ||
184 | { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, | ||
185 | /* mute the output for Line In PW */ | ||
186 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, | ||
187 | /* mute for Mic1 PW */ | ||
188 | { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, | ||
189 | { } /* end */ | ||
190 | }; | ||
191 | |||
192 | /* | ||
193 | * 6ch mode | ||
194 | * need to set the codec line out and mic 1 pin widgets to outputs | ||
195 | */ | ||
196 | static struct hda_verb alc880_threestack_ch6_init[] = { | ||
197 | /* set pin widget 1Ah (line in) for output */ | ||
198 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
199 | /* set pin widget 18h (mic1) for output */ | ||
200 | { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
201 | /* unmute the output for Line In PW */ | ||
202 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 }, | ||
203 | /* unmute for Mic1 PW */ | ||
204 | { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 }, | ||
205 | /* for rear channel output using Line In 1 | ||
206 | * set select widget connection (nid = 0x12) - to summer node | ||
207 | * for rear NID = 0x0f...offset 3 in connection list | ||
208 | */ | ||
209 | { 0x12, AC_VERB_SET_CONNECT_SEL, 0x3 }, | ||
210 | /* for Mic1 - retask for center/lfe */ | ||
211 | /* set select widget connection (nid = 0x10) - to summer node for | ||
212 | * front CLFE NID = 0x0e...offset 2 in connection list | ||
213 | */ | ||
214 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x2 }, | ||
215 | { } /* end */ | ||
216 | }; | ||
217 | |||
218 | static struct alc_channel_mode alc880_threestack_modes[2] = { | ||
219 | { 2, alc880_threestack_ch2_init }, | ||
220 | { 6, alc880_threestack_ch6_init }, | ||
221 | }; | ||
222 | |||
223 | |||
224 | /* | ||
225 | * channel source setting (6/8 channel selection for 5-stack) | ||
226 | */ | ||
227 | |||
228 | /* set the path ways for 6 channel output | ||
229 | * need to set the codec line out and mic 1 pin widgets to inputs | ||
230 | */ | ||
231 | static struct hda_verb alc880_fivestack_ch6_init[] = { | ||
232 | /* set pin widget 1Ah (line in) for input */ | ||
233 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, | ||
234 | /* mute the output for Line In PW */ | ||
235 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, | ||
236 | { } /* end */ | ||
237 | }; | ||
238 | |||
239 | /* need to set the codec line out and mic 1 pin widgets to outputs */ | ||
240 | static struct hda_verb alc880_fivestack_ch8_init[] = { | ||
241 | /* set pin widget 1Ah (line in) for output */ | ||
242 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, | ||
243 | /* unmute the output for Line In PW */ | ||
244 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 }, | ||
245 | /* output for surround channel output using Line In 1 */ | ||
246 | /* set select widget connection (nid = 0x12) - to summer node | ||
247 | * for surr_rear NID = 0x0d...offset 1 in connection list | ||
248 | */ | ||
249 | { 0x12, AC_VERB_SET_CONNECT_SEL, 0x1 }, | ||
250 | { } /* end */ | ||
251 | }; | ||
252 | |||
253 | static struct alc_channel_mode alc880_fivestack_modes[2] = { | ||
254 | { 6, alc880_fivestack_ch6_init }, | ||
255 | { 8, alc880_fivestack_ch8_init }, | ||
256 | }; | ||
257 | |||
258 | /* | ||
259 | * channel source setting for W810 system | ||
260 | * | ||
261 | * W810 has rear IO for: | ||
262 | * Front (DAC 02) | ||
263 | * Surround (DAC 03) | ||
264 | * Center/LFE (DAC 04) | ||
265 | * Digital out (06) | ||
266 | * | ||
267 | * The system also has a pair of internal speakers, and a headphone jack. | ||
268 | * These are both connected to Line2 on the codec, hence to DAC 02. | ||
269 | * | ||
270 | * There is a variable resistor to control the speaker or headphone | ||
271 | * volume. This is a hardware-only device without a software API. | ||
272 | * | ||
273 | * Plugging headphones in will disable the internal speakers. This is | ||
274 | * implemented in hardware, not via the driver using jack sense. In | ||
275 | * a similar fashion, plugging into the rear socket marked "front" will | ||
276 | * disable both the speakers and headphones. | ||
277 | * | ||
278 | * For input, there's a microphone jack, and an "audio in" jack. | ||
279 | * These may not do anything useful with this driver yet, because I | ||
280 | * haven't setup any initialization verbs for these yet... | ||
281 | */ | ||
282 | |||
283 | static struct alc_channel_mode alc880_w810_modes[1] = { | ||
284 | { 6, NULL } | ||
285 | }; | ||
286 | |||
287 | /* | ||
288 | */ | ||
289 | static int alc880_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
290 | { | ||
291 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
292 | struct alc_spec *spec = codec->spec; | ||
293 | |||
294 | snd_assert(spec->channel_mode, return -ENXIO); | ||
295 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
296 | uinfo->count = 1; | ||
297 | uinfo->value.enumerated.items = 2; | ||
298 | if (uinfo->value.enumerated.item >= 2) | ||
299 | uinfo->value.enumerated.item = 1; | ||
300 | sprintf(uinfo->value.enumerated.name, "%dch", | ||
301 | spec->channel_mode[uinfo->value.enumerated.item].channels); | ||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | static int alc880_ch_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
306 | { | ||
307 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
308 | struct alc_spec *spec = codec->spec; | ||
309 | |||
310 | snd_assert(spec->channel_mode, return -ENXIO); | ||
311 | ucontrol->value.enumerated.item[0] = | ||
312 | (spec->multiout.max_channels == spec->channel_mode[0].channels) ? 0 : 1; | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static int alc880_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
317 | { | ||
318 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
319 | struct alc_spec *spec = codec->spec; | ||
320 | int mode; | ||
321 | |||
322 | snd_assert(spec->channel_mode, return -ENXIO); | ||
323 | mode = ucontrol->value.enumerated.item[0] ? 1 : 0; | ||
324 | if (spec->multiout.max_channels == spec->channel_mode[mode].channels && | ||
325 | ! codec->in_resume) | ||
326 | return 0; | ||
327 | |||
328 | /* change the current channel setting */ | ||
329 | spec->multiout.max_channels = spec->channel_mode[mode].channels; | ||
330 | if (spec->channel_mode[mode].sequence) | ||
331 | snd_hda_sequence_write(codec, spec->channel_mode[mode].sequence); | ||
332 | |||
333 | return 1; | ||
334 | } | ||
335 | |||
336 | |||
337 | /* | ||
338 | */ | ||
339 | |||
340 | /* 3-stack mode | ||
341 | * Pin assignment: Front=0x14, Line-In/Rear=0x1a, Mic/CLFE=0x18, F-Mic=0x1b | ||
342 | * HP=0x19 | ||
343 | */ | ||
344 | static snd_kcontrol_new_t alc880_base_mixer[] = { | ||
345 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
346 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
347 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), | ||
348 | HDA_CODEC_MUTE("Surround Playback Switch", 0x1a, 0x0, HDA_OUTPUT), | ||
349 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), | ||
350 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | ||
351 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x18, 1, 0x0, HDA_OUTPUT), | ||
352 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x18, 2, 0x0, HDA_OUTPUT), | ||
353 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
354 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
355 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
356 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
357 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
358 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
359 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), | ||
360 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), | ||
361 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | ||
362 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | ||
363 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
364 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), | ||
365 | HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), | ||
366 | HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), | ||
367 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), | ||
368 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), | ||
369 | { | ||
370 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
371 | /* The multiple "Capture Source" controls confuse alsamixer | ||
372 | * So call somewhat different.. | ||
373 | * FIXME: the controls appear in the "playback" view! | ||
374 | */ | ||
375 | /* .name = "Capture Source", */ | ||
376 | .name = "Input Source", | ||
377 | .count = 2, | ||
378 | .info = alc_mux_enum_info, | ||
379 | .get = alc_mux_enum_get, | ||
380 | .put = alc_mux_enum_put, | ||
381 | }, | ||
382 | { | ||
383 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
384 | .name = "Channel Mode", | ||
385 | .info = alc880_ch_mode_info, | ||
386 | .get = alc880_ch_mode_get, | ||
387 | .put = alc880_ch_mode_put, | ||
388 | }, | ||
389 | { } /* end */ | ||
390 | }; | ||
391 | |||
392 | /* 5-stack mode | ||
393 | * Pin assignment: Front=0x14, Rear=0x17, CLFE=0x16 | ||
394 | * Line-In/Side=0x1a, Mic=0x18, F-Mic=0x1b, HP=0x19 | ||
395 | */ | ||
396 | static snd_kcontrol_new_t alc880_five_stack_mixer[] = { | ||
397 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
398 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
399 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), | ||
400 | HDA_CODEC_MUTE("Surround Playback Switch", 0x17, 0x0, HDA_OUTPUT), | ||
401 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), | ||
402 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | ||
403 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), | ||
404 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), | ||
405 | HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
406 | HDA_CODEC_MUTE("Side Playback Switch", 0x1a, 0x0, HDA_OUTPUT), | ||
407 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
408 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
409 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
410 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
411 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
412 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
413 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT), | ||
414 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT), | ||
415 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | ||
416 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | ||
417 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
418 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT), | ||
419 | HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), | ||
420 | HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), | ||
421 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), | ||
422 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), | ||
423 | { | ||
424 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
425 | /* The multiple "Capture Source" controls confuse alsamixer | ||
426 | * So call somewhat different.. | ||
427 | * FIXME: the controls appear in the "playback" view! | ||
428 | */ | ||
429 | /* .name = "Capture Source", */ | ||
430 | .name = "Input Source", | ||
431 | .count = 2, | ||
432 | .info = alc_mux_enum_info, | ||
433 | .get = alc_mux_enum_get, | ||
434 | .put = alc_mux_enum_put, | ||
435 | }, | ||
436 | { | ||
437 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
438 | .name = "Channel Mode", | ||
439 | .info = alc880_ch_mode_info, | ||
440 | .get = alc880_ch_mode_get, | ||
441 | .put = alc880_ch_mode_put, | ||
442 | }, | ||
443 | { } /* end */ | ||
444 | }; | ||
445 | |||
446 | static snd_kcontrol_new_t alc880_w810_base_mixer[] = { | ||
447 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
448 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
449 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
450 | HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
451 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), | ||
452 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | ||
453 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), | ||
454 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), | ||
455 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
456 | HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), | ||
457 | HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), | ||
458 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), | ||
459 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), | ||
460 | HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), | ||
461 | HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), | ||
462 | { | ||
463 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
464 | /* The multiple "Capture Source" controls confuse alsamixer | ||
465 | * So call somewhat different.. | ||
466 | * FIXME: the controls appear in the "playback" view! | ||
467 | */ | ||
468 | /* .name = "Capture Source", */ | ||
469 | .name = "Input Source", | ||
470 | .count = 3, | ||
471 | .info = alc_mux_enum_info, | ||
472 | .get = alc_mux_enum_get, | ||
473 | .put = alc_mux_enum_put, | ||
474 | }, | ||
475 | { } /* end */ | ||
476 | }; | ||
477 | |||
478 | /* | ||
479 | */ | ||
480 | static int alc_build_controls(struct hda_codec *codec) | ||
481 | { | ||
482 | struct alc_spec *spec = codec->spec; | ||
483 | int err; | ||
484 | int i; | ||
485 | |||
486 | for (i = 0; i < spec->num_mixers; i++) { | ||
487 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); | ||
488 | if (err < 0) | ||
489 | return err; | ||
490 | } | ||
491 | |||
492 | if (spec->multiout.dig_out_nid) { | ||
493 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); | ||
494 | if (err < 0) | ||
495 | return err; | ||
496 | } | ||
497 | if (spec->dig_in_nid) { | ||
498 | err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); | ||
499 | if (err < 0) | ||
500 | return err; | ||
501 | } | ||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | /* | ||
506 | * initialize the codec volumes, etc | ||
507 | */ | ||
508 | |||
509 | static struct hda_verb alc880_init_verbs_three_stack[] = { | ||
510 | /* Line In pin widget for input */ | ||
511 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
512 | /* CD pin widget for input */ | ||
513 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
514 | /* Mic1 (rear panel) pin widget for input and vref at 80% */ | ||
515 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
516 | /* Mic2 (front panel) pin widget for input and vref at 80% */ | ||
517 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
518 | /* unmute amp left and right */ | ||
519 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | ||
520 | /* set connection select to line in (default select for this ADC) */ | ||
521 | {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
522 | /* unmute front mixer amp left (volume = 0) */ | ||
523 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
524 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
525 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
526 | /* unmute rear mixer amp left and right (volume = 0) */ | ||
527 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
528 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
529 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
530 | /* unmute rear mixer amp left and right (volume = 0) */ | ||
531 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
532 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
533 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
534 | |||
535 | /* using rear surround as the path for headphone output */ | ||
536 | /* unmute rear surround mixer amp left and right (volume = 0) */ | ||
537 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
538 | /* PASD 3 stack boards use the Mic 2 as the headphone output */ | ||
539 | /* need to program the selector associated with the Mic 2 pin widget to | ||
540 | * surround path (index 0x01) for headphone output */ | ||
541 | {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
542 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
543 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
544 | /* need to retask the Mic 2 pin widget to output */ | ||
545 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
546 | |||
547 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer widget(nid=0x0B) | ||
548 | * to support the input path of analog loopback | ||
549 | * Note: PASD motherboards uses the Line In 2 as the input for front panel | ||
550 | * mic (mic 2) | ||
551 | */ | ||
552 | /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ | ||
553 | /* unmute CD */ | ||
554 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, | ||
555 | /* unmute Line In */ | ||
556 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | ||
557 | /* unmute Mic 1 */ | ||
558 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
559 | /* unmute Line In 2 (for PASD boards Mic 2) */ | ||
560 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, | ||
561 | |||
562 | /* Unmute input amps for the line out paths to support the output path of | ||
563 | * analog loopback | ||
564 | * the mixers on the output path has 2 inputs, one from the DAC and one | ||
565 | * from the mixer | ||
566 | */ | ||
567 | /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ | ||
568 | /* Unmute Front out path */ | ||
569 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
570 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
571 | /* Unmute Surround (used as HP) out path */ | ||
572 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
573 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
574 | /* Unmute C/LFE out path */ | ||
575 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
576 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, /* mute */ | ||
577 | /* Unmute rear Surround out path */ | ||
578 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
579 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
580 | |||
581 | { } | ||
582 | }; | ||
583 | |||
584 | static struct hda_verb alc880_init_verbs_five_stack[] = { | ||
585 | /* Line In pin widget for input */ | ||
586 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
587 | /* CD pin widget for input */ | ||
588 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
589 | /* Mic1 (rear panel) pin widget for input and vref at 80% */ | ||
590 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
591 | /* Mic2 (front panel) pin widget for input and vref at 80% */ | ||
592 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
593 | /* unmute amp left and right */ | ||
594 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | ||
595 | /* set connection select to line in (default select for this ADC) */ | ||
596 | {0x07, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
597 | /* unmute front mixer amp left and right (volume = 0) */ | ||
598 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
599 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
600 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
601 | /* five rear and clfe */ | ||
602 | /* unmute rear mixer amp left and right (volume = 0) */ | ||
603 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
604 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
605 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
606 | /* unmute clfe mixer amp left and right (volume = 0) */ | ||
607 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
608 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
609 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
610 | |||
611 | /* using rear surround as the path for headphone output */ | ||
612 | /* unmute rear surround mixer amp left and right (volume = 0) */ | ||
613 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
614 | /* PASD 3 stack boards use the Mic 2 as the headphone output */ | ||
615 | /* need to program the selector associated with the Mic 2 pin widget to | ||
616 | * surround path (index 0x01) for headphone output | ||
617 | */ | ||
618 | {0x11, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
619 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
620 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
621 | /* need to retask the Mic 2 pin widget to output */ | ||
622 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
623 | |||
624 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) for mixer | ||
625 | * widget(nid=0x0B) to support the input path of analog loopback | ||
626 | */ | ||
627 | /* Note: PASD motherboards uses the Line In 2 as the input for front panel mic (mic 2) */ | ||
628 | /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03*/ | ||
629 | /* unmute CD */ | ||
630 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, | ||
631 | /* unmute Line In */ | ||
632 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | ||
633 | /* unmute Mic 1 */ | ||
634 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
635 | /* unmute Line In 2 (for PASD boards Mic 2) */ | ||
636 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, | ||
637 | |||
638 | /* Unmute input amps for the line out paths to support the output path of | ||
639 | * analog loopback | ||
640 | * the mixers on the output path has 2 inputs, one from the DAC and | ||
641 | * one from the mixer | ||
642 | */ | ||
643 | /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ | ||
644 | /* Unmute Front out path */ | ||
645 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
646 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
647 | /* Unmute Surround (used as HP) out path */ | ||
648 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
649 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
650 | /* Unmute C/LFE out path */ | ||
651 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
652 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, /* mute */ | ||
653 | /* Unmute rear Surround out path */ | ||
654 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
655 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
656 | |||
657 | { } | ||
658 | }; | ||
659 | |||
660 | static struct hda_verb alc880_w810_init_verbs[] = { | ||
661 | /* front channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ | ||
662 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | ||
663 | |||
664 | /* front channel selector/amp: input 1: capture mix: muted, (no volume selection) */ | ||
665 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, | ||
666 | |||
667 | /* front channel selector/amp: output 0: unmuted, max volume */ | ||
668 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
669 | |||
670 | /* front out pin: muted, (no volume selection) */ | ||
671 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
672 | |||
673 | /* front out pin: NOT headphone enable, out enable, vref disabled */ | ||
674 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
675 | |||
676 | |||
677 | /* surround channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ | ||
678 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | ||
679 | |||
680 | /* surround channel selector/amp: input 1: capture mix: muted, (no volume selection) */ | ||
681 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, | ||
682 | |||
683 | /* surround channel selector/amp: output 0: unmuted, max volume */ | ||
684 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
685 | |||
686 | /* surround out pin: muted, (no volume selection) */ | ||
687 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
688 | |||
689 | /* surround out pin: NOT headphone enable, out enable, vref disabled */ | ||
690 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
691 | |||
692 | |||
693 | /* c/lfe channel selector/amp: input 0: DAC: unmuted, (no volume selection) */ | ||
694 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | ||
695 | |||
696 | /* c/lfe channel selector/amp: input 1: capture mix: muted, (no volume selection) */ | ||
697 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0x7180}, | ||
698 | |||
699 | /* c/lfe channel selector/amp: output 0: unmuted, max volume */ | ||
700 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
701 | |||
702 | /* c/lfe out pin: muted, (no volume selection) */ | ||
703 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
704 | |||
705 | /* c/lfe out pin: NOT headphone enable, out enable, vref disabled */ | ||
706 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
707 | |||
708 | |||
709 | /* hphone/speaker input selector: front DAC */ | ||
710 | {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
711 | |||
712 | /* hphone/speaker out pin: muted, (no volume selection) */ | ||
713 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
714 | |||
715 | /* hphone/speaker out pin: NOT headphone enable, out enable, vref disabled */ | ||
716 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
717 | |||
718 | |||
719 | { } | ||
720 | }; | ||
721 | |||
722 | static int alc_init(struct hda_codec *codec) | ||
723 | { | ||
724 | struct alc_spec *spec = codec->spec; | ||
725 | snd_hda_sequence_write(codec, spec->init_verbs); | ||
726 | return 0; | ||
727 | } | ||
728 | |||
729 | #ifdef CONFIG_PM | ||
730 | /* | ||
731 | * resume | ||
732 | */ | ||
733 | static int alc_resume(struct hda_codec *codec) | ||
734 | { | ||
735 | struct alc_spec *spec = codec->spec; | ||
736 | int i; | ||
737 | |||
738 | alc_init(codec); | ||
739 | for (i = 0; i < spec->num_mixers; i++) { | ||
740 | snd_hda_resume_ctls(codec, spec->mixers[i]); | ||
741 | } | ||
742 | if (spec->multiout.dig_out_nid) | ||
743 | snd_hda_resume_spdif_out(codec); | ||
744 | if (spec->dig_in_nid) | ||
745 | snd_hda_resume_spdif_in(codec); | ||
746 | |||
747 | return 0; | ||
748 | } | ||
749 | #endif | ||
750 | |||
751 | /* | ||
752 | * Analog playback callbacks | ||
753 | */ | ||
754 | static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
755 | struct hda_codec *codec, | ||
756 | snd_pcm_substream_t *substream) | ||
757 | { | ||
758 | struct alc_spec *spec = codec->spec; | ||
759 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); | ||
760 | } | ||
761 | |||
762 | static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
763 | struct hda_codec *codec, | ||
764 | unsigned int stream_tag, | ||
765 | unsigned int format, | ||
766 | snd_pcm_substream_t *substream) | ||
767 | { | ||
768 | struct alc_spec *spec = codec->spec; | ||
769 | return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, | ||
770 | format, substream); | ||
771 | } | ||
772 | |||
773 | static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
774 | struct hda_codec *codec, | ||
775 | snd_pcm_substream_t *substream) | ||
776 | { | ||
777 | struct alc_spec *spec = codec->spec; | ||
778 | return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); | ||
779 | } | ||
780 | |||
781 | /* | ||
782 | * Digital out | ||
783 | */ | ||
784 | static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
785 | struct hda_codec *codec, | ||
786 | snd_pcm_substream_t *substream) | ||
787 | { | ||
788 | struct alc_spec *spec = codec->spec; | ||
789 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | ||
790 | } | ||
791 | |||
792 | static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | ||
793 | struct hda_codec *codec, | ||
794 | snd_pcm_substream_t *substream) | ||
795 | { | ||
796 | struct alc_spec *spec = codec->spec; | ||
797 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | ||
798 | } | ||
799 | |||
800 | /* | ||
801 | * Analog capture | ||
802 | */ | ||
803 | static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
804 | struct hda_codec *codec, | ||
805 | unsigned int stream_tag, | ||
806 | unsigned int format, | ||
807 | snd_pcm_substream_t *substream) | ||
808 | { | ||
809 | struct alc_spec *spec = codec->spec; | ||
810 | |||
811 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | ||
812 | stream_tag, 0, format); | ||
813 | return 0; | ||
814 | } | ||
815 | |||
816 | static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
817 | struct hda_codec *codec, | ||
818 | snd_pcm_substream_t *substream) | ||
819 | { | ||
820 | struct alc_spec *spec = codec->spec; | ||
821 | |||
822 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0); | ||
823 | return 0; | ||
824 | } | ||
825 | |||
826 | |||
827 | /* | ||
828 | */ | ||
829 | static struct hda_pcm_stream alc880_pcm_analog_playback = { | ||
830 | .substreams = 1, | ||
831 | .channels_min = 2, | ||
832 | .channels_max = 8, | ||
833 | .nid = 0x02, /* NID to query formats and rates */ | ||
834 | .ops = { | ||
835 | .open = alc880_playback_pcm_open, | ||
836 | .prepare = alc880_playback_pcm_prepare, | ||
837 | .cleanup = alc880_playback_pcm_cleanup | ||
838 | }, | ||
839 | }; | ||
840 | |||
841 | static struct hda_pcm_stream alc880_pcm_analog_capture = { | ||
842 | .substreams = 2, | ||
843 | .channels_min = 2, | ||
844 | .channels_max = 2, | ||
845 | .nid = 0x07, /* NID to query formats and rates */ | ||
846 | .ops = { | ||
847 | .prepare = alc880_capture_pcm_prepare, | ||
848 | .cleanup = alc880_capture_pcm_cleanup | ||
849 | }, | ||
850 | }; | ||
851 | |||
852 | static struct hda_pcm_stream alc880_pcm_digital_playback = { | ||
853 | .substreams = 1, | ||
854 | .channels_min = 2, | ||
855 | .channels_max = 2, | ||
856 | /* NID is set in alc_build_pcms */ | ||
857 | .ops = { | ||
858 | .open = alc880_dig_playback_pcm_open, | ||
859 | .close = alc880_dig_playback_pcm_close | ||
860 | }, | ||
861 | }; | ||
862 | |||
863 | static struct hda_pcm_stream alc880_pcm_digital_capture = { | ||
864 | .substreams = 1, | ||
865 | .channels_min = 2, | ||
866 | .channels_max = 2, | ||
867 | /* NID is set in alc_build_pcms */ | ||
868 | }; | ||
869 | |||
870 | static int alc_build_pcms(struct hda_codec *codec) | ||
871 | { | ||
872 | struct alc_spec *spec = codec->spec; | ||
873 | struct hda_pcm *info = spec->pcm_rec; | ||
874 | int i; | ||
875 | |||
876 | codec->num_pcms = 1; | ||
877 | codec->pcm_info = info; | ||
878 | |||
879 | info->name = spec->stream_name_analog; | ||
880 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback); | ||
881 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); | ||
882 | |||
883 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0; | ||
884 | for (i = 0; i < spec->num_channel_mode; i++) { | ||
885 | if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) { | ||
886 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels; | ||
887 | } | ||
888 | } | ||
889 | |||
890 | if (spec->multiout.dig_out_nid || spec->dig_in_nid) { | ||
891 | codec->num_pcms++; | ||
892 | info++; | ||
893 | info->name = spec->stream_name_digital; | ||
894 | if (spec->multiout.dig_out_nid) { | ||
895 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback); | ||
896 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; | ||
897 | } | ||
898 | if (spec->dig_in_nid) { | ||
899 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture); | ||
900 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; | ||
901 | } | ||
902 | } | ||
903 | |||
904 | return 0; | ||
905 | } | ||
906 | |||
907 | static void alc_free(struct hda_codec *codec) | ||
908 | { | ||
909 | kfree(codec->spec); | ||
910 | } | ||
911 | |||
912 | /* | ||
913 | */ | ||
914 | static struct hda_codec_ops alc_patch_ops = { | ||
915 | .build_controls = alc_build_controls, | ||
916 | .build_pcms = alc_build_pcms, | ||
917 | .init = alc_init, | ||
918 | .free = alc_free, | ||
919 | #ifdef CONFIG_PM | ||
920 | .resume = alc_resume, | ||
921 | #endif | ||
922 | }; | ||
923 | |||
924 | /* | ||
925 | */ | ||
926 | |||
927 | static struct hda_board_config alc880_cfg_tbl[] = { | ||
928 | /* Back 3 jack, front 2 jack */ | ||
929 | { .modelname = "3stack", .config = ALC880_3ST }, | ||
930 | { .pci_vendor = 0x8086, .pci_device = 0xe200, .config = ALC880_3ST }, | ||
931 | { .pci_vendor = 0x8086, .pci_device = 0xe201, .config = ALC880_3ST }, | ||
932 | { .pci_vendor = 0x8086, .pci_device = 0xe202, .config = ALC880_3ST }, | ||
933 | { .pci_vendor = 0x8086, .pci_device = 0xe203, .config = ALC880_3ST }, | ||
934 | { .pci_vendor = 0x8086, .pci_device = 0xe204, .config = ALC880_3ST }, | ||
935 | { .pci_vendor = 0x8086, .pci_device = 0xe205, .config = ALC880_3ST }, | ||
936 | { .pci_vendor = 0x8086, .pci_device = 0xe206, .config = ALC880_3ST }, | ||
937 | { .pci_vendor = 0x8086, .pci_device = 0xe207, .config = ALC880_3ST }, | ||
938 | { .pci_vendor = 0x8086, .pci_device = 0xe208, .config = ALC880_3ST }, | ||
939 | { .pci_vendor = 0x8086, .pci_device = 0xe209, .config = ALC880_3ST }, | ||
940 | { .pci_vendor = 0x8086, .pci_device = 0xe20a, .config = ALC880_3ST }, | ||
941 | { .pci_vendor = 0x8086, .pci_device = 0xe20b, .config = ALC880_3ST }, | ||
942 | { .pci_vendor = 0x8086, .pci_device = 0xe20c, .config = ALC880_3ST }, | ||
943 | { .pci_vendor = 0x8086, .pci_device = 0xe20d, .config = ALC880_3ST }, | ||
944 | { .pci_vendor = 0x8086, .pci_device = 0xe20e, .config = ALC880_3ST }, | ||
945 | { .pci_vendor = 0x8086, .pci_device = 0xe20f, .config = ALC880_3ST }, | ||
946 | { .pci_vendor = 0x8086, .pci_device = 0xe210, .config = ALC880_3ST }, | ||
947 | { .pci_vendor = 0x8086, .pci_device = 0xe211, .config = ALC880_3ST }, | ||
948 | { .pci_vendor = 0x8086, .pci_device = 0xe214, .config = ALC880_3ST }, | ||
949 | { .pci_vendor = 0x8086, .pci_device = 0xe302, .config = ALC880_3ST }, | ||
950 | { .pci_vendor = 0x8086, .pci_device = 0xe303, .config = ALC880_3ST }, | ||
951 | { .pci_vendor = 0x8086, .pci_device = 0xe304, .config = ALC880_3ST }, | ||
952 | { .pci_vendor = 0x8086, .pci_device = 0xe306, .config = ALC880_3ST }, | ||
953 | { .pci_vendor = 0x8086, .pci_device = 0xe307, .config = ALC880_3ST }, | ||
954 | { .pci_vendor = 0x8086, .pci_device = 0xe404, .config = ALC880_3ST }, | ||
955 | { .pci_vendor = 0x8086, .pci_device = 0xa101, .config = ALC880_3ST }, | ||
956 | { .pci_vendor = 0x107b, .pci_device = 0x3031, .config = ALC880_3ST }, | ||
957 | { .pci_vendor = 0x107b, .pci_device = 0x4036, .config = ALC880_3ST }, | ||
958 | { .pci_vendor = 0x107b, .pci_device = 0x4037, .config = ALC880_3ST }, | ||
959 | { .pci_vendor = 0x107b, .pci_device = 0x4038, .config = ALC880_3ST }, | ||
960 | { .pci_vendor = 0x107b, .pci_device = 0x4040, .config = ALC880_3ST }, | ||
961 | { .pci_vendor = 0x107b, .pci_device = 0x4041, .config = ALC880_3ST }, | ||
962 | |||
963 | /* Back 3 jack, front 2 jack (Internal add Aux-In) */ | ||
964 | { .pci_vendor = 0x1025, .pci_device = 0xe310, .config = ALC880_3ST }, | ||
965 | |||
966 | /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */ | ||
967 | { .modelname = "3stack-digout", .config = ALC880_3ST_DIG }, | ||
968 | { .pci_vendor = 0x8086, .pci_device = 0xe308, .config = ALC880_3ST_DIG }, | ||
969 | |||
970 | /* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/ | ||
971 | { .pci_vendor = 0x8086, .pci_device = 0xe305, .config = ALC880_3ST_DIG }, | ||
972 | { .pci_vendor = 0x8086, .pci_device = 0xd402, .config = ALC880_3ST_DIG }, | ||
973 | { .pci_vendor = 0x1025, .pci_device = 0xe309, .config = ALC880_3ST_DIG }, | ||
974 | |||
975 | /* Back 5 jack, front 2 jack */ | ||
976 | { .modelname = "5stack", .config = ALC880_5ST }, | ||
977 | { .pci_vendor = 0x107b, .pci_device = 0x3033, .config = ALC880_5ST }, | ||
978 | { .pci_vendor = 0x107b, .pci_device = 0x4039, .config = ALC880_5ST }, | ||
979 | { .pci_vendor = 0x107b, .pci_device = 0x3032, .config = ALC880_5ST }, | ||
980 | { .pci_vendor = 0x103c, .pci_device = 0x2a09, .config = ALC880_5ST }, | ||
981 | |||
982 | /* Back 5 jack plus 1 SPDIF out jack, front 2 jack */ | ||
983 | { .modelname = "5stack-digout", .config = ALC880_5ST_DIG }, | ||
984 | { .pci_vendor = 0x8086, .pci_device = 0xe224, .config = ALC880_5ST_DIG }, | ||
985 | { .pci_vendor = 0x8086, .pci_device = 0xe400, .config = ALC880_5ST_DIG }, | ||
986 | { .pci_vendor = 0x8086, .pci_device = 0xe401, .config = ALC880_5ST_DIG }, | ||
987 | { .pci_vendor = 0x8086, .pci_device = 0xe402, .config = ALC880_5ST_DIG }, | ||
988 | { .pci_vendor = 0x8086, .pci_device = 0xd400, .config = ALC880_5ST_DIG }, | ||
989 | { .pci_vendor = 0x8086, .pci_device = 0xd401, .config = ALC880_5ST_DIG }, | ||
990 | { .pci_vendor = 0x8086, .pci_device = 0xa100, .config = ALC880_5ST_DIG }, | ||
991 | { .pci_vendor = 0x1565, .pci_device = 0x8202, .config = ALC880_5ST_DIG }, | ||
992 | |||
993 | { .modelname = "w810", .config = ALC880_W810 }, | ||
994 | { .pci_vendor = 0x161f, .pci_device = 0x203d, .config = ALC880_W810 }, | ||
995 | |||
996 | {} | ||
997 | }; | ||
998 | |||
999 | static int patch_alc880(struct hda_codec *codec) | ||
1000 | { | ||
1001 | struct alc_spec *spec; | ||
1002 | int board_config; | ||
1003 | |||
1004 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | ||
1005 | if (spec == NULL) | ||
1006 | return -ENOMEM; | ||
1007 | |||
1008 | codec->spec = spec; | ||
1009 | |||
1010 | board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl); | ||
1011 | if (board_config < 0) { | ||
1012 | snd_printd(KERN_INFO "hda_codec: Unknown model for ALC880\n"); | ||
1013 | board_config = ALC880_MINIMAL; | ||
1014 | } | ||
1015 | |||
1016 | switch (board_config) { | ||
1017 | case ALC880_W810: | ||
1018 | spec->mixers[spec->num_mixers] = alc880_w810_base_mixer; | ||
1019 | spec->num_mixers++; | ||
1020 | break; | ||
1021 | case ALC880_5ST: | ||
1022 | case ALC880_5ST_DIG: | ||
1023 | spec->mixers[spec->num_mixers] = alc880_five_stack_mixer; | ||
1024 | spec->num_mixers++; | ||
1025 | break; | ||
1026 | default: | ||
1027 | spec->mixers[spec->num_mixers] = alc880_base_mixer; | ||
1028 | spec->num_mixers++; | ||
1029 | break; | ||
1030 | } | ||
1031 | |||
1032 | switch (board_config) { | ||
1033 | case ALC880_3ST_DIG: | ||
1034 | case ALC880_5ST_DIG: | ||
1035 | case ALC880_W810: | ||
1036 | spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; | ||
1037 | break; | ||
1038 | default: | ||
1039 | break; | ||
1040 | } | ||
1041 | |||
1042 | switch (board_config) { | ||
1043 | case ALC880_3ST: | ||
1044 | case ALC880_3ST_DIG: | ||
1045 | case ALC880_5ST: | ||
1046 | case ALC880_5ST_DIG: | ||
1047 | case ALC880_W810: | ||
1048 | spec->front_panel = 1; | ||
1049 | break; | ||
1050 | default: | ||
1051 | break; | ||
1052 | } | ||
1053 | |||
1054 | switch (board_config) { | ||
1055 | case ALC880_5ST: | ||
1056 | case ALC880_5ST_DIG: | ||
1057 | spec->init_verbs = alc880_init_verbs_five_stack; | ||
1058 | spec->channel_mode = alc880_fivestack_modes; | ||
1059 | spec->num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes); | ||
1060 | break; | ||
1061 | case ALC880_W810: | ||
1062 | spec->init_verbs = alc880_w810_init_verbs; | ||
1063 | spec->channel_mode = alc880_w810_modes; | ||
1064 | spec->num_channel_mode = ARRAY_SIZE(alc880_w810_modes); | ||
1065 | break; | ||
1066 | default: | ||
1067 | spec->init_verbs = alc880_init_verbs_three_stack; | ||
1068 | spec->channel_mode = alc880_threestack_modes; | ||
1069 | spec->num_channel_mode = ARRAY_SIZE(alc880_threestack_modes); | ||
1070 | break; | ||
1071 | } | ||
1072 | |||
1073 | spec->stream_name_analog = "ALC880 Analog"; | ||
1074 | spec->stream_analog_playback = &alc880_pcm_analog_playback; | ||
1075 | spec->stream_analog_capture = &alc880_pcm_analog_capture; | ||
1076 | |||
1077 | spec->stream_name_digital = "ALC880 Digital"; | ||
1078 | spec->stream_digital_playback = &alc880_pcm_digital_playback; | ||
1079 | spec->stream_digital_capture = &alc880_pcm_digital_capture; | ||
1080 | |||
1081 | spec->multiout.max_channels = spec->channel_mode[0].channels; | ||
1082 | |||
1083 | switch (board_config) { | ||
1084 | case ALC880_W810: | ||
1085 | spec->multiout.num_dacs = ARRAY_SIZE(alc880_w810_dac_nids); | ||
1086 | spec->multiout.dac_nids = alc880_w810_dac_nids; | ||
1087 | // No dedicated headphone socket - it's shared with built-in speakers. | ||
1088 | break; | ||
1089 | default: | ||
1090 | spec->multiout.num_dacs = ARRAY_SIZE(alc880_dac_nids); | ||
1091 | spec->multiout.dac_nids = alc880_dac_nids; | ||
1092 | spec->multiout.hp_nid = 0x03; /* rear-surround NID */ | ||
1093 | break; | ||
1094 | } | ||
1095 | |||
1096 | spec->input_mux = &alc880_capture_source; | ||
1097 | spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); | ||
1098 | spec->adc_nids = alc880_adc_nids; | ||
1099 | |||
1100 | codec->patch_ops = alc_patch_ops; | ||
1101 | |||
1102 | return 0; | ||
1103 | } | ||
1104 | |||
1105 | /* | ||
1106 | * ALC260 support | ||
1107 | */ | ||
1108 | |||
1109 | /* | ||
1110 | * This is just place-holder, so there's something for alc_build_pcms to look | ||
1111 | * at when it calculates the maximum number of channels. ALC260 has no mixer | ||
1112 | * element which allows changing the channel mode, so the verb list is | ||
1113 | * never used. | ||
1114 | */ | ||
1115 | static struct alc_channel_mode alc260_modes[1] = { | ||
1116 | { 2, NULL }, | ||
1117 | }; | ||
1118 | |||
1119 | snd_kcontrol_new_t alc260_base_mixer[] = { | ||
1120 | HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), | ||
1121 | /* use LINE2 for the output */ | ||
1122 | /* HDA_CODEC_MUTE("Front Playback Switch", 0x0f, 0x0, HDA_OUTPUT), */ | ||
1123 | HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
1124 | HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), | ||
1125 | HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), | ||
1126 | HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), | ||
1127 | HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT), | ||
1128 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT), | ||
1129 | HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT), | ||
1130 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), | ||
1131 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), | ||
1132 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT), | ||
1133 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT), | ||
1134 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), | ||
1135 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT), | ||
1136 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), | ||
1137 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT), | ||
1138 | HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), | ||
1139 | HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), | ||
1140 | { | ||
1141 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1142 | .name = "Capture Source", | ||
1143 | .info = alc_mux_enum_info, | ||
1144 | .get = alc_mux_enum_get, | ||
1145 | .put = alc_mux_enum_put, | ||
1146 | }, | ||
1147 | { } /* end */ | ||
1148 | }; | ||
1149 | |||
1150 | static struct hda_verb alc260_init_verbs[] = { | ||
1151 | /* Line In pin widget for input */ | ||
1152 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
1153 | /* CD pin widget for input */ | ||
1154 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
1155 | /* Mic1 (rear panel) pin widget for input and vref at 80% */ | ||
1156 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
1157 | /* Mic2 (front panel) pin widget for input and vref at 80% */ | ||
1158 | {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
1159 | /* LINE-2 is used for line-out in rear */ | ||
1160 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
1161 | /* select line-out */ | ||
1162 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1163 | /* LINE-OUT pin */ | ||
1164 | {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
1165 | /* enable HP */ | ||
1166 | {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
1167 | /* enable Mono */ | ||
1168 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
1169 | /* unmute amp left and right */ | ||
1170 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | ||
1171 | /* set connection select to line in (default select for this ADC) */ | ||
1172 | {0x04, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
1173 | /* unmute Line-Out mixer amp left and right (volume = 0) */ | ||
1174 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1175 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
1176 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1177 | /* unmute HP mixer amp left and right (volume = 0) */ | ||
1178 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1179 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
1180 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1181 | /* unmute Mono mixer amp left and right (volume = 0) */ | ||
1182 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1183 | /* mute pin widget amp left and right (no gain on this amp) */ | ||
1184 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1185 | /* mute LINE-2 out */ | ||
1186 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | ||
1187 | /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & Line In 2 = 0x03 */ | ||
1188 | /* unmute CD */ | ||
1189 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, | ||
1190 | /* unmute Line In */ | ||
1191 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | ||
1192 | /* unmute Mic */ | ||
1193 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
1194 | /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ | ||
1195 | /* Unmute Front out path */ | ||
1196 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
1197 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
1198 | /* Unmute Headphone out path */ | ||
1199 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
1200 | {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
1201 | /* Unmute Mono out path */ | ||
1202 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
1203 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
1204 | { } | ||
1205 | }; | ||
1206 | |||
1207 | static struct hda_pcm_stream alc260_pcm_analog_playback = { | ||
1208 | .substreams = 1, | ||
1209 | .channels_min = 2, | ||
1210 | .channels_max = 2, | ||
1211 | .nid = 0x2, | ||
1212 | }; | ||
1213 | |||
1214 | static struct hda_pcm_stream alc260_pcm_analog_capture = { | ||
1215 | .substreams = 1, | ||
1216 | .channels_min = 2, | ||
1217 | .channels_max = 2, | ||
1218 | .nid = 0x4, | ||
1219 | }; | ||
1220 | |||
1221 | static int patch_alc260(struct hda_codec *codec) | ||
1222 | { | ||
1223 | struct alc_spec *spec; | ||
1224 | |||
1225 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | ||
1226 | if (spec == NULL) | ||
1227 | return -ENOMEM; | ||
1228 | |||
1229 | codec->spec = spec; | ||
1230 | |||
1231 | spec->mixers[spec->num_mixers] = alc260_base_mixer; | ||
1232 | spec->num_mixers++; | ||
1233 | |||
1234 | spec->init_verbs = alc260_init_verbs; | ||
1235 | spec->channel_mode = alc260_modes; | ||
1236 | spec->num_channel_mode = ARRAY_SIZE(alc260_modes); | ||
1237 | |||
1238 | spec->stream_name_analog = "ALC260 Analog"; | ||
1239 | spec->stream_analog_playback = &alc260_pcm_analog_playback; | ||
1240 | spec->stream_analog_capture = &alc260_pcm_analog_capture; | ||
1241 | |||
1242 | spec->multiout.max_channels = spec->channel_mode[0].channels; | ||
1243 | spec->multiout.num_dacs = ARRAY_SIZE(alc260_dac_nids); | ||
1244 | spec->multiout.dac_nids = alc260_dac_nids; | ||
1245 | |||
1246 | spec->input_mux = &alc260_capture_source; | ||
1247 | spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); | ||
1248 | spec->adc_nids = alc260_adc_nids; | ||
1249 | |||
1250 | codec->patch_ops = alc_patch_ops; | ||
1251 | |||
1252 | return 0; | ||
1253 | } | ||
1254 | |||
1255 | /* | ||
1256 | * ALC882 support | ||
1257 | * | ||
1258 | * ALC882 is almost identical with ALC880 but has cleaner and more flexible | ||
1259 | * configuration. Each pin widget can choose any input DACs and a mixer. | ||
1260 | * Each ADC is connected from a mixer of all inputs. This makes possible | ||
1261 | * 6-channel independent captures. | ||
1262 | * | ||
1263 | * In addition, an independent DAC for the multi-playback (not used in this | ||
1264 | * driver yet). | ||
1265 | */ | ||
1266 | |||
1267 | static struct alc_channel_mode alc882_ch_modes[1] = { | ||
1268 | { 8, NULL } | ||
1269 | }; | ||
1270 | |||
1271 | static hda_nid_t alc882_dac_nids[4] = { | ||
1272 | /* front, rear, clfe, rear_surr */ | ||
1273 | 0x02, 0x03, 0x04, 0x05 | ||
1274 | }; | ||
1275 | |||
1276 | static hda_nid_t alc882_adc_nids[3] = { | ||
1277 | /* ADC0-2 */ | ||
1278 | 0x07, 0x08, 0x09, | ||
1279 | }; | ||
1280 | |||
1281 | /* input MUX */ | ||
1282 | /* FIXME: should be a matrix-type input source selection */ | ||
1283 | |||
1284 | static struct hda_input_mux alc882_capture_source = { | ||
1285 | .num_items = 4, | ||
1286 | .items = { | ||
1287 | { "Mic", 0x0 }, | ||
1288 | { "Front Mic", 0x1 }, | ||
1289 | { "Line", 0x2 }, | ||
1290 | { "CD", 0x4 }, | ||
1291 | }, | ||
1292 | }; | ||
1293 | |||
1294 | #define alc882_mux_enum_info alc_mux_enum_info | ||
1295 | #define alc882_mux_enum_get alc_mux_enum_get | ||
1296 | |||
1297 | static int alc882_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
1298 | { | ||
1299 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1300 | struct alc_spec *spec = codec->spec; | ||
1301 | const struct hda_input_mux *imux = spec->input_mux; | ||
1302 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
1303 | static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 }; | ||
1304 | hda_nid_t nid = capture_mixers[adc_idx]; | ||
1305 | unsigned int *cur_val = &spec->cur_mux[adc_idx]; | ||
1306 | unsigned int i, idx; | ||
1307 | |||
1308 | idx = ucontrol->value.enumerated.item[0]; | ||
1309 | if (idx >= imux->num_items) | ||
1310 | idx = imux->num_items - 1; | ||
1311 | if (*cur_val == idx && ! codec->in_resume) | ||
1312 | return 0; | ||
1313 | for (i = 0; i < imux->num_items; i++) { | ||
1314 | unsigned int v = (i == idx) ? 0x7000 : 0x7080; | ||
1315 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
1316 | v | (imux->items[i].index << 8)); | ||
1317 | } | ||
1318 | *cur_val = idx; | ||
1319 | return 1; | ||
1320 | } | ||
1321 | |||
1322 | /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 | ||
1323 | * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b | ||
1324 | */ | ||
1325 | static snd_kcontrol_new_t alc882_base_mixer[] = { | ||
1326 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
1327 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
1328 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
1329 | HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
1330 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), | ||
1331 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | ||
1332 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x16, 1, 0x0, HDA_OUTPUT), | ||
1333 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), | ||
1334 | HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), | ||
1335 | HDA_CODEC_MUTE("Side Playback Switch", 0x17, 0x0, HDA_OUTPUT), | ||
1336 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
1337 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
1338 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
1339 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
1340 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
1341 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
1342 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
1343 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
1344 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
1345 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | ||
1346 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | ||
1347 | HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), | ||
1348 | HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), | ||
1349 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), | ||
1350 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), | ||
1351 | HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), | ||
1352 | HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), | ||
1353 | { | ||
1354 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1355 | /* .name = "Capture Source", */ | ||
1356 | .name = "Input Source", | ||
1357 | .count = 3, | ||
1358 | .info = alc882_mux_enum_info, | ||
1359 | .get = alc882_mux_enum_get, | ||
1360 | .put = alc882_mux_enum_put, | ||
1361 | }, | ||
1362 | { } /* end */ | ||
1363 | }; | ||
1364 | |||
1365 | static struct hda_verb alc882_init_verbs[] = { | ||
1366 | /* Front mixer: unmute input/output amp left and right (volume = 0) */ | ||
1367 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1368 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
1369 | /* Rear mixer */ | ||
1370 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1371 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
1372 | /* CLFE mixer */ | ||
1373 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1374 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
1375 | /* Side mixer */ | ||
1376 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | ||
1377 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
1378 | |||
1379 | /* Front Pin: to output mode */ | ||
1380 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
1381 | /* Front Pin: mute amp left and right (no volume) */ | ||
1382 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
1383 | /* select Front mixer (0x0c, index 0) */ | ||
1384 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1385 | /* Rear Pin */ | ||
1386 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
1387 | /* Rear Pin: mute amp left and right (no volume) */ | ||
1388 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
1389 | /* select Rear mixer (0x0d, index 1) */ | ||
1390 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
1391 | /* CLFE Pin */ | ||
1392 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
1393 | /* CLFE Pin: mute amp left and right (no volume) */ | ||
1394 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
1395 | /* select CLFE mixer (0x0e, index 2) */ | ||
1396 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
1397 | /* Side Pin */ | ||
1398 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
1399 | /* Side Pin: mute amp left and right (no volume) */ | ||
1400 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
1401 | /* select Side mixer (0x0f, index 3) */ | ||
1402 | {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
1403 | /* Headphone Pin */ | ||
1404 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
1405 | /* Headphone Pin: mute amp left and right (no volume) */ | ||
1406 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000}, | ||
1407 | /* select Front mixer (0x0c, index 0) */ | ||
1408 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1409 | /* Mic (rear) pin widget for input and vref at 80% */ | ||
1410 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
1411 | /* Front Mic pin widget for input and vref at 80% */ | ||
1412 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
1413 | /* Line In pin widget for input */ | ||
1414 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
1415 | /* CD pin widget for input */ | ||
1416 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
1417 | |||
1418 | /* FIXME: use matrix-type input source selection */ | ||
1419 | /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ | ||
1420 | /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ | ||
1421 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
1422 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, | ||
1423 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, | ||
1424 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | ||
1425 | /* Input mixer2 */ | ||
1426 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
1427 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, | ||
1428 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, | ||
1429 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | ||
1430 | /* Input mixer3 */ | ||
1431 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
1432 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, | ||
1433 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, | ||
1434 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | ||
1435 | /* ADC1: unmute amp left and right */ | ||
1436 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | ||
1437 | /* ADC2: unmute amp left and right */ | ||
1438 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | ||
1439 | /* ADC3: unmute amp left and right */ | ||
1440 | {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000}, | ||
1441 | |||
1442 | /* Unmute front loopback */ | ||
1443 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
1444 | /* Unmute rear loopback */ | ||
1445 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
1446 | /* Mute CLFE loopback */ | ||
1447 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, | ||
1448 | /* Unmute side loopback */ | ||
1449 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
1450 | |||
1451 | { } | ||
1452 | }; | ||
1453 | |||
1454 | static int patch_alc882(struct hda_codec *codec) | ||
1455 | { | ||
1456 | struct alc_spec *spec; | ||
1457 | |||
1458 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | ||
1459 | if (spec == NULL) | ||
1460 | return -ENOMEM; | ||
1461 | |||
1462 | codec->spec = spec; | ||
1463 | |||
1464 | spec->mixers[spec->num_mixers] = alc882_base_mixer; | ||
1465 | spec->num_mixers++; | ||
1466 | |||
1467 | spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; | ||
1468 | spec->dig_in_nid = ALC880_DIGIN_NID; | ||
1469 | spec->front_panel = 1; | ||
1470 | spec->init_verbs = alc882_init_verbs; | ||
1471 | spec->channel_mode = alc882_ch_modes; | ||
1472 | spec->num_channel_mode = ARRAY_SIZE(alc882_ch_modes); | ||
1473 | |||
1474 | spec->stream_name_analog = "ALC882 Analog"; | ||
1475 | spec->stream_analog_playback = &alc880_pcm_analog_playback; | ||
1476 | spec->stream_analog_capture = &alc880_pcm_analog_capture; | ||
1477 | |||
1478 | spec->stream_name_digital = "ALC882 Digital"; | ||
1479 | spec->stream_digital_playback = &alc880_pcm_digital_playback; | ||
1480 | spec->stream_digital_capture = &alc880_pcm_digital_capture; | ||
1481 | |||
1482 | spec->multiout.max_channels = spec->channel_mode[0].channels; | ||
1483 | spec->multiout.num_dacs = ARRAY_SIZE(alc882_dac_nids); | ||
1484 | spec->multiout.dac_nids = alc882_dac_nids; | ||
1485 | |||
1486 | spec->input_mux = &alc882_capture_source; | ||
1487 | spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids); | ||
1488 | spec->adc_nids = alc882_adc_nids; | ||
1489 | |||
1490 | codec->patch_ops = alc_patch_ops; | ||
1491 | |||
1492 | return 0; | ||
1493 | } | ||
1494 | |||
1495 | /* | ||
1496 | * patch entries | ||
1497 | */ | ||
1498 | struct hda_codec_preset snd_hda_preset_realtek[] = { | ||
1499 | { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, | ||
1500 | { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, | ||
1501 | { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, | ||
1502 | {} /* terminator */ | ||
1503 | }; | ||