Line data Source code
1 : /* $OpenBSD: azalia.c,v 1.244 2018/04/22 10:02:13 ratchov Exp $ */
2 : /* $NetBSD: azalia.c,v 1.20 2006/05/07 08:31:44 kent Exp $ */
3 :
4 : /*-
5 : * Copyright (c) 2005 The NetBSD Foundation, Inc.
6 : * All rights reserved.
7 : *
8 : * This code is derived from software contributed to The NetBSD Foundation
9 : * by TAMURA Kent
10 : *
11 : * Redistribution and use in source and binary forms, with or without
12 : * modification, are permitted provided that the following conditions
13 : * are met:
14 : * 1. Redistributions of source code must retain the above copyright
15 : * notice, this list of conditions and the following disclaimer.
16 : * 2. Redistributions in binary form must reproduce the above copyright
17 : * notice, this list of conditions and the following disclaimer in the
18 : * documentation and/or other materials provided with the distribution.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 : * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 : * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 : * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 : * POSSIBILITY OF SUCH DAMAGE.
31 : */
32 :
33 : /*
34 : * High Definition Audio Specification
35 : *
36 : * http://www.intel.com/content/dam/www/public/us/en/documents/product-specifications/high-definition-audio-specification.pdf
37 : *
38 : *
39 : * TO DO:
40 : * - multiple codecs (needed?)
41 : * - multiple streams (needed?)
42 : */
43 :
44 : #include <sys/param.h>
45 : #include <sys/fcntl.h>
46 : #include <sys/device.h>
47 : #include <sys/malloc.h>
48 : #include <sys/systm.h>
49 : #include <sys/timeout.h>
50 : #include <dev/audio_if.h>
51 : #include <dev/pci/pcidevs.h>
52 : #include <dev/pci/pcivar.h>
53 :
54 : #include <dev/pci/azalia.h>
55 :
56 : typedef struct audio_params audio_params_t;
57 :
58 : struct audio_format {
59 : void *driver_data;
60 : int32_t mode;
61 : u_int encoding;
62 : u_int precision;
63 : u_int channels;
64 :
65 : /**
66 : * 0: frequency[0] is lower limit, and frequency[1] is higher limit.
67 : * 1-16: frequency[0] to frequency[frequency_type-1] are valid.
68 : */
69 : u_int frequency_type;
70 :
71 : #define AUFMT_MAX_FREQUENCIES 16
72 : /**
73 : * sampling rates
74 : */
75 : u_int frequency[AUFMT_MAX_FREQUENCIES];
76 : };
77 :
78 :
79 : #ifdef AZALIA_DEBUG
80 : # define DPRINTFN(n,x) do { if (az_debug > (n)) printf x; } while (0/*CONSTCOND*/)
81 : int az_debug = 0;
82 : #else
83 : # define DPRINTFN(n,x) do {} while (0/*CONSTCOND*/)
84 : #endif
85 :
86 :
87 : /* ----------------------------------------------------------------
88 : * ICH6/ICH7 constant values
89 : * ---------------------------------------------------------------- */
90 :
91 : /* PCI registers */
92 : #define ICH_PCI_HDBARL 0x10
93 : #define ICH_PCI_HDBARU 0x14
94 : #define ICH_PCI_HDCTL 0x40
95 : #define ICH_PCI_HDCTL_CLKDETCLR 0x08
96 : #define ICH_PCI_HDCTL_CLKDETEN 0x04
97 : #define ICH_PCI_HDCTL_CLKDETINV 0x02
98 : #define ICH_PCI_HDCTL_SIGNALMODE 0x01
99 : #define ICH_PCI_HDTCSEL 0x44
100 : #define ICH_PCI_HDTCSEL_MASK 0x7
101 : #define ICH_PCI_MMC 0x62
102 : #define ICH_PCI_MMC_ME 0x1
103 :
104 : /* internal types */
105 :
106 : typedef struct {
107 : bus_dmamap_t map;
108 : caddr_t addr; /* kernel virtual address */
109 : bus_dma_segment_t segments[1];
110 : size_t size;
111 : } azalia_dma_t;
112 : #define AZALIA_DMA_DMAADDR(p) ((p)->map->dm_segs[0].ds_addr)
113 :
114 : typedef struct {
115 : struct azalia_t *az;
116 : int regbase;
117 : int number;
118 : int dir; /* AUMODE_PLAY or AUMODE_RECORD */
119 : uint32_t intr_bit;
120 : azalia_dma_t bdlist;
121 : azalia_dma_t buffer;
122 : void (*intr)(void*);
123 : void *intr_arg;
124 : int bufsize;
125 : uint16_t fmt;
126 : int blk;
127 : unsigned int swpos; /* position in the audio(4) layer */
128 : } stream_t;
129 : #define STR_READ_1(s, r) \
130 : bus_space_read_1((s)->az->iot, (s)->az->ioh, (s)->regbase + HDA_SD_##r)
131 : #define STR_READ_2(s, r) \
132 : bus_space_read_2((s)->az->iot, (s)->az->ioh, (s)->regbase + HDA_SD_##r)
133 : #define STR_READ_4(s, r) \
134 : bus_space_read_4((s)->az->iot, (s)->az->ioh, (s)->regbase + HDA_SD_##r)
135 : #define STR_WRITE_1(s, r, v) \
136 : bus_space_write_1((s)->az->iot, (s)->az->ioh, (s)->regbase + HDA_SD_##r, v)
137 : #define STR_WRITE_2(s, r, v) \
138 : bus_space_write_2((s)->az->iot, (s)->az->ioh, (s)->regbase + HDA_SD_##r, v)
139 : #define STR_WRITE_4(s, r, v) \
140 : bus_space_write_4((s)->az->iot, (s)->az->ioh, (s)->regbase + HDA_SD_##r, v)
141 :
142 : typedef struct azalia_t {
143 : struct device dev;
144 :
145 : pci_chipset_tag_t pc;
146 : pcitag_t tag;
147 : void *ih;
148 : bus_space_tag_t iot;
149 : bus_space_handle_t ioh;
150 : bus_size_t map_size;
151 : bus_dma_tag_t dmat;
152 : pcireg_t pciid;
153 : uint32_t subid;
154 :
155 : codec_t *codecs;
156 : int ncodecs; /* number of codecs */
157 : int codecno; /* index of the using codec */
158 : int detached; /* 1 if failed to initialize, 2 if
159 : * azalia_pci_detach has run
160 : */
161 : azalia_dma_t corb_dma;
162 : int corb_entries;
163 : uint8_t corbsize;
164 : azalia_dma_t rirb_dma;
165 : int rirb_entries;
166 : uint8_t rirbsize;
167 : int rirb_rp;
168 : #define UNSOLQ_SIZE 256
169 : rirb_entry_t *unsolq;
170 : int unsolq_wp;
171 : int unsolq_rp;
172 : int unsolq_kick;
173 : struct timeout unsol_to;
174 :
175 : int ok64;
176 : int nistreams, nostreams, nbstreams;
177 : stream_t pstream;
178 : stream_t rstream;
179 : } azalia_t;
180 : #define XNAME(sc) ((sc)->dev.dv_xname)
181 : #define AZ_READ_1(z, r) bus_space_read_1((z)->iot, (z)->ioh, HDA_##r)
182 : #define AZ_READ_2(z, r) bus_space_read_2((z)->iot, (z)->ioh, HDA_##r)
183 : #define AZ_READ_4(z, r) bus_space_read_4((z)->iot, (z)->ioh, HDA_##r)
184 : #define AZ_WRITE_1(z, r, v) bus_space_write_1((z)->iot, (z)->ioh, HDA_##r, v)
185 : #define AZ_WRITE_2(z, r, v) bus_space_write_2((z)->iot, (z)->ioh, HDA_##r, v)
186 : #define AZ_WRITE_4(z, r, v) bus_space_write_4((z)->iot, (z)->ioh, HDA_##r, v)
187 :
188 :
189 : /* prototypes */
190 : uint8_t azalia_pci_read(pci_chipset_tag_t, pcitag_t, int);
191 : void azalia_pci_write(pci_chipset_tag_t, pcitag_t, int, uint8_t);
192 : int azalia_pci_match(struct device *, void *, void *);
193 : void azalia_pci_attach(struct device *, struct device *, void *);
194 : int azalia_pci_activate(struct device *, int);
195 : int azalia_pci_detach(struct device *, int);
196 : void azalia_configure_pci(azalia_t *);
197 : int azalia_intr(void *);
198 : void azalia_print_codec(codec_t *);
199 : int azalia_reset(azalia_t *);
200 : int azalia_get_ctrlr_caps(azalia_t *);
201 : int azalia_init(azalia_t *, int);
202 : int azalia_init_codecs(azalia_t *);
203 : int azalia_init_streams(azalia_t *);
204 : void azalia_shutdown(void *);
205 : int azalia_halt_corb(azalia_t *);
206 : int azalia_init_corb(azalia_t *, int);
207 : int azalia_halt_rirb(azalia_t *);
208 : int azalia_init_rirb(azalia_t *, int);
209 : int azalia_set_command(azalia_t *, nid_t, int, uint32_t, uint32_t);
210 : int azalia_get_response(azalia_t *, uint32_t *);
211 : void azalia_rirb_kick_unsol_events(void *);
212 : void azalia_rirb_intr(azalia_t *);
213 : int azalia_alloc_dmamem(azalia_t *, size_t, size_t, azalia_dma_t *);
214 : void azalia_free_dmamem(const azalia_t *, azalia_dma_t*);
215 :
216 : int azalia_codec_init(codec_t *);
217 : int azalia_codec_delete(codec_t *);
218 : void azalia_codec_add_bits(codec_t *, int, uint32_t, int);
219 : void azalia_codec_add_format(codec_t *, int, int, uint32_t, int32_t);
220 : int azalia_codec_connect_stream(stream_t *);
221 : int azalia_codec_disconnect_stream(stream_t *);
222 : void azalia_codec_print_audiofunc(const codec_t *);
223 : void azalia_codec_print_groups(const codec_t *);
224 : int azalia_codec_find_defdac(codec_t *, int, int);
225 : int azalia_codec_find_defadc(codec_t *, int, int);
226 : int azalia_codec_find_defadc_sub(codec_t *, nid_t, int, int);
227 : int azalia_codec_init_volgroups(codec_t *);
228 : int azalia_codec_sort_pins(codec_t *);
229 : int azalia_codec_select_micadc(codec_t *);
230 : int azalia_codec_select_dacs(codec_t *);
231 : int azalia_codec_select_spkrdac(codec_t *);
232 : int azalia_codec_find_inputmixer(codec_t *);
233 :
234 : int azalia_widget_init(widget_t *, const codec_t *, int);
235 : int azalia_widget_label_widgets(codec_t *);
236 : int azalia_widget_init_audio(widget_t *, const codec_t *);
237 : int azalia_widget_init_pin(widget_t *, const codec_t *);
238 : int azalia_widget_init_connection(widget_t *, const codec_t *);
239 : int azalia_widget_check_conn(codec_t *, int, int);
240 : int azalia_widget_sole_conn(codec_t *, nid_t);
241 : void azalia_widget_print_widget(const widget_t *, const codec_t *);
242 : void azalia_widget_print_audio(const widget_t *, const char *);
243 : void azalia_widget_print_pin(const widget_t *);
244 :
245 : int azalia_stream_init(stream_t *, azalia_t *, int, int, int);
246 : int azalia_stream_reset(stream_t *);
247 : int azalia_stream_start(stream_t *);
248 : int azalia_stream_halt(stream_t *);
249 : int azalia_stream_intr(stream_t *);
250 :
251 : int azalia_open(void *, int);
252 : void azalia_close(void *);
253 : int azalia_set_params(void *, int, int, audio_params_t *,
254 : audio_params_t *);
255 : int azalia_round_blocksize(void *, int);
256 : int azalia_halt_output(void *);
257 : int azalia_halt_input(void *);
258 : int azalia_set_port(void *, mixer_ctrl_t *);
259 : int azalia_get_port(void *, mixer_ctrl_t *);
260 : int azalia_query_devinfo(void *, mixer_devinfo_t *);
261 : void *azalia_allocm(void *, int, size_t, int, int);
262 : void azalia_freem(void *, void *, int);
263 : size_t azalia_round_buffersize(void *, int, size_t);
264 : int azalia_get_props(void *);
265 : int azalia_trigger_output(void *, void *, void *, int,
266 : void (*)(void *), void *, audio_params_t *);
267 : int azalia_trigger_input(void *, void *, void *, int,
268 : void (*)(void *), void *, audio_params_t *);
269 :
270 : int azalia_params2fmt(const audio_params_t *, uint16_t *);
271 :
272 : int azalia_match_format(codec_t *, int, audio_params_t *);
273 : int azalia_set_params_sub(codec_t *, int, audio_params_t *);
274 :
275 : int azalia_suspend(azalia_t *);
276 : int azalia_resume(azalia_t *);
277 : int azalia_resume_codec(codec_t *);
278 :
279 : /* variables */
280 : struct cfattach azalia_ca = {
281 : sizeof(azalia_t), azalia_pci_match, azalia_pci_attach,
282 : azalia_pci_detach, azalia_pci_activate
283 : };
284 :
285 : struct cfdriver azalia_cd = {
286 : NULL, "azalia", DV_DULL
287 : };
288 :
289 : struct audio_hw_if azalia_hw_if = {
290 : azalia_open,
291 : azalia_close,
292 : azalia_set_params,
293 : azalia_round_blocksize,
294 : NULL, /* commit_settings */
295 : NULL, /* init_output */
296 : NULL, /* init_input */
297 : NULL, /* start_output */
298 : NULL, /* start_input */
299 : azalia_halt_output,
300 : azalia_halt_input,
301 : NULL, /* speaker_ctl */
302 : NULL, /* setfd */
303 : azalia_set_port,
304 : azalia_get_port,
305 : azalia_query_devinfo,
306 : azalia_allocm,
307 : azalia_freem,
308 : azalia_round_buffersize,
309 : azalia_get_props,
310 : azalia_trigger_output,
311 : azalia_trigger_input
312 : };
313 :
314 : static const char *pin_devices[16] = {
315 : AudioNline, AudioNspeaker, AudioNheadphone, AudioNcd,
316 : "SPDIF", "digital-out", "modem-line", "modem-handset",
317 : "line-in", AudioNaux, AudioNmicrophone, "telephony",
318 : "SPDIF-in", "digital-in", "beep", "other"};
319 : static const char *wtypes[16] = {
320 : "dac", "adc", "mix", "sel", "pin", "pow", "volume",
321 : "beep", "wid08", "wid09", "wid0a", "wid0b", "wid0c",
322 : "wid0d", "wid0e", "vendor"};
323 : static const char *line_colors[16] = {
324 : "unk", "blk", "gry", "blu", "grn", "red", "org", "yel",
325 : "pur", "pnk", "0xa", "0xb", "0xc", "0xd", "wht", "oth"};
326 :
327 : /* ================================================================
328 : * PCI functions
329 : * ================================================================ */
330 :
331 : #define ATI_PCIE_SNOOP_REG 0x42
332 : #define ATI_PCIE_SNOOP_MASK 0xf8
333 : #define ATI_PCIE_SNOOP_ENABLE 0x02
334 : #define NVIDIA_PCIE_SNOOP_REG 0x4e
335 : #define NVIDIA_PCIE_SNOOP_MASK 0xf0
336 : #define NVIDIA_PCIE_SNOOP_ENABLE 0x0f
337 : #define NVIDIA_HDA_ISTR_COH_REG 0x4d
338 : #define NVIDIA_HDA_OSTR_COH_REG 0x4c
339 : #define NVIDIA_HDA_STR_COH_ENABLE 0x01
340 : #define INTEL_PCIE_NOSNOOP_REG 0x79
341 : #define INTEL_PCIE_NOSNOOP_MASK 0xf7
342 : #define INTEL_PCIE_NOSNOOP_ENABLE 0x08
343 :
344 : uint8_t
345 0 : azalia_pci_read(pci_chipset_tag_t pc, pcitag_t pa, int reg)
346 : {
347 0 : return (pci_conf_read(pc, pa, (reg & ~0x03)) >>
348 0 : ((reg & 0x03) * 8) & 0xff);
349 : }
350 :
351 : void
352 0 : azalia_pci_write(pci_chipset_tag_t pc, pcitag_t pa, int reg, uint8_t val)
353 : {
354 : pcireg_t pcival;
355 :
356 0 : pcival = pci_conf_read(pc, pa, (reg & ~0x03));
357 0 : pcival &= ~(0xff << ((reg & 0x03) * 8));
358 0 : pcival |= (val << ((reg & 0x03) * 8));
359 0 : pci_conf_write(pc, pa, (reg & ~0x03), pcival);
360 0 : }
361 :
362 : void
363 0 : azalia_configure_pci(azalia_t *az)
364 : {
365 : pcireg_t v;
366 : uint8_t reg;
367 :
368 : /* enable back-to-back */
369 0 : v = pci_conf_read(az->pc, az->tag, PCI_COMMAND_STATUS_REG);
370 0 : pci_conf_write(az->pc, az->tag, PCI_COMMAND_STATUS_REG,
371 0 : v | PCI_COMMAND_BACKTOBACK_ENABLE);
372 :
373 : /* traffic class select */
374 0 : v = pci_conf_read(az->pc, az->tag, ICH_PCI_HDTCSEL);
375 0 : pci_conf_write(az->pc, az->tag, ICH_PCI_HDTCSEL,
376 0 : v & ~(ICH_PCI_HDTCSEL_MASK));
377 :
378 : /* enable PCIe snoop */
379 0 : switch (PCI_PRODUCT(az->pciid)) {
380 : case PCI_PRODUCT_ATI_SB450_HDA:
381 : case PCI_PRODUCT_ATI_SBX00_HDA:
382 : case PCI_PRODUCT_AMD_HUDSON2_HDA:
383 0 : reg = azalia_pci_read(az->pc, az->tag, ATI_PCIE_SNOOP_REG);
384 0 : reg &= ATI_PCIE_SNOOP_MASK;
385 0 : reg |= ATI_PCIE_SNOOP_ENABLE;
386 0 : azalia_pci_write(az->pc, az->tag, ATI_PCIE_SNOOP_REG, reg);
387 0 : break;
388 : case PCI_PRODUCT_NVIDIA_MCP51_HDA:
389 : case PCI_PRODUCT_NVIDIA_MCP55_HDA:
390 : case PCI_PRODUCT_NVIDIA_MCP61_HDA_1:
391 : case PCI_PRODUCT_NVIDIA_MCP61_HDA_2:
392 : case PCI_PRODUCT_NVIDIA_MCP65_HDA_1:
393 : case PCI_PRODUCT_NVIDIA_MCP65_HDA_2:
394 : case PCI_PRODUCT_NVIDIA_MCP67_HDA_1:
395 : case PCI_PRODUCT_NVIDIA_MCP67_HDA_2:
396 : case PCI_PRODUCT_NVIDIA_MCP73_HDA_1:
397 : case PCI_PRODUCT_NVIDIA_MCP73_HDA_2:
398 : case PCI_PRODUCT_NVIDIA_MCP77_HDA_1:
399 : case PCI_PRODUCT_NVIDIA_MCP77_HDA_2:
400 : case PCI_PRODUCT_NVIDIA_MCP77_HDA_3:
401 : case PCI_PRODUCT_NVIDIA_MCP77_HDA_4:
402 : case PCI_PRODUCT_NVIDIA_MCP79_HDA_1:
403 : case PCI_PRODUCT_NVIDIA_MCP79_HDA_2:
404 : case PCI_PRODUCT_NVIDIA_MCP79_HDA_3:
405 : case PCI_PRODUCT_NVIDIA_MCP79_HDA_4:
406 : case PCI_PRODUCT_NVIDIA_MCP89_HDA_1:
407 : case PCI_PRODUCT_NVIDIA_MCP89_HDA_2:
408 : case PCI_PRODUCT_NVIDIA_MCP89_HDA_3:
409 : case PCI_PRODUCT_NVIDIA_MCP89_HDA_4:
410 0 : reg = azalia_pci_read(az->pc, az->tag,
411 : NVIDIA_HDA_OSTR_COH_REG);
412 0 : reg |= NVIDIA_HDA_STR_COH_ENABLE;
413 0 : azalia_pci_write(az->pc, az->tag,
414 : NVIDIA_HDA_OSTR_COH_REG, reg);
415 :
416 0 : reg = azalia_pci_read(az->pc, az->tag,
417 : NVIDIA_HDA_ISTR_COH_REG);
418 0 : reg |= NVIDIA_HDA_STR_COH_ENABLE;
419 0 : azalia_pci_write(az->pc, az->tag,
420 : NVIDIA_HDA_ISTR_COH_REG, reg);
421 :
422 0 : reg = azalia_pci_read(az->pc, az->tag,
423 : NVIDIA_PCIE_SNOOP_REG);
424 0 : reg &= NVIDIA_PCIE_SNOOP_MASK;
425 0 : reg |= NVIDIA_PCIE_SNOOP_ENABLE;
426 0 : azalia_pci_write(az->pc, az->tag,
427 : NVIDIA_PCIE_SNOOP_REG, reg);
428 :
429 0 : reg = azalia_pci_read(az->pc, az->tag,
430 : NVIDIA_PCIE_SNOOP_REG);
431 0 : if ((reg & NVIDIA_PCIE_SNOOP_ENABLE) !=
432 : NVIDIA_PCIE_SNOOP_ENABLE) {
433 0 : printf(": could not enable PCIe cache snooping!\n");
434 0 : }
435 : break;
436 : case PCI_PRODUCT_INTEL_82801FB_HDA:
437 : case PCI_PRODUCT_INTEL_82801GB_HDA:
438 : case PCI_PRODUCT_INTEL_82801H_HDA:
439 : case PCI_PRODUCT_INTEL_82801I_HDA:
440 : case PCI_PRODUCT_INTEL_82801JI_HDA:
441 : case PCI_PRODUCT_INTEL_82801JD_HDA:
442 : case PCI_PRODUCT_INTEL_6321ESB_HDA:
443 : case PCI_PRODUCT_INTEL_3400_HDA:
444 : case PCI_PRODUCT_INTEL_QS57_HDA:
445 : case PCI_PRODUCT_INTEL_6SERIES_HDA:
446 : case PCI_PRODUCT_INTEL_7SERIES_HDA:
447 : case PCI_PRODUCT_INTEL_8SERIES_HDA:
448 : case PCI_PRODUCT_INTEL_8SERIES_LP_HDA:
449 : case PCI_PRODUCT_INTEL_9SERIES_HDA:
450 : case PCI_PRODUCT_INTEL_9SERIES_LP_HDA:
451 : case PCI_PRODUCT_INTEL_BAYTRAIL_HDA:
452 : case PCI_PRODUCT_INTEL_100SERIES_HDA:
453 : case PCI_PRODUCT_INTEL_100SERIES_LP_HDA:
454 : case PCI_PRODUCT_INTEL_200SERIES_HDA:
455 : case PCI_PRODUCT_INTEL_200SERIES_U_HDA:
456 : case PCI_PRODUCT_INTEL_C600_HDA:
457 : case PCI_PRODUCT_INTEL_C610_HDA:
458 : case PCI_PRODUCT_INTEL_BSW_HDA:
459 : case PCI_PRODUCT_INTEL_APOLLOLAKE_HDA:
460 0 : reg = azalia_pci_read(az->pc, az->tag,
461 : INTEL_PCIE_NOSNOOP_REG);
462 0 : reg &= INTEL_PCIE_NOSNOOP_MASK;
463 0 : azalia_pci_write(az->pc, az->tag,
464 : INTEL_PCIE_NOSNOOP_REG, reg);
465 0 : break;
466 : }
467 0 : }
468 :
469 : int
470 0 : azalia_pci_match(struct device *parent, void *match, void *aux)
471 : {
472 : struct pci_attach_args *pa;
473 :
474 0 : pa = aux;
475 0 : if (PCI_CLASS(pa->pa_class) == PCI_CLASS_MULTIMEDIA
476 0 : && PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MULTIMEDIA_HDAUDIO)
477 0 : return 1;
478 0 : return 0;
479 0 : }
480 :
481 : void
482 0 : azalia_pci_attach(struct device *parent, struct device *self, void *aux)
483 : {
484 : azalia_t *sc;
485 : struct pci_attach_args *pa;
486 : pcireg_t v;
487 : uint8_t reg;
488 0 : pci_intr_handle_t ih;
489 : const char *interrupt_str;
490 :
491 0 : sc = (azalia_t*)self;
492 0 : pa = aux;
493 :
494 0 : sc->dmat = pa->pa_dmat;
495 :
496 0 : pci_set_powerstate(pa->pa_pc, pa->pa_tag, PCI_PMCSR_STATE_D0);
497 :
498 0 : v = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_PCI_HDBARL);
499 0 : v &= PCI_MAPREG_TYPE_MASK | PCI_MAPREG_MEM_TYPE_MASK;
500 0 : if (pci_mapreg_map(pa, ICH_PCI_HDBARL, v, 0,
501 0 : &sc->iot, &sc->ioh, NULL, &sc->map_size, 0)) {
502 0 : printf(": can't map device i/o space\n");
503 0 : return;
504 : }
505 :
506 0 : sc->pc = pa->pa_pc;
507 0 : sc->tag = pa->pa_tag;
508 0 : sc->pciid = pa->pa_id;
509 0 : sc->subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
510 :
511 0 : azalia_configure_pci(sc);
512 :
513 : /* disable MSI, use INTx instead */
514 0 : if (PCI_VENDOR(sc->pciid) == PCI_VENDOR_INTEL) {
515 0 : reg = azalia_pci_read(sc->pc, sc->tag, ICH_PCI_MMC);
516 0 : reg &= ~(ICH_PCI_MMC_ME);
517 0 : azalia_pci_write(sc->pc, sc->tag, ICH_PCI_MMC, reg);
518 0 : }
519 :
520 : /* interrupt */
521 0 : if (pci_intr_map_msi(pa, &ih) && pci_intr_map(pa, &ih)) {
522 0 : printf(": can't map interrupt\n");
523 0 : return;
524 : }
525 0 : interrupt_str = pci_intr_string(pa->pa_pc, ih);
526 0 : sc->ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO | IPL_MPSAFE,
527 0 : azalia_intr, sc, sc->dev.dv_xname);
528 0 : if (sc->ih == NULL) {
529 0 : printf(": can't establish interrupt");
530 0 : if (interrupt_str != NULL)
531 0 : printf(" at %s", interrupt_str);
532 0 : printf("\n");
533 0 : return;
534 : }
535 0 : printf(": %s\n", interrupt_str);
536 :
537 0 : if (azalia_init(sc, 0))
538 : goto err_exit;
539 :
540 0 : if (azalia_init_codecs(sc))
541 : goto err_exit;
542 :
543 0 : if (azalia_init_streams(sc))
544 : goto err_exit;
545 :
546 0 : audio_attach_mi(&azalia_hw_if, sc, &sc->dev);
547 :
548 0 : return;
549 :
550 : err_exit:
551 0 : sc->detached = 1;
552 0 : azalia_pci_detach(self, 0);
553 0 : }
554 :
555 : int
556 0 : azalia_pci_activate(struct device *self, int act)
557 : {
558 0 : azalia_t *sc = (azalia_t*)self;
559 : int rv = 0;
560 :
561 0 : switch (act) {
562 : case DVACT_SUSPEND:
563 0 : azalia_suspend(sc);
564 0 : break;
565 : case DVACT_POWERDOWN:
566 0 : azalia_shutdown(sc);
567 0 : break;
568 : case DVACT_RESUME:
569 0 : azalia_resume(sc);
570 0 : rv = config_activate_children(self, act);
571 0 : break;
572 : default:
573 0 : rv = config_activate_children(self, act);
574 0 : break;
575 : }
576 0 : return (rv);
577 : }
578 :
579 : int
580 0 : azalia_pci_detach(struct device *self, int flags)
581 : {
582 0 : azalia_t *az = (azalia_t*)self;
583 : uint32_t gctl;
584 : int i;
585 :
586 : DPRINTF(("%s\n", __func__));
587 :
588 : /*
589 : * this function is called if the device could not be supported,
590 : * in which case az->detached == 1. check if this function has
591 : * already cleaned up.
592 : */
593 0 : if (az->detached > 1)
594 0 : return 0;
595 :
596 0 : config_detach_children(self, flags);
597 :
598 : /* disable unsolicited responses if soft detaching */
599 0 : if (az->detached == 1) {
600 0 : gctl = AZ_READ_4(az, GCTL);
601 0 : AZ_WRITE_4(az, GCTL, gctl &~(HDA_GCTL_UNSOL));
602 0 : }
603 :
604 0 : timeout_del(&az->unsol_to);
605 :
606 : DPRINTF(("%s: delete streams\n", __func__));
607 0 : if (az->rstream.bdlist.addr != NULL)
608 0 : azalia_free_dmamem(az, &az->rstream.bdlist);
609 0 : if (az->pstream.bdlist.addr != NULL)
610 0 : azalia_free_dmamem(az, &az->pstream.bdlist);
611 :
612 : DPRINTF(("%s: delete codecs\n", __func__));
613 0 : for (i = 0; i < az->ncodecs; i++) {
614 0 : azalia_codec_delete(&az->codecs[i]);
615 : }
616 0 : az->ncodecs = 0;
617 0 : if (az->codecs != NULL) {
618 0 : free(az->codecs, M_DEVBUF, 0);
619 0 : az->codecs = NULL;
620 0 : }
621 :
622 : DPRINTF(("%s: delete CORB and RIRB\n", __func__));
623 0 : if (az->corb_dma.addr != NULL)
624 0 : azalia_free_dmamem(az, &az->corb_dma);
625 0 : if (az->rirb_dma.addr != NULL)
626 0 : azalia_free_dmamem(az, &az->rirb_dma);
627 0 : if (az->unsolq != NULL) {
628 0 : free(az->unsolq, M_DEVBUF, 0);
629 0 : az->unsolq = NULL;
630 0 : }
631 :
632 : /* disable interrupts if soft detaching */
633 0 : if (az->detached == 1) {
634 : DPRINTF(("%s: disable interrupts\n", __func__));
635 0 : AZ_WRITE_4(az, INTCTL, 0);
636 :
637 : DPRINTF(("%s: clear interrupts\n", __func__));
638 0 : AZ_WRITE_4(az, INTSTS, HDA_INTSTS_CIS | HDA_INTSTS_GIS);
639 0 : AZ_WRITE_2(az, STATESTS, HDA_STATESTS_SDIWAKE);
640 0 : AZ_WRITE_1(az, RIRBSTS, HDA_RIRBSTS_RINTFL | HDA_RIRBSTS_RIRBOIS);
641 0 : }
642 :
643 : DPRINTF(("%s: delete PCI resources\n", __func__));
644 0 : if (az->ih != NULL) {
645 0 : pci_intr_disestablish(az->pc, az->ih);
646 0 : az->ih = NULL;
647 0 : }
648 0 : if (az->map_size != 0) {
649 0 : bus_space_unmap(az->iot, az->ioh, az->map_size);
650 0 : az->map_size = 0;
651 0 : }
652 :
653 0 : az->detached = 2;
654 0 : return 0;
655 0 : }
656 :
657 : int
658 0 : azalia_intr(void *v)
659 : {
660 0 : azalia_t *az = v;
661 : uint32_t intsts;
662 : int ret = 0;
663 :
664 0 : mtx_enter(&audio_lock);
665 0 : intsts = AZ_READ_4(az, INTSTS);
666 0 : if (intsts == 0 || intsts == 0xffffffff) {
667 0 : mtx_leave(&audio_lock);
668 0 : return (ret);
669 : }
670 :
671 0 : AZ_WRITE_4(az, INTSTS, intsts);
672 :
673 0 : if (intsts & az->pstream.intr_bit) {
674 0 : azalia_stream_intr(&az->pstream);
675 : ret = 1;
676 0 : }
677 :
678 0 : if (intsts & az->rstream.intr_bit) {
679 0 : azalia_stream_intr(&az->rstream);
680 : ret = 1;
681 0 : }
682 :
683 0 : if ((intsts & HDA_INTSTS_CIS) &&
684 0 : (AZ_READ_1(az, RIRBCTL) & HDA_RIRBCTL_RINTCTL) &&
685 0 : (AZ_READ_1(az, RIRBSTS) & HDA_RIRBSTS_RINTFL)) {
686 0 : azalia_rirb_intr(az);
687 : ret = 1;
688 0 : }
689 0 : mtx_leave(&audio_lock);
690 0 : return (ret);
691 0 : }
692 :
693 : void
694 0 : azalia_shutdown(void *v)
695 : {
696 0 : azalia_t *az = (azalia_t *)v;
697 : uint32_t gctl;
698 :
699 : /* disable unsolicited response */
700 0 : gctl = AZ_READ_4(az, GCTL);
701 0 : AZ_WRITE_4(az, GCTL, gctl & ~(HDA_GCTL_UNSOL));
702 :
703 0 : timeout_del(&az->unsol_to);
704 :
705 : /* halt CORB/RIRB */
706 0 : azalia_halt_corb(az);
707 0 : azalia_halt_rirb(az);
708 0 : }
709 :
710 : /* ================================================================
711 : * HDA controller functions
712 : * ================================================================ */
713 :
714 : void
715 0 : azalia_print_codec(codec_t *codec)
716 : {
717 : const char *vendor;
718 :
719 0 : if (codec->name == NULL) {
720 0 : vendor = pci_findvendor(codec->vid >> 16);
721 0 : if (vendor == NULL)
722 0 : printf("0x%04x/0x%04x",
723 0 : codec->vid >> 16, codec->vid & 0xffff);
724 : else
725 0 : printf("%s/0x%04x", vendor, codec->vid & 0xffff);
726 : } else
727 0 : printf("%s", codec->name);
728 0 : }
729 :
730 : int
731 0 : azalia_reset(azalia_t *az)
732 : {
733 : uint32_t gctl;
734 : int i;
735 :
736 : /* 4.2.2 Starting the High Definition Audio Controller */
737 : DPRINTF(("%s: resetting\n", __func__));
738 0 : gctl = AZ_READ_4(az, GCTL);
739 0 : AZ_WRITE_4(az, GCTL, gctl & ~HDA_GCTL_CRST);
740 0 : for (i = 5000; i > 0; i--) {
741 0 : DELAY(10);
742 0 : if ((AZ_READ_4(az, GCTL) & HDA_GCTL_CRST) == 0)
743 : break;
744 : }
745 : DPRINTF(("%s: reset counter = %d\n", __func__, i));
746 0 : if (i == 0) {
747 : DPRINTF(("%s: reset failure\n", XNAME(az)));
748 0 : return(ETIMEDOUT);
749 : }
750 0 : DELAY(1000);
751 0 : gctl = AZ_READ_4(az, GCTL);
752 0 : AZ_WRITE_4(az, GCTL, gctl | HDA_GCTL_CRST);
753 0 : for (i = 5000; i > 0; i--) {
754 0 : DELAY(10);
755 0 : if (AZ_READ_4(az, GCTL) & HDA_GCTL_CRST)
756 : break;
757 : }
758 : DPRINTF(("%s: reset counter = %d\n", __func__, i));
759 0 : if (i == 0) {
760 : DPRINTF(("%s: reset-exit failure\n", XNAME(az)));
761 0 : return(ETIMEDOUT);
762 : }
763 0 : DELAY(1000);
764 :
765 0 : return(0);
766 0 : }
767 :
768 : int
769 0 : azalia_get_ctrlr_caps(azalia_t *az)
770 : {
771 : int i, n;
772 : uint16_t gcap;
773 : uint16_t statests;
774 : uint8_t cap;
775 :
776 : DPRINTF(("%s: host: High Definition Audio rev. %d.%d\n",
777 : XNAME(az), AZ_READ_1(az, VMAJ), AZ_READ_1(az, VMIN)));
778 0 : gcap = AZ_READ_2(az, GCAP);
779 0 : az->nistreams = HDA_GCAP_ISS(gcap);
780 0 : az->nostreams = HDA_GCAP_OSS(gcap);
781 0 : az->nbstreams = HDA_GCAP_BSS(gcap);
782 0 : az->ok64 = (gcap & HDA_GCAP_64OK) != 0;
783 : DPRINTF(("%s: host: %d output, %d input, and %d bidi streams\n",
784 : XNAME(az), az->nostreams, az->nistreams, az->nbstreams));
785 :
786 : /* 4.3 Codec discovery */
787 0 : statests = AZ_READ_2(az, STATESTS);
788 0 : for (i = 0, n = 0; i < HDA_MAX_CODECS; i++) {
789 0 : if ((statests >> i) & 1) {
790 : DPRINTF(("%s: found a codec at #%d\n", XNAME(az), i));
791 0 : n++;
792 0 : }
793 : }
794 0 : az->ncodecs = n;
795 0 : if (az->ncodecs < 1) {
796 0 : printf("%s: no HD-Audio codecs\n", XNAME(az));
797 0 : return -1;
798 : }
799 0 : az->codecs = mallocarray(az->ncodecs, sizeof(codec_t), M_DEVBUF,
800 : M_NOWAIT | M_ZERO);
801 0 : if (az->codecs == NULL) {
802 0 : printf("%s: can't allocate memory for codecs\n", XNAME(az));
803 0 : return ENOMEM;
804 : }
805 0 : for (i = 0, n = 0; n < az->ncodecs; i++) {
806 0 : if ((statests >> i) & 1) {
807 0 : az->codecs[n].address = i;
808 0 : az->codecs[n++].az = az;
809 0 : }
810 : }
811 :
812 : /* determine CORB size */
813 0 : az->corbsize = AZ_READ_1(az, CORBSIZE);
814 0 : cap = az->corbsize & HDA_CORBSIZE_CORBSZCAP_MASK;
815 0 : az->corbsize &= ~HDA_CORBSIZE_CORBSIZE_MASK;
816 0 : if (cap & HDA_CORBSIZE_CORBSZCAP_256) {
817 0 : az->corb_entries = 256;
818 0 : az->corbsize |= HDA_CORBSIZE_CORBSIZE_256;
819 0 : } else if (cap & HDA_CORBSIZE_CORBSZCAP_16) {
820 0 : az->corb_entries = 16;
821 0 : az->corbsize |= HDA_CORBSIZE_CORBSIZE_16;
822 0 : } else if (cap & HDA_CORBSIZE_CORBSZCAP_2) {
823 0 : az->corb_entries = 2;
824 0 : az->corbsize |= HDA_CORBSIZE_CORBSIZE_2;
825 : } else {
826 0 : printf("%s: invalid CORBSZCAP: 0x%2x\n", XNAME(az), cap);
827 0 : return(-1);
828 : }
829 :
830 : /* determine RIRB size */
831 0 : az->rirbsize = AZ_READ_1(az, RIRBSIZE);
832 0 : cap = az->rirbsize & HDA_RIRBSIZE_RIRBSZCAP_MASK;
833 0 : az->rirbsize &= ~HDA_RIRBSIZE_RIRBSIZE_MASK;
834 0 : if (cap & HDA_RIRBSIZE_RIRBSZCAP_256) {
835 0 : az->rirb_entries = 256;
836 0 : az->rirbsize |= HDA_RIRBSIZE_RIRBSIZE_256;
837 0 : } else if (cap & HDA_RIRBSIZE_RIRBSZCAP_16) {
838 0 : az->rirb_entries = 16;
839 0 : az->rirbsize |= HDA_RIRBSIZE_RIRBSIZE_16;
840 0 : } else if (cap & HDA_RIRBSIZE_RIRBSZCAP_2) {
841 0 : az->rirb_entries = 2;
842 0 : az->rirbsize |= HDA_RIRBSIZE_RIRBSIZE_2;
843 : } else {
844 0 : printf("%s: invalid RIRBSZCAP: 0x%2x\n", XNAME(az), cap);
845 0 : return(-1);
846 : }
847 :
848 0 : return(0);
849 0 : }
850 :
851 : int
852 0 : azalia_init(azalia_t *az, int resuming)
853 : {
854 : int err;
855 :
856 0 : err = azalia_reset(az);
857 0 : if (err)
858 0 : return(err);
859 :
860 0 : if (!resuming) {
861 0 : err = azalia_get_ctrlr_caps(az);
862 0 : if (err)
863 0 : return(err);
864 : }
865 :
866 : /* clear interrupt status */
867 0 : AZ_WRITE_2(az, STATESTS, HDA_STATESTS_SDIWAKE);
868 0 : AZ_WRITE_1(az, RIRBSTS, HDA_RIRBSTS_RINTFL | HDA_RIRBSTS_RIRBOIS);
869 0 : AZ_WRITE_4(az, INTSTS, HDA_INTSTS_CIS | HDA_INTSTS_GIS);
870 0 : AZ_WRITE_4(az, DPLBASE, 0);
871 0 : AZ_WRITE_4(az, DPUBASE, 0);
872 :
873 : /* 4.4.1 Command Outbound Ring Buffer */
874 0 : err = azalia_init_corb(az, resuming);
875 0 : if (err)
876 0 : return(err);
877 :
878 : /* 4.4.2 Response Inbound Ring Buffer */
879 0 : err = azalia_init_rirb(az, resuming);
880 0 : if (err)
881 0 : return(err);
882 :
883 0 : AZ_WRITE_4(az, INTCTL,
884 : AZ_READ_4(az, INTCTL) | HDA_INTCTL_CIE | HDA_INTCTL_GIE);
885 :
886 0 : return(0);
887 0 : }
888 :
889 : int
890 0 : azalia_init_codecs(azalia_t *az)
891 : {
892 : codec_t *codec;
893 : int c, i;
894 :
895 : c = 0;
896 0 : for (i = 0; i < az->ncodecs; i++) {
897 0 : if (!azalia_codec_init(&az->codecs[i]))
898 0 : c++;
899 : }
900 0 : if (c == 0) {
901 0 : printf("%s: No codecs found\n", XNAME(az));
902 0 : return(1);
903 : }
904 :
905 : /* Use the first codec capable of analog I/O. If there are none,
906 : * use the first codec capable of digital I/O. Skip HDMI codecs.
907 : */
908 : c = -1;
909 0 : for (i = 0; i < az->ncodecs; i++) {
910 0 : codec = &az->codecs[i];
911 0 : if ((codec->audiofunc < 0) ||
912 0 : (codec->codec_type == AZ_CODEC_TYPE_HDMI))
913 : continue;
914 0 : if (codec->codec_type == AZ_CODEC_TYPE_DIGITAL) {
915 0 : if (c < 0)
916 0 : c = i;
917 : } else {
918 : c = i;
919 0 : break;
920 : }
921 : }
922 0 : az->codecno = c;
923 0 : if (az->codecno < 0) {
924 0 : printf("%s: no supported codecs\n", XNAME(az));
925 0 : return(1);
926 : }
927 :
928 0 : printf("%s: codecs: ", XNAME(az));
929 0 : for (i = 0; i < az->ncodecs; i++) {
930 0 : azalia_print_codec(&az->codecs[i]);
931 0 : if (i < az->ncodecs - 1)
932 0 : printf(", ");
933 : }
934 0 : if (az->ncodecs > 1) {
935 0 : printf(", using ");
936 0 : azalia_print_codec(&az->codecs[az->codecno]);
937 0 : }
938 0 : printf("\n");
939 :
940 : /* All codecs with audio are enabled, but only one will be used. */
941 0 : for (i = 0; i < az->ncodecs; i++) {
942 0 : codec = &az->codecs[i];
943 0 : if (i != az->codecno) {
944 0 : if (codec->audiofunc < 0)
945 : continue;
946 0 : azalia_comresp(codec, codec->audiofunc,
947 : CORB_SET_POWER_STATE, CORB_PS_D3, NULL);
948 0 : DELAY(100);
949 0 : azalia_codec_delete(codec);
950 0 : }
951 : }
952 :
953 : /* Enable unsolicited responses now that az->codecno is set. */
954 0 : AZ_WRITE_4(az, GCTL, AZ_READ_4(az, GCTL) | HDA_GCTL_UNSOL);
955 :
956 0 : return(0);
957 0 : }
958 :
959 : int
960 0 : azalia_init_streams(azalia_t *az)
961 : {
962 : int err;
963 :
964 : /* Use stream#1 and #2. Don't use stream#0. */
965 0 : err = azalia_stream_init(&az->pstream, az, az->nistreams + 0,
966 : 1, AUMODE_PLAY);
967 0 : if (err)
968 0 : return(err);
969 0 : err = azalia_stream_init(&az->rstream, az, 0, 2, AUMODE_RECORD);
970 0 : if (err)
971 0 : return(err);
972 :
973 0 : return(0);
974 0 : }
975 :
976 : int
977 0 : azalia_halt_corb(azalia_t *az)
978 : {
979 : uint8_t corbctl;
980 : codec_t *codec;
981 : int i;
982 :
983 0 : corbctl = AZ_READ_1(az, CORBCTL);
984 0 : if (corbctl & HDA_CORBCTL_CORBRUN) { /* running? */
985 : /* power off all codecs */
986 0 : for (i = 0; i < az->ncodecs; i++) {
987 0 : codec = &az->codecs[i];
988 0 : if (codec->audiofunc < 0)
989 : continue;
990 0 : azalia_comresp(codec, codec->audiofunc,
991 : CORB_SET_POWER_STATE, CORB_PS_D3, NULL);
992 0 : }
993 :
994 0 : AZ_WRITE_1(az, CORBCTL, corbctl & ~HDA_CORBCTL_CORBRUN);
995 0 : for (i = 5000; i > 0; i--) {
996 0 : DELAY(10);
997 0 : corbctl = AZ_READ_1(az, CORBCTL);
998 0 : if ((corbctl & HDA_CORBCTL_CORBRUN) == 0)
999 : break;
1000 : }
1001 0 : if (i == 0) {
1002 : DPRINTF(("%s: CORB is running\n", XNAME(az)));
1003 0 : return EBUSY;
1004 : }
1005 : }
1006 0 : return(0);
1007 0 : }
1008 :
1009 : int
1010 0 : azalia_init_corb(azalia_t *az, int resuming)
1011 : {
1012 : int err, i;
1013 : uint16_t corbrp, corbwp;
1014 : uint8_t corbctl;
1015 :
1016 0 : err = azalia_halt_corb(az);
1017 0 : if (err)
1018 0 : return(err);
1019 :
1020 0 : if (!resuming) {
1021 0 : err = azalia_alloc_dmamem(az,
1022 0 : az->corb_entries * sizeof(corb_entry_t), 128,
1023 0 : &az->corb_dma);
1024 0 : if (err) {
1025 0 : printf("%s: can't allocate CORB buffer\n", XNAME(az));
1026 0 : return(err);
1027 : }
1028 : DPRINTF(("%s: CORB allocation succeeded.\n", __func__));
1029 : }
1030 0 : timeout_set(&az->unsol_to, azalia_rirb_kick_unsol_events, az);
1031 :
1032 0 : AZ_WRITE_4(az, CORBLBASE, (uint32_t)AZALIA_DMA_DMAADDR(&az->corb_dma));
1033 0 : AZ_WRITE_4(az, CORBUBASE, PTR_UPPER32(AZALIA_DMA_DMAADDR(&az->corb_dma)));
1034 0 : AZ_WRITE_1(az, CORBSIZE, az->corbsize);
1035 :
1036 : /* reset CORBRP */
1037 0 : corbrp = AZ_READ_2(az, CORBRP);
1038 0 : AZ_WRITE_2(az, CORBRP, corbrp | HDA_CORBRP_CORBRPRST);
1039 0 : AZ_WRITE_2(az, CORBRP, corbrp & ~HDA_CORBRP_CORBRPRST);
1040 0 : for (i = 5000; i > 0; i--) {
1041 0 : DELAY(10);
1042 0 : corbrp = AZ_READ_2(az, CORBRP);
1043 0 : if ((corbrp & HDA_CORBRP_CORBRPRST) == 0)
1044 : break;
1045 : }
1046 0 : if (i == 0) {
1047 : DPRINTF(("%s: CORBRP reset failure\n", XNAME(az)));
1048 0 : return -1;
1049 : }
1050 : DPRINTF(("%s: CORBWP=%d; size=%d\n", __func__,
1051 : AZ_READ_2(az, CORBRP) & HDA_CORBRP_CORBRP, az->corb_entries));
1052 :
1053 : /* clear CORBWP */
1054 0 : corbwp = AZ_READ_2(az, CORBWP);
1055 0 : AZ_WRITE_2(az, CORBWP, corbwp & ~HDA_CORBWP_CORBWP);
1056 :
1057 : /* Run! */
1058 0 : corbctl = AZ_READ_1(az, CORBCTL);
1059 0 : AZ_WRITE_1(az, CORBCTL, corbctl | HDA_CORBCTL_CORBRUN);
1060 0 : return 0;
1061 0 : }
1062 :
1063 : int
1064 0 : azalia_halt_rirb(azalia_t *az)
1065 : {
1066 : int i;
1067 : uint8_t rirbctl;
1068 :
1069 0 : rirbctl = AZ_READ_1(az, RIRBCTL);
1070 0 : if (rirbctl & HDA_RIRBCTL_RIRBDMAEN) { /* running? */
1071 0 : AZ_WRITE_1(az, RIRBCTL, rirbctl & ~HDA_RIRBCTL_RIRBDMAEN);
1072 0 : for (i = 5000; i > 0; i--) {
1073 0 : DELAY(10);
1074 0 : rirbctl = AZ_READ_1(az, RIRBCTL);
1075 0 : if ((rirbctl & HDA_RIRBCTL_RIRBDMAEN) == 0)
1076 : break;
1077 : }
1078 0 : if (i == 0) {
1079 : DPRINTF(("%s: RIRB is running\n", XNAME(az)));
1080 0 : return(EBUSY);
1081 : }
1082 : }
1083 0 : return(0);
1084 0 : }
1085 :
1086 : int
1087 0 : azalia_init_rirb(azalia_t *az, int resuming)
1088 : {
1089 : int err, i;
1090 : uint16_t rirbwp;
1091 : uint8_t rirbctl;
1092 :
1093 0 : err = azalia_halt_rirb(az);
1094 0 : if (err)
1095 0 : return(err);
1096 :
1097 0 : if (!resuming) {
1098 0 : err = azalia_alloc_dmamem(az,
1099 0 : az->rirb_entries * sizeof(rirb_entry_t), 128,
1100 0 : &az->rirb_dma);
1101 0 : if (err) {
1102 0 : printf("%s: can't allocate RIRB buffer\n", XNAME(az));
1103 0 : return err;
1104 : }
1105 : DPRINTF(("%s: RIRB allocation succeeded.\n", __func__));
1106 :
1107 : /* setup the unsolicited response queue */
1108 0 : az->unsolq = malloc(sizeof(rirb_entry_t) * UNSOLQ_SIZE,
1109 : M_DEVBUF, M_NOWAIT | M_ZERO);
1110 0 : if (az->unsolq == NULL) {
1111 : DPRINTF(("%s: can't allocate unsolicited response queue.\n",
1112 : XNAME(az)));
1113 0 : azalia_free_dmamem(az, &az->rirb_dma);
1114 0 : return ENOMEM;
1115 : }
1116 : }
1117 0 : AZ_WRITE_4(az, RIRBLBASE, (uint32_t)AZALIA_DMA_DMAADDR(&az->rirb_dma));
1118 0 : AZ_WRITE_4(az, RIRBUBASE, PTR_UPPER32(AZALIA_DMA_DMAADDR(&az->rirb_dma)));
1119 0 : AZ_WRITE_1(az, RIRBSIZE, az->rirbsize);
1120 :
1121 : /* reset the write pointer */
1122 0 : rirbwp = AZ_READ_2(az, RIRBWP);
1123 0 : AZ_WRITE_2(az, RIRBWP, rirbwp | HDA_RIRBWP_RIRBWPRST);
1124 :
1125 : /* clear the read pointer */
1126 0 : az->rirb_rp = AZ_READ_2(az, RIRBWP) & HDA_RIRBWP_RIRBWP;
1127 : DPRINTF(("%s: RIRBRP=%d, size=%d\n", __func__, az->rirb_rp,
1128 : az->rirb_entries));
1129 :
1130 0 : az->unsolq_rp = 0;
1131 0 : az->unsolq_wp = 0;
1132 0 : az->unsolq_kick = 0;
1133 :
1134 0 : AZ_WRITE_2(az, RINTCNT, 1);
1135 :
1136 : /* Run! */
1137 0 : rirbctl = AZ_READ_1(az, RIRBCTL);
1138 0 : AZ_WRITE_1(az, RIRBCTL, rirbctl |
1139 : HDA_RIRBCTL_RIRBDMAEN | HDA_RIRBCTL_RINTCTL);
1140 0 : for (i = 5000; i > 0; i--) {
1141 0 : DELAY(10);
1142 0 : rirbctl = AZ_READ_1(az, RIRBCTL);
1143 0 : if (rirbctl & HDA_RIRBCTL_RIRBDMAEN)
1144 : break;
1145 : }
1146 0 : if (i == 0) {
1147 : DPRINTF(("%s: RIRB is not running\n", XNAME(az)));
1148 0 : return(EBUSY);
1149 : }
1150 :
1151 0 : return (0);
1152 0 : }
1153 :
1154 : int
1155 0 : azalia_comresp(const codec_t *codec, nid_t nid, uint32_t control,
1156 : uint32_t param, uint32_t* result)
1157 : {
1158 : int err;
1159 :
1160 0 : mtx_enter(&audio_lock);
1161 0 : err = azalia_set_command(codec->az, codec->address, nid, control,
1162 : param);
1163 0 : if (err)
1164 : goto exit;
1165 0 : err = azalia_get_response(codec->az, result);
1166 : exit:
1167 0 : mtx_leave(&audio_lock);
1168 0 : return(err);
1169 : }
1170 :
1171 : int
1172 0 : azalia_set_command(azalia_t *az, int caddr, nid_t nid, uint32_t control,
1173 : uint32_t param)
1174 : {
1175 : corb_entry_t *corb;
1176 : int wp;
1177 : uint32_t verb;
1178 : uint16_t corbwp;
1179 :
1180 0 : if ((AZ_READ_1(az, CORBCTL) & HDA_CORBCTL_CORBRUN) == 0) {
1181 0 : printf("%s: CORB is not running.\n", XNAME(az));
1182 0 : return(-1);
1183 : }
1184 0 : verb = (caddr << 28) | (nid << 20) | (control << 8) | param;
1185 0 : corbwp = AZ_READ_2(az, CORBWP);
1186 0 : wp = corbwp & HDA_CORBWP_CORBWP;
1187 0 : corb = (corb_entry_t*)az->corb_dma.addr;
1188 0 : if (++wp >= az->corb_entries)
1189 : wp = 0;
1190 0 : corb[wp] = verb;
1191 :
1192 0 : AZ_WRITE_2(az, CORBWP, (corbwp & ~HDA_CORBWP_CORBWP) | wp);
1193 :
1194 0 : return(0);
1195 0 : }
1196 :
1197 : int
1198 0 : azalia_get_response(azalia_t *az, uint32_t *result)
1199 : {
1200 : const rirb_entry_t *rirb;
1201 : int i;
1202 : uint16_t wp;
1203 :
1204 0 : if ((AZ_READ_1(az, RIRBCTL) & HDA_RIRBCTL_RIRBDMAEN) == 0) {
1205 0 : printf("%s: RIRB is not running.\n", XNAME(az));
1206 0 : return(-1);
1207 : }
1208 :
1209 0 : rirb = (rirb_entry_t*)az->rirb_dma.addr;
1210 : i = 5000;
1211 0 : for (;;) {
1212 0 : while (i > 0) {
1213 0 : wp = AZ_READ_2(az, RIRBWP) & HDA_RIRBWP_RIRBWP;
1214 0 : if (az->rirb_rp != wp)
1215 : break;
1216 0 : DELAY(10);
1217 0 : i--;
1218 : }
1219 0 : if (i == 0) {
1220 : DPRINTF(("%s: RIRB time out\n", XNAME(az)));
1221 0 : return(ETIMEDOUT);
1222 : }
1223 0 : if (++az->rirb_rp >= az->rirb_entries)
1224 0 : az->rirb_rp = 0;
1225 0 : if (rirb[az->rirb_rp].resp_ex & RIRB_RESP_UNSOL) {
1226 0 : az->unsolq[az->unsolq_wp].resp = rirb[az->rirb_rp].resp;
1227 0 : az->unsolq[az->unsolq_wp++].resp_ex = rirb[az->rirb_rp].resp_ex;
1228 0 : az->unsolq_wp %= UNSOLQ_SIZE;
1229 : } else
1230 : break;
1231 : }
1232 0 : if (result != NULL)
1233 0 : *result = rirb[az->rirb_rp].resp;
1234 :
1235 0 : return(0);
1236 0 : }
1237 :
1238 : void
1239 0 : azalia_rirb_kick_unsol_events(void *v)
1240 : {
1241 0 : azalia_t *az = v;
1242 : int addr, tag;
1243 :
1244 0 : if (az->unsolq_kick)
1245 0 : return;
1246 0 : az->unsolq_kick = 1;
1247 0 : while (az->unsolq_rp != az->unsolq_wp) {
1248 0 : addr = RIRB_RESP_CODEC(az->unsolq[az->unsolq_rp].resp_ex);
1249 0 : tag = RIRB_UNSOL_TAG(az->unsolq[az->unsolq_rp].resp);
1250 : DPRINTF(("%s: codec address=%d tag=%d\n", __func__, addr, tag));
1251 :
1252 0 : az->unsolq_rp++;
1253 0 : az->unsolq_rp %= UNSOLQ_SIZE;
1254 :
1255 : /* We only care about events on the using codec. */
1256 0 : if (az->codecs[az->codecno].address == addr)
1257 0 : azalia_unsol_event(&az->codecs[az->codecno], tag);
1258 : }
1259 0 : az->unsolq_kick = 0;
1260 0 : }
1261 :
1262 : void
1263 0 : azalia_rirb_intr(azalia_t *az)
1264 : {
1265 : const rirb_entry_t *rirb;
1266 : uint16_t wp;
1267 : uint8_t rirbsts;
1268 :
1269 0 : rirbsts = AZ_READ_1(az, RIRBSTS);
1270 :
1271 0 : wp = AZ_READ_2(az, RIRBWP) & HDA_RIRBWP_RIRBWP;
1272 0 : rirb = (rirb_entry_t*)az->rirb_dma.addr;
1273 0 : while (az->rirb_rp != wp) {
1274 0 : if (++az->rirb_rp >= az->rirb_entries)
1275 0 : az->rirb_rp = 0;
1276 0 : if (rirb[az->rirb_rp].resp_ex & RIRB_RESP_UNSOL) {
1277 0 : az->unsolq[az->unsolq_wp].resp = rirb[az->rirb_rp].resp;
1278 0 : az->unsolq[az->unsolq_wp++].resp_ex = rirb[az->rirb_rp].resp_ex;
1279 0 : az->unsolq_wp %= UNSOLQ_SIZE;
1280 0 : } else {
1281 : DPRINTF(("%s: dropped solicited response\n", __func__));
1282 : }
1283 : }
1284 0 : timeout_add_msec(&az->unsol_to, 1);
1285 :
1286 0 : AZ_WRITE_1(az, RIRBSTS,
1287 : rirbsts | HDA_RIRBSTS_RIRBOIS | HDA_RIRBSTS_RINTFL);
1288 0 : }
1289 :
1290 : int
1291 0 : azalia_alloc_dmamem(azalia_t *az, size_t size, size_t align, azalia_dma_t *d)
1292 : {
1293 : int err;
1294 0 : int nsegs;
1295 :
1296 0 : d->size = size;
1297 0 : err = bus_dmamem_alloc(az->dmat, size, align, 0, d->segments, 1,
1298 : &nsegs, BUS_DMA_NOWAIT);
1299 0 : if (err)
1300 0 : return err;
1301 0 : if (nsegs != 1)
1302 : goto free;
1303 0 : err = bus_dmamem_map(az->dmat, d->segments, 1, size,
1304 : &d->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
1305 0 : if (err)
1306 : goto free;
1307 0 : err = bus_dmamap_create(az->dmat, size, 1, size, 0,
1308 : BUS_DMA_NOWAIT, &d->map);
1309 0 : if (err)
1310 : goto unmap;
1311 0 : err = bus_dmamap_load(az->dmat, d->map, d->addr, size,
1312 : NULL, BUS_DMA_NOWAIT);
1313 0 : if (err)
1314 : goto destroy;
1315 :
1316 0 : if (!az->ok64 && PTR_UPPER32(AZALIA_DMA_DMAADDR(d)) != 0) {
1317 0 : azalia_free_dmamem(az, d);
1318 0 : return -1;
1319 : }
1320 0 : return 0;
1321 :
1322 : destroy:
1323 0 : bus_dmamap_destroy(az->dmat, d->map);
1324 : unmap:
1325 0 : bus_dmamem_unmap(az->dmat, d->addr, size);
1326 : free:
1327 0 : bus_dmamem_free(az->dmat, d->segments, 1);
1328 0 : d->addr = NULL;
1329 0 : return err;
1330 0 : }
1331 :
1332 : void
1333 0 : azalia_free_dmamem(const azalia_t *az, azalia_dma_t* d)
1334 : {
1335 0 : if (d->addr == NULL)
1336 : return;
1337 0 : bus_dmamap_unload(az->dmat, d->map);
1338 0 : bus_dmamap_destroy(az->dmat, d->map);
1339 0 : bus_dmamem_unmap(az->dmat, d->addr, d->size);
1340 0 : bus_dmamem_free(az->dmat, d->segments, 1);
1341 0 : d->addr = NULL;
1342 0 : }
1343 :
1344 : int
1345 0 : azalia_suspend(azalia_t *az)
1346 : {
1347 : int err;
1348 :
1349 0 : if (az->detached)
1350 0 : return 0;
1351 :
1352 : /* disable unsolicited responses */
1353 0 : AZ_WRITE_4(az, GCTL, AZ_READ_4(az, GCTL) & ~HDA_GCTL_UNSOL);
1354 :
1355 0 : timeout_del(&az->unsol_to);
1356 :
1357 : /* azalia_halt_{corb,rirb}() only fail if the {CORB,RIRB} can't
1358 : * be stopped and azalia_init_{corb,rirb}(), which starts the
1359 : * {CORB,RIRB}, first calls azalia_halt_{corb,rirb}(). If halt
1360 : * fails, don't try to restart.
1361 : */
1362 0 : err = azalia_halt_corb(az);
1363 0 : if (err)
1364 : goto corb_fail;
1365 :
1366 0 : err = azalia_halt_rirb(az);
1367 0 : if (err)
1368 : goto rirb_fail;
1369 :
1370 : /* stop interrupts and clear status registers */
1371 0 : AZ_WRITE_4(az, INTCTL, 0);
1372 0 : AZ_WRITE_4(az, INTSTS, HDA_INTSTS_CIS | HDA_INTSTS_GIS);
1373 0 : AZ_WRITE_2(az, STATESTS, HDA_STATESTS_SDIWAKE);
1374 0 : AZ_WRITE_1(az, RIRBSTS, HDA_RIRBSTS_RINTFL | HDA_RIRBSTS_RIRBOIS);
1375 :
1376 0 : return 0;
1377 :
1378 : rirb_fail:
1379 0 : azalia_init_corb(az, 1);
1380 : corb_fail:
1381 0 : AZ_WRITE_4(az, GCTL, AZ_READ_4(az, GCTL) | HDA_GCTL_UNSOL);
1382 :
1383 0 : return err;
1384 0 : }
1385 :
1386 : int
1387 0 : azalia_resume_codec(codec_t *this)
1388 : {
1389 : widget_t *w;
1390 0 : uint32_t result;
1391 : int i, err;
1392 :
1393 0 : err = azalia_comresp(this, this->audiofunc, CORB_SET_POWER_STATE,
1394 : CORB_PS_D0, &result);
1395 : if (err) {
1396 : DPRINTF(("%s: power audio func error: result=0x%8.8x\n",
1397 : __func__, result));
1398 : }
1399 0 : DELAY(100);
1400 :
1401 0 : FOR_EACH_WIDGET(this, i) {
1402 0 : w = &this->w[i];
1403 0 : if (w->widgetcap & COP_AWCAP_POWER) {
1404 0 : azalia_comresp(this, w->nid, CORB_SET_POWER_STATE,
1405 : CORB_PS_D0, &result);
1406 0 : DELAY(100);
1407 0 : }
1408 0 : if (w->type == COP_AWTYPE_PIN_COMPLEX)
1409 0 : azalia_widget_init_pin(w, this);
1410 0 : if (this->qrks & AZ_QRK_WID_MASK)
1411 0 : azalia_codec_widget_quirks(this, w->nid);
1412 : }
1413 :
1414 0 : if (this->qrks & AZ_QRK_GPIO_MASK) {
1415 0 : err = azalia_codec_gpio_quirks(this);
1416 0 : if (err)
1417 0 : return err;
1418 : }
1419 :
1420 0 : return(0);
1421 0 : }
1422 :
1423 : int
1424 0 : azalia_resume(azalia_t *az)
1425 : {
1426 : int err;
1427 :
1428 0 : if (az->detached)
1429 0 : return 0;
1430 :
1431 0 : azalia_configure_pci(az);
1432 :
1433 : /* is this necessary? */
1434 0 : pci_conf_write(az->pc, az->tag, PCI_SUBSYS_ID_REG, az->subid);
1435 :
1436 0 : err = azalia_init(az, 1);
1437 0 : if (err)
1438 0 : return err;
1439 :
1440 : /* enable unsolicited responses on the controller */
1441 0 : AZ_WRITE_4(az, GCTL, AZ_READ_4(az, GCTL) | HDA_GCTL_UNSOL);
1442 :
1443 0 : err = azalia_resume_codec(&az->codecs[az->codecno]);
1444 0 : if (err)
1445 0 : return err;
1446 :
1447 0 : err = azalia_codec_enable_unsol(&az->codecs[az->codecno]);
1448 0 : if (err)
1449 0 : return err;
1450 :
1451 0 : return 0;
1452 0 : }
1453 :
1454 : /* ================================================================
1455 : * HDA codec functions
1456 : * ================================================================ */
1457 :
1458 : int
1459 0 : azalia_codec_init(codec_t *this)
1460 : {
1461 : widget_t *w;
1462 0 : uint32_t rev, id, result;
1463 : int err, addr, n, i, nspdif, nhdmi;
1464 :
1465 0 : addr = this->address;
1466 : /* codec vendor/device/revision */
1467 0 : err = azalia_comresp(this, CORB_NID_ROOT, CORB_GET_PARAMETER,
1468 : COP_REVISION_ID, &rev);
1469 0 : if (err)
1470 0 : return err;
1471 0 : err = azalia_comresp(this, CORB_NID_ROOT, CORB_GET_PARAMETER,
1472 : COP_VENDOR_ID, &id);
1473 0 : if (err)
1474 0 : return err;
1475 0 : this->vid = id;
1476 0 : this->subid = this->az->subid;
1477 0 : azalia_codec_init_vtbl(this);
1478 : DPRINTF(("%s: codec[%d] vid 0x%8.8x, subid 0x%8.8x, rev. %u.%u,",
1479 : XNAME(this->az), addr, this->vid, this->subid,
1480 : COP_RID_REVISION(rev), COP_RID_STEPPING(rev)));
1481 : DPRINTF((" HDA version %u.%u\n",
1482 : COP_RID_MAJ(rev), COP_RID_MIN(rev)));
1483 :
1484 : /* identify function nodes */
1485 0 : err = azalia_comresp(this, CORB_NID_ROOT, CORB_GET_PARAMETER,
1486 : COP_SUBORDINATE_NODE_COUNT, &result);
1487 0 : if (err)
1488 0 : return err;
1489 0 : this->nfunctions = COP_NSUBNODES(result);
1490 0 : if (COP_NSUBNODES(result) <= 0) {
1491 : DPRINTF(("%s: codec[%d]: No function groups\n",
1492 : XNAME(this->az), addr));
1493 0 : return -1;
1494 : }
1495 : /* iterate function nodes and find an audio function */
1496 0 : n = COP_START_NID(result);
1497 : DPRINTF(("%s: nidstart=%d #functions=%d\n",
1498 : XNAME(this->az), n, this->nfunctions));
1499 0 : this->audiofunc = -1;
1500 0 : for (i = 0; i < this->nfunctions; i++) {
1501 0 : err = azalia_comresp(this, n + i, CORB_GET_PARAMETER,
1502 : COP_FUNCTION_GROUP_TYPE, &result);
1503 0 : if (err)
1504 : continue;
1505 : DPRINTF(("%s: FTYPE result = 0x%8.8x\n", __func__, result));
1506 0 : if (COP_FTYPE(result) == COP_FTYPE_AUDIO) {
1507 0 : this->audiofunc = n + i;
1508 0 : break; /* XXX multiple audio functions? */
1509 : }
1510 : }
1511 0 : if (this->audiofunc < 0) {
1512 : DPRINTF(("%s: codec[%d]: No audio function groups\n",
1513 : XNAME(this->az), addr));
1514 0 : return -1;
1515 : }
1516 :
1517 : /* power the audio function */
1518 0 : azalia_comresp(this, this->audiofunc, CORB_SET_POWER_STATE,
1519 : CORB_PS_D0, &result);
1520 0 : DELAY(100);
1521 :
1522 : /* check widgets in the audio function */
1523 0 : err = azalia_comresp(this, this->audiofunc, CORB_GET_PARAMETER,
1524 : COP_SUBORDINATE_NODE_COUNT, &result);
1525 0 : if (err)
1526 0 : return err;
1527 : DPRINTF(("%s: There are %d widgets in the audio function.\n",
1528 : __func__, COP_NSUBNODES(result)));
1529 0 : this->wstart = COP_START_NID(result);
1530 0 : if (this->wstart < 2) {
1531 0 : printf("%s: invalid node structure\n", XNAME(this->az));
1532 0 : return -1;
1533 : }
1534 0 : this->wend = this->wstart + COP_NSUBNODES(result);
1535 0 : this->w = mallocarray(this->wend, sizeof(widget_t), M_DEVBUF,
1536 : M_NOWAIT | M_ZERO);
1537 0 : if (this->w == NULL) {
1538 0 : printf("%s: out of memory\n", XNAME(this->az));
1539 0 : return ENOMEM;
1540 : }
1541 :
1542 : /* query the base parameters */
1543 0 : azalia_comresp(this, this->audiofunc, CORB_GET_PARAMETER,
1544 : COP_STREAM_FORMATS, &result);
1545 0 : this->w[this->audiofunc].d.audio.encodings = result;
1546 0 : azalia_comresp(this, this->audiofunc, CORB_GET_PARAMETER,
1547 : COP_PCM, &result);
1548 0 : this->w[this->audiofunc].d.audio.bits_rates = result;
1549 0 : azalia_comresp(this, this->audiofunc, CORB_GET_PARAMETER,
1550 : COP_INPUT_AMPCAP, &result);
1551 0 : this->w[this->audiofunc].inamp_cap = result;
1552 0 : azalia_comresp(this, this->audiofunc, CORB_GET_PARAMETER,
1553 : COP_OUTPUT_AMPCAP, &result);
1554 0 : this->w[this->audiofunc].outamp_cap = result;
1555 :
1556 0 : azalia_codec_print_audiofunc(this);
1557 :
1558 0 : strlcpy(this->w[CORB_NID_ROOT].name, "root",
1559 : sizeof(this->w[CORB_NID_ROOT].name));
1560 0 : strlcpy(this->w[this->audiofunc].name, "hdaudio",
1561 : sizeof(this->w[this->audiofunc].name));
1562 0 : this->w[this->audiofunc].enable = 1;
1563 :
1564 0 : FOR_EACH_WIDGET(this, i) {
1565 0 : w = &this->w[i];
1566 0 : err = azalia_widget_init(w, this, i);
1567 0 : if (err)
1568 0 : return err;
1569 0 : err = azalia_widget_init_connection(w, this);
1570 0 : if (err)
1571 0 : return err;
1572 :
1573 0 : azalia_widget_print_widget(w, this);
1574 :
1575 0 : if (this->qrks & AZ_QRK_WID_MASK) {
1576 0 : azalia_codec_widget_quirks(this, i);
1577 0 : }
1578 : }
1579 :
1580 0 : this->na_dacs = this->na_dacs_d = 0;
1581 0 : this->na_adcs = this->na_adcs_d = 0;
1582 0 : this->speaker = this->speaker2 = this->spkr_dac =
1583 0 : this->fhp = this->fhp_dac =
1584 0 : this->mic = this->mic_adc = -1;
1585 0 : this->nsense_pins = 0;
1586 0 : this->nout_jacks = 0;
1587 : nspdif = nhdmi = 0;
1588 0 : FOR_EACH_WIDGET(this, i) {
1589 0 : w = &this->w[i];
1590 :
1591 0 : if (!w->enable)
1592 : continue;
1593 :
1594 0 : switch (w->type) {
1595 :
1596 : case COP_AWTYPE_AUDIO_MIXER:
1597 : case COP_AWTYPE_AUDIO_SELECTOR:
1598 0 : if (!azalia_widget_check_conn(this, i, 0))
1599 0 : w->enable = 0;
1600 : break;
1601 :
1602 : case COP_AWTYPE_AUDIO_OUTPUT:
1603 0 : if ((w->widgetcap & COP_AWCAP_DIGITAL) == 0) {
1604 0 : if (this->na_dacs < HDA_MAX_CHANNELS)
1605 0 : this->a_dacs[this->na_dacs++] = i;
1606 : } else {
1607 0 : if (this->na_dacs_d < HDA_MAX_CHANNELS)
1608 0 : this->a_dacs_d[this->na_dacs_d++] = i;
1609 : }
1610 : break;
1611 :
1612 : case COP_AWTYPE_AUDIO_INPUT:
1613 0 : if ((w->widgetcap & COP_AWCAP_DIGITAL) == 0) {
1614 0 : if (this->na_adcs < HDA_MAX_CHANNELS)
1615 0 : this->a_adcs[this->na_adcs++] = i;
1616 : } else {
1617 0 : if (this->na_adcs_d < HDA_MAX_CHANNELS)
1618 0 : this->a_adcs_d[this->na_adcs_d++] = i;
1619 : }
1620 : break;
1621 :
1622 : case COP_AWTYPE_PIN_COMPLEX:
1623 0 : switch (CORB_CD_PORT(w->d.pin.config)) {
1624 : case CORB_CD_FIXED:
1625 0 : switch (w->d.pin.device) {
1626 : case CORB_CD_SPEAKER:
1627 0 : if (this->speaker == -1) {
1628 0 : this->speaker = i;
1629 0 : } else if (w->d.pin.association <
1630 0 : this->w[this->speaker].d.pin.association ||
1631 0 : (w->d.pin.association ==
1632 0 : this->w[this->speaker].d.pin.association &&
1633 0 : w->d.pin.sequence <
1634 0 : this->w[this->speaker].d.pin.sequence)) {
1635 0 : this->speaker2 = this->speaker;
1636 0 : this->speaker = i;
1637 0 : } else {
1638 0 : this->speaker2 = i;
1639 : }
1640 0 : if (this->speaker == i)
1641 0 : this->spkr_dac =
1642 0 : azalia_codec_find_defdac(this, i, 0);
1643 : break;
1644 : case CORB_CD_MICIN:
1645 0 : this->mic = i;
1646 0 : this->mic_adc =
1647 0 : azalia_codec_find_defadc(this, i, 0);
1648 0 : break;
1649 : }
1650 : break;
1651 : case CORB_CD_JACK:
1652 0 : if (w->d.pin.device == CORB_CD_LINEOUT)
1653 0 : this->nout_jacks++;
1654 0 : else if (w->d.pin.device == CORB_CD_HEADPHONE &&
1655 0 : CORB_CD_LOC_GEO(w->d.pin.config) ==
1656 : CORB_CD_FRONT) {
1657 0 : this->fhp = i;
1658 0 : this->fhp_dac =
1659 0 : azalia_codec_find_defdac(this, i, 0);
1660 0 : }
1661 0 : if (this->nsense_pins >= HDA_MAX_SENSE_PINS ||
1662 0 : !(w->d.pin.cap & COP_PINCAP_PRESENCE))
1663 : break;
1664 : /* check override bit */
1665 0 : err = azalia_comresp(this, i,
1666 : CORB_GET_CONFIGURATION_DEFAULT, 0, &result);
1667 0 : if (err)
1668 : break;
1669 0 : if (!(CORB_CD_MISC(result) & CORB_CD_PRESENCEOV)) {
1670 0 : this->sense_pins[this->nsense_pins++] = i;
1671 0 : }
1672 : break;
1673 : }
1674 0 : if ((w->d.pin.device == CORB_CD_DIGITALOUT) &&
1675 0 : (w->d.pin.cap & COP_PINCAP_HDMI))
1676 0 : nhdmi++;
1677 0 : else if (w->d.pin.device == CORB_CD_SPDIFOUT ||
1678 0 : w->d.pin.device == CORB_CD_SPDIFIN)
1679 0 : nspdif++;
1680 : break;
1681 : }
1682 : }
1683 0 : this->codec_type = AZ_CODEC_TYPE_ANALOG;
1684 0 : if ((this->na_dacs == 0) && (this->na_adcs == 0)) {
1685 0 : this->codec_type = AZ_CODEC_TYPE_DIGITAL;
1686 0 : if (nspdif == 0 && nhdmi > 0)
1687 0 : this->codec_type = AZ_CODEC_TYPE_HDMI;
1688 : }
1689 :
1690 : /* make sure built-in mic is connected to an adc */
1691 0 : if (this->mic != -1 && this->mic_adc == -1) {
1692 0 : if (azalia_codec_select_micadc(this)) {
1693 : DPRINTF(("%s: cound not select mic adc\n", __func__));
1694 : }
1695 0 : }
1696 :
1697 0 : err = azalia_codec_sort_pins(this);
1698 0 : if (err)
1699 0 : return err;
1700 :
1701 0 : err = azalia_codec_find_inputmixer(this);
1702 0 : if (err)
1703 0 : return err;
1704 :
1705 : /* If the codec can do multichannel, select different DACs for
1706 : * the multichannel jack group. Also be sure to keep track of
1707 : * which DAC the front headphone is connected to.
1708 : */
1709 0 : if (this->na_dacs >= 3 && this->nopins >= 3) {
1710 0 : err = azalia_codec_select_dacs(this);
1711 0 : if (err)
1712 0 : return err;
1713 : }
1714 :
1715 0 : err = azalia_codec_select_spkrdac(this);
1716 0 : if (err)
1717 0 : return err;
1718 :
1719 0 : err = azalia_init_dacgroup(this);
1720 0 : if (err)
1721 0 : return err;
1722 :
1723 0 : azalia_codec_print_groups(this);
1724 :
1725 0 : err = azalia_widget_label_widgets(this);
1726 0 : if (err)
1727 0 : return err;
1728 :
1729 0 : err = azalia_codec_construct_format(this, 0, 0);
1730 0 : if (err)
1731 0 : return err;
1732 :
1733 0 : err = azalia_codec_init_volgroups(this);
1734 0 : if (err)
1735 0 : return err;
1736 :
1737 0 : if (this->qrks & AZ_QRK_GPIO_MASK) {
1738 0 : err = azalia_codec_gpio_quirks(this);
1739 0 : if (err)
1740 0 : return err;
1741 : }
1742 :
1743 0 : err = azalia_mixer_init(this);
1744 0 : if (err)
1745 0 : return err;
1746 :
1747 0 : return 0;
1748 0 : }
1749 :
1750 : int
1751 0 : azalia_codec_find_inputmixer(codec_t *this)
1752 : {
1753 : widget_t *w;
1754 : int i, j;
1755 :
1756 0 : this->input_mixer = -1;
1757 :
1758 0 : FOR_EACH_WIDGET(this, i) {
1759 0 : w = &this->w[i];
1760 0 : if (w->type != COP_AWTYPE_AUDIO_MIXER)
1761 : continue;
1762 :
1763 : /* can input from a pin */
1764 0 : for (j = 0; j < this->nipins; j++) {
1765 0 : if (azalia_codec_fnode(this, this->ipins[j].nid,
1766 0 : w->nid, 0) != -1)
1767 : break;
1768 : }
1769 0 : if (j == this->nipins)
1770 : continue;
1771 :
1772 : /* can output to a pin */
1773 0 : for (j = 0; j < this->nopins; j++) {
1774 0 : if (azalia_codec_fnode(this, w->nid,
1775 0 : this->opins[j].nid, 0) != -1)
1776 : break;
1777 : }
1778 0 : if (j == this->nopins)
1779 : continue;
1780 :
1781 : /* can output to an ADC */
1782 0 : for (j = 0; j < this->na_adcs; j++) {
1783 0 : if (azalia_codec_fnode(this, w->nid,
1784 0 : this->a_adcs[j], 0) != -1)
1785 : break;
1786 : }
1787 0 : if (j == this->na_adcs)
1788 : continue;
1789 :
1790 0 : this->input_mixer = i;
1791 0 : break;
1792 : }
1793 0 : return(0);
1794 : }
1795 :
1796 : int
1797 0 : azalia_codec_select_micadc(codec_t *this)
1798 : {
1799 : widget_t *w;
1800 : int i, j, conv, err;
1801 :
1802 0 : for (i = 0; i < this->na_adcs; i++) {
1803 0 : if (azalia_codec_fnode(this, this->mic,
1804 0 : this->a_adcs[i], 0) >= 0)
1805 : break;
1806 : }
1807 0 : if (i >= this->na_adcs)
1808 0 : return(-1);
1809 0 : conv = this->a_adcs[i];
1810 :
1811 0 : w = &this->w[conv];
1812 0 : for (j = 0; j < 10; j++) {
1813 0 : for (i = 0; i < w->nconnections; i++) {
1814 0 : if (!azalia_widget_enabled(this, w->connections[i]))
1815 : continue;
1816 0 : if (azalia_codec_fnode(this, this->mic,
1817 0 : w->connections[i], j + 1) >= 0) {
1818 : break;
1819 : }
1820 : }
1821 0 : if (i >= w->nconnections)
1822 0 : return(-1);
1823 0 : err = azalia_comresp(this, w->nid,
1824 : CORB_SET_CONNECTION_SELECT_CONTROL, i, 0);
1825 0 : if (err)
1826 0 : return(err);
1827 0 : w->selected = i;
1828 0 : if (w->connections[i] == this->mic) {
1829 0 : this->mic_adc = conv;
1830 0 : return(0);
1831 : }
1832 0 : w = &this->w[w->connections[i]];
1833 : }
1834 0 : return(-1);
1835 0 : }
1836 :
1837 : int
1838 0 : azalia_codec_sort_pins(codec_t *this)
1839 : {
1840 : #define MAX_PINS 16
1841 : const widget_t *w;
1842 0 : struct io_pin opins[MAX_PINS], opins_d[MAX_PINS];
1843 0 : struct io_pin ipins[MAX_PINS], ipins_d[MAX_PINS];
1844 : int nopins, nopins_d, nipins, nipins_d;
1845 : int prio, loc, add, nd, conv;
1846 : int i, j, k;
1847 :
1848 : nopins = nopins_d = nipins = nipins_d = 0;
1849 :
1850 0 : FOR_EACH_WIDGET(this, i) {
1851 0 : w = &this->w[i];
1852 0 : if (!w->enable || w->type != COP_AWTYPE_PIN_COMPLEX)
1853 : continue;
1854 :
1855 : loc = 0;
1856 0 : if (this->na_dacs >= 3 && this->nout_jacks < 3)
1857 0 : loc = CORB_CD_LOC_GEO(w->d.pin.config);
1858 :
1859 0 : prio = w->d.pin.association << 4 | w->d.pin.sequence;
1860 : conv = -1;
1861 :
1862 : /* analog out */
1863 0 : if ((w->d.pin.cap & COP_PINCAP_OUTPUT) &&
1864 0 : !(w->widgetcap & COP_AWCAP_DIGITAL)) {
1865 : add = nd = 0;
1866 0 : conv = azalia_codec_find_defdac(this, w->nid, 0);
1867 0 : switch(w->d.pin.device) {
1868 : /* primary - output by default */
1869 : case CORB_CD_SPEAKER:
1870 0 : if (w->nid == this->speaker ||
1871 0 : w->nid == this->speaker2)
1872 : break;
1873 : /* FALLTHROUGH */
1874 : case CORB_CD_HEADPHONE:
1875 : case CORB_CD_LINEOUT:
1876 : add = 1;
1877 0 : break;
1878 : /* secondary - input by default */
1879 : case CORB_CD_MICIN:
1880 0 : if (w->nid == this->mic)
1881 : break;
1882 : /* FALLTHROUGH */
1883 : case CORB_CD_LINEIN:
1884 : add = nd = 1;
1885 0 : break;
1886 : }
1887 0 : if (add && nopins < MAX_PINS) {
1888 0 : opins[nopins].nid = w->nid;
1889 0 : opins[nopins].conv = conv;
1890 0 : prio |= (nd << 8) | (loc << 9);
1891 0 : opins[nopins].prio = prio;
1892 0 : nopins++;
1893 0 : }
1894 : }
1895 : /* digital out */
1896 0 : if ((w->d.pin.cap & COP_PINCAP_OUTPUT) &&
1897 0 : (w->widgetcap & COP_AWCAP_DIGITAL)) {
1898 0 : conv = azalia_codec_find_defdac(this, w->nid, 0);
1899 0 : switch(w->d.pin.device) {
1900 : case CORB_CD_SPDIFOUT:
1901 : case CORB_CD_DIGITALOUT:
1902 0 : if (nopins_d < MAX_PINS) {
1903 0 : opins_d[nopins_d].nid = w->nid;
1904 0 : opins_d[nopins_d].conv = conv;
1905 0 : opins_d[nopins_d].prio = prio;
1906 0 : nopins_d++;
1907 0 : }
1908 : break;
1909 : }
1910 : }
1911 : /* analog in */
1912 0 : if ((w->d.pin.cap & COP_PINCAP_INPUT) &&
1913 0 : !(w->widgetcap & COP_AWCAP_DIGITAL)) {
1914 : add = nd = 0;
1915 0 : conv = azalia_codec_find_defadc(this, w->nid, 0);
1916 0 : switch(w->d.pin.device) {
1917 : /* primary - input by default */
1918 : case CORB_CD_MICIN:
1919 : case CORB_CD_LINEIN:
1920 : add = 1;
1921 0 : break;
1922 : /* secondary - output by default */
1923 : case CORB_CD_SPEAKER:
1924 0 : if (w->nid == this->speaker ||
1925 0 : w->nid == this->speaker2)
1926 : break;
1927 : /* FALLTHROUGH */
1928 : case CORB_CD_HEADPHONE:
1929 : case CORB_CD_LINEOUT:
1930 : add = nd = 1;
1931 0 : break;
1932 : }
1933 0 : if (add && nipins < MAX_PINS) {
1934 0 : ipins[nipins].nid = w->nid;
1935 0 : ipins[nipins].prio = prio | (nd << 8);
1936 0 : ipins[nipins].conv = conv;
1937 0 : nipins++;
1938 0 : }
1939 : }
1940 : /* digital in */
1941 0 : if ((w->d.pin.cap & COP_PINCAP_INPUT) &&
1942 0 : (w->widgetcap & COP_AWCAP_DIGITAL)) {
1943 0 : conv = azalia_codec_find_defadc(this, w->nid, 0);
1944 0 : switch(w->d.pin.device) {
1945 : case CORB_CD_SPDIFIN:
1946 : case CORB_CD_DIGITALIN:
1947 : case CORB_CD_MICIN:
1948 0 : if (nipins_d < MAX_PINS) {
1949 0 : ipins_d[nipins_d].nid = w->nid;
1950 0 : ipins_d[nipins_d].prio = prio;
1951 0 : ipins_d[nipins_d].conv = conv;
1952 0 : nipins_d++;
1953 0 : }
1954 : break;
1955 : }
1956 : }
1957 : }
1958 :
1959 0 : this->opins = mallocarray(nopins, sizeof(struct io_pin), M_DEVBUF,
1960 : M_NOWAIT | M_ZERO);
1961 0 : if (this->opins == NULL)
1962 0 : return(ENOMEM);
1963 0 : this->nopins = 0;
1964 0 : for (i = 0; i < nopins; i++) {
1965 0 : for (j = 0; j < this->nopins; j++)
1966 0 : if (this->opins[j].prio > opins[i].prio)
1967 : break;
1968 0 : for (k = this->nopins; k > j; k--)
1969 0 : this->opins[k] = this->opins[k - 1];
1970 0 : if (j < nopins)
1971 0 : this->opins[j] = opins[i];
1972 0 : this->nopins++;
1973 0 : if (this->nopins == nopins)
1974 : break;
1975 : }
1976 :
1977 0 : this->opins_d = mallocarray(nopins_d, sizeof(struct io_pin), M_DEVBUF,
1978 : M_NOWAIT | M_ZERO);
1979 0 : if (this->opins_d == NULL)
1980 0 : return(ENOMEM);
1981 0 : this->nopins_d = 0;
1982 0 : for (i = 0; i < nopins_d; i++) {
1983 0 : for (j = 0; j < this->nopins_d; j++)
1984 0 : if (this->opins_d[j].prio > opins_d[i].prio)
1985 : break;
1986 0 : for (k = this->nopins_d; k > j; k--)
1987 0 : this->opins_d[k] = this->opins_d[k - 1];
1988 0 : if (j < nopins_d)
1989 0 : this->opins_d[j] = opins_d[i];
1990 0 : this->nopins_d++;
1991 0 : if (this->nopins_d == nopins_d)
1992 : break;
1993 : }
1994 :
1995 0 : this->ipins = mallocarray(nipins, sizeof(struct io_pin), M_DEVBUF,
1996 : M_NOWAIT | M_ZERO);
1997 0 : if (this->ipins == NULL)
1998 0 : return(ENOMEM);
1999 0 : this->nipins = 0;
2000 0 : for (i = 0; i < nipins; i++) {
2001 0 : for (j = 0; j < this->nipins; j++)
2002 0 : if (this->ipins[j].prio > ipins[i].prio)
2003 : break;
2004 0 : for (k = this->nipins; k > j; k--)
2005 0 : this->ipins[k] = this->ipins[k - 1];
2006 0 : if (j < nipins)
2007 0 : this->ipins[j] = ipins[i];
2008 0 : this->nipins++;
2009 0 : if (this->nipins == nipins)
2010 : break;
2011 : }
2012 :
2013 0 : this->ipins_d = mallocarray(nipins_d, sizeof(struct io_pin), M_DEVBUF,
2014 : M_NOWAIT | M_ZERO);
2015 0 : if (this->ipins_d == NULL)
2016 0 : return(ENOMEM);
2017 0 : this->nipins_d = 0;
2018 0 : for (i = 0; i < nipins_d; i++) {
2019 0 : for (j = 0; j < this->nipins_d; j++)
2020 0 : if (this->ipins_d[j].prio > ipins_d[i].prio)
2021 : break;
2022 0 : for (k = this->nipins_d; k > j; k--)
2023 0 : this->ipins_d[k] = this->ipins_d[k - 1];
2024 0 : if (j < nipins_d)
2025 0 : this->ipins_d[j] = ipins_d[i];
2026 0 : this->nipins_d++;
2027 0 : if (this->nipins_d == nipins_d)
2028 : break;
2029 : }
2030 :
2031 : #ifdef AZALIA_DEBUG
2032 : printf("%s: analog out pins:", __func__);
2033 : for (i = 0; i < this->nopins; i++)
2034 : printf(" 0x%2.2x->0x%2.2x", this->opins[i].nid,
2035 : this->opins[i].conv);
2036 : printf("\n");
2037 : printf("%s: digital out pins:", __func__);
2038 : for (i = 0; i < this->nopins_d; i++)
2039 : printf(" 0x%2.2x->0x%2.2x", this->opins_d[i].nid,
2040 : this->opins_d[i].conv);
2041 : printf("\n");
2042 : printf("%s: analog in pins:", __func__);
2043 : for (i = 0; i < this->nipins; i++)
2044 : printf(" 0x%2.2x->0x%2.2x", this->ipins[i].nid,
2045 : this->ipins[i].conv);
2046 : printf("\n");
2047 : printf("%s: digital in pins:", __func__);
2048 : for (i = 0; i < this->nipins_d; i++)
2049 : printf(" 0x%2.2x->0x%2.2x", this->ipins_d[i].nid,
2050 : this->ipins_d[i].conv);
2051 : printf("\n");
2052 : #endif
2053 :
2054 0 : return 0;
2055 : #undef MAX_PINS
2056 0 : }
2057 :
2058 : int
2059 0 : azalia_codec_select_dacs(codec_t *this)
2060 : {
2061 : widget_t *w;
2062 : nid_t *convs;
2063 : int nconv, conv;
2064 : int i, j, k, err;
2065 :
2066 0 : convs = mallocarray(this->na_dacs, sizeof(nid_t), M_DEVBUF,
2067 : M_NOWAIT | M_ZERO);
2068 0 : if (convs == NULL)
2069 0 : return(ENOMEM);
2070 :
2071 : err = 0;
2072 : nconv = 0;
2073 0 : for (i = 0; i < this->nopins; i++) {
2074 0 : w = &this->w[this->opins[i].nid];
2075 :
2076 0 : conv = this->opins[i].conv;
2077 0 : for (j = 0; j < nconv; j++) {
2078 0 : if (conv == convs[j])
2079 : break;
2080 : }
2081 0 : if (j == nconv) {
2082 0 : convs[nconv++] = conv;
2083 0 : if (w->nid == this->fhp)
2084 0 : this->fhp_dac = conv;
2085 0 : if (nconv >= this->na_dacs) {
2086 : break;
2087 : }
2088 : } else {
2089 : /* find a different dac */
2090 : conv = -1;
2091 0 : for (j = 0; j < w->nconnections; j++) {
2092 0 : if (!azalia_widget_enabled(this,
2093 0 : w->connections[j]))
2094 : continue;
2095 0 : conv = azalia_codec_find_defdac(this,
2096 0 : w->connections[j], 1);
2097 0 : if (conv == -1)
2098 : continue;
2099 0 : for (k = 0; k < nconv; k++) {
2100 0 : if (conv == convs[k])
2101 : break;
2102 : }
2103 0 : if (k == nconv)
2104 : break;
2105 : }
2106 0 : if (j < w->nconnections && conv != -1) {
2107 0 : err = azalia_comresp(this, w->nid,
2108 : CORB_SET_CONNECTION_SELECT_CONTROL, j, 0);
2109 0 : if (err)
2110 : break;
2111 0 : w->selected = j;
2112 0 : this->opins[i].conv = conv;
2113 0 : if (w->nid == this->fhp)
2114 0 : this->fhp_dac = conv;
2115 0 : convs[nconv++] = conv;
2116 0 : if (nconv >= this->na_dacs)
2117 : break;
2118 : }
2119 : }
2120 : }
2121 :
2122 0 : free(convs, M_DEVBUF, this->na_dacs * sizeof(nid_t));
2123 0 : return(err);
2124 0 : }
2125 :
2126 : /* Connect the speaker to a DAC that no other output pin is connected
2127 : * to by default. If that is not possible, connect to a DAC other
2128 : * than the one the first output pin is connected to.
2129 : */
2130 : int
2131 0 : azalia_codec_select_spkrdac(codec_t *this)
2132 : {
2133 : widget_t *w;
2134 0 : nid_t convs[HDA_MAX_CHANNELS];
2135 : int nconv, conv;
2136 : int i, j, err, fspkr, conn;
2137 :
2138 : nconv = fspkr = 0;
2139 0 : for (i = 0; i < this->nopins; i++) {
2140 0 : conv = this->opins[i].conv;
2141 0 : for (j = 0; j < nconv; j++) {
2142 0 : if (conv == convs[j])
2143 : break;
2144 : }
2145 0 : if (j == nconv) {
2146 0 : if (conv == this->spkr_dac)
2147 0 : fspkr = 1;
2148 0 : convs[nconv++] = conv;
2149 0 : if (nconv == this->na_dacs)
2150 : break;
2151 : }
2152 : }
2153 :
2154 0 : if (fspkr) {
2155 : conn = conv = -1;
2156 0 : w = &this->w[this->speaker];
2157 0 : for (i = 0; i < w->nconnections; i++) {
2158 0 : conv = azalia_codec_find_defdac(this,
2159 0 : w->connections[i], 1);
2160 0 : for (j = 0; j < nconv; j++)
2161 0 : if (conv == convs[j])
2162 : break;
2163 0 : if (j == nconv)
2164 : break;
2165 : }
2166 0 : if (i < w->nconnections) {
2167 : conn = i;
2168 0 : } else {
2169 : /* Couldn't get a unique DAC. Try to get a diferent
2170 : * DAC than the first pin's DAC.
2171 : */
2172 0 : if (this->spkr_dac == this->opins[0].conv) {
2173 : /* If the speaker connection can't be changed,
2174 : * change the first pin's connection.
2175 : */
2176 0 : if (w->nconnections == 1)
2177 0 : w = &this->w[this->opins[0].nid];
2178 0 : for (j = 0; j < w->nconnections; j++) {
2179 0 : conv = azalia_codec_find_defdac(this,
2180 0 : w->connections[j], 1);
2181 0 : if (conv != this->opins[0].conv) {
2182 : conn = j;
2183 0 : break;
2184 : }
2185 : }
2186 : }
2187 : }
2188 0 : if (conn != -1 && conv != -1) {
2189 0 : err = azalia_comresp(this, w->nid,
2190 : CORB_SET_CONNECTION_SELECT_CONTROL, conn, 0);
2191 0 : if (err)
2192 0 : return(err);
2193 0 : w->selected = conn;
2194 0 : if (w->nid == this->speaker)
2195 0 : this->spkr_dac = conv;
2196 : else
2197 0 : this->opins[0].conv = conv;
2198 : }
2199 : }
2200 :
2201 : /* If there is a speaker2, try to connect it to spkr_dac. */
2202 0 : if (this->speaker2 != -1) {
2203 : conn = conv = -1;
2204 0 : w = &this->w[this->speaker2];
2205 0 : for (i = 0; i < w->nconnections; i++) {
2206 0 : conv = azalia_codec_find_defdac(this,
2207 0 : w->connections[i], 1);
2208 0 : if (conv == this->spkr_dac) {
2209 : conn = i;
2210 0 : break;
2211 : }
2212 : }
2213 0 : if (conn != -1) {
2214 0 : err = azalia_comresp(this, w->nid,
2215 : CORB_SET_CONNECTION_SELECT_CONTROL, conn, 0);
2216 0 : if (err)
2217 0 : return(err);
2218 0 : w->selected = conn;
2219 0 : }
2220 : }
2221 :
2222 0 : return(0);
2223 0 : }
2224 :
2225 : int
2226 0 : azalia_codec_find_defdac(codec_t *this, int index, int depth)
2227 : {
2228 : const widget_t *w;
2229 : int i, ret;
2230 :
2231 0 : w = &this->w[index];
2232 0 : if (w->enable == 0)
2233 0 : return -1;
2234 :
2235 0 : if (w->type == COP_AWTYPE_AUDIO_OUTPUT)
2236 0 : return index;
2237 :
2238 0 : if (depth > 0 &&
2239 0 : (w->type == COP_AWTYPE_PIN_COMPLEX ||
2240 0 : w->type == COP_AWTYPE_BEEP_GENERATOR ||
2241 0 : w->type == COP_AWTYPE_AUDIO_INPUT))
2242 0 : return -1;
2243 0 : if (++depth >= 10)
2244 0 : return -1;
2245 :
2246 0 : if (w->nconnections > 0) {
2247 : /* by default, all mixer connections are active */
2248 0 : if (w->type == COP_AWTYPE_AUDIO_MIXER) {
2249 0 : for (i = 0; i < w->nconnections; i++) {
2250 0 : index = w->connections[i];
2251 0 : if (!azalia_widget_enabled(this, index))
2252 : continue;
2253 0 : ret = azalia_codec_find_defdac(this, index,
2254 : depth);
2255 0 : if (ret >= 0)
2256 0 : return ret;
2257 : }
2258 : /* 7.3.3.2 Connection Select Control
2259 : * If an attempt is made to Set an index value greater than
2260 : * the number of list entries (index is equal to or greater
2261 : * than the Connection List Length property for the widget)
2262 : * the behavior is not predictable.
2263 : */
2264 :
2265 : /* negative index values are wrong too */
2266 0 : } else if (w->selected >= 0 &&
2267 0 : w->selected < sizeof(w->connections)) {
2268 0 : index = w->connections[w->selected];
2269 0 : if (VALID_WIDGET_NID(index, this)) {
2270 0 : ret = azalia_codec_find_defdac(this,
2271 : index, depth);
2272 0 : if (ret >= 0)
2273 0 : return ret;
2274 : }
2275 : }
2276 : }
2277 :
2278 0 : return -1;
2279 0 : }
2280 :
2281 : int
2282 0 : azalia_codec_find_defadc_sub(codec_t *this, nid_t node, int index, int depth)
2283 : {
2284 : const widget_t *w;
2285 : int i, ret;
2286 :
2287 0 : w = &this->w[index];
2288 0 : if (w->nid == node) {
2289 0 : return index;
2290 : }
2291 : /* back at the beginning or a bad end */
2292 0 : if (depth > 0 &&
2293 0 : (w->type == COP_AWTYPE_PIN_COMPLEX ||
2294 0 : w->type == COP_AWTYPE_BEEP_GENERATOR ||
2295 0 : w->type == COP_AWTYPE_AUDIO_OUTPUT ||
2296 0 : w->type == COP_AWTYPE_AUDIO_INPUT))
2297 0 : return -1;
2298 0 : if (++depth >= 10)
2299 0 : return -1;
2300 :
2301 0 : if (w->nconnections > 0) {
2302 : /* by default, all mixer connections are active */
2303 0 : if (w->type == COP_AWTYPE_AUDIO_MIXER) {
2304 0 : for (i = 0; i < w->nconnections; i++) {
2305 0 : if (!azalia_widget_enabled(this, w->connections[i]))
2306 : continue;
2307 0 : ret = azalia_codec_find_defadc_sub(this, node,
2308 0 : w->connections[i], depth);
2309 0 : if (ret >= 0)
2310 0 : return ret;
2311 : }
2312 : /* 7.3.3.2 Connection Select Control
2313 : * If an attempt is made to Set an index value greater than
2314 : * the number of list entries (index is equal to or greater
2315 : * than the Connection List Length property for the widget)
2316 : * the behavior is not predictable.
2317 : */
2318 :
2319 : /* negative index values are wrong too */
2320 0 : } else if (w->selected >= 0 &&
2321 0 : w->selected < sizeof(w->connections)) {
2322 0 : index = w->connections[w->selected];
2323 0 : if (VALID_WIDGET_NID(index, this)) {
2324 0 : ret = azalia_codec_find_defadc_sub(this,
2325 : node, index, depth);
2326 0 : if (ret >= 0)
2327 0 : return ret;
2328 : }
2329 : }
2330 : }
2331 0 : return -1;
2332 0 : }
2333 :
2334 : int
2335 0 : azalia_codec_find_defadc(codec_t *this, int index, int depth)
2336 : {
2337 : int i, j, conv;
2338 :
2339 : conv = -1;
2340 0 : for (i = 0; i < this->na_adcs; i++) {
2341 0 : j = azalia_codec_find_defadc_sub(this, index,
2342 0 : this->a_adcs[i], 0);
2343 0 : if (j >= 0) {
2344 0 : conv = this->a_adcs[i];
2345 0 : break;
2346 : }
2347 : }
2348 0 : return(conv);
2349 : }
2350 :
2351 : int
2352 0 : azalia_codec_init_volgroups(codec_t *this)
2353 : {
2354 : const widget_t *w;
2355 0 : uint32_t cap, result;
2356 : int i, j, dac, err;
2357 :
2358 : j = 0;
2359 0 : this->playvols.mask = 0;
2360 0 : FOR_EACH_WIDGET(this, i) {
2361 0 : w = &this->w[i];
2362 0 : if (w->enable == 0)
2363 : continue;
2364 0 : if (w->mixer_class == AZ_CLASS_RECORD)
2365 : continue;
2366 0 : if (!(w->widgetcap & COP_AWCAP_OUTAMP))
2367 : continue;
2368 0 : if ((COP_AMPCAP_NUMSTEPS(w->outamp_cap) == 0) &&
2369 0 : !(w->outamp_cap & COP_AMPCAP_MUTE))
2370 : continue;
2371 0 : this->playvols.mask |= (1 << j);
2372 0 : this->playvols.slaves[j++] = w->nid;
2373 0 : if (j >= AZ_MAX_VOL_SLAVES)
2374 : break;
2375 : }
2376 0 : this->playvols.nslaves = j;
2377 :
2378 0 : this->playvols.cur = 0;
2379 0 : for (i = 0; i < this->playvols.nslaves; i++) {
2380 0 : w = &this->w[this->playvols.slaves[i]];
2381 0 : if (w->nid == this->input_mixer ||
2382 0 : w->parent == this->input_mixer ||
2383 0 : WIDGET_CHANNELS(w) < 2)
2384 : continue;
2385 : j = 0;
2386 : /* azalia_codec_find_defdac only goes 10 connections deep.
2387 : * Start the connection depth at 7 so it doesn't go more
2388 : * than 3 connections deep.
2389 : */
2390 0 : if (w->type == COP_AWTYPE_AUDIO_MIXER ||
2391 0 : w->type == COP_AWTYPE_AUDIO_SELECTOR)
2392 0 : j = 7;
2393 0 : dac = azalia_codec_find_defdac(this, w->nid, j);
2394 0 : if (dac == -1)
2395 : continue;
2396 0 : if (dac != this->dacs.groups[this->dacs.cur].conv[0] &&
2397 0 : dac != this->spkr_dac && dac != this->fhp_dac)
2398 : continue;
2399 0 : cap = w->outamp_cap;
2400 0 : if ((cap & COP_AMPCAP_MUTE) && COP_AMPCAP_NUMSTEPS(cap)) {
2401 0 : if (w->type == COP_AWTYPE_BEEP_GENERATOR) {
2402 : continue;
2403 0 : } else if (w->type == COP_AWTYPE_PIN_COMPLEX) {
2404 0 : err = azalia_comresp(this, w->nid,
2405 : CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
2406 0 : if (!err && (result & CORB_PWC_OUTPUT))
2407 0 : this->playvols.cur |= (1 << i);
2408 : } else
2409 0 : this->playvols.cur |= (1 << i);
2410 : }
2411 : }
2412 0 : if (this->playvols.cur == 0) {
2413 0 : for (i = 0; i < this->playvols.nslaves; i++) {
2414 0 : w = &this->w[this->playvols.slaves[i]];
2415 : j = 0;
2416 0 : if (w->type == COP_AWTYPE_AUDIO_MIXER ||
2417 0 : w->type == COP_AWTYPE_AUDIO_SELECTOR)
2418 0 : j = 7;
2419 0 : dac = azalia_codec_find_defdac(this, w->nid, j);
2420 0 : if (dac == -1)
2421 : continue;
2422 0 : if (dac != this->dacs.groups[this->dacs.cur].conv[0] &&
2423 0 : dac != this->spkr_dac && dac != this->fhp_dac)
2424 : continue;
2425 0 : if (w->type == COP_AWTYPE_BEEP_GENERATOR)
2426 : continue;
2427 0 : if (w->type == COP_AWTYPE_PIN_COMPLEX) {
2428 0 : err = azalia_comresp(this, w->nid,
2429 : CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
2430 0 : if (!err && (result & CORB_PWC_OUTPUT))
2431 0 : this->playvols.cur |= (1 << i);
2432 : } else {
2433 0 : this->playvols.cur |= (1 << i);
2434 : }
2435 : }
2436 : }
2437 :
2438 0 : this->playvols.master = this->audiofunc;
2439 0 : if (this->playvols.nslaves > 0) {
2440 0 : FOR_EACH_WIDGET(this, i) {
2441 0 : w = &this->w[i];
2442 0 : if (w->type != COP_AWTYPE_VOLUME_KNOB)
2443 : continue;
2444 0 : if (!COP_VKCAP_NUMSTEPS(w->d.volume.cap))
2445 : continue;
2446 0 : this->playvols.master = w->nid;
2447 0 : break;
2448 : }
2449 : }
2450 :
2451 : j = 0;
2452 0 : this->recvols.mask = 0;
2453 0 : FOR_EACH_WIDGET(this, i) {
2454 0 : w = &this->w[i];
2455 0 : if (w->enable == 0)
2456 : continue;
2457 0 : if (w->type == COP_AWTYPE_AUDIO_INPUT ||
2458 0 : w->type == COP_AWTYPE_PIN_COMPLEX) {
2459 0 : if (!(w->widgetcap & COP_AWCAP_INAMP))
2460 : continue;
2461 0 : if ((COP_AMPCAP_NUMSTEPS(w->inamp_cap) == 0) &&
2462 0 : !(w->inamp_cap & COP_AMPCAP_MUTE))
2463 : continue;
2464 0 : } else if (w->type == COP_AWTYPE_AUDIO_MIXER ||
2465 0 : w->type == COP_AWTYPE_AUDIO_SELECTOR) {
2466 0 : if (w->mixer_class != AZ_CLASS_RECORD)
2467 : continue;
2468 0 : if (!(w->widgetcap & COP_AWCAP_OUTAMP))
2469 : continue;
2470 0 : if ((COP_AMPCAP_NUMSTEPS(w->outamp_cap) == 0) &&
2471 0 : !(w->outamp_cap & COP_AMPCAP_MUTE))
2472 : continue;
2473 : } else {
2474 : continue;
2475 : }
2476 0 : this->recvols.mask |= (1 << j);
2477 0 : this->recvols.slaves[j++] = w->nid;
2478 0 : if (j >= AZ_MAX_VOL_SLAVES)
2479 : break;
2480 : }
2481 0 : this->recvols.nslaves = j;
2482 :
2483 0 : this->recvols.cur = 0;
2484 0 : for (i = 0; i < this->recvols.nslaves; i++) {
2485 0 : w = &this->w[this->recvols.slaves[i]];
2486 0 : cap = w->outamp_cap;
2487 0 : if (w->type == COP_AWTYPE_AUDIO_INPUT ||
2488 0 : w->type != COP_AWTYPE_PIN_COMPLEX)
2489 0 : cap = w->inamp_cap;
2490 : else
2491 0 : if (w->mixer_class != AZ_CLASS_RECORD)
2492 : continue;
2493 0 : if ((cap & COP_AMPCAP_MUTE) && COP_AMPCAP_NUMSTEPS(cap)) {
2494 0 : if (w->type == COP_AWTYPE_PIN_COMPLEX) {
2495 0 : err = azalia_comresp(this, w->nid,
2496 : CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
2497 0 : if (!err && !(result & CORB_PWC_OUTPUT))
2498 0 : this->recvols.cur |= (1 << i);
2499 : } else
2500 0 : this->recvols.cur |= (1 << i);
2501 : }
2502 : }
2503 0 : if (this->recvols.cur == 0) {
2504 0 : for (i = 0; i < this->recvols.nslaves; i++) {
2505 0 : w = &this->w[this->recvols.slaves[i]];
2506 0 : cap = w->outamp_cap;
2507 0 : if (w->type == COP_AWTYPE_AUDIO_INPUT ||
2508 0 : w->type != COP_AWTYPE_PIN_COMPLEX)
2509 0 : cap = w->inamp_cap;
2510 : else
2511 0 : if (w->mixer_class != AZ_CLASS_RECORD)
2512 : continue;
2513 0 : if (w->type == COP_AWTYPE_PIN_COMPLEX) {
2514 0 : err = azalia_comresp(this, w->nid,
2515 : CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
2516 0 : if (!err && !(result & CORB_PWC_OUTPUT))
2517 0 : this->recvols.cur |= (1 << i);
2518 : } else {
2519 0 : this->recvols.cur |= (1 << i);
2520 : }
2521 : }
2522 : }
2523 :
2524 0 : this->recvols.master = this->audiofunc;
2525 :
2526 0 : return 0;
2527 0 : }
2528 :
2529 : int
2530 0 : azalia_codec_delete(codec_t *this)
2531 : {
2532 0 : azalia_mixer_delete(this);
2533 :
2534 0 : if (this->formats != NULL) {
2535 0 : free(this->formats, M_DEVBUF, 0);
2536 0 : this->formats = NULL;
2537 0 : }
2538 0 : this->nformats = 0;
2539 :
2540 0 : if (this->opins != NULL) {
2541 0 : free(this->opins, M_DEVBUF, 0);
2542 0 : this->opins = NULL;
2543 0 : }
2544 0 : this->nopins = 0;
2545 :
2546 0 : if (this->opins_d != NULL) {
2547 0 : free(this->opins_d, M_DEVBUF, 0);
2548 0 : this->opins_d = NULL;
2549 0 : }
2550 0 : this->nopins_d = 0;
2551 :
2552 0 : if (this->ipins != NULL) {
2553 0 : free(this->ipins, M_DEVBUF, 0);
2554 0 : this->ipins = NULL;
2555 0 : }
2556 0 : this->nipins = 0;
2557 :
2558 0 : if (this->ipins_d != NULL) {
2559 0 : free(this->ipins_d, M_DEVBUF, 0);
2560 0 : this->ipins_d = NULL;
2561 0 : }
2562 0 : this->nipins_d = 0;
2563 :
2564 0 : if (this->w != NULL) {
2565 0 : free(this->w, M_DEVBUF, 0);
2566 0 : this->w = NULL;
2567 0 : }
2568 :
2569 0 : return 0;
2570 : }
2571 :
2572 : int
2573 0 : azalia_codec_construct_format(codec_t *this, int newdac, int newadc)
2574 : {
2575 : const convgroup_t *group;
2576 : uint32_t bits_rates;
2577 : int variation;
2578 : int nbits, c, chan, i;
2579 : nid_t nid;
2580 :
2581 : variation = 0;
2582 :
2583 0 : if (this->dacs.ngroups > 0 && newdac < this->dacs.ngroups &&
2584 0 : newdac >= 0) {
2585 0 : this->dacs.cur = newdac;
2586 0 : group = &this->dacs.groups[this->dacs.cur];
2587 0 : bits_rates = this->w[group->conv[0]].d.audio.bits_rates;
2588 : nbits = 0;
2589 0 : if (bits_rates & COP_PCM_B8)
2590 0 : nbits++;
2591 0 : if (bits_rates & COP_PCM_B16)
2592 0 : nbits++;
2593 0 : if (bits_rates & COP_PCM_B20)
2594 0 : nbits++;
2595 0 : if (bits_rates & COP_PCM_B24)
2596 0 : nbits++;
2597 0 : if ((bits_rates & COP_PCM_B32) &&
2598 0 : !(this->w[group->conv[0]].widgetcap & COP_AWCAP_DIGITAL))
2599 0 : nbits++;
2600 0 : if (nbits == 0) {
2601 0 : printf("%s: invalid DAC PCM format: 0x%8.8x\n",
2602 0 : XNAME(this->az), bits_rates);
2603 0 : return -1;
2604 : }
2605 0 : variation += group->nconv * nbits;
2606 0 : }
2607 :
2608 0 : if (this->adcs.ngroups > 0 && newadc < this->adcs.ngroups &&
2609 0 : newadc >= 0) {
2610 0 : this->adcs.cur = newadc;
2611 0 : group = &this->adcs.groups[this->adcs.cur];
2612 0 : bits_rates = this->w[group->conv[0]].d.audio.bits_rates;
2613 : nbits = 0;
2614 0 : if (bits_rates & COP_PCM_B8)
2615 0 : nbits++;
2616 0 : if (bits_rates & COP_PCM_B16)
2617 0 : nbits++;
2618 0 : if (bits_rates & COP_PCM_B20)
2619 0 : nbits++;
2620 0 : if (bits_rates & COP_PCM_B24)
2621 0 : nbits++;
2622 0 : if ((bits_rates & COP_PCM_B32) &&
2623 0 : !(this->w[group->conv[0]].widgetcap & COP_AWCAP_DIGITAL))
2624 0 : nbits++;
2625 0 : if (nbits == 0) {
2626 0 : printf("%s: invalid ADC PCM format: 0x%8.8x\n",
2627 0 : XNAME(this->az), bits_rates);
2628 0 : return -1;
2629 : }
2630 0 : variation += group->nconv * nbits;
2631 0 : }
2632 :
2633 0 : if (variation == 0) {
2634 : DPRINTF(("%s: no converter groups\n", XNAME(this->az)));
2635 0 : return -1;
2636 : }
2637 :
2638 0 : if (this->formats != NULL)
2639 0 : free(this->formats, M_DEVBUF, 0);
2640 0 : this->nformats = 0;
2641 0 : this->formats = mallocarray(variation, sizeof(struct audio_format),
2642 : M_DEVBUF, M_NOWAIT | M_ZERO);
2643 0 : if (this->formats == NULL) {
2644 0 : printf("%s: out of memory in %s\n",
2645 0 : XNAME(this->az), __func__);
2646 0 : return ENOMEM;
2647 : }
2648 :
2649 : /* register formats for playback */
2650 0 : if (this->dacs.ngroups > 0) {
2651 0 : group = &this->dacs.groups[this->dacs.cur];
2652 0 : for (c = 0; c < group->nconv; c++) {
2653 : chan = 0;
2654 : bits_rates = ~0;
2655 0 : if (this->w[group->conv[0]].widgetcap &
2656 : COP_AWCAP_DIGITAL)
2657 0 : bits_rates &= ~(COP_PCM_B32);
2658 0 : for (i = 0; i <= c; i++) {
2659 0 : nid = group->conv[i];
2660 0 : chan += WIDGET_CHANNELS(&this->w[nid]);
2661 0 : bits_rates &= this->w[nid].d.audio.bits_rates;
2662 : }
2663 0 : azalia_codec_add_bits(this, chan, bits_rates,
2664 : AUMODE_PLAY);
2665 : }
2666 : }
2667 :
2668 : /* register formats for recording */
2669 0 : if (this->adcs.ngroups > 0) {
2670 0 : group = &this->adcs.groups[this->adcs.cur];
2671 0 : for (c = 0; c < group->nconv; c++) {
2672 : chan = 0;
2673 : bits_rates = ~0;
2674 0 : if (this->w[group->conv[0]].widgetcap &
2675 : COP_AWCAP_DIGITAL)
2676 0 : bits_rates &= ~(COP_PCM_B32);
2677 0 : for (i = 0; i <= c; i++) {
2678 0 : nid = group->conv[i];
2679 0 : chan += WIDGET_CHANNELS(&this->w[nid]);
2680 0 : bits_rates &= this->w[nid].d.audio.bits_rates;
2681 : }
2682 0 : azalia_codec_add_bits(this, chan, bits_rates,
2683 : AUMODE_RECORD);
2684 : }
2685 : }
2686 :
2687 0 : return 0;
2688 0 : }
2689 :
2690 : void
2691 0 : azalia_codec_add_bits(codec_t *this, int chan, uint32_t bits_rates, int mode)
2692 : {
2693 0 : if (bits_rates & COP_PCM_B8)
2694 0 : azalia_codec_add_format(this, chan, 8, bits_rates, mode);
2695 0 : if (bits_rates & COP_PCM_B16)
2696 0 : azalia_codec_add_format(this, chan, 16, bits_rates, mode);
2697 0 : if (bits_rates & COP_PCM_B20)
2698 0 : azalia_codec_add_format(this, chan, 20, bits_rates, mode);
2699 0 : if (bits_rates & COP_PCM_B24)
2700 0 : azalia_codec_add_format(this, chan, 24, bits_rates, mode);
2701 0 : if (bits_rates & COP_PCM_B32)
2702 0 : azalia_codec_add_format(this, chan, 32, bits_rates, mode);
2703 0 : }
2704 :
2705 : void
2706 0 : azalia_codec_add_format(codec_t *this, int chan, int prec, uint32_t rates,
2707 : int32_t mode)
2708 : {
2709 : struct audio_format *f;
2710 :
2711 0 : f = &this->formats[this->nformats++];
2712 0 : f->mode = mode;
2713 0 : f->encoding = AUDIO_ENCODING_SLINEAR_LE;
2714 0 : if (prec == 8)
2715 0 : f->encoding = AUDIO_ENCODING_ULINEAR_LE;
2716 0 : f->precision = prec;
2717 0 : f->channels = chan;
2718 0 : f->frequency_type = 0;
2719 0 : if (rates & COP_PCM_R80)
2720 0 : f->frequency[f->frequency_type++] = 8000;
2721 0 : if (rates & COP_PCM_R110)
2722 0 : f->frequency[f->frequency_type++] = 11025;
2723 0 : if (rates & COP_PCM_R160)
2724 0 : f->frequency[f->frequency_type++] = 16000;
2725 0 : if (rates & COP_PCM_R220)
2726 0 : f->frequency[f->frequency_type++] = 22050;
2727 0 : if (rates & COP_PCM_R320)
2728 0 : f->frequency[f->frequency_type++] = 32000;
2729 0 : if (rates & COP_PCM_R441)
2730 0 : f->frequency[f->frequency_type++] = 44100;
2731 0 : if (rates & COP_PCM_R480)
2732 0 : f->frequency[f->frequency_type++] = 48000;
2733 0 : if (rates & COP_PCM_R882)
2734 0 : f->frequency[f->frequency_type++] = 88200;
2735 0 : if (rates & COP_PCM_R960)
2736 0 : f->frequency[f->frequency_type++] = 96000;
2737 0 : if (rates & COP_PCM_R1764)
2738 0 : f->frequency[f->frequency_type++] = 176400;
2739 0 : if (rates & COP_PCM_R1920)
2740 0 : f->frequency[f->frequency_type++] = 192000;
2741 0 : if (rates & COP_PCM_R3840)
2742 0 : f->frequency[f->frequency_type++] = 384000;
2743 0 : }
2744 :
2745 : int
2746 0 : azalia_codec_connect_stream(stream_t *this)
2747 : {
2748 0 : const codec_t *codec = &this->az->codecs[this->az->codecno];
2749 : const convgroup_t *group;
2750 : widget_t *w;
2751 0 : uint32_t digital, stream_chan;
2752 : int i, err, curchan, nchan, widchan;
2753 :
2754 : err = 0;
2755 0 : nchan = (this->fmt & HDA_SD_FMT_CHAN) + 1;
2756 :
2757 0 : if (this->dir == AUMODE_RECORD)
2758 0 : group = &codec->adcs.groups[codec->adcs.cur];
2759 : else
2760 0 : group = &codec->dacs.groups[codec->dacs.cur];
2761 :
2762 : curchan = 0;
2763 0 : for (i = 0; i < group->nconv; i++) {
2764 0 : w = &codec->w[group->conv[i]];
2765 0 : widchan = WIDGET_CHANNELS(w);
2766 :
2767 0 : stream_chan = (this->number << 4);
2768 0 : if (curchan < nchan) {
2769 0 : stream_chan |= curchan;
2770 0 : } else if (w->nid == codec->spkr_dac ||
2771 0 : w->nid == codec->fhp_dac) {
2772 : stream_chan |= 0; /* first channel(s) */
2773 0 : } else
2774 : stream_chan = 0; /* idle stream */
2775 :
2776 : if (stream_chan == 0) {
2777 : DPRINTFN(0, ("%s: %2.2x is idle\n", __func__, w->nid));
2778 : } else {
2779 : DPRINTFN(0, ("%s: %2.2x on stream chan %d\n", __func__,
2780 : w->nid, stream_chan & ~(this->number << 4)));
2781 : }
2782 :
2783 0 : err = azalia_comresp(codec, w->nid, CORB_SET_CONVERTER_FORMAT,
2784 0 : this->fmt, NULL);
2785 0 : if (err) {
2786 : DPRINTF(("%s: nid %2.2x fmt %2.2x: %d\n",
2787 : __func__, w->nid, this->fmt, err));
2788 : break;
2789 : }
2790 0 : err = azalia_comresp(codec, w->nid,
2791 : CORB_SET_CONVERTER_STREAM_CHANNEL, stream_chan, NULL);
2792 0 : if (err) {
2793 : DPRINTF(("%s: nid %2.2x chan %d: %d\n",
2794 : __func__, w->nid, stream_chan, err));
2795 : break;
2796 : }
2797 :
2798 0 : if (w->widgetcap & COP_AWCAP_DIGITAL) {
2799 0 : err = azalia_comresp(codec, w->nid,
2800 : CORB_GET_DIGITAL_CONTROL, 0, &digital);
2801 0 : if (err) {
2802 : DPRINTF(("%s: nid %2.2x get digital: %d\n",
2803 : __func__, w->nid, err));
2804 : break;
2805 : }
2806 0 : digital = (digital & 0xff) | CORB_DCC_DIGEN;
2807 0 : err = azalia_comresp(codec, w->nid,
2808 : CORB_SET_DIGITAL_CONTROL_L, digital, NULL);
2809 0 : if (err) {
2810 : DPRINTF(("%s: nid %2.2x set digital: %d\n",
2811 : __func__, w->nid, err));
2812 : break;
2813 : }
2814 : }
2815 0 : curchan += widchan;
2816 : }
2817 :
2818 0 : return err;
2819 0 : }
2820 :
2821 : int
2822 0 : azalia_codec_disconnect_stream(stream_t *this)
2823 : {
2824 0 : const codec_t *codec = &this->az->codecs[this->az->codecno];
2825 : const convgroup_t *group;
2826 0 : uint32_t v;
2827 : int i;
2828 : nid_t nid;
2829 :
2830 0 : if (this->dir == AUMODE_RECORD)
2831 0 : group = &codec->adcs.groups[codec->adcs.cur];
2832 : else
2833 0 : group = &codec->dacs.groups[codec->dacs.cur];
2834 0 : for (i = 0; i < group->nconv; i++) {
2835 0 : nid = group->conv[i];
2836 0 : azalia_comresp(codec, nid, CORB_SET_CONVERTER_STREAM_CHANNEL,
2837 : 0, NULL); /* stream#0 */
2838 0 : if (codec->w[nid].widgetcap & COP_AWCAP_DIGITAL) {
2839 : /* disable S/PDIF */
2840 0 : azalia_comresp(codec, nid, CORB_GET_DIGITAL_CONTROL,
2841 : 0, &v);
2842 0 : v = (v & ~CORB_DCC_DIGEN) & 0xff;
2843 0 : azalia_comresp(codec, nid, CORB_SET_DIGITAL_CONTROL_L,
2844 : v, NULL);
2845 0 : }
2846 : }
2847 0 : return 0;
2848 0 : }
2849 :
2850 : /* ================================================================
2851 : * HDA widget functions
2852 : * ================================================================ */
2853 :
2854 : int
2855 0 : azalia_widget_init(widget_t *this, const codec_t *codec, nid_t nid)
2856 : {
2857 0 : uint32_t result;
2858 : int err;
2859 :
2860 0 : err = azalia_comresp(codec, nid, CORB_GET_PARAMETER,
2861 : COP_AUDIO_WIDGET_CAP, &result);
2862 0 : if (err)
2863 0 : return err;
2864 0 : this->nid = nid;
2865 0 : this->widgetcap = result;
2866 0 : this->type = COP_AWCAP_TYPE(result);
2867 0 : if (this->widgetcap & COP_AWCAP_POWER) {
2868 0 : azalia_comresp(codec, nid, CORB_SET_POWER_STATE, CORB_PS_D0,
2869 : &result);
2870 0 : DELAY(100);
2871 0 : }
2872 :
2873 0 : this->enable = 1;
2874 0 : this->mixer_class = -1;
2875 0 : this->parent = codec->audiofunc;
2876 :
2877 0 : switch (this->type) {
2878 : case COP_AWTYPE_AUDIO_OUTPUT:
2879 : /* FALLTHROUGH */
2880 : case COP_AWTYPE_AUDIO_INPUT:
2881 0 : azalia_widget_init_audio(this, codec);
2882 0 : break;
2883 : case COP_AWTYPE_PIN_COMPLEX:
2884 0 : azalia_widget_init_pin(this, codec);
2885 0 : break;
2886 : case COP_AWTYPE_VOLUME_KNOB:
2887 0 : err = azalia_comresp(codec, this->nid, CORB_GET_PARAMETER,
2888 : COP_VOLUME_KNOB_CAPABILITIES, &result);
2889 0 : if (err)
2890 0 : return err;
2891 0 : this->d.volume.cap = result;
2892 0 : break;
2893 : case COP_AWTYPE_POWER:
2894 : /* FALLTHROUGH */
2895 : case COP_AWTYPE_VENDOR_DEFINED:
2896 0 : this->enable = 0;
2897 0 : break;
2898 : }
2899 :
2900 : /* amplifier information */
2901 : /* XXX (ab)use bits 24-30 to store the "control offset", which is
2902 : * the number of steps, starting at 0, that have no effect. these
2903 : * bits are reserved in HDA 1.0.
2904 : */
2905 0 : if (this->widgetcap & COP_AWCAP_INAMP) {
2906 0 : if (this->widgetcap & COP_AWCAP_AMPOV)
2907 0 : azalia_comresp(codec, nid, CORB_GET_PARAMETER,
2908 0 : COP_INPUT_AMPCAP, &this->inamp_cap);
2909 : else
2910 0 : this->inamp_cap = codec->w[codec->audiofunc].inamp_cap;
2911 0 : this->inamp_cap &= ~(0x7f << 24);
2912 0 : }
2913 0 : if (this->widgetcap & COP_AWCAP_OUTAMP) {
2914 0 : if (this->widgetcap & COP_AWCAP_AMPOV)
2915 0 : azalia_comresp(codec, nid, CORB_GET_PARAMETER,
2916 0 : COP_OUTPUT_AMPCAP, &this->outamp_cap);
2917 : else
2918 0 : this->outamp_cap = codec->w[codec->audiofunc].outamp_cap;
2919 0 : this->outamp_cap &= ~(0x7f << 24);
2920 0 : }
2921 0 : return 0;
2922 0 : }
2923 :
2924 : int
2925 0 : azalia_widget_sole_conn(codec_t *this, nid_t nid)
2926 : {
2927 : int i, j, target, nconn, has_target;
2928 :
2929 : /* connected to ADC */
2930 0 : for (i = 0; i < this->adcs.ngroups; i++) {
2931 0 : for (j = 0; j < this->adcs.groups[i].nconv; j++) {
2932 0 : target = this->adcs.groups[i].conv[j];
2933 0 : if (this->w[target].nconnections == 1 &&
2934 0 : this->w[target].connections[0] == nid) {
2935 0 : return target;
2936 : }
2937 : }
2938 : }
2939 : /* connected to DAC */
2940 0 : for (i = 0; i < this->dacs.ngroups; i++) {
2941 0 : for (j = 0; j < this->dacs.groups[i].nconv; j++) {
2942 0 : target = this->dacs.groups[i].conv[j];
2943 0 : if (this->w[target].nconnections == 1 &&
2944 0 : this->w[target].connections[0] == nid) {
2945 0 : return target;
2946 : }
2947 : }
2948 : }
2949 : /* connected to pin complex */
2950 : target = -1;
2951 0 : FOR_EACH_WIDGET(this, i) {
2952 0 : if (this->w[i].type != COP_AWTYPE_PIN_COMPLEX)
2953 : continue;
2954 0 : if (this->w[i].nconnections == 1 &&
2955 0 : this->w[i].connections[0] == nid) {
2956 0 : if (target != -1)
2957 0 : return -1;
2958 : target = i;
2959 0 : } else {
2960 : nconn = 0;
2961 : has_target = 0;
2962 0 : for (j = 0; j < this->w[i].nconnections; j++) {
2963 0 : if (!this->w[this->w[i].connections[j]].enable)
2964 : continue;
2965 0 : nconn++;
2966 0 : if (this->w[i].connections[j] == nid)
2967 0 : has_target = 1;
2968 : }
2969 0 : if (has_target == 1) {
2970 0 : if (nconn == 1) {
2971 0 : if (target != -1)
2972 0 : return -1;
2973 : target = i;
2974 : } else {
2975 : /* not sole connection at least once */
2976 0 : return -1;
2977 : }
2978 0 : }
2979 : }
2980 : }
2981 0 : if (target != -1)
2982 0 : return target;
2983 :
2984 0 : return -1;
2985 0 : }
2986 :
2987 : int
2988 0 : azalia_widget_label_widgets(codec_t *codec)
2989 : {
2990 : widget_t *w;
2991 : convgroup_t *group;
2992 0 : int types[16];
2993 0 : int pins[16];
2994 : int colors_used, use_colors, schan;
2995 : int i, j;
2996 :
2997 0 : bzero(&pins, sizeof(pins));
2998 0 : bzero(&types, sizeof(types));
2999 :
3000 : /* If codec has more than one line-out jack, check if the jacks
3001 : * have unique colors. If so, use the colors in the mixer names.
3002 : */
3003 : use_colors = 1;
3004 : colors_used = 0;
3005 0 : if (codec->nout_jacks < 2)
3006 0 : use_colors = 0;
3007 0 : for (i = 0; use_colors && i < codec->nopins; i++) {
3008 0 : w = &codec->w[codec->opins[i].nid];
3009 0 : if (w->d.pin.device != CORB_CD_LINEOUT)
3010 : continue;
3011 0 : if (colors_used & (1 << w->d.pin.color))
3012 0 : use_colors = 0;
3013 : else
3014 0 : colors_used |= (1 << w->d.pin.color);
3015 : }
3016 :
3017 0 : FOR_EACH_WIDGET(codec, i) {
3018 0 : w = &codec->w[i];
3019 : /* default for disabled/unused widgets */
3020 0 : snprintf(w->name, sizeof(w->name), "u-wid%2.2x", w->nid);
3021 0 : if (w->enable == 0)
3022 : continue;
3023 0 : switch (w->type) {
3024 : case COP_AWTYPE_PIN_COMPLEX:
3025 0 : pins[w->d.pin.device]++;
3026 0 : if (use_colors && w->d.pin.device == CORB_CD_LINEOUT) {
3027 0 : snprintf(w->name, sizeof(w->name), "%s-%s",
3028 0 : pin_devices[w->d.pin.device],
3029 0 : line_colors[w->d.pin.color]);
3030 0 : } else if (pins[w->d.pin.device] > 1) {
3031 0 : snprintf(w->name, sizeof(w->name), "%s%d",
3032 : pin_devices[w->d.pin.device],
3033 : pins[w->d.pin.device]);
3034 0 : } else {
3035 0 : snprintf(w->name, sizeof(w->name), "%s",
3036 : pin_devices[w->d.pin.device]);
3037 : }
3038 : break;
3039 : case COP_AWTYPE_AUDIO_OUTPUT:
3040 0 : if (codec->dacs.ngroups < 1)
3041 : break;
3042 0 : group = &codec->dacs.groups[0];
3043 : schan = 0;
3044 0 : for (j = 0; j < group->nconv; j++) {
3045 0 : if (w->nid == group->conv[j]) {
3046 0 : snprintf(w->name, sizeof(w->name),
3047 0 : "%s-%d:%d", wtypes[w->type], schan,
3048 0 : schan + WIDGET_CHANNELS(w) - 1);
3049 0 : }
3050 0 : schan += WIDGET_CHANNELS(w);
3051 : }
3052 0 : if (codec->dacs.ngroups < 2)
3053 : break;
3054 0 : group = &codec->dacs.groups[1];
3055 : schan = 0;
3056 0 : for (j = 0; j < group->nconv; j++) {
3057 0 : if (w->nid == group->conv[j]) {
3058 0 : snprintf(w->name, sizeof(w->name),
3059 0 : "dig-%s-%d:%d", wtypes[w->type],
3060 : schan,
3061 0 : schan + WIDGET_CHANNELS(w) - 1);
3062 0 : }
3063 0 : schan += WIDGET_CHANNELS(w);
3064 : }
3065 : break;
3066 : case COP_AWTYPE_AUDIO_INPUT:
3067 0 : w->mixer_class = AZ_CLASS_RECORD;
3068 0 : if (codec->adcs.ngroups < 1)
3069 : break;
3070 0 : group = &codec->adcs.groups[0];
3071 : schan = 0;
3072 0 : for (j = 0; j < group->nconv; j++) {
3073 0 : if (w->nid == group->conv[j]) {
3074 0 : snprintf(w->name, sizeof(w->name),
3075 0 : "%s-%d:%d", wtypes[w->type], schan,
3076 0 : schan + WIDGET_CHANNELS(w) - 1);
3077 0 : }
3078 0 : schan += WIDGET_CHANNELS(w);
3079 : }
3080 0 : if (codec->adcs.ngroups < 2)
3081 : break;
3082 0 : group = &codec->adcs.groups[1];
3083 : schan = 0;
3084 0 : for (j = 0; j < group->nconv; j++) {
3085 0 : if (w->nid == group->conv[j]) {
3086 0 : snprintf(w->name, sizeof(w->name),
3087 0 : "dig-%s-%d:%d", wtypes[w->type],
3088 : schan,
3089 0 : schan + WIDGET_CHANNELS(w) - 1);
3090 0 : }
3091 0 : schan += WIDGET_CHANNELS(w);
3092 : }
3093 : break;
3094 : default:
3095 0 : types[w->type]++;
3096 0 : if (types[w->type] > 1)
3097 0 : snprintf(w->name, sizeof(w->name), "%s%d",
3098 : wtypes[w->type], types[w->type]);
3099 : else
3100 0 : snprintf(w->name, sizeof(w->name), "%s",
3101 : wtypes[w->type]);
3102 : break;
3103 : }
3104 : }
3105 :
3106 : /* Mixers and selectors that connect to only one other widget are
3107 : * functionally part of the widget they are connected to. Show that
3108 : * relationship in the name.
3109 : */
3110 0 : FOR_EACH_WIDGET(codec, i) {
3111 0 : if (codec->w[i].type != COP_AWTYPE_AUDIO_MIXER &&
3112 0 : codec->w[i].type != COP_AWTYPE_AUDIO_SELECTOR)
3113 : continue;
3114 0 : if (codec->w[i].enable == 0)
3115 : continue;
3116 0 : j = azalia_widget_sole_conn(codec, i);
3117 0 : if (j == -1) {
3118 : /* Special case. A selector with outamp capabilities
3119 : * and is connected to a single widget that has either
3120 : * no input or no output capabilities. This widget
3121 : * serves as the input or output amp for the widget
3122 : * it is connected to.
3123 : */
3124 0 : if (codec->w[i].type == COP_AWTYPE_AUDIO_SELECTOR &&
3125 0 : (codec->w[i].widgetcap & COP_AWCAP_OUTAMP) &&
3126 0 : codec->w[i].nconnections == 1) {
3127 0 : j = codec->w[i].connections[0];
3128 0 : if (!azalia_widget_enabled(codec, j))
3129 : continue;
3130 0 : if (!(codec->w[j].widgetcap & COP_AWCAP_INAMP))
3131 0 : codec->w[i].mixer_class =
3132 : AZ_CLASS_INPUT;
3133 0 : else if (!(codec->w[j].widgetcap & COP_AWCAP_OUTAMP))
3134 0 : codec->w[i].mixer_class =
3135 : AZ_CLASS_OUTPUT;
3136 : else
3137 : continue;
3138 : }
3139 : }
3140 0 : if (j >= 0) {
3141 : /* As part of a disabled widget, this widget
3142 : * should be disabled as well.
3143 : */
3144 0 : if (codec->w[j].enable == 0) {
3145 0 : codec->w[i].enable = 0;
3146 0 : snprintf(codec->w[i].name,
3147 : sizeof(codec->w[i].name),
3148 : "u-wid%2.2x", i);
3149 0 : continue;
3150 : }
3151 0 : snprintf(codec->w[i].name, sizeof(codec->w[i].name),
3152 0 : "%s", codec->w[j].name);
3153 0 : if (codec->w[j].mixer_class == AZ_CLASS_RECORD)
3154 0 : codec->w[i].mixer_class = AZ_CLASS_RECORD;
3155 0 : codec->w[i].parent = j;
3156 0 : }
3157 : }
3158 :
3159 0 : return 0;
3160 0 : }
3161 :
3162 : int
3163 0 : azalia_widget_init_audio(widget_t *this, const codec_t *codec)
3164 : {
3165 0 : uint32_t result;
3166 : int err;
3167 :
3168 : /* check audio format */
3169 0 : if (this->widgetcap & COP_AWCAP_FORMATOV) {
3170 0 : err = azalia_comresp(codec, this->nid, CORB_GET_PARAMETER,
3171 : COP_STREAM_FORMATS, &result);
3172 0 : if (err)
3173 0 : return err;
3174 0 : this->d.audio.encodings = result;
3175 0 : if (result == 0) { /* quirk for CMI9880.
3176 : * This must not occur usually... */
3177 0 : this->d.audio.encodings =
3178 0 : codec->w[codec->audiofunc].d.audio.encodings;
3179 0 : this->d.audio.bits_rates =
3180 0 : codec->w[codec->audiofunc].d.audio.bits_rates;
3181 0 : } else {
3182 0 : if ((result & COP_STREAM_FORMAT_PCM) == 0) {
3183 0 : printf("%s: %s: No PCM support: %x\n",
3184 0 : XNAME(codec->az), this->name, result);
3185 0 : return -1;
3186 : }
3187 0 : err = azalia_comresp(codec, this->nid,
3188 : CORB_GET_PARAMETER, COP_PCM, &result);
3189 0 : if (err)
3190 0 : return err;
3191 0 : this->d.audio.bits_rates = result;
3192 : }
3193 : } else {
3194 0 : this->d.audio.encodings =
3195 0 : codec->w[codec->audiofunc].d.audio.encodings;
3196 0 : this->d.audio.bits_rates =
3197 0 : codec->w[codec->audiofunc].d.audio.bits_rates;
3198 : }
3199 0 : return 0;
3200 0 : }
3201 :
3202 : int
3203 0 : azalia_widget_init_pin(widget_t *this, const codec_t *codec)
3204 : {
3205 0 : uint32_t result, dir;
3206 : int err;
3207 :
3208 0 : err = azalia_comresp(codec, this->nid, CORB_GET_CONFIGURATION_DEFAULT,
3209 : 0, &result);
3210 0 : if (err)
3211 0 : return err;
3212 0 : this->d.pin.config = result;
3213 0 : this->d.pin.sequence = CORB_CD_SEQUENCE(result);
3214 0 : this->d.pin.association = CORB_CD_ASSOCIATION(result);
3215 0 : this->d.pin.color = CORB_CD_COLOR(result);
3216 0 : this->d.pin.device = CORB_CD_DEVICE(result);
3217 :
3218 0 : err = azalia_comresp(codec, this->nid, CORB_GET_PARAMETER,
3219 : COP_PINCAP, &result);
3220 0 : if (err)
3221 0 : return err;
3222 0 : this->d.pin.cap = result;
3223 :
3224 : dir = CORB_PWC_INPUT;
3225 0 : switch (this->d.pin.device) {
3226 : case CORB_CD_LINEOUT:
3227 : case CORB_CD_SPEAKER:
3228 : case CORB_CD_HEADPHONE:
3229 : case CORB_CD_SPDIFOUT:
3230 : case CORB_CD_DIGITALOUT:
3231 : dir = CORB_PWC_OUTPUT;
3232 0 : break;
3233 : }
3234 :
3235 0 : if (dir == CORB_PWC_INPUT && !(this->d.pin.cap & COP_PINCAP_INPUT))
3236 0 : dir = CORB_PWC_OUTPUT;
3237 0 : if (dir == CORB_PWC_OUTPUT && !(this->d.pin.cap & COP_PINCAP_OUTPUT))
3238 0 : dir = CORB_PWC_INPUT;
3239 :
3240 0 : if (dir == CORB_PWC_INPUT && this->d.pin.device == CORB_CD_MICIN) {
3241 0 : if (COP_PINCAP_VREF(this->d.pin.cap) & (1 << CORB_PWC_VREF_80))
3242 0 : dir |= CORB_PWC_VREF_80;
3243 0 : else if (COP_PINCAP_VREF(this->d.pin.cap) &
3244 : (1 << CORB_PWC_VREF_50))
3245 0 : dir |= CORB_PWC_VREF_50;
3246 : }
3247 :
3248 0 : if ((codec->qrks & AZ_QRK_WID_OVREF50) && (dir == CORB_PWC_OUTPUT))
3249 0 : dir |= CORB_PWC_VREF_50;
3250 :
3251 0 : azalia_comresp(codec, this->nid, CORB_SET_PIN_WIDGET_CONTROL,
3252 : dir, NULL);
3253 :
3254 0 : if (this->d.pin.cap & COP_PINCAP_EAPD) {
3255 0 : err = azalia_comresp(codec, this->nid,
3256 : CORB_GET_EAPD_BTL_ENABLE, 0, &result);
3257 0 : if (err)
3258 0 : return err;
3259 0 : result &= 0xff;
3260 0 : result |= CORB_EAPD_EAPD;
3261 0 : err = azalia_comresp(codec, this->nid,
3262 : CORB_SET_EAPD_BTL_ENABLE, result, &result);
3263 0 : if (err)
3264 0 : return err;
3265 : }
3266 :
3267 : /* Disable unconnected pins */
3268 0 : if (CORB_CD_PORT(this->d.pin.config) == CORB_CD_NONE)
3269 0 : this->enable = 0;
3270 :
3271 0 : return 0;
3272 0 : }
3273 :
3274 : int
3275 0 : azalia_widget_init_connection(widget_t *this, const codec_t *codec)
3276 : {
3277 0 : uint32_t result;
3278 : int err;
3279 : int i, j, k;
3280 : int length, nconn, bits, conn, last;
3281 :
3282 0 : this->selected = -1;
3283 0 : if ((this->widgetcap & COP_AWCAP_CONNLIST) == 0)
3284 0 : return 0;
3285 :
3286 0 : err = azalia_comresp(codec, this->nid, CORB_GET_PARAMETER,
3287 : COP_CONNECTION_LIST_LENGTH, &result);
3288 0 : if (err)
3289 0 : return err;
3290 :
3291 : bits = 8;
3292 0 : if (result & COP_CLL_LONG)
3293 : bits = 16;
3294 :
3295 0 : length = COP_CLL_LENGTH(result);
3296 0 : if (length == 0)
3297 0 : return 0;
3298 :
3299 : /*
3300 : * 'length' is the number of entries, not the number of
3301 : * connections. Find the number of connections, 'nconn', so
3302 : * enough space can be allocated for the list of connected
3303 : * nids.
3304 : */
3305 : nconn = last = 0;
3306 0 : for (i = 0; i < length;) {
3307 0 : err = azalia_comresp(codec, this->nid,
3308 : CORB_GET_CONNECTION_LIST_ENTRY, i, &result);
3309 0 : if (err)
3310 0 : return err;
3311 0 : for (k = 0; i < length && (k < 32 / bits); k++) {
3312 0 : conn = (result >> (k * bits)) & ((1 << bits) - 1);
3313 : /* If high bit is set, this is the end of a continuous
3314 : * list that started with the last connection.
3315 : */
3316 0 : if ((nconn > 0) && (conn & (1 << (bits - 1))))
3317 0 : nconn += (conn & ~(1 << (bits - 1))) - last;
3318 : else
3319 0 : nconn++;
3320 : last = conn;
3321 0 : i++;
3322 : }
3323 : }
3324 :
3325 0 : this->connections = mallocarray(nconn, sizeof(nid_t), M_DEVBUF, M_NOWAIT);
3326 0 : if (this->connections == NULL) {
3327 0 : printf("%s: out of memory\n", XNAME(codec->az));
3328 0 : return ENOMEM;
3329 : }
3330 0 : for (i = 0; i < nconn;) {
3331 0 : err = azalia_comresp(codec, this->nid,
3332 : CORB_GET_CONNECTION_LIST_ENTRY, i, &result);
3333 0 : if (err)
3334 0 : return err;
3335 0 : for (k = 0; i < nconn && (k < 32 / bits); k++) {
3336 0 : conn = (result >> (k * bits)) & ((1 << bits) - 1);
3337 : /* If high bit is set, this is the end of a continuous
3338 : * list that started with the last connection.
3339 : */
3340 0 : if ((i > 0) && (conn & (1 << (bits - 1)))) {
3341 0 : for (j = 1; i < nconn && j <= conn - last; j++)
3342 0 : this->connections[i++] = last + j;
3343 : } else {
3344 0 : this->connections[i++] = conn;
3345 : }
3346 : last = conn;
3347 : }
3348 : }
3349 0 : this->nconnections = nconn;
3350 :
3351 0 : if (nconn > 0) {
3352 0 : err = azalia_comresp(codec, this->nid,
3353 : CORB_GET_CONNECTION_SELECT_CONTROL, 0, &result);
3354 0 : if (err)
3355 0 : return err;
3356 0 : this->selected = CORB_CSC_INDEX(result);
3357 0 : }
3358 0 : return 0;
3359 0 : }
3360 :
3361 : int
3362 0 : azalia_widget_check_conn(codec_t *codec, int index, int depth)
3363 : {
3364 : const widget_t *w;
3365 : int i;
3366 :
3367 0 : w = &codec->w[index];
3368 :
3369 0 : if (w->type == COP_AWTYPE_BEEP_GENERATOR)
3370 0 : return 0;
3371 :
3372 0 : if (depth > 0 &&
3373 0 : (w->type == COP_AWTYPE_PIN_COMPLEX ||
3374 0 : w->type == COP_AWTYPE_AUDIO_OUTPUT ||
3375 0 : w->type == COP_AWTYPE_AUDIO_INPUT)) {
3376 0 : if (w->enable)
3377 0 : return 1;
3378 : else
3379 0 : return 0;
3380 : }
3381 0 : if (++depth >= 10)
3382 0 : return 0;
3383 0 : for (i = 0; i < w->nconnections; i++) {
3384 0 : if (!azalia_widget_enabled(codec, w->connections[i]))
3385 : continue;
3386 0 : if (azalia_widget_check_conn(codec, w->connections[i], depth))
3387 0 : return 1;
3388 : }
3389 0 : return 0;
3390 0 : }
3391 :
3392 : #ifdef AZALIA_DEBUG
3393 :
3394 : #define WIDGETCAP_BITS \
3395 : "\20\014LRSWAP\013POWER\012DIGITAL" \
3396 : "\011CONNLIST\010UNSOL\07PROC\06STRIPE\05FORMATOV\04AMPOV\03OUTAMP" \
3397 : "\02INAMP\01STEREO"
3398 :
3399 : #define PINCAP_BITS "\20\021EAPD\16VREF100\15VREF80" \
3400 : "\13VREFGND\12VREF50\11VREFHIZ\07BALANCE\06INPUT" \
3401 : "\05OUTPUT\04HEADPHONE\03PRESENCE\02TRIGGER\01IMPEDANCE"
3402 :
3403 : #define ENCODING_BITS "\20\3AC3\2FLOAT32\1PCM"
3404 :
3405 : #define BITSRATES_BITS "\20\x15""32bit\x14""24bit\x13""20bit" \
3406 : "\x12""16bit\x11""8bit""\x0c""384kHz\x0b""192kHz\x0a""176.4kHz" \
3407 : "\x09""96kHz\x08""88.2kHz\x07""48kHz\x06""44.1kHz\x05""32kHz\x04" \
3408 : "22.05kHz\x03""16kHz\x02""11.025kHz\x01""8kHz"
3409 :
3410 : static const char *pin_colors[16] = {
3411 : "unknown", "black", "gray", "blue",
3412 : "green", "red", "orange", "yellow",
3413 : "purple", "pink", "col0a", "col0b",
3414 : "col0c", "col0d", "white", "other"};
3415 : static const char *pin_conn[4] = {
3416 : "jack", "none", "fixed", "combined"};
3417 : static const char *pin_conntype[16] = {
3418 : "unknown", "1/8", "1/4", "atapi", "rca", "optical",
3419 : "digital", "analog", "din", "xlr", "rj-11", "combination",
3420 : "con0c", "con0d", "con0e", "other"};
3421 : static const char *pin_geo[15] = {
3422 : "n/a", "rear", "front", "left",
3423 : "right", "top", "bottom", "spec0", "spec1", "spec2",
3424 : "loc0a", "loc0b", "loc0c", "loc0d", "loc0f"};
3425 : static const char *pin_chass[4] = {
3426 : "external", "internal", "separate", "other"};
3427 :
3428 : void
3429 : azalia_codec_print_audiofunc(const codec_t *this)
3430 : {
3431 : uint32_t result;
3432 :
3433 : azalia_widget_print_audio(&this->w[this->audiofunc], "\t");
3434 :
3435 : result = this->w[this->audiofunc].inamp_cap;
3436 : DPRINTF(("\tinamp: mute=%u size=%u steps=%u offset=%u\n",
3437 : (result & COP_AMPCAP_MUTE) != 0, COP_AMPCAP_STEPSIZE(result),
3438 : COP_AMPCAP_NUMSTEPS(result), COP_AMPCAP_OFFSET(result)));
3439 : result = this->w[this->audiofunc].outamp_cap;
3440 : DPRINTF(("\toutamp: mute=%u size=%u steps=%u offset=%u\n",
3441 : (result & COP_AMPCAP_MUTE) != 0, COP_AMPCAP_STEPSIZE(result),
3442 : COP_AMPCAP_NUMSTEPS(result), COP_AMPCAP_OFFSET(result)));
3443 : azalia_comresp(this, this->audiofunc, CORB_GET_PARAMETER,
3444 : COP_GPIO_COUNT, &result);
3445 : DPRINTF(("\tgpio: wake=%u unsol=%u gpis=%u gpos=%u gpios=%u\n",
3446 : (result & COP_GPIO_WAKE) != 0, (result & COP_GPIO_UNSOL) != 0,
3447 : COP_GPIO_GPIS(result), COP_GPIO_GPOS(result),
3448 : COP_GPIO_GPIOS(result)));
3449 : }
3450 :
3451 : void
3452 : azalia_codec_print_groups(const codec_t *this)
3453 : {
3454 : int i, n;
3455 :
3456 : for (i = 0; i < this->dacs.ngroups; i++) {
3457 : printf("%s: dacgroup[%d]:", XNAME(this->az), i);
3458 : for (n = 0; n < this->dacs.groups[i].nconv; n++) {
3459 : printf(" %2.2x", this->dacs.groups[i].conv[n]);
3460 : }
3461 : printf("\n");
3462 : }
3463 : for (i = 0; i < this->adcs.ngroups; i++) {
3464 : printf("%s: adcgroup[%d]:", XNAME(this->az), i);
3465 : for (n = 0; n < this->adcs.groups[i].nconv; n++) {
3466 : printf(" %2.2x", this->adcs.groups[i].conv[n]);
3467 : }
3468 : printf("\n");
3469 : }
3470 : }
3471 :
3472 : void
3473 : azalia_widget_print_audio(const widget_t *this, const char *lead)
3474 : {
3475 : printf("%sencodings=%b\n", lead, this->d.audio.encodings,
3476 : ENCODING_BITS);
3477 : printf("%sPCM formats=%b\n", lead, this->d.audio.bits_rates,
3478 : BITSRATES_BITS);
3479 : }
3480 :
3481 : void
3482 : azalia_widget_print_widget(const widget_t *w, const codec_t *codec)
3483 : {
3484 : int i;
3485 :
3486 : printf("%s: ", XNAME(codec->az));
3487 : printf("%s%2.2x wcap=%b\n", w->type == COP_AWTYPE_PIN_COMPLEX ?
3488 : pin_colors[w->d.pin.color] : wtypes[w->type],
3489 : w->nid, w->widgetcap, WIDGETCAP_BITS);
3490 : if (w->widgetcap & COP_AWCAP_FORMATOV)
3491 : azalia_widget_print_audio(w, "\t");
3492 : if (w->type == COP_AWTYPE_PIN_COMPLEX)
3493 : azalia_widget_print_pin(w);
3494 :
3495 : if (w->type == COP_AWTYPE_VOLUME_KNOB)
3496 : printf("\tdelta=%d steps=%d\n",
3497 : !!(w->d.volume.cap & COP_VKCAP_DELTA),
3498 : COP_VKCAP_NUMSTEPS(w->d.volume.cap));
3499 :
3500 : if ((w->widgetcap & COP_AWCAP_INAMP) &&
3501 : (w->widgetcap & COP_AWCAP_AMPOV))
3502 : printf("\tinamp: mute=%u size=%u steps=%u offset=%u\n",
3503 : (w->inamp_cap & COP_AMPCAP_MUTE) != 0,
3504 : COP_AMPCAP_STEPSIZE(w->inamp_cap),
3505 : COP_AMPCAP_NUMSTEPS(w->inamp_cap),
3506 : COP_AMPCAP_OFFSET(w->inamp_cap));
3507 :
3508 : if ((w->widgetcap & COP_AWCAP_OUTAMP) &&
3509 : (w->widgetcap & COP_AWCAP_AMPOV))
3510 : printf("\toutamp: mute=%u size=%u steps=%u offset=%u\n",
3511 : (w->outamp_cap & COP_AMPCAP_MUTE) != 0,
3512 : COP_AMPCAP_STEPSIZE(w->outamp_cap),
3513 : COP_AMPCAP_NUMSTEPS(w->outamp_cap),
3514 : COP_AMPCAP_OFFSET(w->outamp_cap));
3515 :
3516 : if (w->nconnections > 0) {
3517 : printf("\tconnections=0x%x", w->connections[0]);
3518 : for (i = 1; i < w->nconnections; i++)
3519 : printf(",0x%x", w->connections[i]);
3520 : printf("; selected=0x%x\n", w->connections[w->selected]);
3521 : }
3522 : }
3523 :
3524 : void
3525 : azalia_widget_print_pin(const widget_t *this)
3526 : {
3527 : printf("\tcap=%b\n", this->d.pin.cap, PINCAP_BITS);
3528 : printf("\t[%2.2d/%2.2d] ", CORB_CD_ASSOCIATION(this->d.pin.config),
3529 : CORB_CD_SEQUENCE(this->d.pin.config));
3530 : printf("color=%s ", pin_colors[CORB_CD_COLOR(this->d.pin.config)]);
3531 : printf("device=%s ", pin_devices[CORB_CD_DEVICE(this->d.pin.config)]);
3532 : printf("conn=%s ", pin_conn[CORB_CD_PORT(this->d.pin.config)]);
3533 : printf("conntype=%s\n", pin_conntype[CORB_CD_CONNECTION(this->d.pin.config)]);
3534 : printf("\tlocation=%s ", pin_geo[CORB_CD_LOC_GEO(this->d.pin.config)]);
3535 : printf("chassis=%s ", pin_chass[CORB_CD_LOC_CHASS(this->d.pin.config)]);
3536 : printf("special=");
3537 : if (CORB_CD_LOC_GEO(this->d.pin.config) == CORB_CD_LOC_SPEC0) {
3538 : if (CORB_CD_LOC_CHASS(this->d.pin.config) == CORB_CD_EXTERNAL)
3539 : printf("rear-panel");
3540 : else if (CORB_CD_LOC_CHASS(this->d.pin.config) == CORB_CD_INTERNAL)
3541 : printf("riser");
3542 : else if (CORB_CD_LOC_CHASS(this->d.pin.config) == CORB_CD_LOC_OTHER)
3543 : printf("mobile-lid-internal");
3544 : } else if (CORB_CD_LOC_GEO(this->d.pin.config) == CORB_CD_LOC_SPEC1) {
3545 : if (CORB_CD_LOC_CHASS(this->d.pin.config) == CORB_CD_EXTERNAL)
3546 : printf("drive-bay");
3547 : else if (CORB_CD_LOC_CHASS(this->d.pin.config) == CORB_CD_INTERNAL)
3548 : printf("hdmi");
3549 : else if (CORB_CD_LOC_CHASS(this->d.pin.config) == CORB_CD_LOC_OTHER)
3550 : printf("mobile-lid-external");
3551 : } else if (CORB_CD_LOC_GEO(this->d.pin.config) == CORB_CD_LOC_SPEC2) {
3552 : if (CORB_CD_LOC_CHASS(this->d.pin.config) == CORB_CD_INTERNAL)
3553 : printf("atapi");
3554 : } else
3555 : printf("none");
3556 : printf("\n");
3557 : }
3558 :
3559 : #else /* AZALIA_DEBUG */
3560 :
3561 : void
3562 0 : azalia_codec_print_audiofunc(const codec_t *this) {}
3563 :
3564 : void
3565 0 : azalia_codec_print_groups(const codec_t *this) {}
3566 :
3567 : void
3568 0 : azalia_widget_print_audio(const widget_t *this, const char *lead) {}
3569 :
3570 : void
3571 0 : azalia_widget_print_widget(const widget_t *w, const codec_t *codec) {}
3572 :
3573 : void
3574 0 : azalia_widget_print_pin(const widget_t *this) {}
3575 :
3576 : #endif /* AZALIA_DEBUG */
3577 :
3578 : /* ================================================================
3579 : * Stream functions
3580 : * ================================================================ */
3581 :
3582 : int
3583 0 : azalia_stream_init(stream_t *this, azalia_t *az, int regindex, int strnum,
3584 : int dir)
3585 : {
3586 : int err;
3587 :
3588 0 : this->az = az;
3589 0 : this->regbase = HDA_SD_BASE + regindex * HDA_SD_SIZE;
3590 0 : this->intr_bit = 1 << regindex;
3591 0 : this->number = strnum;
3592 0 : this->dir = dir;
3593 :
3594 : /* setup BDL buffers */
3595 0 : err = azalia_alloc_dmamem(az, sizeof(bdlist_entry_t) * HDA_BDL_MAX,
3596 0 : 128, &this->bdlist);
3597 0 : if (err) {
3598 0 : printf("%s: can't allocate a BDL buffer\n", XNAME(az));
3599 0 : return err;
3600 : }
3601 0 : return 0;
3602 0 : }
3603 :
3604 : int
3605 0 : azalia_stream_reset(stream_t *this)
3606 : {
3607 : int i;
3608 : uint16_t ctl;
3609 : uint8_t sts;
3610 :
3611 : /* Make sure RUN bit is zero before resetting */
3612 0 : ctl = STR_READ_2(this, CTL);
3613 0 : ctl &= ~HDA_SD_CTL_RUN;
3614 0 : STR_WRITE_2(this, CTL, ctl);
3615 0 : DELAY(40);
3616 :
3617 : /* Start reset and wait for chip to enter. */
3618 0 : ctl = STR_READ_2(this, CTL);
3619 0 : STR_WRITE_2(this, CTL, ctl | HDA_SD_CTL_SRST);
3620 0 : for (i = 5000; i > 0; i--) {
3621 0 : DELAY(10);
3622 0 : ctl = STR_READ_2(this, CTL);
3623 0 : if (ctl & HDA_SD_CTL_SRST)
3624 : break;
3625 : }
3626 0 : if (i == 0) {
3627 : DPRINTF(("%s: stream reset failure 1\n", XNAME(this->az)));
3628 0 : return -1;
3629 : }
3630 :
3631 : /* Clear reset and wait for chip to finish */
3632 0 : STR_WRITE_2(this, CTL, ctl & ~HDA_SD_CTL_SRST);
3633 0 : for (i = 5000; i > 0; i--) {
3634 0 : DELAY(10);
3635 0 : ctl = STR_READ_2(this, CTL);
3636 0 : if ((ctl & HDA_SD_CTL_SRST) == 0)
3637 : break;
3638 : }
3639 0 : if (i == 0) {
3640 : DPRINTF(("%s: stream reset failure 2\n", XNAME(this->az)));
3641 0 : return -1;
3642 : }
3643 :
3644 0 : sts = STR_READ_1(this, STS);
3645 0 : sts |= HDA_SD_STS_DESE | HDA_SD_STS_FIFOE | HDA_SD_STS_BCIS;
3646 0 : STR_WRITE_1(this, STS, sts);
3647 :
3648 0 : return (0);
3649 0 : }
3650 :
3651 : int
3652 0 : azalia_stream_start(stream_t *this)
3653 : {
3654 : bdlist_entry_t *bdlist;
3655 : bus_addr_t dmaaddr, dmaend;
3656 : int err, index;
3657 : uint32_t intctl;
3658 : uint8_t ctl2;
3659 :
3660 0 : err = azalia_stream_reset(this);
3661 0 : if (err) {
3662 : DPRINTF(("%s: stream reset failed\n", "azalia"));
3663 0 : return err;
3664 : }
3665 :
3666 0 : STR_WRITE_4(this, BDPL, 0);
3667 0 : STR_WRITE_4(this, BDPU, 0);
3668 :
3669 : /* setup BDL */
3670 0 : dmaaddr = AZALIA_DMA_DMAADDR(&this->buffer);
3671 0 : dmaend = dmaaddr + this->bufsize;
3672 0 : bdlist = (bdlist_entry_t*)this->bdlist.addr;
3673 0 : for (index = 0; index < HDA_BDL_MAX; index++) {
3674 0 : bdlist[index].low = htole32(dmaaddr);
3675 0 : bdlist[index].high = htole32(PTR_UPPER32(dmaaddr));
3676 0 : bdlist[index].length = htole32(this->blk);
3677 0 : bdlist[index].flags = htole32(BDLIST_ENTRY_IOC);
3678 0 : dmaaddr += this->blk;
3679 0 : if (dmaaddr >= dmaend) {
3680 : index++;
3681 : break;
3682 : }
3683 : }
3684 :
3685 : DPRINTFN(1, ("%s: size=%d fmt=0x%4.4x index=%d\n",
3686 : __func__, this->bufsize, this->fmt, index));
3687 :
3688 0 : dmaaddr = AZALIA_DMA_DMAADDR(&this->bdlist);
3689 0 : STR_WRITE_4(this, BDPL, dmaaddr);
3690 0 : STR_WRITE_4(this, BDPU, PTR_UPPER32(dmaaddr));
3691 0 : STR_WRITE_2(this, LVI, (index - 1) & HDA_SD_LVI_LVI);
3692 0 : ctl2 = STR_READ_1(this, CTL2);
3693 0 : STR_WRITE_1(this, CTL2,
3694 : (ctl2 & ~HDA_SD_CTL2_STRM) | (this->number << HDA_SD_CTL2_STRM_SHIFT));
3695 0 : STR_WRITE_4(this, CBL, this->bufsize);
3696 0 : STR_WRITE_2(this, FMT, this->fmt);
3697 :
3698 0 : err = azalia_codec_connect_stream(this);
3699 0 : if (err)
3700 0 : return EINVAL;
3701 :
3702 0 : intctl = AZ_READ_4(this->az, INTCTL);
3703 0 : intctl |= this->intr_bit;
3704 0 : AZ_WRITE_4(this->az, INTCTL, intctl);
3705 :
3706 0 : STR_WRITE_1(this, CTL, STR_READ_1(this, CTL) |
3707 : HDA_SD_CTL_DEIE | HDA_SD_CTL_FEIE | HDA_SD_CTL_IOCE |
3708 : HDA_SD_CTL_RUN);
3709 0 : return (0);
3710 0 : }
3711 :
3712 : int
3713 0 : azalia_stream_halt(stream_t *this)
3714 : {
3715 : uint16_t ctl;
3716 :
3717 0 : ctl = STR_READ_2(this, CTL);
3718 0 : ctl &= ~(HDA_SD_CTL_DEIE | HDA_SD_CTL_FEIE | HDA_SD_CTL_IOCE | HDA_SD_CTL_RUN);
3719 0 : STR_WRITE_2(this, CTL, ctl);
3720 0 : AZ_WRITE_4(this->az, INTCTL,
3721 : AZ_READ_4(this->az, INTCTL) & ~this->intr_bit);
3722 0 : azalia_codec_disconnect_stream(this);
3723 :
3724 0 : return (0);
3725 : }
3726 :
3727 : #define HDA_SD_STS_BITS "\20\3BCIS\4FIFOE\5DESE\6FIFORDY"
3728 :
3729 : int
3730 0 : azalia_stream_intr(stream_t *this)
3731 : {
3732 : unsigned int lpib, fifos, hwpos, cnt;
3733 : u_int8_t sts;
3734 :
3735 0 : sts = STR_READ_1(this, STS);
3736 0 : STR_WRITE_1(this, STS, sts |
3737 : HDA_SD_STS_DESE | HDA_SD_STS_FIFOE | HDA_SD_STS_BCIS);
3738 :
3739 0 : if (sts & (HDA_SD_STS_DESE | HDA_SD_STS_FIFOE))
3740 : DPRINTF(("%s: stream %d: sts=%b\n", XNAME(this->az),
3741 : this->number, sts, HDA_SD_STS_BITS));
3742 :
3743 0 : if (sts & HDA_SD_STS_BCIS) {
3744 0 : lpib = STR_READ_4(this, LPIB);
3745 0 : fifos = STR_READ_2(this, FIFOS);
3746 0 : if (fifos & 1)
3747 0 : fifos++;
3748 : hwpos = lpib;
3749 0 : if (this->dir == AUMODE_PLAY)
3750 0 : hwpos += fifos + 1;
3751 0 : if (hwpos >= this->bufsize)
3752 0 : hwpos -= this->bufsize;
3753 : DPRINTFN(2, ("%s: stream %d, pos = %d -> %d, "
3754 : "lpib = %u, fifos = %u\n", __func__,
3755 : this->number, this->swpos, hwpos, lpib, fifos));
3756 : cnt = 0;
3757 0 : while (hwpos - this->swpos >= this->blk) {
3758 0 : this->intr(this->intr_arg);
3759 0 : this->swpos += this->blk;
3760 0 : if (this->swpos == this->bufsize)
3761 0 : this->swpos = 0;
3762 0 : cnt++;
3763 : }
3764 : if (cnt != 1) {
3765 : DPRINTF(("%s: stream %d: hwpos %u, %u intrs\n",
3766 : __func__, this->number, this->swpos, cnt));
3767 : }
3768 0 : }
3769 0 : return (1);
3770 : }
3771 :
3772 : /* ================================================================
3773 : * MI audio entries
3774 : * ================================================================ */
3775 :
3776 : int
3777 0 : azalia_open(void *v, int flags)
3778 : {
3779 : azalia_t *az;
3780 : codec_t *codec;
3781 :
3782 : DPRINTFN(1, ("%s: flags=0x%x\n", __func__, flags));
3783 0 : az = v;
3784 0 : codec = &az->codecs[az->codecno];
3785 0 : if ((flags & FWRITE) && codec->dacs.ngroups == 0)
3786 0 : return ENODEV;
3787 0 : if ((flags & FREAD) && codec->adcs.ngroups == 0)
3788 0 : return ENODEV;
3789 0 : codec->running++;
3790 0 : return 0;
3791 0 : }
3792 :
3793 : void
3794 0 : azalia_close(void *v)
3795 : {
3796 : azalia_t *az;
3797 : codec_t *codec;
3798 :
3799 : DPRINTFN(1, ("%s\n", __func__));
3800 0 : az = v;
3801 0 : codec = &az->codecs[az->codecno];
3802 0 : codec->running--;
3803 0 : }
3804 :
3805 : int
3806 0 : azalia_match_format(codec_t *codec, int mode, audio_params_t *par)
3807 : {
3808 : int i;
3809 :
3810 : DPRINTFN(1, ("%s: mode=%d, want: enc=%d, prec=%d, chans=%d\n", __func__,
3811 : mode, par->encoding, par->precision, par->channels));
3812 :
3813 0 : for (i = 0; i < codec->nformats; i++) {
3814 0 : if (mode != codec->formats[i].mode)
3815 : continue;
3816 0 : if (par->encoding != codec->formats[i].encoding)
3817 : continue;
3818 0 : if (par->precision != codec->formats[i].precision)
3819 : continue;
3820 0 : if (par->channels != codec->formats[i].channels)
3821 : continue;
3822 : break;
3823 : }
3824 :
3825 : DPRINTFN(1, ("%s: return: enc=%d, prec=%d, chans=%d\n", __func__,
3826 : codec->formats[i].encoding, codec->formats[i].precision,
3827 : codec->formats[i].channels));
3828 :
3829 0 : return (i);
3830 : }
3831 :
3832 : int
3833 0 : azalia_set_params_sub(codec_t *codec, int mode, audio_params_t *par)
3834 : {
3835 : int i, j;
3836 : uint ochan, oenc, opre;
3837 : #ifdef AZALIA_DEBUG
3838 : char *cmode = (mode == AUMODE_PLAY) ? "play" : "record";
3839 : #endif
3840 :
3841 0 : ochan = par->channels;
3842 0 : oenc = par->encoding;
3843 0 : opre = par->precision;
3844 :
3845 0 : if ((mode == AUMODE_PLAY && codec->dacs.ngroups == 0) ||
3846 0 : (mode == AUMODE_RECORD && codec->adcs.ngroups == 0))
3847 0 : return 0;
3848 :
3849 0 : i = azalia_match_format(codec, mode, par);
3850 0 : if (i == codec->nformats && (par->precision != 16 || par->encoding !=
3851 : AUDIO_ENCODING_SLINEAR_LE)) {
3852 : /* try with default encoding/precision */
3853 0 : par->encoding = AUDIO_ENCODING_SLINEAR_LE;
3854 0 : par->precision = 16;
3855 0 : i = azalia_match_format(codec, mode, par);
3856 0 : }
3857 0 : if (i == codec->nformats && par->channels != 2) {
3858 : /* try with default channels */
3859 0 : par->encoding = oenc;
3860 0 : par->precision = opre;
3861 0 : par->channels = 2;
3862 0 : i = azalia_match_format(codec, mode, par);
3863 0 : }
3864 : /* try with default everything */
3865 0 : if (i == codec->nformats) {
3866 0 : par->encoding = AUDIO_ENCODING_SLINEAR_LE;
3867 0 : par->precision = 16;
3868 0 : par->channels = 2;
3869 0 : i = azalia_match_format(codec, mode, par);
3870 0 : if (i == codec->nformats) {
3871 : DPRINTF(("%s: can't find %s format %u/%u/%u\n",
3872 : __func__, cmode, par->encoding,
3873 : par->precision, par->channels));
3874 0 : return EINVAL;
3875 : }
3876 : }
3877 0 : if (codec->formats[i].frequency_type == 0) {
3878 : DPRINTF(("%s: matched %s format %d has 0 frequencies\n",
3879 : __func__, cmode, i));
3880 0 : return EINVAL;
3881 : }
3882 :
3883 0 : for (j = 0; j < codec->formats[i].frequency_type; j++) {
3884 0 : if (par->sample_rate != codec->formats[i].frequency[j])
3885 : continue;
3886 : break;
3887 : }
3888 0 : if (j == codec->formats[i].frequency_type) {
3889 : /* try again with default */
3890 0 : par->sample_rate = 48000;
3891 0 : for (j = 0; j < codec->formats[i].frequency_type; j++) {
3892 0 : if (par->sample_rate != codec->formats[i].frequency[j])
3893 : continue;
3894 : break;
3895 : }
3896 0 : if (j == codec->formats[i].frequency_type) {
3897 : DPRINTF(("%s: can't find %s rate %lu\n",
3898 : __func__, cmode, par->sample_rate));
3899 0 : return EINVAL;
3900 : }
3901 : }
3902 0 : par->bps = AUDIO_BPS(par->precision);
3903 0 : par->msb = 1;
3904 :
3905 0 : return (0);
3906 0 : }
3907 :
3908 : int
3909 0 : azalia_set_params(void *v, int smode, int umode, audio_params_t *p,
3910 : audio_params_t *r)
3911 : {
3912 : azalia_t *az;
3913 : codec_t *codec;
3914 : int ret;
3915 :
3916 0 : az = v;
3917 0 : codec = &az->codecs[az->codecno];
3918 0 : if (codec->nformats == 0) {
3919 : DPRINTF(("%s: codec has no formats\n", __func__));
3920 0 : return EINVAL;
3921 : }
3922 :
3923 0 : if (smode & AUMODE_RECORD && r != NULL) {
3924 0 : ret = azalia_set_params_sub(codec, AUMODE_RECORD, r);
3925 0 : if (ret)
3926 0 : return (ret);
3927 : }
3928 :
3929 0 : if (smode & AUMODE_PLAY && p != NULL) {
3930 0 : ret = azalia_set_params_sub(codec, AUMODE_PLAY, p);
3931 0 : if (ret)
3932 0 : return (ret);
3933 : }
3934 :
3935 0 : return (0);
3936 0 : }
3937 :
3938 : int
3939 0 : azalia_round_blocksize(void *v, int blk)
3940 : {
3941 : azalia_t *az;
3942 : size_t size;
3943 :
3944 0 : blk &= ~0x7f; /* must be multiple of 128 */
3945 0 : if (blk <= 0)
3946 : blk = 128;
3947 : /* number of blocks must be <= HDA_BDL_MAX */
3948 0 : az = v;
3949 0 : size = az->pstream.buffer.size;
3950 0 : if (size > HDA_BDL_MAX * blk) {
3951 0 : blk = size / HDA_BDL_MAX;
3952 0 : if (blk & 0x7f)
3953 0 : blk = (blk + 0x7f) & ~0x7f;
3954 : }
3955 : DPRINTFN(1,("%s: resultant block size = %d\n", __func__, blk));
3956 0 : return blk;
3957 : }
3958 :
3959 : int
3960 0 : azalia_halt_output(void *v)
3961 : {
3962 : azalia_t *az;
3963 :
3964 : DPRINTFN(1, ("%s\n", __func__));
3965 0 : az = v;
3966 0 : return azalia_stream_halt(&az->pstream);
3967 : }
3968 :
3969 : int
3970 0 : azalia_halt_input(void *v)
3971 : {
3972 : azalia_t *az;
3973 :
3974 : DPRINTFN(1, ("%s\n", __func__));
3975 0 : az = v;
3976 0 : return azalia_stream_halt(&az->rstream);
3977 : }
3978 :
3979 : int
3980 0 : azalia_set_port(void *v, mixer_ctrl_t *mc)
3981 : {
3982 : azalia_t *az;
3983 : codec_t *co;
3984 : const mixer_item_t *m;
3985 :
3986 0 : az = v;
3987 0 : co = &az->codecs[az->codecno];
3988 0 : if (mc->dev < 0 || mc->dev >= co->nmixers)
3989 0 : return EINVAL;
3990 :
3991 0 : m = &co->mixers[mc->dev];
3992 0 : if (mc->type != m->devinfo.type)
3993 0 : return EINVAL;
3994 :
3995 0 : return azalia_mixer_set(co, m->nid, m->target, mc);
3996 0 : }
3997 :
3998 : int
3999 0 : azalia_get_port(void *v, mixer_ctrl_t *mc)
4000 : {
4001 : azalia_t *az;
4002 : codec_t *co;
4003 : const mixer_item_t *m;
4004 :
4005 0 : az = v;
4006 0 : co = &az->codecs[az->codecno];
4007 0 : if (mc->dev < 0 || mc->dev >= co->nmixers)
4008 0 : return EINVAL;
4009 :
4010 0 : m = &co->mixers[mc->dev];
4011 0 : mc->type = m->devinfo.type;
4012 :
4013 0 : return azalia_mixer_get(co, m->nid, m->target, mc);
4014 0 : }
4015 :
4016 : int
4017 0 : azalia_query_devinfo(void *v, mixer_devinfo_t *mdev)
4018 : {
4019 : azalia_t *az;
4020 : const codec_t *co;
4021 :
4022 0 : az = v;
4023 0 : co = &az->codecs[az->codecno];
4024 0 : if (mdev->index < 0 || mdev->index >= co->nmixers)
4025 0 : return ENXIO;
4026 0 : *mdev = co->mixers[mdev->index].devinfo;
4027 0 : return 0;
4028 0 : }
4029 :
4030 : void *
4031 0 : azalia_allocm(void *v, int dir, size_t size, int pool, int flags)
4032 : {
4033 : azalia_t *az;
4034 : stream_t *stream;
4035 : int err;
4036 :
4037 0 : az = v;
4038 0 : stream = dir == AUMODE_PLAY ? &az->pstream : &az->rstream;
4039 0 : err = azalia_alloc_dmamem(az, size, 128, &stream->buffer);
4040 0 : if (err) {
4041 0 : printf("%s: allocm failed\n", az->dev.dv_xname);
4042 0 : return NULL;
4043 : }
4044 0 : return stream->buffer.addr;
4045 0 : }
4046 :
4047 : void
4048 0 : azalia_freem(void *v, void *addr, int pool)
4049 : {
4050 : azalia_t *az;
4051 : stream_t *stream;
4052 :
4053 0 : az = v;
4054 0 : if (addr == az->pstream.buffer.addr) {
4055 : stream = &az->pstream;
4056 0 : } else if (addr == az->rstream.buffer.addr) {
4057 : stream = &az->rstream;
4058 : } else {
4059 0 : return;
4060 : }
4061 0 : azalia_free_dmamem(az, &stream->buffer);
4062 0 : }
4063 :
4064 : size_t
4065 0 : azalia_round_buffersize(void *v, int dir, size_t size)
4066 : {
4067 0 : size &= ~0x7f; /* must be multiple of 128 */
4068 0 : if (size <= 0)
4069 : size = 128;
4070 0 : return size;
4071 : }
4072 :
4073 : int
4074 0 : azalia_get_props(void *v)
4075 : {
4076 0 : return AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
4077 : }
4078 :
4079 : int
4080 0 : azalia_trigger_output(void *v, void *start, void *end, int blk,
4081 : void (*intr)(void *), void *arg, audio_params_t *param)
4082 : {
4083 : azalia_t *az;
4084 : int err;
4085 0 : uint16_t fmt;
4086 :
4087 0 : az = v;
4088 :
4089 0 : if (az->codecs[az->codecno].dacs.ngroups == 0) {
4090 : DPRINTF(("%s: can't play without a DAC\n", __func__));
4091 0 : return ENXIO;
4092 : }
4093 :
4094 0 : err = azalia_params2fmt(param, &fmt);
4095 0 : if (err)
4096 0 : return(EINVAL);
4097 :
4098 0 : az->pstream.bufsize = (caddr_t)end - (caddr_t)start;
4099 0 : az->pstream.blk = blk;
4100 0 : az->pstream.fmt = fmt;
4101 0 : az->pstream.intr = intr;
4102 0 : az->pstream.intr_arg = arg;
4103 0 : az->pstream.swpos = 0;
4104 :
4105 0 : return azalia_stream_start(&az->pstream);
4106 0 : }
4107 :
4108 : int
4109 0 : azalia_trigger_input(void *v, void *start, void *end, int blk,
4110 : void (*intr)(void *), void *arg, audio_params_t *param)
4111 : {
4112 : azalia_t *az;
4113 : int err;
4114 0 : uint16_t fmt;
4115 :
4116 : DPRINTFN(1, ("%s: this=%p start=%p end=%p blk=%d {enc=%u %uch %ubit %luHz}\n",
4117 : __func__, v, start, end, blk, param->encoding, param->channels,
4118 : param->precision, param->sample_rate));
4119 :
4120 0 : az = v;
4121 :
4122 0 : if (az->codecs[az->codecno].adcs.ngroups == 0) {
4123 : DPRINTF(("%s: can't record without an ADC\n", __func__));
4124 0 : return ENXIO;
4125 : }
4126 :
4127 0 : err = azalia_params2fmt(param, &fmt);
4128 0 : if (err)
4129 0 : return(EINVAL);
4130 :
4131 0 : az->rstream.bufsize = (caddr_t)end - (caddr_t)start;
4132 0 : az->rstream.blk = blk;
4133 0 : az->rstream.fmt = fmt;
4134 0 : az->rstream.intr = intr;
4135 0 : az->rstream.intr_arg = arg;
4136 0 : az->rstream.swpos = 0;
4137 :
4138 0 : return azalia_stream_start(&az->rstream);
4139 0 : }
4140 :
4141 : /* --------------------------------
4142 : * helpers for MI audio functions
4143 : * -------------------------------- */
4144 : int
4145 0 : azalia_params2fmt(const audio_params_t *param, uint16_t *fmt)
4146 : {
4147 : uint16_t ret;
4148 :
4149 : ret = 0;
4150 0 : if (param->channels > HDA_MAX_CHANNELS) {
4151 0 : printf("%s: too many channels: %u\n", __func__,
4152 : param->channels);
4153 0 : return EINVAL;
4154 : }
4155 :
4156 : DPRINTFN(1, ("%s: prec=%d, chan=%d, rate=%ld\n", __func__,
4157 : param->precision, param->channels, param->sample_rate));
4158 :
4159 : /* XXX: can channels be >2 ? */
4160 0 : ret |= param->channels - 1;
4161 :
4162 0 : switch (param->precision) {
4163 : case 8:
4164 0 : ret |= HDA_SD_FMT_BITS_8_16;
4165 0 : break;
4166 : case 16:
4167 0 : ret |= HDA_SD_FMT_BITS_16_16;
4168 0 : break;
4169 : case 20:
4170 0 : ret |= HDA_SD_FMT_BITS_20_32;
4171 0 : break;
4172 : case 24:
4173 0 : ret |= HDA_SD_FMT_BITS_24_32;
4174 0 : break;
4175 : case 32:
4176 0 : ret |= HDA_SD_FMT_BITS_32_32;
4177 0 : break;
4178 : }
4179 :
4180 0 : switch (param->sample_rate) {
4181 : default:
4182 : case 384000:
4183 0 : printf("%s: invalid sample_rate: %lu\n", __func__,
4184 : param->sample_rate);
4185 0 : return EINVAL;
4186 : case 192000:
4187 0 : ret |= HDA_SD_FMT_BASE_48 | HDA_SD_FMT_MULT_X4 | HDA_SD_FMT_DIV_BY1;
4188 0 : break;
4189 : case 176400:
4190 0 : ret |= HDA_SD_FMT_BASE_44 | HDA_SD_FMT_MULT_X4 | HDA_SD_FMT_DIV_BY1;
4191 0 : break;
4192 : case 96000:
4193 0 : ret |= HDA_SD_FMT_BASE_48 | HDA_SD_FMT_MULT_X2 | HDA_SD_FMT_DIV_BY1;
4194 0 : break;
4195 : case 88200:
4196 0 : ret |= HDA_SD_FMT_BASE_44 | HDA_SD_FMT_MULT_X2 | HDA_SD_FMT_DIV_BY1;
4197 0 : break;
4198 : case 48000:
4199 0 : ret |= HDA_SD_FMT_BASE_48 | HDA_SD_FMT_MULT_X1 | HDA_SD_FMT_DIV_BY1;
4200 0 : break;
4201 : case 44100:
4202 0 : ret |= HDA_SD_FMT_BASE_44 | HDA_SD_FMT_MULT_X1 | HDA_SD_FMT_DIV_BY1;
4203 0 : break;
4204 : case 32000:
4205 0 : ret |= HDA_SD_FMT_BASE_48 | HDA_SD_FMT_MULT_X2 | HDA_SD_FMT_DIV_BY3;
4206 0 : break;
4207 : case 22050:
4208 0 : ret |= HDA_SD_FMT_BASE_44 | HDA_SD_FMT_MULT_X1 | HDA_SD_FMT_DIV_BY2;
4209 0 : break;
4210 : case 16000:
4211 0 : ret |= HDA_SD_FMT_BASE_48 | HDA_SD_FMT_MULT_X1 | HDA_SD_FMT_DIV_BY3;
4212 0 : break;
4213 : case 11025:
4214 0 : ret |= HDA_SD_FMT_BASE_44 | HDA_SD_FMT_MULT_X1 | HDA_SD_FMT_DIV_BY4;
4215 0 : break;
4216 : case 8000:
4217 0 : ret |= HDA_SD_FMT_BASE_48 | HDA_SD_FMT_MULT_X1 | HDA_SD_FMT_DIV_BY6;
4218 0 : break;
4219 : }
4220 0 : *fmt = ret;
4221 0 : return 0;
4222 0 : }
|