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