| @@ -1,1255 +1,1255 @@ | | | @@ -1,1255 +1,1255 @@ |
1 | /* $NetBSD: ad1848.c,v 1.29 2008/04/28 20:23:48 martin Exp $ */ | | 1 | /* $NetBSD: ad1848.c,v 1.30 2011/04/27 07:47:33 plunky Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1999 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1999 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 Ken Hornstein and John Kohl. | | 8 | * by Ken Hornstein and John Kohl. |
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 | * Copyright (c) 1994 John Brezak | | 32 | * Copyright (c) 1994 John Brezak |
33 | * Copyright (c) 1991-1993 Regents of the University of California. | | 33 | * Copyright (c) 1991-1993 Regents of the University of California. |
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. All advertising materials mentioning features or use of this software | | 44 | * 3. All advertising materials mentioning features or use of this software |
45 | * must display the following acknowledgement: | | 45 | * must display the following acknowledgement: |
46 | * This product includes software developed by the Computer Systems | | 46 | * This product includes software developed by the Computer Systems |
47 | * Engineering Group at Lawrence Berkeley Laboratory. | | 47 | * Engineering Group at Lawrence Berkeley Laboratory. |
48 | * 4. Neither the name of the University nor of the Laboratory may be used | | 48 | * 4. Neither the name of the University nor of the Laboratory may be used |
49 | * to endorse or promote products derived from this software without | | 49 | * to endorse or promote products derived from this software without |
50 | * specific prior written permission. | | 50 | * specific prior written permission. |
51 | * | | 51 | * |
52 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 52 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
53 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 53 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
54 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 54 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
55 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 55 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
56 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 56 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
57 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 57 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
58 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 58 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
59 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 59 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
60 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 60 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
61 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 61 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
62 | * SUCH DAMAGE. | | 62 | * SUCH DAMAGE. |
63 | * | | 63 | * |
64 | */ | | 64 | */ |
65 | | | 65 | |
66 | /* | | 66 | /* |
67 | * Copyright by Hannu Savolainen 1994 | | 67 | * Copyright by Hannu Savolainen 1994 |
68 | * | | 68 | * |
69 | * Redistribution and use in source and binary forms, with or without | | 69 | * Redistribution and use in source and binary forms, with or without |
70 | * modification, are permitted provided that the following conditions are | | 70 | * modification, are permitted provided that the following conditions are |
71 | * met: 1. Redistributions of source code must retain the above copyright | | 71 | * met: 1. Redistributions of source code must retain the above copyright |
72 | * notice, this list of conditions and the following disclaimer. 2. | | 72 | * notice, this list of conditions and the following disclaimer. 2. |
73 | * Redistributions in binary form must reproduce the above copyright notice, | | 73 | * Redistributions in binary form must reproduce the above copyright notice, |
74 | * this list of conditions and the following disclaimer in the documentation | | 74 | * this list of conditions and the following disclaimer in the documentation |
75 | * and/or other materials provided with the distribution. | | 75 | * and/or other materials provided with the distribution. |
76 | * | | 76 | * |
77 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY | | 77 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY |
78 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | | 78 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
79 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | | 79 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
80 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | | 80 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR |
81 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 81 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
82 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | | 82 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
83 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | | 83 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
84 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 84 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
85 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 85 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
86 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 86 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
87 | * SUCH DAMAGE. | | 87 | * SUCH DAMAGE. |
88 | * | | 88 | * |
89 | */ | | 89 | */ |
90 | /* | | 90 | /* |
91 | * Portions of this code are from the VOXware support for the ad1848 | | 91 | * Portions of this code are from the VOXware support for the ad1848 |
92 | * by Hannu Savolainen <hannu@voxware.pp.fi> | | 92 | * by Hannu Savolainen <hannu@voxware.pp.fi> |
93 | * | | 93 | * |
94 | * Portions also supplied from the SoundBlaster driver for NetBSD. | | 94 | * Portions also supplied from the SoundBlaster driver for NetBSD. |
95 | */ | | 95 | */ |
96 | | | 96 | |
97 | #include <sys/cdefs.h> | | 97 | #include <sys/cdefs.h> |
98 | __KERNEL_RCSID(0, "$NetBSD: ad1848.c,v 1.29 2008/04/28 20:23:48 martin Exp $"); | | 98 | __KERNEL_RCSID(0, "$NetBSD: ad1848.c,v 1.30 2011/04/27 07:47:33 plunky Exp $"); |
99 | | | 99 | |
100 | #include <sys/param.h> | | 100 | #include <sys/param.h> |
101 | #include <sys/systm.h> | | 101 | #include <sys/systm.h> |
102 | #include <sys/errno.h> | | 102 | #include <sys/errno.h> |
103 | #include <sys/ioctl.h> | | 103 | #include <sys/ioctl.h> |
104 | #include <sys/device.h> | | 104 | #include <sys/device.h> |
105 | #include <sys/fcntl.h> | | 105 | #include <sys/fcntl.h> |
106 | /*#include <sys/syslog.h>*/ | | 106 | /*#include <sys/syslog.h>*/ |
107 | /*#include <sys/proc.h>*/ | | 107 | /*#include <sys/proc.h>*/ |
108 | | | 108 | |
109 | #include <sys/cpu.h> | | 109 | #include <sys/cpu.h> |
110 | #include <sys/bus.h> | | 110 | #include <sys/bus.h> |
111 | | | 111 | |
112 | #include <sys/audioio.h> | | 112 | #include <sys/audioio.h> |
113 | | | 113 | |
114 | #include <dev/audio_if.h> | | 114 | #include <dev/audio_if.h> |
115 | #include <dev/auconv.h> | | 115 | #include <dev/auconv.h> |
116 | | | 116 | |
117 | #include <dev/ic/ad1848reg.h> | | 117 | #include <dev/ic/ad1848reg.h> |
118 | #include <dev/ic/cs4231reg.h> | | 118 | #include <dev/ic/cs4231reg.h> |
119 | #include <dev/ic/cs4237reg.h> | | 119 | #include <dev/ic/cs4237reg.h> |
120 | #include <dev/ic/ad1848var.h> | | 120 | #include <dev/ic/ad1848var.h> |
121 | #if 0 | | 121 | #if 0 |
122 | #include <dev/isa/cs4231var.h> | | 122 | #include <dev/isa/cs4231var.h> |
123 | #endif | | 123 | #endif |
124 | | | 124 | |
125 | /* | | 125 | /* |
126 | * AD1845 on some machines don't match the AD1845 doc | | 126 | * AD1845 on some machines don't match the AD1845 doc |
127 | * and defining AD1845_HACK to 1 works around the problems. | | 127 | * and defining AD1845_HACK to 1 works around the problems. |
128 | * options AD1845_HACK=0 should work if you have ``correct'' one. | | 128 | * options AD1845_HACK=0 should work if you have ``correct'' one. |
129 | */ | | 129 | */ |
130 | #ifndef AD1845_HACK | | 130 | #ifndef AD1845_HACK |
131 | #define AD1845_HACK 1 /* weird mixer, can't play slinear_be */ | | 131 | #define AD1845_HACK 1 /* weird mixer, can't play slinear_be */ |
132 | #endif | | 132 | #endif |
133 | | | 133 | |
134 | #ifdef AUDIO_DEBUG | | 134 | #ifdef AUDIO_DEBUG |
135 | #define DPRINTF(x) if (ad1848debug) printf x | | 135 | #define DPRINTF(x) if (ad1848debug) printf x |
136 | int ad1848debug = 0; | | 136 | int ad1848debug = 0; |
137 | void ad1848_dump_regs(struct ad1848_softc *); | | 137 | void ad1848_dump_regs(struct ad1848_softc *); |
138 | #else | | 138 | #else |
139 | #define DPRINTF(x) | | 139 | #define DPRINTF(x) |
140 | #endif | | 140 | #endif |
141 | | | 141 | |
142 | /* | | 142 | /* |
143 | * Initial values for the indirect registers of CS4248/AD1848. | | 143 | * Initial values for the indirect registers of CS4248/AD1848. |
144 | */ | | 144 | */ |
145 | static const int ad1848_init_values[] = { | | 145 | static const int ad1848_init_values[] = { |
146 | GAIN_12|INPUT_MIC_GAIN_ENABLE, /* Left Input Control */ | | 146 | GAIN_12|INPUT_MIC_GAIN_ENABLE, /* Left Input Control */ |
147 | GAIN_12|INPUT_MIC_GAIN_ENABLE, /* Right Input Control */ | | 147 | GAIN_12|INPUT_MIC_GAIN_ENABLE, /* Right Input Control */ |
148 | ATTEN_12, /* Left Aux #1 Input Control */ | | 148 | ATTEN_12, /* Left Aux #1 Input Control */ |
149 | ATTEN_12, /* Right Aux #1 Input Control */ | | 149 | ATTEN_12, /* Right Aux #1 Input Control */ |
150 | ATTEN_12, /* Left Aux #2 Input Control */ | | 150 | ATTEN_12, /* Left Aux #2 Input Control */ |
151 | ATTEN_12, /* Right Aux #2 Input Control */ | | 151 | ATTEN_12, /* Right Aux #2 Input Control */ |
152 | /* bits 5-0 are attenuation select */ | | 152 | /* bits 5-0 are attenuation select */ |
153 | ATTEN_12, /* Left DAC output Control */ | | 153 | ATTEN_12, /* Left DAC output Control */ |
154 | ATTEN_12, /* Right DAC output Control */ | | 154 | ATTEN_12, /* Right DAC output Control */ |
155 | CLOCK_XTAL1|FMT_PCM8, /* Clock and Data Format */ | | 155 | CLOCK_XTAL1|FMT_PCM8, /* Clock and Data Format */ |
156 | SINGLE_DMA|AUTO_CAL_ENABLE, /* Interface Config */ | | 156 | SINGLE_DMA|AUTO_CAL_ENABLE, /* Interface Config */ |
157 | INTERRUPT_ENABLE, /* Pin control */ | | 157 | INTERRUPT_ENABLE, /* Pin control */ |
158 | 0x00, /* Test and Init */ | | 158 | 0x00, /* Test and Init */ |
159 | MODE2, /* Misc control */ | | 159 | MODE2, /* Misc control */ |
160 | ATTEN_0<<2, /* Digital Mix Control */ | | 160 | ATTEN_0<<2, /* Digital Mix Control */ |
161 | 0, /* Upper base Count */ | | 161 | 0, /* Upper base Count */ |
162 | 0, /* Lower base Count */ | | 162 | 0, /* Lower base Count */ |
163 | | | 163 | |
164 | /* These are for CS4231 &c. only (additional registers): */ | | 164 | /* These are for CS4231 &c. only (additional registers): */ |
165 | 0, /* Alt feature 1 */ | | 165 | 0, /* Alt feature 1 */ |
166 | 0, /* Alt feature 2 */ | | 166 | 0, /* Alt feature 2 */ |
167 | ATTEN_12, /* Left line in */ | | 167 | ATTEN_12, /* Left line in */ |
168 | ATTEN_12, /* Right line in */ | | 168 | ATTEN_12, /* Right line in */ |
169 | 0, /* Timer low */ | | 169 | 0, /* Timer low */ |
170 | 0, /* Timer high */ | | 170 | 0, /* Timer high */ |
171 | 0, /* unused */ | | 171 | 0, /* unused */ |
172 | 0, /* unused */ | | 172 | 0, /* unused */ |
173 | 0, /* IRQ status */ | | 173 | 0, /* IRQ status */ |
174 | 0, /* unused */ | | 174 | 0, /* unused */ |
175 | /* Mono input (a.k.a speaker) (mic) Control */ | | 175 | /* Mono input (a.k.a speaker) (mic) Control */ |
176 | MONO_INPUT_MUTE|ATTEN_6, /* mute speaker by default */ | | 176 | MONO_INPUT_MUTE|ATTEN_6, /* mute speaker by default */ |
177 | 0, /* unused */ | | 177 | 0, /* unused */ |
178 | 0, /* record format */ | | 178 | 0, /* record format */ |
179 | 0, /* Crystal Clock Select */ | | 179 | 0, /* Crystal Clock Select */ |
180 | 0, /* upper record count */ | | 180 | 0, /* upper record count */ |
181 | 0 /* lower record count */ | | 181 | 0 /* lower record count */ |
182 | }; | | 182 | }; |
183 | | | 183 | |
184 | | | 184 | |
185 | int | | 185 | int |
186 | ad1848_to_vol(mixer_ctrl_t *cp, struct ad1848_volume *vol) | | 186 | ad1848_to_vol(mixer_ctrl_t *cp, struct ad1848_volume *vol) |
187 | { | | 187 | { |
188 | | | 188 | |
189 | if (cp->un.value.num_channels == 1) { | | 189 | if (cp->un.value.num_channels == 1) { |
190 | vol->left = | | 190 | vol->left = |
191 | vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; | | 191 | vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; |
192 | return 1; | | 192 | return 1; |
193 | } | | 193 | } |
194 | else if (cp->un.value.num_channels == 2) { | | 194 | else if (cp->un.value.num_channels == 2) { |
195 | vol->left = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; | | 195 | vol->left = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; |
196 | vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; | | 196 | vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; |
197 | return 1; | | 197 | return 1; |
198 | } | | 198 | } |
199 | return 0; | | 199 | return 0; |
200 | } | | 200 | } |
201 | | | 201 | |
202 | int | | 202 | int |
203 | ad1848_from_vol(mixer_ctrl_t *cp, struct ad1848_volume *vol) | | 203 | ad1848_from_vol(mixer_ctrl_t *cp, struct ad1848_volume *vol) |
204 | { | | 204 | { |
205 | | | 205 | |
206 | if (cp->un.value.num_channels == 1) { | | 206 | if (cp->un.value.num_channels == 1) { |
207 | cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol->left; | | 207 | cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol->left; |
208 | return 1; | | 208 | return 1; |
209 | } | | 209 | } |
210 | else if (cp->un.value.num_channels == 2) { | | 210 | else if (cp->un.value.num_channels == 2) { |
211 | cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = vol->left; | | 211 | cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = vol->left; |
212 | cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = vol->right; | | 212 | cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = vol->right; |
213 | return 1; | | 213 | return 1; |
214 | } | | 214 | } |
215 | return 0; | | 215 | return 0; |
216 | } | | 216 | } |
217 | | | 217 | |
218 | | | 218 | |
219 | inline int | | 219 | int |
220 | ad_read(struct ad1848_softc *sc, int reg) | | 220 | ad_read(struct ad1848_softc *sc, int reg) |
221 | { | | 221 | { |
222 | int x; | | 222 | int x; |
223 | | | 223 | |
224 | ADWRITE(sc, AD1848_IADDR, (reg & 0xff) | sc->MCE_bit); | | 224 | ADWRITE(sc, AD1848_IADDR, (reg & 0xff) | sc->MCE_bit); |
225 | x = ADREAD(sc, AD1848_IDATA); | | 225 | x = ADREAD(sc, AD1848_IDATA); |
226 | /* printf("(%02x<-%02x) ", reg|sc->MCE_bit, x); */ | | 226 | /* printf("(%02x<-%02x) ", reg|sc->MCE_bit, x); */ |
227 | return x; | | 227 | return x; |
228 | } | | 228 | } |
229 | | | 229 | |
230 | inline void | | 230 | void |
231 | ad_write(struct ad1848_softc *sc, int reg, int data) | | 231 | ad_write(struct ad1848_softc *sc, int reg, int data) |
232 | { | | 232 | { |
233 | | | 233 | |
234 | ADWRITE(sc, AD1848_IADDR, (reg & 0xff) | sc->MCE_bit); | | 234 | ADWRITE(sc, AD1848_IADDR, (reg & 0xff) | sc->MCE_bit); |
235 | ADWRITE(sc, AD1848_IDATA, data & 0xff); | | 235 | ADWRITE(sc, AD1848_IDATA, data & 0xff); |
236 | /* printf("(%02x->%02x) ", reg|sc->MCE_bit, data); */ | | 236 | /* printf("(%02x->%02x) ", reg|sc->MCE_bit, data); */ |
237 | } | | 237 | } |
238 | | | 238 | |
239 | /* | | 239 | /* |
240 | * extended registers (mode 3) require an additional level of | | 240 | * extended registers (mode 3) require an additional level of |
241 | * indirection through CS_XREG (I23). | | 241 | * indirection through CS_XREG (I23). |
242 | */ | | 242 | */ |
243 | | | 243 | |
244 | inline int | | 244 | int |
245 | ad_xread(struct ad1848_softc *sc, int reg) | | 245 | ad_xread(struct ad1848_softc *sc, int reg) |
246 | { | | 246 | { |
247 | int x; | | 247 | int x; |
248 | | | 248 | |
249 | ADWRITE(sc, AD1848_IADDR, CS_XREG | sc->MCE_bit); | | 249 | ADWRITE(sc, AD1848_IADDR, CS_XREG | sc->MCE_bit); |
250 | ADWRITE(sc, AD1848_IDATA, (reg | ALT_F3_XRAE) & 0xff); | | 250 | ADWRITE(sc, AD1848_IDATA, (reg | ALT_F3_XRAE) & 0xff); |
251 | x = ADREAD(sc, AD1848_IDATA); | | 251 | x = ADREAD(sc, AD1848_IDATA); |
252 | | | 252 | |
253 | return x; | | 253 | return x; |
254 | } | | 254 | } |
255 | | | 255 | |
256 | inline void | | 256 | void |
257 | ad_xwrite(struct ad1848_softc *sc, int reg, int val) | | 257 | ad_xwrite(struct ad1848_softc *sc, int reg, int val) |
258 | { | | 258 | { |
259 | | | 259 | |
260 | ADWRITE(sc, AD1848_IADDR, CS_XREG | sc->MCE_bit); | | 260 | ADWRITE(sc, AD1848_IADDR, CS_XREG | sc->MCE_bit); |
261 | ADWRITE(sc, AD1848_IDATA, (reg | ALT_F3_XRAE) & 0xff); | | 261 | ADWRITE(sc, AD1848_IDATA, (reg | ALT_F3_XRAE) & 0xff); |
262 | ADWRITE(sc, AD1848_IDATA, val & 0xff); | | 262 | ADWRITE(sc, AD1848_IDATA, val & 0xff); |
263 | } | | 263 | } |
264 | | | 264 | |
265 | static void | | 265 | static void |
266 | ad_set_MCE(struct ad1848_softc *sc, int state) | | 266 | ad_set_MCE(struct ad1848_softc *sc, int state) |
267 | { | | 267 | { |
268 | | | 268 | |
269 | if (state) | | 269 | if (state) |
270 | sc->MCE_bit = MODE_CHANGE_ENABLE; | | 270 | sc->MCE_bit = MODE_CHANGE_ENABLE; |
271 | else | | 271 | else |
272 | sc->MCE_bit = 0; | | 272 | sc->MCE_bit = 0; |
273 | ADWRITE(sc, AD1848_IADDR, sc->MCE_bit); | | 273 | ADWRITE(sc, AD1848_IADDR, sc->MCE_bit); |
274 | } | | 274 | } |
275 | | | 275 | |
276 | static void | | 276 | static void |
277 | wait_for_calibration(struct ad1848_softc *sc) | | 277 | wait_for_calibration(struct ad1848_softc *sc) |
278 | { | | 278 | { |
279 | int timeout; | | 279 | int timeout; |
280 | | | 280 | |
281 | DPRINTF(("ad1848: Auto calibration started.\n")); | | 281 | DPRINTF(("ad1848: Auto calibration started.\n")); |
282 | /* | | 282 | /* |
283 | * Wait until the auto calibration process has finished. | | 283 | * Wait until the auto calibration process has finished. |
284 | * | | 284 | * |
285 | * 1) Wait until the chip becomes ready (reads don't return 0x80). | | 285 | * 1) Wait until the chip becomes ready (reads don't return 0x80). |
286 | * 2) Wait until the ACI bit of I11 gets on and then off. | | 286 | * 2) Wait until the ACI bit of I11 gets on and then off. |
287 | * Because newer chips are fast we may never see the ACI | | 287 | * Because newer chips are fast we may never see the ACI |
288 | * bit go on. Just delay a little instead. | | 288 | * bit go on. Just delay a little instead. |
289 | */ | | 289 | */ |
290 | timeout = 10000; | | 290 | timeout = 10000; |
291 | while (timeout > 0 && ADREAD(sc, AD1848_IADDR) == SP_IN_INIT) { | | 291 | while (timeout > 0 && ADREAD(sc, AD1848_IADDR) == SP_IN_INIT) { |
292 | delay(10); | | 292 | delay(10); |
293 | timeout--; | | 293 | timeout--; |
294 | } | | 294 | } |
295 | if (timeout <= 0) { | | 295 | if (timeout <= 0) { |
296 | DPRINTF(("ad1848: Auto calibration timed out(1).\n")); | | 296 | DPRINTF(("ad1848: Auto calibration timed out(1).\n")); |
297 | } | | 297 | } |
298 | | | 298 | |
299 | /* Set register addr */ | | 299 | /* Set register addr */ |
300 | ADWRITE(sc, AD1848_IADDR, SP_TEST_AND_INIT); | | 300 | ADWRITE(sc, AD1848_IADDR, SP_TEST_AND_INIT); |
301 | /* Wait for address to appear when read back. */ | | 301 | /* Wait for address to appear when read back. */ |
302 | timeout = 100000; | | 302 | timeout = 100000; |
303 | while (timeout > 0 && | | 303 | while (timeout > 0 && |
304 | (ADREAD(sc, AD1848_IADDR)&SP_IADDR_MASK) != SP_TEST_AND_INIT) { | | 304 | (ADREAD(sc, AD1848_IADDR)&SP_IADDR_MASK) != SP_TEST_AND_INIT) { |
305 | delay(10); | | 305 | delay(10); |
306 | timeout--; | | 306 | timeout--; |
307 | } | | 307 | } |
308 | if (timeout <= 0) { | | 308 | if (timeout <= 0) { |
309 | DPRINTF(("ad1848: Auto calibration timed out(1.5).\n")); | | 309 | DPRINTF(("ad1848: Auto calibration timed out(1.5).\n")); |
310 | } | | 310 | } |
311 | | | 311 | |
312 | if (!(ad_read(sc, SP_TEST_AND_INIT) & AUTO_CAL_IN_PROG)) { | | 312 | if (!(ad_read(sc, SP_TEST_AND_INIT) & AUTO_CAL_IN_PROG)) { |
313 | if (sc->mode > 1) { | | 313 | if (sc->mode > 1) { |
314 | /* A new chip, just delay a little. */ | | 314 | /* A new chip, just delay a little. */ |
315 | delay(100); /* XXX what should it be? */ | | 315 | delay(100); /* XXX what should it be? */ |
316 | } else { | | 316 | } else { |
317 | timeout = 10000; | | 317 | timeout = 10000; |
318 | while (timeout > 0 && | | 318 | while (timeout > 0 && |
319 | !(ad_read(sc, SP_TEST_AND_INIT) & | | 319 | !(ad_read(sc, SP_TEST_AND_INIT) & |
320 | AUTO_CAL_IN_PROG)) { | | 320 | AUTO_CAL_IN_PROG)) { |
321 | delay(10); | | 321 | delay(10); |
322 | timeout--; | | 322 | timeout--; |
323 | } | | 323 | } |
324 | if (timeout <= 0) { | | 324 | if (timeout <= 0) { |
325 | DPRINTF(("ad1848: Auto calibration timed out(2).\n")); | | 325 | DPRINTF(("ad1848: Auto calibration timed out(2).\n")); |
326 | } | | 326 | } |
327 | } | | 327 | } |
328 | } | | 328 | } |
329 | | | 329 | |
330 | timeout = 10000; | | 330 | timeout = 10000; |
331 | while (timeout > 0 && | | 331 | while (timeout > 0 && |
332 | ad_read(sc, SP_TEST_AND_INIT) & AUTO_CAL_IN_PROG) { | | 332 | ad_read(sc, SP_TEST_AND_INIT) & AUTO_CAL_IN_PROG) { |
333 | delay(10); | | 333 | delay(10); |
334 | timeout--; | | 334 | timeout--; |
335 | } | | 335 | } |
336 | if (timeout <= 0) { | | 336 | if (timeout <= 0) { |
337 | DPRINTF(("ad1848: Auto calibration timed out(3).\n")); | | 337 | DPRINTF(("ad1848: Auto calibration timed out(3).\n")); |
338 | } | | 338 | } |
339 | } | | 339 | } |
340 | | | 340 | |
341 | #ifdef AUDIO_DEBUG | | 341 | #ifdef AUDIO_DEBUG |
342 | void | | 342 | void |
343 | ad1848_dump_regs(struct ad1848_softc *sc) | | 343 | ad1848_dump_regs(struct ad1848_softc *sc) |
344 | { | | 344 | { |
345 | int i; | | 345 | int i; |
346 | u_char r; | | 346 | u_char r; |
347 | | | 347 | |
348 | printf("ad1848 status=%02x", ADREAD(sc, AD1848_STATUS)); | | 348 | printf("ad1848 status=%02x", ADREAD(sc, AD1848_STATUS)); |
349 | printf(" regs: "); | | 349 | printf(" regs: "); |
350 | for (i = 0; i < 16; i++) { | | 350 | for (i = 0; i < 16; i++) { |
351 | r = ad_read(sc, i); | | 351 | r = ad_read(sc, i); |
352 | printf("%02x ", r); | | 352 | printf("%02x ", r); |
353 | } | | 353 | } |
354 | if (sc->mode >= 2) { | | 354 | if (sc->mode >= 2) { |
355 | for (i = 16; i < 32; i++) { | | 355 | for (i = 16; i < 32; i++) { |
356 | r = ad_read(sc, i); | | 356 | r = ad_read(sc, i); |
357 | printf("%02x ", r); | | 357 | printf("%02x ", r); |
358 | } | | 358 | } |
359 | } | | 359 | } |
360 | printf("\n"); | | 360 | printf("\n"); |
361 | } | | 361 | } |
362 | #endif /* AUDIO_DEBUG */ | | 362 | #endif /* AUDIO_DEBUG */ |
363 | | | 363 | |
364 | | | 364 | |
365 | /* | | 365 | /* |
366 | * Attach hardware to driver, attach hardware driver to audio | | 366 | * Attach hardware to driver, attach hardware driver to audio |
367 | * pseudo-device driver . | | 367 | * pseudo-device driver . |
368 | */ | | 368 | */ |
369 | void | | 369 | void |
370 | ad1848_attach(struct ad1848_softc *sc) | | 370 | ad1848_attach(struct ad1848_softc *sc) |
371 | { | | 371 | { |
372 | static struct ad1848_volume vol_mid = {220, 220}; | | 372 | static struct ad1848_volume vol_mid = {220, 220}; |
373 | static struct ad1848_volume vol_0 = {0, 0}; | | 373 | static struct ad1848_volume vol_0 = {0, 0}; |
374 | int i; | | 374 | int i; |
375 | int timeout; | | 375 | int timeout; |
376 | | | 376 | |
377 | /* Initialize the ad1848... */ | | 377 | /* Initialize the ad1848... */ |
378 | for (i = 0; i < 0x10; i++) { | | 378 | for (i = 0; i < 0x10; i++) { |
379 | ad_write(sc, i, ad1848_init_values[i]); | | 379 | ad_write(sc, i, ad1848_init_values[i]); |
380 | timeout = 100000; | | 380 | timeout = 100000; |
381 | while (timeout > 0 && ADREAD(sc, AD1848_IADDR) & SP_IN_INIT) | | 381 | while (timeout > 0 && ADREAD(sc, AD1848_IADDR) & SP_IN_INIT) |
382 | timeout--; | | 382 | timeout--; |
383 | } | | 383 | } |
384 | /* ...and additional CS4231 stuff too */ | | 384 | /* ...and additional CS4231 stuff too */ |
385 | if (sc->mode >= 2) { | | 385 | if (sc->mode >= 2) { |
386 | ad_write(sc, SP_INTERFACE_CONFIG, 0); /* disable SINGLE_DMA */ | | 386 | ad_write(sc, SP_INTERFACE_CONFIG, 0); /* disable SINGLE_DMA */ |
387 | for (i = 0x10; i < 0x20; i++) | | 387 | for (i = 0x10; i < 0x20; i++) |
388 | if (ad1848_init_values[i] != 0) { | | 388 | if (ad1848_init_values[i] != 0) { |
389 | ad_write(sc, i, ad1848_init_values[i]); | | 389 | ad_write(sc, i, ad1848_init_values[i]); |
390 | timeout = 100000; | | 390 | timeout = 100000; |
391 | while (timeout > 0 && | | 391 | while (timeout > 0 && |
392 | ADREAD(sc, AD1848_IADDR) & SP_IN_INIT) | | 392 | ADREAD(sc, AD1848_IADDR) & SP_IN_INIT) |
393 | timeout--; | | 393 | timeout--; |
394 | } | | 394 | } |
395 | } | | 395 | } |
396 | ad1848_reset(sc); | | 396 | ad1848_reset(sc); |
397 | | | 397 | |
398 | /* Set default gains */ | | 398 | /* Set default gains */ |
399 | ad1848_set_rec_gain(sc, &vol_mid); | | 399 | ad1848_set_rec_gain(sc, &vol_mid); |
400 | ad1848_set_channel_gain(sc, AD1848_DAC_CHANNEL, &vol_mid); | | 400 | ad1848_set_channel_gain(sc, AD1848_DAC_CHANNEL, &vol_mid); |
401 | ad1848_set_channel_gain(sc, AD1848_MONITOR_CHANNEL, &vol_0); | | 401 | ad1848_set_channel_gain(sc, AD1848_MONITOR_CHANNEL, &vol_0); |
402 | ad1848_set_channel_gain(sc, AD1848_AUX1_CHANNEL, &vol_mid); /* CD volume */ | | 402 | ad1848_set_channel_gain(sc, AD1848_AUX1_CHANNEL, &vol_mid); /* CD volume */ |
403 | sc->mute[AD1848_MONITOR_CHANNEL] = MUTE_ALL; | | 403 | sc->mute[AD1848_MONITOR_CHANNEL] = MUTE_ALL; |
404 | if (sc->mode >= 2 | | 404 | if (sc->mode >= 2 |
405 | #if AD1845_HACK | | 405 | #if AD1845_HACK |
406 | && sc->is_ad1845 == 0 | | 406 | && sc->is_ad1845 == 0 |
407 | #endif | | 407 | #endif |
408 | ) { | | 408 | ) { |
409 | ad1848_set_channel_gain(sc, AD1848_AUX2_CHANNEL, &vol_mid); /* CD volume */ | | 409 | ad1848_set_channel_gain(sc, AD1848_AUX2_CHANNEL, &vol_mid); /* CD volume */ |
410 | ad1848_set_channel_gain(sc, AD1848_LINE_CHANNEL, &vol_mid); | | 410 | ad1848_set_channel_gain(sc, AD1848_LINE_CHANNEL, &vol_mid); |
411 | ad1848_set_channel_gain(sc, AD1848_MONO_CHANNEL, &vol_0); | | 411 | ad1848_set_channel_gain(sc, AD1848_MONO_CHANNEL, &vol_0); |
412 | sc->mute[AD1848_MONO_CHANNEL] = MUTE_ALL; | | 412 | sc->mute[AD1848_MONO_CHANNEL] = MUTE_ALL; |
413 | } else | | 413 | } else |
414 | ad1848_set_channel_gain(sc, AD1848_AUX2_CHANNEL, &vol_0); | | 414 | ad1848_set_channel_gain(sc, AD1848_AUX2_CHANNEL, &vol_0); |
415 | | | 415 | |
416 | /* Set default port */ | | 416 | /* Set default port */ |
417 | ad1848_set_rec_port(sc, MIC_IN_PORT); | | 417 | ad1848_set_rec_port(sc, MIC_IN_PORT); |
418 | | | 418 | |
419 | printf(": %s", sc->chip_name); | | 419 | printf(": %s", sc->chip_name); |
420 | } | | 420 | } |
421 | | | 421 | |
422 | /* | | 422 | /* |
423 | * Various routines to interface to higher level audio driver | | 423 | * Various routines to interface to higher level audio driver |
424 | */ | | 424 | */ |
425 | static const struct ad1848_mixerinfo { | | 425 | static const struct ad1848_mixerinfo { |
426 | int left_reg; | | 426 | int left_reg; |
427 | int right_reg; | | 427 | int right_reg; |
428 | int atten_bits; | | 428 | int atten_bits; |
429 | int atten_mask; | | 429 | int atten_mask; |
430 | } mixer_channel_info[] = | | 430 | } mixer_channel_info[] = |
431 | { | | 431 | { |
432 | { SP_LEFT_AUX2_CONTROL, SP_RIGHT_AUX2_CONTROL, AUX_INPUT_ATTEN_BITS, | | 432 | { SP_LEFT_AUX2_CONTROL, SP_RIGHT_AUX2_CONTROL, AUX_INPUT_ATTEN_BITS, |
433 | AUX_INPUT_ATTEN_MASK }, | | 433 | AUX_INPUT_ATTEN_MASK }, |
434 | { SP_LEFT_AUX1_CONTROL, SP_RIGHT_AUX1_CONTROL, AUX_INPUT_ATTEN_BITS, | | 434 | { SP_LEFT_AUX1_CONTROL, SP_RIGHT_AUX1_CONTROL, AUX_INPUT_ATTEN_BITS, |
435 | AUX_INPUT_ATTEN_MASK }, | | 435 | AUX_INPUT_ATTEN_MASK }, |
436 | { SP_LEFT_OUTPUT_CONTROL, SP_RIGHT_OUTPUT_CONTROL, | | 436 | { SP_LEFT_OUTPUT_CONTROL, SP_RIGHT_OUTPUT_CONTROL, |
437 | OUTPUT_ATTEN_BITS, OUTPUT_ATTEN_MASK }, | | 437 | OUTPUT_ATTEN_BITS, OUTPUT_ATTEN_MASK }, |
438 | { CS_LEFT_LINE_CONTROL, CS_RIGHT_LINE_CONTROL, LINE_INPUT_ATTEN_BITS, | | 438 | { CS_LEFT_LINE_CONTROL, CS_RIGHT_LINE_CONTROL, LINE_INPUT_ATTEN_BITS, |
439 | LINE_INPUT_ATTEN_MASK }, | | 439 | LINE_INPUT_ATTEN_MASK }, |
440 | { CS_MONO_IO_CONTROL, 0, MONO_INPUT_ATTEN_BITS, MONO_INPUT_ATTEN_MASK }, | | 440 | { CS_MONO_IO_CONTROL, 0, MONO_INPUT_ATTEN_BITS, MONO_INPUT_ATTEN_MASK }, |
441 | { CS_MONO_IO_CONTROL, 0, 0, 0 }, | | 441 | { CS_MONO_IO_CONTROL, 0, 0, 0 }, |
442 | { SP_DIGITAL_MIX, 0, OUTPUT_ATTEN_BITS, MIX_ATTEN_MASK } | | 442 | { SP_DIGITAL_MIX, 0, OUTPUT_ATTEN_BITS, MIX_ATTEN_MASK } |
443 | }; | | 443 | }; |
444 | | | 444 | |
445 | /* | | 445 | /* |
446 | * This function doesn't set the mute flags but does use them. | | 446 | * This function doesn't set the mute flags but does use them. |
447 | * The mute flags reflect the mutes that have been applied by the user. | | 447 | * The mute flags reflect the mutes that have been applied by the user. |
448 | * However, the driver occasionally wants to mute devices (e.g. when chaing | | 448 | * However, the driver occasionally wants to mute devices (e.g. when chaing |
449 | * sampling rate). These operations should not affect the mute flags. | | 449 | * sampling rate). These operations should not affect the mute flags. |
450 | */ | | 450 | */ |
451 | | | 451 | |
452 | void | | 452 | void |
453 | ad1848_mute_channel(struct ad1848_softc *sc, int device, int mute) | | 453 | ad1848_mute_channel(struct ad1848_softc *sc, int device, int mute) |
454 | { | | 454 | { |
455 | u_char reg; | | 455 | u_char reg; |
456 | | | 456 | |
457 | reg = ad_read(sc, mixer_channel_info[device].left_reg); | | 457 | reg = ad_read(sc, mixer_channel_info[device].left_reg); |
458 | | | 458 | |
459 | if (mute & MUTE_LEFT) { | | 459 | if (mute & MUTE_LEFT) { |
460 | if (device == AD1848_MONITOR_CHANNEL) { | | 460 | if (device == AD1848_MONITOR_CHANNEL) { |
461 | if (sc->open_mode & FREAD) | | 461 | if (sc->open_mode & FREAD) |
462 | ad1848_mute_wave_output(sc, WAVE_UNMUTE1, 0); | | 462 | ad1848_mute_wave_output(sc, WAVE_UNMUTE1, 0); |
463 | ad_write(sc, mixer_channel_info[device].left_reg, | | 463 | ad_write(sc, mixer_channel_info[device].left_reg, |
464 | reg & ~DIGITAL_MIX1_ENABLE); | | 464 | reg & ~DIGITAL_MIX1_ENABLE); |
465 | } else if (device == AD1848_OUT_CHANNEL) | | 465 | } else if (device == AD1848_OUT_CHANNEL) |
466 | ad_write(sc, mixer_channel_info[device].left_reg, | | 466 | ad_write(sc, mixer_channel_info[device].left_reg, |
467 | reg | MONO_OUTPUT_MUTE); | | 467 | reg | MONO_OUTPUT_MUTE); |
468 | else | | 468 | else |
469 | ad_write(sc, mixer_channel_info[device].left_reg, | | 469 | ad_write(sc, mixer_channel_info[device].left_reg, |
470 | reg | 0x80); | | 470 | reg | 0x80); |
471 | } else if (!(sc->mute[device] & MUTE_LEFT)) { | | 471 | } else if (!(sc->mute[device] & MUTE_LEFT)) { |
472 | if (device == AD1848_MONITOR_CHANNEL) { | | 472 | if (device == AD1848_MONITOR_CHANNEL) { |
473 | ad_write(sc, mixer_channel_info[device].left_reg, | | 473 | ad_write(sc, mixer_channel_info[device].left_reg, |
474 | reg | DIGITAL_MIX1_ENABLE); | | 474 | reg | DIGITAL_MIX1_ENABLE); |
475 | if (sc->open_mode & FREAD) | | 475 | if (sc->open_mode & FREAD) |
476 | ad1848_mute_wave_output(sc, WAVE_UNMUTE1, 1); | | 476 | ad1848_mute_wave_output(sc, WAVE_UNMUTE1, 1); |
477 | } else if (device == AD1848_OUT_CHANNEL) | | 477 | } else if (device == AD1848_OUT_CHANNEL) |
478 | ad_write(sc, mixer_channel_info[device].left_reg, | | 478 | ad_write(sc, mixer_channel_info[device].left_reg, |
479 | reg & ~MONO_OUTPUT_MUTE); | | 479 | reg & ~MONO_OUTPUT_MUTE); |
480 | else | | 480 | else |
481 | ad_write(sc, mixer_channel_info[device].left_reg, | | 481 | ad_write(sc, mixer_channel_info[device].left_reg, |
482 | reg & ~0x80); | | 482 | reg & ~0x80); |
483 | } | | 483 | } |
484 | | | 484 | |
485 | if (!mixer_channel_info[device].right_reg) | | 485 | if (!mixer_channel_info[device].right_reg) |
486 | return; | | 486 | return; |
487 | | | 487 | |
488 | reg = ad_read(sc, mixer_channel_info[device].right_reg); | | 488 | reg = ad_read(sc, mixer_channel_info[device].right_reg); |
489 | | | 489 | |
490 | if (mute & MUTE_RIGHT) { | | 490 | if (mute & MUTE_RIGHT) { |
491 | ad_write(sc, mixer_channel_info[device].right_reg, reg | 0x80); | | 491 | ad_write(sc, mixer_channel_info[device].right_reg, reg | 0x80); |
492 | } else if (!(sc->mute[device] & MUTE_RIGHT)) { | | 492 | } else if (!(sc->mute[device] & MUTE_RIGHT)) { |
493 | ad_write(sc, mixer_channel_info[device].right_reg, reg &~0x80); | | 493 | ad_write(sc, mixer_channel_info[device].right_reg, reg &~0x80); |
494 | } | | 494 | } |
495 | } | | 495 | } |
496 | | | 496 | |
497 | int | | 497 | int |
498 | ad1848_set_channel_gain(struct ad1848_softc *sc, int device, | | 498 | ad1848_set_channel_gain(struct ad1848_softc *sc, int device, |
499 | struct ad1848_volume *gp) | | 499 | struct ad1848_volume *gp) |
500 | { | | 500 | { |
501 | const struct ad1848_mixerinfo *info; | | 501 | const struct ad1848_mixerinfo *info; |
502 | u_char reg; | | 502 | u_char reg; |
503 | u_int atten; | | 503 | u_int atten; |
504 | | | 504 | |
505 | info = &mixer_channel_info[device]; | | 505 | info = &mixer_channel_info[device]; |
506 | sc->gains[device] = *gp; | | 506 | sc->gains[device] = *gp; |
507 | | | 507 | |
508 | atten = (AUDIO_MAX_GAIN - gp->left) * (info->atten_bits + 1) / | | 508 | atten = (AUDIO_MAX_GAIN - gp->left) * (info->atten_bits + 1) / |
509 | (AUDIO_MAX_GAIN + 1); | | 509 | (AUDIO_MAX_GAIN + 1); |
510 | | | 510 | |
511 | reg = ad_read(sc, info->left_reg) & (info->atten_mask); | | 511 | reg = ad_read(sc, info->left_reg) & (info->atten_mask); |
512 | if (device == AD1848_MONITOR_CHANNEL) | | 512 | if (device == AD1848_MONITOR_CHANNEL) |
513 | reg |= ((atten & info->atten_bits) << 2); | | 513 | reg |= ((atten & info->atten_bits) << 2); |
514 | else | | 514 | else |
515 | reg |= ((atten & info->atten_bits)); | | 515 | reg |= ((atten & info->atten_bits)); |
516 | | | 516 | |
517 | ad_write(sc, info->left_reg, reg); | | 517 | ad_write(sc, info->left_reg, reg); |
518 | | | 518 | |
519 | if (!info->right_reg) | | 519 | if (!info->right_reg) |
520 | return 0; | | 520 | return 0; |
521 | | | 521 | |
522 | atten = (AUDIO_MAX_GAIN - gp->right) * (info->atten_bits + 1) / | | 522 | atten = (AUDIO_MAX_GAIN - gp->right) * (info->atten_bits + 1) / |
523 | (AUDIO_MAX_GAIN + 1); | | 523 | (AUDIO_MAX_GAIN + 1); |
524 | reg = ad_read(sc, info->right_reg); | | 524 | reg = ad_read(sc, info->right_reg); |
525 | reg &= info->atten_mask; | | 525 | reg &= info->atten_mask; |
526 | ad_write(sc, info->right_reg, (atten & info->atten_bits) | reg); | | 526 | ad_write(sc, info->right_reg, (atten & info->atten_bits) | reg); |
527 | | | 527 | |
528 | return 0; | | 528 | return 0; |
529 | } | | 529 | } |
530 | | | 530 | |
531 | int | | 531 | int |
532 | ad1848_get_device_gain(struct ad1848_softc *sc, int device, | | 532 | ad1848_get_device_gain(struct ad1848_softc *sc, int device, |
533 | struct ad1848_volume *gp) | | 533 | struct ad1848_volume *gp) |
534 | { | | 534 | { |
535 | | | 535 | |
536 | *gp = sc->gains[device]; | | 536 | *gp = sc->gains[device]; |
537 | return 0; | | 537 | return 0; |
538 | } | | 538 | } |
539 | | | 539 | |
540 | int | | 540 | int |
541 | ad1848_get_rec_gain(struct ad1848_softc *sc, struct ad1848_volume *gp) | | 541 | ad1848_get_rec_gain(struct ad1848_softc *sc, struct ad1848_volume *gp) |
542 | { | | 542 | { |
543 | | | 543 | |
544 | *gp = sc->rec_gain; | | 544 | *gp = sc->rec_gain; |
545 | return 0; | | 545 | return 0; |
546 | } | | 546 | } |
547 | | | 547 | |
548 | int | | 548 | int |
549 | ad1848_set_rec_gain(struct ad1848_softc *sc, struct ad1848_volume *gp) | | 549 | ad1848_set_rec_gain(struct ad1848_softc *sc, struct ad1848_volume *gp) |
550 | { | | 550 | { |
551 | u_char reg, gain; | | 551 | u_char reg, gain; |
552 | | | 552 | |
553 | DPRINTF(("ad1848_set_rec_gain: %d:%d\n", gp->left, gp->right)); | | 553 | DPRINTF(("ad1848_set_rec_gain: %d:%d\n", gp->left, gp->right)); |
554 | | | 554 | |
555 | sc->rec_gain = *gp; | | 555 | sc->rec_gain = *gp; |
556 | | | 556 | |
557 | gain = (gp->left * (GAIN_22_5 + 1)) / (AUDIO_MAX_GAIN + 1); | | 557 | gain = (gp->left * (GAIN_22_5 + 1)) / (AUDIO_MAX_GAIN + 1); |
558 | reg = ad_read(sc, SP_LEFT_INPUT_CONTROL); | | 558 | reg = ad_read(sc, SP_LEFT_INPUT_CONTROL); |
559 | reg &= INPUT_GAIN_MASK; | | 559 | reg &= INPUT_GAIN_MASK; |
560 | ad_write(sc, SP_LEFT_INPUT_CONTROL, (gain & 0x0f) | reg); | | 560 | ad_write(sc, SP_LEFT_INPUT_CONTROL, (gain & 0x0f) | reg); |
561 | | | 561 | |
562 | gain = (gp->right * (GAIN_22_5 + 1)) / (AUDIO_MAX_GAIN + 1); | | 562 | gain = (gp->right * (GAIN_22_5 + 1)) / (AUDIO_MAX_GAIN + 1); |
563 | reg = ad_read(sc, SP_RIGHT_INPUT_CONTROL); | | 563 | reg = ad_read(sc, SP_RIGHT_INPUT_CONTROL); |
564 | reg &= INPUT_GAIN_MASK; | | 564 | reg &= INPUT_GAIN_MASK; |
565 | ad_write(sc, SP_RIGHT_INPUT_CONTROL, (gain & 0x0f) | reg); | | 565 | ad_write(sc, SP_RIGHT_INPUT_CONTROL, (gain & 0x0f) | reg); |
566 | | | 566 | |
567 | return 0; | | 567 | return 0; |
568 | } | | 568 | } |
569 | | | 569 | |
570 | void | | 570 | void |
571 | ad1848_mute_wave_output(struct ad1848_softc *sc, int mute, int set) | | 571 | ad1848_mute_wave_output(struct ad1848_softc *sc, int mute, int set) |
572 | { | | 572 | { |
573 | int m; | | 573 | int m; |
574 | | | 574 | |
575 | DPRINTF(("ad1848_mute_wave_output: %d, %d\n", mute, set)); | | 575 | DPRINTF(("ad1848_mute_wave_output: %d, %d\n", mute, set)); |
576 | | | 576 | |
577 | if (mute == WAVE_MUTE2_INIT) { | | 577 | if (mute == WAVE_MUTE2_INIT) { |
578 | sc->wave_mute_status = 0; | | 578 | sc->wave_mute_status = 0; |
579 | mute = WAVE_MUTE2; | | 579 | mute = WAVE_MUTE2; |
580 | } | | 580 | } |
581 | if (set) | | 581 | if (set) |
582 | m = sc->wave_mute_status |= mute; | | 582 | m = sc->wave_mute_status |= mute; |
583 | else | | 583 | else |
584 | m = sc->wave_mute_status &= ~mute; | | 584 | m = sc->wave_mute_status &= ~mute; |
585 | | | 585 | |
586 | if (m & WAVE_MUTE0 || ((m & WAVE_UNMUTE1) == 0 && m & WAVE_MUTE2)) | | 586 | if (m & WAVE_MUTE0 || ((m & WAVE_UNMUTE1) == 0 && m & WAVE_MUTE2)) |
587 | ad1848_mute_channel(sc, AD1848_DAC_CHANNEL, MUTE_ALL); | | 587 | ad1848_mute_channel(sc, AD1848_DAC_CHANNEL, MUTE_ALL); |
588 | else | | 588 | else |
589 | ad1848_mute_channel(sc, AD1848_DAC_CHANNEL, | | 589 | ad1848_mute_channel(sc, AD1848_DAC_CHANNEL, |
590 | sc->mute[AD1848_DAC_CHANNEL]); | | 590 | sc->mute[AD1848_DAC_CHANNEL]); |
591 | } | | 591 | } |
592 | | | 592 | |
593 | int | | 593 | int |
594 | ad1848_set_mic_gain(struct ad1848_softc *sc, struct ad1848_volume *gp) | | 594 | ad1848_set_mic_gain(struct ad1848_softc *sc, struct ad1848_volume *gp) |
595 | { | | 595 | { |
596 | u_char reg; | | 596 | u_char reg; |
597 | | | 597 | |
598 | DPRINTF(("cs4231_set_mic_gain: %d\n", gp->left)); | | 598 | DPRINTF(("cs4231_set_mic_gain: %d\n", gp->left)); |
599 | | | 599 | |
600 | if (gp->left > AUDIO_MAX_GAIN/2) { | | 600 | if (gp->left > AUDIO_MAX_GAIN/2) { |
601 | sc->mic_gain_on = 1; | | 601 | sc->mic_gain_on = 1; |
602 | reg = ad_read(sc, SP_LEFT_INPUT_CONTROL); | | 602 | reg = ad_read(sc, SP_LEFT_INPUT_CONTROL); |
603 | ad_write(sc, SP_LEFT_INPUT_CONTROL, | | 603 | ad_write(sc, SP_LEFT_INPUT_CONTROL, |
604 | reg | INPUT_MIC_GAIN_ENABLE); | | 604 | reg | INPUT_MIC_GAIN_ENABLE); |
605 | } else { | | 605 | } else { |
606 | sc->mic_gain_on = 0; | | 606 | sc->mic_gain_on = 0; |
607 | reg = ad_read(sc, SP_LEFT_INPUT_CONTROL); | | 607 | reg = ad_read(sc, SP_LEFT_INPUT_CONTROL); |
608 | ad_write(sc, SP_LEFT_INPUT_CONTROL, | | 608 | ad_write(sc, SP_LEFT_INPUT_CONTROL, |
609 | reg & ~INPUT_MIC_GAIN_ENABLE); | | 609 | reg & ~INPUT_MIC_GAIN_ENABLE); |
610 | } | | 610 | } |
611 | | | 611 | |
612 | return 0; | | 612 | return 0; |
613 | } | | 613 | } |
614 | | | 614 | |
615 | int | | 615 | int |
616 | ad1848_get_mic_gain(struct ad1848_softc *sc, struct ad1848_volume *gp) | | 616 | ad1848_get_mic_gain(struct ad1848_softc *sc, struct ad1848_volume *gp) |
617 | { | | 617 | { |
618 | if (sc->mic_gain_on) | | 618 | if (sc->mic_gain_on) |
619 | gp->left = gp->right = AUDIO_MAX_GAIN; | | 619 | gp->left = gp->right = AUDIO_MAX_GAIN; |
620 | else | | 620 | else |
621 | gp->left = gp->right = AUDIO_MIN_GAIN; | | 621 | gp->left = gp->right = AUDIO_MIN_GAIN; |
622 | return 0; | | 622 | return 0; |
623 | } | | 623 | } |
624 | | | 624 | |
625 | static const ad1848_devmap_t * | | 625 | static const ad1848_devmap_t * |
626 | ad1848_mixer_find_dev(const ad1848_devmap_t *map, int cnt, mixer_ctrl_t *cp) | | 626 | ad1848_mixer_find_dev(const ad1848_devmap_t *map, int cnt, mixer_ctrl_t *cp) |
627 | { | | 627 | { |
628 | int i; | | 628 | int i; |
629 | | | 629 | |
630 | for (i = 0; i < cnt; i++) { | | 630 | for (i = 0; i < cnt; i++) { |
631 | if (map[i].id == cp->dev) { | | 631 | if (map[i].id == cp->dev) { |
632 | return (&map[i]); | | 632 | return (&map[i]); |
633 | } | | 633 | } |
634 | } | | 634 | } |
635 | return 0; | | 635 | return 0; |
636 | } | | 636 | } |
637 | | | 637 | |
638 | int | | 638 | int |
639 | ad1848_mixer_get_port(struct ad1848_softc *ac, const struct ad1848_devmap *map, | | 639 | ad1848_mixer_get_port(struct ad1848_softc *ac, const struct ad1848_devmap *map, |
640 | int cnt, mixer_ctrl_t *cp) | | 640 | int cnt, mixer_ctrl_t *cp) |
641 | { | | 641 | { |
642 | const ad1848_devmap_t *entry; | | 642 | const ad1848_devmap_t *entry; |
643 | struct ad1848_volume vol; | | 643 | struct ad1848_volume vol; |
644 | int error; | | 644 | int error; |
645 | int dev; | | 645 | int dev; |
646 | | | 646 | |
647 | error = EINVAL; | | 647 | error = EINVAL; |
648 | if (!(entry = ad1848_mixer_find_dev(map, cnt, cp))) | | 648 | if (!(entry = ad1848_mixer_find_dev(map, cnt, cp))) |
649 | return ENXIO; | | 649 | return ENXIO; |
650 | | | 650 | |
651 | dev = entry->dev; | | 651 | dev = entry->dev; |
652 | | | 652 | |
653 | switch (entry->kind) { | | 653 | switch (entry->kind) { |
654 | case AD1848_KIND_LVL: | | 654 | case AD1848_KIND_LVL: |
655 | if (cp->type != AUDIO_MIXER_VALUE) | | 655 | if (cp->type != AUDIO_MIXER_VALUE) |
656 | break; | | 656 | break; |
657 | | | 657 | |
658 | if (dev < AD1848_AUX2_CHANNEL || | | 658 | if (dev < AD1848_AUX2_CHANNEL || |
659 | dev > AD1848_MONITOR_CHANNEL) | | 659 | dev > AD1848_MONITOR_CHANNEL) |
660 | break; | | 660 | break; |
661 | | | 661 | |
662 | if (cp->un.value.num_channels != 1 && | | 662 | if (cp->un.value.num_channels != 1 && |
663 | mixer_channel_info[dev].right_reg == 0) | | 663 | mixer_channel_info[dev].right_reg == 0) |
664 | break; | | 664 | break; |
665 | | | 665 | |
666 | error = ad1848_get_device_gain(ac, dev, &vol); | | 666 | error = ad1848_get_device_gain(ac, dev, &vol); |
667 | if (!error) | | 667 | if (!error) |
668 | ad1848_from_vol(cp, &vol); | | 668 | ad1848_from_vol(cp, &vol); |
669 | | | 669 | |
670 | break; | | 670 | break; |
671 | | | 671 | |
672 | case AD1848_KIND_MUTE: | | 672 | case AD1848_KIND_MUTE: |
673 | if (cp->type != AUDIO_MIXER_ENUM) break; | | 673 | if (cp->type != AUDIO_MIXER_ENUM) break; |
674 | | | 674 | |
675 | cp->un.ord = ac->mute[dev] ? 1 : 0; | | 675 | cp->un.ord = ac->mute[dev] ? 1 : 0; |
676 | error = 0; | | 676 | error = 0; |
677 | break; | | 677 | break; |
678 | | | 678 | |
679 | case AD1848_KIND_RECORDGAIN: | | 679 | case AD1848_KIND_RECORDGAIN: |
680 | if (cp->type != AUDIO_MIXER_VALUE) break; | | 680 | if (cp->type != AUDIO_MIXER_VALUE) break; |
681 | | | 681 | |
682 | error = ad1848_get_rec_gain(ac, &vol); | | 682 | error = ad1848_get_rec_gain(ac, &vol); |
683 | if (!error) | | 683 | if (!error) |
684 | ad1848_from_vol(cp, &vol); | | 684 | ad1848_from_vol(cp, &vol); |
685 | | | 685 | |
686 | break; | | 686 | break; |
687 | | | 687 | |
688 | case AD1848_KIND_MICGAIN: | | 688 | case AD1848_KIND_MICGAIN: |
689 | if (cp->type != AUDIO_MIXER_VALUE) break; | | 689 | if (cp->type != AUDIO_MIXER_VALUE) break; |
690 | | | 690 | |
691 | error = ad1848_get_mic_gain(ac, &vol); | | 691 | error = ad1848_get_mic_gain(ac, &vol); |
692 | if (!error) | | 692 | if (!error) |
693 | ad1848_from_vol(cp, &vol); | | 693 | ad1848_from_vol(cp, &vol); |
694 | | | 694 | |
695 | break; | | 695 | break; |
696 | | | 696 | |
697 | case AD1848_KIND_RECORDSOURCE: | | 697 | case AD1848_KIND_RECORDSOURCE: |
698 | if (cp->type != AUDIO_MIXER_ENUM) break; | | 698 | if (cp->type != AUDIO_MIXER_ENUM) break; |
699 | cp->un.ord = ad1848_get_rec_port(ac); | | 699 | cp->un.ord = ad1848_get_rec_port(ac); |
700 | error = 0; | | 700 | error = 0; |
701 | break; | | 701 | break; |
702 | | | 702 | |
703 | default: | | 703 | default: |
704 | printf ("Invalid kind\n"); | | 704 | printf ("Invalid kind\n"); |
705 | break; | | 705 | break; |
706 | } | | 706 | } |
707 | | | 707 | |
708 | return error; | | 708 | return error; |
709 | } | | 709 | } |
710 | | | 710 | |
711 | int | | 711 | int |
712 | ad1848_mixer_set_port(struct ad1848_softc *ac, const struct ad1848_devmap *map, | | 712 | ad1848_mixer_set_port(struct ad1848_softc *ac, const struct ad1848_devmap *map, |
713 | int cnt, mixer_ctrl_t *cp) | | 713 | int cnt, mixer_ctrl_t *cp) |
714 | { | | 714 | { |
715 | const ad1848_devmap_t *entry; | | 715 | const ad1848_devmap_t *entry; |
716 | struct ad1848_volume vol; | | 716 | struct ad1848_volume vol; |
717 | int error; | | 717 | int error; |
718 | int dev; | | 718 | int dev; |
719 | | | 719 | |
720 | error = EINVAL; | | 720 | error = EINVAL; |
721 | if (!(entry = ad1848_mixer_find_dev(map, cnt, cp))) | | 721 | if (!(entry = ad1848_mixer_find_dev(map, cnt, cp))) |
722 | return ENXIO; | | 722 | return ENXIO; |
723 | | | 723 | |
724 | dev = entry->dev; | | 724 | dev = entry->dev; |
725 | | | 725 | |
726 | switch (entry->kind) { | | 726 | switch (entry->kind) { |
727 | case AD1848_KIND_LVL: | | 727 | case AD1848_KIND_LVL: |
728 | if (cp->type != AUDIO_MIXER_VALUE) | | 728 | if (cp->type != AUDIO_MIXER_VALUE) |
729 | break; | | 729 | break; |
730 | | | 730 | |
731 | if (dev < AD1848_AUX2_CHANNEL || | | 731 | if (dev < AD1848_AUX2_CHANNEL || |
732 | dev > AD1848_MONITOR_CHANNEL) | | 732 | dev > AD1848_MONITOR_CHANNEL) |
733 | break; | | 733 | break; |
734 | | | 734 | |
735 | if (cp->un.value.num_channels != 1 && | | 735 | if (cp->un.value.num_channels != 1 && |
736 | mixer_channel_info[dev].right_reg == 0) | | 736 | mixer_channel_info[dev].right_reg == 0) |
737 | break; | | 737 | break; |
738 | | | 738 | |
739 | ad1848_to_vol(cp, &vol); | | 739 | ad1848_to_vol(cp, &vol); |
740 | error = ad1848_set_channel_gain(ac, dev, &vol); | | 740 | error = ad1848_set_channel_gain(ac, dev, &vol); |
741 | break; | | 741 | break; |
742 | | | 742 | |
743 | case AD1848_KIND_MUTE: | | 743 | case AD1848_KIND_MUTE: |
744 | if (cp->type != AUDIO_MIXER_ENUM) break; | | 744 | if (cp->type != AUDIO_MIXER_ENUM) break; |
745 | | | 745 | |
746 | ac->mute[dev] = (cp->un.ord ? MUTE_ALL : 0); | | 746 | ac->mute[dev] = (cp->un.ord ? MUTE_ALL : 0); |
747 | ad1848_mute_channel(ac, dev, ac->mute[dev]); | | 747 | ad1848_mute_channel(ac, dev, ac->mute[dev]); |
748 | error = 0; | | 748 | error = 0; |
749 | break; | | 749 | break; |
750 | | | 750 | |
751 | case AD1848_KIND_RECORDGAIN: | | 751 | case AD1848_KIND_RECORDGAIN: |
752 | if (cp->type != AUDIO_MIXER_VALUE) break; | | 752 | if (cp->type != AUDIO_MIXER_VALUE) break; |
753 | | | 753 | |
754 | ad1848_to_vol(cp, &vol); | | 754 | ad1848_to_vol(cp, &vol); |
755 | error = ad1848_set_rec_gain(ac, &vol); | | 755 | error = ad1848_set_rec_gain(ac, &vol); |
756 | break; | | 756 | break; |
757 | | | 757 | |
758 | case AD1848_KIND_MICGAIN: | | 758 | case AD1848_KIND_MICGAIN: |
759 | if (cp->type != AUDIO_MIXER_VALUE) break; | | 759 | if (cp->type != AUDIO_MIXER_VALUE) break; |
760 | | | 760 | |
761 | ad1848_to_vol(cp, &vol); | | 761 | ad1848_to_vol(cp, &vol); |
762 | error = ad1848_set_mic_gain(ac, &vol); | | 762 | error = ad1848_set_mic_gain(ac, &vol); |
763 | break; | | 763 | break; |
764 | | | 764 | |
765 | case AD1848_KIND_RECORDSOURCE: | | 765 | case AD1848_KIND_RECORDSOURCE: |
766 | if (cp->type != AUDIO_MIXER_ENUM) break; | | 766 | if (cp->type != AUDIO_MIXER_ENUM) break; |
767 | | | 767 | |
768 | error = ad1848_set_rec_port(ac, cp->un.ord); | | 768 | error = ad1848_set_rec_port(ac, cp->un.ord); |
769 | break; | | 769 | break; |
770 | | | 770 | |
771 | default: | | 771 | default: |
772 | printf ("Invalid kind\n"); | | 772 | printf ("Invalid kind\n"); |
773 | break; | | 773 | break; |
774 | } | | 774 | } |
775 | | | 775 | |
776 | return error; | | 776 | return error; |
777 | } | | 777 | } |
778 | | | 778 | |
779 | int | | 779 | int |
780 | ad1848_query_encoding(void *addr, struct audio_encoding *fp) | | 780 | ad1848_query_encoding(void *addr, struct audio_encoding *fp) |
781 | { | | 781 | { |
782 | struct ad1848_softc *sc; | | 782 | struct ad1848_softc *sc; |
783 | | | 783 | |
784 | sc = addr; | | 784 | sc = addr; |
785 | switch (fp->index) { | | 785 | switch (fp->index) { |
786 | case 0: | | 786 | case 0: |
787 | strcpy(fp->name, AudioEmulaw); | | 787 | strcpy(fp->name, AudioEmulaw); |
788 | fp->encoding = AUDIO_ENCODING_ULAW; | | 788 | fp->encoding = AUDIO_ENCODING_ULAW; |
789 | fp->precision = 8; | | 789 | fp->precision = 8; |
790 | fp->flags = 0; | | 790 | fp->flags = 0; |
791 | break; | | 791 | break; |
792 | case 1: | | 792 | case 1: |
793 | strcpy(fp->name, AudioEalaw); | | 793 | strcpy(fp->name, AudioEalaw); |
794 | fp->encoding = AUDIO_ENCODING_ALAW; | | 794 | fp->encoding = AUDIO_ENCODING_ALAW; |
795 | fp->precision = 8; | | 795 | fp->precision = 8; |
796 | fp->flags = 0; | | 796 | fp->flags = 0; |
797 | break; | | 797 | break; |
798 | case 2: | | 798 | case 2: |
799 | strcpy(fp->name, AudioEslinear_le); | | 799 | strcpy(fp->name, AudioEslinear_le); |
800 | fp->encoding = AUDIO_ENCODING_SLINEAR_LE; | | 800 | fp->encoding = AUDIO_ENCODING_SLINEAR_LE; |
801 | fp->precision = 16; | | 801 | fp->precision = 16; |
802 | fp->flags = 0; | | 802 | fp->flags = 0; |
803 | break; | | 803 | break; |
804 | case 3: | | 804 | case 3: |
805 | strcpy(fp->name, AudioEulinear); | | 805 | strcpy(fp->name, AudioEulinear); |
806 | fp->encoding = AUDIO_ENCODING_ULINEAR; | | 806 | fp->encoding = AUDIO_ENCODING_ULINEAR; |
807 | fp->precision = 8; | | 807 | fp->precision = 8; |
808 | fp->flags = 0; | | 808 | fp->flags = 0; |
809 | break; | | 809 | break; |
810 | | | 810 | |
811 | case 4: /* only on CS4231 */ | | 811 | case 4: /* only on CS4231 */ |
812 | strcpy(fp->name, AudioEslinear_be); | | 812 | strcpy(fp->name, AudioEslinear_be); |
813 | fp->encoding = AUDIO_ENCODING_SLINEAR_BE; | | 813 | fp->encoding = AUDIO_ENCODING_SLINEAR_BE; |
814 | fp->precision = 16; | | 814 | fp->precision = 16; |
815 | fp->flags = sc->mode == 1 | | 815 | fp->flags = sc->mode == 1 |
816 | #if AD1845_HACK | | 816 | #if AD1845_HACK |
817 | || sc->is_ad1845 | | 817 | || sc->is_ad1845 |
818 | #endif | | 818 | #endif |
819 | ? AUDIO_ENCODINGFLAG_EMULATED : 0; | | 819 | ? AUDIO_ENCODINGFLAG_EMULATED : 0; |
820 | break; | | 820 | break; |
821 | | | 821 | |
822 | /* emulate some modes */ | | 822 | /* emulate some modes */ |
823 | case 5: | | 823 | case 5: |
824 | strcpy(fp->name, AudioEslinear); | | 824 | strcpy(fp->name, AudioEslinear); |
825 | fp->encoding = AUDIO_ENCODING_SLINEAR; | | 825 | fp->encoding = AUDIO_ENCODING_SLINEAR; |
826 | fp->precision = 8; | | 826 | fp->precision = 8; |
827 | fp->flags = AUDIO_ENCODINGFLAG_EMULATED; | | 827 | fp->flags = AUDIO_ENCODINGFLAG_EMULATED; |
828 | break; | | 828 | break; |
829 | case 6: | | 829 | case 6: |
830 | strcpy(fp->name, AudioEulinear_le); | | 830 | strcpy(fp->name, AudioEulinear_le); |
831 | fp->encoding = AUDIO_ENCODING_ULINEAR_LE; | | 831 | fp->encoding = AUDIO_ENCODING_ULINEAR_LE; |
832 | fp->precision = 16; | | 832 | fp->precision = 16; |
833 | fp->flags = AUDIO_ENCODINGFLAG_EMULATED; | | 833 | fp->flags = AUDIO_ENCODINGFLAG_EMULATED; |
834 | break; | | 834 | break; |
835 | case 7: | | 835 | case 7: |
836 | strcpy(fp->name, AudioEulinear_be); | | 836 | strcpy(fp->name, AudioEulinear_be); |
837 | fp->encoding = AUDIO_ENCODING_ULINEAR_BE; | | 837 | fp->encoding = AUDIO_ENCODING_ULINEAR_BE; |
838 | fp->precision = 16; | | 838 | fp->precision = 16; |
839 | fp->flags = AUDIO_ENCODINGFLAG_EMULATED; | | 839 | fp->flags = AUDIO_ENCODINGFLAG_EMULATED; |
840 | break; | | 840 | break; |
841 | | | 841 | |
842 | case 8: /* only on CS4231 */ | | 842 | case 8: /* only on CS4231 */ |
843 | if (sc->mode == 1 || sc->is_ad1845) | | 843 | if (sc->mode == 1 || sc->is_ad1845) |
844 | return EINVAL; | | 844 | return EINVAL; |
845 | strcpy(fp->name, AudioEadpcm); | | 845 | strcpy(fp->name, AudioEadpcm); |
846 | fp->encoding = AUDIO_ENCODING_ADPCM; | | 846 | fp->encoding = AUDIO_ENCODING_ADPCM; |
847 | fp->precision = 4; | | 847 | fp->precision = 4; |
848 | fp->flags = 0; | | 848 | fp->flags = 0; |
849 | break; | | 849 | break; |
850 | default: | | 850 | default: |
851 | return EINVAL; | | 851 | return EINVAL; |
852 | /*NOTREACHED*/ | | 852 | /*NOTREACHED*/ |
853 | } | | 853 | } |
854 | return 0; | | 854 | return 0; |
855 | } | | 855 | } |
856 | | | 856 | |
857 | int | | 857 | int |
858 | ad1848_set_params(void *addr, int setmode, int usemode, | | 858 | ad1848_set_params(void *addr, int setmode, int usemode, |
859 | audio_params_t *p, audio_params_t *r, stream_filter_list_t *pfil, | | 859 | audio_params_t *p, audio_params_t *r, stream_filter_list_t *pfil, |
860 | stream_filter_list_t *rfil) | | 860 | stream_filter_list_t *rfil) |
861 | { | | 861 | { |
862 | audio_params_t phw, rhw; | | 862 | audio_params_t phw, rhw; |
863 | struct ad1848_softc *sc; | | 863 | struct ad1848_softc *sc; |
864 | int error, bits, enc; | | 864 | int error, bits, enc; |
865 | stream_filter_factory_t *pswcode; | | 865 | stream_filter_factory_t *pswcode; |
866 | stream_filter_factory_t *rswcode; | | 866 | stream_filter_factory_t *rswcode; |
867 | | | 867 | |
868 | DPRINTF(("ad1848_set_params: %u %u %u %u\n", | | 868 | DPRINTF(("ad1848_set_params: %u %u %u %u\n", |
869 | p->encoding, p->precision, p->channels, p->sample_rate)); | | 869 | p->encoding, p->precision, p->channels, p->sample_rate)); |
870 | | | 870 | |
871 | sc = addr; | | 871 | sc = addr; |
872 | enc = p->encoding; | | 872 | enc = p->encoding; |
873 | pswcode = rswcode = 0; | | 873 | pswcode = rswcode = 0; |
874 | phw = *p; | | 874 | phw = *p; |
875 | rhw = *r; | | 875 | rhw = *r; |
876 | switch (enc) { | | 876 | switch (enc) { |
877 | case AUDIO_ENCODING_SLINEAR_LE: | | 877 | case AUDIO_ENCODING_SLINEAR_LE: |
878 | if (p->precision == 8) { | | 878 | if (p->precision == 8) { |
879 | enc = AUDIO_ENCODING_ULINEAR_LE; | | 879 | enc = AUDIO_ENCODING_ULINEAR_LE; |
880 | phw.encoding = AUDIO_ENCODING_ULINEAR_LE; | | 880 | phw.encoding = AUDIO_ENCODING_ULINEAR_LE; |
881 | rhw.encoding = AUDIO_ENCODING_ULINEAR_LE; | | 881 | rhw.encoding = AUDIO_ENCODING_ULINEAR_LE; |
882 | pswcode = rswcode = change_sign8; | | 882 | pswcode = rswcode = change_sign8; |
883 | } | | 883 | } |
884 | break; | | 884 | break; |
885 | case AUDIO_ENCODING_SLINEAR_BE: | | 885 | case AUDIO_ENCODING_SLINEAR_BE: |
886 | if (p->precision == 16 && (sc->mode == 1 | | 886 | if (p->precision == 16 && (sc->mode == 1 |
887 | #if AD1845_HACK | | 887 | #if AD1845_HACK |
888 | || sc->is_ad1845 | | 888 | || sc->is_ad1845 |
889 | #endif | | 889 | #endif |
890 | )) { | | 890 | )) { |
891 | enc = AUDIO_ENCODING_SLINEAR_LE; | | 891 | enc = AUDIO_ENCODING_SLINEAR_LE; |
892 | phw.encoding = AUDIO_ENCODING_SLINEAR_LE; | | 892 | phw.encoding = AUDIO_ENCODING_SLINEAR_LE; |
893 | rhw.encoding = AUDIO_ENCODING_SLINEAR_LE; | | 893 | rhw.encoding = AUDIO_ENCODING_SLINEAR_LE; |
894 | pswcode = rswcode = swap_bytes; | | 894 | pswcode = rswcode = swap_bytes; |
895 | } | | 895 | } |
896 | break; | | 896 | break; |
897 | case AUDIO_ENCODING_ULINEAR_LE: | | 897 | case AUDIO_ENCODING_ULINEAR_LE: |
898 | if (p->precision == 16) { | | 898 | if (p->precision == 16) { |
899 | enc = AUDIO_ENCODING_SLINEAR_LE; | | 899 | enc = AUDIO_ENCODING_SLINEAR_LE; |
900 | phw.encoding = AUDIO_ENCODING_SLINEAR_LE; | | 900 | phw.encoding = AUDIO_ENCODING_SLINEAR_LE; |
901 | rhw.encoding = AUDIO_ENCODING_SLINEAR_LE; | | 901 | rhw.encoding = AUDIO_ENCODING_SLINEAR_LE; |
902 | pswcode = rswcode = change_sign16; | | 902 | pswcode = rswcode = change_sign16; |
903 | } | | 903 | } |
904 | break; | | 904 | break; |
905 | case AUDIO_ENCODING_ULINEAR_BE: | | 905 | case AUDIO_ENCODING_ULINEAR_BE: |
906 | if (p->precision == 16) { | | 906 | if (p->precision == 16) { |
907 | if (sc->mode == 1 | | 907 | if (sc->mode == 1 |
908 | #if AD1845_HACK | | 908 | #if AD1845_HACK |
909 | || sc->is_ad1845 | | 909 | || sc->is_ad1845 |
910 | #endif | | 910 | #endif |
911 | ) { | | 911 | ) { |
912 | enc = AUDIO_ENCODING_SLINEAR_LE; | | 912 | enc = AUDIO_ENCODING_SLINEAR_LE; |
913 | phw.encoding = AUDIO_ENCODING_SLINEAR_LE; | | 913 | phw.encoding = AUDIO_ENCODING_SLINEAR_LE; |
914 | rhw.encoding = AUDIO_ENCODING_SLINEAR_LE; | | 914 | rhw.encoding = AUDIO_ENCODING_SLINEAR_LE; |
915 | pswcode = swap_bytes_change_sign16; | | 915 | pswcode = swap_bytes_change_sign16; |
916 | rswcode = swap_bytes_change_sign16; | | 916 | rswcode = swap_bytes_change_sign16; |
917 | } else { | | 917 | } else { |
918 | enc = AUDIO_ENCODING_SLINEAR_BE; | | 918 | enc = AUDIO_ENCODING_SLINEAR_BE; |
919 | phw.encoding = AUDIO_ENCODING_SLINEAR_BE; | | 919 | phw.encoding = AUDIO_ENCODING_SLINEAR_BE; |
920 | rhw.encoding = AUDIO_ENCODING_SLINEAR_BE; | | 920 | rhw.encoding = AUDIO_ENCODING_SLINEAR_BE; |
921 | pswcode = rswcode = change_sign16; | | 921 | pswcode = rswcode = change_sign16; |
922 | } | | 922 | } |
923 | } | | 923 | } |
924 | break; | | 924 | break; |
925 | } | | 925 | } |
926 | switch (enc) { | | 926 | switch (enc) { |
927 | case AUDIO_ENCODING_ULAW: | | 927 | case AUDIO_ENCODING_ULAW: |
928 | bits = FMT_ULAW >> 5; | | 928 | bits = FMT_ULAW >> 5; |
929 | break; | | 929 | break; |
930 | case AUDIO_ENCODING_ALAW: | | 930 | case AUDIO_ENCODING_ALAW: |
931 | bits = FMT_ALAW >> 5; | | 931 | bits = FMT_ALAW >> 5; |
932 | break; | | 932 | break; |
933 | case AUDIO_ENCODING_ADPCM: | | 933 | case AUDIO_ENCODING_ADPCM: |
934 | bits = FMT_ADPCM >> 5; | | 934 | bits = FMT_ADPCM >> 5; |
935 | break; | | 935 | break; |
936 | case AUDIO_ENCODING_SLINEAR_LE: | | 936 | case AUDIO_ENCODING_SLINEAR_LE: |
937 | if (p->precision == 16) | | 937 | if (p->precision == 16) |
938 | bits = FMT_TWOS_COMP >> 5; | | 938 | bits = FMT_TWOS_COMP >> 5; |
939 | else | | 939 | else |
940 | return EINVAL; | | 940 | return EINVAL; |
941 | break; | | 941 | break; |
942 | case AUDIO_ENCODING_SLINEAR_BE: | | 942 | case AUDIO_ENCODING_SLINEAR_BE: |
943 | if (p->precision == 16) | | 943 | if (p->precision == 16) |
944 | bits = FMT_TWOS_COMP_BE >> 5; | | 944 | bits = FMT_TWOS_COMP_BE >> 5; |
945 | else | | 945 | else |
946 | return EINVAL; | | 946 | return EINVAL; |
947 | break; | | 947 | break; |
948 | case AUDIO_ENCODING_ULINEAR_LE: | | 948 | case AUDIO_ENCODING_ULINEAR_LE: |
949 | if (p->precision == 8) | | 949 | if (p->precision == 8) |
950 | bits = FMT_PCM8 >> 5; | | 950 | bits = FMT_PCM8 >> 5; |
951 | else | | 951 | else |
952 | return EINVAL; | | 952 | return EINVAL; |
953 | break; | | 953 | break; |
954 | default: | | 954 | default: |
955 | return EINVAL; | | 955 | return EINVAL; |
956 | } | | 956 | } |
957 | | | 957 | |
958 | if (p->channels < 1 || p->channels > 2) | | 958 | if (p->channels < 1 || p->channels > 2) |
959 | return EINVAL; | | 959 | return EINVAL; |
960 | | | 960 | |
961 | error = ad1848_set_speed(sc, &p->sample_rate); | | 961 | error = ad1848_set_speed(sc, &p->sample_rate); |
962 | if (error) | | 962 | if (error) |
963 | return error; | | 963 | return error; |
964 | phw.sample_rate = p->sample_rate; | | 964 | phw.sample_rate = p->sample_rate; |
965 | | | 965 | |
966 | if (pswcode != NULL) | | 966 | if (pswcode != NULL) |
967 | pfil->append(pfil, pswcode, &phw); | | 967 | pfil->append(pfil, pswcode, &phw); |
968 | if (rswcode != NULL) | | 968 | if (rswcode != NULL) |
969 | rfil->append(rfil, rswcode, &rhw); | | 969 | rfil->append(rfil, rswcode, &rhw); |
970 | | | 970 | |
971 | sc->format_bits = bits; | | 971 | sc->format_bits = bits; |
972 | sc->channels = p->channels; | | 972 | sc->channels = p->channels; |
973 | sc->precision = p->precision; | | 973 | sc->precision = p->precision; |
974 | sc->need_commit = 1; | | 974 | sc->need_commit = 1; |
975 | | | 975 | |
976 | DPRINTF(("ad1848_set_params succeeded, bits=%x\n", bits)); | | 976 | DPRINTF(("ad1848_set_params succeeded, bits=%x\n", bits)); |
977 | return 0; | | 977 | return 0; |
978 | } | | 978 | } |
979 | | | 979 | |
980 | int | | 980 | int |
981 | ad1848_set_rec_port(struct ad1848_softc *sc, int port) | | 981 | ad1848_set_rec_port(struct ad1848_softc *sc, int port) |
982 | { | | 982 | { |
983 | u_char inp, reg; | | 983 | u_char inp, reg; |
984 | | | 984 | |
985 | DPRINTF(("ad1848_set_rec_port: 0x%x\n", port)); | | 985 | DPRINTF(("ad1848_set_rec_port: 0x%x\n", port)); |
986 | | | 986 | |
987 | if (port == MIC_IN_PORT) | | 987 | if (port == MIC_IN_PORT) |
988 | inp = MIC_INPUT; | | 988 | inp = MIC_INPUT; |
989 | else if (port == LINE_IN_PORT) | | 989 | else if (port == LINE_IN_PORT) |
990 | inp = LINE_INPUT; | | 990 | inp = LINE_INPUT; |
991 | else if (port == DAC_IN_PORT) | | 991 | else if (port == DAC_IN_PORT) |
992 | inp = MIXED_DAC_INPUT; | | 992 | inp = MIXED_DAC_INPUT; |
993 | else if (sc->mode >= 2 && port == AUX1_IN_PORT) | | 993 | else if (sc->mode >= 2 && port == AUX1_IN_PORT) |
994 | inp = AUX_INPUT; | | 994 | inp = AUX_INPUT; |
995 | else | | 995 | else |
996 | return EINVAL; | | 996 | return EINVAL; |
997 | | | 997 | |
998 | reg = ad_read(sc, SP_LEFT_INPUT_CONTROL); | | 998 | reg = ad_read(sc, SP_LEFT_INPUT_CONTROL); |
999 | reg &= INPUT_SOURCE_MASK; | | 999 | reg &= INPUT_SOURCE_MASK; |
1000 | ad_write(sc, SP_LEFT_INPUT_CONTROL, (inp|reg)); | | 1000 | ad_write(sc, SP_LEFT_INPUT_CONTROL, (inp|reg)); |
1001 | | | 1001 | |
1002 | reg = ad_read(sc, SP_RIGHT_INPUT_CONTROL); | | 1002 | reg = ad_read(sc, SP_RIGHT_INPUT_CONTROL); |
1003 | reg &= INPUT_SOURCE_MASK; | | 1003 | reg &= INPUT_SOURCE_MASK; |
1004 | ad_write(sc, SP_RIGHT_INPUT_CONTROL, (inp|reg)); | | 1004 | ad_write(sc, SP_RIGHT_INPUT_CONTROL, (inp|reg)); |
1005 | | | 1005 | |
1006 | sc->rec_port = port; | | 1006 | sc->rec_port = port; |
1007 | | | 1007 | |
1008 | return 0; | | 1008 | return 0; |
1009 | } | | 1009 | } |
1010 | | | 1010 | |
1011 | int | | 1011 | int |
1012 | ad1848_get_rec_port(struct ad1848_softc *sc) | | 1012 | ad1848_get_rec_port(struct ad1848_softc *sc) |
1013 | { | | 1013 | { |
1014 | return sc->rec_port; | | 1014 | return sc->rec_port; |
1015 | } | | 1015 | } |
1016 | | | 1016 | |
1017 | int | | 1017 | int |
1018 | ad1848_round_blocksize(void *addr, int blk, | | 1018 | ad1848_round_blocksize(void *addr, int blk, |
1019 | int mode, const audio_params_t *param) | | 1019 | int mode, const audio_params_t *param) |
1020 | { | | 1020 | { |
1021 | | | 1021 | |
1022 | /* Round to a multiple of the biggest sample size. */ | | 1022 | /* Round to a multiple of the biggest sample size. */ |
1023 | return blk &= -4; | | 1023 | return blk &= -4; |
1024 | } | | 1024 | } |
1025 | | | 1025 | |
1026 | int | | 1026 | int |
1027 | ad1848_open(void *addr, int flags) | | 1027 | ad1848_open(void *addr, int flags) |
1028 | { | | 1028 | { |
1029 | struct ad1848_softc *sc; | | 1029 | struct ad1848_softc *sc; |
1030 | u_char reg; | | 1030 | u_char reg; |
1031 | | | 1031 | |
1032 | sc = addr; | | 1032 | sc = addr; |
1033 | DPRINTF(("ad1848_open: sc=%p\n", sc)); | | 1033 | DPRINTF(("ad1848_open: sc=%p\n", sc)); |
1034 | | | 1034 | |
1035 | sc->open_mode = flags; | | 1035 | sc->open_mode = flags; |
1036 | | | 1036 | |
1037 | /* Enable interrupts */ | | 1037 | /* Enable interrupts */ |
1038 | DPRINTF(("ad1848_open: enable intrs\n")); | | 1038 | DPRINTF(("ad1848_open: enable intrs\n")); |
1039 | reg = ad_read(sc, SP_PIN_CONTROL); | | 1039 | reg = ad_read(sc, SP_PIN_CONTROL); |
1040 | ad_write(sc, SP_PIN_CONTROL, reg | INTERRUPT_ENABLE); | | 1040 | ad_write(sc, SP_PIN_CONTROL, reg | INTERRUPT_ENABLE); |
1041 | | | 1041 | |
1042 | /* If recording && monitoring, the playback part is also used. */ | | 1042 | /* If recording && monitoring, the playback part is also used. */ |
1043 | if (flags & FREAD && sc->mute[AD1848_MONITOR_CHANNEL] == 0) | | 1043 | if (flags & FREAD && sc->mute[AD1848_MONITOR_CHANNEL] == 0) |
1044 | ad1848_mute_wave_output(sc, WAVE_UNMUTE1, 1); | | 1044 | ad1848_mute_wave_output(sc, WAVE_UNMUTE1, 1); |
1045 | | | 1045 | |
1046 | #ifdef AUDIO_DEBUG | | 1046 | #ifdef AUDIO_DEBUG |
1047 | if (ad1848debug) | | 1047 | if (ad1848debug) |
1048 | ad1848_dump_regs(sc); | | 1048 | ad1848_dump_regs(sc); |
1049 | #endif | | 1049 | #endif |
1050 | | | 1050 | |
1051 | return 0; | | 1051 | return 0; |
1052 | } | | 1052 | } |
1053 | | | 1053 | |
1054 | /* | | 1054 | /* |
1055 | * Close function is called at splaudio(). | | 1055 | * Close function is called at splaudio(). |
1056 | */ | | 1056 | */ |
1057 | void | | 1057 | void |
1058 | ad1848_close(void *addr) | | 1058 | ad1848_close(void *addr) |
1059 | { | | 1059 | { |
1060 | struct ad1848_softc *sc; | | 1060 | struct ad1848_softc *sc; |
1061 | u_char reg; | | 1061 | u_char reg; |
1062 | | | 1062 | |
1063 | sc = addr; | | 1063 | sc = addr; |
1064 | sc->open_mode = 0; | | 1064 | sc->open_mode = 0; |
1065 | | | 1065 | |
1066 | ad1848_mute_wave_output(sc, WAVE_UNMUTE1, 0); | | 1066 | ad1848_mute_wave_output(sc, WAVE_UNMUTE1, 0); |
1067 | | | 1067 | |
1068 | /* Disable interrupts */ | | 1068 | /* Disable interrupts */ |
1069 | DPRINTF(("ad1848_close: disable intrs\n")); | | 1069 | DPRINTF(("ad1848_close: disable intrs\n")); |
1070 | reg = ad_read(sc, SP_PIN_CONTROL); | | 1070 | reg = ad_read(sc, SP_PIN_CONTROL); |
1071 | ad_write(sc, SP_PIN_CONTROL, reg & ~INTERRUPT_ENABLE); | | 1071 | ad_write(sc, SP_PIN_CONTROL, reg & ~INTERRUPT_ENABLE); |
1072 | | | 1072 | |
1073 | #ifdef AUDIO_DEBUG | | 1073 | #ifdef AUDIO_DEBUG |
1074 | if (ad1848debug) | | 1074 | if (ad1848debug) |
1075 | ad1848_dump_regs(sc); | | 1075 | ad1848_dump_regs(sc); |
1076 | #endif | | 1076 | #endif |
1077 | } | | 1077 | } |
1078 | | | 1078 | |
1079 | /* | | 1079 | /* |
1080 | * Lower-level routines | | 1080 | * Lower-level routines |
1081 | */ | | 1081 | */ |
1082 | int | | 1082 | int |
1083 | ad1848_commit_settings(void *addr) | | 1083 | ad1848_commit_settings(void *addr) |
1084 | { | | 1084 | { |
1085 | struct ad1848_softc *sc; | | 1085 | struct ad1848_softc *sc; |
1086 | int timeout; | | 1086 | int timeout; |
1087 | u_char fs; | | 1087 | u_char fs; |
1088 | int s; | | 1088 | int s; |
1089 | | | 1089 | |
1090 | sc = addr; | | 1090 | sc = addr; |
1091 | if (!sc->need_commit) | | 1091 | if (!sc->need_commit) |
1092 | return 0; | | 1092 | return 0; |
1093 | | | 1093 | |
1094 | s = splaudio(); | | 1094 | s = splaudio(); |
1095 | | | 1095 | |
1096 | ad1848_mute_wave_output(sc, WAVE_MUTE0, 1); | | 1096 | ad1848_mute_wave_output(sc, WAVE_MUTE0, 1); |
1097 | | | 1097 | |
1098 | ad_set_MCE(sc, 1); /* Enables changes to the format select reg */ | | 1098 | ad_set_MCE(sc, 1); /* Enables changes to the format select reg */ |
1099 | | | 1099 | |
1100 | fs = sc->speed_bits | (sc->format_bits << 5); | | 1100 | fs = sc->speed_bits | (sc->format_bits << 5); |
1101 | | | 1101 | |
1102 | if (sc->channels == 2) | | 1102 | if (sc->channels == 2) |
1103 | fs |= FMT_STEREO; | | 1103 | fs |= FMT_STEREO; |
1104 | | | 1104 | |
1105 | /* | | 1105 | /* |
1106 | * OPL3-SA2 (YMF711) is sometimes busy here. | | 1106 | * OPL3-SA2 (YMF711) is sometimes busy here. |
1107 | * Wait until it becomes ready. | | 1107 | * Wait until it becomes ready. |
1108 | */ | | 1108 | */ |
1109 | for (timeout = 0; | | 1109 | for (timeout = 0; |
1110 | timeout < 1000 && ADREAD(sc, AD1848_IADDR) & SP_IN_INIT; timeout++) | | 1110 | timeout < 1000 && ADREAD(sc, AD1848_IADDR) & SP_IN_INIT; timeout++) |
1111 | delay(10); | | 1111 | delay(10); |
1112 | | | 1112 | |
1113 | ad_write(sc, SP_CLOCK_DATA_FORMAT, fs); | | 1113 | ad_write(sc, SP_CLOCK_DATA_FORMAT, fs); |
1114 | | | 1114 | |
1115 | /* | | 1115 | /* |
1116 | * If mode >= 2 (CS4231), set I28 also. | | 1116 | * If mode >= 2 (CS4231), set I28 also. |
1117 | * It's the capture format register. | | 1117 | * It's the capture format register. |
1118 | */ | | 1118 | */ |
1119 | if (sc->mode >= 2) { | | 1119 | if (sc->mode >= 2) { |
1120 | /* | | 1120 | /* |
1121 | * Gravis Ultrasound MAX SDK sources says something about | | 1121 | * Gravis Ultrasound MAX SDK sources says something about |
1122 | * errata sheets, with the implication that these inb()s | | 1122 | * errata sheets, with the implication that these inb()s |
1123 | * are necessary. | | 1123 | * are necessary. |
1124 | */ | | 1124 | */ |
1125 | (void)ADREAD(sc, AD1848_IDATA); | | 1125 | (void)ADREAD(sc, AD1848_IDATA); |
1126 | (void)ADREAD(sc, AD1848_IDATA); | | 1126 | (void)ADREAD(sc, AD1848_IDATA); |
1127 | /* Write to I8 starts resynchronization. Wait for completion. */ | | 1127 | /* Write to I8 starts resynchronization. Wait for completion. */ |
1128 | timeout = 100000; | | 1128 | timeout = 100000; |
1129 | while (timeout > 0 && ADREAD(sc, AD1848_IADDR) == SP_IN_INIT) | | 1129 | while (timeout > 0 && ADREAD(sc, AD1848_IADDR) == SP_IN_INIT) |
1130 | timeout--; | | 1130 | timeout--; |
1131 | | | 1131 | |
1132 | ad_write(sc, CS_REC_FORMAT, fs); | | 1132 | ad_write(sc, CS_REC_FORMAT, fs); |
1133 | (void)ADREAD(sc, AD1848_IDATA); | | 1133 | (void)ADREAD(sc, AD1848_IDATA); |
1134 | (void)ADREAD(sc, AD1848_IDATA); | | 1134 | (void)ADREAD(sc, AD1848_IDATA); |
1135 | /* Now wait for resync for capture side of the house */ | | 1135 | /* Now wait for resync for capture side of the house */ |
1136 | } | | 1136 | } |
1137 | /* | | 1137 | /* |
1138 | * Write to I8 starts resynchronization. Wait until it completes. | | 1138 | * Write to I8 starts resynchronization. Wait until it completes. |
1139 | */ | | 1139 | */ |
1140 | timeout = 100000; | | 1140 | timeout = 100000; |
1141 | while (timeout > 0 && ADREAD(sc, AD1848_IADDR) == SP_IN_INIT) { | | 1141 | while (timeout > 0 && ADREAD(sc, AD1848_IADDR) == SP_IN_INIT) { |
1142 | delay(10); | | 1142 | delay(10); |
1143 | timeout--; | | 1143 | timeout--; |
1144 | } | | 1144 | } |
1145 | | | 1145 | |
1146 | if (ADREAD(sc, AD1848_IADDR) == SP_IN_INIT) | | 1146 | if (ADREAD(sc, AD1848_IADDR) == SP_IN_INIT) |
1147 | printf("ad1848_commit: Auto calibration timed out\n"); | | 1147 | printf("ad1848_commit: Auto calibration timed out\n"); |
1148 | | | 1148 | |
1149 | /* | | 1149 | /* |
1150 | * Starts the calibration process and | | 1150 | * Starts the calibration process and |
1151 | * enters playback mode after it. | | 1151 | * enters playback mode after it. |
1152 | */ | | 1152 | */ |
1153 | ad_set_MCE(sc, 0); | | 1153 | ad_set_MCE(sc, 0); |
1154 | wait_for_calibration(sc); | | 1154 | wait_for_calibration(sc); |
1155 | | | 1155 | |
1156 | ad1848_mute_wave_output(sc, WAVE_MUTE0, 0); | | 1156 | ad1848_mute_wave_output(sc, WAVE_MUTE0, 0); |
1157 | | | 1157 | |
1158 | splx(s); | | 1158 | splx(s); |
1159 | | | 1159 | |
1160 | sc->need_commit = 0; | | 1160 | sc->need_commit = 0; |
1161 | return 0; | | 1161 | return 0; |
1162 | } | | 1162 | } |
1163 | | | 1163 | |
1164 | void | | 1164 | void |
1165 | ad1848_reset(struct ad1848_softc *sc) | | 1165 | ad1848_reset(struct ad1848_softc *sc) |
1166 | { | | 1166 | { |
1167 | u_char r; | | 1167 | u_char r; |
1168 | | | 1168 | |
1169 | DPRINTF(("ad1848_reset\n")); | | 1169 | DPRINTF(("ad1848_reset\n")); |
1170 | | | 1170 | |
1171 | /* Clear the PEN and CEN bits */ | | 1171 | /* Clear the PEN and CEN bits */ |
1172 | r = ad_read(sc, SP_INTERFACE_CONFIG); | | 1172 | r = ad_read(sc, SP_INTERFACE_CONFIG); |
1173 | r &= ~(CAPTURE_ENABLE | PLAYBACK_ENABLE); | | 1173 | r &= ~(CAPTURE_ENABLE | PLAYBACK_ENABLE); |
1174 | ad_write(sc, SP_INTERFACE_CONFIG, r); | | 1174 | ad_write(sc, SP_INTERFACE_CONFIG, r); |
1175 | | | 1175 | |
1176 | if (sc->mode >= 2) { | | 1176 | if (sc->mode >= 2) { |
1177 | ADWRITE(sc, AD1848_IADDR, CS_IRQ_STATUS); | | 1177 | ADWRITE(sc, AD1848_IADDR, CS_IRQ_STATUS); |
1178 | ADWRITE(sc, AD1848_IDATA, 0); | | 1178 | ADWRITE(sc, AD1848_IDATA, 0); |
1179 | } | | 1179 | } |
1180 | /* Clear interrupt status */ | | 1180 | /* Clear interrupt status */ |
1181 | ADWRITE(sc, AD1848_STATUS, 0); | | 1181 | ADWRITE(sc, AD1848_STATUS, 0); |
1182 | #ifdef AUDIO_DEBUG | | 1182 | #ifdef AUDIO_DEBUG |
1183 | if (ad1848debug) | | 1183 | if (ad1848debug) |
1184 | ad1848_dump_regs(sc); | | 1184 | ad1848_dump_regs(sc); |
1185 | #endif | | 1185 | #endif |
1186 | } | | 1186 | } |
1187 | | | 1187 | |
1188 | int | | 1188 | int |
1189 | ad1848_set_speed(struct ad1848_softc *sc, u_int *argp) | | 1189 | ad1848_set_speed(struct ad1848_softc *sc, u_int *argp) |
1190 | { | | 1190 | { |
1191 | /* | | 1191 | /* |
1192 | * The sampling speed is encoded in the least significant nible of I8. | | 1192 | * The sampling speed is encoded in the least significant nible of I8. |
1193 | * The LSB selects the clock source (0=24.576 MHz, 1=16.9344 MHz) and | | 1193 | * The LSB selects the clock source (0=24.576 MHz, 1=16.9344 MHz) and |
1194 | * other three bits select the divisor (indirectly): | | 1194 | * other three bits select the divisor (indirectly): |
1195 | * | | 1195 | * |
1196 | * The available speeds are in the following table. Keep the speeds in | | 1196 | * The available speeds are in the following table. Keep the speeds in |
1197 | * the increasing order. | | 1197 | * the increasing order. |
1198 | */ | | 1198 | */ |
1199 | typedef struct { | | 1199 | typedef struct { |
1200 | int speed; | | 1200 | int speed; |
1201 | u_char bits; | | 1201 | u_char bits; |
1202 | } speed_struct; | | 1202 | } speed_struct; |
1203 | u_long arg; | | 1203 | u_long arg; |
1204 | | | 1204 | |
1205 | static const speed_struct speed_table[] = { | | 1205 | static const speed_struct speed_table[] = { |
1206 | {5510, (0 << 1) | 1}, | | 1206 | {5510, (0 << 1) | 1}, |
1207 | {5510, (0 << 1) | 1}, | | 1207 | {5510, (0 << 1) | 1}, |
1208 | {6620, (7 << 1) | 1}, | | 1208 | {6620, (7 << 1) | 1}, |
1209 | {8000, (0 << 1) | 0}, | | 1209 | {8000, (0 << 1) | 0}, |
1210 | {9600, (7 << 1) | 0}, | | 1210 | {9600, (7 << 1) | 0}, |
1211 | {11025, (1 << 1) | 1}, | | 1211 | {11025, (1 << 1) | 1}, |
1212 | {16000, (1 << 1) | 0}, | | 1212 | {16000, (1 << 1) | 0}, |
1213 | {18900, (2 << 1) | 1}, | | 1213 | {18900, (2 << 1) | 1}, |
1214 | {22050, (3 << 1) | 1}, | | 1214 | {22050, (3 << 1) | 1}, |
1215 | {27420, (2 << 1) | 0}, | | 1215 | {27420, (2 << 1) | 0}, |
1216 | {32000, (3 << 1) | 0}, | | 1216 | {32000, (3 << 1) | 0}, |
1217 | {33075, (6 << 1) | 1}, | | 1217 | {33075, (6 << 1) | 1}, |
1218 | {37800, (4 << 1) | 1}, | | 1218 | {37800, (4 << 1) | 1}, |
1219 | {44100, (5 << 1) | 1}, | | 1219 | {44100, (5 << 1) | 1}, |
1220 | {48000, (6 << 1) | 0} | | 1220 | {48000, (6 << 1) | 0} |
1221 | }; | | 1221 | }; |
1222 | | | 1222 | |
1223 | int i, n, selected; | | 1223 | int i, n, selected; |
1224 | | | 1224 | |
1225 | arg = *argp; | | 1225 | arg = *argp; |
1226 | selected = -1; | | 1226 | selected = -1; |
1227 | n = sizeof(speed_table) / sizeof(speed_struct); | | 1227 | n = sizeof(speed_table) / sizeof(speed_struct); |
1228 | | | 1228 | |
1229 | if (arg < speed_table[0].speed) | | 1229 | if (arg < speed_table[0].speed) |
1230 | selected = 0; | | 1230 | selected = 0; |
1231 | if (arg > speed_table[n - 1].speed) | | 1231 | if (arg > speed_table[n - 1].speed) |
1232 | selected = n - 1; | | 1232 | selected = n - 1; |
1233 | | | 1233 | |
1234 | for (i = 1 /*really*/ ; selected == -1 && i < n; i++) | | 1234 | for (i = 1 /*really*/ ; selected == -1 && i < n; i++) |
1235 | if (speed_table[i].speed == arg) | | 1235 | if (speed_table[i].speed == arg) |
1236 | selected = i; | | 1236 | selected = i; |
1237 | else if (speed_table[i].speed > arg) { | | 1237 | else if (speed_table[i].speed > arg) { |
1238 | int diff1, diff2; | | 1238 | int diff1, diff2; |
1239 | | | 1239 | |
1240 | diff1 = arg - speed_table[i - 1].speed; | | 1240 | diff1 = arg - speed_table[i - 1].speed; |
1241 | diff2 = speed_table[i].speed - arg; | | 1241 | diff2 = speed_table[i].speed - arg; |
1242 | | | 1242 | |
1243 | if (diff1 < diff2) | | 1243 | if (diff1 < diff2) |
1244 | selected = i - 1; | | 1244 | selected = i - 1; |
1245 | else | | 1245 | else |
1246 | selected = i; | | 1246 | selected = i; |
1247 | } | | 1247 | } |
1248 | | | 1248 | |
1249 | if (selected == -1) { | | 1249 | if (selected == -1) { |
1250 | printf("ad1848: Can't find speed???\n"); | | 1250 | printf("ad1848: Can't find speed???\n"); |
1251 | selected = 3; | | 1251 | selected = 3; |
1252 | } | | 1252 | } |
1253 | | | 1253 | |
1254 | sc->speed_bits = speed_table[selected].bits; | | 1254 | sc->speed_bits = speed_table[selected].bits; |
1255 | sc->need_commit = 1; | | 1255 | sc->need_commit = 1; |