File: | dev/pci/azalia.c |
Warning: | line 2909, column 11 The left operand of '&' is a garbage value |
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; | |||
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 | } |