File: | dev/pci/azalia.c |
Warning: | line 1914, column 3 Value stored to 'conv' is never read |
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; |
Value stored to 'conv' is never read | |
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 | } |