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