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