This source file includes following definitions.
- azalia_codec_init_vtbl
- azalia_generic_codec_init_dacgroup
- azalia_generic_codec_add_dacgroup
- azalia_generic_codec_find_pin
- azalia_generic_codec_find_dac
- azalia_generic_mixer_init
- azalia_generic_mixer_ensure_capacity
- azalia_generic_mixer_fix_indexes
- azalia_generic_mixer_default
- azalia_generic_mixer_delete
- azalia_generic_mixer_get
- azalia_generic_mixer_set
- azalia_generic_mixer_pinctrl
- azalia_generic_mixer_from_device_value
- azalia_generic_mixer_to_device_value
- azalia_generic_mixer_max
- azalia_generic_mixer_validate_value
- azalia_generic_set_port
- azalia_generic_get_port
- azalia_alc260_mixer_init
- azalia_alc260_init_dacgroup
- azalia_alc260_set_port
- azalia_alc880_init_dacgroup
- azalia_alc882_mixer_init
- azalia_alc882_init_dacgroup
- azalia_alc882_set_port
- azalia_alc882_get_port
- azalia_alc883_init_dacgroup
- azalia_alc883_mixer_init
- azalia_ad1981hd_init_widget
- azalia_ad1981hd_mixer_init
- azalia_cmi9880_mixer_init
- azalia_cmi9880_init_dacgroup
- azalia_stac9221_init_dacgroup
- azalia_stac9200_mixer_init
- azalia_stac9200_unsol_event
- azalia_stac9221_apple_init_dacgroup
- azalia_stac9221_apple_mixer_init
- azalia_stac9221_gpio_unmute
- azalia_stac7661_init_dacgroup
- azalia_stac7661_mixer_init
- azalia_stac7661_set_port
- azalia_stac7661_get_port
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 #include <sys/cdefs.h>
41 #ifdef NETBSD_GOOP
42 __KERNEL_RCSID(0, "$NetBSD: azalia_codec.c,v 1.3 2005/09/29 04:14:03 kent Exp $");
43 #endif
44
45 #include <sys/param.h>
46 #include <sys/device.h>
47 #include <sys/malloc.h>
48 #include <sys/systm.h>
49 #include <uvm/uvm_param.h>
50 #include <dev/pci/azalia.h>
51
52 #define XNAME(co) (((struct device *)co->az)->dv_xname)
53 #ifdef MAX_VOLUME_255
54 # define MIXER_DELTA(n) (AUDIO_MAX_GAIN / (n))
55 #else
56 # define MIXER_DELTA(n) (1)
57 #endif
58 #define AZ_CLASS_INPUT 0
59 #define AZ_CLASS_OUTPUT 1
60 #define AZ_CLASS_RECORD 2
61 #define ENUM_OFFON .un.e={2, {{{AudioNoff}, 0}, {{AudioNon}, 1}}}
62 #define ENUM_IO .un.e={2, {{{"input"}, 0}, {{"output"}, 1}}}
63 #define AzaliaNfront "front"
64 #define AzaliaNclfe "clfe"
65 #define AzaliaNside "side"
66
67
68 int azalia_generic_codec_init_dacgroup(codec_t *);
69 int azalia_generic_codec_add_dacgroup(codec_t *, int, uint32_t);
70 int azalia_generic_codec_find_pin(const codec_t *, int, int, uint32_t);
71 int azalia_generic_codec_find_dac(const codec_t *, int, int);
72
73 int azalia_generic_mixer_init(codec_t *);
74 int azalia_generic_mixer_fix_indexes(codec_t *);
75 int azalia_generic_mixer_default(codec_t *);
76 int azalia_generic_mixer_delete(codec_t *);
77 int azalia_generic_mixer_ensure_capacity(codec_t *, size_t);
78 int azalia_generic_mixer_get(const codec_t *, nid_t, int, mixer_ctrl_t *);
79 int azalia_generic_mixer_set(codec_t *, nid_t, int, const mixer_ctrl_t *);
80 int azalia_generic_mixer_pinctrl(codec_t *, nid_t, uint32_t);
81 u_char azalia_generic_mixer_from_device_value
82 (const codec_t *, nid_t, int, uint32_t );
83 uint32_t azalia_generic_mixer_to_device_value
84 (const codec_t *, nid_t, int, u_char);
85 uint32_t azalia_generic_mixer_max(const codec_t *, nid_t, int);
86 boolean_t azalia_generic_mixer_validate_value
87 (const codec_t *, nid_t, int, u_char);
88 int azalia_generic_set_port(codec_t *, mixer_ctrl_t *);
89 int azalia_generic_get_port(codec_t *, mixer_ctrl_t *);
90
91 int azalia_alc260_init_dacgroup(codec_t *);
92 int azalia_alc260_mixer_init(codec_t *);
93 int azalia_alc260_set_port(codec_t *, mixer_ctrl_t *);
94 int azalia_alc880_init_dacgroup(codec_t *);
95 int azalia_alc882_init_dacgroup(codec_t *);
96 int azalia_alc882_mixer_init(codec_t *);
97 int azalia_alc882_set_port(codec_t *, mixer_ctrl_t *);
98 int azalia_alc882_get_port(codec_t *, mixer_ctrl_t *);
99 int azalia_alc883_init_dacgroup(codec_t *);
100 int azalia_alc883_mixer_init(codec_t *);
101 int azalia_ad1981hd_init_widget(const codec_t *, widget_t *, nid_t);
102 int azalia_ad1981hd_mixer_init(codec_t *);
103 int azalia_cmi9880_init_dacgroup(codec_t *);
104 int azalia_cmi9880_mixer_init(codec_t *);
105 int azalia_stac9221_init_dacgroup(codec_t *);
106 int azalia_stac9200_mixer_init(codec_t *);
107 int azalia_stac9200_unsol_event(codec_t *, int);
108 int azalia_stac9221_apple_mixer_init(codec_t *);
109 int azalia_stac9221_apple_init_dacgroup(codec_t *);
110 int azalia_stac9221_gpio_unmute(codec_t *, int);
111 int azalia_stac7661_init_dacgroup(codec_t *);
112 int azalia_stac7661_mixer_init(codec_t *);
113 int azalia_stac7661_set_port(codec_t *, mixer_ctrl_t *);
114 int azalia_stac7661_get_port(codec_t *, mixer_ctrl_t *);
115
116 int
117 azalia_codec_init_vtbl(codec_t *this)
118 {
119
120
121
122 DPRINTF(("%s: vid=%08x subid=%08x\n", __func__, this->vid, this->subid));
123 this->name = NULL;
124 this->init_dacgroup = azalia_generic_codec_init_dacgroup;
125 this->mixer_init = azalia_generic_mixer_init;
126 this->mixer_delete = azalia_generic_mixer_delete;
127 this->set_port = azalia_generic_set_port;
128 this->get_port = azalia_generic_get_port;
129 switch (this->vid) {
130 case 0x10ec0260:
131 this->name = "Realtek ALC260";
132 this->mixer_init = azalia_alc260_mixer_init;
133 this->init_dacgroup = azalia_alc260_init_dacgroup;
134 this->set_port = azalia_alc260_set_port;
135 break;
136 case 0x10ec0880:
137 this->name = "Realtek ALC880";
138 this->init_dacgroup = azalia_alc880_init_dacgroup;
139 break;
140 case 0x10ec0882:
141 this->name = "Realtek ALC882";
142 this->init_dacgroup = azalia_alc882_init_dacgroup;
143 this->mixer_init = azalia_alc882_mixer_init;
144 this->get_port = azalia_alc882_get_port;
145 this->set_port = azalia_alc882_set_port;
146 break;
147 case 0x10ec0883:
148
149 this->name = "Realtek ALC883";
150 this->init_dacgroup = azalia_alc883_init_dacgroup;
151 this->mixer_init = azalia_alc883_mixer_init;
152 this->get_port = azalia_alc882_get_port;
153 this->set_port = azalia_alc882_set_port;
154 break;
155 case 0x11d41981:
156
157 this->name = "Analog Devices AD1981HD";
158 this->init_widget = azalia_ad1981hd_init_widget;
159 this->mixer_init = azalia_ad1981hd_mixer_init;
160 break;
161 case 0x11d41983:
162
163 this->name = "Analog Devices AD1983";
164 break;
165 case 0x434d4980:
166 this->name = "CMedia CMI9880";
167 this->init_dacgroup = azalia_cmi9880_init_dacgroup;
168 this->mixer_init = azalia_cmi9880_mixer_init;
169 break;
170 case 0x83847680:
171 this->name = "Sigmatel STAC9221";
172 this->init_dacgroup = azalia_stac9221_init_dacgroup;
173 if (this->subid == 0x76808384) {
174 this->init_dacgroup =
175 azalia_stac9221_apple_init_dacgroup;
176 this->mixer_init =
177 azalia_stac9221_apple_mixer_init;
178 break;
179 }
180 break;
181 case 0x83847683:
182 this->name = "Sigmatel STAC9221D";
183 this->init_dacgroup = azalia_stac9221_init_dacgroup;
184 break;
185 case 0x83847690:
186
187 this->name = "Sigmatel STAC9200";
188 this->mixer_init = azalia_stac9200_mixer_init;
189 this->unsol_event = azalia_stac9200_unsol_event;
190 break;
191 case 0x83847691:
192 this->name = "Sigmatel STAC9200D";
193 break;
194 case 0x83847661:
195 this->name = "Sigmatel 83847661";
196 this->init_dacgroup = azalia_stac7661_init_dacgroup;
197 this->mixer_init = azalia_stac7661_mixer_init;
198 this->get_port = azalia_stac7661_get_port;
199 this->set_port = azalia_stac7661_set_port;
200 break;
201 }
202 return 0;
203 }
204
205
206
207
208
209 int
210 azalia_generic_codec_init_dacgroup(codec_t *this)
211 {
212 int i, j, assoc, group;
213
214
215
216
217
218
219
220
221 this->dacs.ngroups = 0;
222 for (assoc = 0; assoc < CORB_CD_ASSOCIATION_MAX; assoc++) {
223 azalia_generic_codec_add_dacgroup(this, assoc, 0);
224 azalia_generic_codec_add_dacgroup(this, assoc, COP_AWCAP_DIGITAL);
225 }
226
227
228 DPRINTF(("%s: find non-connected DACs\n", __func__));
229 FOR_EACH_WIDGET(this, i) {
230 boolean_t found;
231
232 if (this->w[i].type != COP_AWTYPE_AUDIO_OUTPUT)
233 continue;
234 found = FALSE;
235 for (group = 0; group < this->dacs.ngroups; group++) {
236 for (j = 0; j < this->dacs.groups[group].nconv; j++) {
237 if (i == this->dacs.groups[group].conv[j]) {
238 found = TRUE;
239 group = this->dacs.ngroups;
240 break;
241 }
242 }
243 }
244 if (found)
245 continue;
246 if (this->dacs.ngroups >= 32)
247 break;
248 this->dacs.groups[this->dacs.ngroups].nconv = 1;
249 this->dacs.groups[this->dacs.ngroups].conv[0] = i;
250 this->dacs.ngroups++;
251 }
252 this->dacs.cur = 0;
253
254
255 this->adcs.ngroups = 0;
256 FOR_EACH_WIDGET(this, i) {
257 if (this->w[i].type != COP_AWTYPE_AUDIO_INPUT)
258 continue;
259 this->adcs.groups[this->adcs.ngroups].nconv = 1;
260 this->adcs.groups[this->adcs.ngroups].conv[0] = i;
261 this->adcs.ngroups++;
262 if (this->adcs.ngroups >= 32)
263 break;
264 }
265 this->adcs.cur = 0;
266 return 0;
267 }
268
269 int
270 azalia_generic_codec_add_dacgroup(codec_t *this, int assoc, uint32_t digital)
271 {
272 int i, j, n, dac, seq;
273
274 n = 0;
275 for (seq = 0 ; seq < CORB_CD_SEQUENCE_MAX; seq++) {
276 i = azalia_generic_codec_find_pin(this, assoc, seq, digital);
277 if (i < 0)
278 continue;
279 dac = azalia_generic_codec_find_dac(this, i, 0);
280 if (dac < 0)
281 continue;
282
283 for (j = 0; j < n; j++) {
284 if (this->dacs.groups[this->dacs.ngroups].conv[j] == dac)
285 break;
286 }
287 if (j < n)
288 continue;
289 this->dacs.groups[this->dacs.ngroups].conv[n++] = dac;
290 DPRINTF(("%s: assoc=%d seq=%d ==> g=%d n=%d\n",
291 __func__, assoc, seq, this->dacs.ngroups, n-1));
292 }
293 if (n <= 0)
294 return 0;
295 this->dacs.groups[this->dacs.ngroups].nconv = n;
296
297
298 for (i = 0; i < this->dacs.ngroups; i++) {
299 if (n != this->dacs.groups[i].nconv)
300 continue;
301 for (j = 0; j < n; j++) {
302 if (this->dacs.groups[this->dacs.ngroups].conv[j] !=
303 this->dacs.groups[i].conv[j])
304 break;
305 }
306 if (j >= n)
307 return 0;
308 }
309
310 this->dacs.ngroups++;
311 return 0;
312 }
313
314 int
315 azalia_generic_codec_find_pin(const codec_t *this, int assoc, int seq, uint32_t digital)
316 {
317 int i;
318
319 FOR_EACH_WIDGET(this, i) {
320 if (this->w[i].type != COP_AWTYPE_PIN_COMPLEX)
321 continue;
322 if ((this->w[i].d.pin.cap & COP_PINCAP_OUTPUT) == 0)
323 continue;
324 if ((this->w[i].widgetcap & COP_AWCAP_DIGITAL) != digital)
325 continue;
326 if (this->w[i].d.pin.association != assoc)
327 continue;
328 if (this->w[i].d.pin.sequence == seq) {
329 return i;
330 }
331 }
332 return -1;
333 }
334
335 int
336 azalia_generic_codec_find_dac(const codec_t *this, int index, int depth)
337 {
338 const widget_t *w;
339 int i, j, ret;
340
341 w = &this->w[index];
342 if (w->type == COP_AWTYPE_AUDIO_OUTPUT) {
343 DPRINTF(("%s: DAC: nid=0x%x index=%d\n",
344 __func__, w->nid, index));
345 return index;
346 }
347 if (++depth > 50) {
348 return -1;
349 }
350 if (w->selected >= 0) {
351 j = w->connections[w->selected];
352 if (VALID_WIDGET_NID(j, this)) {
353 ret = azalia_generic_codec_find_dac(this, j, depth);
354 if (ret >= 0) {
355 DPRINTF(("%s: DAC path: nid=0x%x index=%d\n",
356 __func__, w->nid, index));
357 return ret;
358 }
359 }
360 }
361 for (i = 0; i < w->nconnections; i++) {
362 j = w->connections[i];
363 if (!VALID_WIDGET_NID(j, this))
364 continue;
365 ret = azalia_generic_codec_find_dac(this, j, depth);
366 if (ret >= 0) {
367 DPRINTF(("%s: DAC path: nid=0x%x index=%d\n",
368 __func__, w->nid, index));
369 return ret;
370 }
371 }
372 return -1;
373 }
374
375
376
377
378
379 int
380 azalia_generic_mixer_init(codec_t *this)
381 {
382
383
384
385
386
387
388
389 mixer_item_t *m;
390 int err, i, j, k;
391
392 this->maxmixers = 10;
393 this->nmixers = 0;
394 this->mixers = malloc(sizeof(mixer_item_t) * this->maxmixers,
395 M_DEVBUF, M_NOWAIT);
396 if (this->mixers == NULL) {
397 printf("%s: out of memory in %s\n", XNAME(this), __func__);
398 return ENOMEM;
399 }
400 bzero(this->mixers, sizeof(mixer_item_t) * this->maxmixers);
401
402
403 DPRINTF(("%s: register classes\n", __func__));
404 m = &this->mixers[AZ_CLASS_INPUT];
405 m->devinfo.index = AZ_CLASS_INPUT;
406 strlcpy(m->devinfo.label.name, AudioCinputs,
407 sizeof(m->devinfo.label.name));
408 m->devinfo.type = AUDIO_MIXER_CLASS;
409 m->devinfo.mixer_class = AZ_CLASS_INPUT;
410 m->devinfo.next = AUDIO_MIXER_LAST;
411 m->devinfo.prev = AUDIO_MIXER_LAST;
412 m->nid = 0;
413
414 m = &this->mixers[AZ_CLASS_OUTPUT];
415 m->devinfo.index = AZ_CLASS_OUTPUT;
416 strlcpy(m->devinfo.label.name, AudioCoutputs,
417 sizeof(m->devinfo.label.name));
418 m->devinfo.type = AUDIO_MIXER_CLASS;
419 m->devinfo.mixer_class = AZ_CLASS_OUTPUT;
420 m->devinfo.next = AUDIO_MIXER_LAST;
421 m->devinfo.prev = AUDIO_MIXER_LAST;
422 m->nid = 0;
423
424 m = &this->mixers[AZ_CLASS_RECORD];
425 m->devinfo.index = AZ_CLASS_RECORD;
426 strlcpy(m->devinfo.label.name, AudioCrecord,
427 sizeof(m->devinfo.label.name));
428 m->devinfo.type = AUDIO_MIXER_CLASS;
429 m->devinfo.mixer_class = AZ_CLASS_RECORD;
430 m->devinfo.next = AUDIO_MIXER_LAST;
431 m->devinfo.prev = AUDIO_MIXER_LAST;
432 m->nid = 0;
433
434 this->nmixers = AZ_CLASS_RECORD + 1;
435
436 #define MIXER_REG_PROLOG \
437 mixer_devinfo_t *d; \
438 err = azalia_generic_mixer_ensure_capacity(this, this->nmixers + 1); \
439 if (err) \
440 return err; \
441 m = &this->mixers[this->nmixers]; \
442 d = &m->devinfo; \
443 m->nid = i
444
445 FOR_EACH_WIDGET(this, i) {
446 const widget_t *w;
447
448 w = &this->w[i];
449
450
451 if (w->type != COP_AWTYPE_AUDIO_MIXER && w->nconnections >= 2) {
452 MIXER_REG_PROLOG;
453 DPRINTF(("%s: selector %s\n", __func__, w->name));
454 snprintf(d->label.name, sizeof(d->label.name),
455 "%s.source", w->name);
456 d->type = AUDIO_MIXER_ENUM;
457 if (w->type == COP_AWTYPE_AUDIO_MIXER)
458 d->mixer_class = AZ_CLASS_RECORD;
459 else if (w->type == COP_AWTYPE_AUDIO_SELECTOR)
460 d->mixer_class = AZ_CLASS_INPUT;
461 else
462 d->mixer_class = AZ_CLASS_OUTPUT;
463 m->target = MI_TARGET_CONNLIST;
464 for (j = 0, k = 0; j < w->nconnections && k < 32; j++) {
465 if (!VALID_WIDGET_NID(w->connections[j], this))
466 continue;
467 DPRINTF(("%s: selector %d=%s\n", __func__, j,
468 this->w[w->connections[j]].name));
469 d->un.e.member[k].ord = j;
470 strlcpy(d->un.e.member[k].label.name,
471 this->w[w->connections[j]].name,
472 MAX_AUDIO_DEV_LEN);
473 k++;
474 }
475 d->un.e.num_mem = k;
476 this->nmixers++;
477 }
478
479
480 if (w->widgetcap & COP_AWCAP_OUTAMP &&
481 w->outamp_cap & COP_AMPCAP_MUTE) {
482 MIXER_REG_PROLOG;
483 DPRINTF(("%s: output mute %s\n", __func__, w->name));
484 snprintf(d->label.name, sizeof(d->label.name),
485 "%s.mute", w->name);
486 d->type = AUDIO_MIXER_ENUM;
487 if (w->type == COP_AWTYPE_AUDIO_MIXER)
488 d->mixer_class = AZ_CLASS_OUTPUT;
489 else if (w->type == COP_AWTYPE_AUDIO_SELECTOR)
490 d->mixer_class = AZ_CLASS_OUTPUT;
491 else if (w->type == COP_AWTYPE_PIN_COMPLEX)
492 d->mixer_class = AZ_CLASS_OUTPUT;
493 else
494 d->mixer_class = AZ_CLASS_INPUT;
495 m->target = MI_TARGET_OUTAMP;
496 d->un.e.num_mem = 2;
497 d->un.e.member[0].ord = 0;
498 strlcpy(d->un.e.member[0].label.name, AudioNoff,
499 MAX_AUDIO_DEV_LEN);
500 d->un.e.member[1].ord = 1;
501 strlcpy(d->un.e.member[1].label.name, AudioNon,
502 MAX_AUDIO_DEV_LEN);
503 this->nmixers++;
504 }
505
506
507 if (w->widgetcap & COP_AWCAP_OUTAMP
508 && COP_AMPCAP_NUMSTEPS(w->outamp_cap)) {
509 MIXER_REG_PROLOG;
510 DPRINTF(("%s: output gain %s\n", __func__, w->name));
511 snprintf(d->label.name, sizeof(d->label.name),
512 "%s", w->name);
513 d->type = AUDIO_MIXER_VALUE;
514 if (w->type == COP_AWTYPE_AUDIO_MIXER)
515 d->mixer_class = AZ_CLASS_OUTPUT;
516 else if (w->type == COP_AWTYPE_AUDIO_SELECTOR)
517 d->mixer_class = AZ_CLASS_OUTPUT;
518 else if (w->type == COP_AWTYPE_PIN_COMPLEX)
519 d->mixer_class = AZ_CLASS_OUTPUT;
520 else
521 d->mixer_class = AZ_CLASS_INPUT;
522 m->target = MI_TARGET_OUTAMP;
523 d->un.v.num_channels = WIDGET_CHANNELS(w);
524 #ifdef MAX_VOLUME_255
525 d->un.v.units.name[0] = 0;
526 #else
527 snprintf(d->un.v.units.name, sizeof(d->un.v.units.name),
528 "0.25x%ddB", COP_AMPCAP_STEPSIZE(w->outamp_cap)+1);
529 #endif
530 d->un.v.delta =
531 MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->outamp_cap));
532 this->nmixers++;
533 }
534
535
536 if (w->widgetcap & COP_AWCAP_INAMP &&
537 w->inamp_cap & COP_AMPCAP_MUTE) {
538 DPRINTF(("%s: input mute %s\n", __func__, w->name));
539 if (w->type != COP_AWTYPE_AUDIO_SELECTOR &&
540 w->type != COP_AWTYPE_AUDIO_MIXER) {
541 MIXER_REG_PROLOG;
542 snprintf(d->label.name, sizeof(d->label.name),
543 "%s.mute", w->name);
544 d->type = AUDIO_MIXER_ENUM;
545 if (w->type == COP_AWTYPE_PIN_COMPLEX)
546 d->mixer_class = AZ_CLASS_OUTPUT;
547 else if (w->type == COP_AWTYPE_AUDIO_INPUT)
548 d->mixer_class = AZ_CLASS_RECORD;
549 else
550 d->mixer_class = AZ_CLASS_INPUT;
551 m->target = 0;
552 d->un.e.num_mem = 2;
553 d->un.e.member[0].ord = 0;
554 strlcpy(d->un.e.member[0].label.name,
555 AudioNoff, MAX_AUDIO_DEV_LEN);
556 d->un.e.member[1].ord = 1;
557 strlcpy(d->un.e.member[1].label.name,
558 AudioNon, MAX_AUDIO_DEV_LEN);
559 this->nmixers++;
560 } else {
561 for (j = 0; j < w->nconnections; j++) {
562 MIXER_REG_PROLOG;
563 if (!VALID_WIDGET_NID(w->connections[j], this))
564 continue;
565 DPRINTF(("%s: input mute %s.%s\n", __func__,
566 w->name, this->w[w->connections[j]].name));
567 snprintf(d->label.name, sizeof(d->label.name),
568 "%s.%s.mute", w->name,
569 this->w[w->connections[j]].name);
570 d->type = AUDIO_MIXER_ENUM;
571 if (w->type == COP_AWTYPE_PIN_COMPLEX)
572 d->mixer_class = AZ_CLASS_OUTPUT;
573 else if (w->type == COP_AWTYPE_AUDIO_INPUT)
574 d->mixer_class = AZ_CLASS_RECORD;
575 else
576 d->mixer_class = AZ_CLASS_INPUT;
577 m->target = j;
578 d->un.e.num_mem = 2;
579 d->un.e.member[0].ord = 0;
580 strlcpy(d->un.e.member[0].label.name,
581 AudioNoff, MAX_AUDIO_DEV_LEN);
582 d->un.e.member[1].ord = 1;
583 strlcpy(d->un.e.member[1].label.name,
584 AudioNon, MAX_AUDIO_DEV_LEN);
585 this->nmixers++;
586 }
587 }
588 }
589
590
591 if (w->widgetcap & COP_AWCAP_INAMP
592 && COP_AMPCAP_NUMSTEPS(w->inamp_cap)) {
593 DPRINTF(("%s: input gain %s\n", __func__, w->name));
594 if (w->type != COP_AWTYPE_AUDIO_SELECTOR &&
595 w->type != COP_AWTYPE_AUDIO_MIXER) {
596 MIXER_REG_PROLOG;
597 snprintf(d->label.name, sizeof(d->label.name),
598 "%s", w->name);
599 d->type = AUDIO_MIXER_VALUE;
600 if (w->type == COP_AWTYPE_PIN_COMPLEX)
601 d->mixer_class = AZ_CLASS_OUTPUT;
602 else if (w->type == COP_AWTYPE_AUDIO_INPUT)
603 d->mixer_class = AZ_CLASS_RECORD;
604 else
605 d->mixer_class = AZ_CLASS_INPUT;
606 m->target = 0;
607 d->un.v.num_channels = WIDGET_CHANNELS(w);
608 #ifdef MAX_VOLUME_255
609 d->un.v.units.name[0] = 0;
610 #else
611 snprintf(d->un.v.units.name,
612 sizeof(d->un.v.units.name), "0.25x%ddB",
613 COP_AMPCAP_STEPSIZE(w->inamp_cap)+1);
614 #endif
615 d->un.v.delta =
616 MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->inamp_cap));
617 this->nmixers++;
618 } else {
619 for (j = 0; j < w->nconnections; j++) {
620 MIXER_REG_PROLOG;
621 if (!VALID_WIDGET_NID(w->connections[j], this))
622 continue;
623 DPRINTF(("%s: input gain %s.%s\n", __func__,
624 w->name, this->w[w->connections[j]].name));
625 snprintf(d->label.name, sizeof(d->label.name),
626 "%s.%s", w->name,
627 this->w[w->connections[j]].name);
628 d->type = AUDIO_MIXER_VALUE;
629 if (w->type == COP_AWTYPE_PIN_COMPLEX)
630 d->mixer_class = AZ_CLASS_OUTPUT;
631 else if (w->type == COP_AWTYPE_AUDIO_INPUT)
632 d->mixer_class = AZ_CLASS_RECORD;
633 else
634 d->mixer_class = AZ_CLASS_INPUT;
635 m->target = j;
636 d->un.v.num_channels = WIDGET_CHANNELS(w);
637 #ifdef MAX_VOLUME_255
638 d->un.v.units.name[0] = 0;
639 #else
640 snprintf(d->un.v.units.name,
641 sizeof(d->un.v.units.name), "0.25x%ddB",
642 COP_AMPCAP_STEPSIZE(w->inamp_cap)+1);
643 #endif
644 d->un.v.delta =
645 MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->inamp_cap));
646 this->nmixers++;
647 }
648 }
649 }
650
651
652 if (w->type == COP_AWTYPE_PIN_COMPLEX &&
653 w->d.pin.cap & COP_PINCAP_OUTPUT &&
654 w->d.pin.cap & COP_PINCAP_INPUT) {
655 MIXER_REG_PROLOG;
656 DPRINTF(("%s: pin dir %s\n", __func__, w->name));
657 snprintf(d->label.name, sizeof(d->label.name),
658 "%s.dir", w->name);
659 d->type = AUDIO_MIXER_ENUM;
660 d->mixer_class = AZ_CLASS_OUTPUT;
661 m->target = MI_TARGET_PINDIR;
662 d->un.e.num_mem = 2;
663 d->un.e.member[0].ord = 0;
664 strlcpy(d->un.e.member[0].label.name, AudioNinput,
665 MAX_AUDIO_DEV_LEN);
666 d->un.e.member[1].ord = 1;
667 strlcpy(d->un.e.member[1].label.name, AudioNoutput,
668 MAX_AUDIO_DEV_LEN);
669 this->nmixers++;
670 }
671
672
673 if (w->type == COP_AWTYPE_PIN_COMPLEX &&
674 w->d.pin.cap & COP_PINCAP_HEADPHONE) {
675 MIXER_REG_PROLOG;
676 DPRINTF(("%s: hpboost %s\n", __func__, w->name));
677 snprintf(d->label.name, sizeof(d->label.name),
678 "%s.boost", w->name);
679 d->type = AUDIO_MIXER_ENUM;
680 d->mixer_class = AZ_CLASS_OUTPUT;
681 m->target = MI_TARGET_PINBOOST;
682 d->un.e.num_mem = 2;
683 d->un.e.member[0].ord = 0;
684 strlcpy(d->un.e.member[0].label.name, AudioNoff,
685 MAX_AUDIO_DEV_LEN);
686 d->un.e.member[1].ord = 1;
687 strlcpy(d->un.e.member[1].label.name, AudioNon,
688 MAX_AUDIO_DEV_LEN);
689 this->nmixers++;
690 }
691
692
693 if (w->type == COP_AWTYPE_VOLUME_KNOB &&
694 w->d.volume.cap & COP_VKCAP_DELTA) {
695 MIXER_REG_PROLOG;
696 DPRINTF(("%s: volume knob %s\n", __func__, w->name));
697 strlcpy(d->label.name, w->name, sizeof(d->label.name));
698 d->type = AUDIO_MIXER_VALUE;
699 d->mixer_class = AZ_CLASS_OUTPUT;
700 m->target = MI_TARGET_VOLUME;
701 d->un.v.num_channels = 1;
702 d->un.v.units.name[0] = 0;
703 d->un.v.delta =
704 MIXER_DELTA(COP_VKCAP_NUMSTEPS(w->d.volume.cap));
705 this->nmixers++;
706 }
707 }
708
709
710 if (this->dacs.ngroups > 1) {
711 MIXER_REG_PROLOG;
712 DPRINTF(("%s: create inputs.usingdac\n", __func__));
713 strlcpy(d->label.name, "usingdac", sizeof(d->label.name));
714 d->type = AUDIO_MIXER_ENUM;
715 d->mixer_class = AZ_CLASS_INPUT;
716 m->target = MI_TARGET_DAC;
717 for (i = 0; i < this->dacs.ngroups && i < 32; i++) {
718 d->un.e.member[i].ord = i;
719 for (j = 0; j < this->dacs.groups[i].nconv; j++) {
720 if (j * 2 >= MAX_AUDIO_DEV_LEN)
721 break;
722 snprintf(d->un.e.member[i].label.name + j*2,
723 MAX_AUDIO_DEV_LEN - j*2, "%2.2x",
724 this->dacs.groups[i].conv[j]);
725 }
726 }
727 d->un.e.num_mem = i;
728 this->nmixers++;
729 }
730
731
732 if (this->adcs.ngroups > 1) {
733 MIXER_REG_PROLOG;
734 DPRINTF(("%s: create inputs.usingadc\n", __func__));
735 strlcpy(d->label.name, "usingadc", sizeof(d->label.name));
736 d->type = AUDIO_MIXER_ENUM;
737 d->mixer_class = AZ_CLASS_RECORD;
738 m->target = MI_TARGET_ADC;
739 for (i = 0; i < this->adcs.ngroups && i < 32; i++) {
740 d->un.e.member[i].ord = i;
741 for (j = 0; j < this->adcs.groups[i].nconv; j++) {
742 if (j * 2 >= MAX_AUDIO_DEV_LEN)
743 break;
744 snprintf(d->un.e.member[i].label.name + j*2,
745 MAX_AUDIO_DEV_LEN - j*2, "%2.2x",
746 this->adcs.groups[i].conv[j]);
747 }
748 }
749 d->un.e.num_mem = i;
750 this->nmixers++;
751 }
752
753 azalia_generic_mixer_fix_indexes(this);
754 azalia_generic_mixer_default(this);
755 return 0;
756 }
757
758 int
759 azalia_generic_mixer_ensure_capacity(codec_t *this, size_t newsize)
760 {
761 size_t newmax;
762 void *newbuf;
763
764 if (this->maxmixers >= newsize)
765 return 0;
766 newmax = this->maxmixers + 10;
767 if (newmax < newsize)
768 newmax = newsize;
769 newbuf = malloc(sizeof(mixer_item_t) * newmax, M_DEVBUF, M_NOWAIT);
770 if (newbuf == NULL) {
771 printf("%s: out of memory in %s\n", XNAME(this), __func__);
772 return ENOMEM;
773 }
774 bzero(newbuf, sizeof(mixer_item_t) * newmax);
775 bcopy(this->mixers, newbuf, this->maxmixers * sizeof(mixer_item_t));
776 free(this->mixers, M_DEVBUF);
777 this->mixers = newbuf;
778 this->maxmixers = newmax;
779 return 0;
780 }
781
782 int
783 azalia_generic_mixer_fix_indexes(codec_t *this)
784 {
785 int i;
786 mixer_devinfo_t *d;
787
788 for (i = 0; i < this->nmixers; i++) {
789 d = &this->mixers[i].devinfo;
790 #ifdef DIAGNOSTIC
791 if (d->index != 0 && d->index != i)
792 printf("%s: index mismatch %d %d\n", __func__,
793 d->index, i);
794 #endif
795 d->index = i;
796 if (d->prev == 0)
797 d->prev = AUDIO_MIXER_LAST;
798 if (d->next == 0)
799 d->next = AUDIO_MIXER_LAST;
800 }
801 return 0;
802 }
803
804 int
805 azalia_generic_mixer_default(codec_t *this)
806 {
807 int i;
808 mixer_item_t *m;
809
810 DPRINTF(("%s: unmute\n", __func__));
811 for (i = 0; i < this->nmixers; i++) {
812 mixer_ctrl_t mc;
813
814 m = &this->mixers[i];
815 if (!IS_MI_TARGET_INAMP(m->target) &&
816 m->target != MI_TARGET_OUTAMP)
817 continue;
818 if (m->devinfo.type != AUDIO_MIXER_ENUM)
819 continue;
820 mc.dev = i;
821 mc.type = AUDIO_MIXER_ENUM;
822 mc.un.ord = 0;
823 azalia_generic_mixer_set(this, m->nid, m->target, &mc);
824 }
825
826
827
828
829
830
831 DPRINTF(("%s: process bidirectional pins\n", __func__));
832 for (i = 0; i < this->nmixers; i++) {
833 mixer_ctrl_t mc;
834
835 m = &this->mixers[i];
836 if (m->target != MI_TARGET_PINDIR)
837 continue;
838 mc.dev = i;
839 mc.type = AUDIO_MIXER_ENUM;
840 switch (this->w[m->nid].d.pin.device) {
841 case CORB_CD_LINEOUT:
842 case CORB_CD_SPEAKER:
843 case CORB_CD_HEADPHONE:
844 case CORB_CD_SPDIFOUT:
845 case CORB_CD_DIGITALOUT:
846 case CORB_CD_DEVICE_OTHER:
847 mc.un.ord = 1;
848 break;
849 default:
850 mc.un.ord = 0;
851 }
852 azalia_generic_mixer_set(this, m->nid, m->target, &mc);
853 }
854
855
856 DPRINTF(("%s: set volume\n", __func__));
857 for (i = 0; i < this->nmixers; i++) {
858 mixer_ctrl_t mc;
859
860 m = &this->mixers[i];
861 if (!IS_MI_TARGET_INAMP(m->target) &&
862 m->target != MI_TARGET_OUTAMP &&
863 m->target != MI_TARGET_VOLUME)
864 continue;
865 if (m->devinfo.type != AUDIO_MIXER_VALUE)
866 continue;
867 mc.dev = i;
868 mc.type = AUDIO_MIXER_VALUE;
869 mc.un.value.num_channels = 1;
870 mc.un.value.level[0] = AUDIO_MAX_GAIN / 2;
871 if (m->target != MI_TARGET_VOLUME &&
872 WIDGET_CHANNELS(&this->w[m->nid]) == 2) {
873 mc.un.value.num_channels = 2;
874 mc.un.value.level[1] = AUDIO_MAX_GAIN / 2;
875 }
876 azalia_generic_mixer_set(this, m->nid, m->target, &mc);
877 }
878
879 return 0;
880 }
881
882 int
883 azalia_generic_mixer_delete(codec_t *this)
884 {
885 if (this->mixers == NULL)
886 return 0;
887 free(this->mixers, M_DEVBUF);
888 this->mixers = NULL;
889 return 0;
890 }
891
892
893
894
895 int
896 azalia_generic_mixer_get(const codec_t *this, nid_t nid, int target, mixer_ctrl_t *mc)
897 {
898 uint32_t result;
899 nid_t n;
900 int err;
901
902
903 if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_ENUM) {
904 err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
905 CORB_GAGM_INPUT | CORB_GAGM_LEFT |
906 MI_TARGET_INAMP(target), &result);
907 if (err)
908 return err;
909 mc->un.ord = result & CORB_GAGM_MUTE ? 1 : 0;
910 }
911
912
913 else if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_VALUE) {
914 err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
915 CORB_GAGM_INPUT | CORB_GAGM_LEFT |
916 MI_TARGET_INAMP(target), &result);
917 if (err)
918 return err;
919 mc->un.value.level[0] = azalia_generic_mixer_from_device_value(this,
920 nid, target, CORB_GAGM_GAIN(result));
921 if (this->w[nid].type == COP_AWTYPE_AUDIO_SELECTOR ||
922 this->w[nid].type == COP_AWTYPE_AUDIO_MIXER) {
923 n = this->w[nid].connections[MI_TARGET_INAMP(target)];
924 #ifdef AZALIA_DEBUG
925 if (!VALID_WIDGET_NID(n, this)) {
926 DPRINTF(("%s: invalid target: nid=%d nconn=%d index=%d\n",
927 __func__, nid, this->w[nid].nconnections,
928 MI_TARGET_INAMP(target)));
929 return EINVAL;
930 }
931 #endif
932 } else
933 n = nid;
934 mc->un.value.num_channels = WIDGET_CHANNELS(&this->w[n]);
935 if (mc->un.value.num_channels == 2) {
936 err = this->comresp(this, nid,
937 CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_INPUT |
938 CORB_GAGM_RIGHT | MI_TARGET_INAMP(target),
939 &result);
940 if (err)
941 return err;
942 mc->un.value.level[1] = azalia_generic_mixer_from_device_value
943 (this, nid, target, CORB_GAGM_GAIN(result));
944 }
945 }
946
947
948 else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_ENUM) {
949 err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
950 CORB_GAGM_OUTPUT | CORB_GAGM_LEFT | 0, &result);
951 if (err)
952 return err;
953 mc->un.ord = result & CORB_GAGM_MUTE ? 1 : 0;
954 }
955
956
957 else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_VALUE) {
958 err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
959 CORB_GAGM_OUTPUT | CORB_GAGM_LEFT | 0, &result);
960 if (err)
961 return err;
962 mc->un.value.level[0] = azalia_generic_mixer_from_device_value(this,
963 nid, target, CORB_GAGM_GAIN(result));
964 mc->un.value.num_channels = WIDGET_CHANNELS(&this->w[nid]);
965 if (mc->un.value.num_channels == 2) {
966 err = this->comresp(this, nid,
967 CORB_GET_AMPLIFIER_GAIN_MUTE,
968 CORB_GAGM_OUTPUT | CORB_GAGM_RIGHT | 0, &result);
969 if (err)
970 return err;
971 mc->un.value.level[1] = azalia_generic_mixer_from_device_value
972 (this, nid, target, CORB_GAGM_GAIN(result));
973 }
974 }
975
976
977 else if (target == MI_TARGET_CONNLIST) {
978 err = this->comresp(this, nid,
979 CORB_GET_CONNECTION_SELECT_CONTROL, 0, &result);
980 if (err)
981 return err;
982 result = CORB_CSC_INDEX(result);
983 if (!VALID_WIDGET_NID(this->w[nid].connections[result], this))
984 mc->un.ord = -1;
985 else
986 mc->un.ord = result;
987 }
988
989
990 else if (target == MI_TARGET_PINDIR) {
991 err = this->comresp(this, nid,
992 CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
993 if (err)
994 return err;
995 mc->un.ord = result & CORB_PWC_OUTPUT ? 1 : 0;
996 }
997
998
999 else if (target == MI_TARGET_PINBOOST) {
1000 err = this->comresp(this, nid,
1001 CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
1002 if (err)
1003 return err;
1004 mc->un.ord = result & CORB_PWC_HEADPHONE ? 1 : 0;
1005 }
1006
1007
1008 else if (target == MI_TARGET_DAC) {
1009 mc->un.ord = this->dacs.cur;
1010 }
1011
1012
1013 else if (target == MI_TARGET_ADC) {
1014 mc->un.ord = this->adcs.cur;
1015 }
1016
1017
1018 else if (target == MI_TARGET_VOLUME) {
1019 err = this->comresp(this, nid, CORB_GET_VOLUME_KNOB,
1020 0, &result);
1021 if (err)
1022 return err;
1023 mc->un.value.level[0] = azalia_generic_mixer_from_device_value(this,
1024 nid, target, CORB_VKNOB_VOLUME(result));
1025 mc->un.value.num_channels = 1;
1026 }
1027
1028 else {
1029 printf("%s: internal error in %s: target=%x\n",
1030 XNAME(this), __func__, target);
1031 return -1;
1032 }
1033 return 0;
1034 }
1035
1036 int
1037 azalia_generic_mixer_set(codec_t *this, nid_t nid, int target, const mixer_ctrl_t *mc)
1038 {
1039 uint32_t result, value;
1040 int err;
1041
1042
1043 if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_ENUM) {
1044
1045 err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1046 CORB_GAGM_INPUT | CORB_GAGM_LEFT |
1047 MI_TARGET_INAMP(target), &result);
1048 if (err)
1049 return err;
1050 value = CORB_AGM_INPUT | CORB_AGM_LEFT |
1051 (target << CORB_AGM_INDEX_SHIFT) |
1052 CORB_GAGM_GAIN(result);
1053 if (mc->un.ord)
1054 value |= CORB_AGM_MUTE;
1055 err = this->comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE,
1056 value, &result);
1057 if (err)
1058 return err;
1059 if (WIDGET_CHANNELS(&this->w[nid]) == 2) {
1060 err = this->comresp(this, nid,
1061 CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_INPUT |
1062 CORB_GAGM_RIGHT | MI_TARGET_INAMP(target),
1063 &result);
1064 if (err)
1065 return err;
1066 value = CORB_AGM_INPUT | CORB_AGM_RIGHT |
1067 (target << CORB_AGM_INDEX_SHIFT) |
1068 CORB_GAGM_GAIN(result);
1069 if (mc->un.ord)
1070 value |= CORB_AGM_MUTE;
1071 err = this->comresp(this, nid,
1072 CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result);
1073 if (err)
1074 return err;
1075 }
1076 }
1077
1078
1079 else if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_VALUE) {
1080 if (mc->un.value.num_channels < 1)
1081 return EINVAL;
1082 if (!azalia_generic_mixer_validate_value(this, nid, target,
1083 mc->un.value.level[0]))
1084 return EINVAL;
1085 err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1086 CORB_GAGM_INPUT | CORB_GAGM_LEFT |
1087 MI_TARGET_INAMP(target), &result);
1088 if (err)
1089 return err;
1090 value = azalia_generic_mixer_to_device_value(this, nid, target,
1091 mc->un.value.level[0]);
1092 value = CORB_AGM_INPUT | CORB_AGM_LEFT |
1093 (target << CORB_AGM_INDEX_SHIFT) |
1094 (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) |
1095 (value & CORB_AGM_GAIN_MASK);
1096 err = this->comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE,
1097 value, &result);
1098 if (err)
1099 return err;
1100 if (mc->un.value.num_channels >= 2 &&
1101 WIDGET_CHANNELS(&this->w[nid]) == 2) {
1102 if (!azalia_generic_mixer_validate_value(this, nid, target,
1103 mc->un.value.level[1]))
1104 return EINVAL;
1105 err = this->comresp(this, nid,
1106 CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_INPUT |
1107 CORB_GAGM_RIGHT | MI_TARGET_INAMP(target),
1108 &result);
1109 if (err)
1110 return err;
1111 value = azalia_generic_mixer_to_device_value(this, nid, target,
1112 mc->un.value.level[1]);
1113 value = CORB_AGM_INPUT | CORB_AGM_RIGHT |
1114 (target << CORB_AGM_INDEX_SHIFT) |
1115 (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) |
1116 (value & CORB_AGM_GAIN_MASK);
1117 err = this->comresp(this, nid,
1118 CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result);
1119 if (err)
1120 return err;
1121 }
1122 }
1123
1124
1125 else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_ENUM) {
1126 err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1127 CORB_GAGM_OUTPUT | CORB_GAGM_LEFT, &result);
1128 if (err)
1129 return err;
1130 value = CORB_AGM_OUTPUT | CORB_AGM_LEFT | CORB_GAGM_GAIN(result);
1131 if (mc->un.ord)
1132 value |= CORB_AGM_MUTE;
1133 err = this->comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE,
1134 value, &result);
1135 if (err)
1136 return err;
1137 if (WIDGET_CHANNELS(&this->w[nid]) == 2) {
1138 err = this->comresp(this, nid,
1139 CORB_GET_AMPLIFIER_GAIN_MUTE,
1140 CORB_GAGM_OUTPUT | CORB_GAGM_RIGHT, &result);
1141 if (err)
1142 return err;
1143 value = CORB_AGM_OUTPUT | CORB_AGM_RIGHT |
1144 CORB_GAGM_GAIN(result);
1145 if (mc->un.ord)
1146 value |= CORB_AGM_MUTE;
1147 err = this->comresp(this, nid,
1148 CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result);
1149 if (err)
1150 return err;
1151 }
1152 }
1153
1154
1155 else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_VALUE) {
1156 if (mc->un.value.num_channels < 1)
1157 return EINVAL;
1158 if (!azalia_generic_mixer_validate_value(this, nid, target,
1159 mc->un.value.level[0]))
1160 return EINVAL;
1161 err = this->comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1162 CORB_GAGM_OUTPUT | CORB_GAGM_LEFT, &result);
1163 if (err)
1164 return err;
1165 value = azalia_generic_mixer_to_device_value(this, nid, target,
1166 mc->un.value.level[0]);
1167 value = CORB_AGM_OUTPUT | CORB_AGM_LEFT |
1168 (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) |
1169 (value & CORB_AGM_GAIN_MASK);
1170 err = this->comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE,
1171 value, &result);
1172 if (err)
1173 return err;
1174 if (mc->un.value.num_channels >= 2 &&
1175 WIDGET_CHANNELS(&this->w[nid]) == 2) {
1176 if (!azalia_generic_mixer_validate_value(this, nid, target,
1177 mc->un.value.level[1]))
1178 return EINVAL;
1179 err = this->comresp(this, nid,
1180 CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_OUTPUT |
1181 CORB_GAGM_RIGHT, &result);
1182 if (err)
1183 return err;
1184 value = azalia_generic_mixer_to_device_value(this, nid, target,
1185 mc->un.value.level[1]);
1186 value = CORB_AGM_OUTPUT | CORB_AGM_RIGHT |
1187 (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) |
1188 (value & CORB_AGM_GAIN_MASK);
1189 err = this->comresp(this, nid,
1190 CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result);
1191 if (err)
1192 return err;
1193 }
1194 }
1195
1196
1197 else if (target == MI_TARGET_CONNLIST) {
1198 if (mc->un.ord < 0 ||
1199 mc->un.ord >= this->w[nid].nconnections ||
1200 !VALID_WIDGET_NID(this->w[nid].connections[mc->un.ord], this))
1201 return EINVAL;
1202 err = this->comresp(this, nid,
1203 CORB_SET_CONNECTION_SELECT_CONTROL, mc->un.ord, &result);
1204 if (err)
1205 return err;
1206 }
1207
1208
1209 else if (target == MI_TARGET_PINDIR) {
1210 if (mc->un.ord >= 2)
1211 return EINVAL;
1212 err = this->comresp(this, nid,
1213 CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
1214 if (err)
1215 return err;
1216 if (mc->un.ord == 0) {
1217 result &= ~CORB_PWC_OUTPUT;
1218 result |= CORB_PWC_INPUT;
1219 } else {
1220 result &= ~CORB_PWC_INPUT;
1221 result |= CORB_PWC_OUTPUT;
1222 }
1223 err = this->comresp(this, nid,
1224 CORB_SET_PIN_WIDGET_CONTROL, result, &result);
1225 if (err)
1226 return err;
1227 }
1228
1229
1230 else if (target == MI_TARGET_PINBOOST) {
1231 if (mc->un.ord >= 2)
1232 return EINVAL;
1233 err = this->comresp(this, nid,
1234 CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
1235 if (err)
1236 return err;
1237 if (mc->un.ord == 0) {
1238 result &= ~CORB_PWC_HEADPHONE;
1239 } else {
1240 result |= CORB_PWC_HEADPHONE;
1241 }
1242 err = this->comresp(this, nid,
1243 CORB_SET_PIN_WIDGET_CONTROL, result, &result);
1244 if (err)
1245 return err;
1246 }
1247
1248
1249 else if (target == MI_TARGET_DAC) {
1250 if (this->running)
1251 return EBUSY;
1252 if (mc->un.ord >= this->dacs.ngroups)
1253 return EINVAL;
1254 return azalia_codec_construct_format(this,
1255 mc->un.ord, this->adcs.cur);
1256 }
1257
1258
1259 else if (target == MI_TARGET_ADC) {
1260 if (this->running)
1261 return EBUSY;
1262 if (mc->un.ord >= this->adcs.ngroups)
1263 return EINVAL;
1264 return azalia_codec_construct_format(this,
1265 this->dacs.cur, mc->un.ord);
1266 }
1267
1268
1269 else if (target == MI_TARGET_VOLUME) {
1270 if (mc->un.value.num_channels != 1)
1271 return EINVAL;
1272 if (!azalia_generic_mixer_validate_value(this, nid,
1273 target, mc->un.value.level[0]))
1274 return EINVAL;
1275 value = azalia_generic_mixer_to_device_value(this, nid, target,
1276 mc->un.value.level[0]) | CORB_VKNOB_DIRECT;
1277 err = this->comresp(this, nid, CORB_SET_VOLUME_KNOB,
1278 value, &result);
1279 if (err)
1280 return err;
1281 }
1282
1283 else {
1284 printf("%s: internal error in %s: target=%x\n",
1285 XNAME(this), __func__, target);
1286 return -1;
1287 }
1288 return 0;
1289 }
1290
1291 int
1292 azalia_generic_mixer_pinctrl(codec_t *this, nid_t nid, uint32_t value)
1293 {
1294 int err;
1295 uint32_t result;
1296
1297 err = this->comresp(this, nid, CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
1298 if (err)
1299 return err;
1300 result &= ~(CORB_PWC_OUTPUT | CORB_PWC_INPUT);
1301 result |= value & (CORB_PWC_OUTPUT | CORB_PWC_INPUT);
1302 return this->comresp(this, nid,
1303 CORB_SET_PIN_WIDGET_CONTROL, result, NULL);
1304 }
1305
1306 u_char
1307 azalia_generic_mixer_from_device_value(const codec_t *this, nid_t nid, int target,
1308 uint32_t dv)
1309 {
1310 #ifdef MAX_VOLUME_255
1311 uint32_t dmax;
1312
1313 if (IS_MI_TARGET_INAMP(target))
1314 dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap);
1315 else if (target == MI_TARGET_OUTAMP)
1316 dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap);
1317 else if (target == MI_TARGET_VOLUME)
1318 dmax = COP_VKCAP_NUMSTEPS(this->w[nid].d.volume.cap);
1319 else {
1320 printf("unknown target: %d\n", target);
1321 dmax = 255;
1322 }
1323 if (dv <= 0 || dmax == 0)
1324 return AUDIO_MIN_GAIN;
1325 if (dv >= dmax)
1326 return AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % dmax;
1327 return dv * (AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % dmax) / dmax;
1328 #else
1329 return dv;
1330 #endif
1331 }
1332
1333 uint32_t
1334 azalia_generic_mixer_to_device_value(const codec_t *this, nid_t nid, int target,
1335 u_char uv)
1336 {
1337 #ifdef MAX_VOLUME_255
1338 uint32_t dmax;
1339
1340 if (IS_MI_TARGET_INAMP(target))
1341 dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap);
1342 else if (target == MI_TARGET_OUTAMP)
1343 dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap);
1344 else if (target == MI_TARGET_VOLUME)
1345 dmax = COP_VKCAP_NUMSTEPS(this->w[nid].d.volume.cap);
1346 else {
1347 printf("unknown target: %d\n", target);
1348 dmax = 255;
1349 }
1350 if (uv <= AUDIO_MIN_GAIN || dmax == 0)
1351 return 0;
1352 if (uv >= AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % dmax)
1353 return dmax;
1354 return uv * dmax / (AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % dmax);
1355 #else
1356 return uv;
1357 #endif
1358 }
1359
1360 uint32_t
1361 azalia_generic_mixer_max(const codec_t *this, nid_t nid, int target)
1362 {
1363 #ifdef MAX_VOLUME_255
1364 return AUDIO_MAX_GAIN;
1365 #else
1366 uint32_t dmax;
1367
1368 if (IS_MI_TARGET_INAMP(target))
1369 dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap);
1370 else if (target == MI_TARGET_OUTAMP)
1371 dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap);
1372 else if (target == MI_TARGET_VOLUME)
1373 dmax = COP_VKCAP_NUMSTEPS(this->w[nid].d.volume.cap);
1374 return dmax;
1375 #endif
1376 }
1377
1378 boolean_t
1379 azalia_generic_mixer_validate_value(const codec_t *this, nid_t nid, int target,
1380 u_char uv)
1381 {
1382 #ifdef MAX_VOLUME_255
1383 return TRUE;
1384 #else
1385 return uv <= generic_mixer_max(this, nid, target);
1386 #endif
1387 }
1388
1389 int
1390 azalia_generic_set_port(codec_t *this, mixer_ctrl_t *mc)
1391 {
1392 const mixer_item_t *m;
1393
1394 if (mc->dev >= this->nmixers)
1395 return ENXIO;
1396 m = &this->mixers[mc->dev];
1397 if (mc->type != m->devinfo.type)
1398 return EINVAL;
1399 if (mc->type == AUDIO_MIXER_CLASS)
1400 return 0;
1401 return azalia_generic_mixer_set(this, m->nid, m->target, mc);
1402 }
1403
1404 int
1405 azalia_generic_get_port(codec_t *this, mixer_ctrl_t *mc)
1406 {
1407 const mixer_item_t *m;
1408
1409 if (mc->dev >= this->nmixers)
1410 return ENXIO;
1411 m = &this->mixers[mc->dev];
1412 mc->type = m->devinfo.type;
1413 if (mc->type == AUDIO_MIXER_CLASS)
1414 return 0;
1415 return azalia_generic_mixer_get(this, m->nid, m->target, mc);
1416 }
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428 #define ALC260_FUJITSU_ID 0x132610cf
1429 static const mixer_item_t alc260_mixer_items[] = {
1430 {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0},
1431 {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0},
1432 {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0},
1433
1434 {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
1435 0, 0, .un.v={{""}, 2, 3}}, 0x08, MI_TARGET_OUTAMP},
1436 {{0, {AudioNmaster".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1437 0, 0, ENUM_OFFON}, 0x0f, MI_TARGET_OUTAMP},
1438 {{0, {AudioNheadphone".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1439 0, 0, ENUM_OFFON}, 0x10, MI_TARGET_OUTAMP},
1440 {{0, {AudioNheadphone".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1441 0, 0, ENUM_OFFON}, 0x10, MI_TARGET_PINBOOST},
1442 {{0, {AudioNmono".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1443 0, 0, ENUM_OFFON}, 0x11, MI_TARGET_OUTAMP},
1444 {{0, {"mic1.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1445 0, 0, ENUM_OFFON}, 0x12, MI_TARGET_OUTAMP},
1446 {{0, {"mic1"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1447 0, 0, ENUM_IO}, 0x12, MI_TARGET_PINDIR},
1448 {{0, {"mic2.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1449 0, 0, ENUM_OFFON}, 0x13, MI_TARGET_OUTAMP},
1450 {{0, {"mic2"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1451 0, 0, ENUM_IO}, 0x13, MI_TARGET_PINDIR},
1452 {{0, {"line1.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1453 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_OUTAMP},
1454 {{0, {"line1"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1455 0, 0, ENUM_IO}, 0x14, MI_TARGET_PINDIR},
1456 {{0, {"line2.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1457 0, 0, ENUM_OFFON}, 0x15, MI_TARGET_OUTAMP},
1458 {{0, {"line2"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1459 0, 0, ENUM_IO}, 0x15, MI_TARGET_PINDIR},
1460
1461 {{0, {AudioNdac".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1462 0, 0, ENUM_OFFON}, 0x08, MI_TARGET_INAMP(0)},
1463 {{0, {"mic1.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1464 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(0)},
1465 {{0, {"mic1"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
1466 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(0)},
1467 {{0, {"mic2.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1468 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(1)},
1469 {{0, {"mic2"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
1470 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(1)},
1471 {{0, {"line1.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1472 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(2)},
1473 {{0, {"line1"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
1474 0, 0, .un.v={{""}, 2, 3}}, 0x07, MI_TARGET_INAMP(2)},
1475 {{0, {"line2.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1476 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(3)},
1477 {{0, {"line2"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
1478 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(3)},
1479 {{0, {AudioNcd".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1480 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(4)},
1481 {{0, {AudioNcd}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
1482 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(4)},
1483 {{0, {AudioNspeaker".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1484 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(5)},
1485 {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
1486 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(5)},
1487
1488 {{0, {"adc04.source"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
1489 .un.e={5, {{{"mic1"}, 0}, {{"mic2"}, 1}, {{"line1"}, 2},
1490 {{"line2"}, 3}, {{AudioNcd}, 4}}}},
1491 0x04, MI_TARGET_CONNLIST},
1492 {{0, {"adc04.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
1493 ENUM_OFFON}, 0x04, MI_TARGET_INAMP(0)},
1494 {{0, {"adc04"}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0,
1495 .un.v={{""}, 2, MIXER_DELTA(35)}}, 0x04, MI_TARGET_INAMP(0)},
1496 {{0, {"adc05.source"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
1497 .un.e={6, {{{"mic1"}, 0}, {{"mic2"}, 1}, {{"line1"}, 2},
1498 {{"line2"}, 3}, {{AudioNcd}, 4}, {{AudioNmixerout}, 5}}}},
1499 0x05, MI_TARGET_CONNLIST},
1500 {{0, {"adc05.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
1501 ENUM_OFFON}, 0x05, MI_TARGET_INAMP(0)},
1502 {{0, {"adc05"}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0,
1503 .un.v={{""}, 2, MIXER_DELTA(35)}}, 0x05, MI_TARGET_INAMP(0)},
1504
1505 {{0, {"usingdac"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0,
1506 .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_DAC},
1507 {{0, {"usingadc"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
1508 .un.e={3, {{{"adc04"}, 0}, {{"adc05"}, 1}, {{"digital"}, 2}}}}, 0, MI_TARGET_ADC},
1509 };
1510
1511 static const mixer_item_t alc260_loox_mixer_items[] = {
1512 {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0},
1513 {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0},
1514 {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0},
1515
1516 {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
1517 0, 0, .un.v={{""}, 2, 3}}, 0x08, MI_TARGET_OUTAMP},
1518 {{0, {AudioNmaster".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1519 0, 0, ENUM_OFFON}, 0x10, MI_TARGET_OUTAMP},
1520 {{0, {AudioNmaster".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1521 0, 0, ENUM_OFFON}, 0x10, MI_TARGET_PINBOOST},
1522 {{0, {AudioNheadphone".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1523 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_OUTAMP},
1524 {{0, {AudioNheadphone".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1525 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_PINBOOST},
1526
1527 {{0, {AudioNdac".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1528 0, 0, ENUM_OFFON}, 0x08, MI_TARGET_INAMP(0)},
1529 {{0, {AudioNmicrophone".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1530 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(0)},
1531 {{0, {AudioNmicrophone}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
1532 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(0)},
1533 {{0, {AudioNcd".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1534 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(4)},
1535 {{0, {AudioNcd}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
1536 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(4)},
1537 {{0, {AudioNspeaker".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1538 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(5)},
1539 {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
1540 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(5)},
1541
1542 {{0, {"adc04.source"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
1543 .un.e={2, {{{AudioNmicrophone}, 0}, {{AudioNcd}, 4}}}}, 0x04, MI_TARGET_CONNLIST},
1544 {{0, {"adc04.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
1545 ENUM_OFFON}, 0x04, MI_TARGET_INAMP(0)},
1546 {{0, {"adc04"}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0,
1547 .un.v={{""}, 2, MIXER_DELTA(35)}}, 0x04, MI_TARGET_INAMP(0)},
1548 {{0, {"adc05.source"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
1549 .un.e={3, {{{AudioNmicrophone}, 0}, {{AudioNcd}, 4}, {{AudioNmixerout}, 5}}}},
1550 0x05, MI_TARGET_CONNLIST},
1551 {{0, {"adc05.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
1552 ENUM_OFFON}, 0x05, MI_TARGET_INAMP(0)},
1553 {{0, {"adc05"}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0,
1554 .un.v={{""}, 2, MIXER_DELTA(35)}}, 0x05, MI_TARGET_INAMP(0)},
1555
1556 {{0, {"usingdac"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0,
1557 .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_DAC},
1558 {{0, {"usingadc"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
1559 .un.e={3, {{{"adc04"}, 0}, {{"adc05"}, 1}, {{"digital"}, 2}}}}, 0, MI_TARGET_ADC},
1560 };
1561
1562 int
1563 azalia_alc260_mixer_init(codec_t *this)
1564 {
1565 const mixer_item_t *mi;
1566 mixer_ctrl_t mc;
1567
1568 switch (this->subid) {
1569 case ALC260_FUJITSU_ID:
1570 this->nmixers = sizeof(alc260_loox_mixer_items) / sizeof(mixer_item_t);
1571 mi = alc260_loox_mixer_items;
1572 break;
1573 default:
1574 this->nmixers = sizeof(alc260_mixer_items) / sizeof(mixer_item_t);
1575 mi = alc260_mixer_items;
1576 }
1577 this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers,
1578 M_DEVBUF, M_NOWAIT);
1579 if (this->mixers == NULL) {
1580 printf("%s: out of memory in %s\n", XNAME(this), __func__);
1581 return ENOMEM;
1582 }
1583 bzero(this->mixers, sizeof(mixer_item_t) * this->nmixers);
1584 memcpy(this->mixers, mi, sizeof(mixer_item_t) * this->nmixers);
1585 azalia_generic_mixer_fix_indexes(this);
1586 azalia_generic_mixer_default(this);
1587
1588 mc.dev = -1;
1589 mc.type = AUDIO_MIXER_ENUM;
1590 mc.un.ord = 1;
1591 azalia_generic_mixer_set(this, 0x0f, MI_TARGET_PINDIR, &mc);
1592 azalia_generic_mixer_set(this, 0x10, MI_TARGET_PINDIR, &mc);
1593 mc.un.ord = 0;
1594 azalia_generic_mixer_set(this, 0x12, MI_TARGET_PINDIR, &mc);
1595 azalia_generic_mixer_set(this, 0x13, MI_TARGET_PINDIR, &mc);
1596 azalia_generic_mixer_set(this, 0x14, MI_TARGET_PINDIR, &mc);
1597 azalia_generic_mixer_set(this, 0x15, MI_TARGET_PINDIR, &mc);
1598 mc.un.ord = 0;
1599 azalia_generic_mixer_set(this, 0x08, MI_TARGET_INAMP(0), &mc);
1600 azalia_generic_mixer_set(this, 0x08, MI_TARGET_INAMP(1), &mc);
1601 azalia_generic_mixer_set(this, 0x09, MI_TARGET_INAMP(0), &mc);
1602 azalia_generic_mixer_set(this, 0x09, MI_TARGET_INAMP(1), &mc);
1603 azalia_generic_mixer_set(this, 0x0a, MI_TARGET_INAMP(0), &mc);
1604 azalia_generic_mixer_set(this, 0x0a, MI_TARGET_INAMP(1), &mc);
1605 if (this->subid == ALC260_FUJITSU_ID) {
1606 mc.un.ord = 1;
1607 azalia_generic_mixer_set(this, 0x14, MI_TARGET_PINDIR, &mc);
1608 mc.un.ord = 4;
1609 azalia_generic_mixer_set(this, 0x05, MI_TARGET_CONNLIST, &mc);
1610 }
1611 return 0;
1612 }
1613
1614 int
1615 azalia_alc260_init_dacgroup(codec_t *this)
1616 {
1617 static const convgroupset_t dacs = {
1618 -1, 2,
1619 {{1, {0x02}},
1620 {1, {0x03}}}};
1621 static const convgroupset_t adcs = {
1622 -1, 3,
1623 {{1, {0x04}},
1624 {1, {0x05}},
1625 {1, {0x06}}}};
1626
1627 this->dacs = dacs;
1628 this->adcs = adcs;
1629 return 0;
1630 }
1631
1632 int
1633 azalia_alc260_set_port(codec_t *this, mixer_ctrl_t *mc)
1634 {
1635 const mixer_item_t *m;
1636 mixer_ctrl_t mc2;
1637 int err;
1638
1639 if (mc->dev >= this->nmixers)
1640 return ENXIO;
1641 m = &this->mixers[mc->dev];
1642 if (mc->type != m->devinfo.type)
1643 return EINVAL;
1644 if (mc->type == AUDIO_MIXER_CLASS)
1645 return 0;
1646 if (m->nid == 0x08 && m->target == MI_TARGET_OUTAMP) {
1647 DPRINTF(("%s: hook for outputs.master\n", __func__));
1648 err = azalia_generic_mixer_set(this, m->nid, m->target, mc);
1649 if (!err) {
1650 azalia_generic_mixer_set(this, 0x09, m->target, mc);
1651 mc2 = *mc;
1652 mc2.un.value.num_channels = 1;
1653 mc2.un.value.level[0] = (mc2.un.value.level[0]
1654 + mc2.un.value.level[1]) / 2;
1655 azalia_generic_mixer_set(this, 0x0a, m->target, &mc2);
1656 }
1657 return err;
1658 } else if (m->nid == 0x08 && m->target == MI_TARGET_INAMP(0)) {
1659 DPRINTF(("%s: hook for inputs.dac.mute\n", __func__));
1660 err = azalia_generic_mixer_set(this, m->nid, m->target, mc);
1661 if (!err) {
1662 azalia_generic_mixer_set(this, 0x09, m->target, mc);
1663 azalia_generic_mixer_set(this, 0x0a, m->target, mc);
1664 }
1665 return err;
1666 } else if (m->nid == 0x04 &&
1667 m->target == MI_TARGET_CONNLIST &&
1668 m->devinfo.un.e.num_mem == 2) {
1669 if (1 <= mc->un.ord && mc->un.ord <= 3)
1670 return EINVAL;
1671 } else if (m->nid == 0x05 &&
1672 m->target == MI_TARGET_CONNLIST &&
1673 m->devinfo.un.e.num_mem == 3) {
1674 if (1 <= mc->un.ord && mc->un.ord <= 3)
1675 return EINVAL;
1676 }
1677 return azalia_generic_mixer_set(this, m->nid, m->target, mc);
1678 }
1679
1680
1681
1682
1683
1684 int
1685 azalia_alc880_init_dacgroup(codec_t *this)
1686 {
1687 static const convgroupset_t dacs = {
1688 -1, 2,
1689 {{4, {0x02, 0x03, 0x04, 0x05}},
1690 {1, {0x06}}}};
1691 static const convgroupset_t adcs = {
1692 -1, 2,
1693 {{2, {0x08, 0x09}},
1694 {1, {0x0a}}}};
1695
1696 this->dacs = dacs;
1697 this->adcs = adcs;
1698 return 0;
1699 }
1700
1701
1702
1703
1704
1705 static const mixer_item_t alc882_mixer_items[] = {
1706 {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0},
1707 {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0},
1708 {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0},
1709
1710
1711 {{0, {"mic1."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1712 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(0)},
1713 {{0, {"mic1"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
1714 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(0)},
1715 {{0, {"mic2."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1716 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(1)},
1717 {{0, {"mic2"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
1718 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(1)},
1719 {{0, {AudioNline"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1720 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(2)},
1721 {{0, {AudioNline}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
1722 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(2)},
1723 {{0, {AudioNcd"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1724 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(4)},
1725 {{0, {AudioNcd}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
1726 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(4)},
1727 {{0, {AudioNspeaker"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1728 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(5)},
1729 {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
1730 0, 0, .un.v={{""}, 1, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(5)},
1731
1732 {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
1733 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0c, MI_TARGET_OUTAMP},
1734 {{0, {AudioNmaster"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1735 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_OUTAMP},
1736 {{0, {AudioNmaster".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1737 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_PINBOOST},
1738 {{0, {AudioNheadphone"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1739 0, 0, ENUM_OFFON}, 0x1b, MI_TARGET_OUTAMP},
1740 {{0, {AudioNheadphone".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1741 0, 0, ENUM_OFFON}, 0x1b, MI_TARGET_PINBOOST},
1742 {{0, {AzaliaNfront".dac.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1743 0, 0, ENUM_OFFON}, 0x0c, MI_TARGET_INAMP(0)},
1744 {{0, {AzaliaNfront".mixer.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1745 0, 0, ENUM_OFFON}, 0x0c, MI_TARGET_INAMP(1)},
1746
1747 {{0, {AudioNsurround}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
1748 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0d, MI_TARGET_OUTAMP},
1749 {{0, {AudioNsurround"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1750 0, 0, ENUM_OFFON}, 0x15, MI_TARGET_OUTAMP},
1751 {{0, {AudioNsurround".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1752 0, 0, ENUM_OFFON}, 0x15, MI_TARGET_PINBOOST},
1753 {{0, {AudioNsurround".dac.mut"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1754 0, 0, ENUM_OFFON}, 0x0d, MI_TARGET_INAMP(0)},
1755 {{0, {AudioNsurround".mixer.m"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1756 0, 0, ENUM_OFFON}, 0x0d, MI_TARGET_INAMP(1)},
1757
1758 {{0, {AzaliaNclfe}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
1759 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0e, MI_TARGET_OUTAMP},
1760 {{0, {AzaliaNclfe"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1761 0, 0, ENUM_OFFON}, 0x16, MI_TARGET_OUTAMP},
1762 {{0, {AzaliaNclfe".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1763 0, 0, ENUM_OFFON}, 0x16, MI_TARGET_PINBOOST},
1764 {{0, {AzaliaNclfe".dac.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1765 0, 0, ENUM_OFFON}, 0x0e, MI_TARGET_INAMP(0)},
1766 {{0, {AzaliaNclfe".mixer.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1767 0, 0, ENUM_OFFON}, 0x0e, MI_TARGET_INAMP(1)},
1768
1769 {{0, {AzaliaNside}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
1770 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0f, MI_TARGET_OUTAMP},
1771 {{0, {AzaliaNside"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1772 0, 0, ENUM_OFFON}, 0x17, MI_TARGET_OUTAMP},
1773 {{0, {AzaliaNside".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
1774 0, 0, ENUM_OFFON}, 0x17, MI_TARGET_PINBOOST},
1775 {{0, {AzaliaNside".dac.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1776 0, 0, ENUM_OFFON}, 0x0f, MI_TARGET_INAMP(0)},
1777 {{0, {AzaliaNside".mixer.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1778 0, 0, ENUM_OFFON}, 0x0f, MI_TARGET_INAMP(1)},
1779
1780
1781 #define ALC882_MIC1 0x001
1782 #define ALC882_MIC2 0x002
1783 #define ALC882_LINE 0x004
1784 #define ALC882_CD 0x010
1785 #define ALC882_BEEP 0x020
1786 #define ALC882_MIX 0x400
1787 #define ALC882_MASK 0x437
1788 {{0, {AzaliaNfront"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
1789 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(0)},
1790 {{0, {AzaliaNfront}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD,
1791 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x07, MI_TARGET_INAMP(0)},
1792 {{0, {AzaliaNfront"."AudioNsource}, AUDIO_MIXER_SET, AZ_CLASS_RECORD,
1793 0, 0, .un.s={6, {{{"mic1"}, ALC882_MIC1}, {{"mic2"}, ALC882_MIC2},
1794 {{AudioNline}, ALC882_LINE}, {{AudioNcd}, ALC882_CD},
1795 {{AudioNspeaker}, ALC882_BEEP},
1796 {{AudioNmixerout}, ALC882_MIX}}}}, 0x24, -1},
1797 {{0, {AudioNsurround"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
1798 0, 0, ENUM_OFFON}, 0x08, MI_TARGET_INAMP(0)},
1799 {{0, {AudioNsurround}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD,
1800 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x08, MI_TARGET_INAMP(0)},
1801 {{0, {AudioNsurround"."AudioNsource}, AUDIO_MIXER_SET, AZ_CLASS_RECORD,
1802 0, 0, .un.s={6, {{{"mic1"}, ALC882_MIC1}, {{"mic2"}, ALC882_MIC2},
1803 {{AudioNline}, ALC882_LINE}, {{AudioNcd}, ALC882_CD},
1804 {{AudioNspeaker}, ALC882_BEEP},
1805 {{AudioNmixerout}, ALC882_MIX}}}}, 0x23, -1},
1806 {{0, {AzaliaNclfe"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
1807 0, 0, ENUM_OFFON}, 0x09, MI_TARGET_INAMP(0)},
1808 {{0, {AzaliaNclfe}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD,
1809 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x09, MI_TARGET_INAMP(0)},
1810 {{0, {AzaliaNclfe"."AudioNsource}, AUDIO_MIXER_SET, AZ_CLASS_RECORD,
1811 0, 0, .un.s={6, {{{"mic1"}, ALC882_MIC1}, {{"mic2"}, ALC882_MIC2},
1812 {{AudioNline}, ALC882_LINE}, {{AudioNcd}, ALC882_CD},
1813 {{AudioNspeaker}, ALC882_BEEP},
1814 {{AudioNmixerout}, ALC882_MIX}}}}, 0x22, -1},
1815
1816 {{0, {"usingdac"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0,
1817 .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_DAC},
1818 {{0, {"usingadc"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
1819 .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_ADC},
1820 };
1821
1822 int
1823 azalia_alc882_mixer_init(codec_t *this)
1824 {
1825 mixer_ctrl_t mc;
1826
1827 this->nmixers = sizeof(alc882_mixer_items) / sizeof(mixer_item_t);
1828 this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers,
1829 M_DEVBUF, M_NOWAIT);
1830 if (this->mixers == NULL) {
1831 printf("%s: out of memory in %s\n", XNAME(this), __func__);
1832 return ENOMEM;
1833 }
1834 bzero(this->mixers, sizeof(mixer_item_t) * this->maxmixers);
1835 memcpy(this->mixers, alc882_mixer_items,
1836 sizeof(mixer_item_t) * this->nmixers);
1837 azalia_generic_mixer_fix_indexes(this);
1838 azalia_generic_mixer_default(this);
1839
1840 mc.dev = -1;
1841 mc.type = AUDIO_MIXER_ENUM;
1842 mc.un.ord = 1;
1843 azalia_generic_mixer_set(this, 0x14, MI_TARGET_PINDIR, &mc);
1844 azalia_generic_mixer_set(this, 0x1b, MI_TARGET_PINDIR, &mc);
1845 azalia_generic_mixer_set(this, 0x15, MI_TARGET_PINDIR, &mc);
1846 azalia_generic_mixer_set(this, 0x16, MI_TARGET_PINDIR, &mc);
1847 azalia_generic_mixer_set(this, 0x17, MI_TARGET_PINDIR, &mc);
1848 mc.un.ord = 0;
1849 azalia_generic_mixer_set(this, 0x14, MI_TARGET_CONNLIST, &mc);
1850 azalia_generic_mixer_set(this, 0x1b, MI_TARGET_CONNLIST, &mc);
1851 mc.un.ord = 1;
1852 azalia_generic_mixer_set(this, 0x15, MI_TARGET_CONNLIST, &mc);
1853 mc.un.ord = 2;
1854 azalia_generic_mixer_set(this, 0x16, MI_TARGET_CONNLIST, &mc);
1855 mc.un.ord = 2;
1856 azalia_generic_mixer_set(this, 0x17, MI_TARGET_CONNLIST, &mc);
1857
1858 mc.un.ord = 0;
1859 azalia_generic_mixer_set(this, 0x18, MI_TARGET_PINDIR, &mc);
1860 azalia_generic_mixer_set(this, 0x19, MI_TARGET_PINDIR, &mc);
1861 azalia_generic_mixer_set(this, 0x1a, MI_TARGET_PINDIR, &mc);
1862
1863
1864 mc.un.ord = 0;
1865 azalia_generic_mixer_set(this, 0x24, MI_TARGET_INAMP(0), &mc);
1866 azalia_generic_mixer_set(this, 0x23, MI_TARGET_INAMP(1), &mc);
1867 azalia_generic_mixer_set(this, 0x22, MI_TARGET_INAMP(2), &mc);
1868 return 0;
1869 }
1870
1871 int
1872 azalia_alc882_init_dacgroup(codec_t *this)
1873 {
1874 #if 0
1875 static const convgroupset_t dacs = {
1876 -1, 3,
1877 {{4, {0x02, 0x03, 0x04, 0x05}},
1878 {1, {0x06}},
1879 {1, {0x25}}}};
1880 #else
1881 static const convgroupset_t dacs = {
1882 -1, 2,
1883 {{4, {0x02, 0x03, 0x04, 0x05}},
1884 {1, {0x06}}}};
1885 #endif
1886 static const convgroupset_t adcs = {
1887 -1, 2,
1888 {{3, {0x07, 0x08, 0x09}},
1889 {1, {0x0a}}}};
1890
1891 this->dacs = dacs;
1892 this->adcs = adcs;
1893 return 0;
1894 }
1895
1896 int
1897 azalia_alc882_set_port(codec_t *this, mixer_ctrl_t *mc)
1898 {
1899 const mixer_item_t *m;
1900 mixer_ctrl_t mc2;
1901 uint32_t mask, bit;
1902 int i, err;
1903
1904 if (mc->dev >= this->nmixers)
1905 return ENXIO;
1906 m = &this->mixers[mc->dev];
1907 if (mc->type != m->devinfo.type)
1908 return EINVAL;
1909 if (mc->type == AUDIO_MIXER_CLASS)
1910 return 0;
1911 if ((m->nid == 0x22 || m->nid == 0x23 || m->nid == 0x24)
1912 && m->target == -1) {
1913 DPRINTF(("%s: hook for record.*.source\n", __func__));
1914 mc2.dev = -1;
1915 mc2.type = AUDIO_MIXER_ENUM;
1916 bit = 1;
1917 mask = mc->un.mask & ALC882_MASK;
1918 for (i = 0; i < this->w[m->nid].nconnections && i < 32; i++) {
1919 mc2.un.ord = (mask & bit) ? 0 : 1;
1920 err = azalia_generic_mixer_set(this, m->nid,
1921 MI_TARGET_INAMP(i), &mc2);
1922 if (err)
1923 return err;
1924 bit = bit << 1;
1925 }
1926 return 0;
1927 }
1928 return azalia_generic_mixer_set(this, m->nid, m->target, mc);
1929 }
1930
1931 int
1932 azalia_alc882_get_port(codec_t *this, mixer_ctrl_t *mc)
1933 {
1934 const mixer_item_t *m;
1935 uint32_t mask, bit, result;
1936 int i, err;
1937
1938 if (mc->dev >= this->nmixers)
1939 return ENXIO;
1940 m = &this->mixers[mc->dev];
1941 mc->type = m->devinfo.type;
1942 if (mc->type == AUDIO_MIXER_CLASS)
1943 return 0;
1944 if ((m->nid == 0x22 || m->nid == 0x23 || m->nid == 0x24)
1945 && m->target == -1) {
1946 DPRINTF(("%s: hook for record.*.source\n", __func__));
1947 mask = 0;
1948 bit = 1;
1949 for (i = 0; i < this->w[m->nid].nconnections && i < 32; i++) {
1950 err = this->comresp(this, m->nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1951 CORB_GAGM_INPUT | CORB_GAGM_LEFT |
1952 i, &result);
1953 if (err)
1954 return err;
1955 if ((result & CORB_GAGM_MUTE) == 0)
1956 mask |= bit;
1957 bit = bit << 1;
1958 }
1959 mc->un.mask = mask & ALC882_MASK;
1960 return 0;
1961 }
1962 return azalia_generic_mixer_get(this, m->nid, m->target, mc);
1963 }
1964
1965
1966
1967
1968
1969
1970 int
1971 azalia_alc883_init_dacgroup(codec_t *this)
1972 {
1973 static const convgroupset_t dacs = {
1974 -1, 2,
1975 {{4, {0x02, 0x03, 0x04, 0x05}},
1976 {1, {0x06}}}};
1977
1978 static const convgroupset_t adcs = {
1979 -1, 2,
1980 {{2, {0x08, 0x09}},
1981 {1, {0x0a}}}};
1982
1983 this->dacs = dacs;
1984 this->adcs = adcs;
1985 return 0;
1986 }
1987
1988 static const mixer_item_t alc883_mixer_items[] = {
1989 {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0},
1990 {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0},
1991 {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0},
1992
1993
1994 {{0, {"mic1."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1995 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(0)},
1996 {{0, {"mic1"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
1997 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(0)},
1998 {{0, {"mic2."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
1999 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(1)},
2000 {{0, {"mic2"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
2001 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(1)},
2002 {{0, {AudioNline"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
2003 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(2)},
2004 {{0, {AudioNline}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
2005 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(2)},
2006 {{0, {AudioNcd"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
2007 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(4)},
2008 {{0, {AudioNcd}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
2009 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(4)},
2010 {{0, {AudioNspeaker"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
2011 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_INAMP(5)},
2012 {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
2013 0, 0, .un.v={{""}, 1, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(5)},
2014
2015 {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
2016 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0c, MI_TARGET_OUTAMP},
2017 {{0, {AudioNmaster"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2018 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_OUTAMP},
2019 {{0, {AudioNmaster".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2020 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_PINBOOST},
2021 {{0, {AudioNheadphone"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2022 0, 0, ENUM_OFFON}, 0x1b, MI_TARGET_OUTAMP},
2023 {{0, {AudioNheadphone".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2024 0, 0, ENUM_OFFON}, 0x1b, MI_TARGET_PINBOOST},
2025 {{0, {AzaliaNfront".dac.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
2026 0, 0, ENUM_OFFON}, 0x0c, MI_TARGET_INAMP(0)},
2027 {{0, {AzaliaNfront".mixer.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
2028 0, 0, ENUM_OFFON}, 0x0c, MI_TARGET_INAMP(1)},
2029 {{0, {AudioNsurround}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
2030 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0d, MI_TARGET_OUTAMP},
2031 {{0, {AudioNsurround"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2032 0, 0, ENUM_OFFON}, 0x15, MI_TARGET_OUTAMP},
2033 {{0, {AudioNsurround".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2034 0, 0, ENUM_OFFON}, 0x15, MI_TARGET_PINBOOST},
2035 {{0, {AudioNsurround".dac.mut"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
2036 0, 0, ENUM_OFFON}, 0x0d, MI_TARGET_INAMP(0)},
2037 {{0, {AudioNsurround".mixer.m"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
2038 0, 0, ENUM_OFFON}, 0x0d, MI_TARGET_INAMP(1)},
2039
2040 {{0, {AzaliaNclfe}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
2041 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0e, MI_TARGET_OUTAMP},
2042 {{0, {AzaliaNclfe"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2043 0, 0, ENUM_OFFON}, 0x16, MI_TARGET_OUTAMP},
2044 {{0, {AzaliaNclfe".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2045 0, 0, ENUM_OFFON}, 0x16, MI_TARGET_PINBOOST},
2046 {{0, {AzaliaNclfe".dac.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
2047 0, 0, ENUM_OFFON}, 0x0e, MI_TARGET_INAMP(0)},
2048 {{0, {AzaliaNclfe".mixer.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
2049 0, 0, ENUM_OFFON}, 0x0e, MI_TARGET_INAMP(1)},
2050
2051 {{0, {AzaliaNside}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
2052 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0f, MI_TARGET_OUTAMP},
2053 {{0, {AzaliaNside"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2054 0, 0, ENUM_OFFON}, 0x17, MI_TARGET_OUTAMP},
2055 {{0, {AzaliaNside".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2056 0, 0, ENUM_OFFON}, 0x17, MI_TARGET_PINBOOST},
2057 {{0, {AzaliaNside".dac.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
2058 0, 0, ENUM_OFFON}, 0x0f, MI_TARGET_INAMP(0)},
2059 {{0, {AzaliaNside".mixer.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
2060 0, 0, ENUM_OFFON}, 0x0f, MI_TARGET_INAMP(1)},
2061
2062 {{0, {AudioNsurround"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
2063 0, 0, ENUM_OFFON}, 0x08, MI_TARGET_INAMP(0)},
2064 {{0, {AudioNsurround}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD,
2065 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x08, MI_TARGET_INAMP(0)},
2066 {{0, {AudioNsurround"."AudioNsource}, AUDIO_MIXER_SET, AZ_CLASS_RECORD,
2067 0, 0, .un.s={6, {{{"mic1"}, ALC882_MIC1}, {{"mic2"}, ALC882_MIC2},
2068 {{AudioNline}, ALC882_LINE}, {{AudioNcd}, ALC882_CD},
2069 {{AudioNspeaker}, ALC882_BEEP},
2070 {{AudioNmixerout}, ALC882_MIX}}}}, 0x23, -1},
2071
2072 {{0, {AzaliaNclfe"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
2073 0, 0, ENUM_OFFON}, 0x09, MI_TARGET_INAMP(0)},
2074 {{0, {AzaliaNclfe}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD,
2075 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x09, MI_TARGET_INAMP(0)},
2076 {{0, {AzaliaNclfe"."AudioNsource}, AUDIO_MIXER_SET, AZ_CLASS_RECORD,
2077 0, 0, .un.s={6, {{{"mic1"}, ALC882_MIC1}, {{"mic2"}, ALC882_MIC2},
2078 {{AudioNline}, ALC882_LINE}, {{AudioNcd}, ALC882_CD},
2079 {{AudioNspeaker}, ALC882_BEEP},
2080 {{AudioNmixerout}, ALC882_MIX}}}}, 0x22, -1},
2081
2082 {{0, {"usingdac"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0,
2083 .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_DAC},
2084 {{0, {"usingadc"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
2085 .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_ADC},
2086 };
2087
2088 int
2089 azalia_alc883_mixer_init(codec_t *this)
2090 {
2091 mixer_ctrl_t mc;
2092
2093 this->nmixers = sizeof(alc883_mixer_items) / sizeof(mixer_item_t);
2094 this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers,
2095 M_DEVBUF, M_NOWAIT);
2096 if (this->mixers == NULL) {
2097 printf("%s: out of memory in %s\n", XNAME(this), __func__);
2098 return ENOMEM;
2099 }
2100 bzero(this->mixers, sizeof(mixer_item_t) * this->maxmixers);
2101 memcpy(this->mixers, alc883_mixer_items,
2102 sizeof(mixer_item_t) * this->nmixers);
2103 azalia_generic_mixer_fix_indexes(this);
2104 azalia_generic_mixer_default(this);
2105
2106 mc.dev = -1;
2107 mc.type = AUDIO_MIXER_ENUM;
2108 mc.un.ord = 1;
2109 azalia_generic_mixer_set(this, 0x14, MI_TARGET_PINDIR, &mc);
2110 azalia_generic_mixer_set(this, 0x1b, MI_TARGET_PINDIR, &mc);
2111 azalia_generic_mixer_set(this, 0x15, MI_TARGET_PINDIR, &mc);
2112 azalia_generic_mixer_set(this, 0x16, MI_TARGET_PINDIR, &mc);
2113 azalia_generic_mixer_set(this, 0x17, MI_TARGET_PINDIR, &mc);
2114 mc.un.ord = 0;
2115 azalia_generic_mixer_set(this, 0x14, MI_TARGET_CONNLIST, &mc);
2116 azalia_generic_mixer_set(this, 0x1b, MI_TARGET_CONNLIST, &mc);
2117 mc.un.ord = 1;
2118 azalia_generic_mixer_set(this, 0x15, MI_TARGET_CONNLIST, &mc);
2119 mc.un.ord = 2;
2120 azalia_generic_mixer_set(this, 0x16, MI_TARGET_CONNLIST, &mc);
2121 mc.un.ord = 2;
2122 azalia_generic_mixer_set(this, 0x17, MI_TARGET_CONNLIST, &mc);
2123
2124 mc.un.ord = 0;
2125 azalia_generic_mixer_set(this, 0x18, MI_TARGET_PINDIR, &mc);
2126 azalia_generic_mixer_set(this, 0x19, MI_TARGET_PINDIR, &mc);
2127 azalia_generic_mixer_set(this, 0x1a, MI_TARGET_PINDIR, &mc);
2128
2129
2130 mc.un.ord = 0;
2131 azalia_generic_mixer_set(this, 0x23, MI_TARGET_INAMP(1), &mc);
2132 azalia_generic_mixer_set(this, 0x22, MI_TARGET_INAMP(2), &mc);
2133 return 0;
2134 }
2135
2136
2137
2138
2139
2140
2141 #define AD1981HD_THINKPAD 0x201017aa
2142
2143 int
2144 azalia_ad1981hd_init_widget(const codec_t *this, widget_t *w, nid_t nid)
2145 {
2146 switch (nid) {
2147 case 0x05:
2148 strlcpy(w->name, AudioNline "out", sizeof(w->name));
2149 break;
2150 case 0x06:
2151 strlcpy(w->name, "hp", sizeof(w->name));
2152 break;
2153 case 0x07:
2154 strlcpy(w->name, AudioNmono, sizeof(w->name));
2155 break;
2156 case 0x08:
2157 strlcpy(w->name, AudioNmicrophone, sizeof(w->name));
2158 break;
2159 case 0x09:
2160 strlcpy(w->name, AudioNline "in", sizeof(w->name));
2161 break;
2162 case 0x0d:
2163 strlcpy(w->name, "beep", sizeof(w->name));
2164 break;
2165 case 0x17:
2166 strlcpy(w->name, AudioNaux, sizeof(w->name));
2167 break;
2168 case 0x18:
2169 strlcpy(w->name, AudioNmicrophone "2", sizeof(w->name));
2170 break;
2171 case 0x19:
2172 strlcpy(w->name, AudioNcd, sizeof(w->name));
2173 break;
2174 case 0x1d:
2175 strlcpy(w->name, AudioNspeaker, sizeof(w->name));
2176 break;
2177 }
2178 return 0;
2179 }
2180
2181 int
2182 azalia_ad1981hd_mixer_init(codec_t *this)
2183 {
2184 mixer_ctrl_t mc;
2185 int err;
2186
2187 err = azalia_generic_mixer_init(this);
2188 if (err)
2189 return err;
2190 if (this->subid == AD1981HD_THINKPAD) {
2191 mc.dev = -1;
2192 mc.type = AUDIO_MIXER_ENUM;
2193 mc.un.ord = 1;
2194 azalia_generic_mixer_set(this, 0x09, MI_TARGET_PINDIR, &mc);
2195 }
2196 return 0;
2197 }
2198
2199
2200
2201
2202
2203 static const mixer_item_t cmi9880_mixer_items[] = {
2204 {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0},
2205 {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0},
2206 {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0},
2207
2208 {{0, {AudioNmaster"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2209 0, 0, ENUM_OFFON}, 0x03, MI_TARGET_OUTAMP},
2210 {{0, {AudioNsurround"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2211 0, 0, ENUM_OFFON}, 0x04, MI_TARGET_OUTAMP},
2212 {{0, {AzaliaNclfe"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2213 0, 0, ENUM_OFFON}, 0x05, MI_TARGET_OUTAMP},
2214 {{0, {AzaliaNside"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2215 0, 0, ENUM_OFFON}, 0x06, MI_TARGET_OUTAMP},
2216 {{0, {"digital."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2217 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_OUTAMP},
2218
2219 {{0, {AzaliaNfront"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
2220 0, 0, ENUM_OFFON}, 0x08, MI_TARGET_INAMP(0)},
2221 {{0, {AzaliaNfront}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD,
2222 0, 0, .un.v={{""}, 2, MIXER_DELTA(30)}}, 0x08, MI_TARGET_INAMP(0)},
2223 {{0, {AzaliaNfront"."AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
2224 0, 0, .un.e={4, {{{AudioNmicrophone}, 5}, {{AudioNcd}, 6},
2225 {{"line1"}, 7}, {{"line2"}, 8}}}},
2226 0x08, MI_TARGET_CONNLIST},
2227 {{0, {AudioNsurround"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
2228 0, 0, ENUM_OFFON}, 0x09, MI_TARGET_INAMP(0)},
2229 {{0, {AudioNsurround}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD,
2230 0, 0, .un.v={{""}, 2, MIXER_DELTA(30)}}, 0x09, MI_TARGET_INAMP(0)},
2231 {{0, {AudioNsurround"."AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
2232 0, 0, .un.e={4, {{{AudioNmicrophone}, 5}, {{AudioNcd}, 6},
2233 {{"line1"}, 7}, {{"line2"}, 8}}}},
2234 0x09, MI_TARGET_CONNLIST},
2235
2236 {{0, {AudioNspeaker"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
2237 0, 0, ENUM_OFFON}, 0x23, MI_TARGET_OUTAMP},
2238 {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
2239 0, 0, .un.v={{""}, 1, MIXER_DELTA(15)}}, 0x23, MI_TARGET_OUTAMP}
2240 };
2241
2242 int
2243 azalia_cmi9880_mixer_init(codec_t *this)
2244 {
2245 mixer_ctrl_t mc;
2246
2247 this->nmixers = sizeof(cmi9880_mixer_items) / sizeof(mixer_item_t);
2248 this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers,
2249 M_DEVBUF, M_NOWAIT);
2250 if (this->mixers == NULL) {
2251 printf("%s: out of memory in %s\n", XNAME(this), __func__);
2252 return ENOMEM;
2253 }
2254 bzero(this->mixers, sizeof(mixer_item_t) * this->maxmixers);
2255 memcpy(this->mixers, cmi9880_mixer_items,
2256 sizeof(mixer_item_t) * this->nmixers);
2257 azalia_generic_mixer_fix_indexes(this);
2258 azalia_generic_mixer_default(this);
2259
2260 mc.dev = -1;
2261 mc.type = AUDIO_MIXER_ENUM;
2262 mc.un.ord = 5;
2263 azalia_generic_mixer_set(this, 0x08, MI_TARGET_CONNLIST, &mc);
2264 mc.un.ord = 7;
2265 azalia_generic_mixer_set(this, 0x09, MI_TARGET_CONNLIST, &mc);
2266 mc.un.ord = 1;
2267 azalia_generic_mixer_set(this, 0x0b, MI_TARGET_PINDIR, &mc);
2268 azalia_generic_mixer_set(this, 0x0c, MI_TARGET_PINDIR, &mc);
2269 azalia_generic_mixer_set(this, 0x0d, MI_TARGET_PINDIR, &mc);
2270 azalia_generic_mixer_set(this, 0x0e, MI_TARGET_PINDIR, &mc);
2271 azalia_generic_mixer_set(this, 0x0f, MI_TARGET_PINDIR, &mc);
2272 mc.un.ord = 0;
2273 azalia_generic_mixer_set(this, 0x0f, MI_TARGET_CONNLIST, &mc);
2274 mc.un.ord = 0;
2275 azalia_generic_mixer_set(this, 0x10, MI_TARGET_PINDIR, &mc);
2276 azalia_generic_mixer_set(this, 0x13, MI_TARGET_PINDIR, &mc);
2277 azalia_generic_mixer_set(this, 0x1f, MI_TARGET_PINDIR, &mc);
2278 azalia_generic_mixer_set(this, 0x20, MI_TARGET_PINDIR, &mc);
2279 return 0;
2280 }
2281
2282 int
2283 azalia_cmi9880_init_dacgroup(codec_t *this)
2284 {
2285 static const convgroupset_t dacs = {
2286 -1, 2,
2287 {{4, {0x03, 0x04, 0x05, 0x06}},
2288 {1, {0x07}}}};
2289 static const convgroupset_t adcs = {
2290 -1, 2,
2291 {{2, {0x08, 0x09}},
2292 {1, {0x0a}}}};
2293
2294 this->dacs = dacs;
2295 this->adcs = adcs;
2296 return 0;
2297 }
2298
2299
2300
2301
2302
2303 int
2304 azalia_stac9221_init_dacgroup(codec_t *this)
2305 {
2306 static const convgroupset_t dacs = {
2307 -1, 3,
2308 {{4, {0x02, 0x03, 0x04, 0x05}},
2309 {1, {0x08}},
2310 {1, {0x1a}}}};
2311 static const convgroupset_t adcs = {
2312 -1, 2,
2313 {{2, {0x06, 0x07}},
2314 {1, {0x09}}}};
2315
2316 this->dacs = dacs;
2317 this->adcs = adcs;
2318 return 0;
2319 }
2320
2321
2322
2323
2324
2325 static const mixer_item_t stac9200_mixer_items[] = {
2326 {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0},
2327 {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0},
2328 {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0},
2329
2330 {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
2331 4, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_OUTAMP},
2332 {{0, {AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2333 0, 3, ENUM_OFFON}, 0x0b, MI_TARGET_OUTAMP},
2334 {{0, {AudioNvolume}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD,
2335 0, 0, .un.v={{""}, 2, MIXER_DELTA(15)}}, 0x0a, MI_TARGET_OUTAMP},
2336 {{0, {AudioNvolume"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
2337 0, 0, ENUM_OFFON}, 0x0a, MI_TARGET_OUTAMP},
2338 {{0, {AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
2339 0, 0, .un.e={5, {{{AudioNline}, 0}, {{AudioNmicrophone}, 1},
2340 {{AudioNline"2"}, 2}, {{AudioNline"3"}, 3},
2341 {{AudioNcd}, 4}}}},
2342 0x0c, MI_TARGET_CONNLIST},
2343 {{0, {AudioNmicrophone}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT,
2344 0, 0, .un.v={{""}, 2, MIXER_DELTA(4)}}, 0x0c, MI_TARGET_OUTAMP},
2345 {{0, {AudioNmicrophone"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
2346 0, 0, ENUM_OFFON}, 0x0c, MI_TARGET_OUTAMP},
2347 {{0, {AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2348 0, 0, .un.e={3, {{{AudioNdac}, 0}, {{"digital-in"}, 1}, {{"selector"}, 2}}}},
2349 0x07, MI_TARGET_CONNLIST},
2350 {{0, {"digital."AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2351 0, 0, .un.e={2, {{{AudioNdac}, 0}, {{"selector"}, 1}}}},
2352 0x09, MI_TARGET_CONNLIST},
2353 {{0, {AudioNheadphone".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2354 0, 0, ENUM_OFFON}, 0x0d, MI_TARGET_PINBOOST},
2355 {{0, {AudioNspeaker".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2356 0, 0, ENUM_OFFON}, 0x0e, MI_TARGET_PINBOOST},
2357 {{0, {AudioNmono"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2358 0, 0, ENUM_OFFON}, 0x11, MI_TARGET_OUTAMP},
2359 {{0, {AudioNmono}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
2360 0, 0, .un.v={{""}, 1, MIXER_DELTA(31)}}, 0x11, MI_TARGET_OUTAMP},
2361 {{0, {"beep."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2362 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_OUTAMP},
2363 {{0, {"beep"}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
2364 0, 0, .un.v={{""}, 1, MIXER_DELTA(3)}}, 0x14, MI_TARGET_OUTAMP},
2365 {{0, {"usingdac"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT,
2366 0, 0, .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}},
2367 0, MI_TARGET_DAC},
2368 {{0, {"usingadc"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
2369 0, 0, .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}},
2370 0, MI_TARGET_ADC},
2371 };
2372
2373 int
2374 azalia_stac9200_mixer_init(codec_t *this)
2375 {
2376 mixer_ctrl_t mc;
2377
2378 this->nmixers = sizeof(stac9200_mixer_items) / sizeof(mixer_item_t);
2379 this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers,
2380 M_DEVBUF, M_NOWAIT);
2381 if (this->mixers == NULL) {
2382 printf("%s: out of memory in %s\n", XNAME(this), __func__);
2383 return ENOMEM;
2384 }
2385 bzero(this->mixers, sizeof(mixer_item_t) * this->maxmixers);
2386 memcpy(this->mixers, stac9200_mixer_items,
2387 sizeof(mixer_item_t) * this->nmixers);
2388 azalia_generic_mixer_fix_indexes(this);
2389 azalia_generic_mixer_default(this);
2390
2391 mc.dev = -1;
2392 mc.type = AUDIO_MIXER_ENUM;
2393 mc.un.ord = 1;
2394 azalia_generic_mixer_set(this, 0x0d, MI_TARGET_PINDIR, &mc);
2395 azalia_generic_mixer_set(this, 0x0e, MI_TARGET_PINDIR, &mc);
2396 mc.un.ord = 0;
2397 azalia_generic_mixer_set(this, 0x0f, MI_TARGET_PINDIR, &mc);
2398 azalia_generic_mixer_set(this, 0x10, MI_TARGET_PINDIR, &mc);
2399 mc.type = AUDIO_MIXER_VALUE;
2400 mc.un.value.num_channels = 2;
2401 mc.un.value.level[0] = azalia_generic_mixer_max(this, 0x0c, MI_TARGET_OUTAMP);
2402 mc.un.value.level[1] = mc.un.value.level[0];
2403 azalia_generic_mixer_set(this, 0x0c, MI_TARGET_OUTAMP, &mc);
2404
2405 #define STAC9200_EVENT_HP 0
2406 #define STAC9200_NID_HP 0x0d
2407 #define STAC9200_NID_SPEAKER 0x0e
2408
2409
2410 this->comresp(this, STAC9200_NID_HP,
2411 CORB_SET_UNSOLICITED_RESPONSE,
2412 CORB_UNSOL_ENABLE | STAC9200_EVENT_HP, NULL);
2413
2414 azalia_stac9200_unsol_event(this, STAC9200_EVENT_HP);
2415
2416 return 0;
2417 }
2418 int
2419 azalia_stac9200_unsol_event(codec_t *this, int tag)
2420 {
2421 int err;
2422 uint32_t value;
2423
2424 switch (tag) {
2425 case STAC9200_EVENT_HP:
2426 err = this->comresp(this, STAC9200_NID_HP,
2427 CORB_GET_PIN_SENSE, 0, &value);
2428 if (err)
2429 break;
2430 if (value & CORB_PS_PRESENCE) {
2431 DPRINTF(("%s: headphone inserted\n", __func__));
2432 azalia_generic_mixer_pinctrl(this,
2433 STAC9200_NID_SPEAKER, 0);
2434 } else {
2435 DPRINTF(("%s: headphone pulled\n", __func__));
2436 azalia_generic_mixer_pinctrl(this,
2437 STAC9200_NID_SPEAKER, CORB_PWC_OUTPUT);
2438 }
2439 break;
2440 default:
2441 DPRINTF(("%s: unknown tag: %d\n", __func__, tag));
2442 }
2443 return 0;
2444 }
2445
2446 int
2447 azalia_stac9221_apple_init_dacgroup(codec_t *this)
2448 {
2449 static const convgroupset_t dacs = {
2450 -1, 1,
2451 {{4, {0x02, 0x03, 0x04, 0x05}}}};
2452
2453 static const convgroupset_t adcs = {
2454 -1, 2,
2455 {{2, {0x06, 0x07}},
2456 {1, {0x09}}}};
2457
2458 this->dacs = dacs;
2459 this->adcs = adcs;
2460 return 0;
2461 }
2462
2463 static const mixer_item_t stac9221_apple_mixer_items[] = {
2464 {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0},
2465 {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0},
2466 {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0},
2467
2468 {{0, {AudioNheadphone}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
2469 0, 0, .un.v={{""}, 2, MIXER_DELTA(15)}}, 0x02, MI_TARGET_OUTAMP},
2470 {{0, {AudioNheadphone".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2471 0, 0, ENUM_OFFON}, 0x02, MI_TARGET_OUTAMP},
2472
2473 {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
2474 0, 0, .un.v={{""}, 2, MIXER_DELTA(15)}}, 0x03, MI_TARGET_OUTAMP},
2475 {{0, {AudioNspeaker".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2476 0, 0, ENUM_OFFON}, 0x03, MI_TARGET_OUTAMP},
2477
2478 {{0, {"line"}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
2479 0, 0, .un.v={{""}, 2, MIXER_DELTA(15)}}, 0x04, MI_TARGET_OUTAMP},
2480 {{0, {"line.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2481 0, 0, ENUM_OFFON}, 0x04, MI_TARGET_OUTAMP},
2482
2483 {{0, {"line2"}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
2484 0, 0, .un.v={{""}, 2, MIXER_DELTA(15)}}, 0x05, MI_TARGET_OUTAMP},
2485 {{0, {"line2.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2486 0, 0, ENUM_OFFON}, 0x05, MI_TARGET_OUTAMP},
2487
2488 {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
2489 0, 0, .un.v={{""}, 1, MIXER_DELTA(15)}}, 0x16, MI_TARGET_VOLUME},
2490 };
2491
2492 int
2493 azalia_stac9221_apple_mixer_init(codec_t *this)
2494 {
2495 mixer_ctrl_t mc;
2496
2497 this->nmixers = sizeof(stac9221_apple_mixer_items) / sizeof(mixer_item_t);
2498 this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers,
2499 M_DEVBUF, M_NOWAIT);
2500 if (this->mixers == NULL) {
2501 printf("%s: out of memory in %s\n", XNAME(this), __func__);
2502 return ENOMEM;
2503 }
2504 bzero(this->mixers, sizeof(mixer_item_t) * this->maxmixers);
2505 memcpy(this->mixers, stac9221_apple_mixer_items,
2506 sizeof(mixer_item_t) * this->nmixers);
2507 azalia_generic_mixer_fix_indexes(this);
2508 azalia_generic_mixer_default(this);
2509
2510 mc.dev = -1;
2511 mc.type = AUDIO_MIXER_ENUM;
2512 mc.un.ord = 1;
2513 azalia_generic_mixer_set(this, 0x0a, MI_TARGET_PINDIR, &mc);
2514 azalia_generic_mixer_set(this, 0x0b, MI_TARGET_PINDIR, &mc);
2515 azalia_generic_mixer_set(this, 0x0c, MI_TARGET_PINDIR, &mc);
2516 azalia_generic_mixer_set(this, 0x0d, MI_TARGET_PINDIR, &mc);
2517 azalia_generic_mixer_set(this, 0x0f, MI_TARGET_PINDIR, &mc);
2518
2519
2520 mc.type = AUDIO_MIXER_VALUE;
2521 mc.un.value.num_channels = 2;
2522 mc.un.value.level[0] = azalia_generic_mixer_max(this, 0x02, MI_TARGET_OUTAMP);
2523 mc.un.value.level[1] = mc.un.value.level[0];
2524 azalia_generic_mixer_set(this, 0x02, MI_TARGET_OUTAMP, &mc);
2525
2526 mc.un.value.level[0] = azalia_generic_mixer_max(this, 0x03, MI_TARGET_OUTAMP);
2527 mc.un.value.level[1] = mc.un.value.level[0];
2528 azalia_generic_mixer_set(this, 0x03, MI_TARGET_OUTAMP, &mc);
2529
2530 mc.un.value.level[0] = azalia_generic_mixer_max(this, 0x04, MI_TARGET_OUTAMP);
2531 mc.un.value.level[1] = mc.un.value.level[0];
2532 azalia_generic_mixer_set(this, 0x04, MI_TARGET_OUTAMP, &mc);
2533
2534 mc.un.value.level[0] = azalia_generic_mixer_max(this, 0x05, MI_TARGET_OUTAMP);
2535 mc.un.value.level[1] = mc.un.value.level[0];
2536 azalia_generic_mixer_set(this, 0x05, MI_TARGET_OUTAMP, &mc);
2537
2538 azalia_stac9221_gpio_unmute(this, 0);
2539 azalia_stac9221_gpio_unmute(this, 1);
2540
2541 return 0;
2542 }
2543
2544 int
2545 azalia_stac9221_gpio_unmute(codec_t *this, int pin)
2546 {
2547 uint32_t data, mask, dir;
2548
2549 this->comresp(this, this->audiofunc, CORB_GET_GPIO_DATA, 0, &data);
2550 this->comresp(this, this->audiofunc, CORB_GET_GPIO_ENABLE_MASK, 0, &mask);
2551 this->comresp(this, this->audiofunc, CORB_GET_GPIO_DIRECTION, 0, &dir);
2552
2553 data |= 1 << pin;
2554 mask |= 1 << pin;
2555 dir |= 1 << pin;
2556
2557 this->comresp(this, this->audiofunc, 0x7e7, 0, NULL);
2558 this->comresp(this, this->audiofunc, CORB_SET_GPIO_ENABLE_MASK, mask, NULL);
2559 this->comresp(this, this->audiofunc, CORB_SET_GPIO_DIRECTION, dir, NULL);
2560 DELAY(1000);
2561 this->comresp(this, this->audiofunc, CORB_SET_GPIO_DATA, data, NULL);
2562
2563 return 0;
2564 }
2565
2566
2567
2568
2569
2570 int
2571 azalia_stac7661_init_dacgroup(codec_t *this)
2572 {
2573 static const convgroupset_t dacs = {
2574 -1, 1,
2575 {{2, {0x02, 0x05}}}};
2576
2577 static const convgroupset_t adcs = {
2578 -1, 1,
2579 {{1, {0x08}}}};
2580
2581 this->dacs = dacs;
2582 this->adcs = adcs;
2583
2584 return 0;
2585 }
2586
2587 static const mixer_item_t stac7661_mixer_items[] = {
2588 {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0},
2589 {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0},
2590 {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0},
2591
2592 #define STAC7661_DAC_HP 0x02
2593 #define STAC7661_DAC_SPEAKER 0x05
2594 #define STAC7661_TARGET_MASTER -1
2595
2596 {{0, {AudioNvolume"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0,
2597 ENUM_OFFON}, 0x09, MI_TARGET_INAMP(0)},
2598 {{0, {AudioNvolume}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0,
2599 .un.v={{""}, 2, MIXER_DELTA(15)}}, 0x09, MI_TARGET_INAMP(0)},
2600 {{0, {AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD,
2601 0, 0, .un.e={3, {{{AudioNmicrophone}, 1}, {{AudioNmicrophone"2"}, 2},
2602 {{AudioNdac}, 3}}}},
2603 0x15, MI_TARGET_CONNLIST},
2604 {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
2605 0, 0, .un.v={{""}, 2, MIXER_DELTA(127)}}, 0x02, STAC7661_TARGET_MASTER},
2606 {{0, {AudioNmaster"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2607 0, 0, ENUM_OFFON}, 0x02, STAC7661_TARGET_MASTER},
2608 {{0, {AudioNvolume".knob"}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
2609 0, 0, .un.v={{""}, 1, MIXER_DELTA(15)}}, 0x17, MI_TARGET_VOLUME},
2610 {{0, {AudioNheadphone".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2611 0, 0, ENUM_OFFON}, 0x02, MI_TARGET_OUTAMP},
2612 {{0, {AudioNheadphone}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
2613 0, 0, .un.v={{""}, 2, MIXER_DELTA(127)}}, 0x02, MI_TARGET_OUTAMP},
2614 {{0, {AudioNspeaker".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT,
2615 0, 0, ENUM_OFFON}, 0x05, MI_TARGET_OUTAMP},
2616 {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT,
2617 0, 0, .un.v={{""}, 2, MIXER_DELTA(127)}}, 0x05, MI_TARGET_OUTAMP}
2618 };
2619
2620 int
2621 azalia_stac7661_mixer_init(codec_t *this)
2622 {
2623 mixer_ctrl_t mc;
2624
2625 this->nmixers = sizeof(stac7661_mixer_items) / sizeof(mixer_item_t);
2626 this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers,
2627 M_DEVBUF, M_NOWAIT);
2628 if (this->mixers == NULL) {
2629 printf("%s: out of memory in %s\n", XNAME(this), __func__);
2630 return ENOMEM;
2631 }
2632 bzero(this->mixers, sizeof(mixer_item_t) * this->maxmixers);
2633 memcpy(this->mixers, stac7661_mixer_items,
2634 sizeof(mixer_item_t) * this->nmixers);
2635 azalia_generic_mixer_fix_indexes(this);
2636 azalia_generic_mixer_default(this);
2637 mc.dev = -1;
2638 mc.type = AUDIO_MIXER_ENUM;
2639 mc.un.ord = 1;
2640 azalia_generic_mixer_set(this, 0x0a, MI_TARGET_PINDIR, &mc);
2641 azalia_generic_mixer_set(this, 0x0f, MI_TARGET_PINDIR, &mc);
2642 azalia_generic_mixer_set(this, 0x09, MI_TARGET_INAMP(0), &mc);
2643 mc.un.ord = 0;
2644 azalia_generic_mixer_set(this, 0x0d, MI_TARGET_PINDIR, &mc);
2645 azalia_generic_mixer_set(this, 0x14, MI_TARGET_PINDIR, &mc);
2646 mc.un.ord = 2;
2647 azalia_generic_mixer_set(this, 0x15, MI_TARGET_CONNLIST, &mc);
2648 mc.type = AUDIO_MIXER_VALUE;
2649 mc.un.value.num_channels = 1;
2650 mc.un.value.level[0] = azalia_generic_mixer_max(this, 0x17, MI_TARGET_VOLUME);
2651 azalia_generic_mixer_set(this, 0x17, MI_TARGET_VOLUME, &mc);
2652
2653 return 0;
2654 }
2655
2656 int
2657 azalia_stac7661_set_port(codec_t *this, mixer_ctrl_t *mc)
2658 {
2659 const mixer_item_t *m;
2660 int err;
2661
2662 if (mc->dev >= this->nmixers)
2663 return ENXIO;
2664 m = &this->mixers[mc->dev];
2665 if (mc->type != m->devinfo.type)
2666 return EINVAL;
2667 if (mc->type == AUDIO_MIXER_CLASS)
2668 return 0;
2669 if (m->target == STAC7661_TARGET_MASTER) {
2670 err = azalia_generic_mixer_set(this, STAC7661_DAC_HP,
2671 MI_TARGET_OUTAMP, mc);
2672 err = azalia_generic_mixer_set(this, STAC7661_DAC_SPEAKER,
2673 MI_TARGET_OUTAMP, mc);
2674 return err;
2675 }
2676 return azalia_generic_mixer_set(this, m->nid, m->target, mc);
2677 }
2678 int
2679 azalia_stac7661_get_port(codec_t *this, mixer_ctrl_t *mc)
2680 {
2681 const mixer_item_t *m;
2682
2683 if (mc->dev >= this->nmixers)
2684 return ENXIO;
2685 m = &this->mixers[mc->dev];
2686 mc->type = m->devinfo.type;
2687 if (mc->type == AUDIO_MIXER_CLASS)
2688 return 0;
2689 if (m->target == STAC7661_TARGET_MASTER)
2690 return azalia_generic_mixer_get(this, m->nid,
2691 MI_TARGET_OUTAMP, mc);
2692 return azalia_generic_mixer_get(this, m->nid, m->target, mc);
2693 }