ac97.c revision 1.83 1 /* $NetBSD: ac97.c,v 1.83 2006/08/23 11:24:07 kent Exp $ */
2 /* $OpenBSD: ac97.c,v 1.8 2000/07/19 09:01:35 csapuntz Exp $ */
3
4 /*
5 * Copyright (c) 1999, 2000 Constantine Sapuntzakis
6 *
7 * Author: Constantine Sapuntzakis <csapuntz (at) stanford.edu>
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote
18 * products derived from this software without specific prior written
19 * permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
21 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
30 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 * DAMAGE
32 */
33
34 /* Partially inspired by FreeBSD's sys/dev/pcm/ac97.c. It came with
35 the following copyright */
36
37 /*
38 * Copyright (c) 1999 Cameron Grant <gandalf (at) vilnya.demon.co.uk>
39 * All rights reserved.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * SUCH DAMAGE.
61 *
62 * $FreeBSD$
63 */
64
65 #include <sys/cdefs.h>
66 __KERNEL_RCSID(0, "$NetBSD: ac97.c,v 1.83 2006/08/23 11:24:07 kent Exp $");
67
68 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/kernel.h>
71 #include <sys/malloc.h>
72 #include <sys/device.h>
73 #include <sys/sysctl.h>
74
75 #include <sys/audioio.h>
76 #include <dev/audio_if.h>
77
78 #include <dev/ic/ac97reg.h>
79 #include <dev/ic/ac97var.h>
80
81 struct ac97_softc;
82 struct ac97_source_info;
83 static int ac97_mixer_get_port(struct ac97_codec_if *, mixer_ctrl_t *);
84 static int ac97_mixer_set_port(struct ac97_codec_if *, mixer_ctrl_t *);
85 static void ac97_detach(struct ac97_codec_if *);
86 static void ac97_lock(struct ac97_codec_if *);
87 static void ac97_unlock(struct ac97_codec_if *);
88 static int ac97_query_devinfo(struct ac97_codec_if *, mixer_devinfo_t *);
89 static int ac97_get_portnum_by_name(struct ac97_codec_if *, const char *,
90 const char *, const char *);
91 static void ac97_restore_shadow(struct ac97_codec_if *);
92 static int ac97_set_rate(struct ac97_codec_if *, int, u_int *);
93 static void ac97_set_clock(struct ac97_codec_if *, unsigned int);
94 static uint16_t ac97_get_extcaps(struct ac97_codec_if *);
95 static int ac97_add_port(struct ac97_softc *,
96 const struct ac97_source_info *);
97 static int ac97_str_equal(const char *, const char *);
98 static int ac97_check_capability(struct ac97_softc *, int);
99 static void ac97_setup_source_info(struct ac97_softc *);
100 static void ac97_read(struct ac97_softc *, uint8_t, uint16_t *);
101 static void ac97_setup_defaults(struct ac97_softc *);
102 static int ac97_write(struct ac97_softc *, uint8_t, uint16_t);
103
104 static void ac97_ad198x_init(struct ac97_softc *);
105 static void ac97_alc650_init(struct ac97_softc *);
106 static void ac97_vt1616_init(struct ac97_softc *);
107
108 static int ac97_modem_offhook_set(struct ac97_softc *, int, int);
109 static int ac97_sysctl_verify(SYSCTLFN_ARGS);
110
111 #define Ac97Nphone "phone"
112 #define Ac97Nline1 "line1"
113 #define Ac97Nline2 "line2"
114 #define Ac97Nhandset "handset"
115
116 static const struct audio_mixer_enum
117 ac97_on_off = { 2, { { { AudioNoff } , 0 },
118 { { AudioNon } , 1 } } };
119
120 static const struct audio_mixer_enum
121 ac97_mic_select = { 2, { { { AudioNmicrophone "0" }, 0 },
122 { { AudioNmicrophone "1" }, 1 } } };
123
124 static const struct audio_mixer_enum
125 ac97_mono_select = { 2, { { { AudioNmixerout }, 0 },
126 { { AudioNmicrophone }, 1 } } };
127
128 static const struct audio_mixer_enum
129 ac97_source = { 8, { { { AudioNmicrophone } , 0 },
130 { { AudioNcd }, 1 },
131 { { AudioNvideo }, 2 },
132 { { AudioNaux }, 3 },
133 { { AudioNline }, 4 },
134 { { AudioNmixerout }, 5 },
135 { { AudioNmixerout AudioNmono }, 6 },
136 { { Ac97Nphone }, 7 } } };
137
138 /*
139 * Due to different values for each source that uses these structures,
140 * the ac97_query_devinfo function sets delta in mixer_devinfo_t using
141 * ac97_source_info.bits.
142 */
143 static const struct audio_mixer_value
144 ac97_volume_stereo = { { AudioNvolume }, 2 };
145
146 static const struct audio_mixer_value
147 ac97_volume_mono = { { AudioNvolume }, 1 };
148
149 #define WRAP(a) &a, sizeof(a)
150
151 struct ac97_source_info {
152 const char *class;
153 const char *device;
154 const char *qualifier;
155
156 int type;
157 const void *info;
158 int info_size;
159
160 uint8_t reg;
161 int32_t default_value;
162 unsigned bits:3;
163 unsigned ofs:4;
164 unsigned mute:1;
165 unsigned polarity:1; /* Does 0 == MAX or MIN */
166 unsigned checkbits:1;
167 enum {
168 CHECK_NONE = 0,
169 CHECK_SURROUND,
170 CHECK_CENTER,
171 CHECK_LFE,
172 CHECK_HEADPHONES,
173 CHECK_TONE,
174 CHECK_MIC,
175 CHECK_LOUDNESS,
176 CHECK_3D,
177 CHECK_LINE1,
178 CHECK_LINE2,
179 CHECK_HANDSET,
180 CHECK_SPDIF
181 } req_feature;
182
183 int prev;
184 int next;
185 int mixer_class;
186 };
187
188 static const struct ac97_source_info audio_source_info[] = {
189 { AudioCinputs, NULL, NULL,
190 AUDIO_MIXER_CLASS, },
191 { AudioCoutputs, NULL, NULL,
192 AUDIO_MIXER_CLASS, },
193 { AudioCrecord, NULL, NULL,
194 AUDIO_MIXER_CLASS, },
195 /* Stereo master volume*/
196 { AudioCoutputs, AudioNmaster, NULL,
197 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
198 AC97_REG_MASTER_VOLUME, 0x8000, 5, 0, 1, 0, 1
199 },
200 /* Mono volume */
201 { AudioCoutputs, AudioNmono, NULL,
202 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
203 AC97_REG_MASTER_VOLUME_MONO, 0x8000, 6, 0, 1, 0, 1
204 },
205 { AudioCoutputs, AudioNmono, AudioNsource,
206 AUDIO_MIXER_ENUM, WRAP(ac97_mono_select),
207 AC97_REG_GP, 0x0000, 1, 9, 0, 0, 0
208 },
209 /* Headphone volume */
210 { AudioCoutputs, AudioNheadphone, NULL,
211 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
212 AC97_REG_HEADPHONE_VOLUME, 0x8000, 5, 0, 1, 0, 1, CHECK_HEADPHONES
213 },
214 /* Surround volume - logic hard coded for mute */
215 { AudioCoutputs, AudioNsurround, NULL,
216 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
217 AC97_REG_SURR_MASTER, 0x8080, 5, 0, 1, 0, 1, CHECK_SURROUND
218 },
219 /* Center volume*/
220 { AudioCoutputs, AudioNcenter, NULL,
221 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
222 AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 0, 0, 0, 1, CHECK_CENTER
223 },
224 { AudioCoutputs, AudioNcenter, AudioNmute,
225 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
226 AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 7, 0, 0, 0, CHECK_CENTER
227 },
228 /* LFE volume*/
229 { AudioCoutputs, AudioNlfe, NULL,
230 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
231 AC97_REG_CENTER_LFE_MASTER, 0x8080, 5, 8, 0, 0, 1, CHECK_LFE
232 },
233 { AudioCoutputs, AudioNlfe, AudioNmute,
234 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
235 AC97_REG_CENTER_LFE_MASTER, 0x8080, 1, 15, 0, 0, 0, CHECK_LFE
236 },
237 /* Tone - bass */
238 { AudioCoutputs, AudioNbass, NULL,
239 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
240 AC97_REG_MASTER_TONE, 0x0f0f, 4, 8, 0, 0, 0, CHECK_TONE
241 },
242 /* Tone - treble */
243 { AudioCoutputs, AudioNtreble, NULL,
244 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
245 AC97_REG_MASTER_TONE, 0x0f0f, 4, 0, 0, 0, 0, CHECK_TONE
246 },
247 /* PC Beep Volume */
248 { AudioCinputs, AudioNspeaker, NULL,
249 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
250 AC97_REG_PCBEEP_VOLUME, 0x0000, 4, 1, 1, 0, 0
251 },
252
253 /* Phone */
254 { AudioCinputs, Ac97Nphone, NULL,
255 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
256 AC97_REG_PHONE_VOLUME, 0x8008, 5, 0, 1, 0, 0
257 },
258 /* Mic Volume */
259 { AudioCinputs, AudioNmicrophone, NULL,
260 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
261 AC97_REG_MIC_VOLUME, 0x8008, 5, 0, 1, 0, 0
262 },
263 { AudioCinputs, AudioNmicrophone, AudioNpreamp,
264 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
265 AC97_REG_MIC_VOLUME, 0x8008, 1, 6, 0, 0, 0
266 },
267 { AudioCinputs, AudioNmicrophone, AudioNsource,
268 AUDIO_MIXER_ENUM, WRAP(ac97_mic_select),
269 AC97_REG_GP, 0x0000, 1, 8, 0, 0, 0
270 },
271 /* Line in Volume */
272 { AudioCinputs, AudioNline, NULL,
273 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
274 AC97_REG_LINEIN_VOLUME, 0x8808, 5, 0, 1, 0, 0
275 },
276 /* CD Volume */
277 { AudioCinputs, AudioNcd, NULL,
278 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
279 AC97_REG_CD_VOLUME, 0x8808, 5, 0, 1, 0, 0
280 },
281 /* Video Volume */
282 { AudioCinputs, AudioNvideo, NULL,
283 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
284 AC97_REG_VIDEO_VOLUME, 0x8808, 5, 0, 1, 0, 0
285 },
286 /* AUX volume */
287 { AudioCinputs, AudioNaux, NULL,
288 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
289 AC97_REG_AUX_VOLUME, 0x8808, 5, 0, 1, 0, 0
290 },
291 /* PCM out volume */
292 { AudioCinputs, AudioNdac, NULL,
293 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
294 AC97_REG_PCMOUT_VOLUME, 0x8808, 5, 0, 1, 0, 0
295 },
296 /* Record Source - some logic for this is hard coded - see below */
297 { AudioCrecord, AudioNsource, NULL,
298 AUDIO_MIXER_ENUM, WRAP(ac97_source),
299 AC97_REG_RECORD_SELECT, 0x0000, 3, 0, 0, 0, 0
300 },
301 /* Record Gain */
302 { AudioCrecord, AudioNvolume, NULL,
303 AUDIO_MIXER_VALUE, WRAP(ac97_volume_stereo),
304 AC97_REG_RECORD_GAIN, 0x8000, 4, 0, 1, 1, 0
305 },
306 /* Record Gain mic */
307 { AudioCrecord, AudioNmicrophone, NULL,
308 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
309 AC97_REG_RECORD_GAIN_MIC, 0x8000, 4, 0, 1, 1, 0, CHECK_MIC
310 },
311 /* */
312 { AudioCoutputs, AudioNloudness, NULL,
313 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
314 AC97_REG_GP, 0x0000, 1, 12, 0, 0, 0, CHECK_LOUDNESS
315 },
316 { AudioCoutputs, AudioNspatial, NULL,
317 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
318 AC97_REG_GP, 0x0000, 1, 13, 0, 1, 0, CHECK_3D
319 },
320 { AudioCoutputs, AudioNspatial, "center",
321 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
322 AC97_REG_3D_CONTROL, 0x0000, 4, 8, 0, 1, 0, CHECK_3D
323 },
324 { AudioCoutputs, AudioNspatial, "depth",
325 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
326 AC97_REG_3D_CONTROL, 0x0000, 4, 0, 0, 1, 0, CHECK_3D
327 },
328
329 /* SPDIF */
330 { "spdif", NULL, NULL,
331 AUDIO_MIXER_CLASS, NULL, 0,
332 0, 0, 0, 0, 0, 0, 0, CHECK_SPDIF},
333 { "spdif", "enable", NULL,
334 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
335 AC97_REG_EXT_AUDIO_CTRL, -1, 1, 2, 0, 0, 0, CHECK_SPDIF},
336
337 /* Missing features: Simulated Stereo, POP, Loopback mode */
338 };
339
340 static const struct ac97_source_info modem_source_info[] = {
341 /* Classes */
342 { AudioCinputs, NULL, NULL,
343 AUDIO_MIXER_CLASS, },
344 { AudioCoutputs, NULL, NULL,
345 AUDIO_MIXER_CLASS, },
346 { AudioCinputs, Ac97Nline1, NULL,
347 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
348 AC97_REG_LINE1_LEVEL, 0x8080, 4, 0, 0, 1, 0, CHECK_LINE1
349 },
350 { AudioCoutputs, Ac97Nline1, NULL,
351 AUDIO_MIXER_VALUE, WRAP(ac97_volume_mono),
352 AC97_REG_LINE1_LEVEL, 0x8080, 4, 8, 0, 1, 0, CHECK_LINE1
353 },
354 { AudioCinputs, Ac97Nline1, AudioNmute,
355 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
356 AC97_REG_LINE1_LEVEL, 0x8080, 1, 7, 0, 0, 0, CHECK_LINE1
357 },
358 { AudioCoutputs, Ac97Nline1, AudioNmute,
359 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
360 AC97_REG_LINE1_LEVEL, 0x8080, 1, 15, 0, 0, 0, CHECK_LINE1
361 },
362 };
363
364 #define AUDIO_SOURCE_INFO_SIZE \
365 (sizeof(audio_source_info)/sizeof(audio_source_info[0]))
366 #define MODEM_SOURCE_INFO_SIZE \
367 (sizeof(modem_source_info)/sizeof(modem_source_info[0]))
368 #define SOURCE_INFO_SIZE(as) ((as)->type == AC97_CODEC_TYPE_MODEM ? \
369 MODEM_SOURCE_INFO_SIZE : AUDIO_SOURCE_INFO_SIZE)
370
371 /*
372 * Check out http://developer.intel.com/pc-supp/platform/ac97/ for
373 * information on AC-97
374 */
375
376 struct ac97_softc {
377 /* ac97_codec_if must be at the first of ac97_softc. */
378 struct ac97_codec_if codec_if;
379
380 struct ac97_host_if *host_if;
381
382 #define AUDIO_MAX_SOURCES (2 * AUDIO_SOURCE_INFO_SIZE)
383 #define MODEM_MAX_SOURCES (2 * MODEM_SOURCE_INFO_SIZE)
384 struct ac97_source_info audio_source_info[AUDIO_MAX_SOURCES];
385 struct ac97_source_info modem_source_info[MODEM_MAX_SOURCES];
386 struct ac97_source_info *source_info;
387 int num_source_info;
388
389 enum ac97_host_flags host_flags;
390 unsigned int ac97_clock; /* usually 48000 */
391 #define AC97_STANDARD_CLOCK 48000U
392 uint16_t power_all;
393 uint16_t power_reg; /* -> AC97_REG_POWER */
394 uint16_t caps; /* -> AC97_REG_RESET */
395 uint16_t ext_id; /* -> AC97_REG_EXT_AUDIO_ID */
396 uint16_t ext_mid; /* -> AC97_REG_EXT_MODEM_ID */
397 uint16_t shadow_reg[128];
398
399 int lock_counter;
400 int type;
401
402 /* sysctl */
403 struct sysctllog *log;
404 int offhook_line1_mib;
405 int offhook_line2_mib;
406 int offhook_line1;
407 int offhook_line2;
408 };
409
410 static struct ac97_codec_if_vtbl ac97civ = {
411 ac97_mixer_get_port,
412 ac97_mixer_set_port,
413 ac97_query_devinfo,
414 ac97_get_portnum_by_name,
415 ac97_restore_shadow,
416 ac97_get_extcaps,
417 ac97_set_rate,
418 ac97_set_clock,
419 ac97_detach,
420 ac97_lock,
421 ac97_unlock,
422 };
423
424 static const struct ac97_codecid {
425 uint32_t id;
426 uint32_t mask;
427 const char *name;
428 void (*init)(struct ac97_softc *);
429 } ac97codecid[] = {
430 /*
431 * Analog Devices SoundMAX
432 * http://www.soundmax.com/products/information/codecs.html
433 * http://www.analog.com/productSelection/pdf/AD1881A_0.pdf
434 * http://www.analog.com/productSelection/pdf/AD1885_0.pdf
435 * http://www.analog.com/UploadedFiles/Data_Sheets/206585810AD1980_0.pdf
436 * http://www.analog.com/productSelection/pdf/AD1981A_0.pdf
437 * http://www.analog.com/productSelection/pdf/AD1981B_0.pdf
438 * http://www.analog.com/UploadedFiles/Data_Sheets/180644528AD1985_0.pdf
439 */
440 { AC97_CODEC_ID('A', 'D', 'S', 3),
441 0xffffffff, "Analog Devices AD1819B" },
442 { AC97_CODEC_ID('A', 'D', 'S', 0x40),
443 0xffffffff, "Analog Devices AD1881" },
444 { AC97_CODEC_ID('A', 'D', 'S', 0x48),
445 0xffffffff, "Analog Devices AD1881A" },
446 { AC97_CODEC_ID('A', 'D', 'S', 0x60),
447 0xffffffff, "Analog Devices AD1885" },
448 { AC97_CODEC_ID('A', 'D', 'S', 0x61),
449 0xffffffff, "Analog Devices AD1886" },
450 { AC97_CODEC_ID('A', 'D', 'S', 0x63),
451 0xffffffff, "Analog Devices AD1886A" },
452 { AC97_CODEC_ID('A', 'D', 'S', 0x68),
453 0xffffffff, "Analog Devices AD1888", ac97_ad198x_init },
454 { AC97_CODEC_ID('A', 'D', 'S', 0x70),
455 0xffffffff, "Analog Devices AD1980", ac97_ad198x_init },
456 { AC97_CODEC_ID('A', 'D', 'S', 0x72),
457 0xffffffff, "Analog Devices AD1981A" },
458 { AC97_CODEC_ID('A', 'D', 'S', 0x74),
459 0xffffffff, "Analog Devices AD1981B" },
460 { AC97_CODEC_ID('A', 'D', 'S', 0x75),
461 0xffffffff, "Analog Devices AD1985", ac97_ad198x_init },
462 { AC97_CODEC_ID('A', 'D', 'S', 0),
463 AC97_VENDOR_ID_MASK, "Analog Devices unknown" },
464
465 /*
466 * Datasheets:
467 * http://www.asahi-kasei.co.jp/akm/japanese/product/ak4543/ek4543.pdf
468 * http://www.asahi-kasei.co.jp/akm/japanese/product/ak4544a/ek4544a.pdf
469 * http://www.asahi-kasei.co.jp/akm/japanese/product/ak4545/ak4545_f00e.pdf
470 */
471 { AC97_CODEC_ID('A', 'K', 'M', 0),
472 0xffffffff, "Asahi Kasei AK4540" },
473 { AC97_CODEC_ID('A', 'K', 'M', 1),
474 0xffffffff, "Asahi Kasei AK4542" },
475 { AC97_CODEC_ID('A', 'K', 'M', 2),
476 0xffffffff, "Asahi Kasei AK4541/AK4543" },
477 { AC97_CODEC_ID('A', 'K', 'M', 5),
478 0xffffffff, "Asahi Kasei AK4544" },
479 { AC97_CODEC_ID('A', 'K', 'M', 6),
480 0xffffffff, "Asahi Kasei AK4544A" },
481 { AC97_CODEC_ID('A', 'K', 'M', 7),
482 0xffffffff, "Asahi Kasei AK4545" },
483 { AC97_CODEC_ID('A', 'K', 'M', 0),
484 AC97_VENDOR_ID_MASK, "Asahi Kasei unknown" },
485
486 /*
487 * Realtek & Avance Logic
488 * http://www.realtek.com.tw/downloads/downloads1-3.aspx?lineid=5&famid=All&series=All&Spec=True
489 *
490 * ALC650 and ALC658 support VRA, but it supports only 8000, 11025,
491 * 12000, 16000, 22050, 24000, 32000, 44100, and 48000 Hz.
492 */
493 { AC97_CODEC_ID('A', 'L', 'C', 0x00),
494 0xfffffff0, "Realtek RL5306" },
495 { AC97_CODEC_ID('A', 'L', 'C', 0x10),
496 0xfffffff0, "Realtek RL5382" },
497 { AC97_CODEC_ID('A', 'L', 'C', 0x20),
498 0xfffffff0, "Realtek RL5383/RL5522/ALC100" },
499 { AC97_CODEC_ID('A', 'L', 'G', 0x10),
500 0xffffffff, "Avance Logic ALC200/ALC201" },
501 { AC97_CODEC_ID('A', 'L', 'G', 0x20),
502 0xfffffff0, "Avance Logic ALC650", ac97_alc650_init },
503 { AC97_CODEC_ID('A', 'L', 'G', 0x30),
504 0xffffffff, "Avance Logic ALC101" },
505 { AC97_CODEC_ID('A', 'L', 'G', 0x40),
506 0xffffffff, "Avance Logic ALC202" },
507 { AC97_CODEC_ID('A', 'L', 'G', 0x50),
508 0xffffffff, "Avance Logic ALC250" },
509 { AC97_CODEC_ID('A', 'L', 'G', 0x60),
510 0xfffffff0, "Avance Logic ALC655" },
511 { AC97_CODEC_ID('A', 'L', 'G', 0x80),
512 0xfffffff0, "Avance Logic ALC658" },
513 { AC97_CODEC_ID('A', 'L', 'G', 0x90),
514 0xfffffff0, "Avance Logic ALC850" },
515 { AC97_CODEC_ID('A', 'L', 'C', 0),
516 AC97_VENDOR_ID_MASK, "Realtek unknown" },
517 { AC97_CODEC_ID('A', 'L', 'G', 0),
518 AC97_VENDOR_ID_MASK, "Avance Logic unknown" },
519
520 /**
521 * C-Media Electronics Inc.
522 * http://www.cmedia.com.tw/doc/CMI9739%206CH%20Audio%20Codec%20SPEC_Ver12.pdf
523 */
524 { AC97_CODEC_ID('C', 'M', 'I', 0x61),
525 0xffffffff, "C-Media CMI9739" },
526 { AC97_CODEC_ID('C', 'M', 'I', 0),
527 AC97_VENDOR_ID_MASK, "C-Media unknown" },
528
529 /* Cirrus Logic, Crystal series:
530 * 'C' 'R' 'Y' 0x0[0-7] - CS4297
531 * 0x1[0-7] - CS4297A
532 * 0x2[0-7] - CS4298
533 * 0x2[8-f] - CS4294
534 * 0x3[0-7] - CS4299
535 * 0x4[8-f] - CS4201
536 * 0x5[8-f] - CS4205
537 * 0x6[0-7] - CS4291
538 * 0x7[0-7] - CS4202
539 * Datasheets:
540 * http://www.cirrus.com/pubs/cs4297A-5.pdf?DocumentID=593
541 * http://www.cirrus.com/pubs/cs4294.pdf?DocumentID=32
542 * http://www.cirrus.com/pubs/cs4299-5.pdf?DocumentID=594
543 * http://www.cirrus.com/pubs/cs4201-2.pdf?DocumentID=492
544 * http://www.cirrus.com/pubs/cs4205-2.pdf?DocumentID=492
545 * http://www.cirrus.com/pubs/cs4202-1.pdf?DocumentID=852
546 */
547 { AC97_CODEC_ID('C', 'R', 'Y', 0x00),
548 0xfffffff8, "Crystal CS4297", },
549 { AC97_CODEC_ID('C', 'R', 'Y', 0x10),
550 0xfffffff8, "Crystal CS4297A", },
551 { AC97_CODEC_ID('C', 'R', 'Y', 0x20),
552 0xfffffff8, "Crystal CS4298", },
553 { AC97_CODEC_ID('C', 'R', 'Y', 0x28),
554 0xfffffff8, "Crystal CS4294", },
555 { AC97_CODEC_ID('C', 'R', 'Y', 0x30),
556 0xfffffff8, "Crystal CS4299", },
557 { AC97_CODEC_ID('C', 'R', 'Y', 0x48),
558 0xfffffff8, "Crystal CS4201", },
559 { AC97_CODEC_ID('C', 'R', 'Y', 0x58),
560 0xfffffff8, "Crystal CS4205", },
561 { AC97_CODEC_ID('C', 'R', 'Y', 0x60),
562 0xfffffff8, "Crystal CS4291", },
563 { AC97_CODEC_ID('C', 'R', 'Y', 0x70),
564 0xfffffff8, "Crystal CS4202", },
565 { AC97_CODEC_ID('C', 'R', 'Y', 0),
566 AC97_VENDOR_ID_MASK, "Cirrus Logic unknown", },
567
568 { 0x45838308, 0xffffffff, "ESS Technology ES1921", },
569 { 0x45838300, AC97_VENDOR_ID_MASK, "ESS Technology unknown", },
570
571 { AC97_CODEC_ID('H', 'R', 'S', 0),
572 0xffffffff, "Intersil HMP9701", },
573 { AC97_CODEC_ID('H', 'R', 'S', 0),
574 AC97_VENDOR_ID_MASK, "Intersil unknown", },
575
576 /*
577 * IC Ensemble (VIA)
578 * http://www.viatech.com/en/datasheet/DS1616.pdf
579 */
580 { AC97_CODEC_ID('I', 'C', 'E', 0x01),
581 0xffffffff, "ICEnsemble ICE1230/VT1611", },
582 { AC97_CODEC_ID('I', 'C', 'E', 0x11),
583 0xffffffff, "ICEnsemble ICE1232/VT1611A", },
584 { AC97_CODEC_ID('I', 'C', 'E', 0x14),
585 0xffffffff, "ICEnsemble ICE1232A", },
586 { AC97_CODEC_ID('I', 'C', 'E', 0x51),
587 0xffffffff, "VIA Technologies VT1616", ac97_vt1616_init },
588 { AC97_CODEC_ID('I', 'C', 'E', 0x52),
589 0xffffffff, "VIA Technologies VT1616i", ac97_vt1616_init },
590 { AC97_CODEC_ID('I', 'C', 'E', 0),
591 AC97_VENDOR_ID_MASK, "ICEnsemble/VIA unknown", },
592
593 { AC97_CODEC_ID('N', 'S', 'C', 0),
594 0xffffffff, "National Semiconductor LM454[03568]", },
595 { AC97_CODEC_ID('N', 'S', 'C', 49),
596 0xffffffff, "National Semiconductor LM4549", },
597 { AC97_CODEC_ID('N', 'S', 'C', 0),
598 AC97_VENDOR_ID_MASK, "National Semiconductor unknown", },
599
600 { AC97_CODEC_ID('P', 'S', 'C', 4),
601 0xffffffff, "Philips Semiconductor UCB1400", },
602 { AC97_CODEC_ID('P', 'S', 'C', 0),
603 AC97_VENDOR_ID_MASK, "Philips Semiconductor unknown", },
604
605 { AC97_CODEC_ID('S', 'I', 'L', 34),
606 0xffffffff, "Silicon Laboratory Si3036", },
607 { AC97_CODEC_ID('S', 'I', 'L', 35),
608 0xffffffff, "Silicon Laboratory Si3038", },
609 { AC97_CODEC_ID('S', 'I', 'L', 0),
610 AC97_VENDOR_ID_MASK, "Silicon Laboratory unknown", },
611
612 { AC97_CODEC_ID('T', 'R', 'A', 2),
613 0xffffffff, "TriTech TR28022", },
614 { AC97_CODEC_ID('T', 'R', 'A', 3),
615 0xffffffff, "TriTech TR28023", },
616 { AC97_CODEC_ID('T', 'R', 'A', 6),
617 0xffffffff, "TriTech TR28026", },
618 { AC97_CODEC_ID('T', 'R', 'A', 8),
619 0xffffffff, "TriTech TR28028", },
620 { AC97_CODEC_ID('T', 'R', 'A', 35),
621 0xffffffff, "TriTech TR28602", },
622 { AC97_CODEC_ID('T', 'R', 'A', 0),
623 AC97_VENDOR_ID_MASK, "TriTech unknown", },
624
625 { AC97_CODEC_ID('T', 'X', 'N', 0x20),
626 0xffffffff, "Texas Instruments TLC320AD9xC", },
627 { AC97_CODEC_ID('T', 'X', 'N', 0),
628 AC97_VENDOR_ID_MASK, "Texas Instruments unknown", },
629
630 /*
631 * VIA
632 * http://www.viatech.com/en/multimedia/audio.jsp
633 */
634 { AC97_CODEC_ID('V', 'I', 'A', 0x61),
635 0xffffffff, "VIA Technologies VT1612A", },
636 { AC97_CODEC_ID('V', 'I', 'A', 0),
637 AC97_VENDOR_ID_MASK, "VIA Technologies unknown", },
638
639 { AC97_CODEC_ID('W', 'E', 'C', 1),
640 0xffffffff, "Winbond W83971D", },
641 { AC97_CODEC_ID('W', 'E', 'C', 0),
642 AC97_VENDOR_ID_MASK, "Winbond unknown", },
643
644 /*
645 * http://www.wolfsonmicro.com/product_list.asp?cid=64
646 * http://www.wolfsonmicro.com/download.asp/did.56/WM9701A.pdf - 00
647 * http://www.wolfsonmicro.com/download.asp/did.57/WM9703.pdf - 03
648 * http://www.wolfsonmicro.com/download.asp/did.58/WM9704M.pdf - 04
649 * http://www.wolfsonmicro.com/download.asp/did.59/WM9704Q.pdf - 04
650 * http://www.wolfsonmicro.com/download.asp/did.184/WM9705_Rev34.pdf - 05
651 * http://www.wolfsonmicro.com/download.asp/did.60/WM9707.pdf - 03
652 * http://www.wolfsonmicro.com/download.asp/did.136/WM9708.pdf - 03
653 * http://www.wolfsonmicro.com/download.asp/did.243/WM9710.pdf - 05
654 */
655 { AC97_CODEC_ID('W', 'M', 'L', 0),
656 0xffffffff, "Wolfson WM9701A", },
657 { AC97_CODEC_ID('W', 'M', 'L', 3),
658 0xffffffff, "Wolfson WM9703/WM9707/WM9708", },
659 { AC97_CODEC_ID('W', 'M', 'L', 4),
660 0xffffffff, "Wolfson WM9704", },
661 { AC97_CODEC_ID('W', 'M', 'L', 5),
662 0xffffffff, "Wolfson WM9705/WM9710", },
663 { AC97_CODEC_ID('W', 'M', 'L', 0),
664 AC97_VENDOR_ID_MASK, "Wolfson unknown", },
665
666 /*
667 * http://www.yamaha.co.jp/english/product/lsi/us/products/pcaudio.html
668 * Datasheets:
669 * http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF743A20.pdf
670 * http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF753A20.pdf
671 */
672 { AC97_CODEC_ID('Y', 'M', 'H', 0),
673 0xffffffff, "Yamaha YMF743-S", },
674 { AC97_CODEC_ID('Y', 'M', 'H', 3),
675 0xffffffff, "Yamaha YMF753-S", },
676 { AC97_CODEC_ID('Y', 'M', 'H', 0),
677 AC97_VENDOR_ID_MASK, "Yamaha unknown", },
678
679 /*
680 * http://www.sigmatel.com/products/technical_docs.htm
681 * and
682 * http://www.sigmatel.com/documents/c-major-brochure-9-0.pdf
683 */
684 { 0x83847600, 0xffffffff, "SigmaTel STAC9700", },
685 { 0x83847604, 0xffffffff, "SigmaTel STAC9701/3/4/5", },
686 { 0x83847605, 0xffffffff, "SigmaTel STAC9704", },
687 { 0x83847608, 0xffffffff, "SigmaTel STAC9708", },
688 { 0x83847609, 0xffffffff, "SigmaTel STAC9721/23", },
689 { 0x83847644, 0xffffffff, "SigmaTel STAC9744/45", },
690 { 0x83847650, 0xffffffff, "SigmaTel STAC9750/51", },
691 { 0x83847652, 0xffffffff, "SigmaTel STAC9752/53", },
692 { 0x83847656, 0xffffffff, "SigmaTel STAC9756/57", },
693 { 0x83847658, 0xffffffff, "SigmaTel STAC9758/59", },
694 { 0x83847666, 0xffffffff, "SigmaTel STAC9766/67", },
695 { 0x83847684, 0xffffffff, "SigmaTel STAC9783/84", },
696 { 0x83847600, AC97_VENDOR_ID_MASK, "SigmaTel unknown", },
697
698 /* Conexant AC'97 modems -- good luck finding datasheets! */
699 { AC97_CODEC_ID('C', 'X', 'T', 33),
700 0xffffffff, "Conexant HSD11246", },
701 { AC97_CODEC_ID('C', 'X', 'T', 34),
702 0xffffffff, "Conexant D480 MDC V.92 Modem", },
703 { AC97_CODEC_ID('C', 'X', 'T', 48),
704 0xffffffff, "Conexant CXT48", },
705 { AC97_CODEC_ID('C', 'X', 'T', 0),
706 AC97_VENDOR_ID_MASK, "Conexant unknown", },
707
708 { 0,
709 0, NULL, }
710 };
711
712 static const char * const ac97enhancement[] = {
713 "no 3D stereo",
714 "Analog Devices Phat Stereo",
715 "Creative",
716 "National Semi 3D",
717 "Yamaha Ymersion",
718 "BBE 3D",
719 "Crystal Semi 3D",
720 "Qsound QXpander",
721 "Spatializer 3D",
722 "SRS 3D",
723 "Platform Tech 3D",
724 "AKM 3D",
725 "Aureal",
726 "AZTECH 3D",
727 "Binaura 3D",
728 "ESS Technology",
729 "Harman International VMAx",
730 "Nvidea 3D",
731 "Philips Incredible Sound",
732 "Texas Instruments' 3D",
733 "VLSI Technology 3D",
734 "TriTech 3D",
735 "Realtek 3D",
736 "Samsung 3D",
737 "Wolfson Microelectronics 3D",
738 "Delta Integration 3D",
739 "SigmaTel 3D",
740 "KS Waves 3D",
741 "Rockwell 3D",
742 "Unknown 3D",
743 "Unknown 3D",
744 "Unknown 3D",
745 };
746
747 static const char * const ac97feature[] = {
748 "dedicated mic channel",
749 "reserved",
750 "tone",
751 "simulated stereo",
752 "headphone",
753 "bass boost",
754 "18 bit DAC",
755 "20 bit DAC",
756 "18 bit ADC",
757 "20 bit ADC"
758 };
759
760
761 /* #define AC97_DEBUG 10 */
762 /* #define AC97_IO_DEBUG */
763
764 #ifdef AUDIO_DEBUG
765 #define DPRINTF(x) if (ac97debug) printf x
766 #define DPRINTFN(n,x) if (ac97debug>(n)) printf x
767 #ifdef AC97_DEBUG
768 int ac97debug = AC97_DEBUG;
769 #else
770 int ac97debug = 0;
771 #endif
772 #else
773 #define DPRINTF(x)
774 #define DPRINTFN(n,x)
775 #endif
776
777 #ifdef AC97_IO_DEBUG
778 static const char *ac97_register_names[0x80 / 2] = {
779 "RESET", "MASTER_VOLUME", "HEADPHONE_VOLUME", "MASTER_VOLUME_MONO",
780 "MASTER_TONE", "PCBEEP_VOLUME", "PHONE_VOLUME", "MIC_VOLUME",
781 "LINEIN_VOLUME", "CD_VOLUME", "VIDEO_VOLUME", "AUX_VOLUME",
782 "PCMOUT_VOLUME", "RECORD_SELECT", "RECORD_GATIN", "RECORD_GAIN_MIC",
783 "GP", "3D_CONTROL", "AUDIO_INT", "POWER",
784 "EXT_AUDIO_ID", "EXT_AUDIO_CTRL", "PCM_FRONT_DAC_RATE", "PCM_SURR_DAC_RATE",
785 "PCM_LFE_DAC_RATE", "PCM_LR_ADC_RATE", "PCM_MIC_ADC_RATE", "CENTER_LFE_MASTER",
786 "SURR_MASTER", "SPDIF_CTRL", "EXT_MODEM_ID", "EXT_MODEM_CTRL",
787 "LINE1_RATE", "LINE2_RATE", "HANDSET_RATE", "LINE1_LEVEL",
788 "LINE2_LEVEL", "HANDSET_LEVEL", "GPIO_PIN_CONFIG", "GPIO_PIN_POLARITY",
789 "GPIO_PIN_STICKY", "GPIO_PIN_WAKEUP", "GPIO_PIN_STATUS", "MISC_MODEM_CTRL",
790 "0x58", "VENDOR-5A", "VENDOR-5C", "VENDOR-5E",
791 "0x60", "0x62", "0x64", "0x66",
792 "0x68", "0x6a", "0x6c", "0x6e",
793 "VENDOR-70", "VENDOR-72", "VENDOR-74", "VENDOR-76",
794 "VENDOR-78", "VENDOR-7A", "VENDOR_ID1", "VENDOR_ID2"
795 };
796 #endif
797
798 /*
799 * XXX Some cards have an inverted AC97_POWER_EAMP bit.
800 * These cards will produce no sound unless AC97_HOST_INVERTED_EAMP is set.
801 */
802
803 #define POWER_EAMP_ON(as) ((as->host_flags & AC97_HOST_INVERTED_EAMP) \
804 ? AC97_POWER_EAMP : 0)
805 #define POWER_EAMP_OFF(as) ((as->host_flags & AC97_HOST_INVERTED_EAMP) \
806 ? 0 : AC97_POWER_EAMP)
807
808 static void
809 ac97_read(struct ac97_softc *as, uint8_t reg, uint16_t *val)
810 {
811 if (as->host_flags & AC97_HOST_DONT_READ &&
812 (reg != AC97_REG_VENDOR_ID1 && reg != AC97_REG_VENDOR_ID2 &&
813 reg != AC97_REG_RESET)) {
814 *val = as->shadow_reg[reg >> 1];
815 return;
816 }
817
818 if (as->host_if->read(as->host_if->arg, reg, val)) {
819 *val = as->shadow_reg[reg >> 1];
820 }
821 }
822
823 static int
824 ac97_write(struct ac97_softc *as, uint8_t reg, uint16_t val)
825 {
826 #ifndef AC97_IO_DEBUG
827 as->shadow_reg[reg >> 1] = val;
828 return as->host_if->write(as->host_if->arg, reg, val);
829 #else
830 int ret;
831 uint16_t actual;
832
833 as->shadow_reg[reg >> 1] = val;
834 ret = as->host_if->write(as->host_if->arg, reg, val);
835 as->host_if->read(as->host_if->arg, reg, &actual);
836 if (val != actual && reg < 0x80) {
837 printf("ac97_write: reg=%s, written=0x%04x, read=0x%04x\n",
838 ac97_register_names[reg / 2], val, actual);
839 }
840 return ret;
841 #endif
842 }
843
844 static void
845 ac97_setup_defaults(struct ac97_softc *as)
846 {
847 int idx;
848 const struct ac97_source_info *si;
849
850 memset(as->shadow_reg, 0, sizeof(as->shadow_reg));
851
852 for (idx = 0; idx < AUDIO_SOURCE_INFO_SIZE; idx++) {
853 si = &audio_source_info[idx];
854 if (si->default_value >= 0)
855 ac97_write(as, si->reg, si->default_value);
856 }
857 for (idx = 0; idx < MODEM_SOURCE_INFO_SIZE; idx++) {
858 si = &modem_source_info[idx];
859 if (si->default_value >= 0)
860 ac97_write(as, si->reg, si->default_value);
861 }
862 }
863
864 static void
865 ac97_restore_shadow(struct ac97_codec_if *self)
866 {
867 struct ac97_softc *as;
868 const struct ac97_source_info *si;
869 int idx;
870 uint16_t val;
871
872 as = (struct ac97_softc *) self;
873
874 if (as->type == AC97_CODEC_TYPE_AUDIO) {
875 /* restore AC97_REG_POWER */
876 ac97_write(as, AC97_REG_POWER, as->power_reg);
877 /* make sure chip is fully operational */
878 for (idx = 50000; idx >= 0; idx--) {
879 ac97_read(as, AC97_REG_POWER, &val);
880 if ((val & as->power_all) == as->power_all)
881 break;
882 DELAY(10);
883 }
884
885 /*
886 * actually try changing a value!
887 * The default value of AC97_REG_MASTER_VOLUME is 0x8000.
888 */
889 for (idx = 50000; idx >= 0; idx--) {
890 ac97_write(as, AC97_REG_MASTER_VOLUME, 0x1010);
891 ac97_read(as, AC97_REG_MASTER_VOLUME, &val);
892 if (val == 0x1010)
893 break;
894 DELAY(10);
895 }
896 }
897
898 for (idx = 0; idx < SOURCE_INFO_SIZE(as); idx++) {
899 if (as->type == AC97_CODEC_TYPE_MODEM)
900 si = &modem_source_info[idx];
901 else
902 si = &audio_source_info[idx];
903 /* don't "restore" to the reset reg! */
904 if (si->reg != AC97_REG_RESET)
905 ac97_write(as, si->reg, as->shadow_reg[si->reg >> 1]);
906 }
907
908 if (as->ext_id & (AC97_EXT_AUDIO_VRA | AC97_EXT_AUDIO_DRA
909 | AC97_EXT_AUDIO_SPDIF | AC97_EXT_AUDIO_VRM
910 | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_SDAC
911 | AC97_EXT_AUDIO_LDAC)) {
912 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL,
913 as->shadow_reg[AC97_REG_EXT_AUDIO_CTRL >> 1]);
914 }
915 if (as->ext_mid & (AC97_EXT_MODEM_LINE1 | AC97_EXT_MODEM_LINE2
916 | AC97_EXT_MODEM_HANDSET | AC97_EXT_MODEM_CID1
917 | AC97_EXT_MODEM_CID2 | AC97_EXT_MODEM_ID0
918 | AC97_EXT_MODEM_ID1)) {
919 ac97_write(as, AC97_REG_EXT_MODEM_CTRL,
920 as->shadow_reg[AC97_REG_EXT_MODEM_CTRL >> 1]);
921 }
922 }
923
924 static int
925 ac97_str_equal(const char *a, const char *b)
926 {
927 return (a == b) || (a && b && (!strcmp(a, b)));
928 }
929
930 static int
931 ac97_check_capability(struct ac97_softc *as, int check)
932 {
933 switch (check) {
934 case CHECK_NONE:
935 return 1;
936 case CHECK_SURROUND:
937 return as->ext_id & AC97_EXT_AUDIO_SDAC;
938 case CHECK_CENTER:
939 return as->ext_id & AC97_EXT_AUDIO_CDAC;
940 case CHECK_LFE:
941 return as->ext_id & AC97_EXT_AUDIO_LDAC;
942 case CHECK_SPDIF:
943 return as->ext_id & AC97_EXT_AUDIO_SPDIF;
944 case CHECK_HEADPHONES:
945 return as->caps & AC97_CAPS_HEADPHONES;
946 case CHECK_TONE:
947 return as->caps & AC97_CAPS_TONECTRL;
948 case CHECK_MIC:
949 return as->caps & AC97_CAPS_MICIN;
950 case CHECK_LOUDNESS:
951 return as->caps & AC97_CAPS_LOUDNESS;
952 case CHECK_3D:
953 return AC97_CAPS_ENHANCEMENT(as->caps) != 0;
954 case CHECK_LINE1:
955 return as->ext_mid & AC97_EXT_MODEM_LINE1;
956 case CHECK_LINE2:
957 return as->ext_mid & AC97_EXT_MODEM_LINE2;
958 case CHECK_HANDSET:
959 return as->ext_mid & AC97_EXT_MODEM_HANDSET;
960 default:
961 printf("%s: internal error: feature=%d\n", __func__, check);
962 return 0;
963 }
964 }
965
966 static void
967 ac97_setup_source_info(struct ac97_softc *as)
968 {
969 int idx, ouridx;
970 struct ac97_source_info *si, *si2;
971 uint16_t value1, value2, value3;
972
973 for (idx = 0, ouridx = 0; idx < SOURCE_INFO_SIZE(as); idx++) {
974 si = &as->source_info[ouridx];
975 if (as->type == AC97_CODEC_TYPE_MODEM) {
976 memcpy(si, &modem_source_info[idx], sizeof(*si));
977 } else {
978 memcpy(si, &audio_source_info[idx], sizeof(*si));
979 }
980 if (!ac97_check_capability(as, si->req_feature))
981 continue;
982 if (si->checkbits) {
983 /* read the register value */
984 ac97_read(as, si->reg, &value1);
985 /* write 0b100000 */
986 value2 = value1 & 0xffc0;
987 value2 |= 0x20;
988 ac97_write(as, si->reg, value2);
989 /* verify */
990 ac97_read(as, si->reg, &value3);
991 if (value2 == value3) {
992 si->bits = 6;
993 } else {
994 si->bits = 5;
995 }
996 DPRINTF(("%s: register=%02x bits=%d\n",
997 __func__, si->reg, si->bits));
998 ac97_write(as, si->reg, value1);
999 }
1000
1001 switch (si->type) {
1002 case AUDIO_MIXER_CLASS:
1003 si->mixer_class = ouridx;
1004 ouridx++;
1005 break;
1006 case AUDIO_MIXER_VALUE:
1007 /* Todo - Test to see if it works */
1008 ouridx++;
1009
1010 /* Add an entry for mute, if necessary */
1011 if (si->mute) {
1012 si = &as->source_info[ouridx];
1013 if (as->type == AC97_CODEC_TYPE_MODEM)
1014 memcpy(si, &modem_source_info[idx],
1015 sizeof(*si));
1016 else
1017 memcpy(si, &audio_source_info[idx],
1018 sizeof(*si));
1019 si->qualifier = AudioNmute;
1020 si->type = AUDIO_MIXER_ENUM;
1021 si->info = &ac97_on_off;
1022 si->info_size = sizeof(ac97_on_off);
1023 si->bits = 1;
1024 si->ofs = 15;
1025 si->mute = 0;
1026 si->polarity = 0;
1027 ouridx++;
1028 }
1029 break;
1030 case AUDIO_MIXER_ENUM:
1031 /* Todo - Test to see if it works */
1032 ouridx++;
1033 break;
1034 default:
1035 aprint_error ("ac97: shouldn't get here\n");
1036 break;
1037 }
1038 }
1039
1040 as->num_source_info = ouridx;
1041
1042 for (idx = 0; idx < as->num_source_info; idx++) {
1043 int idx2, previdx;
1044
1045 si = &as->source_info[idx];
1046
1047 /* Find mixer class */
1048 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
1049 si2 = &as->source_info[idx2];
1050
1051 if (si2->type == AUDIO_MIXER_CLASS &&
1052 ac97_str_equal(si->class,
1053 si2->class)) {
1054 si->mixer_class = idx2;
1055 }
1056 }
1057
1058
1059 /* Setup prev and next pointers */
1060 if (si->prev != 0)
1061 continue;
1062
1063 if (si->qualifier)
1064 continue;
1065
1066 si->prev = AUDIO_MIXER_LAST;
1067 previdx = idx;
1068
1069 for (idx2 = 0; idx2 < as->num_source_info; idx2++) {
1070 if (idx2 == idx)
1071 continue;
1072
1073 si2 = &as->source_info[idx2];
1074
1075 if (!si2->prev &&
1076 ac97_str_equal(si->class, si2->class) &&
1077 ac97_str_equal(si->device, si2->device)) {
1078 as->source_info[previdx].next = idx2;
1079 as->source_info[idx2].prev = previdx;
1080
1081 previdx = idx2;
1082 }
1083 }
1084
1085 as->source_info[previdx].next = AUDIO_MIXER_LAST;
1086 }
1087 }
1088
1089 /* backward compatibility */
1090 int
1091 ac97_attach(struct ac97_host_if *host_if, struct device *sc_dev)
1092 {
1093 return ac97_attach_type(host_if, sc_dev, AC97_CODEC_TYPE_AUDIO);
1094 }
1095
1096 int
1097 ac97_attach_type(struct ac97_host_if *host_if, struct device *sc_dev, int type)
1098 {
1099 struct ac97_softc *as;
1100 int error, i, j;
1101 uint32_t id;
1102 uint16_t id1, id2;
1103 uint16_t extstat, rate;
1104 uint16_t val;
1105 mixer_ctrl_t ctl;
1106 void (*initfunc)(struct ac97_softc *);
1107 #define FLAGBUFLEN 140
1108 char flagbuf[FLAGBUFLEN];
1109
1110 initfunc = NULL;
1111 as = malloc(sizeof(struct ac97_softc), M_DEVBUF, M_WAITOK|M_ZERO);
1112
1113 if (as == NULL)
1114 return ENOMEM;
1115
1116 as->codec_if.vtbl = &ac97civ;
1117 as->host_if = host_if;
1118 as->type = type;
1119
1120 if ((error = host_if->attach(host_if->arg, &as->codec_if))) {
1121 free(as, M_DEVBUF);
1122 return error;
1123 }
1124
1125 if (host_if->reset != NULL) {
1126 if ((error = host_if->reset(host_if->arg))) {
1127 free(as, M_DEVBUF);
1128 return error;
1129 }
1130 }
1131
1132 if (host_if->flags)
1133 as->host_flags = host_if->flags(host_if->arg);
1134
1135 /*
1136 * Assume codec has all four power bits.
1137 * XXXSCW: what to do for modems?
1138 */
1139 as->power_all = AC97_POWER_REF | AC97_POWER_ANL | AC97_POWER_DAC |
1140 AC97_POWER_ADC;
1141 if (as->type == AC97_CODEC_TYPE_AUDIO) {
1142 host_if->write(host_if->arg, AC97_REG_RESET, 0);
1143
1144 /*
1145 * Power-up everything except the analogue mixer.
1146 * If this codec doesn't support analogue mixer power-down,
1147 * AC97_POWER_MIXER will read back as zero.
1148 */
1149 host_if->write(host_if->arg, AC97_REG_POWER, AC97_POWER_MIXER);
1150 ac97_read(as, AC97_REG_POWER, &val);
1151 if ((val & AC97_POWER_MIXER) == 0) {
1152 /* Codec doesn't support analogue mixer power-down */
1153 as->power_all &= ~AC97_POWER_ANL;
1154 }
1155 host_if->write(host_if->arg, AC97_REG_POWER, POWER_EAMP_ON(as));
1156
1157 for (i = 500000; i >= 0; i--) {
1158 ac97_read(as, AC97_REG_POWER, &val);
1159 if ((val & as->power_all) == as->power_all)
1160 break;
1161 DELAY(1);
1162 }
1163
1164 /* save AC97_REG_POWER so that we can restore it later */
1165 ac97_read(as, AC97_REG_POWER, &as->power_reg);
1166 } else if (as->type == AC97_CODEC_TYPE_MODEM) {
1167 host_if->write(host_if->arg, AC97_REG_EXT_MODEM_ID, 0);
1168 }
1169
1170 ac97_setup_defaults(as);
1171 if (as->type == AC97_CODEC_TYPE_AUDIO)
1172 ac97_read(as, AC97_REG_RESET, &as->caps);
1173 ac97_read(as, AC97_REG_VENDOR_ID1, &id1);
1174 ac97_read(as, AC97_REG_VENDOR_ID2, &id2);
1175
1176 id = (id1 << 16) | id2;
1177 aprint_normal("%s: ac97: ", sc_dev->dv_xname);
1178
1179 for (i = 0; ; i++) {
1180 if (ac97codecid[i].id == 0) {
1181 char pnp[4];
1182
1183 AC97_GET_CODEC_ID(id, pnp);
1184 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f)
1185 if (ISASCII(pnp[0]) && ISASCII(pnp[1]) &&
1186 ISASCII(pnp[2]))
1187 aprint_normal("%c%c%c%d",
1188 pnp[0], pnp[1], pnp[2], pnp[3]);
1189 else
1190 aprint_normal("unknown (0x%08x)", id);
1191 break;
1192 }
1193 if (ac97codecid[i].id == (id & ac97codecid[i].mask)) {
1194 aprint_normal("%s", ac97codecid[i].name);
1195 if (ac97codecid[i].mask == AC97_VENDOR_ID_MASK) {
1196 aprint_normal(" (0x%08x)", id);
1197 }
1198 initfunc = ac97codecid[i].init;
1199 break;
1200 }
1201 }
1202 aprint_normal(" codec; ");
1203 for (i = j = 0; i < 10; i++) {
1204 if (as->caps & (1 << i)) {
1205 aprint_normal("%s%s", j ? ", " : "", ac97feature[i]);
1206 j++;
1207 }
1208 }
1209 aprint_normal("%s%s\n", j ? ", " : "",
1210 ac97enhancement[AC97_CAPS_ENHANCEMENT(as->caps)]);
1211
1212 as->ac97_clock = AC97_STANDARD_CLOCK;
1213
1214 if (as->type == AC97_CODEC_TYPE_AUDIO) {
1215 ac97_read(as, AC97_REG_EXT_AUDIO_ID, &as->ext_id);
1216 if (as->ext_id != 0) {
1217 /* Print capabilities */
1218 bitmask_snprintf(as->ext_id,
1219 "\20\20SECONDARY10\17SECONDARY01"
1220 "\14AC97_23\13AC97_22\12AMAP\11LDAC\10SDAC"
1221 "\7CDAC\4VRM\3SPDIF\2DRA\1VRA",
1222 flagbuf, FLAGBUFLEN);
1223 aprint_normal("%s: ac97: ext id %s\n", sc_dev->dv_xname,
1224 flagbuf);
1225
1226 /* Print unusual settings */
1227 if (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) {
1228 aprint_normal("%s: ac97: Slot assignment: ",
1229 sc_dev->dv_xname);
1230 switch (as->ext_id & AC97_EXT_AUDIO_DSA_MASK) {
1231 case AC97_EXT_AUDIO_DSA01:
1232 aprint_normal("7&8, 6&9, 10&11.\n");
1233 break;
1234 case AC97_EXT_AUDIO_DSA10:
1235 aprint_normal("6&9, 10&11, 3&4.\n");
1236 break;
1237 case AC97_EXT_AUDIO_DSA11:
1238 aprint_normal("10&11, 3&4, 7&8.\n");
1239 break;
1240 }
1241 }
1242 if (as->host_flags & AC97_HOST_INVERTED_EAMP) {
1243 aprint_normal("%s: ac97: using inverted "
1244 "AC97_POWER_EAMP bit\n",
1245 sc_dev->dv_xname);
1246 }
1247
1248 /* Enable and disable features */
1249 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &extstat);
1250 extstat &= ~AC97_EXT_AUDIO_DRA;
1251 if (as->ext_id & AC97_EXT_AUDIO_LDAC)
1252 extstat |= AC97_EXT_AUDIO_LDAC;
1253 if (as->ext_id & AC97_EXT_AUDIO_SDAC)
1254 extstat |= AC97_EXT_AUDIO_SDAC;
1255 if (as->ext_id & AC97_EXT_AUDIO_CDAC)
1256 extstat |= AC97_EXT_AUDIO_CDAC;
1257 if (as->ext_id & AC97_EXT_AUDIO_VRM)
1258 extstat |= AC97_EXT_AUDIO_VRM;
1259 if (as->ext_id & AC97_EXT_AUDIO_SPDIF) {
1260 /* Output the same data as DAC to SPDIF output */
1261 extstat &= ~AC97_EXT_AUDIO_SPSA_MASK;
1262 extstat |= AC97_EXT_AUDIO_SPSA34;
1263 ac97_read(as, AC97_REG_SPDIF_CTRL, &val);
1264 val = (val & ~AC97_SPDIF_SPSR_MASK)
1265 | AC97_SPDIF_SPSR_48K;
1266 ac97_write(as, AC97_REG_SPDIF_CTRL, val);
1267 }
1268 if (as->ext_id & AC97_EXT_AUDIO_VRA)
1269 extstat |= AC97_EXT_AUDIO_VRA;
1270 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, extstat);
1271 if (as->ext_id & AC97_EXT_AUDIO_VRA) {
1272 /* VRA should be enabled. */
1273 /* so it claims to do variable rate, let's make sure */
1274 ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
1275 44100);
1276 ac97_read(as, AC97_REG_PCM_FRONT_DAC_RATE,
1277 &rate);
1278 if (rate != 44100) {
1279 /* We can't believe ext_id */
1280 as->ext_id = 0;
1281 aprint_normal(
1282 "%s: Ignore these capabilities.\n",
1283 sc_dev->dv_xname);
1284 }
1285 /* restore the default value */
1286 ac97_write(as, AC97_REG_PCM_FRONT_DAC_RATE,
1287 AC97_SINGLE_RATE);
1288 }
1289 }
1290 } else if (as->type == AC97_CODEC_TYPE_MODEM) {
1291 const struct sysctlnode *node;
1292 const struct sysctlnode *node_line1;
1293 const struct sysctlnode *node_line2;
1294 uint16_t xrate = 8000;
1295 uint16_t xval, reg;
1296 int err;
1297
1298 ac97_read(as, AC97_REG_EXT_MODEM_ID, &as->ext_mid);
1299 if (as->ext_mid == 0 || as->ext_mid == 0xffff) {
1300 aprint_normal("%s: no modem codec found\n",
1301 sc_dev->dv_xname);
1302 return ENXIO;
1303 }
1304 as->type = AC97_CODEC_TYPE_MODEM;
1305
1306 /* Print capabilities */
1307 bitmask_snprintf(as->ext_mid,
1308 "\20\5CID2\4CID1\3HANDSET\2LINE2\1LINE1",
1309 flagbuf, FLAGBUFLEN);
1310 aprint_normal("%s: ac97: ext mid %s", sc_dev->dv_xname,
1311 flagbuf);
1312 aprint_normal(", %s codec\n",
1313 (as->ext_mid & 0xc000) == 0 ?
1314 "primary" : "secondary");
1315
1316 /* Setup modem and sysctls */
1317 err = sysctl_createv(&as->log, 0, NULL, NULL, 0, CTLTYPE_NODE,
1318 "hw", NULL, NULL, 0, NULL, 0, CTL_HW,
1319 CTL_EOL);
1320 if (err != 0)
1321 goto setup_modem;
1322 err = sysctl_createv(&as->log, 0, NULL, &node, 0,
1323 CTLTYPE_NODE, sc_dev->dv_xname, NULL,
1324 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE,
1325 CTL_EOL);
1326 if (err != 0)
1327 goto setup_modem;
1328 setup_modem:
1329 /* reset */
1330 ac97_write(as, AC97_REG_EXT_MODEM_ID, 1);
1331
1332 /* program rates */
1333 xval = 0xff00 & ~AC97_EXT_MODEM_CTRL_PRA;
1334 if (as->ext_mid & AC97_EXT_MODEM_LINE1) {
1335 ac97_write(as, AC97_REG_LINE1_RATE, xrate);
1336 xval &= ~(AC97_EXT_MODEM_CTRL_PRC |
1337 AC97_EXT_MODEM_CTRL_PRD);
1338 }
1339 if (as->ext_mid & AC97_EXT_MODEM_LINE2) {
1340 ac97_write(as, AC97_REG_LINE2_RATE, xrate);
1341 xval &= ~(AC97_EXT_MODEM_CTRL_PRE |
1342 AC97_EXT_MODEM_CTRL_PRF);
1343 }
1344 if (as->ext_mid & AC97_EXT_MODEM_HANDSET) {
1345 ac97_write(as, AC97_REG_HANDSET_RATE, xrate);
1346 xval &= ~(AC97_EXT_MODEM_CTRL_PRG |
1347 AC97_EXT_MODEM_CTRL_PRH);
1348 }
1349
1350 /* power-up everything */
1351 ac97_write(as, AC97_REG_EXT_MODEM_CTRL, 0);
1352 for (i = 5000; i >= 0; i--) {
1353 ac97_read(as, AC97_REG_EXT_MODEM_CTRL, ®);
1354 if ((reg & /*XXXval*/0xf) == /*XXXval*/0xf)
1355 break;
1356 DELAY(1);
1357 }
1358 if (i <= 0) {
1359 printf("%s: codec not responding, status=0x%x\n",
1360 sc_dev->dv_xname, reg);
1361 return ENXIO;
1362 }
1363
1364 /* setup sysctls */
1365 if (as->ext_mid & AC97_EXT_MODEM_LINE1) {
1366 ac97_read(as, AC97_REG_GPIO_CFG, ®);
1367 reg &= ~AC97_GPIO_LINE1_OH;
1368 ac97_write(as, AC97_REG_GPIO_CFG, reg);
1369 ac97_read(as, AC97_REG_GPIO_POLARITY, ®);
1370 reg &= ~AC97_GPIO_LINE1_OH;
1371 ac97_write(as, AC97_REG_GPIO_POLARITY, reg);
1372
1373 err = sysctl_createv(&as->log, 0, NULL, &node_line1,
1374 CTLFLAG_READWRITE, CTLTYPE_INT,
1375 "line1",
1376 SYSCTL_DESCR("off-hook line1"),
1377 ac97_sysctl_verify, 0, as, 0,
1378 CTL_HW, node->sysctl_num,
1379 CTL_CREATE, CTL_EOL);
1380 if (err != 0)
1381 goto sysctl_err;
1382 as->offhook_line1_mib = node_line1->sysctl_num;
1383 }
1384 if (as->ext_mid & AC97_EXT_MODEM_LINE2) {
1385 ac97_read(as, AC97_REG_GPIO_CFG, ®);
1386 reg &= ~AC97_GPIO_LINE2_OH;
1387 ac97_write(as, AC97_REG_GPIO_CFG, reg);
1388 ac97_read(as, AC97_REG_GPIO_POLARITY, ®);
1389 reg &= ~AC97_GPIO_LINE2_OH;
1390 ac97_write(as, AC97_REG_GPIO_POLARITY, reg);
1391
1392 err = sysctl_createv(&as->log, 0, NULL, &node_line2,
1393 CTLFLAG_READWRITE, CTLTYPE_INT,
1394 "line2",
1395 SYSCTL_DESCR("off-hook line2"),
1396 ac97_sysctl_verify, 0, as, 0,
1397 CTL_HW, node->sysctl_num,
1398 CTL_CREATE, CTL_EOL);
1399 if (err != 0)
1400 goto sysctl_err;
1401 as->offhook_line2_mib = node_line2->sysctl_num;
1402 }
1403 sysctl_err:
1404
1405 ac97_write(as, AC97_REG_GPIO_STICKY, 0xffff);
1406 ac97_write(as, AC97_REG_GPIO_WAKEUP, 0x0);
1407 ac97_write(as, AC97_REG_MISC_AFE, 0x0);
1408 }
1409
1410 as->source_info = (as->type == AC97_CODEC_TYPE_MODEM ?
1411 as->modem_source_info : as->audio_source_info);
1412 ac97_setup_source_info(as);
1413
1414 memset(&ctl, 0, sizeof(ctl));
1415 /* disable mutes */
1416 for (i = 0; i < 11; i++) {
1417 static struct {
1418 const char *class, *device;
1419 } d[11] = {
1420 { AudioCoutputs, AudioNmaster},
1421 { AudioCoutputs, AudioNheadphone},
1422 { AudioCoutputs, AudioNsurround},
1423 { AudioCoutputs, AudioNcenter},
1424 { AudioCoutputs, AudioNlfe},
1425 { AudioCinputs, AudioNdac},
1426 { AudioCinputs, AudioNcd},
1427 { AudioCinputs, AudioNline},
1428 { AudioCinputs, AudioNaux},
1429 { AudioCinputs, AudioNvideo},
1430 { AudioCrecord, AudioNvolume},
1431 };
1432
1433 ctl.type = AUDIO_MIXER_ENUM;
1434 ctl.un.ord = 0;
1435
1436 ctl.dev = ac97_get_portnum_by_name(&as->codec_if,
1437 d[i].class, d[i].device, AudioNmute);
1438 ac97_mixer_set_port(&as->codec_if, &ctl);
1439 }
1440 ctl.type = AUDIO_MIXER_ENUM;
1441 ctl.un.ord = 0;
1442 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCrecord,
1443 AudioNsource, NULL);
1444 ac97_mixer_set_port(&as->codec_if, &ctl);
1445
1446 /* set a reasonable default volume */
1447 ctl.type = AUDIO_MIXER_VALUE;
1448 ctl.un.value.num_channels = 2;
1449 ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = \
1450 ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 127;
1451 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
1452 AudioNmaster, NULL);
1453 ac97_mixer_set_port(&as->codec_if, &ctl);
1454 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
1455 AudioNsurround, NULL);
1456 ac97_mixer_set_port(&as->codec_if, &ctl);
1457 ctl.un.value.num_channels = 1;
1458 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
1459 AudioNcenter, NULL);
1460 ac97_mixer_set_port(&as->codec_if, &ctl);
1461 ctl.dev = ac97_get_portnum_by_name(&as->codec_if, AudioCoutputs,
1462 AudioNlfe, NULL);
1463 ac97_mixer_set_port(&as->codec_if, &ctl);
1464
1465 if (initfunc != NULL)
1466 initfunc(as);
1467
1468 /* restore AC97_REG_POWER */
1469 if (as->type == AC97_CODEC_TYPE_AUDIO)
1470 ac97_write(as, AC97_REG_POWER, as->power_reg);
1471
1472 return 0;
1473 }
1474
1475 static void
1476 ac97_detach(struct ac97_codec_if *codec_if)
1477 {
1478 struct ac97_softc *as;
1479
1480 as = (struct ac97_softc *)codec_if;
1481 ac97_write(as, AC97_REG_POWER, AC97_POWER_IN | AC97_POWER_OUT
1482 | AC97_POWER_MIXER | AC97_POWER_MIXER_VREF
1483 | AC97_POWER_ACLINK | AC97_POWER_CLK | AC97_POWER_AUX
1484 | POWER_EAMP_OFF(as));
1485 free(as, M_DEVBUF);
1486 }
1487
1488 static void
1489 ac97_lock(struct ac97_codec_if *codec_if)
1490 {
1491 struct ac97_softc *as;
1492
1493 as = (struct ac97_softc *)codec_if;
1494 as->lock_counter++;
1495 }
1496
1497 static void
1498 ac97_unlock(struct ac97_codec_if *codec_if)
1499 {
1500 struct ac97_softc *as;
1501
1502 as = (struct ac97_softc *)codec_if;
1503 as->lock_counter--;
1504 }
1505
1506 static int
1507 ac97_query_devinfo(struct ac97_codec_if *codec_if, mixer_devinfo_t *dip)
1508 {
1509 struct ac97_softc *as;
1510 struct ac97_source_info *si;
1511 const char *name;
1512
1513 as = (struct ac97_softc *)codec_if;
1514 if (dip->index < as->num_source_info) {
1515 si = &as->source_info[dip->index];
1516 dip->type = si->type;
1517 dip->mixer_class = si->mixer_class;
1518 dip->prev = si->prev;
1519 dip->next = si->next;
1520
1521 if (si->qualifier)
1522 name = si->qualifier;
1523 else if (si->device)
1524 name = si->device;
1525 else if (si->class)
1526 name = si->class;
1527 else
1528 name = 0;
1529
1530 if (name)
1531 strcpy(dip->label.name, name);
1532
1533 memcpy(&dip->un, si->info, si->info_size);
1534
1535 /* Set the delta for volume sources */
1536 if (dip->type == AUDIO_MIXER_VALUE)
1537 dip->un.v.delta = 1 << (8 - si->bits);
1538
1539 return 0;
1540 }
1541
1542 return ENXIO;
1543 }
1544
1545 static int
1546 ac97_mixer_set_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
1547 {
1548 struct ac97_softc *as;
1549 struct ac97_source_info *si;
1550 uint16_t mask;
1551 uint16_t val, newval;
1552 int error;
1553 boolean_t spdif;
1554
1555 as = (struct ac97_softc *)codec_if;
1556 if (cp->dev < 0 || cp->dev >= as->num_source_info)
1557 return EINVAL;
1558 si = &as->source_info[cp->dev];
1559
1560 if (cp->type == AUDIO_MIXER_CLASS || cp->type != si->type)
1561 return EINVAL;
1562 spdif = si->req_feature == CHECK_SPDIF && si->reg == AC97_REG_EXT_AUDIO_CTRL;
1563 if (spdif && as->lock_counter >= 0) {
1564 /* When the value of lock_counter is the default 0,
1565 * it is not allowed to change the SPDIF mode. */
1566 return EBUSY;
1567 }
1568
1569 ac97_read(as, si->reg, &val);
1570
1571 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
1572
1573 mask = (1 << si->bits) - 1;
1574
1575 switch (cp->type) {
1576 case AUDIO_MIXER_ENUM:
1577 if (cp->un.ord > mask || cp->un.ord < 0)
1578 return EINVAL;
1579
1580 newval = (cp->un.ord << si->ofs);
1581 if (si->reg == AC97_REG_RECORD_SELECT) {
1582 newval |= (newval << (8 + si->ofs));
1583 mask |= (mask << 8);
1584 mask = mask << si->ofs;
1585 } else if (si->reg == AC97_REG_SURR_MASTER) {
1586 newval = cp->un.ord ? 0x8080 : 0x0000;
1587 mask = 0x8080;
1588 } else
1589 mask = mask << si->ofs;
1590 break;
1591 case AUDIO_MIXER_VALUE:
1592 {
1593 const struct audio_mixer_value *value = si->info;
1594 uint16_t l, r, ol, or;
1595 int deltal, deltar;
1596
1597 if ((cp->un.value.num_channels <= 0) ||
1598 (cp->un.value.num_channels > value->num_channels))
1599 return EINVAL;
1600
1601 if (cp->un.value.num_channels == 1) {
1602 l = r = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
1603 } else {
1604 if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
1605 l = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1606 r = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1607 } else { /* left/right is reversed here */
1608 r = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1609 l = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1610 }
1611
1612 }
1613
1614 if (!si->polarity) {
1615 l = 255 - l;
1616 r = 255 - r;
1617 }
1618
1619 ol = (val >> (8+si->ofs)) & mask;
1620 or = (val >> si->ofs) & mask;
1621
1622 deltal = (ol << (8 - si->bits)) - l;
1623 deltar = (or << (8 - si->bits)) - r;
1624
1625 l = l >> (8 - si->bits);
1626 r = r >> (8 - si->bits);
1627
1628 if (deltal && ol == l)
1629 l += (deltal > 0) ? (l ? -1 : 0) : (l < mask ? 1 : 0);
1630 if (deltar && or == r)
1631 r += (deltar > 0) ? (r ? -1 : 0) : (r < mask ? 1 : 0);
1632
1633 newval = ((r & mask) << si->ofs);
1634 if (value->num_channels == 2) {
1635 newval = newval | ((l & mask) << (si->ofs+8));
1636 mask |= (mask << 8);
1637 }
1638 mask = mask << si->ofs;
1639 break;
1640 }
1641 default:
1642 return EINVAL;
1643 }
1644
1645 error = ac97_write(as, si->reg, (val & ~mask) | newval);
1646 if (error)
1647 return error;
1648
1649 if (spdif && as->host_if->spdif_event != NULL) {
1650 DPRINTF(("%s: call spdif_event(%d)\n", __func__, cp->un.ord));
1651 as->host_if->spdif_event(as->host_if->arg, cp->un.ord);
1652 }
1653 return 0;
1654 }
1655
1656 static int
1657 ac97_get_portnum_by_name(struct ac97_codec_if *codec_if, const char *class,
1658 const char *device, const char *qualifier)
1659 {
1660 struct ac97_softc *as;
1661 int idx;
1662
1663 as = (struct ac97_softc *)codec_if;
1664 for (idx = 0; idx < as->num_source_info; idx++) {
1665 struct ac97_source_info *si = &as->source_info[idx];
1666 if (ac97_str_equal(class, si->class) &&
1667 ac97_str_equal(device, si->device) &&
1668 ac97_str_equal(qualifier, si->qualifier))
1669 return idx;
1670 }
1671
1672 return -1;
1673 }
1674
1675 static int
1676 ac97_mixer_get_port(struct ac97_codec_if *codec_if, mixer_ctrl_t *cp)
1677 {
1678 struct ac97_softc *as;
1679 struct ac97_source_info *si;
1680 uint16_t mask;
1681 uint16_t val;
1682
1683 as = (struct ac97_softc *)codec_if;
1684 si = &as->source_info[cp->dev];
1685 if (cp->dev < 0 || cp->dev >= as->num_source_info)
1686 return EINVAL;
1687
1688 if (cp->type != si->type)
1689 return EINVAL;
1690
1691 ac97_read(as, si->reg, &val);
1692
1693 DPRINTFN(5, ("read(%x) = %x\n", si->reg, val));
1694
1695 mask = (1 << si->bits) - 1;
1696
1697 switch (cp->type) {
1698 case AUDIO_MIXER_ENUM:
1699 cp->un.ord = (val >> si->ofs) & mask;
1700 DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n",
1701 val, si->ofs, mask, cp->un.ord));
1702 break;
1703 case AUDIO_MIXER_VALUE:
1704 {
1705 const struct audio_mixer_value *value = si->info;
1706 uint16_t l, r;
1707
1708 if ((cp->un.value.num_channels <= 0) ||
1709 (cp->un.value.num_channels > value->num_channels))
1710 return EINVAL;
1711
1712 if (value->num_channels == 1) {
1713 l = r = (val >> si->ofs) & mask;
1714 } else {
1715 if (!(as->host_flags & AC97_HOST_SWAPPED_CHANNELS)) {
1716 l = (val >> (si->ofs + 8)) & mask;
1717 r = (val >> si->ofs) & mask;
1718 } else { /* host has reversed channels */
1719 r = (val >> (si->ofs + 8)) & mask;
1720 l = (val >> si->ofs) & mask;
1721 }
1722 }
1723
1724 l = (l << (8 - si->bits));
1725 r = (r << (8 - si->bits));
1726 if (!si->polarity) {
1727 l = 255 - l;
1728 r = 255 - r;
1729 }
1730
1731 /* The EAP driver averages l and r for stereo
1732 channels that are requested in MONO mode. Does this
1733 make sense? */
1734 if (cp->un.value.num_channels == 1) {
1735 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = l;
1736 } else if (cp->un.value.num_channels == 2) {
1737 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
1738 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
1739 }
1740
1741 break;
1742 }
1743 default:
1744 return EINVAL;
1745 }
1746
1747 return 0;
1748 }
1749
1750
1751 static int
1752 ac97_set_rate(struct ac97_codec_if *codec_if, int target, u_int *rate)
1753 {
1754 struct ac97_softc *as;
1755 u_int value;
1756 uint16_t ext_stat;
1757 uint16_t actual;
1758 uint16_t power;
1759 uint16_t power_bit;
1760
1761 as = (struct ac97_softc *)codec_if;
1762 if (target == AC97_REG_PCM_MIC_ADC_RATE) {
1763 if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
1764 *rate = AC97_SINGLE_RATE;
1765 return 0;
1766 }
1767 } else {
1768 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
1769 *rate = AC97_SINGLE_RATE;
1770 return 0;
1771 }
1772 }
1773 value = *rate * AC97_STANDARD_CLOCK / as->ac97_clock;
1774 ext_stat = 0;
1775 /*
1776 * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE
1777 * Check VRA, DRA
1778 * PCM_LR_ADC_RATE
1779 * Check VRA
1780 * PCM_MIC_ADC_RATE
1781 * Check VRM
1782 */
1783 switch (target) {
1784 case AC97_REG_PCM_FRONT_DAC_RATE:
1785 case AC97_REG_PCM_SURR_DAC_RATE:
1786 case AC97_REG_PCM_LFE_DAC_RATE:
1787 power_bit = AC97_POWER_OUT;
1788 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
1789 *rate = AC97_SINGLE_RATE;
1790 return 0;
1791 }
1792 if (as->ext_id & AC97_EXT_AUDIO_DRA) {
1793 ac97_read(as, AC97_REG_EXT_AUDIO_CTRL, &ext_stat);
1794 if (value > 0x1ffff) {
1795 return EINVAL;
1796 } else if (value > 0xffff) {
1797 /* Enable DRA */
1798 ext_stat |= AC97_EXT_AUDIO_DRA;
1799 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
1800 value /= 2;
1801 } else {
1802 /* Disable DRA */
1803 ext_stat &= ~AC97_EXT_AUDIO_DRA;
1804 ac97_write(as, AC97_REG_EXT_AUDIO_CTRL, ext_stat);
1805 }
1806 } else {
1807 if (value > 0xffff)
1808 return EINVAL;
1809 }
1810 break;
1811 case AC97_REG_PCM_LR_ADC_RATE:
1812 power_bit = AC97_POWER_IN;
1813 if (!(as->ext_id & AC97_EXT_AUDIO_VRA)) {
1814 *rate = AC97_SINGLE_RATE;
1815 return 0;
1816 }
1817 if (value > 0xffff)
1818 return EINVAL;
1819 break;
1820 case AC97_REG_PCM_MIC_ADC_RATE:
1821 power_bit = AC97_POWER_IN;
1822 if (!(as->ext_id & AC97_EXT_AUDIO_VRM)) {
1823 *rate = AC97_SINGLE_RATE;
1824 return 0;
1825 }
1826 if (value > 0xffff)
1827 return EINVAL;
1828 break;
1829 default:
1830 printf("%s: Unknown register: 0x%x\n", __func__, target);
1831 return EINVAL;
1832 }
1833
1834 ac97_read(as, AC97_REG_POWER, &power);
1835 ac97_write(as, AC97_REG_POWER, power | power_bit);
1836
1837 ac97_write(as, target, (uint16_t)value);
1838 ac97_read(as, target, &actual);
1839 actual = (uint32_t)actual * as->ac97_clock / AC97_STANDARD_CLOCK;
1840
1841 ac97_write(as, AC97_REG_POWER, power);
1842 if (ext_stat & AC97_EXT_AUDIO_DRA) {
1843 *rate = actual * 2;
1844 } else {
1845 *rate = actual;
1846 }
1847 return 0;
1848 }
1849
1850 static void
1851 ac97_set_clock(struct ac97_codec_if *codec_if, unsigned int clock)
1852 {
1853 struct ac97_softc *as;
1854
1855 as = (struct ac97_softc *)codec_if;
1856 as->ac97_clock = clock;
1857 }
1858
1859 static uint16_t
1860 ac97_get_extcaps(struct ac97_codec_if *codec_if)
1861 {
1862 struct ac97_softc *as;
1863
1864 as = (struct ac97_softc *)codec_if;
1865 return as->ext_id;
1866 }
1867
1868 static int
1869 ac97_add_port(struct ac97_softc *as, const struct ac97_source_info *src)
1870 {
1871 struct ac97_source_info *si;
1872 int ouridx, idx;
1873
1874 if ((as->type == AC97_CODEC_TYPE_AUDIO &&
1875 as->num_source_info >= AUDIO_MAX_SOURCES) ||
1876 (as->type == AC97_CODEC_TYPE_MODEM &&
1877 as->num_source_info >= MODEM_MAX_SOURCES)) {
1878 printf("%s: internal error: increase MAX_SOURCES in %s\n",
1879 __func__, __FILE__);
1880 return -1;
1881 }
1882 if (!ac97_check_capability(as, src->req_feature))
1883 return -1;
1884 ouridx = as->num_source_info;
1885 si = &as->source_info[ouridx];
1886 memcpy(si, src, sizeof(*si));
1887
1888 switch (si->type) {
1889 case AUDIO_MIXER_CLASS:
1890 case AUDIO_MIXER_VALUE:
1891 printf("%s: adding class/value is not supported yet.\n",
1892 __func__);
1893 return -1;
1894 case AUDIO_MIXER_ENUM:
1895 break;
1896 default:
1897 printf("%s: unknown type: %d\n", __func__, si->type);
1898 return -1;
1899 }
1900 as->num_source_info++;
1901
1902 si->mixer_class = ac97_get_portnum_by_name(&as->codec_if, si->class,
1903 NULL, NULL);
1904 /* Find the root of the device */
1905 idx = ac97_get_portnum_by_name(&as->codec_if, si->class,
1906 si->device, NULL);
1907 /* Find the last item */
1908 while (as->source_info[idx].next != AUDIO_MIXER_LAST)
1909 idx = as->source_info[idx].next;
1910 /* Append */
1911 as->source_info[idx].next = ouridx;
1912 si->prev = idx;
1913 si->next = AUDIO_MIXER_LAST;
1914
1915 return 0;
1916 }
1917
1918 /**
1919 * Codec-dependent initialization
1920 */
1921
1922 #define AD1980_REG_MISC 0x76
1923 #define AD1980_MISC_MBG0 0x0001 /* 0 1888/1980/1981 /1985 */
1924 #define AD1980_MISC_MBG1 0x0002 /* 1 1888/1980/1981 /1985 */
1925 #define AD1980_MISC_VREFD 0x0004 /* 2 1888/1980/1981 /1985 */
1926 #define AD1980_MISC_VREFH 0x0008 /* 3 1888/1980/1981 /1985 */
1927 #define AD1980_MISC_SRU 0x0010 /* 4 1888/1980 /1985 */
1928 #define AD1980_MISC_LOSEL 0x0020 /* 5 1888/1980/1981 /1985 */
1929 #define AD1980_MISC_2CMIC 0x0040 /* 6 1980/1981B/1985 */
1930 #define AD1980_MISC_SPRD 0x0080 /* 7 1888/1980 /1985 */
1931 #define AD1980_MISC_DMIX0 0x0100 /* 8 1888/1980 /1985 */
1932 #define AD1980_MISC_DMIX1 0x0200 /* 9 1888/1980 /1985 */
1933 #define AD1980_MISC_HPSEL 0x0400 /*10 1888/1980 /1985 */
1934 #define AD1980_MISC_CLDIS 0x0800 /*11 1888/1980 /1985 */
1935 #define AD1980_MISC_LODIS 0x1000 /*12 1888/1980/1981 /1985 */
1936 #define AD1980_MISC_MSPLT 0x2000 /*13 1888/1980/1981 /1985 */
1937 #define AD1980_MISC_AC97NC 0x4000 /*14 1888/1980 /1985 */
1938 #define AD1980_MISC_DACZ 0x8000 /*15 1888/1980/1981 /1985 */
1939 #define AD1981_REG_MISC 0x76
1940 #define AD1981_MISC_MADST 0x0010 /* 4 */
1941 #define AD1981A_MISC_MADPD 0x0040 /* 6 */
1942 #define AD1981B_MISC_MADPD 0x0080 /* 7 */
1943 #define AD1981_MISC_FMXE 0x0200 /* 9 */
1944 #define AD1981_MISC_DAM 0x0800 /*11 */
1945 static void
1946 ac97_ad198x_init(struct ac97_softc *as)
1947 {
1948 int i;
1949 uint16_t misc;
1950
1951 ac97_read(as, AD1980_REG_MISC, &misc);
1952 ac97_write(as, AD1980_REG_MISC,
1953 misc | AD1980_MISC_LOSEL | AD1980_MISC_HPSEL);
1954
1955 for (i = 0; i < as->num_source_info; i++) {
1956 if (as->source_info[i].type != AUDIO_MIXER_VALUE)
1957 continue;
1958
1959 if (as->source_info[i].reg == AC97_REG_MASTER_VOLUME)
1960 as->source_info[i].reg = AC97_REG_SURR_MASTER;
1961 else if (as->source_info[i].reg == AC97_REG_SURR_MASTER)
1962 as->source_info[i].reg = AC97_REG_MASTER_VOLUME;
1963 }
1964 }
1965
1966 #define ALC650_REG_MULTI_CHANNEL_CONTROL 0x6a
1967 #define ALC650_MCC_SLOT_MODIFY_MASK 0xc000
1968 #define ALC650_MCC_FRONTDAC_FROM_SPDIFIN 0x2000 /* 13 */
1969 #define ALC650_MCC_SPDIFOUT_FROM_ADC 0x1000 /* 12 */
1970 #define ALC650_MCC_PCM_FROM_SPDIFIN 0x0800 /* 11 */
1971 #define ALC650_MCC_MIC_OR_CENTERLFE 0x0400 /* 10 */
1972 #define ALC650_MCC_LINEIN_OR_SURROUND 0x0200 /* 9 */
1973 #define ALC650_MCC_INDEPENDENT_MASTER_L 0x0080 /* 7 */
1974 #define ALC650_MCC_INDEPENDENT_MASTER_R 0x0040 /* 6 */
1975 #define ALC650_MCC_ANALOG_TO_CENTERLFE 0x0020 /* 5 */
1976 #define ALC650_MCC_ANALOG_TO_SURROUND 0x0010 /* 4 */
1977 #define ALC650_MCC_EXCHANGE_CENTERLFE 0x0008 /* 3 */
1978 #define ALC650_MCC_CENTERLFE_DOWNMIX 0x0004 /* 2 */
1979 #define ALC650_MCC_SURROUND_DOWNMIX 0x0002 /* 1 */
1980 #define ALC650_MCC_LINEOUT_TO_SURROUND 0x0001 /* 0 */
1981 static void
1982 ac97_alc650_init(struct ac97_softc *as)
1983 {
1984 static const struct ac97_source_info sources[6] = {
1985 { AudioCoutputs, AudioNsurround, "lineinjack",
1986 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1987 ALC650_REG_MULTI_CHANNEL_CONTROL,
1988 0x0000, 1, 9, 0, 0, 0, CHECK_SURROUND },
1989 { AudioCoutputs, AudioNsurround, "mixtofront",
1990 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1991 ALC650_REG_MULTI_CHANNEL_CONTROL,
1992 0x0000, 1, 1, 0, 0, 0, CHECK_SURROUND },
1993 { AudioCoutputs, AudioNcenter, "micjack",
1994 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1995 ALC650_REG_MULTI_CHANNEL_CONTROL,
1996 0x0000, 1, 10, 0, 0, 0, CHECK_CENTER },
1997 { AudioCoutputs, AudioNlfe, "micjack",
1998 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
1999 ALC650_REG_MULTI_CHANNEL_CONTROL,
2000 0x0000, 1, 10, 0, 0, 0, CHECK_LFE },
2001 { AudioCoutputs, AudioNcenter, "mixtofront",
2002 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
2003 ALC650_REG_MULTI_CHANNEL_CONTROL,
2004 0x0000, 1, 2, 0, 0, 0, CHECK_CENTER },
2005 { AudioCoutputs, AudioNlfe, "mixtofront",
2006 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
2007 ALC650_REG_MULTI_CHANNEL_CONTROL,
2008 0x0000, 1, 2, 0, 0, 0, CHECK_LFE },
2009 };
2010
2011 ac97_add_port(as, &sources[0]);
2012 ac97_add_port(as, &sources[1]);
2013 ac97_add_port(as, &sources[2]);
2014 ac97_add_port(as, &sources[3]);
2015 ac97_add_port(as, &sources[4]);
2016 ac97_add_port(as, &sources[5]);
2017 }
2018
2019 #define VT1616_REG_IO_CONTROL 0x5a
2020 #define VT1616_IC_LVL (1 << 15)
2021 #define VT1616_IC_LFECENTER_TO_FRONT (1 << 12)
2022 #define VT1616_IC_SURROUND_TO_FRONT (1 << 11)
2023 #define VT1616_IC_BPDC (1 << 10)
2024 #define VT1616_IC_DC (1 << 9)
2025 #define VT1616_IC_IB_MASK 0x000c
2026 static void
2027 ac97_vt1616_init(struct ac97_softc *as)
2028 {
2029 static const struct ac97_source_info sources[3] = {
2030 { AudioCoutputs, AudioNsurround, "mixtofront",
2031 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
2032 VT1616_REG_IO_CONTROL,
2033 0x0000, 1, 11, 0, 0, 0, CHECK_SURROUND },
2034 { AudioCoutputs, AudioNcenter, "mixtofront",
2035 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
2036 VT1616_REG_IO_CONTROL,
2037 0x0000, 1, 12, 0, 0, 0, CHECK_CENTER },
2038 { AudioCoutputs, AudioNlfe, "mixtofront",
2039 AUDIO_MIXER_ENUM, WRAP(ac97_on_off),
2040 VT1616_REG_IO_CONTROL,
2041 0x0000, 1, 12, 0, 0, 0, CHECK_LFE },
2042 };
2043
2044 ac97_add_port(as, &sources[0]);
2045 ac97_add_port(as, &sources[1]);
2046 ac97_add_port(as, &sources[2]);
2047 }
2048
2049 static int
2050 ac97_modem_offhook_set(struct ac97_softc *as, int line, int newval)
2051 {
2052 uint16_t val;
2053
2054 val = as->shadow_reg[AC97_REG_GPIO_STATUS >> 1];
2055 switch (newval) {
2056 case 0:
2057 val &= ~line;
2058 break;
2059 case 1:
2060 val |= line;
2061 break;
2062 }
2063 ac97_write(as, AC97_REG_GPIO_STATUS, val);
2064
2065 return 0;
2066 }
2067
2068 static int
2069 ac97_sysctl_verify(SYSCTLFN_ARGS)
2070 {
2071 int error, tmp;
2072 struct sysctlnode node;
2073 struct ac97_softc *as;
2074
2075 node = *rnode;
2076 as = rnode->sysctl_data;
2077 if (node.sysctl_num == as->offhook_line1_mib) {
2078 tmp = as->offhook_line1;
2079 node.sysctl_data = &tmp;
2080 error = sysctl_lookup(SYSCTLFN_CALL(&node));
2081 if (error || newp == NULL)
2082 return error;
2083
2084 if (tmp < 0 || tmp > 1)
2085 return EINVAL;
2086
2087 as->offhook_line1 = tmp;
2088 ac97_modem_offhook_set(as, AC97_GPIO_LINE1_OH, tmp);
2089 } else if (node.sysctl_num == as->offhook_line2_mib) {
2090 tmp = as->offhook_line2;
2091 node.sysctl_data = &tmp;
2092 error = sysctl_lookup(SYSCTLFN_CALL(&node));
2093 if (error || newp == NULL)
2094 return error;
2095
2096 if (tmp < 0 || tmp > 1)
2097 return EINVAL;
2098
2099 as->offhook_line2 = tmp;
2100 ac97_modem_offhook_set(as, AC97_GPIO_LINE2_OH, tmp);
2101 }
2102
2103 return 0;
2104 }
2105