| @@ -1,1691 +1,1702 @@ | | | @@ -1,1691 +1,1702 @@ |
1 | /* $NetBSD: auich.c,v 1.128 2008/11/08 00:26:35 dyoung Exp $ */ | | 1 | /* $NetBSD: auich.c,v 1.129 2009/03/17 19:38:34 dyoung Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2000, 2004, 2005 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2000, 2004, 2005 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Jason R. Thorpe and by Charles M. Hannum. | | 8 | * by Jason R. Thorpe and by Charles M. Hannum. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * Copyright (c) 2000 Michael Shalayeff | | 33 | * Copyright (c) 2000 Michael Shalayeff |
34 | * All rights reserved. | | 34 | * All rights reserved. |
35 | * | | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | | 36 | * Redistribution and use in source and binary forms, with or without |
37 | * modification, are permitted provided that the following conditions | | 37 | * modification, are permitted provided that the following conditions |
38 | * are met: | | 38 | * are met: |
39 | * 1. Redistributions of source code must retain the above copyright | | 39 | * 1. Redistributions of source code must retain the above copyright |
40 | * notice, this list of conditions and the following disclaimer. | | 40 | * notice, this list of conditions and the following disclaimer. |
41 | * 2. Redistributions in binary form must reproduce the above copyright | | 41 | * 2. Redistributions in binary form must reproduce the above copyright |
42 | * notice, this list of conditions and the following disclaimer in the | | 42 | * notice, this list of conditions and the following disclaimer in the |
43 | * documentation and/or other materials provided with the distribution. | | 43 | * documentation and/or other materials provided with the distribution. |
44 | * 3. The name of the author may not be used to endorse or promote products | | 44 | * 3. The name of the author may not be used to endorse or promote products |
45 | * derived from this software without specific prior written permission. | | 45 | * derived from this software without specific prior written permission. |
46 | * | | 46 | * |
47 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 47 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
48 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 48 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
49 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 49 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
50 | * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, | | 50 | * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, |
51 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | | 51 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
52 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | 52 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
53 | * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 53 | * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
54 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | | 54 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
55 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | | 55 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
56 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | | 56 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
57 | * THE POSSIBILITY OF SUCH DAMAGE. | | 57 | * THE POSSIBILITY OF SUCH DAMAGE. |
58 | * | | 58 | * |
59 | * from OpenBSD: ich.c,v 1.3 2000/08/11 06:17:18 mickey Exp | | 59 | * from OpenBSD: ich.c,v 1.3 2000/08/11 06:17:18 mickey Exp |
60 | */ | | 60 | */ |
61 | | | 61 | |
62 | /* | | 62 | /* |
63 | * Copyright (c) 2000 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp> | | 63 | * Copyright (c) 2000 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp> |
64 | * Copyright (c) 2001 Cameron Grant <cg@freebsd.org> | | 64 | * Copyright (c) 2001 Cameron Grant <cg@freebsd.org> |
65 | * All rights reserved. | | 65 | * All rights reserved. |
66 | * | | 66 | * |
67 | * Redistribution and use in source and binary forms, with or without | | 67 | * Redistribution and use in source and binary forms, with or without |
68 | * modification, are permitted provided that the following conditions | | 68 | * modification, are permitted provided that the following conditions |
69 | * are met: | | 69 | * are met: |
70 | * 1. Redistributions of source code must retain the above copyright | | 70 | * 1. Redistributions of source code must retain the above copyright |
71 | * notice, this list of conditions and the following disclaimer. | | 71 | * notice, this list of conditions and the following disclaimer. |
72 | * 2. Redistributions in binary form must reproduce the above copyright | | 72 | * 2. Redistributions in binary form must reproduce the above copyright |
73 | * notice, this list of conditions and the following disclaimer in the | | 73 | * notice, this list of conditions and the following disclaimer in the |
74 | * documentation and/or other materials provided with the distribution. | | 74 | * documentation and/or other materials provided with the distribution. |
75 | * | | 75 | * |
76 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | | 76 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
77 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 77 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
78 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 78 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
79 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | | 79 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
80 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 80 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
81 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 81 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
82 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 82 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
83 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT | | 83 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT |
84 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 84 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
85 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF | | 85 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF |
86 | * SUCH DAMAGE. | | 86 | * SUCH DAMAGE. |
87 | * | | 87 | * |
88 | * auich_calibrate() was from FreeBSD: ich.c,v 1.22 2002/06/27 22:36:01 scottl Exp | | 88 | * auich_calibrate() was from FreeBSD: ich.c,v 1.22 2002/06/27 22:36:01 scottl Exp |
89 | */ | | 89 | */ |
90 | | | 90 | |
91 | | | 91 | |
92 | /* #define AUICH_DEBUG */ | | 92 | /* #define AUICH_DEBUG */ |
93 | /* | | 93 | /* |
94 | * AC'97 audio found on Intel 810/820/440MX chipsets. | | 94 | * AC'97 audio found on Intel 810/820/440MX chipsets. |
95 | * http://developer.intel.com/design/chipsets/datashts/290655.htm | | 95 | * http://developer.intel.com/design/chipsets/datashts/290655.htm |
96 | * http://developer.intel.com/design/chipsets/manuals/298028.htm | | 96 | * http://developer.intel.com/design/chipsets/manuals/298028.htm |
97 | * ICH3:http://www.intel.com/design/chipsets/datashts/290716.htm | | 97 | * ICH3:http://www.intel.com/design/chipsets/datashts/290716.htm |
98 | * ICH4:http://www.intel.com/design/chipsets/datashts/290744.htm | | 98 | * ICH4:http://www.intel.com/design/chipsets/datashts/290744.htm |
99 | * ICH5:http://www.intel.com/design/chipsets/datashts/252516.htm | | 99 | * ICH5:http://www.intel.com/design/chipsets/datashts/252516.htm |
100 | * AMD8111: | | 100 | * AMD8111: |
101 | * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/24674.pdf | | 101 | * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/24674.pdf |
102 | * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25720.pdf | | 102 | * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25720.pdf |
103 | * | | 103 | * |
104 | * TODO: | | 104 | * TODO: |
105 | * - Add support for the dedicated microphone input. | | 105 | * - Add support for the dedicated microphone input. |
106 | * | | 106 | * |
107 | * NOTE: | | 107 | * NOTE: |
108 | * - The 440MX B-stepping at running 100MHz has a hardware erratum. | | 108 | * - The 440MX B-stepping at running 100MHz has a hardware erratum. |
109 | * It causes PCI master abort and hangups until cold reboot. | | 109 | * It causes PCI master abort and hangups until cold reboot. |
110 | * http://www.intel.com/design/chipsets/specupdt/245051.htm | | 110 | * http://www.intel.com/design/chipsets/specupdt/245051.htm |
111 | */ | | 111 | */ |
112 | | | 112 | |
113 | #include <sys/cdefs.h> | | 113 | #include <sys/cdefs.h> |
114 | __KERNEL_RCSID(0, "$NetBSD: auich.c,v 1.128 2008/11/08 00:26:35 dyoung Exp $"); | | 114 | __KERNEL_RCSID(0, "$NetBSD: auich.c,v 1.129 2009/03/17 19:38:34 dyoung Exp $"); |
115 | | | 115 | |
116 | #include <sys/param.h> | | 116 | #include <sys/param.h> |
117 | #include <sys/systm.h> | | 117 | #include <sys/systm.h> |
118 | #include <sys/kernel.h> | | 118 | #include <sys/kernel.h> |
119 | #include <sys/malloc.h> | | 119 | #include <sys/malloc.h> |
120 | #include <sys/device.h> | | 120 | #include <sys/device.h> |
121 | #include <sys/fcntl.h> | | 121 | #include <sys/fcntl.h> |
122 | #include <sys/proc.h> | | 122 | #include <sys/proc.h> |
123 | #include <sys/sysctl.h> | | 123 | #include <sys/sysctl.h> |
124 | | | 124 | |
125 | #include <uvm/uvm_extern.h> /* for PAGE_SIZE */ | | 125 | #include <uvm/uvm_extern.h> /* for PAGE_SIZE */ |
126 | | | 126 | |
127 | #include <dev/pci/pcidevs.h> | | 127 | #include <dev/pci/pcidevs.h> |
128 | #include <dev/pci/pcivar.h> | | 128 | #include <dev/pci/pcivar.h> |
129 | #include <dev/pci/auichreg.h> | | 129 | #include <dev/pci/auichreg.h> |
130 | | | 130 | |
131 | #include <sys/audioio.h> | | 131 | #include <sys/audioio.h> |
132 | #include <dev/audio_if.h> | | 132 | #include <dev/audio_if.h> |
133 | #include <dev/mulaw.h> | | 133 | #include <dev/mulaw.h> |
134 | #include <dev/auconv.h> | | 134 | #include <dev/auconv.h> |
135 | | | 135 | |
136 | #include <sys/bus.h> | | 136 | #include <sys/bus.h> |
137 | | | 137 | |
138 | #include <dev/ic/ac97reg.h> | | 138 | #include <dev/ic/ac97reg.h> |
139 | #include <dev/ic/ac97var.h> | | 139 | #include <dev/ic/ac97var.h> |
140 | | | 140 | |
141 | struct auich_dma { | | 141 | struct auich_dma { |
142 | bus_dmamap_t map; | | 142 | bus_dmamap_t map; |
143 | void *addr; | | 143 | void *addr; |
144 | bus_dma_segment_t segs[1]; | | 144 | bus_dma_segment_t segs[1]; |
145 | int nsegs; | | 145 | int nsegs; |
146 | size_t size; | | 146 | size_t size; |
147 | struct auich_dma *next; | | 147 | struct auich_dma *next; |
148 | }; | | 148 | }; |
149 | | | 149 | |
150 | #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr) | | 150 | #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr) |
151 | #define KERNADDR(p) ((void *)((p)->addr)) | | 151 | #define KERNADDR(p) ((void *)((p)->addr)) |
152 | | | 152 | |
153 | struct auich_cdata { | | 153 | struct auich_cdata { |
154 | struct auich_dmalist ic_dmalist_pcmo[ICH_DMALIST_MAX]; | | 154 | struct auich_dmalist ic_dmalist_pcmo[ICH_DMALIST_MAX]; |
155 | struct auich_dmalist ic_dmalist_pcmi[ICH_DMALIST_MAX]; | | 155 | struct auich_dmalist ic_dmalist_pcmi[ICH_DMALIST_MAX]; |
156 | struct auich_dmalist ic_dmalist_mici[ICH_DMALIST_MAX]; | | 156 | struct auich_dmalist ic_dmalist_mici[ICH_DMALIST_MAX]; |
157 | }; | | 157 | }; |
158 | | | 158 | |
159 | #define ICH_CDOFF(x) offsetof(struct auich_cdata, x) | | 159 | #define ICH_CDOFF(x) offsetof(struct auich_cdata, x) |
160 | #define ICH_PCMO_OFF(x) ICH_CDOFF(ic_dmalist_pcmo[(x)]) | | 160 | #define ICH_PCMO_OFF(x) ICH_CDOFF(ic_dmalist_pcmo[(x)]) |
161 | #define ICH_PCMI_OFF(x) ICH_CDOFF(ic_dmalist_pcmi[(x)]) | | 161 | #define ICH_PCMI_OFF(x) ICH_CDOFF(ic_dmalist_pcmi[(x)]) |
162 | #define ICH_MICI_OFF(x) ICH_CDOFF(ic_dmalist_mici[(x)]) | | 162 | #define ICH_MICI_OFF(x) ICH_CDOFF(ic_dmalist_mici[(x)]) |
163 | | | 163 | |
164 | struct auich_softc { | | 164 | struct auich_softc { |
165 | device_t sc_dev; | | 165 | device_t sc_dev; |
166 | void *sc_ih; | | 166 | void *sc_ih; |
167 | | | 167 | |
168 | device_t sc_audiodev; | | 168 | device_t sc_audiodev; |
169 | audio_device_t sc_audev; | | 169 | audio_device_t sc_audev; |
170 | | | 170 | |
171 | pci_chipset_tag_t sc_pc; | | 171 | pci_chipset_tag_t sc_pc; |
172 | pcitag_t sc_pt; | | 172 | pcitag_t sc_pt; |
173 | bus_space_tag_t iot; | | 173 | bus_space_tag_t iot; |
174 | bus_space_handle_t mix_ioh; | | 174 | bus_space_handle_t mix_ioh; |
175 | bus_size_t mix_size; | | 175 | bus_size_t mix_size; |
176 | bus_space_handle_t aud_ioh; | | 176 | bus_space_handle_t aud_ioh; |
177 | bus_size_t aud_size; | | 177 | bus_size_t aud_size; |
178 | bus_dma_tag_t dmat; | | 178 | bus_dma_tag_t dmat; |
179 | pci_intr_handle_t intrh; | | 179 | pci_intr_handle_t intrh; |
180 | | | 180 | |
181 | struct ac97_codec_if *codec_if; | | 181 | struct ac97_codec_if *codec_if; |
182 | struct ac97_host_if host_if; | | 182 | struct ac97_host_if host_if; |
183 | int sc_codecnum; | | 183 | int sc_codecnum; |
184 | int sc_codectype; | | 184 | int sc_codectype; |
185 | enum ac97_host_flags sc_codecflags; | | 185 | enum ac97_host_flags sc_codecflags; |
186 | bool sc_spdif; | | 186 | bool sc_spdif; |
187 | | | 187 | |
188 | /* DMA scatter-gather lists. */ | | 188 | /* DMA scatter-gather lists. */ |
189 | bus_dmamap_t sc_cddmamap; | | 189 | bus_dmamap_t sc_cddmamap; |
190 | #define sc_cddma sc_cddmamap->dm_segs[0].ds_addr | | 190 | #define sc_cddma sc_cddmamap->dm_segs[0].ds_addr |
191 | | | 191 | |
192 | struct auich_cdata *sc_cdata; | | 192 | struct auich_cdata *sc_cdata; |
193 | | | 193 | |
194 | struct auich_ring { | | 194 | struct auich_ring { |
195 | int qptr; | | 195 | int qptr; |
196 | struct auich_dmalist *dmalist; | | 196 | struct auich_dmalist *dmalist; |
197 | | | 197 | |
198 | uint32_t start, p, end; | | 198 | uint32_t start, p, end; |
199 | int blksize; | | 199 | int blksize; |
200 | | | 200 | |
201 | void (*intr)(void *); | | 201 | void (*intr)(void *); |
202 | void *arg; | | 202 | void *arg; |
203 | } pcmo, pcmi, mici; | | 203 | } pcmo, pcmi, mici; |
204 | | | 204 | |
205 | struct auich_dma *sc_dmas; | | 205 | struct auich_dma *sc_dmas; |
206 | | | 206 | |
207 | /* SiS 7012 hack */ | | 207 | /* SiS 7012 hack */ |
208 | int sc_sample_shift; | | 208 | int sc_sample_shift; |
209 | int sc_sts_reg; | | 209 | int sc_sts_reg; |
210 | /* 440MX workaround */ | | 210 | /* 440MX workaround */ |
211 | int sc_dmamap_flags; | | 211 | int sc_dmamap_flags; |
212 | /* Native mode? */ | | 212 | /* Native mode? */ |
213 | int sc_native_mode; | | 213 | int sc_native_mode; |
214 | | | 214 | |
215 | /* sysctl */ | | 215 | /* sysctl */ |
216 | struct sysctllog *sc_log; | | 216 | struct sysctllog *sc_log; |
217 | uint32_t sc_ac97_clock; | | 217 | uint32_t sc_ac97_clock; |
218 | int sc_ac97_clock_mib; | | 218 | int sc_ac97_clock_mib; |
219 | | | 219 | |
220 | int sc_modem_offset; | | 220 | int sc_modem_offset; |
221 | | | 221 | |
222 | #define AUICH_AUDIO_NFORMATS 3 | | 222 | #define AUICH_AUDIO_NFORMATS 3 |
223 | #define AUICH_MODEM_NFORMATS 1 | | 223 | #define AUICH_MODEM_NFORMATS 1 |
224 | struct audio_format sc_audio_formats[AUICH_AUDIO_NFORMATS]; | | 224 | struct audio_format sc_audio_formats[AUICH_AUDIO_NFORMATS]; |
225 | struct audio_format sc_modem_formats[AUICH_MODEM_NFORMATS]; | | 225 | struct audio_format sc_modem_formats[AUICH_MODEM_NFORMATS]; |
226 | struct audio_encoding_set *sc_encodings; | | 226 | struct audio_encoding_set *sc_encodings; |
227 | struct audio_encoding_set *sc_spdif_encodings; | | 227 | struct audio_encoding_set *sc_spdif_encodings; |
228 | }; | | 228 | }; |
229 | | | 229 | |
230 | /* Debug */ | | 230 | /* Debug */ |
231 | #ifdef AUICH_DEBUG | | 231 | #ifdef AUICH_DEBUG |
232 | #define DPRINTF(l,x) do { if (auich_debug & (l)) printf x; } while(0) | | 232 | #define DPRINTF(l,x) do { if (auich_debug & (l)) printf x; } while(0) |
233 | int auich_debug = 0xfffe; | | 233 | int auich_debug = 0xfffe; |
234 | #define ICH_DEBUG_CODECIO 0x0001 | | 234 | #define ICH_DEBUG_CODECIO 0x0001 |
235 | #define ICH_DEBUG_DMA 0x0002 | | 235 | #define ICH_DEBUG_DMA 0x0002 |
236 | #define ICH_DEBUG_INTR 0x0004 | | 236 | #define ICH_DEBUG_INTR 0x0004 |
237 | #else | | 237 | #else |
238 | #define DPRINTF(x,y) /* nothing */ | | 238 | #define DPRINTF(x,y) /* nothing */ |
239 | #endif | | 239 | #endif |
240 | | | 240 | |
241 | static int auich_match(device_t, cfdata_t, void *); | | 241 | static int auich_match(device_t, cfdata_t, void *); |
242 | static void auich_attach(device_t, device_t, void *); | | 242 | static void auich_attach(device_t, device_t, void *); |
243 | static int auich_detach(device_t, int); | | 243 | static int auich_detach(device_t, int); |
| | | 244 | static void auich_childdet(device_t, device_t); |
244 | static int auich_activate(device_t, enum devact); | | 245 | static int auich_activate(device_t, enum devact); |
245 | static int auich_intr(void *); | | 246 | static int auich_intr(void *); |
246 | | | 247 | |
247 | CFATTACH_DECL_NEW(auich, sizeof(struct auich_softc), | | 248 | CFATTACH_DECL2_NEW(auich, sizeof(struct auich_softc), |
248 | auich_match, auich_attach, auich_detach, auich_activate); | | 249 | auich_match, auich_attach, auich_detach, auich_activate, NULL, |
| | | 250 | auich_childdet); |
249 | | | 251 | |
250 | static int auich_open(void *, int); | | 252 | static int auich_open(void *, int); |
251 | static void auich_close(void *); | | 253 | static void auich_close(void *); |
252 | static int auich_query_encoding(void *, struct audio_encoding *); | | 254 | static int auich_query_encoding(void *, struct audio_encoding *); |
253 | static int auich_set_params(void *, int, int, audio_params_t *, | | 255 | static int auich_set_params(void *, int, int, audio_params_t *, |
254 | audio_params_t *, stream_filter_list_t *, | | 256 | audio_params_t *, stream_filter_list_t *, |
255 | stream_filter_list_t *); | | 257 | stream_filter_list_t *); |
256 | static int auich_round_blocksize(void *, int, int, const audio_params_t *); | | 258 | static int auich_round_blocksize(void *, int, int, const audio_params_t *); |
257 | static void auich_halt_pipe(struct auich_softc *, int); | | 259 | static void auich_halt_pipe(struct auich_softc *, int); |
258 | static int auich_halt_output(void *); | | 260 | static int auich_halt_output(void *); |
259 | static int auich_halt_input(void *); | | 261 | static int auich_halt_input(void *); |
260 | static int auich_getdev(void *, struct audio_device *); | | 262 | static int auich_getdev(void *, struct audio_device *); |
261 | static int auich_set_port(void *, mixer_ctrl_t *); | | 263 | static int auich_set_port(void *, mixer_ctrl_t *); |
262 | static int auich_get_port(void *, mixer_ctrl_t *); | | 264 | static int auich_get_port(void *, mixer_ctrl_t *); |
263 | static int auich_query_devinfo(void *, mixer_devinfo_t *); | | 265 | static int auich_query_devinfo(void *, mixer_devinfo_t *); |
264 | static void *auich_allocm(void *, int, size_t, struct malloc_type *, int); | | 266 | static void *auich_allocm(void *, int, size_t, struct malloc_type *, int); |
265 | static void auich_freem(void *, void *, struct malloc_type *); | | 267 | static void auich_freem(void *, void *, struct malloc_type *); |
266 | static size_t auich_round_buffersize(void *, int, size_t); | | 268 | static size_t auich_round_buffersize(void *, int, size_t); |
267 | static paddr_t auich_mappage(void *, void *, off_t, int); | | 269 | static paddr_t auich_mappage(void *, void *, off_t, int); |
268 | static int auich_get_props(void *); | | 270 | static int auich_get_props(void *); |
269 | static void auich_trigger_pipe(struct auich_softc *, int, struct auich_ring *); | | 271 | static void auich_trigger_pipe(struct auich_softc *, int, struct auich_ring *); |
270 | static void auich_intr_pipe(struct auich_softc *, int, struct auich_ring *); | | 272 | static void auich_intr_pipe(struct auich_softc *, int, struct auich_ring *); |
271 | static int auich_trigger_output(void *, void *, void *, int, | | 273 | static int auich_trigger_output(void *, void *, void *, int, |
272 | void (*)(void *), void *, const audio_params_t *); | | 274 | void (*)(void *), void *, const audio_params_t *); |
273 | static int auich_trigger_input(void *, void *, void *, int, | | 275 | static int auich_trigger_input(void *, void *, void *, int, |
274 | void (*)(void *), void *, const audio_params_t *); | | 276 | void (*)(void *), void *, const audio_params_t *); |
275 | static int auich_powerstate(void *, int); | | 277 | static int auich_powerstate(void *, int); |
276 | | | 278 | |
277 | static int auich_alloc_cdata(struct auich_softc *); | | 279 | static int auich_alloc_cdata(struct auich_softc *); |
278 | | | 280 | |
279 | static int auich_allocmem(struct auich_softc *, size_t, size_t, | | 281 | static int auich_allocmem(struct auich_softc *, size_t, size_t, |
280 | struct auich_dma *); | | 282 | struct auich_dma *); |
281 | static int auich_freemem(struct auich_softc *, struct auich_dma *); | | 283 | static int auich_freemem(struct auich_softc *, struct auich_dma *); |
282 | | | 284 | |
283 | static bool auich_resume(device_t PMF_FN_PROTO); | | 285 | static bool auich_resume(device_t PMF_FN_PROTO); |
284 | static int auich_set_rate(struct auich_softc *, int, u_long); | | 286 | static int auich_set_rate(struct auich_softc *, int, u_long); |
285 | static int auich_sysctl_verify(SYSCTLFN_ARGS); | | 287 | static int auich_sysctl_verify(SYSCTLFN_ARGS); |
286 | static void auich_finish_attach(device_t); | | 288 | static void auich_finish_attach(device_t); |
287 | static void auich_calibrate(struct auich_softc *); | | 289 | static void auich_calibrate(struct auich_softc *); |
288 | static void auich_clear_cas(struct auich_softc *); | | 290 | static void auich_clear_cas(struct auich_softc *); |
289 | | | 291 | |
290 | static int auich_attach_codec(void *, struct ac97_codec_if *); | | 292 | static int auich_attach_codec(void *, struct ac97_codec_if *); |
291 | static int auich_read_codec(void *, uint8_t, uint16_t *); | | 293 | static int auich_read_codec(void *, uint8_t, uint16_t *); |
292 | static int auich_write_codec(void *, uint8_t, uint16_t); | | 294 | static int auich_write_codec(void *, uint8_t, uint16_t); |
293 | static int auich_reset_codec(void *); | | 295 | static int auich_reset_codec(void *); |
294 | static enum ac97_host_flags auich_flags_codec(void *); | | 296 | static enum ac97_host_flags auich_flags_codec(void *); |
295 | static void auich_spdif_event(void *, bool); | | 297 | static void auich_spdif_event(void *, bool); |
296 | | | 298 | |
297 | static const struct audio_hw_if auich_hw_if = { | | 299 | static const struct audio_hw_if auich_hw_if = { |
298 | auich_open, | | 300 | auich_open, |
299 | auich_close, | | 301 | auich_close, |
300 | NULL, /* drain */ | | 302 | NULL, /* drain */ |
301 | auich_query_encoding, | | 303 | auich_query_encoding, |
302 | auich_set_params, | | 304 | auich_set_params, |
303 | auich_round_blocksize, | | 305 | auich_round_blocksize, |
304 | NULL, /* commit_setting */ | | 306 | NULL, /* commit_setting */ |
305 | NULL, /* init_output */ | | 307 | NULL, /* init_output */ |
306 | NULL, /* init_input */ | | 308 | NULL, /* init_input */ |
307 | NULL, /* start_output */ | | 309 | NULL, /* start_output */ |
308 | NULL, /* start_input */ | | 310 | NULL, /* start_input */ |
309 | auich_halt_output, | | 311 | auich_halt_output, |
310 | auich_halt_input, | | 312 | auich_halt_input, |
311 | NULL, /* speaker_ctl */ | | 313 | NULL, /* speaker_ctl */ |
312 | auich_getdev, | | 314 | auich_getdev, |
313 | NULL, /* getfd */ | | 315 | NULL, /* getfd */ |
314 | auich_set_port, | | 316 | auich_set_port, |
315 | auich_get_port, | | 317 | auich_get_port, |
316 | auich_query_devinfo, | | 318 | auich_query_devinfo, |
317 | auich_allocm, | | 319 | auich_allocm, |
318 | auich_freem, | | 320 | auich_freem, |
319 | auich_round_buffersize, | | 321 | auich_round_buffersize, |
320 | auich_mappage, | | 322 | auich_mappage, |
321 | auich_get_props, | | 323 | auich_get_props, |
322 | auich_trigger_output, | | 324 | auich_trigger_output, |
323 | auich_trigger_input, | | 325 | auich_trigger_input, |
324 | NULL, /* dev_ioctl */ | | 326 | NULL, /* dev_ioctl */ |
325 | auich_powerstate, | | 327 | auich_powerstate, |
326 | }; | | 328 | }; |
327 | | | 329 | |
328 | #define AUICH_FORMATS_1CH 0 | | 330 | #define AUICH_FORMATS_1CH 0 |
329 | #define AUICH_FORMATS_4CH 1 | | 331 | #define AUICH_FORMATS_4CH 1 |
330 | #define AUICH_FORMATS_6CH 2 | | 332 | #define AUICH_FORMATS_6CH 2 |
331 | static const struct audio_format auich_audio_formats[AUICH_AUDIO_NFORMATS] = { | | 333 | static const struct audio_format auich_audio_formats[AUICH_AUDIO_NFORMATS] = { |
332 | {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16, | | 334 | {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16, |
333 | 2, AUFMT_STEREO, 0, {8000, 48000}}, | | 335 | 2, AUFMT_STEREO, 0, {8000, 48000}}, |
334 | {NULL, AUMODE_PLAY, AUDIO_ENCODING_SLINEAR_LE, 16, 16, | | 336 | {NULL, AUMODE_PLAY, AUDIO_ENCODING_SLINEAR_LE, 16, 16, |
335 | 4, AUFMT_SURROUND4, 0, {8000, 48000}}, | | 337 | 4, AUFMT_SURROUND4, 0, {8000, 48000}}, |
336 | {NULL, AUMODE_PLAY, AUDIO_ENCODING_SLINEAR_LE, 16, 16, | | 338 | {NULL, AUMODE_PLAY, AUDIO_ENCODING_SLINEAR_LE, 16, 16, |
337 | 6, AUFMT_DOLBY_5_1, 0, {8000, 48000}}, | | 339 | 6, AUFMT_DOLBY_5_1, 0, {8000, 48000}}, |
338 | }; | | 340 | }; |
339 | | | 341 | |
340 | #define AUICH_SPDIF_NFORMATS 1 | | 342 | #define AUICH_SPDIF_NFORMATS 1 |
341 | static const struct audio_format auich_spdif_formats[AUICH_SPDIF_NFORMATS] = { | | 343 | static const struct audio_format auich_spdif_formats[AUICH_SPDIF_NFORMATS] = { |
342 | {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16, | | 344 | {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16, |
343 | 2, AUFMT_STEREO, 1, {48000}}, | | 345 | 2, AUFMT_STEREO, 1, {48000}}, |
344 | }; | | 346 | }; |
345 | | | 347 | |
346 | static const struct audio_format auich_modem_formats[AUICH_MODEM_NFORMATS] = { | | 348 | static const struct audio_format auich_modem_formats[AUICH_MODEM_NFORMATS] = { |
347 | {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16, | | 349 | {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16, |
348 | 1, AUFMT_MONAURAL, 0, {8000, 16000}}, | | 350 | 1, AUFMT_MONAURAL, 0, {8000, 16000}}, |
349 | }; | | 351 | }; |
350 | | | 352 | |
351 | #define PCI_ID_CODE0(v, p) PCI_ID_CODE(PCI_VENDOR_##v, PCI_PRODUCT_##v##_##p) | | 353 | #define PCI_ID_CODE0(v, p) PCI_ID_CODE(PCI_VENDOR_##v, PCI_PRODUCT_##v##_##p) |
352 | #define PCIID_ICH PCI_ID_CODE0(INTEL, 82801AA_ACA) | | 354 | #define PCIID_ICH PCI_ID_CODE0(INTEL, 82801AA_ACA) |
353 | #define PCIID_ICH0 PCI_ID_CODE0(INTEL, 82801AB_ACA) | | 355 | #define PCIID_ICH0 PCI_ID_CODE0(INTEL, 82801AB_ACA) |
354 | #define PCIID_ICH2 PCI_ID_CODE0(INTEL, 82801BA_ACA) | | 356 | #define PCIID_ICH2 PCI_ID_CODE0(INTEL, 82801BA_ACA) |
355 | #define PCIID_440MX PCI_ID_CODE0(INTEL, 82440MX_ACA) | | 357 | #define PCIID_440MX PCI_ID_CODE0(INTEL, 82440MX_ACA) |
356 | #define PCIID_ICH3 PCI_ID_CODE0(INTEL, 82801CA_AC) | | 358 | #define PCIID_ICH3 PCI_ID_CODE0(INTEL, 82801CA_AC) |
357 | #define PCIID_ICH4 PCI_ID_CODE0(INTEL, 82801DB_AC) | | 359 | #define PCIID_ICH4 PCI_ID_CODE0(INTEL, 82801DB_AC) |
358 | #define PCIID_ICH5 PCI_ID_CODE0(INTEL, 82801EB_AC) | | 360 | #define PCIID_ICH5 PCI_ID_CODE0(INTEL, 82801EB_AC) |
359 | #define PCIID_ICH6 PCI_ID_CODE0(INTEL, 82801FB_AC) | | 361 | #define PCIID_ICH6 PCI_ID_CODE0(INTEL, 82801FB_AC) |
360 | #define PCIID_ICH7 PCI_ID_CODE0(INTEL, 82801G_ACA) | | 362 | #define PCIID_ICH7 PCI_ID_CODE0(INTEL, 82801G_ACA) |
361 | #define PCIID_I6300ESB PCI_ID_CODE0(INTEL, 6300ESB_ACA) | | 363 | #define PCIID_I6300ESB PCI_ID_CODE0(INTEL, 6300ESB_ACA) |
362 | #define PCIID_SIS7012 PCI_ID_CODE0(SIS, 7012_AC) | | 364 | #define PCIID_SIS7012 PCI_ID_CODE0(SIS, 7012_AC) |
363 | #define PCIID_NFORCE PCI_ID_CODE0(NVIDIA, NFORCE_MCP_AC) | | 365 | #define PCIID_NFORCE PCI_ID_CODE0(NVIDIA, NFORCE_MCP_AC) |
364 | #define PCIID_NFORCE2 PCI_ID_CODE0(NVIDIA, NFORCE2_MCPT_AC) | | 366 | #define PCIID_NFORCE2 PCI_ID_CODE0(NVIDIA, NFORCE2_MCPT_AC) |
365 | #define PCIID_NFORCE2_400 PCI_ID_CODE0(NVIDIA, NFORCE2_400_MCPT_AC) | | 367 | #define PCIID_NFORCE2_400 PCI_ID_CODE0(NVIDIA, NFORCE2_400_MCPT_AC) |
366 | #define PCIID_NFORCE3 PCI_ID_CODE0(NVIDIA, NFORCE3_MCPT_AC) | | 368 | #define PCIID_NFORCE3 PCI_ID_CODE0(NVIDIA, NFORCE3_MCPT_AC) |
367 | #define PCIID_NFORCE3_250 PCI_ID_CODE0(NVIDIA, NFORCE3_250_MCPT_AC) | | 369 | #define PCIID_NFORCE3_250 PCI_ID_CODE0(NVIDIA, NFORCE3_250_MCPT_AC) |
368 | #define PCIID_NFORCE4 PCI_ID_CODE0(NVIDIA, NFORCE4_AC) | | 370 | #define PCIID_NFORCE4 PCI_ID_CODE0(NVIDIA, NFORCE4_AC) |
369 | #define PCIID_NFORCE430 PCI_ID_CODE0(NVIDIA, NFORCE430_AC) | | 371 | #define PCIID_NFORCE430 PCI_ID_CODE0(NVIDIA, NFORCE430_AC) |
370 | #define PCIID_AMD768 PCI_ID_CODE0(AMD, PBC768_AC) | | 372 | #define PCIID_AMD768 PCI_ID_CODE0(AMD, PBC768_AC) |
371 | #define PCIID_AMD8111 PCI_ID_CODE0(AMD, PBC8111_AC) | | 373 | #define PCIID_AMD8111 PCI_ID_CODE0(AMD, PBC8111_AC) |
372 | | | 374 | |
373 | #define PCIID_ICH3MODEM PCI_ID_CODE0(INTEL, 82801CA_MOD) | | 375 | #define PCIID_ICH3MODEM PCI_ID_CODE0(INTEL, 82801CA_MOD) |
374 | #define PCIID_ICH4MODEM PCI_ID_CODE0(INTEL, 82801DB_MOD) | | 376 | #define PCIID_ICH4MODEM PCI_ID_CODE0(INTEL, 82801DB_MOD) |
375 | #define PCIID_ICH6MODEM PCI_ID_CODE0(INTEL, 82801FB_ACM) | | 377 | #define PCIID_ICH6MODEM PCI_ID_CODE0(INTEL, 82801FB_ACM) |
376 | | | 378 | |
377 | struct auich_devtype { | | 379 | struct auich_devtype { |
378 | pcireg_t id; | | 380 | pcireg_t id; |
379 | const char *name; | | 381 | const char *name; |
380 | const char *shortname; /* must be less than 11 characters */ | | 382 | const char *shortname; /* must be less than 11 characters */ |
381 | }; | | 383 | }; |
382 | | | 384 | |
383 | static const struct auich_devtype auich_audio_devices[] = { | | 385 | static const struct auich_devtype auich_audio_devices[] = { |
384 | { PCIID_ICH, "i82801AA (ICH) AC-97 Audio", "ICH" }, | | 386 | { PCIID_ICH, "i82801AA (ICH) AC-97 Audio", "ICH" }, |
385 | { PCIID_ICH0, "i82801AB (ICH0) AC-97 Audio", "ICH0" }, | | 387 | { PCIID_ICH0, "i82801AB (ICH0) AC-97 Audio", "ICH0" }, |
386 | { PCIID_ICH2, "i82801BA (ICH2) AC-97 Audio", "ICH2" }, | | 388 | { PCIID_ICH2, "i82801BA (ICH2) AC-97 Audio", "ICH2" }, |
387 | { PCIID_440MX, "i82440MX AC-97 Audio", "440MX" }, | | 389 | { PCIID_440MX, "i82440MX AC-97 Audio", "440MX" }, |
388 | { PCIID_ICH3, "i82801CA (ICH3) AC-97 Audio", "ICH3" }, | | 390 | { PCIID_ICH3, "i82801CA (ICH3) AC-97 Audio", "ICH3" }, |
389 | { PCIID_ICH4, "i82801DB/DBM (ICH4/ICH4M) AC-97 Audio", "ICH4" }, | | 391 | { PCIID_ICH4, "i82801DB/DBM (ICH4/ICH4M) AC-97 Audio", "ICH4" }, |
390 | { PCIID_ICH5, "i82801EB (ICH5) AC-97 Audio", "ICH5" }, | | 392 | { PCIID_ICH5, "i82801EB (ICH5) AC-97 Audio", "ICH5" }, |
391 | { PCIID_ICH6, "i82801FB (ICH6) AC-97 Audio", "ICH6" }, | | 393 | { PCIID_ICH6, "i82801FB (ICH6) AC-97 Audio", "ICH6" }, |
392 | { PCIID_ICH7, "i82801GB/GR (ICH7) AC-97 Audio", "ICH7" }, | | 394 | { PCIID_ICH7, "i82801GB/GR (ICH7) AC-97 Audio", "ICH7" }, |
393 | { PCIID_I6300ESB, "Intel 6300ESB AC-97 Audio", "I6300ESB" }, | | 395 | { PCIID_I6300ESB, "Intel 6300ESB AC-97 Audio", "I6300ESB" }, |
394 | { PCIID_SIS7012, "SiS 7012 AC-97 Audio", "SiS7012" }, | | 396 | { PCIID_SIS7012, "SiS 7012 AC-97 Audio", "SiS7012" }, |
395 | { PCIID_NFORCE, "nForce MCP AC-97 Audio", "nForce" }, | | 397 | { PCIID_NFORCE, "nForce MCP AC-97 Audio", "nForce" }, |
396 | { PCIID_NFORCE2, "nForce2 MCP-T AC-97 Audio", "nForce2" }, | | 398 | { PCIID_NFORCE2, "nForce2 MCP-T AC-97 Audio", "nForce2" }, |
397 | { PCIID_NFORCE2_400, "nForce2 400 MCP-T AC-97 Audio", "nForce2" }, | | 399 | { PCIID_NFORCE2_400, "nForce2 400 MCP-T AC-97 Audio", "nForce2" }, |
398 | { PCIID_NFORCE3, "nForce3 MCP-T AC-97 Audio", "nForce3" }, | | 400 | { PCIID_NFORCE3, "nForce3 MCP-T AC-97 Audio", "nForce3" }, |
399 | { PCIID_NFORCE3_250, "nForce3 250 MCP-T AC-97 Audio", "nForce3" }, | | 401 | { PCIID_NFORCE3_250, "nForce3 250 MCP-T AC-97 Audio", "nForce3" }, |
400 | { PCIID_NFORCE4, "nForce4 AC-97 Audio", "nForce4" }, | | 402 | { PCIID_NFORCE4, "nForce4 AC-97 Audio", "nForce4" }, |
401 | { PCIID_NFORCE430, "nForce430 (MCP51) AC-97 Audio", "nForce430" }, | | 403 | { PCIID_NFORCE430, "nForce430 (MCP51) AC-97 Audio", "nForce430" }, |
402 | { PCIID_AMD768, "AMD768 AC-97 Audio", "AMD768" }, | | 404 | { PCIID_AMD768, "AMD768 AC-97 Audio", "AMD768" }, |
403 | { PCIID_AMD8111,"AMD8111 AC-97 Audio", "AMD8111" }, | | 405 | { PCIID_AMD8111,"AMD8111 AC-97 Audio", "AMD8111" }, |
404 | { 0, NULL, NULL }, | | 406 | { 0, NULL, NULL }, |
405 | }; | | 407 | }; |
406 | | | 408 | |
407 | static const struct auich_devtype auich_modem_devices[] = { | | 409 | static const struct auich_devtype auich_modem_devices[] = { |
408 | #ifdef AUICH_ATTACH_MODEM | | 410 | #ifdef AUICH_ATTACH_MODEM |
409 | { PCIID_ICH3MODEM, "i82801CA (ICH3) AC-97 Modem", "ICH3MODEM" }, | | 411 | { PCIID_ICH3MODEM, "i82801CA (ICH3) AC-97 Modem", "ICH3MODEM" }, |
410 | { PCIID_ICH4MODEM, "i82801DB (ICH4) AC-97 Modem", "ICH4MODEM" }, | | 412 | { PCIID_ICH4MODEM, "i82801DB (ICH4) AC-97 Modem", "ICH4MODEM" }, |
411 | { PCIID_ICH6MODEM, "i82801FB (ICH6) AC-97 Modem", "ICH6MODEM" }, | | 413 | { PCIID_ICH6MODEM, "i82801FB (ICH6) AC-97 Modem", "ICH6MODEM" }, |
412 | #endif | | 414 | #endif |
413 | { 0, NULL, NULL }, | | 415 | { 0, NULL, NULL }, |
414 | }; | | 416 | }; |
415 | | | 417 | |
416 | static const struct auich_devtype * | | 418 | static const struct auich_devtype * |
417 | auich_lookup(struct pci_attach_args *pa, const struct auich_devtype *auich_devices) | | 419 | auich_lookup(struct pci_attach_args *pa, const struct auich_devtype *auich_devices) |
418 | { | | 420 | { |
419 | const struct auich_devtype *d; | | 421 | const struct auich_devtype *d; |
420 | | | 422 | |
421 | for (d = auich_devices; d->name != NULL; d++) { | | 423 | for (d = auich_devices; d->name != NULL; d++) { |
422 | if (pa->pa_id == d->id) | | 424 | if (pa->pa_id == d->id) |
423 | return d; | | 425 | return d; |
424 | } | | 426 | } |
425 | | | 427 | |
426 | return NULL; | | 428 | return NULL; |
427 | } | | 429 | } |
428 | | | 430 | |
429 | static int | | 431 | static int |
430 | auich_match(device_t parent, cfdata_t match, void *aux) | | 432 | auich_match(device_t parent, cfdata_t match, void *aux) |
431 | { | | 433 | { |
432 | struct pci_attach_args *pa; | | 434 | struct pci_attach_args *pa; |
433 | | | 435 | |
434 | pa = aux; | | 436 | pa = aux; |
435 | if (auich_lookup(pa, auich_audio_devices) != NULL) | | 437 | if (auich_lookup(pa, auich_audio_devices) != NULL) |
436 | return 1; | | 438 | return 1; |
437 | if (auich_lookup(pa, auich_modem_devices) != NULL) | | 439 | if (auich_lookup(pa, auich_modem_devices) != NULL) |
438 | return 1; | | 440 | return 1; |
439 | | | 441 | |
440 | return 0; | | 442 | return 0; |
441 | } | | 443 | } |
442 | | | 444 | |
443 | static void | | 445 | static void |
444 | auich_attach(device_t parent, device_t self, void *aux) | | 446 | auich_attach(device_t parent, device_t self, void *aux) |
445 | { | | 447 | { |
446 | struct auich_softc *sc = device_private(self); | | 448 | struct auich_softc *sc = device_private(self); |
447 | struct pci_attach_args *pa; | | 449 | struct pci_attach_args *pa; |
448 | pcireg_t v, subdev; | | 450 | pcireg_t v, subdev; |
449 | const char *intrstr; | | 451 | const char *intrstr; |
450 | const struct auich_devtype *d; | | 452 | const struct auich_devtype *d; |
451 | const struct sysctlnode *node, *node_ac97clock; | | 453 | const struct sysctlnode *node, *node_ac97clock; |
452 | int err, node_mib, i; | | 454 | int err, node_mib, i; |
453 | | | 455 | |
454 | sc->sc_dev = self; | | 456 | sc->sc_dev = self; |
455 | pa = aux; | | 457 | pa = aux; |
456 | | | 458 | |
457 | if ((d = auich_lookup(pa, auich_modem_devices)) != NULL) { | | 459 | if ((d = auich_lookup(pa, auich_modem_devices)) != NULL) { |
458 | sc->sc_modem_offset = 0x10; | | 460 | sc->sc_modem_offset = 0x10; |
459 | sc->sc_codectype = AC97_CODEC_TYPE_MODEM; | | 461 | sc->sc_codectype = AC97_CODEC_TYPE_MODEM; |
460 | } else if ((d = auich_lookup(pa, auich_audio_devices)) != NULL) { | | 462 | } else if ((d = auich_lookup(pa, auich_audio_devices)) != NULL) { |
461 | sc->sc_modem_offset = 0; | | 463 | sc->sc_modem_offset = 0; |
462 | sc->sc_codectype = AC97_CODEC_TYPE_AUDIO; | | 464 | sc->sc_codectype = AC97_CODEC_TYPE_AUDIO; |
463 | } else | | 465 | } else |
464 | panic("auich_attach: impossible"); | | 466 | panic("auich_attach: impossible"); |
465 | | | 467 | |
466 | if (sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) | | 468 | if (sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) |
467 | aprint_naive(": Audio controller\n"); | | 469 | aprint_naive(": Audio controller\n"); |
468 | else | | 470 | else |
469 | aprint_naive(": Modem controller\n"); | | 471 | aprint_naive(": Modem controller\n"); |
470 | | | 472 | |
471 | sc->sc_pc = pa->pa_pc; | | 473 | sc->sc_pc = pa->pa_pc; |
472 | sc->sc_pt = pa->pa_tag; | | 474 | sc->sc_pt = pa->pa_tag; |
473 | | | 475 | |
474 | aprint_normal(": %s\n", d->name); | | 476 | aprint_normal(": %s\n", d->name); |
475 | | | 477 | |
476 | if (d->id == PCIID_ICH4 || d->id == PCIID_ICH5 || d->id == PCIID_ICH6 | | 478 | if (d->id == PCIID_ICH4 || d->id == PCIID_ICH5 || d->id == PCIID_ICH6 |
477 | || d->id == PCIID_ICH7 || d->id == PCIID_I6300ESB | | 479 | || d->id == PCIID_ICH7 || d->id == PCIID_I6300ESB |
478 | || d->id == PCIID_ICH4MODEM) { | | 480 | || d->id == PCIID_ICH4MODEM) { |
479 | sc->sc_native_mode = 1; | | 481 | sc->sc_native_mode = 1; |
480 | /* | | 482 | /* |
481 | * Use native mode for Intel 6300ESB and ICH4/ICH5/ICH6/ICH7 | | 483 | * Use native mode for Intel 6300ESB and ICH4/ICH5/ICH6/ICH7 |
482 | */ | | 484 | */ |
483 | if (pci_mapreg_map(pa, ICH_MMBAR, PCI_MAPREG_TYPE_MEM, 0, | | 485 | if (pci_mapreg_map(pa, ICH_MMBAR, PCI_MAPREG_TYPE_MEM, 0, |
484 | &sc->iot, &sc->mix_ioh, NULL, &sc->mix_size)) { | | 486 | &sc->iot, &sc->mix_ioh, NULL, &sc->mix_size)) { |
485 | v = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_CFG); | | 487 | v = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_CFG); |
486 | pci_conf_write(pa->pa_pc, pa->pa_tag, ICH_CFG, | | 488 | pci_conf_write(pa->pa_pc, pa->pa_tag, ICH_CFG, |
487 | v | ICH_CFG_IOSE); | | 489 | v | ICH_CFG_IOSE); |
488 | if (pci_mapreg_map(pa, ICH_NAMBAR, PCI_MAPREG_TYPE_IO, | | 490 | if (pci_mapreg_map(pa, ICH_NAMBAR, PCI_MAPREG_TYPE_IO, |
489 | 0, &sc->iot, &sc->mix_ioh, NULL, | | 491 | 0, &sc->iot, &sc->mix_ioh, NULL, |
490 | &sc->mix_size)) { | | 492 | &sc->mix_size)) { |
491 | aprint_error_dev(self, "can't map codec i/o space\n"); | | 493 | aprint_error_dev(self, "can't map codec i/o space\n"); |
492 | return; | | 494 | return; |
493 | } | | 495 | } |
494 | } | | 496 | } |
495 | if (pci_mapreg_map(pa, ICH_MBBAR, PCI_MAPREG_TYPE_MEM, 0, | | 497 | if (pci_mapreg_map(pa, ICH_MBBAR, PCI_MAPREG_TYPE_MEM, 0, |
496 | &sc->iot, &sc->aud_ioh, NULL, &sc->aud_size)) { | | 498 | &sc->iot, &sc->aud_ioh, NULL, &sc->aud_size)) { |
497 | v = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_CFG); | | 499 | v = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_CFG); |
498 | pci_conf_write(pa->pa_pc, pa->pa_tag, ICH_CFG, | | 500 | pci_conf_write(pa->pa_pc, pa->pa_tag, ICH_CFG, |
499 | v | ICH_CFG_IOSE); | | 501 | v | ICH_CFG_IOSE); |
500 | if (pci_mapreg_map(pa, ICH_NABMBAR, PCI_MAPREG_TYPE_IO, | | 502 | if (pci_mapreg_map(pa, ICH_NABMBAR, PCI_MAPREG_TYPE_IO, |
501 | 0, &sc->iot, &sc->aud_ioh, NULL, | | 503 | 0, &sc->iot, &sc->aud_ioh, NULL, |
502 | &sc->aud_size)) { | | 504 | &sc->aud_size)) { |
503 | aprint_error_dev(self, "can't map device i/o space\n"); | | 505 | aprint_error_dev(self, "can't map device i/o space\n"); |
504 | return; | | 506 | return; |
505 | } | | 507 | } |
506 | } | | 508 | } |
507 | } else { | | 509 | } else { |
508 | if (pci_mapreg_map(pa, ICH_NAMBAR, PCI_MAPREG_TYPE_IO, 0, | | 510 | if (pci_mapreg_map(pa, ICH_NAMBAR, PCI_MAPREG_TYPE_IO, 0, |
509 | &sc->iot, &sc->mix_ioh, NULL, &sc->mix_size)) { | | 511 | &sc->iot, &sc->mix_ioh, NULL, &sc->mix_size)) { |
510 | aprint_error_dev(self, "can't map codec i/o space\n"); | | 512 | aprint_error_dev(self, "can't map codec i/o space\n"); |
511 | return; | | 513 | return; |
512 | } | | 514 | } |
513 | if (pci_mapreg_map(pa, ICH_NABMBAR, PCI_MAPREG_TYPE_IO, 0, | | 515 | if (pci_mapreg_map(pa, ICH_NABMBAR, PCI_MAPREG_TYPE_IO, 0, |
514 | &sc->iot, &sc->aud_ioh, NULL, &sc->aud_size)) { | | 516 | &sc->iot, &sc->aud_ioh, NULL, &sc->aud_size)) { |
515 | aprint_error_dev(self, "can't map device i/o space\n"); | | 517 | aprint_error_dev(self, "can't map device i/o space\n"); |
516 | return; | | 518 | return; |
517 | } | | 519 | } |
518 | } | | 520 | } |
519 | sc->dmat = pa->pa_dmat; | | 521 | sc->dmat = pa->pa_dmat; |
520 | | | 522 | |
521 | /* enable bus mastering */ | | 523 | /* enable bus mastering */ |
522 | v = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); | | 524 | v = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); |
523 | pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, | | 525 | pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, |
524 | v | PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_BACKTOBACK_ENABLE); | | 526 | v | PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_BACKTOBACK_ENABLE); |
525 | | | 527 | |
526 | /* Map and establish the interrupt. */ | | 528 | /* Map and establish the interrupt. */ |
527 | if (pci_intr_map(pa, &sc->intrh)) { | | 529 | if (pci_intr_map(pa, &sc->intrh)) { |
528 | aprint_error_dev(self, "can't map interrupt\n"); | | 530 | aprint_error_dev(self, "can't map interrupt\n"); |
529 | return; | | 531 | return; |
530 | } | | 532 | } |
531 | intrstr = pci_intr_string(pa->pa_pc, sc->intrh); | | 533 | intrstr = pci_intr_string(pa->pa_pc, sc->intrh); |
532 | sc->sc_ih = pci_intr_establish(pa->pa_pc, sc->intrh, IPL_AUDIO, | | 534 | sc->sc_ih = pci_intr_establish(pa->pa_pc, sc->intrh, IPL_AUDIO, |
533 | auich_intr, sc); | | 535 | auich_intr, sc); |
534 | if (sc->sc_ih == NULL) { | | 536 | if (sc->sc_ih == NULL) { |
535 | aprint_error_dev(self, "can't establish interrupt"); | | 537 | aprint_error_dev(self, "can't establish interrupt"); |
536 | if (intrstr != NULL) | | 538 | if (intrstr != NULL) |
537 | aprint_normal(" at %s", intrstr); | | 539 | aprint_normal(" at %s", intrstr); |
538 | aprint_normal("\n"); | | 540 | aprint_normal("\n"); |
539 | return; | | 541 | return; |
540 | } | | 542 | } |
541 | aprint_normal_dev(self, "interrupting at %s\n", intrstr); | | 543 | aprint_normal_dev(self, "interrupting at %s\n", intrstr); |
542 | | | 544 | |
543 | snprintf(sc->sc_audev.name, MAX_AUDIO_DEV_LEN, "%s AC97", d->shortname); | | 545 | snprintf(sc->sc_audev.name, MAX_AUDIO_DEV_LEN, "%s AC97", d->shortname); |
544 | snprintf(sc->sc_audev.version, MAX_AUDIO_DEV_LEN, | | 546 | snprintf(sc->sc_audev.version, MAX_AUDIO_DEV_LEN, |
545 | "0x%02x", PCI_REVISION(pa->pa_class)); | | 547 | "0x%02x", PCI_REVISION(pa->pa_class)); |
546 | strlcpy(sc->sc_audev.config, device_xname(self), MAX_AUDIO_DEV_LEN); | | 548 | strlcpy(sc->sc_audev.config, device_xname(self), MAX_AUDIO_DEV_LEN); |
547 | | | 549 | |
548 | /* SiS 7012 needs special handling */ | | 550 | /* SiS 7012 needs special handling */ |
549 | if (d->id == PCIID_SIS7012) { | | 551 | if (d->id == PCIID_SIS7012) { |
550 | sc->sc_sts_reg = ICH_PICB; | | 552 | sc->sc_sts_reg = ICH_PICB; |
551 | sc->sc_sample_shift = 0; | | 553 | sc->sc_sample_shift = 0; |
552 | /* Un-mute output. From Linux. */ | | 554 | /* Un-mute output. From Linux. */ |
553 | bus_space_write_4(sc->iot, sc->aud_ioh, ICH_SIS_NV_CTL, | | 555 | bus_space_write_4(sc->iot, sc->aud_ioh, ICH_SIS_NV_CTL, |
554 | bus_space_read_4(sc->iot, sc->aud_ioh, ICH_SIS_NV_CTL) | | | 556 | bus_space_read_4(sc->iot, sc->aud_ioh, ICH_SIS_NV_CTL) | |
555 | ICH_SIS_CTL_UNMUTE); | | 557 | ICH_SIS_CTL_UNMUTE); |
556 | } else { | | 558 | } else { |
557 | sc->sc_sts_reg = ICH_STS; | | 559 | sc->sc_sts_reg = ICH_STS; |
558 | sc->sc_sample_shift = 1; | | 560 | sc->sc_sample_shift = 1; |
559 | } | | 561 | } |
560 | | | 562 | |
561 | /* Workaround for a 440MX B-stepping erratum */ | | 563 | /* Workaround for a 440MX B-stepping erratum */ |
562 | sc->sc_dmamap_flags = BUS_DMA_COHERENT; | | 564 | sc->sc_dmamap_flags = BUS_DMA_COHERENT; |
563 | if (d->id == PCIID_440MX) { | | 565 | if (d->id == PCIID_440MX) { |
564 | sc->sc_dmamap_flags |= BUS_DMA_NOCACHE; | | 566 | sc->sc_dmamap_flags |= BUS_DMA_NOCACHE; |
565 | aprint_normal_dev(self, "DMA bug workaround enabled\n"); | | 567 | aprint_normal_dev(self, "DMA bug workaround enabled\n"); |
566 | } | | 568 | } |
567 | | | 569 | |
568 | /* Set up DMA lists. */ | | 570 | /* Set up DMA lists. */ |
569 | sc->pcmo.qptr = sc->pcmi.qptr = sc->mici.qptr = 0; | | 571 | sc->pcmo.qptr = sc->pcmi.qptr = sc->mici.qptr = 0; |
570 | auich_alloc_cdata(sc); | | 572 | auich_alloc_cdata(sc); |
571 | | | 573 | |
572 | DPRINTF(ICH_DEBUG_DMA, ("auich_attach: lists %p %p %p\n", | | 574 | DPRINTF(ICH_DEBUG_DMA, ("auich_attach: lists %p %p %p\n", |
573 | sc->pcmo.dmalist, sc->pcmi.dmalist, sc->mici.dmalist)); | | 575 | sc->pcmo.dmalist, sc->pcmi.dmalist, sc->mici.dmalist)); |
574 | | | 576 | |
575 | /* Modem codecs are always the secondary codec on ICH */ | | 577 | /* Modem codecs are always the secondary codec on ICH */ |
576 | sc->sc_codecnum = sc->sc_codectype == AC97_CODEC_TYPE_MODEM ? 1 : 0; | | 578 | sc->sc_codecnum = sc->sc_codectype == AC97_CODEC_TYPE_MODEM ? 1 : 0; |
577 | | | 579 | |
578 | sc->host_if.arg = sc; | | 580 | sc->host_if.arg = sc; |
579 | sc->host_if.attach = auich_attach_codec; | | 581 | sc->host_if.attach = auich_attach_codec; |
580 | sc->host_if.read = auich_read_codec; | | 582 | sc->host_if.read = auich_read_codec; |
581 | sc->host_if.write = auich_write_codec; | | 583 | sc->host_if.write = auich_write_codec; |
582 | sc->host_if.reset = auich_reset_codec; | | 584 | sc->host_if.reset = auich_reset_codec; |
583 | sc->host_if.flags = auich_flags_codec; | | 585 | sc->host_if.flags = auich_flags_codec; |
584 | sc->host_if.spdif_event = auich_spdif_event; | | 586 | sc->host_if.spdif_event = auich_spdif_event; |
585 | | | 587 | |
586 | subdev = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); | | 588 | subdev = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); |
587 | switch (subdev) { | | 589 | switch (subdev) { |
588 | case 0x202f161f: /* Gateway 7326GZ */ | | 590 | case 0x202f161f: /* Gateway 7326GZ */ |
589 | case 0x203a161f: /* Gateway 4028GZ */ | | 591 | case 0x203a161f: /* Gateway 4028GZ */ |
590 | case 0x204c161f: /* Kvazar-Micro Senator 3592XT */ | | 592 | case 0x204c161f: /* Kvazar-Micro Senator 3592XT */ |
591 | case 0x8144104d: /* Sony VAIO PCG-TR* */ | | 593 | case 0x8144104d: /* Sony VAIO PCG-TR* */ |
592 | case 0x8197104d: /* Sony S1XP */ | | 594 | case 0x8197104d: /* Sony S1XP */ |
593 | case 0x81c0104d: /* Sony VAIO type T */ | | 595 | case 0x81c0104d: /* Sony VAIO type T */ |
594 | case 0x81c5104d: /* Sony VAIO VGN-B1XP */ | | 596 | case 0x81c5104d: /* Sony VAIO VGN-B1XP */ |
595 | sc->sc_codecflags = AC97_HOST_INVERTED_EAMP; | | 597 | sc->sc_codecflags = AC97_HOST_INVERTED_EAMP; |
596 | break; | | 598 | break; |
597 | default: | | 599 | default: |
598 | sc->sc_codecflags = 0; | | 600 | sc->sc_codecflags = 0; |
599 | break; | | 601 | break; |
600 | } | | 602 | } |
601 | | | 603 | |
602 | if (ac97_attach_type(&sc->host_if, self, sc->sc_codectype) != 0) | | 604 | if (ac97_attach_type(&sc->host_if, self, sc->sc_codectype) != 0) |
603 | return; | | 605 | return; |
604 | sc->codec_if->vtbl->unlock(sc->codec_if); | | 606 | sc->codec_if->vtbl->unlock(sc->codec_if); |
605 | | | 607 | |
606 | /* setup audio_format */ | | 608 | /* setup audio_format */ |
607 | if (sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) { | | 609 | if (sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) { |
608 | memcpy(sc->sc_audio_formats, auich_audio_formats, sizeof(auich_audio_formats)); | | 610 | memcpy(sc->sc_audio_formats, auich_audio_formats, sizeof(auich_audio_formats)); |
609 | if (!AC97_IS_4CH(sc->codec_if)) | | 611 | if (!AC97_IS_4CH(sc->codec_if)) |
610 | AUFMT_INVALIDATE(&sc->sc_audio_formats[AUICH_FORMATS_4CH]); | | 612 | AUFMT_INVALIDATE(&sc->sc_audio_formats[AUICH_FORMATS_4CH]); |
611 | if (!AC97_IS_6CH(sc->codec_if)) | | 613 | if (!AC97_IS_6CH(sc->codec_if)) |
612 | AUFMT_INVALIDATE(&sc->sc_audio_formats[AUICH_FORMATS_6CH]); | | 614 | AUFMT_INVALIDATE(&sc->sc_audio_formats[AUICH_FORMATS_6CH]); |
613 | if (AC97_IS_FIXED_RATE(sc->codec_if)) { | | 615 | if (AC97_IS_FIXED_RATE(sc->codec_if)) { |
614 | for (i = 0; i < AUICH_AUDIO_NFORMATS; i++) { | | 616 | for (i = 0; i < AUICH_AUDIO_NFORMATS; i++) { |
615 | sc->sc_audio_formats[i].frequency_type = 1; | | 617 | sc->sc_audio_formats[i].frequency_type = 1; |
616 | sc->sc_audio_formats[i].frequency[0] = 48000; | | 618 | sc->sc_audio_formats[i].frequency[0] = 48000; |
617 | } | | 619 | } |
618 | } | | 620 | } |
619 | if (0 != auconv_create_encodings(sc->sc_audio_formats, AUICH_AUDIO_NFORMATS, | | 621 | if (0 != auconv_create_encodings(sc->sc_audio_formats, AUICH_AUDIO_NFORMATS, |
620 | &sc->sc_encodings)) | | 622 | &sc->sc_encodings)) |
621 | return; | | 623 | return; |
622 | if (0 != auconv_create_encodings(auich_spdif_formats, AUICH_SPDIF_NFORMATS, | | 624 | if (0 != auconv_create_encodings(auich_spdif_formats, AUICH_SPDIF_NFORMATS, |
623 | &sc->sc_spdif_encodings)) | | 625 | &sc->sc_spdif_encodings)) |
624 | return; | | 626 | return; |
625 | } else { | | 627 | } else { |
626 | memcpy(sc->sc_modem_formats, auich_modem_formats, sizeof(auich_modem_formats)); | | 628 | memcpy(sc->sc_modem_formats, auich_modem_formats, sizeof(auich_modem_formats)); |
627 | if (0 != auconv_create_encodings(sc->sc_modem_formats, AUICH_MODEM_NFORMATS, | | 629 | if (0 != auconv_create_encodings(sc->sc_modem_formats, AUICH_MODEM_NFORMATS, |
628 | &sc->sc_encodings)) | | 630 | &sc->sc_encodings)) |
629 | return; | | 631 | return; |
630 | } | | 632 | } |
631 | | | 633 | |
632 | /* Watch for power change */ | | 634 | /* Watch for power change */ |
633 | if (!pmf_device_register(self, NULL, auich_resume)) | | 635 | if (!pmf_device_register(self, NULL, auich_resume)) |
634 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 636 | aprint_error_dev(self, "couldn't establish power handler\n"); |
635 | | | 637 | |
636 | config_interrupts(self, auich_finish_attach); | | 638 | config_interrupts(self, auich_finish_attach); |
637 | | | 639 | |
638 | /* sysctl setup */ | | 640 | /* sysctl setup */ |
639 | if (AC97_IS_FIXED_RATE(sc->codec_if) && | | 641 | if (AC97_IS_FIXED_RATE(sc->codec_if) && |
640 | sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) | | 642 | sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) |
641 | return; | | 643 | return; |
642 | | | 644 | |
643 | err = sysctl_createv(&sc->sc_log, 0, NULL, NULL, 0, | | 645 | err = sysctl_createv(&sc->sc_log, 0, NULL, NULL, 0, |
644 | CTLTYPE_NODE, "hw", NULL, NULL, 0, NULL, 0, | | 646 | CTLTYPE_NODE, "hw", NULL, NULL, 0, NULL, 0, |
645 | CTL_HW, CTL_EOL); | | 647 | CTL_HW, CTL_EOL); |
646 | if (err != 0) | | 648 | if (err != 0) |
647 | goto sysctl_err; | | 649 | goto sysctl_err; |
648 | err = sysctl_createv(&sc->sc_log, 0, NULL, &node, 0, | | 650 | err = sysctl_createv(&sc->sc_log, 0, NULL, &node, 0, |
649 | CTLTYPE_NODE, device_xname(self), NULL, NULL, 0, | | 651 | CTLTYPE_NODE, device_xname(self), NULL, NULL, 0, |
650 | NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); | | 652 | NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); |
651 | if (err != 0) | | 653 | if (err != 0) |
652 | goto sysctl_err; | | 654 | goto sysctl_err; |
653 | node_mib = node->sysctl_num; | | 655 | node_mib = node->sysctl_num; |
654 | | | 656 | |
655 | if (!AC97_IS_FIXED_RATE(sc->codec_if)) { | | 657 | if (!AC97_IS_FIXED_RATE(sc->codec_if)) { |
656 | /* passing the sc address instead of &sc->sc_ac97_clock */ | | 658 | /* passing the sc address instead of &sc->sc_ac97_clock */ |
657 | err = sysctl_createv(&sc->sc_log, 0, NULL, &node_ac97clock, | | 659 | err = sysctl_createv(&sc->sc_log, 0, NULL, &node_ac97clock, |
658 | CTLFLAG_READWRITE, | | 660 | CTLFLAG_READWRITE, |
659 | CTLTYPE_INT, "ac97rate", | | 661 | CTLTYPE_INT, "ac97rate", |
660 | SYSCTL_DESCR("AC'97 codec link rate"), | | 662 | SYSCTL_DESCR("AC'97 codec link rate"), |
661 | auich_sysctl_verify, 0, sc, 0, | | 663 | auich_sysctl_verify, 0, sc, 0, |
662 | CTL_HW, node_mib, CTL_CREATE, CTL_EOL); | | 664 | CTL_HW, node_mib, CTL_CREATE, CTL_EOL); |
663 | if (err != 0) | | 665 | if (err != 0) |
664 | goto sysctl_err; | | 666 | goto sysctl_err; |
665 | sc->sc_ac97_clock_mib = node_ac97clock->sysctl_num; | | 667 | sc->sc_ac97_clock_mib = node_ac97clock->sysctl_num; |
666 | } | | 668 | } |
667 | | | 669 | |
668 | return; | | 670 | return; |
669 | | | 671 | |
670 | sysctl_err: | | 672 | sysctl_err: |
671 | printf("%s: failed to add sysctl nodes. (%d)\n", | | 673 | printf("%s: failed to add sysctl nodes. (%d)\n", |
672 | device_xname(self), err); | | 674 | device_xname(self), err); |
673 | return; /* failure of sysctl is not fatal. */ | | 675 | return; /* failure of sysctl is not fatal. */ |
674 | } | | 676 | } |
675 | | | 677 | |
676 | static int | | 678 | static int |
677 | auich_activate(device_t self, enum devact act) | | 679 | auich_activate(device_t self, enum devact act) |
678 | { | | 680 | { |
679 | struct auich_softc *sc = device_private(self); | | 681 | struct auich_softc *sc = device_private(self); |
680 | int ret; | | 682 | int ret; |
681 | | | 683 | |
682 | ret = 0; | | 684 | ret = 0; |
683 | switch (act) { | | 685 | switch (act) { |
684 | case DVACT_ACTIVATE: | | 686 | case DVACT_ACTIVATE: |
685 | return EOPNOTSUPP; | | 687 | return EOPNOTSUPP; |
686 | case DVACT_DEACTIVATE: | | 688 | case DVACT_DEACTIVATE: |
687 | if (sc->sc_audiodev != NULL) | | 689 | if (sc->sc_audiodev != NULL) |
688 | ret = config_deactivate(sc->sc_audiodev); | | 690 | ret = config_deactivate(sc->sc_audiodev); |
689 | return ret; | | 691 | return ret; |
690 | } | | 692 | } |
691 | return EOPNOTSUPP; | | 693 | return EOPNOTSUPP; |
692 | } | | 694 | } |
| | | 695 | |
| | | 696 | static void |
| | | 697 | auich_childdet(device_t self, device_t child) |
| | | 698 | { |
| | | 699 | struct auich_softc *sc = device_private(self); |
| | | 700 | |
| | | 701 | KASSERT(sc->sc_audiodev == child); |
| | | 702 | sc->sc_audiodev = NULL; |
| | | 703 | } |
693 | | | 704 | |
694 | static int | | 705 | static int |
695 | auich_detach(device_t self, int flags) | | 706 | auich_detach(device_t self, int flags) |
696 | { | | 707 | { |
697 | struct auich_softc *sc = device_private(self); | | 708 | struct auich_softc *sc = device_private(self); |
698 | | | 709 | |
699 | /* audio */ | | 710 | /* audio */ |
700 | if (sc->sc_audiodev != NULL) | | 711 | if (sc->sc_audiodev != NULL) |
701 | config_detach(sc->sc_audiodev, flags); | | 712 | config_detach(sc->sc_audiodev, flags); |
702 | | | 713 | |
703 | /* sysctl */ | | 714 | /* sysctl */ |
704 | sysctl_teardown(&sc->sc_log); | | 715 | sysctl_teardown(&sc->sc_log); |
705 | | | 716 | |
706 | /* audio_encoding_set */ | | 717 | /* audio_encoding_set */ |
707 | auconv_delete_encodings(sc->sc_encodings); | | 718 | auconv_delete_encodings(sc->sc_encodings); |
708 | auconv_delete_encodings(sc->sc_spdif_encodings); | | 719 | auconv_delete_encodings(sc->sc_spdif_encodings); |
709 | | | 720 | |
710 | /* ac97 */ | | 721 | /* ac97 */ |
711 | if (sc->codec_if != NULL) | | 722 | if (sc->codec_if != NULL) |
712 | sc->codec_if->vtbl->detach(sc->codec_if); | | 723 | sc->codec_if->vtbl->detach(sc->codec_if); |
713 | | | 724 | |
714 | /* PCI */ | | 725 | /* PCI */ |
715 | if (sc->sc_ih != NULL) | | 726 | if (sc->sc_ih != NULL) |
716 | pci_intr_disestablish(sc->sc_pc, sc->sc_ih); | | 727 | pci_intr_disestablish(sc->sc_pc, sc->sc_ih); |
717 | if (sc->mix_size != 0) | | 728 | if (sc->mix_size != 0) |
718 | bus_space_unmap(sc->iot, sc->mix_ioh, sc->mix_size); | | 729 | bus_space_unmap(sc->iot, sc->mix_ioh, sc->mix_size); |
719 | if (sc->aud_size != 0) | | 730 | if (sc->aud_size != 0) |
720 | bus_space_unmap(sc->iot, sc->aud_ioh, sc->aud_size); | | 731 | bus_space_unmap(sc->iot, sc->aud_ioh, sc->aud_size); |
721 | return 0; | | 732 | return 0; |
722 | } | | 733 | } |
723 | | | 734 | |
724 | static int | | 735 | static int |
725 | auich_sysctl_verify(SYSCTLFN_ARGS) | | 736 | auich_sysctl_verify(SYSCTLFN_ARGS) |
726 | { | | 737 | { |
727 | int error, tmp; | | 738 | int error, tmp; |
728 | struct sysctlnode node; | | 739 | struct sysctlnode node; |
729 | struct auich_softc *sc; | | 740 | struct auich_softc *sc; |
730 | | | 741 | |
731 | node = *rnode; | | 742 | node = *rnode; |
732 | sc = rnode->sysctl_data; | | 743 | sc = rnode->sysctl_data; |
733 | if (node.sysctl_num == sc->sc_ac97_clock_mib) { | | 744 | if (node.sysctl_num == sc->sc_ac97_clock_mib) { |
734 | tmp = sc->sc_ac97_clock; | | 745 | tmp = sc->sc_ac97_clock; |
735 | node.sysctl_data = &tmp; | | 746 | node.sysctl_data = &tmp; |
736 | error = sysctl_lookup(SYSCTLFN_CALL(&node)); | | 747 | error = sysctl_lookup(SYSCTLFN_CALL(&node)); |
737 | if (error || newp == NULL) | | 748 | if (error || newp == NULL) |
738 | return error; | | 749 | return error; |
739 | | | 750 | |
740 | if (tmp < 48000 || tmp > 96000) | | 751 | if (tmp < 48000 || tmp > 96000) |
741 | return EINVAL; | | 752 | return EINVAL; |
742 | sc->sc_ac97_clock = tmp; | | 753 | sc->sc_ac97_clock = tmp; |
743 | } | | 754 | } |
744 | | | 755 | |
745 | return 0; | | 756 | return 0; |
746 | } | | 757 | } |
747 | | | 758 | |
748 | static void | | 759 | static void |
749 | auich_finish_attach(device_t self) | | 760 | auich_finish_attach(device_t self) |
750 | { | | 761 | { |
751 | struct auich_softc *sc = device_private(self); | | 762 | struct auich_softc *sc = device_private(self); |
752 | | | 763 | |
753 | if (!AC97_IS_FIXED_RATE(sc->codec_if)) | | 764 | if (!AC97_IS_FIXED_RATE(sc->codec_if)) |
754 | auich_calibrate(sc); | | 765 | auich_calibrate(sc); |
755 | | | 766 | |
756 | sc->sc_audiodev = audio_attach_mi(&auich_hw_if, sc, sc->sc_dev); | | 767 | sc->sc_audiodev = audio_attach_mi(&auich_hw_if, sc, sc->sc_dev); |
757 | | | 768 | |
758 | return; | | 769 | return; |
759 | } | | 770 | } |
760 | | | 771 | |
761 | #define ICH_CODECIO_INTERVAL 10 | | 772 | #define ICH_CODECIO_INTERVAL 10 |
762 | static int | | 773 | static int |
763 | auich_read_codec(void *v, uint8_t reg, uint16_t *val) | | 774 | auich_read_codec(void *v, uint8_t reg, uint16_t *val) |
764 | { | | 775 | { |
765 | struct auich_softc *sc; | | 776 | struct auich_softc *sc; |
766 | int i; | | 777 | int i; |
767 | uint32_t status; | | 778 | uint32_t status; |
768 | | | 779 | |
769 | sc = v; | | 780 | sc = v; |
770 | /* wait for an access semaphore */ | | 781 | /* wait for an access semaphore */ |
771 | for (i = ICH_SEMATIMO / ICH_CODECIO_INTERVAL; i-- && | | 782 | for (i = ICH_SEMATIMO / ICH_CODECIO_INTERVAL; i-- && |
772 | bus_space_read_1(sc->iot, sc->aud_ioh, | | 783 | bus_space_read_1(sc->iot, sc->aud_ioh, |
773 | ICH_CAS + sc->sc_modem_offset) & 1; | | 784 | ICH_CAS + sc->sc_modem_offset) & 1; |
774 | DELAY(ICH_CODECIO_INTERVAL)); | | 785 | DELAY(ICH_CODECIO_INTERVAL)); |
775 | | | 786 | |
776 | if (i > 0) { | | 787 | if (i > 0) { |
777 | *val = bus_space_read_2(sc->iot, sc->mix_ioh, | | 788 | *val = bus_space_read_2(sc->iot, sc->mix_ioh, |
778 | reg + (sc->sc_codecnum * ICH_CODEC_OFFSET)); | | 789 | reg + (sc->sc_codecnum * ICH_CODEC_OFFSET)); |
779 | DPRINTF(ICH_DEBUG_CODECIO, | | 790 | DPRINTF(ICH_DEBUG_CODECIO, |
780 | ("auich_read_codec(%x, %x)\n", reg, *val)); | | 791 | ("auich_read_codec(%x, %x)\n", reg, *val)); |
781 | status = bus_space_read_4(sc->iot, sc->aud_ioh, | | 792 | status = bus_space_read_4(sc->iot, sc->aud_ioh, |
782 | ICH_GSTS + sc->sc_modem_offset); | | 793 | ICH_GSTS + sc->sc_modem_offset); |
783 | if (status & ICH_RCS) { | | 794 | if (status & ICH_RCS) { |
784 | bus_space_write_4(sc->iot, sc->aud_ioh, | | 795 | bus_space_write_4(sc->iot, sc->aud_ioh, |
785 | ICH_GSTS + sc->sc_modem_offset, | | 796 | ICH_GSTS + sc->sc_modem_offset, |
786 | status & ~(ICH_SRI|ICH_PRI|ICH_GSCI)); | | 797 | status & ~(ICH_SRI|ICH_PRI|ICH_GSCI)); |
787 | *val = 0xffff; | | 798 | *val = 0xffff; |
788 | DPRINTF(ICH_DEBUG_CODECIO, | | 799 | DPRINTF(ICH_DEBUG_CODECIO, |
789 | ("%s: read_codec error\n", device_xname(sc->sc_dev))); | | 800 | ("%s: read_codec error\n", device_xname(sc->sc_dev))); |
790 | if (reg == AC97_REG_GPIO_STATUS) | | 801 | if (reg == AC97_REG_GPIO_STATUS) |
791 | auich_clear_cas(sc); | | 802 | auich_clear_cas(sc); |
792 | return -1; | | 803 | return -1; |
793 | } | | 804 | } |
794 | if (reg == AC97_REG_GPIO_STATUS) | | 805 | if (reg == AC97_REG_GPIO_STATUS) |
795 | auich_clear_cas(sc); | | 806 | auich_clear_cas(sc); |
796 | return 0; | | 807 | return 0; |
797 | } else { | | 808 | } else { |
798 | aprint_normal_dev(sc->sc_dev, "read_codec timeout\n"); | | 809 | aprint_normal_dev(sc->sc_dev, "read_codec timeout\n"); |
799 | if (reg == AC97_REG_GPIO_STATUS) | | 810 | if (reg == AC97_REG_GPIO_STATUS) |
800 | auich_clear_cas(sc); | | 811 | auich_clear_cas(sc); |
801 | return -1; | | 812 | return -1; |
802 | } | | 813 | } |
803 | } | | 814 | } |
804 | | | 815 | |
805 | static int | | 816 | static int |
806 | auich_write_codec(void *v, uint8_t reg, uint16_t val) | | 817 | auich_write_codec(void *v, uint8_t reg, uint16_t val) |
807 | { | | 818 | { |
808 | struct auich_softc *sc; | | 819 | struct auich_softc *sc; |
809 | int i; | | 820 | int i; |
810 | | | 821 | |
811 | DPRINTF(ICH_DEBUG_CODECIO, ("auich_write_codec(%x, %x)\n", reg, val)); | | 822 | DPRINTF(ICH_DEBUG_CODECIO, ("auich_write_codec(%x, %x)\n", reg, val)); |
812 | sc = v; | | 823 | sc = v; |
813 | /* wait for an access semaphore */ | | 824 | /* wait for an access semaphore */ |
814 | for (i = ICH_SEMATIMO / ICH_CODECIO_INTERVAL; i-- && | | 825 | for (i = ICH_SEMATIMO / ICH_CODECIO_INTERVAL; i-- && |
815 | bus_space_read_1(sc->iot, sc->aud_ioh, | | 826 | bus_space_read_1(sc->iot, sc->aud_ioh, |
816 | ICH_CAS + sc->sc_modem_offset) & 1; | | 827 | ICH_CAS + sc->sc_modem_offset) & 1; |
817 | DELAY(ICH_CODECIO_INTERVAL)); | | 828 | DELAY(ICH_CODECIO_INTERVAL)); |
818 | | | 829 | |
819 | if (i > 0) { | | 830 | if (i > 0) { |
820 | bus_space_write_2(sc->iot, sc->mix_ioh, | | 831 | bus_space_write_2(sc->iot, sc->mix_ioh, |
821 | reg + (sc->sc_codecnum * ICH_CODEC_OFFSET), val); | | 832 | reg + (sc->sc_codecnum * ICH_CODEC_OFFSET), val); |
822 | return 0; | | 833 | return 0; |
823 | } else { | | 834 | } else { |
824 | aprint_normal_dev(sc->sc_dev, "write_codec timeout\n"); | | 835 | aprint_normal_dev(sc->sc_dev, "write_codec timeout\n"); |
825 | return -1; | | 836 | return -1; |
826 | } | | 837 | } |
827 | } | | 838 | } |
828 | | | 839 | |
829 | static int | | 840 | static int |
830 | auich_attach_codec(void *v, struct ac97_codec_if *cif) | | 841 | auich_attach_codec(void *v, struct ac97_codec_if *cif) |
831 | { | | 842 | { |
832 | struct auich_softc *sc; | | 843 | struct auich_softc *sc; |
833 | | | 844 | |
834 | sc = v; | | 845 | sc = v; |
835 | sc->codec_if = cif; | | 846 | sc->codec_if = cif; |
836 | | | 847 | |
837 | return 0; | | 848 | return 0; |
838 | } | | 849 | } |
839 | | | 850 | |
840 | static int | | 851 | static int |
841 | auich_reset_codec(void *v) | | 852 | auich_reset_codec(void *v) |
842 | { | | 853 | { |
843 | struct auich_softc *sc; | | 854 | struct auich_softc *sc; |
844 | int i; | | 855 | int i; |
845 | uint32_t control, status; | | 856 | uint32_t control, status; |
846 | | | 857 | |
847 | sc = v; | | 858 | sc = v; |
848 | control = bus_space_read_4(sc->iot, sc->aud_ioh, | | 859 | control = bus_space_read_4(sc->iot, sc->aud_ioh, |
849 | ICH_GCTRL + sc->sc_modem_offset); | | 860 | ICH_GCTRL + sc->sc_modem_offset); |
850 | if (sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) { | | 861 | if (sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) { |
851 | control &= ~(ICH_ACLSO | ICH_PCM246_MASK); | | 862 | control &= ~(ICH_ACLSO | ICH_PCM246_MASK); |
852 | } else { | | 863 | } else { |
853 | control &= ~ICH_ACLSO; | | 864 | control &= ~ICH_ACLSO; |
854 | control |= ICH_GIE; | | 865 | control |= ICH_GIE; |
855 | } | | 866 | } |
856 | control |= (control & ICH_CRESET) ? ICH_WRESET : ICH_CRESET; | | 867 | control |= (control & ICH_CRESET) ? ICH_WRESET : ICH_CRESET; |
857 | bus_space_write_4(sc->iot, sc->aud_ioh, | | 868 | bus_space_write_4(sc->iot, sc->aud_ioh, |
858 | ICH_GCTRL + sc->sc_modem_offset, control); | | 869 | ICH_GCTRL + sc->sc_modem_offset, control); |
859 | | | 870 | |
860 | for (i = 500000; i >= 0; i--) { | | 871 | for (i = 500000; i >= 0; i--) { |
861 | status = bus_space_read_4(sc->iot, sc->aud_ioh, | | 872 | status = bus_space_read_4(sc->iot, sc->aud_ioh, |
862 | ICH_GSTS + sc->sc_modem_offset); | | 873 | ICH_GSTS + sc->sc_modem_offset); |
863 | if (status & (ICH_PCR | ICH_SCR | ICH_S2CR)) | | 874 | if (status & (ICH_PCR | ICH_SCR | ICH_S2CR)) |
864 | break; | | 875 | break; |
865 | DELAY(1); | | 876 | DELAY(1); |
866 | } | | 877 | } |
867 | if (i <= 0) { | | 878 | if (i <= 0) { |
868 | aprint_error_dev(sc->sc_dev, "auich_reset_codec: time out\n"); | | 879 | aprint_error_dev(sc->sc_dev, "auich_reset_codec: time out\n"); |
869 | return ETIMEDOUT; | | 880 | return ETIMEDOUT; |
870 | } | | 881 | } |
871 | #ifdef AUICH_DEBUG | | 882 | #ifdef AUICH_DEBUG |
872 | if (status & ICH_SCR) | | 883 | if (status & ICH_SCR) |
873 | printf("%s: The 2nd codec is ready.\n", | | 884 | printf("%s: The 2nd codec is ready.\n", |
874 | device_xname(sc->sc_dev)); | | 885 | device_xname(sc->sc_dev)); |
875 | if (status & ICH_S2CR) | | 886 | if (status & ICH_S2CR) |
876 | printf("%s: The 3rd codec is ready.\n", | | 887 | printf("%s: The 3rd codec is ready.\n", |
877 | device_xname(sc->sc_dev)); | | 888 | device_xname(sc->sc_dev)); |
878 | #endif | | 889 | #endif |
879 | return 0; | | 890 | return 0; |
880 | } | | 891 | } |
881 | | | 892 | |
882 | static enum ac97_host_flags | | 893 | static enum ac97_host_flags |
883 | auich_flags_codec(void *v) | | 894 | auich_flags_codec(void *v) |
884 | { | | 895 | { |
885 | struct auich_softc *sc = v; | | 896 | struct auich_softc *sc = v; |
886 | return sc->sc_codecflags; | | 897 | return sc->sc_codecflags; |
887 | } | | 898 | } |
888 | | | 899 | |
889 | static void | | 900 | static void |
890 | auich_spdif_event(void *addr, bool flag) | | 901 | auich_spdif_event(void *addr, bool flag) |
891 | { | | 902 | { |
892 | struct auich_softc *sc; | | 903 | struct auich_softc *sc; |
893 | | | 904 | |
894 | sc = addr; | | 905 | sc = addr; |
895 | sc->sc_spdif = flag; | | 906 | sc->sc_spdif = flag; |
896 | } | | 907 | } |
897 | | | 908 | |
898 | static int | | 909 | static int |
899 | auich_open(void *addr, int flags) | | 910 | auich_open(void *addr, int flags) |
900 | { | | 911 | { |
901 | struct auich_softc *sc; | | 912 | struct auich_softc *sc; |
902 | | | 913 | |
903 | sc = (struct auich_softc *)addr; | | 914 | sc = (struct auich_softc *)addr; |
904 | sc->codec_if->vtbl->lock(sc->codec_if); | | 915 | sc->codec_if->vtbl->lock(sc->codec_if); |
905 | return 0; | | 916 | return 0; |
906 | } | | 917 | } |
907 | | | 918 | |
908 | static void | | 919 | static void |
909 | auich_close(void *addr) | | 920 | auich_close(void *addr) |
910 | { | | 921 | { |
911 | struct auich_softc *sc; | | 922 | struct auich_softc *sc; |
912 | | | 923 | |
913 | sc = (struct auich_softc *)addr; | | 924 | sc = (struct auich_softc *)addr; |
914 | sc->codec_if->vtbl->unlock(sc->codec_if); | | 925 | sc->codec_if->vtbl->unlock(sc->codec_if); |
915 | } | | 926 | } |
916 | | | 927 | |
917 | static int | | 928 | static int |
918 | auich_query_encoding(void *v, struct audio_encoding *aep) | | 929 | auich_query_encoding(void *v, struct audio_encoding *aep) |
919 | { | | 930 | { |
920 | struct auich_softc *sc; | | 931 | struct auich_softc *sc; |
921 | | | 932 | |
922 | sc = (struct auich_softc *)v; | | 933 | sc = (struct auich_softc *)v; |
923 | return auconv_query_encoding( | | 934 | return auconv_query_encoding( |
924 | sc->sc_spdif ? sc->sc_spdif_encodings : sc->sc_encodings, aep); | | 935 | sc->sc_spdif ? sc->sc_spdif_encodings : sc->sc_encodings, aep); |
925 | } | | 936 | } |
926 | | | 937 | |
927 | static int | | 938 | static int |
928 | auich_set_rate(struct auich_softc *sc, int mode, u_long srate) | | 939 | auich_set_rate(struct auich_softc *sc, int mode, u_long srate) |
929 | { | | 940 | { |
930 | int ret; | | 941 | int ret; |
931 | u_int ratetmp; | | 942 | u_int ratetmp; |
932 | | | 943 | |
933 | sc->codec_if->vtbl->set_clock(sc->codec_if, sc->sc_ac97_clock); | | 944 | sc->codec_if->vtbl->set_clock(sc->codec_if, sc->sc_ac97_clock); |
934 | ratetmp = srate; | | 945 | ratetmp = srate; |
935 | if (mode == AUMODE_RECORD) | | 946 | if (mode == AUMODE_RECORD) |
936 | return sc->codec_if->vtbl->set_rate(sc->codec_if, | | 947 | return sc->codec_if->vtbl->set_rate(sc->codec_if, |
937 | AC97_REG_PCM_LR_ADC_RATE, &ratetmp); | | 948 | AC97_REG_PCM_LR_ADC_RATE, &ratetmp); |
938 | ret = sc->codec_if->vtbl->set_rate(sc->codec_if, | | 949 | ret = sc->codec_if->vtbl->set_rate(sc->codec_if, |
939 | AC97_REG_PCM_FRONT_DAC_RATE, &ratetmp); | | 950 | AC97_REG_PCM_FRONT_DAC_RATE, &ratetmp); |
940 | if (ret) | | 951 | if (ret) |
941 | return ret; | | 952 | return ret; |
942 | ratetmp = srate; | | 953 | ratetmp = srate; |
943 | ret = sc->codec_if->vtbl->set_rate(sc->codec_if, | | 954 | ret = sc->codec_if->vtbl->set_rate(sc->codec_if, |
944 | AC97_REG_PCM_SURR_DAC_RATE, &ratetmp); | | 955 | AC97_REG_PCM_SURR_DAC_RATE, &ratetmp); |
945 | if (ret) | | 956 | if (ret) |
946 | return ret; | | 957 | return ret; |
947 | ratetmp = srate; | | 958 | ratetmp = srate; |
948 | ret = sc->codec_if->vtbl->set_rate(sc->codec_if, | | 959 | ret = sc->codec_if->vtbl->set_rate(sc->codec_if, |
949 | AC97_REG_PCM_LFE_DAC_RATE, &ratetmp); | | 960 | AC97_REG_PCM_LFE_DAC_RATE, &ratetmp); |
950 | return ret; | | 961 | return ret; |
951 | } | | 962 | } |
952 | | | 963 | |
953 | static int | | 964 | static int |
954 | auich_set_params(void *v, int setmode, int usemode, | | 965 | auich_set_params(void *v, int setmode, int usemode, |
955 | audio_params_t *play, audio_params_t *rec, stream_filter_list_t *pfil, | | 966 | audio_params_t *play, audio_params_t *rec, stream_filter_list_t *pfil, |
956 | stream_filter_list_t *rfil) | | 967 | stream_filter_list_t *rfil) |
957 | { | | 968 | { |
958 | struct auich_softc *sc; | | 969 | struct auich_softc *sc; |
959 | audio_params_t *p; | | 970 | audio_params_t *p; |
960 | stream_filter_list_t *fil; | | 971 | stream_filter_list_t *fil; |
961 | int mode, index; | | 972 | int mode, index; |
962 | uint32_t control; | | 973 | uint32_t control; |
963 | | | 974 | |
964 | sc = v; | | 975 | sc = v; |
965 | for (mode = AUMODE_RECORD; mode != -1; | | 976 | for (mode = AUMODE_RECORD; mode != -1; |
966 | mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { | | 977 | mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { |
967 | if ((setmode & mode) == 0) | | 978 | if ((setmode & mode) == 0) |
968 | continue; | | 979 | continue; |
969 | | | 980 | |
970 | p = mode == AUMODE_PLAY ? play : rec; | | 981 | p = mode == AUMODE_PLAY ? play : rec; |
971 | fil = mode == AUMODE_PLAY ? pfil : rfil; | | 982 | fil = mode == AUMODE_PLAY ? pfil : rfil; |
972 | if (p == NULL) | | 983 | if (p == NULL) |
973 | continue; | | 984 | continue; |
974 | | | 985 | |
975 | if (sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) { | | 986 | if (sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) { |
976 | if (p->sample_rate < 8000 || | | 987 | if (p->sample_rate < 8000 || |
977 | p->sample_rate > 48000) | | 988 | p->sample_rate > 48000) |
978 | return EINVAL; | | 989 | return EINVAL; |
979 | | | 990 | |
980 | if (!sc->sc_spdif) | | 991 | if (!sc->sc_spdif) |
981 | index = auconv_set_converter(sc->sc_audio_formats, | | 992 | index = auconv_set_converter(sc->sc_audio_formats, |
982 | AUICH_AUDIO_NFORMATS, mode, p, TRUE, fil); | | 993 | AUICH_AUDIO_NFORMATS, mode, p, TRUE, fil); |
983 | else | | 994 | else |
984 | index = auconv_set_converter(auich_spdif_formats, | | 995 | index = auconv_set_converter(auich_spdif_formats, |
985 | AUICH_SPDIF_NFORMATS, mode, p, TRUE, fil); | | 996 | AUICH_SPDIF_NFORMATS, mode, p, TRUE, fil); |
986 | } else { | | 997 | } else { |
987 | if (p->sample_rate != 8000 && p->sample_rate != 16000) | | 998 | if (p->sample_rate != 8000 && p->sample_rate != 16000) |
988 | return EINVAL; | | 999 | return EINVAL; |
989 | index = auconv_set_converter(sc->sc_modem_formats, | | 1000 | index = auconv_set_converter(sc->sc_modem_formats, |
990 | AUICH_MODEM_NFORMATS, mode, p, TRUE, fil); | | 1001 | AUICH_MODEM_NFORMATS, mode, p, TRUE, fil); |
991 | } | | 1002 | } |
992 | if (index < 0) | | 1003 | if (index < 0) |
993 | return EINVAL; | | 1004 | return EINVAL; |
994 | if (fil->req_size > 0) | | 1005 | if (fil->req_size > 0) |
995 | p = &fil->filters[0].param; | | 1006 | p = &fil->filters[0].param; |
996 | /* p represents HW encoding */ | | 1007 | /* p represents HW encoding */ |
997 | if (sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) { | | 1008 | if (sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) { |
998 | if (sc->sc_audio_formats[index].frequency_type != 1 | | 1009 | if (sc->sc_audio_formats[index].frequency_type != 1 |
999 | && auich_set_rate(sc, mode, p->sample_rate)) | | 1010 | && auich_set_rate(sc, mode, p->sample_rate)) |
1000 | return EINVAL; | | 1011 | return EINVAL; |
1001 | } else { | | 1012 | } else { |
1002 | if (sc->sc_modem_formats[index].frequency_type != 1 | | 1013 | if (sc->sc_modem_formats[index].frequency_type != 1 |
1003 | && auich_set_rate(sc, mode, p->sample_rate)) | | 1014 | && auich_set_rate(sc, mode, p->sample_rate)) |
1004 | return EINVAL; | | 1015 | return EINVAL; |
1005 | auich_write_codec(sc, AC97_REG_LINE1_RATE, | | 1016 | auich_write_codec(sc, AC97_REG_LINE1_RATE, |
1006 | p->sample_rate); | | 1017 | p->sample_rate); |
1007 | auich_write_codec(sc, AC97_REG_LINE1_LEVEL, 0); | | 1018 | auich_write_codec(sc, AC97_REG_LINE1_LEVEL, 0); |
1008 | } | | 1019 | } |
1009 | if (mode == AUMODE_PLAY && | | 1020 | if (mode == AUMODE_PLAY && |
1010 | sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) { | | 1021 | sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) { |
1011 | control = bus_space_read_4(sc->iot, sc->aud_ioh, | | 1022 | control = bus_space_read_4(sc->iot, sc->aud_ioh, |
1012 | ICH_GCTRL + sc->sc_modem_offset); | | 1023 | ICH_GCTRL + sc->sc_modem_offset); |
1013 | control &= ~ICH_PCM246_MASK; | | 1024 | control &= ~ICH_PCM246_MASK; |
1014 | if (p->channels == 4) { | | 1025 | if (p->channels == 4) { |
1015 | control |= ICH_PCM4; | | 1026 | control |= ICH_PCM4; |
1016 | } else if (p->channels == 6) { | | 1027 | } else if (p->channels == 6) { |
1017 | control |= ICH_PCM6; | | 1028 | control |= ICH_PCM6; |
1018 | } | | 1029 | } |
1019 | bus_space_write_4(sc->iot, sc->aud_ioh, | | 1030 | bus_space_write_4(sc->iot, sc->aud_ioh, |
1020 | ICH_GCTRL + sc->sc_modem_offset, control); | | 1031 | ICH_GCTRL + sc->sc_modem_offset, control); |
1021 | } | | 1032 | } |
1022 | } | | 1033 | } |
1023 | | | 1034 | |
1024 | return 0; | | 1035 | return 0; |
1025 | } | | 1036 | } |
1026 | | | 1037 | |
1027 | static int | | 1038 | static int |
1028 | auich_round_blocksize(void *v, int blk, int mode, | | 1039 | auich_round_blocksize(void *v, int blk, int mode, |
1029 | const audio_params_t *param) | | 1040 | const audio_params_t *param) |
1030 | { | | 1041 | { |
1031 | | | 1042 | |
1032 | return blk & ~0x3f; /* keep good alignment */ | | 1043 | return blk & ~0x3f; /* keep good alignment */ |
1033 | } | | 1044 | } |
1034 | | | 1045 | |
1035 | static void | | 1046 | static void |
1036 | auich_halt_pipe(struct auich_softc *sc, int pipe) | | 1047 | auich_halt_pipe(struct auich_softc *sc, int pipe) |
1037 | { | | 1048 | { |
1038 | int i; | | 1049 | int i; |
1039 | uint32_t status; | | 1050 | uint32_t status; |
1040 | | | 1051 | |
1041 | bus_space_write_1(sc->iot, sc->aud_ioh, pipe + ICH_CTRL, 0); | | 1052 | bus_space_write_1(sc->iot, sc->aud_ioh, pipe + ICH_CTRL, 0); |
1042 | for (i = 0; i < 100; i++) { | | 1053 | for (i = 0; i < 100; i++) { |
1043 | status = bus_space_read_4(sc->iot, sc->aud_ioh, pipe + ICH_STS); | | 1054 | status = bus_space_read_4(sc->iot, sc->aud_ioh, pipe + ICH_STS); |
1044 | if (status & ICH_DCH) | | 1055 | if (status & ICH_DCH) |
1045 | break; | | 1056 | break; |
1046 | DELAY(1); | | 1057 | DELAY(1); |
1047 | } | | 1058 | } |
1048 | bus_space_write_1(sc->iot, sc->aud_ioh, pipe + ICH_CTRL, ICH_RR); | | 1059 | bus_space_write_1(sc->iot, sc->aud_ioh, pipe + ICH_CTRL, ICH_RR); |
1049 | | | 1060 | |
1050 | #if AUICH_DEBUG | | 1061 | #if AUICH_DEBUG |
1051 | if (i > 0) | | 1062 | if (i > 0) |
1052 | printf("auich_halt_pipe: halt took %d cycles\n", i); | | 1063 | printf("auich_halt_pipe: halt took %d cycles\n", i); |
1053 | #endif | | 1064 | #endif |
1054 | } | | 1065 | } |
1055 | | | 1066 | |
1056 | static int | | 1067 | static int |
1057 | auich_halt_output(void *v) | | 1068 | auich_halt_output(void *v) |
1058 | { | | 1069 | { |
1059 | struct auich_softc *sc; | | 1070 | struct auich_softc *sc; |
1060 | | | 1071 | |
1061 | sc = v; | | 1072 | sc = v; |
1062 | DPRINTF(ICH_DEBUG_DMA, ("%s: halt_output\n", device_xname(sc->sc_dev))); | | 1073 | DPRINTF(ICH_DEBUG_DMA, ("%s: halt_output\n", device_xname(sc->sc_dev))); |
1063 | | | 1074 | |
1064 | auich_halt_pipe(sc, ICH_PCMO); | | 1075 | auich_halt_pipe(sc, ICH_PCMO); |
1065 | sc->pcmo.intr = NULL; | | 1076 | sc->pcmo.intr = NULL; |
1066 | | | 1077 | |
1067 | return 0; | | 1078 | return 0; |
1068 | } | | 1079 | } |
1069 | | | 1080 | |
1070 | static int | | 1081 | static int |
1071 | auich_halt_input(void *v) | | 1082 | auich_halt_input(void *v) |
1072 | { | | 1083 | { |
1073 | struct auich_softc *sc; | | 1084 | struct auich_softc *sc; |
1074 | | | 1085 | |
1075 | sc = v; | | 1086 | sc = v; |
1076 | DPRINTF(ICH_DEBUG_DMA, ("%s: halt_input\n", device_xname(sc->sc_dev))); | | 1087 | DPRINTF(ICH_DEBUG_DMA, ("%s: halt_input\n", device_xname(sc->sc_dev))); |
1077 | | | 1088 | |
1078 | auich_halt_pipe(sc, ICH_PCMI); | | 1089 | auich_halt_pipe(sc, ICH_PCMI); |
1079 | sc->pcmi.intr = NULL; | | 1090 | sc->pcmi.intr = NULL; |
1080 | | | 1091 | |
1081 | return 0; | | 1092 | return 0; |
1082 | } | | 1093 | } |
1083 | | | 1094 | |
1084 | static int | | 1095 | static int |
1085 | auich_getdev(void *v, struct audio_device *adp) | | 1096 | auich_getdev(void *v, struct audio_device *adp) |
1086 | { | | 1097 | { |
1087 | struct auich_softc *sc; | | 1098 | struct auich_softc *sc; |
1088 | | | 1099 | |
1089 | sc = v; | | 1100 | sc = v; |
1090 | *adp = sc->sc_audev; | | 1101 | *adp = sc->sc_audev; |
1091 | return 0; | | 1102 | return 0; |
1092 | } | | 1103 | } |
1093 | | | 1104 | |
1094 | static int | | 1105 | static int |
1095 | auich_set_port(void *v, mixer_ctrl_t *cp) | | 1106 | auich_set_port(void *v, mixer_ctrl_t *cp) |
1096 | { | | 1107 | { |
1097 | struct auich_softc *sc; | | 1108 | struct auich_softc *sc; |
1098 | | | 1109 | |
1099 | sc = v; | | 1110 | sc = v; |
1100 | return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp); | | 1111 | return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp); |
1101 | } | | 1112 | } |
1102 | | | 1113 | |
1103 | static int | | 1114 | static int |
1104 | auich_get_port(void *v, mixer_ctrl_t *cp) | | 1115 | auich_get_port(void *v, mixer_ctrl_t *cp) |
1105 | { | | 1116 | { |
1106 | struct auich_softc *sc; | | 1117 | struct auich_softc *sc; |
1107 | | | 1118 | |
1108 | sc = v; | | 1119 | sc = v; |
1109 | return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp); | | 1120 | return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp); |
1110 | } | | 1121 | } |
1111 | | | 1122 | |
1112 | static int | | 1123 | static int |
1113 | auich_query_devinfo(void *v, mixer_devinfo_t *dp) | | 1124 | auich_query_devinfo(void *v, mixer_devinfo_t *dp) |
1114 | { | | 1125 | { |
1115 | struct auich_softc *sc; | | 1126 | struct auich_softc *sc; |
1116 | | | 1127 | |
1117 | sc = v; | | 1128 | sc = v; |
1118 | return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dp); | | 1129 | return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dp); |
1119 | } | | 1130 | } |
1120 | | | 1131 | |
1121 | static void * | | 1132 | static void * |
1122 | auich_allocm(void *v, int direction, size_t size, | | 1133 | auich_allocm(void *v, int direction, size_t size, |
1123 | struct malloc_type *pool, int flags) | | 1134 | struct malloc_type *pool, int flags) |
1124 | { | | 1135 | { |
1125 | struct auich_softc *sc; | | 1136 | struct auich_softc *sc; |
1126 | struct auich_dma *p; | | 1137 | struct auich_dma *p; |
1127 | int error; | | 1138 | int error; |
1128 | | | 1139 | |
1129 | if (size > (ICH_DMALIST_MAX * ICH_DMASEG_MAX)) | | 1140 | if (size > (ICH_DMALIST_MAX * ICH_DMASEG_MAX)) |
1130 | return NULL; | | 1141 | return NULL; |
1131 | | | 1142 | |
1132 | p = malloc(sizeof(*p), pool, flags|M_ZERO); | | 1143 | p = malloc(sizeof(*p), pool, flags|M_ZERO); |
1133 | if (p == NULL) | | 1144 | if (p == NULL) |
1134 | return NULL; | | 1145 | return NULL; |
1135 | | | 1146 | |
1136 | sc = v; | | 1147 | sc = v; |
1137 | error = auich_allocmem(sc, size, 0, p); | | 1148 | error = auich_allocmem(sc, size, 0, p); |
1138 | if (error) { | | 1149 | if (error) { |
1139 | free(p, pool); | | 1150 | free(p, pool); |
1140 | return NULL; | | 1151 | return NULL; |
1141 | } | | 1152 | } |
1142 | | | 1153 | |
1143 | p->next = sc->sc_dmas; | | 1154 | p->next = sc->sc_dmas; |
1144 | sc->sc_dmas = p; | | 1155 | sc->sc_dmas = p; |
1145 | | | 1156 | |
1146 | return KERNADDR(p); | | 1157 | return KERNADDR(p); |
1147 | } | | 1158 | } |
1148 | | | 1159 | |
1149 | static void | | 1160 | static void |
1150 | auich_freem(void *v, void *ptr, struct malloc_type *pool) | | 1161 | auich_freem(void *v, void *ptr, struct malloc_type *pool) |
1151 | { | | 1162 | { |
1152 | struct auich_softc *sc; | | 1163 | struct auich_softc *sc; |
1153 | struct auich_dma *p, **pp; | | 1164 | struct auich_dma *p, **pp; |
1154 | | | 1165 | |
1155 | sc = v; | | 1166 | sc = v; |
1156 | for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) { | | 1167 | for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) { |
1157 | if (KERNADDR(p) == ptr) { | | 1168 | if (KERNADDR(p) == ptr) { |
1158 | auich_freemem(sc, p); | | 1169 | auich_freemem(sc, p); |
1159 | *pp = p->next; | | 1170 | *pp = p->next; |
1160 | free(p, pool); | | 1171 | free(p, pool); |
1161 | return; | | 1172 | return; |
1162 | } | | 1173 | } |
1163 | } | | 1174 | } |
1164 | } | | 1175 | } |
1165 | | | 1176 | |
1166 | static size_t | | 1177 | static size_t |
1167 | auich_round_buffersize(void *v, int direction, size_t size) | | 1178 | auich_round_buffersize(void *v, int direction, size_t size) |
1168 | { | | 1179 | { |
1169 | | | 1180 | |
1170 | if (size > (ICH_DMALIST_MAX * ICH_DMASEG_MAX)) | | 1181 | if (size > (ICH_DMALIST_MAX * ICH_DMASEG_MAX)) |
1171 | size = ICH_DMALIST_MAX * ICH_DMASEG_MAX; | | 1182 | size = ICH_DMALIST_MAX * ICH_DMASEG_MAX; |
1172 | | | 1183 | |
1173 | return size; | | 1184 | return size; |
1174 | } | | 1185 | } |
1175 | | | 1186 | |
1176 | static paddr_t | | 1187 | static paddr_t |
1177 | auich_mappage(void *v, void *mem, off_t off, int prot) | | 1188 | auich_mappage(void *v, void *mem, off_t off, int prot) |
1178 | { | | 1189 | { |
1179 | struct auich_softc *sc; | | 1190 | struct auich_softc *sc; |
1180 | struct auich_dma *p; | | 1191 | struct auich_dma *p; |
1181 | | | 1192 | |
1182 | if (off < 0) | | 1193 | if (off < 0) |
1183 | return -1; | | 1194 | return -1; |
1184 | sc = v; | | 1195 | sc = v; |
1185 | for (p = sc->sc_dmas; p && KERNADDR(p) != mem; p = p->next) | | 1196 | for (p = sc->sc_dmas; p && KERNADDR(p) != mem; p = p->next) |
1186 | continue; | | 1197 | continue; |
1187 | if (!p) | | 1198 | if (!p) |
1188 | return -1; | | 1199 | return -1; |
1189 | return bus_dmamem_mmap(sc->dmat, p->segs, p->nsegs, | | 1200 | return bus_dmamem_mmap(sc->dmat, p->segs, p->nsegs, |
1190 | off, prot, BUS_DMA_WAITOK); | | 1201 | off, prot, BUS_DMA_WAITOK); |
1191 | } | | 1202 | } |
1192 | | | 1203 | |
1193 | static int | | 1204 | static int |
1194 | auich_get_props(void *v) | | 1205 | auich_get_props(void *v) |
1195 | { | | 1206 | { |
1196 | struct auich_softc *sc; | | 1207 | struct auich_softc *sc; |
1197 | int props; | | 1208 | int props; |
1198 | | | 1209 | |
1199 | props = AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX; | | 1210 | props = AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX; |
1200 | sc = v; | | 1211 | sc = v; |
1201 | /* | | 1212 | /* |
1202 | * Even if the codec is fixed-rate, set_param() succeeds for any sample | | 1213 | * Even if the codec is fixed-rate, set_param() succeeds for any sample |
1203 | * rate because of aurateconv. Applications can't know what rate the | | 1214 | * rate because of aurateconv. Applications can't know what rate the |
1204 | * device can process in the case of mmap(). | | 1215 | * device can process in the case of mmap(). |
1205 | */ | | 1216 | */ |
1206 | if (!AC97_IS_FIXED_RATE(sc->codec_if) || | | 1217 | if (!AC97_IS_FIXED_RATE(sc->codec_if) || |
1207 | sc->sc_codectype == AC97_CODEC_TYPE_MODEM) | | 1218 | sc->sc_codectype == AC97_CODEC_TYPE_MODEM) |
1208 | props |= AUDIO_PROP_MMAP; | | 1219 | props |= AUDIO_PROP_MMAP; |
1209 | return props; | | 1220 | return props; |
1210 | } | | 1221 | } |
1211 | | | 1222 | |
1212 | static int | | 1223 | static int |
1213 | auich_intr(void *v) | | 1224 | auich_intr(void *v) |
1214 | { | | 1225 | { |
1215 | struct auich_softc *sc; | | 1226 | struct auich_softc *sc; |
1216 | int ret, gsts; | | 1227 | int ret, gsts; |
1217 | #ifdef DIAGNOSTIC | | 1228 | #ifdef DIAGNOSTIC |
1218 | int csts; | | 1229 | int csts; |
1219 | #endif | | 1230 | #endif |
1220 | | | 1231 | |
1221 | sc = v; | | 1232 | sc = v; |
1222 | | | 1233 | |
1223 | if (!device_has_power(sc->sc_dev)) | | 1234 | if (!device_has_power(sc->sc_dev)) |
1224 | return (0); | | 1235 | return (0); |
1225 | | | 1236 | |
1226 | ret = 0; | | 1237 | ret = 0; |
1227 | #ifdef DIAGNOSTIC | | 1238 | #ifdef DIAGNOSTIC |
1228 | csts = pci_conf_read(sc->sc_pc, sc->sc_pt, PCI_COMMAND_STATUS_REG); | | 1239 | csts = pci_conf_read(sc->sc_pc, sc->sc_pt, PCI_COMMAND_STATUS_REG); |
1229 | if (csts & PCI_STATUS_MASTER_ABORT) { | | 1240 | if (csts & PCI_STATUS_MASTER_ABORT) { |
1230 | printf("auich_intr: PCI master abort\n"); | | 1241 | printf("auich_intr: PCI master abort\n"); |
1231 | } | | 1242 | } |
1232 | #endif | | 1243 | #endif |
1233 | | | 1244 | |
1234 | gsts = bus_space_read_4(sc->iot, sc->aud_ioh, | | 1245 | gsts = bus_space_read_4(sc->iot, sc->aud_ioh, |
1235 | ICH_GSTS + sc->sc_modem_offset); | | 1246 | ICH_GSTS + sc->sc_modem_offset); |
1236 | DPRINTF(ICH_DEBUG_INTR, ("auich_intr: gsts=0x%x\n", gsts)); | | 1247 | DPRINTF(ICH_DEBUG_INTR, ("auich_intr: gsts=0x%x\n", gsts)); |
1237 | | | 1248 | |
1238 | if ((sc->sc_codectype == AC97_CODEC_TYPE_AUDIO && gsts & ICH_POINT) || | | 1249 | if ((sc->sc_codectype == AC97_CODEC_TYPE_AUDIO && gsts & ICH_POINT) || |
1239 | (sc->sc_codectype == AC97_CODEC_TYPE_MODEM && gsts & ICH_MOINT)) { | | 1250 | (sc->sc_codectype == AC97_CODEC_TYPE_MODEM && gsts & ICH_MOINT)) { |
1240 | int sts; | | 1251 | int sts; |
1241 | | | 1252 | |
1242 | sts = bus_space_read_2(sc->iot, sc->aud_ioh, | | 1253 | sts = bus_space_read_2(sc->iot, sc->aud_ioh, |
1243 | ICH_PCMO + sc->sc_sts_reg); | | 1254 | ICH_PCMO + sc->sc_sts_reg); |
1244 | DPRINTF(ICH_DEBUG_INTR, | | 1255 | DPRINTF(ICH_DEBUG_INTR, |
1245 | ("auich_intr: osts=0x%x\n", sts)); | | 1256 | ("auich_intr: osts=0x%x\n", sts)); |
1246 | | | 1257 | |
1247 | if (sts & ICH_FIFOE) | | 1258 | if (sts & ICH_FIFOE) |
1248 | printf("%s: fifo underrun\n", device_xname(sc->sc_dev)); | | 1259 | printf("%s: fifo underrun\n", device_xname(sc->sc_dev)); |
1249 | | | 1260 | |
1250 | if (sts & ICH_BCIS) | | 1261 | if (sts & ICH_BCIS) |
1251 | auich_intr_pipe(sc, ICH_PCMO, &sc->pcmo); | | 1262 | auich_intr_pipe(sc, ICH_PCMO, &sc->pcmo); |
1252 | | | 1263 | |
1253 | /* int ack */ | | 1264 | /* int ack */ |
1254 | bus_space_write_2(sc->iot, sc->aud_ioh, ICH_PCMO + | | 1265 | bus_space_write_2(sc->iot, sc->aud_ioh, ICH_PCMO + |
1255 | sc->sc_sts_reg, sts & (ICH_BCIS | ICH_FIFOE)); | | 1266 | sc->sc_sts_reg, sts & (ICH_BCIS | ICH_FIFOE)); |
1256 | if (sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) | | 1267 | if (sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) |
1257 | bus_space_write_4(sc->iot, sc->aud_ioh, | | 1268 | bus_space_write_4(sc->iot, sc->aud_ioh, |
1258 | ICH_GSTS + sc->sc_modem_offset, ICH_POINT); | | 1269 | ICH_GSTS + sc->sc_modem_offset, ICH_POINT); |
1259 | else | | 1270 | else |
1260 | bus_space_write_4(sc->iot, sc->aud_ioh, | | 1271 | bus_space_write_4(sc->iot, sc->aud_ioh, |
1261 | ICH_GSTS + sc->sc_modem_offset, ICH_MOINT); | | 1272 | ICH_GSTS + sc->sc_modem_offset, ICH_MOINT); |
1262 | ret++; | | 1273 | ret++; |
1263 | } | | 1274 | } |
1264 | | | 1275 | |
1265 | if ((sc->sc_codectype == AC97_CODEC_TYPE_AUDIO && gsts & ICH_PIINT) || | | 1276 | if ((sc->sc_codectype == AC97_CODEC_TYPE_AUDIO && gsts & ICH_PIINT) || |
1266 | (sc->sc_codectype == AC97_CODEC_TYPE_MODEM && gsts & ICH_MIINT)) { | | 1277 | (sc->sc_codectype == AC97_CODEC_TYPE_MODEM && gsts & ICH_MIINT)) { |
1267 | int sts; | | 1278 | int sts; |
1268 | | | 1279 | |
1269 | sts = bus_space_read_2(sc->iot, sc->aud_ioh, | | 1280 | sts = bus_space_read_2(sc->iot, sc->aud_ioh, |
1270 | ICH_PCMI + sc->sc_sts_reg); | | 1281 | ICH_PCMI + sc->sc_sts_reg); |
1271 | DPRINTF(ICH_DEBUG_INTR, | | 1282 | DPRINTF(ICH_DEBUG_INTR, |
1272 | ("auich_intr: ists=0x%x\n", sts)); | | 1283 | ("auich_intr: ists=0x%x\n", sts)); |
1273 | | | 1284 | |
1274 | if (sts & ICH_FIFOE) | | 1285 | if (sts & ICH_FIFOE) |
1275 | printf("%s: fifo overrun\n", device_xname(sc->sc_dev)); | | 1286 | printf("%s: fifo overrun\n", device_xname(sc->sc_dev)); |
1276 | | | 1287 | |
1277 | if (sts & ICH_BCIS) | | 1288 | if (sts & ICH_BCIS) |
1278 | auich_intr_pipe(sc, ICH_PCMI, &sc->pcmi); | | 1289 | auich_intr_pipe(sc, ICH_PCMI, &sc->pcmi); |
1279 | | | 1290 | |
1280 | /* int ack */ | | 1291 | /* int ack */ |
1281 | bus_space_write_2(sc->iot, sc->aud_ioh, ICH_PCMI + | | 1292 | bus_space_write_2(sc->iot, sc->aud_ioh, ICH_PCMI + |
1282 | sc->sc_sts_reg, sts & (ICH_BCIS | ICH_FIFOE)); | | 1293 | sc->sc_sts_reg, sts & (ICH_BCIS | ICH_FIFOE)); |
1283 | if (sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) | | 1294 | if (sc->sc_codectype == AC97_CODEC_TYPE_AUDIO) |
1284 | bus_space_write_4(sc->iot, sc->aud_ioh, | | 1295 | bus_space_write_4(sc->iot, sc->aud_ioh, |
1285 | ICH_GSTS + sc->sc_modem_offset, ICH_PIINT); | | 1296 | ICH_GSTS + sc->sc_modem_offset, ICH_PIINT); |
1286 | else | | 1297 | else |
1287 | bus_space_write_4(sc->iot, sc->aud_ioh, | | 1298 | bus_space_write_4(sc->iot, sc->aud_ioh, |
1288 | ICH_GSTS + sc->sc_modem_offset, ICH_MIINT); | | 1299 | ICH_GSTS + sc->sc_modem_offset, ICH_MIINT); |
1289 | ret++; | | 1300 | ret++; |
1290 | } | | 1301 | } |
1291 | | | 1302 | |
1292 | if (sc->sc_codectype == AC97_CODEC_TYPE_AUDIO && gsts & ICH_MINT) { | | 1303 | if (sc->sc_codectype == AC97_CODEC_TYPE_AUDIO && gsts & ICH_MINT) { |
1293 | int sts; | | 1304 | int sts; |
1294 | | | 1305 | |
1295 | sts = bus_space_read_2(sc->iot, sc->aud_ioh, | | 1306 | sts = bus_space_read_2(sc->iot, sc->aud_ioh, |
1296 | ICH_MICI + sc->sc_sts_reg); | | 1307 | ICH_MICI + sc->sc_sts_reg); |
1297 | DPRINTF(ICH_DEBUG_INTR, | | 1308 | DPRINTF(ICH_DEBUG_INTR, |
1298 | ("auich_intr: ists=0x%x\n", sts)); | | 1309 | ("auich_intr: ists=0x%x\n", sts)); |
1299 | | | 1310 | |
1300 | if (sts & ICH_FIFOE) | | 1311 | if (sts & ICH_FIFOE) |
1301 | printf("%s: fifo overrun\n", device_xname(sc->sc_dev)); | | 1312 | printf("%s: fifo overrun\n", device_xname(sc->sc_dev)); |
1302 | | | 1313 | |
1303 | if (sts & ICH_BCIS) | | 1314 | if (sts & ICH_BCIS) |
1304 | auich_intr_pipe(sc, ICH_MICI, &sc->mici); | | 1315 | auich_intr_pipe(sc, ICH_MICI, &sc->mici); |
1305 | | | 1316 | |
1306 | /* int ack */ | | 1317 | /* int ack */ |
1307 | bus_space_write_2(sc->iot, sc->aud_ioh, ICH_MICI + | | 1318 | bus_space_write_2(sc->iot, sc->aud_ioh, ICH_MICI + |
1308 | sc->sc_sts_reg, sts & (ICH_BCIS | ICH_FIFOE)); | | 1319 | sc->sc_sts_reg, sts & (ICH_BCIS | ICH_FIFOE)); |
1309 | bus_space_write_4(sc->iot, sc->aud_ioh, | | 1320 | bus_space_write_4(sc->iot, sc->aud_ioh, |
1310 | ICH_GSTS + sc->sc_modem_offset, ICH_MINT); | | 1321 | ICH_GSTS + sc->sc_modem_offset, ICH_MINT); |
1311 | ret++; | | 1322 | ret++; |
1312 | } | | 1323 | } |
1313 | | | 1324 | |
1314 | #ifdef AUICH_MODEM_DEBUG | | 1325 | #ifdef AUICH_MODEM_DEBUG |
1315 | if (sc->sc_codectype == AC97_CODEC_TYPE_MODEM && gsts & ICH_GSCI) { | | 1326 | if (sc->sc_codectype == AC97_CODEC_TYPE_MODEM && gsts & ICH_GSCI) { |
1316 | printf("%s: gsts=0x%x\n", device_xname(sc->sc_dev), gsts); | | 1327 | printf("%s: gsts=0x%x\n", device_xname(sc->sc_dev), gsts); |
1317 | /* int ack */ | | 1328 | /* int ack */ |
1318 | bus_space_write_4(sc->iot, sc->aud_ioh, | | 1329 | bus_space_write_4(sc->iot, sc->aud_ioh, |
1319 | ICH_GSTS + sc->sc_modem_offset, ICH_GSCI); | | 1330 | ICH_GSTS + sc->sc_modem_offset, ICH_GSCI); |
1320 | ret++; | | 1331 | ret++; |
1321 | } | | 1332 | } |
1322 | #endif | | 1333 | #endif |
1323 | | | 1334 | |
1324 | return ret; | | 1335 | return ret; |
1325 | } | | 1336 | } |
1326 | | | 1337 | |
1327 | static void | | 1338 | static void |
1328 | auich_trigger_pipe(struct auich_softc *sc, int pipe, struct auich_ring *ring) | | 1339 | auich_trigger_pipe(struct auich_softc *sc, int pipe, struct auich_ring *ring) |
1329 | { | | 1340 | { |
1330 | int blksize, qptr; | | 1341 | int blksize, qptr; |
1331 | struct auich_dmalist *q; | | 1342 | struct auich_dmalist *q; |
1332 | | | 1343 | |
1333 | blksize = ring->blksize; | | 1344 | blksize = ring->blksize; |
1334 | | | 1345 | |
1335 | for (qptr = 0; qptr < ICH_DMALIST_MAX; qptr++) { | | 1346 | for (qptr = 0; qptr < ICH_DMALIST_MAX; qptr++) { |
1336 | q = &ring->dmalist[qptr]; | | 1347 | q = &ring->dmalist[qptr]; |
1337 | q->base = ring->p; | | 1348 | q->base = ring->p; |
1338 | q->len = (blksize >> sc->sc_sample_shift) | ICH_DMAF_IOC; | | 1349 | q->len = (blksize >> sc->sc_sample_shift) | ICH_DMAF_IOC; |
1339 | | | 1350 | |
1340 | ring->p += blksize; | | 1351 | ring->p += blksize; |
1341 | if (ring->p >= ring->end) | | 1352 | if (ring->p >= ring->end) |
1342 | ring->p = ring->start; | | 1353 | ring->p = ring->start; |
1343 | } | | 1354 | } |
1344 | ring->qptr = 0; | | 1355 | ring->qptr = 0; |
1345 | | | 1356 | |
1346 | bus_space_write_1(sc->iot, sc->aud_ioh, pipe + ICH_LVI, | | 1357 | bus_space_write_1(sc->iot, sc->aud_ioh, pipe + ICH_LVI, |
1347 | (qptr - 1) & ICH_LVI_MASK); | | 1358 | (qptr - 1) & ICH_LVI_MASK); |
1348 | bus_space_write_1(sc->iot, sc->aud_ioh, pipe + ICH_CTRL, | | 1359 | bus_space_write_1(sc->iot, sc->aud_ioh, pipe + ICH_CTRL, |
1349 | ICH_IOCE | ICH_FEIE | ICH_RPBM); | | 1360 | ICH_IOCE | ICH_FEIE | ICH_RPBM); |
1350 | } | | 1361 | } |
1351 | | | 1362 | |
1352 | static void | | 1363 | static void |
1353 | auich_intr_pipe(struct auich_softc *sc, int pipe, struct auich_ring *ring) | | 1364 | auich_intr_pipe(struct auich_softc *sc, int pipe, struct auich_ring *ring) |
1354 | { | | 1365 | { |
1355 | int blksize, qptr, nqptr; | | 1366 | int blksize, qptr, nqptr; |
1356 | struct auich_dmalist *q; | | 1367 | struct auich_dmalist *q; |
1357 | | | 1368 | |
1358 | blksize = ring->blksize; | | 1369 | blksize = ring->blksize; |
1359 | qptr = ring->qptr; | | 1370 | qptr = ring->qptr; |
1360 | nqptr = bus_space_read_1(sc->iot, sc->aud_ioh, pipe + ICH_CIV); | | 1371 | nqptr = bus_space_read_1(sc->iot, sc->aud_ioh, pipe + ICH_CIV); |
1361 | | | 1372 | |
1362 | while (qptr != nqptr) { | | 1373 | while (qptr != nqptr) { |
1363 | q = &ring->dmalist[qptr]; | | 1374 | q = &ring->dmalist[qptr]; |
1364 | q->base = ring->p; | | 1375 | q->base = ring->p; |
1365 | q->len = (blksize >> sc->sc_sample_shift) | ICH_DMAF_IOC; | | 1376 | q->len = (blksize >> sc->sc_sample_shift) | ICH_DMAF_IOC; |
1366 | | | 1377 | |
1367 | DPRINTF(ICH_DEBUG_INTR, | | 1378 | DPRINTF(ICH_DEBUG_INTR, |
1368 | ("auich_intr: %p, %p = %x @ 0x%x\n", | | 1379 | ("auich_intr: %p, %p = %x @ 0x%x\n", |
1369 | &ring->dmalist[qptr], q, q->len, q->base)); | | 1380 | &ring->dmalist[qptr], q, q->len, q->base)); |
1370 | | | 1381 | |
1371 | ring->p += blksize; | | 1382 | ring->p += blksize; |
1372 | if (ring->p >= ring->end) | | 1383 | if (ring->p >= ring->end) |
1373 | ring->p = ring->start; | | 1384 | ring->p = ring->start; |
1374 | | | 1385 | |
1375 | qptr = (qptr + 1) & ICH_LVI_MASK; | | 1386 | qptr = (qptr + 1) & ICH_LVI_MASK; |
1376 | if (ring->intr) | | 1387 | if (ring->intr) |
1377 | ring->intr(ring->arg); | | 1388 | ring->intr(ring->arg); |
1378 | } | | 1389 | } |
1379 | ring->qptr = qptr; | | 1390 | ring->qptr = qptr; |
1380 | | | 1391 | |
1381 | bus_space_write_1(sc->iot, sc->aud_ioh, pipe + ICH_LVI, | | 1392 | bus_space_write_1(sc->iot, sc->aud_ioh, pipe + ICH_LVI, |
1382 | (qptr - 1) & ICH_LVI_MASK); | | 1393 | (qptr - 1) & ICH_LVI_MASK); |
1383 | } | | 1394 | } |
1384 | | | 1395 | |
1385 | static int | | 1396 | static int |
1386 | auich_trigger_output(void *v, void *start, void *end, int blksize, | | 1397 | auich_trigger_output(void *v, void *start, void *end, int blksize, |
1387 | void (*intr)(void *), void *arg, const audio_params_t *param) | | 1398 | void (*intr)(void *), void *arg, const audio_params_t *param) |
1388 | { | | 1399 | { |
1389 | struct auich_softc *sc; | | 1400 | struct auich_softc *sc; |
1390 | struct auich_dma *p; | | 1401 | struct auich_dma *p; |
1391 | size_t size; | | 1402 | size_t size; |
1392 | | | 1403 | |
1393 | DPRINTF(ICH_DEBUG_DMA, | | 1404 | DPRINTF(ICH_DEBUG_DMA, |
1394 | ("auich_trigger_output(%p, %p, %d, %p, %p, %p)\n", | | 1405 | ("auich_trigger_output(%p, %p, %d, %p, %p, %p)\n", |
1395 | start, end, blksize, intr, arg, param)); | | 1406 | start, end, blksize, intr, arg, param)); |
1396 | sc = v; | | 1407 | sc = v; |
1397 | | | 1408 | |
1398 | for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next) | | 1409 | for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next) |
1399 | continue; | | 1410 | continue; |
1400 | if (!p) { | | 1411 | if (!p) { |
1401 | printf("auich_trigger_output: bad addr %p\n", start); | | 1412 | printf("auich_trigger_output: bad addr %p\n", start); |
1402 | return EINVAL; | | 1413 | return EINVAL; |
1403 | } | | 1414 | } |
1404 | | | 1415 | |
1405 | size = (size_t)((char *)end - (char *)start); | | 1416 | size = (size_t)((char *)end - (char *)start); |
1406 | | | 1417 | |
1407 | sc->pcmo.intr = intr; | | 1418 | sc->pcmo.intr = intr; |
1408 | sc->pcmo.arg = arg; | | 1419 | sc->pcmo.arg = arg; |
1409 | sc->pcmo.start = DMAADDR(p); | | 1420 | sc->pcmo.start = DMAADDR(p); |
1410 | sc->pcmo.p = sc->pcmo.start; | | 1421 | sc->pcmo.p = sc->pcmo.start; |
1411 | sc->pcmo.end = sc->pcmo.start + size; | | 1422 | sc->pcmo.end = sc->pcmo.start + size; |
1412 | sc->pcmo.blksize = blksize; | | 1423 | sc->pcmo.blksize = blksize; |
1413 | | | 1424 | |
1414 | bus_space_write_4(sc->iot, sc->aud_ioh, ICH_PCMO + ICH_BDBAR, | | 1425 | bus_space_write_4(sc->iot, sc->aud_ioh, ICH_PCMO + ICH_BDBAR, |
1415 | sc->sc_cddma + ICH_PCMO_OFF(0)); | | 1426 | sc->sc_cddma + ICH_PCMO_OFF(0)); |
1416 | auich_trigger_pipe(sc, ICH_PCMO, &sc->pcmo); | | 1427 | auich_trigger_pipe(sc, ICH_PCMO, &sc->pcmo); |
1417 | | | 1428 | |
1418 | return 0; | | 1429 | return 0; |
1419 | } | | 1430 | } |
1420 | | | 1431 | |
1421 | static int | | 1432 | static int |
1422 | auich_trigger_input(void *v, void *start, void *end, int blksize, | | 1433 | auich_trigger_input(void *v, void *start, void *end, int blksize, |
1423 | void (*intr)(void *), void *arg, const audio_params_t *param) | | 1434 | void (*intr)(void *), void *arg, const audio_params_t *param) |
1424 | { | | 1435 | { |
1425 | struct auich_softc *sc; | | 1436 | struct auich_softc *sc; |
1426 | struct auich_dma *p; | | 1437 | struct auich_dma *p; |
1427 | size_t size; | | 1438 | size_t size; |
1428 | | | 1439 | |
1429 | DPRINTF(ICH_DEBUG_DMA, | | 1440 | DPRINTF(ICH_DEBUG_DMA, |
1430 | ("auich_trigger_input(%p, %p, %d, %p, %p, %p)\n", | | 1441 | ("auich_trigger_input(%p, %p, %d, %p, %p, %p)\n", |
1431 | start, end, blksize, intr, arg, param)); | | 1442 | start, end, blksize, intr, arg, param)); |
1432 | sc = v; | | 1443 | sc = v; |
1433 | | | 1444 | |
1434 | for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next) | | 1445 | for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next) |
1435 | continue; | | 1446 | continue; |
1436 | if (!p) { | | 1447 | if (!p) { |
1437 | printf("auich_trigger_input: bad addr %p\n", start); | | 1448 | printf("auich_trigger_input: bad addr %p\n", start); |
1438 | return EINVAL; | | 1449 | return EINVAL; |
1439 | } | | 1450 | } |
1440 | | | 1451 | |
1441 | size = (size_t)((char *)end - (char *)start); | | 1452 | size = (size_t)((char *)end - (char *)start); |
1442 | | | 1453 | |
1443 | sc->pcmi.intr = intr; | | 1454 | sc->pcmi.intr = intr; |
1444 | sc->pcmi.arg = arg; | | 1455 | sc->pcmi.arg = arg; |
1445 | sc->pcmi.start = DMAADDR(p); | | 1456 | sc->pcmi.start = DMAADDR(p); |
1446 | sc->pcmi.p = sc->pcmi.start; | | 1457 | sc->pcmi.p = sc->pcmi.start; |
1447 | sc->pcmi.end = sc->pcmi.start + size; | | 1458 | sc->pcmi.end = sc->pcmi.start + size; |
1448 | sc->pcmi.blksize = blksize; | | 1459 | sc->pcmi.blksize = blksize; |
1449 | | | 1460 | |
1450 | bus_space_write_4(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_BDBAR, | | 1461 | bus_space_write_4(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_BDBAR, |
1451 | sc->sc_cddma + ICH_PCMI_OFF(0)); | | 1462 | sc->sc_cddma + ICH_PCMI_OFF(0)); |
1452 | auich_trigger_pipe(sc, ICH_PCMI, &sc->pcmi); | | 1463 | auich_trigger_pipe(sc, ICH_PCMI, &sc->pcmi); |
1453 | | | 1464 | |
1454 | return 0; | | 1465 | return 0; |
1455 | } | | 1466 | } |
1456 | | | 1467 | |
1457 | static int | | 1468 | static int |
1458 | auich_powerstate(void *v, int state) | | 1469 | auich_powerstate(void *v, int state) |
1459 | { | | 1470 | { |
1460 | return 0; | | 1471 | return 0; |
1461 | } | | 1472 | } |
1462 | | | 1473 | |
1463 | static int | | 1474 | static int |
1464 | auich_allocmem(struct auich_softc *sc, size_t size, size_t align, | | 1475 | auich_allocmem(struct auich_softc *sc, size_t size, size_t align, |
1465 | struct auich_dma *p) | | 1476 | struct auich_dma *p) |
1466 | { | | 1477 | { |
1467 | int error; | | 1478 | int error; |
1468 | | | 1479 | |
1469 | p->size = size; | | 1480 | p->size = size; |
1470 | error = bus_dmamem_alloc(sc->dmat, p->size, align, 0, | | 1481 | error = bus_dmamem_alloc(sc->dmat, p->size, align, 0, |
1471 | p->segs, sizeof(p->segs)/sizeof(p->segs[0]), | | 1482 | p->segs, sizeof(p->segs)/sizeof(p->segs[0]), |
1472 | &p->nsegs, BUS_DMA_NOWAIT); | | 1483 | &p->nsegs, BUS_DMA_NOWAIT); |
1473 | if (error) | | 1484 | if (error) |
1474 | return error; | | 1485 | return error; |
1475 | | | 1486 | |
1476 | error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size, | | 1487 | error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size, |
1477 | &p->addr, BUS_DMA_NOWAIT|sc->sc_dmamap_flags); | | 1488 | &p->addr, BUS_DMA_NOWAIT|sc->sc_dmamap_flags); |
1478 | if (error) | | 1489 | if (error) |
1479 | goto free; | | 1490 | goto free; |
1480 | | | 1491 | |
1481 | error = bus_dmamap_create(sc->dmat, p->size, 1, p->size, | | 1492 | error = bus_dmamap_create(sc->dmat, p->size, 1, p->size, |
1482 | 0, BUS_DMA_NOWAIT, &p->map); | | 1493 | 0, BUS_DMA_NOWAIT, &p->map); |
1483 | if (error) | | 1494 | if (error) |
1484 | goto unmap; | | 1495 | goto unmap; |
1485 | | | 1496 | |
1486 | error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size, NULL, | | 1497 | error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size, NULL, |
1487 | BUS_DMA_NOWAIT); | | 1498 | BUS_DMA_NOWAIT); |
1488 | if (error) | | 1499 | if (error) |
1489 | goto destroy; | | 1500 | goto destroy; |
1490 | return 0; | | 1501 | return 0; |
1491 | | | 1502 | |
1492 | destroy: | | 1503 | destroy: |
1493 | bus_dmamap_destroy(sc->dmat, p->map); | | 1504 | bus_dmamap_destroy(sc->dmat, p->map); |
1494 | unmap: | | 1505 | unmap: |
1495 | bus_dmamem_unmap(sc->dmat, p->addr, p->size); | | 1506 | bus_dmamem_unmap(sc->dmat, p->addr, p->size); |
1496 | free: | | 1507 | free: |
1497 | bus_dmamem_free(sc->dmat, p->segs, p->nsegs); | | 1508 | bus_dmamem_free(sc->dmat, p->segs, p->nsegs); |
1498 | return error; | | 1509 | return error; |
1499 | } | | 1510 | } |
1500 | | | 1511 | |
1501 | static int | | 1512 | static int |
1502 | auich_freemem(struct auich_softc *sc, struct auich_dma *p) | | 1513 | auich_freemem(struct auich_softc *sc, struct auich_dma *p) |
1503 | { | | 1514 | { |
1504 | | | 1515 | |
1505 | bus_dmamap_unload(sc->dmat, p->map); | | 1516 | bus_dmamap_unload(sc->dmat, p->map); |
1506 | bus_dmamap_destroy(sc->dmat, p->map); | | 1517 | bus_dmamap_destroy(sc->dmat, p->map); |
1507 | bus_dmamem_unmap(sc->dmat, p->addr, p->size); | | 1518 | bus_dmamem_unmap(sc->dmat, p->addr, p->size); |
1508 | bus_dmamem_free(sc->dmat, p->segs, p->nsegs); | | 1519 | bus_dmamem_free(sc->dmat, p->segs, p->nsegs); |
1509 | return 0; | | 1520 | return 0; |
1510 | } | | 1521 | } |
1511 | | | 1522 | |
1512 | static int | | 1523 | static int |
1513 | auich_alloc_cdata(struct auich_softc *sc) | | 1524 | auich_alloc_cdata(struct auich_softc *sc) |
1514 | { | | 1525 | { |
1515 | bus_dma_segment_t seg; | | 1526 | bus_dma_segment_t seg; |
1516 | int error, rseg; | | 1527 | int error, rseg; |
1517 | | | 1528 | |
1518 | /* | | 1529 | /* |
1519 | * Allocate the control data structure, and create and load the | | 1530 | * Allocate the control data structure, and create and load the |
1520 | * DMA map for it. | | 1531 | * DMA map for it. |
1521 | */ | | 1532 | */ |
1522 | if ((error = bus_dmamem_alloc(sc->dmat, | | 1533 | if ((error = bus_dmamem_alloc(sc->dmat, |
1523 | sizeof(struct auich_cdata), | | 1534 | sizeof(struct auich_cdata), |
1524 | PAGE_SIZE, 0, &seg, 1, &rseg, 0)) != 0) { | | 1535 | PAGE_SIZE, 0, &seg, 1, &rseg, 0)) != 0) { |
1525 | aprint_error_dev(sc->sc_dev, "unable to allocate control data, error = %d\n", error); | | 1536 | aprint_error_dev(sc->sc_dev, "unable to allocate control data, error = %d\n", error); |
1526 | goto fail_0; | | 1537 | goto fail_0; |
1527 | } | | 1538 | } |
1528 | | | 1539 | |
1529 | if ((error = bus_dmamem_map(sc->dmat, &seg, rseg, | | 1540 | if ((error = bus_dmamem_map(sc->dmat, &seg, rseg, |
1530 | sizeof(struct auich_cdata), | | 1541 | sizeof(struct auich_cdata), |
1531 | (void **) &sc->sc_cdata, | | 1542 | (void **) &sc->sc_cdata, |
1532 | sc->sc_dmamap_flags)) != 0) { | | 1543 | sc->sc_dmamap_flags)) != 0) { |
1533 | aprint_error_dev(sc->sc_dev, "unable to map control data, error = %d\n", error); | | 1544 | aprint_error_dev(sc->sc_dev, "unable to map control data, error = %d\n", error); |
1534 | goto fail_1; | | 1545 | goto fail_1; |
1535 | } | | 1546 | } |
1536 | | | 1547 | |
1537 | if ((error = bus_dmamap_create(sc->dmat, sizeof(struct auich_cdata), 1, | | 1548 | if ((error = bus_dmamap_create(sc->dmat, sizeof(struct auich_cdata), 1, |
1538 | sizeof(struct auich_cdata), 0, 0, | | 1549 | sizeof(struct auich_cdata), 0, 0, |
1539 | &sc->sc_cddmamap)) != 0) { | | 1550 | &sc->sc_cddmamap)) != 0) { |
1540 | aprint_error_dev(sc->sc_dev, "unable to create control data DMA map, " | | 1551 | aprint_error_dev(sc->sc_dev, "unable to create control data DMA map, " |
1541 | "error = %d\n", error); | | 1552 | "error = %d\n", error); |
1542 | goto fail_2; | | 1553 | goto fail_2; |
1543 | } | | 1554 | } |
1544 | | | 1555 | |
1545 | if ((error = bus_dmamap_load(sc->dmat, sc->sc_cddmamap, | | 1556 | if ((error = bus_dmamap_load(sc->dmat, sc->sc_cddmamap, |
1546 | sc->sc_cdata, sizeof(struct auich_cdata), | | 1557 | sc->sc_cdata, sizeof(struct auich_cdata), |
1547 | NULL, 0)) != 0) { | | 1558 | NULL, 0)) != 0) { |
1548 | aprint_error_dev(sc->sc_dev, "unable tp load control data DMA map, " | | 1559 | aprint_error_dev(sc->sc_dev, "unable tp load control data DMA map, " |
1549 | "error = %d\n", error); | | 1560 | "error = %d\n", error); |
1550 | goto fail_3; | | 1561 | goto fail_3; |
1551 | } | | 1562 | } |
1552 | | | 1563 | |
1553 | sc->pcmo.dmalist = sc->sc_cdata->ic_dmalist_pcmo; | | 1564 | sc->pcmo.dmalist = sc->sc_cdata->ic_dmalist_pcmo; |
1554 | sc->pcmi.dmalist = sc->sc_cdata->ic_dmalist_pcmi; | | 1565 | sc->pcmi.dmalist = sc->sc_cdata->ic_dmalist_pcmi; |
1555 | sc->mici.dmalist = sc->sc_cdata->ic_dmalist_mici; | | 1566 | sc->mici.dmalist = sc->sc_cdata->ic_dmalist_mici; |
1556 | | | 1567 | |
1557 | return 0; | | 1568 | return 0; |
1558 | | | 1569 | |
1559 | fail_3: | | 1570 | fail_3: |
1560 | bus_dmamap_destroy(sc->dmat, sc->sc_cddmamap); | | 1571 | bus_dmamap_destroy(sc->dmat, sc->sc_cddmamap); |
1561 | fail_2: | | 1572 | fail_2: |
1562 | bus_dmamem_unmap(sc->dmat, (void *) sc->sc_cdata, | | 1573 | bus_dmamem_unmap(sc->dmat, (void *) sc->sc_cdata, |
1563 | sizeof(struct auich_cdata)); | | 1574 | sizeof(struct auich_cdata)); |
1564 | fail_1: | | 1575 | fail_1: |
1565 | bus_dmamem_free(sc->dmat, &seg, rseg); | | 1576 | bus_dmamem_free(sc->dmat, &seg, rseg); |
1566 | fail_0: | | 1577 | fail_0: |
1567 | return error; | | 1578 | return error; |
1568 | } | | 1579 | } |
1569 | | | 1580 | |
1570 | static bool | | 1581 | static bool |
1571 | auich_resume(device_t dv PMF_FN_ARGS) | | 1582 | auich_resume(device_t dv PMF_FN_ARGS) |
1572 | { | | 1583 | { |
1573 | struct auich_softc *sc = device_private(dv); | | 1584 | struct auich_softc *sc = device_private(dv); |
1574 | pcireg_t v; | | 1585 | pcireg_t v; |
1575 | | | 1586 | |
1576 | if (sc->sc_native_mode) { | | 1587 | if (sc->sc_native_mode) { |
1577 | v = pci_conf_read(sc->sc_pc, sc->sc_pt, ICH_CFG); | | 1588 | v = pci_conf_read(sc->sc_pc, sc->sc_pt, ICH_CFG); |
1578 | pci_conf_write(sc->sc_pc, sc->sc_pt, ICH_CFG, | | 1589 | pci_conf_write(sc->sc_pc, sc->sc_pt, ICH_CFG, |
1579 | v | ICH_CFG_IOSE); | | 1590 | v | ICH_CFG_IOSE); |
1580 | } | | 1591 | } |
1581 | | | 1592 | |
1582 | auich_reset_codec(sc); | | 1593 | auich_reset_codec(sc); |
1583 | DELAY(1000); | | 1594 | DELAY(1000); |
1584 | (sc->codec_if->vtbl->restore_ports)(sc->codec_if); | | 1595 | (sc->codec_if->vtbl->restore_ports)(sc->codec_if); |
1585 | | | 1596 | |
1586 | return true; | | 1597 | return true; |
1587 | } | | 1598 | } |
1588 | | | 1599 | |
1589 | /* | | 1600 | /* |
1590 | * Calibrate card (some boards are overclocked and need scaling) | | 1601 | * Calibrate card (some boards are overclocked and need scaling) |
1591 | */ | | 1602 | */ |
1592 | static void | | 1603 | static void |
1593 | auich_calibrate(struct auich_softc *sc) | | 1604 | auich_calibrate(struct auich_softc *sc) |
1594 | { | | 1605 | { |
1595 | struct timeval t1, t2; | | 1606 | struct timeval t1, t2; |
1596 | uint8_t ociv, nciv; | | 1607 | uint8_t ociv, nciv; |
1597 | uint64_t wait_us; | | 1608 | uint64_t wait_us; |
1598 | uint32_t actual_48k_rate, bytes, ac97rate; | | 1609 | uint32_t actual_48k_rate, bytes, ac97rate; |
1599 | void *temp_buffer; | | 1610 | void *temp_buffer; |
1600 | struct auich_dma *p; | | 1611 | struct auich_dma *p; |
1601 | u_int rate; | | 1612 | u_int rate; |
1602 | | | 1613 | |
1603 | /* | | 1614 | /* |
1604 | * Grab audio from input for fixed interval and compare how | | 1615 | * Grab audio from input for fixed interval and compare how |
1605 | * much we actually get with what we expect. Interval needs | | 1616 | * much we actually get with what we expect. Interval needs |
1606 | * to be sufficiently short that no interrupts are | | 1617 | * to be sufficiently short that no interrupts are |
1607 | * generated. | | 1618 | * generated. |
1608 | */ | | 1619 | */ |
1609 | | | 1620 | |
1610 | /* Force the codec to a known state first. */ | | 1621 | /* Force the codec to a known state first. */ |
1611 | sc->codec_if->vtbl->set_clock(sc->codec_if, 48000); | | 1622 | sc->codec_if->vtbl->set_clock(sc->codec_if, 48000); |
1612 | rate = sc->sc_ac97_clock = 48000; | | 1623 | rate = sc->sc_ac97_clock = 48000; |
1613 | sc->codec_if->vtbl->set_rate(sc->codec_if, AC97_REG_PCM_LR_ADC_RATE, | | 1624 | sc->codec_if->vtbl->set_rate(sc->codec_if, AC97_REG_PCM_LR_ADC_RATE, |
1614 | &rate); | | 1625 | &rate); |
1615 | | | 1626 | |
1616 | /* Setup a buffer */ | | 1627 | /* Setup a buffer */ |
1617 | bytes = 64000; | | 1628 | bytes = 64000; |
1618 | temp_buffer = auich_allocm(sc, AUMODE_RECORD, bytes, M_DEVBUF, M_WAITOK); | | 1629 | temp_buffer = auich_allocm(sc, AUMODE_RECORD, bytes, M_DEVBUF, M_WAITOK); |
1619 | | | 1630 | |
1620 | for (p = sc->sc_dmas; p && KERNADDR(p) != temp_buffer; p = p->next) | | 1631 | for (p = sc->sc_dmas; p && KERNADDR(p) != temp_buffer; p = p->next) |
1621 | continue; | | 1632 | continue; |
1622 | if (p == NULL) { | | 1633 | if (p == NULL) { |
1623 | printf("auich_calibrate: bad address %p\n", temp_buffer); | | 1634 | printf("auich_calibrate: bad address %p\n", temp_buffer); |
1624 | return; | | 1635 | return; |
1625 | } | | 1636 | } |
1626 | sc->pcmi.dmalist[0].base = DMAADDR(p); | | 1637 | sc->pcmi.dmalist[0].base = DMAADDR(p); |
1627 | sc->pcmi.dmalist[0].len = (bytes >> sc->sc_sample_shift); | | 1638 | sc->pcmi.dmalist[0].len = (bytes >> sc->sc_sample_shift); |
1628 | | | 1639 | |
1629 | /* | | 1640 | /* |
1630 | * our data format is stereo, 16 bit so each sample is 4 bytes. | | 1641 | * our data format is stereo, 16 bit so each sample is 4 bytes. |
1631 | * assuming we get 48000 samples per second, we get 192000 bytes/sec. | | 1642 | * assuming we get 48000 samples per second, we get 192000 bytes/sec. |
1632 | * we're going to start recording with interrupts disabled and measure | | 1643 | * we're going to start recording with interrupts disabled and measure |
1633 | * the time taken for one block to complete. we know the block size, | | 1644 | * the time taken for one block to complete. we know the block size, |
1634 | * we know the time in microseconds, we calculate the sample rate: | | 1645 | * we know the time in microseconds, we calculate the sample rate: |
1635 | * | | 1646 | * |
1636 | * actual_rate [bps] = bytes / (time [s] * 4) | | 1647 | * actual_rate [bps] = bytes / (time [s] * 4) |
1637 | * actual_rate [bps] = (bytes * 1000000) / (time [us] * 4) | | 1648 | * actual_rate [bps] = (bytes * 1000000) / (time [us] * 4) |
1638 | * actual_rate [Hz] = (bytes * 250000) / time [us] | | 1649 | * actual_rate [Hz] = (bytes * 250000) / time [us] |
1639 | */ | | 1650 | */ |
1640 | | | 1651 | |
1641 | /* prepare */ | | 1652 | /* prepare */ |
1642 | ociv = bus_space_read_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_CIV); | | 1653 | ociv = bus_space_read_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_CIV); |
1643 | bus_space_write_4(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_BDBAR, | | 1654 | bus_space_write_4(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_BDBAR, |
1644 | sc->sc_cddma + ICH_PCMI_OFF(0)); | | 1655 | sc->sc_cddma + ICH_PCMI_OFF(0)); |
1645 | bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_LVI, | | 1656 | bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_LVI, |
1646 | (0 - 1) & ICH_LVI_MASK); | | 1657 | (0 - 1) & ICH_LVI_MASK); |
1647 | | | 1658 | |
1648 | /* start */ | | 1659 | /* start */ |
1649 | microtime(&t1); | | 1660 | microtime(&t1); |
1650 | bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_CTRL, ICH_RPBM); | | 1661 | bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_CTRL, ICH_RPBM); |
1651 | | | 1662 | |
1652 | /* wait */ | | 1663 | /* wait */ |
1653 | nciv = ociv; | | 1664 | nciv = ociv; |
1654 | do { | | 1665 | do { |
1655 | microtime(&t2); | | 1666 | microtime(&t2); |
1656 | if (t2.tv_sec - t1.tv_sec > 1) | | 1667 | if (t2.tv_sec - t1.tv_sec > 1) |
1657 | break; | | 1668 | break; |
1658 | nciv = bus_space_read_1(sc->iot, sc->aud_ioh, | | 1669 | nciv = bus_space_read_1(sc->iot, sc->aud_ioh, |
1659 | ICH_PCMI + ICH_CIV); | | 1670 | ICH_PCMI + ICH_CIV); |
1660 | } while (nciv == ociv); | | 1671 | } while (nciv == ociv); |
1661 | microtime(&t2); | | 1672 | microtime(&t2); |
1662 | | | 1673 | |
1663 | /* stop */ | | 1674 | /* stop */ |
1664 | bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_CTRL, 0); | | 1675 | bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_CTRL, 0); |
1665 | | | 1676 | |
1666 | /* reset */ | | 1677 | /* reset */ |
1667 | DELAY(100); | | 1678 | DELAY(100); |
1668 | bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_CTRL, ICH_RR); | | 1679 | bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_CTRL, ICH_RR); |
1669 | | | 1680 | |
1670 | /* turn time delta into us */ | | 1681 | /* turn time delta into us */ |
1671 | wait_us = ((t2.tv_sec - t1.tv_sec) * 1000000) + t2.tv_usec - t1.tv_usec; | | 1682 | wait_us = ((t2.tv_sec - t1.tv_sec) * 1000000) + t2.tv_usec - t1.tv_usec; |
1672 | | | 1683 | |
1673 | auich_freem(sc, temp_buffer, M_DEVBUF); | | 1684 | auich_freem(sc, temp_buffer, M_DEVBUF); |
1674 | | | 1685 | |
1675 | if (nciv == ociv) { | | 1686 | if (nciv == ociv) { |
1676 | printf("%s: ac97 link rate calibration timed out after %" | | 1687 | printf("%s: ac97 link rate calibration timed out after %" |
1677 | PRIu64 " us\n", device_xname(sc->sc_dev), wait_us); | | 1688 | PRIu64 " us\n", device_xname(sc->sc_dev), wait_us); |
1678 | return; | | 1689 | return; |
1679 | } | | 1690 | } |
1680 | | | 1691 | |
1681 | actual_48k_rate = (bytes * UINT64_C(250000)) / wait_us; | | 1692 | actual_48k_rate = (bytes * UINT64_C(250000)) / wait_us; |
1682 | | | 1693 | |
1683 | if (actual_48k_rate < 50000) | | 1694 | if (actual_48k_rate < 50000) |
1684 | ac97rate = 48000; | | 1695 | ac97rate = 48000; |
1685 | else | | 1696 | else |
1686 | ac97rate = ((actual_48k_rate + 500) / 1000) * 1000; | | 1697 | ac97rate = ((actual_48k_rate + 500) / 1000) * 1000; |
1687 | | | 1698 | |
1688 | printf("%s: measured ac97 link rate at %d Hz", | | 1699 | printf("%s: measured ac97 link rate at %d Hz", |
1689 | device_xname(sc->sc_dev), actual_48k_rate); | | 1700 | device_xname(sc->sc_dev), actual_48k_rate); |
1690 | if (ac97rate != actual_48k_rate) | | 1701 | if (ac97rate != actual_48k_rate) |
1691 | printf(", will use %d Hz", ac97rate); | | 1702 | printf(", will use %d Hz", ac97rate); |