1 /* $NetBSD: ac97.c,v 1.90 2009/05/12 14:25:17 cegger Exp $ */
2 /* $OpenBSD: ac97.c,v 1.8 2000/07/19 09:01:35 csapuntz Exp $ */
5 * Copyright (c) 1999, 2000 Constantine Sapuntzakis
7 * Author: Constantine Sapuntzakis <csapuntz@stanford.edu>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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
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
34 /* Partially inspired by FreeBSD's sys/dev/pcm/ac97.c. It came with
35 the following copyright */
38 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
39 * All rights reserved.
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
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.
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
65 #include <sys/cdefs.h>
66 __KERNEL_RCSID(0, "$NetBSD: ac97.c,v 1.90 2009/05/12 14:25:17 cegger Exp $");
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>
75 #include <sys/audioio.h>
76 #include <dev/audio_if.h>
78 #include <dev/ic/ac97reg.h>
79 #include <dev/ic/ac97var.h>
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);
104 static void ac97_ad198x_init(struct ac97_softc
*);
105 static void ac97_alc650_init(struct ac97_softc
*);
106 static void ac97_ucb1400_init(struct ac97_softc
*);
107 static void ac97_vt1616_init(struct ac97_softc
*);
109 static int ac97_modem_offhook_set(struct ac97_softc
*, int, int);
110 static int ac97_sysctl_verify(SYSCTLFN_ARGS
);
112 #define Ac97Nphone "phone"
113 #define Ac97Nline1 "line1"
114 #define Ac97Nline2 "line2"
115 #define Ac97Nhandset "handset"
117 static const struct audio_mixer_enum
118 ac97_on_off
= { 2, { { { AudioNoff
, 0 } , 0 },
119 { { AudioNon
, 0 } , 1 },
149 { { "", 0 } , 0 }, } };
151 static const struct audio_mixer_enum
152 ac97_mic_select
= { 2, { { { AudioNmicrophone
"0", 0 }, 0 },
153 { { AudioNmicrophone
"1", 0 }, 1 },
183 { { "", 0 } , 0 }, } };
185 static const struct audio_mixer_enum
186 ac97_mono_select
= { 2, { { { AudioNmixerout
, 0 }, 0 },
187 { { AudioNmicrophone
, 0 }, 1 },
217 { { "", 0 } , 0 }, } };
219 static const struct audio_mixer_enum
220 ac97_source
= { 8, { { { AudioNmicrophone
, 0 } , 0 },
221 { { AudioNcd
, 0 }, 1 },
222 { { AudioNvideo
, 0 }, 2 },
223 { { AudioNaux
, 0 }, 3 },
224 { { AudioNline
, 0 }, 4 },
225 { { AudioNmixerout
, 0 }, 5 },
226 { { AudioNmixerout AudioNmono
, 0 }, 6 },
227 { { Ac97Nphone
, 0 }, 7 },
251 { { "", 0 } , 0 }, } };
254 * Due to different values for each source that uses these structures,
255 * the ac97_query_devinfo function sets delta in mixer_devinfo_t using
256 * ac97_source_info.bits.
258 static const struct audio_mixer_value
259 ac97_volume_stereo
= { { AudioNvolume
, 0 }, 2, 0 };
261 static const struct audio_mixer_value
262 ac97_volume_mono
= { { AudioNvolume
, 0 }, 1, 0 };
264 #define WRAP(a) &a, sizeof(a)
266 struct ac97_source_info
{
269 const char *qualifier
;
276 int32_t default_value
;
280 unsigned polarity
:1; /* Does 0 == MAX or MIN */
281 unsigned checkbits
:1;
303 static const struct ac97_source_info audio_source_info
[] = {
304 { AudioCinputs
, NULL
, NULL
,
305 AUDIO_MIXER_CLASS
, NULL
, 0,
306 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
307 { AudioCoutputs
, NULL
, 0,
308 AUDIO_MIXER_CLASS
, NULL
, 0,
309 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
310 { AudioCrecord
, NULL
, 0,
311 AUDIO_MIXER_CLASS
, NULL
, 0,
312 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
313 /* Stereo master volume*/
314 { AudioCoutputs
, AudioNmaster
, 0,
315 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_stereo
),
316 AC97_REG_MASTER_VOLUME
, 0x8000, 5, 0, 1, 0, 1, 0, 0, 0, 0,
319 { AudioCoutputs
, AudioNmono
, NULL
,
320 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_mono
),
321 AC97_REG_MASTER_VOLUME_MONO
, 0x8000, 6, 0, 1, 0, 1, 0, 0, 0, 0,
323 { AudioCoutputs
, AudioNmono
, AudioNsource
,
324 AUDIO_MIXER_ENUM
, WRAP(ac97_mono_select
),
325 AC97_REG_GP
, 0x0000, 1, 9, 0, 0, 0, 0, 0, 0, 0,
327 /* Headphone volume */
328 { AudioCoutputs
, AudioNheadphone
, NULL
,
329 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_stereo
),
330 AC97_REG_HEADPHONE_VOLUME
, 0x8000, 5, 0, 1, 0, 1, CHECK_HEADPHONES
, 0, 0, 0,
332 /* Surround volume - logic hard coded for mute */
333 { AudioCoutputs
, AudioNsurround
, NULL
,
334 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_stereo
),
335 AC97_REG_SURR_MASTER
, 0x8080, 5, 0, 1, 0, 1, CHECK_SURROUND
, 0, 0, 0
338 { AudioCoutputs
, AudioNcenter
, NULL
,
339 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_mono
),
340 AC97_REG_CENTER_LFE_MASTER
, 0x8080, 5, 0, 0, 0, 1, CHECK_CENTER
, 0, 0, 0
342 { AudioCoutputs
, AudioNcenter
, AudioNmute
,
343 AUDIO_MIXER_ENUM
, WRAP(ac97_on_off
),
344 AC97_REG_CENTER_LFE_MASTER
, 0x8080, 1, 7, 0, 0, 0, CHECK_CENTER
, 0, 0, 0
347 { AudioCoutputs
, AudioNlfe
, NULL
,
348 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_mono
),
349 AC97_REG_CENTER_LFE_MASTER
, 0x8080, 5, 8, 0, 0, 1, CHECK_LFE
, 0, 0, 0
351 { AudioCoutputs
, AudioNlfe
, AudioNmute
,
352 AUDIO_MIXER_ENUM
, WRAP(ac97_on_off
),
353 AC97_REG_CENTER_LFE_MASTER
, 0x8080, 1, 15, 0, 0, 0, CHECK_LFE
, 0, 0, 0
356 { AudioCoutputs
, AudioNbass
, NULL
,
357 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_mono
),
358 AC97_REG_MASTER_TONE
, 0x0f0f, 4, 8, 0, 0, 0, CHECK_TONE
, 0, 0, 0
361 { AudioCoutputs
, AudioNtreble
, NULL
,
362 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_mono
),
363 AC97_REG_MASTER_TONE
, 0x0f0f, 4, 0, 0, 0, 0, CHECK_TONE
, 0, 0, 0
366 { AudioCinputs
, AudioNspeaker
, NULL
,
367 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_mono
),
368 AC97_REG_PCBEEP_VOLUME
, 0x0000, 4, 1, 1, 0, 0, 0, 0, 0, 0,
372 { AudioCinputs
, Ac97Nphone
, NULL
,
373 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_mono
),
374 AC97_REG_PHONE_VOLUME
, 0x8008, 5, 0, 1, 0, 0, 0, 0, 0, 0,
377 { AudioCinputs
, AudioNmicrophone
, NULL
,
378 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_mono
),
379 AC97_REG_MIC_VOLUME
, 0x8008, 5, 0, 1, 0, 0, 0, 0, 0, 0,
381 { AudioCinputs
, AudioNmicrophone
, AudioNpreamp
,
382 AUDIO_MIXER_ENUM
, WRAP(ac97_on_off
),
383 AC97_REG_MIC_VOLUME
, 0x8008, 1, 6, 0, 0, 0, 0, 0, 0, 0,
385 { AudioCinputs
, AudioNmicrophone
, AudioNsource
,
386 AUDIO_MIXER_ENUM
, WRAP(ac97_mic_select
),
387 AC97_REG_GP
, 0x0000, 1, 8, 0, 0, 0, 0, 0, 0, 0,
390 { AudioCinputs
, AudioNline
, NULL
,
391 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_stereo
),
392 AC97_REG_LINEIN_VOLUME
, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
395 { AudioCinputs
, AudioNcd
, NULL
,
396 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_stereo
),
397 AC97_REG_CD_VOLUME
, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
400 { AudioCinputs
, AudioNvideo
, NULL
,
401 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_stereo
),
402 AC97_REG_VIDEO_VOLUME
, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
405 { AudioCinputs
, AudioNaux
, NULL
,
406 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_stereo
),
407 AC97_REG_AUX_VOLUME
, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
410 { AudioCinputs
, AudioNdac
, NULL
,
411 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_stereo
),
412 AC97_REG_PCMOUT_VOLUME
, 0x8808, 5, 0, 1, 0, 0, 0, 0, 0, 0,
414 /* Record Source - some logic for this is hard coded - see below */
415 { AudioCrecord
, AudioNsource
, NULL
,
416 AUDIO_MIXER_ENUM
, WRAP(ac97_source
),
417 AC97_REG_RECORD_SELECT
, 0x0000, 3, 0, 0, 0, 0, 0, 0, 0, 0,
420 { AudioCrecord
, AudioNvolume
, NULL
,
421 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_stereo
),
422 AC97_REG_RECORD_GAIN
, 0x8000, 4, 0, 1, 1, 0, 0, 0, 0, 0,
424 /* Record Gain mic */
425 { AudioCrecord
, AudioNmicrophone
, NULL
,
426 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_mono
),
427 AC97_REG_RECORD_GAIN_MIC
, 0x8000, 4, 0, 1, 1, 0, CHECK_MIC
, 0, 0, 0
430 { AudioCoutputs
, AudioNloudness
, NULL
,
431 AUDIO_MIXER_ENUM
, WRAP(ac97_on_off
),
432 AC97_REG_GP
, 0x0000, 1, 12, 0, 0, 0, CHECK_LOUDNESS
, 0, 0, 0
434 { AudioCoutputs
, AudioNspatial
, NULL
,
435 AUDIO_MIXER_ENUM
, WRAP(ac97_on_off
),
436 AC97_REG_GP
, 0x0000, 1, 13, 0, 1, 0, CHECK_3D
, 0, 0, 0
438 { AudioCoutputs
, AudioNspatial
, "center",
439 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_mono
),
440 AC97_REG_3D_CONTROL
, 0x0000, 4, 8, 0, 1, 0, CHECK_3D
, 0, 0, 0
442 { AudioCoutputs
, AudioNspatial
, "depth",
443 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_mono
),
444 AC97_REG_3D_CONTROL
, 0x0000, 4, 0, 0, 1, 0, CHECK_3D
, 0, 0, 0
448 { "spdif", NULL
, NULL
,
449 AUDIO_MIXER_CLASS
, NULL
, 0,
450 0, 0, 0, 0, 0, 0, 0, CHECK_SPDIF
, 0, 0, 0
452 { "spdif", "enable", NULL
,
453 AUDIO_MIXER_ENUM
, WRAP(ac97_on_off
),
454 AC97_REG_EXT_AUDIO_CTRL
, -1, 1, 2, 0, 0, 0, CHECK_SPDIF
, 0, 0, 0
457 /* Missing features: Simulated Stereo, POP, Loopback mode */
460 static const struct ac97_source_info modem_source_info
[] = {
462 { AudioCinputs
, NULL
, NULL
,
463 AUDIO_MIXER_CLASS
, NULL
, 0,
464 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
465 { AudioCoutputs
, NULL
, NULL
,
466 AUDIO_MIXER_CLASS
, NULL
, 0,
467 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
468 { AudioCinputs
, Ac97Nline1
, NULL
,
469 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_mono
),
470 AC97_REG_LINE1_LEVEL
, 0x8080, 4, 0, 0, 1, 0, CHECK_LINE1
, 0, 0, 0
472 { AudioCoutputs
, Ac97Nline1
, NULL
,
473 AUDIO_MIXER_VALUE
, WRAP(ac97_volume_mono
),
474 AC97_REG_LINE1_LEVEL
, 0x8080, 4, 8, 0, 1, 0, CHECK_LINE1
, 0, 0, 0
476 { AudioCinputs
, Ac97Nline1
, AudioNmute
,
477 AUDIO_MIXER_ENUM
, WRAP(ac97_on_off
),
478 AC97_REG_LINE1_LEVEL
, 0x8080, 1, 7, 0, 0, 0, CHECK_LINE1
, 0, 0, 0
480 { AudioCoutputs
, Ac97Nline1
, AudioNmute
,
481 AUDIO_MIXER_ENUM
, WRAP(ac97_on_off
),
482 AC97_REG_LINE1_LEVEL
, 0x8080, 1, 15, 0, 0, 0, CHECK_LINE1
, 0, 0, 0
486 #define AUDIO_SOURCE_INFO_SIZE \
487 (sizeof(audio_source_info)/sizeof(audio_source_info[0]))
488 #define MODEM_SOURCE_INFO_SIZE \
489 (sizeof(modem_source_info)/sizeof(modem_source_info[0]))
490 #define SOURCE_INFO_SIZE(as) ((as)->type == AC97_CODEC_TYPE_MODEM ? \
491 MODEM_SOURCE_INFO_SIZE : AUDIO_SOURCE_INFO_SIZE)
494 * Check out http://www.intel.com/support/motherboards/desktop/sb/cs-025406.htm for
495 * AC'97 Component Specification
499 /* ac97_codec_if must be at the first of ac97_softc. */
500 struct ac97_codec_if codec_if
;
502 struct ac97_host_if
*host_if
;
504 #define AUDIO_MAX_SOURCES (2 * AUDIO_SOURCE_INFO_SIZE)
505 #define MODEM_MAX_SOURCES (2 * MODEM_SOURCE_INFO_SIZE)
506 struct ac97_source_info audio_source_info
[AUDIO_MAX_SOURCES
];
507 struct ac97_source_info modem_source_info
[MODEM_MAX_SOURCES
];
508 struct ac97_source_info
*source_info
;
511 enum ac97_host_flags host_flags
;
512 unsigned int ac97_clock
; /* usually 48000 */
513 #define AC97_STANDARD_CLOCK 48000U
515 uint16_t power_reg
; /* -> AC97_REG_POWER */
516 uint16_t caps
; /* -> AC97_REG_RESET */
517 uint16_t ext_id
; /* -> AC97_REG_EXT_AUDIO_ID */
518 uint16_t ext_mid
; /* -> AC97_REG_EXT_MODEM_ID */
519 uint16_t shadow_reg
[128];
525 struct sysctllog
*log
;
526 int offhook_line1_mib
;
527 int offhook_line2_mib
;
532 static struct ac97_codec_if_vtbl ac97civ
= {
536 ac97_get_portnum_by_name
,
546 static const struct ac97_codecid
{
550 void (*init
)(struct ac97_softc
*);
553 * Analog Devices SoundMAX
554 * http://www.soundmax.com/products/information/codecs.html
555 * http://www.analog.com/productSelection/pdf/AD1881A_0.pdf
556 * http://www.analog.com/productSelection/pdf/AD1885_0.pdf
557 * http://www.analog.com/UploadedFiles/Data_Sheets/206585810AD1980_0.pdf
558 * http://www.analog.com/productSelection/pdf/AD1981A_0.pdf
559 * http://www.analog.com/productSelection/pdf/AD1981B_0.pdf
560 * http://www.analog.com/UploadedFiles/Data_Sheets/180644528AD1985_0.pdf
562 { AC97_CODEC_ID('A', 'D', 'S', 3),
563 0xffffffff, "Analog Devices AD1819B", NULL
, },
564 { AC97_CODEC_ID('A', 'D', 'S', 0x40),
565 0xffffffff, "Analog Devices AD1881", NULL
, },
566 { AC97_CODEC_ID('A', 'D', 'S', 0x48),
567 0xffffffff, "Analog Devices AD1881A", NULL
, },
568 { AC97_CODEC_ID('A', 'D', 'S', 0x60),
569 0xffffffff, "Analog Devices AD1885", NULL
, },
570 { AC97_CODEC_ID('A', 'D', 'S', 0x61),
571 0xffffffff, "Analog Devices AD1886", NULL
, },
572 { AC97_CODEC_ID('A', 'D', 'S', 0x63),
573 0xffffffff, "Analog Devices AD1886A", NULL
, },
574 { AC97_CODEC_ID('A', 'D', 'S', 0x68),
575 0xffffffff, "Analog Devices AD1888", ac97_ad198x_init
},
576 { AC97_CODEC_ID('A', 'D', 'S', 0x70),
577 0xffffffff, "Analog Devices AD1980", ac97_ad198x_init
},
578 { AC97_CODEC_ID('A', 'D', 'S', 0x72),
579 0xffffffff, "Analog Devices AD1981A", NULL
, },
580 { AC97_CODEC_ID('A', 'D', 'S', 0x74),
581 0xffffffff, "Analog Devices AD1981B", NULL
, },
582 { AC97_CODEC_ID('A', 'D', 'S', 0x75),
583 0xffffffff, "Analog Devices AD1985", ac97_ad198x_init
},
584 { AC97_CODEC_ID('A', 'D', 'S', 0),
585 AC97_VENDOR_ID_MASK
, "Analog Devices unknown", NULL
, },
589 * http://www.asahi-kasei.co.jp/akm/japanese/product/ak4543/ek4543.pdf
590 * http://www.asahi-kasei.co.jp/akm/japanese/product/ak4544a/ek4544a.pdf
591 * http://www.asahi-kasei.co.jp/akm/japanese/product/ak4545/ak4545_f00e.pdf
593 { AC97_CODEC_ID('A', 'K', 'M', 0),
594 0xffffffff, "Asahi Kasei AK4540", NULL
, },
595 { AC97_CODEC_ID('A', 'K', 'M', 1),
596 0xffffffff, "Asahi Kasei AK4542", NULL
, },
597 { AC97_CODEC_ID('A', 'K', 'M', 2),
598 0xffffffff, "Asahi Kasei AK4541/AK4543", NULL
, },
599 { AC97_CODEC_ID('A', 'K', 'M', 5),
600 0xffffffff, "Asahi Kasei AK4544", NULL
, },
601 { AC97_CODEC_ID('A', 'K', 'M', 6),
602 0xffffffff, "Asahi Kasei AK4544A", NULL
, },
603 { AC97_CODEC_ID('A', 'K', 'M', 7),
604 0xffffffff, "Asahi Kasei AK4545", NULL
, },
605 { AC97_CODEC_ID('A', 'K', 'M', 0),
606 AC97_VENDOR_ID_MASK
, "Asahi Kasei unknown", NULL
, },
609 * Realtek & Avance Logic
610 * http://www.realtek.com.tw/downloads/downloads1-3.aspx?lineid=5&famid=All&series=All&Spec=True
612 * ALC650 and ALC658 support VRA, but it supports only 8000, 11025,
613 * 12000, 16000, 22050, 24000, 32000, 44100, and 48000 Hz.
615 { AC97_CODEC_ID('A', 'L', 'C', 0x00),
616 0xfffffff0, "Realtek RL5306", NULL
, },
617 { AC97_CODEC_ID('A', 'L', 'C', 0x10),
618 0xfffffff0, "Realtek RL5382", NULL
, },
619 { AC97_CODEC_ID('A', 'L', 'C', 0x20),
620 0xfffffff0, "Realtek RL5383/RL5522/ALC100", NULL
, },
621 { AC97_CODEC_ID('A', 'L', 'G', 0x10),
622 0xffffffff, "Avance Logic ALC200/ALC201", NULL
, },
623 { AC97_CODEC_ID('A', 'L', 'G', 0x20),
624 0xfffffff0, "Avance Logic ALC650", ac97_alc650_init
},
625 { AC97_CODEC_ID('A', 'L', 'G', 0x30),
626 0xffffffff, "Avance Logic ALC101", NULL
, },
627 { AC97_CODEC_ID('A', 'L', 'G', 0x40),
628 0xffffffff, "Avance Logic ALC202", NULL
, },
629 { AC97_CODEC_ID('A', 'L', 'G', 0x50),
630 0xffffffff, "Avance Logic ALC250", NULL
, },
631 { AC97_CODEC_ID('A', 'L', 'G', 0x60),
632 0xfffffff0, "Avance Logic ALC655", NULL
, },
633 { AC97_CODEC_ID('A', 'L', 'G', 0x80),
634 0xfffffff0, "Avance Logic ALC658", NULL
, },
635 { AC97_CODEC_ID('A', 'L', 'G', 0x90),
636 0xfffffff0, "Avance Logic ALC850", NULL
, },
637 { AC97_CODEC_ID('A', 'L', 'C', 0),
638 AC97_VENDOR_ID_MASK
, "Realtek unknown", NULL
, },
639 { AC97_CODEC_ID('A', 'L', 'G', 0),
640 AC97_VENDOR_ID_MASK
, "Avance Logic unknown", NULL
, },
643 * C-Media Electronics Inc.
644 * http://www.cmedia.com.tw/doc/CMI9739%206CH%20Audio%20Codec%20SPEC_Ver12.pdf
646 { AC97_CODEC_ID('C', 'M', 'I', 0x61),
647 0xffffffff, "C-Media CMI9739", NULL
, },
648 { AC97_CODEC_ID('C', 'M', 'I', 0),
649 AC97_VENDOR_ID_MASK
, "C-Media unknown", NULL
, },
651 /* Cirrus Logic, Crystal series:
652 * 'C' 'R' 'Y' 0x0[0-7] - CS4297
662 * http://www.cirrus.com/pubs/cs4297A-5.pdf?DocumentID=593
663 * http://www.cirrus.com/pubs/cs4294.pdf?DocumentID=32
664 * http://www.cirrus.com/pubs/cs4299-5.pdf?DocumentID=594
665 * http://www.cirrus.com/pubs/cs4201-2.pdf?DocumentID=492
666 * http://www.cirrus.com/pubs/cs4205-2.pdf?DocumentID=492
667 * http://www.cirrus.com/pubs/cs4202-1.pdf?DocumentID=852
669 { AC97_CODEC_ID('C', 'R', 'Y', 0x00),
670 0xfffffff8, "Crystal CS4297", NULL
, },
671 { AC97_CODEC_ID('C', 'R', 'Y', 0x10),
672 0xfffffff8, "Crystal CS4297A", NULL
, },
673 { AC97_CODEC_ID('C', 'R', 'Y', 0x20),
674 0xfffffff8, "Crystal CS4298", NULL
, },
675 { AC97_CODEC_ID('C', 'R', 'Y', 0x28),
676 0xfffffff8, "Crystal CS4294", NULL
, },
677 { AC97_CODEC_ID('C', 'R', 'Y', 0x30),
678 0xfffffff8, "Crystal CS4299", NULL
, },
679 { AC97_CODEC_ID('C', 'R', 'Y', 0x48),
680 0xfffffff8, "Crystal CS4201", NULL
, },
681 { AC97_CODEC_ID('C', 'R', 'Y', 0x58),
682 0xfffffff8, "Crystal CS4205", NULL
, },
683 { AC97_CODEC_ID('C', 'R', 'Y', 0x60),
684 0xfffffff8, "Crystal CS4291", NULL
, },
685 { AC97_CODEC_ID('C', 'R', 'Y', 0x70),
686 0xfffffff8, "Crystal CS4202", NULL
, },
687 { AC97_CODEC_ID('C', 'R', 'Y', 0),
688 AC97_VENDOR_ID_MASK
, "Cirrus Logic unknown", NULL
, },
690 { 0x45838308, 0xffffffff, "ESS Technology ES1921", NULL
, },
691 { 0x45838300, AC97_VENDOR_ID_MASK
, "ESS Technology unknown", NULL
, },
693 { AC97_CODEC_ID('H', 'R', 'S', 0),
694 0xffffffff, "Intersil HMP9701", NULL
, },
695 { AC97_CODEC_ID('H', 'R', 'S', 0),
696 AC97_VENDOR_ID_MASK
, "Intersil unknown", NULL
, },
700 * http://www.viatech.com/en/datasheet/DS1616.pdf
702 { AC97_CODEC_ID('I', 'C', 'E', 0x01),
703 0xffffffff, "ICEnsemble ICE1230/VT1611", NULL
, },
704 { AC97_CODEC_ID('I', 'C', 'E', 0x11),
705 0xffffffff, "ICEnsemble ICE1232/VT1611A", NULL
, },
706 { AC97_CODEC_ID('I', 'C', 'E', 0x14),
707 0xffffffff, "ICEnsemble ICE1232A", NULL
, },
708 { AC97_CODEC_ID('I', 'C', 'E', 0x51),
709 0xffffffff, "VIA Technologies VT1616", ac97_vt1616_init
},
710 { AC97_CODEC_ID('I', 'C', 'E', 0x52),
711 0xffffffff, "VIA Technologies VT1616i", ac97_vt1616_init
},
712 { AC97_CODEC_ID('I', 'C', 'E', 0),
713 AC97_VENDOR_ID_MASK
, "ICEnsemble/VIA unknown", NULL
, },
715 { AC97_CODEC_ID('N', 'S', 'C', 0),
716 0xffffffff, "National Semiconductor LM454[03568]", NULL
, },
717 { AC97_CODEC_ID('N', 'S', 'C', 49),
718 0xffffffff, "National Semiconductor LM4549", NULL
, },
719 { AC97_CODEC_ID('N', 'S', 'C', 0),
720 AC97_VENDOR_ID_MASK
, "National Semiconductor unknown", NULL
, },
722 { AC97_CODEC_ID('P', 'S', 'C', 4),
723 0xffffffff, "Philips Semiconductor UCB1400", ac97_ucb1400_init
, },
724 { AC97_CODEC_ID('P', 'S', 'C', 0),
725 AC97_VENDOR_ID_MASK
, "Philips Semiconductor unknown", NULL
, },
727 { AC97_CODEC_ID('S', 'I', 'L', 34),
728 0xffffffff, "Silicon Laboratory Si3036", NULL
, },
729 { AC97_CODEC_ID('S', 'I', 'L', 35),
730 0xffffffff, "Silicon Laboratory Si3038", NULL
, },
731 { AC97_CODEC_ID('S', 'I', 'L', 0),
732 AC97_VENDOR_ID_MASK
, "Silicon Laboratory unknown", NULL
, },
734 { AC97_CODEC_ID('T', 'R', 'A', 2),
735 0xffffffff, "TriTech TR28022", NULL
, },
736 { AC97_CODEC_ID('T', 'R', 'A', 3),
737 0xffffffff, "TriTech TR28023", NULL
, },
738 { AC97_CODEC_ID('T', 'R', 'A', 6),
739 0xffffffff, "TriTech TR28026", NULL
, },
740 { AC97_CODEC_ID('T', 'R', 'A', 8),
741 0xffffffff, "TriTech TR28028", NULL
, },
742 { AC97_CODEC_ID('T', 'R', 'A', 35),
743 0xffffffff, "TriTech TR28602", NULL
, },
744 { AC97_CODEC_ID('T', 'R', 'A', 0),
745 AC97_VENDOR_ID_MASK
, "TriTech unknown", NULL
, },
747 { AC97_CODEC_ID('T', 'X', 'N', 0x20),
748 0xffffffff, "Texas Instruments TLC320AD9xC", NULL
, },
749 { AC97_CODEC_ID('T', 'X', 'N', 0),
750 AC97_VENDOR_ID_MASK
, "Texas Instruments unknown", NULL
, },
754 * http://www.viatech.com/en/multimedia/audio.jsp
756 { AC97_CODEC_ID('V', 'I', 'A', 0x61),
757 0xffffffff, "VIA Technologies VT1612A", NULL
, },
758 { AC97_CODEC_ID('V', 'I', 'A', 0),
759 AC97_VENDOR_ID_MASK
, "VIA Technologies unknown", NULL
, },
761 { AC97_CODEC_ID('W', 'E', 'C', 1),
762 0xffffffff, "Winbond W83971D", NULL
, },
763 { AC97_CODEC_ID('W', 'E', 'C', 0),
764 AC97_VENDOR_ID_MASK
, "Winbond unknown", NULL
, },
767 * http://www.wolfsonmicro.com/product_list.asp?cid=64
768 * http://www.wolfsonmicro.com/download.asp/did.56/WM9701A.pdf - 00
769 * http://www.wolfsonmicro.com/download.asp/did.57/WM9703.pdf - 03
770 * http://www.wolfsonmicro.com/download.asp/did.58/WM9704M.pdf - 04
771 * http://www.wolfsonmicro.com/download.asp/did.59/WM9704Q.pdf - 04
772 * http://www.wolfsonmicro.com/download.asp/did.184/WM9705_Rev34.pdf - 05
773 * http://www.wolfsonmicro.com/download.asp/did.60/WM9707.pdf - 03
774 * http://www.wolfsonmicro.com/download.asp/did.136/WM9708.pdf - 03
775 * http://www.wolfsonmicro.com/download.asp/did.243/WM9710.pdf - 05
777 { AC97_CODEC_ID('W', 'M', 'L', 0),
778 0xffffffff, "Wolfson WM9701A", NULL
, },
779 { AC97_CODEC_ID('W', 'M', 'L', 3),
780 0xffffffff, "Wolfson WM9703/WM9707/WM9708", NULL
, },
781 { AC97_CODEC_ID('W', 'M', 'L', 4),
782 0xffffffff, "Wolfson WM9704", NULL
, },
783 { AC97_CODEC_ID('W', 'M', 'L', 5),
784 0xffffffff, "Wolfson WM9705/WM9710", NULL
, },
785 { AC97_CODEC_ID('W', 'M', 'L', 0),
786 AC97_VENDOR_ID_MASK
, "Wolfson unknown", NULL
, },
789 * http://www.yamaha.co.jp/english/product/lsi/us/products/pcaudio.html
791 * http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF743A20.pdf
792 * http://www.yamaha.co.jp/english/product/lsi/us/products/pdf/4MF753A20.pdf
794 { AC97_CODEC_ID('Y', 'M', 'H', 0),
795 0xffffffff, "Yamaha YMF743-S", NULL
, },
796 { AC97_CODEC_ID('Y', 'M', 'H', 3),
797 0xffffffff, "Yamaha YMF753-S", NULL
, },
798 { AC97_CODEC_ID('Y', 'M', 'H', 0),
799 AC97_VENDOR_ID_MASK
, "Yamaha unknown", NULL
, },
802 * http://www.sigmatel.com/products/technical_docs.htm
804 * http://www.sigmatel.com/documents/c-major-brochure-9-0.pdf
806 { 0x83847600, 0xffffffff, "SigmaTel STAC9700", NULL
, },
807 { 0x83847604, 0xffffffff, "SigmaTel STAC9701/3/4/5", NULL
, },
808 { 0x83847605, 0xffffffff, "SigmaTel STAC9704", NULL
, },
809 { 0x83847608, 0xffffffff, "SigmaTel STAC9708", NULL
, },
810 { 0x83847609, 0xffffffff, "SigmaTel STAC9721/23", NULL
, },
811 { 0x83847644, 0xffffffff, "SigmaTel STAC9744/45", NULL
, },
812 { 0x83847650, 0xffffffff, "SigmaTel STAC9750/51", NULL
, },
813 { 0x83847652, 0xffffffff, "SigmaTel STAC9752/53", NULL
, },
814 { 0x83847656, 0xffffffff, "SigmaTel STAC9756/57", NULL
, },
815 { 0x83847658, 0xffffffff, "SigmaTel STAC9758/59", NULL
, },
816 { 0x83847666, 0xffffffff, "SigmaTel STAC9766/67", NULL
, },
817 { 0x83847684, 0xffffffff, "SigmaTel STAC9783/84", NULL
, },
818 { 0x83847600, AC97_VENDOR_ID_MASK
, "SigmaTel unknown", NULL
, },
820 /* Conexant AC'97 modems -- good luck finding datasheets! */
821 { AC97_CODEC_ID('C', 'X', 'T', 33),
822 0xffffffff, "Conexant HSD11246", NULL
, },
823 { AC97_CODEC_ID('C', 'X', 'T', 34),
824 0xffffffff, "Conexant D480 MDC V.92 Modem", NULL
, },
825 { AC97_CODEC_ID('C', 'X', 'T', 48),
826 0xffffffff, "Conexant CXT48", NULL
, },
827 { AC97_CODEC_ID('C', 'X', 'T', 0),
828 AC97_VENDOR_ID_MASK
, "Conexant unknown", NULL
, },
834 static const char * const ac97enhancement
[] = {
836 "Analog Devices Phat Stereo",
851 "Harman International VMAx",
853 "Philips Incredible Sound",
854 "Texas Instruments' 3D",
855 "VLSI Technology 3D",
859 "Wolfson Microelectronics 3D",
860 "Delta Integration 3D",
869 static const char * const ac97feature
[] = {
870 "dedicated mic channel",
883 /* #define AC97_DEBUG 10 */
884 /* #define AC97_IO_DEBUG */
887 #define DPRINTF(x) if (ac97debug) printf x
888 #define DPRINTFN(n,x) if (ac97debug>(n)) printf x
890 int ac97debug
= AC97_DEBUG
;
896 #define DPRINTFN(n,x)
900 static const char *ac97_register_names
[0x80 / 2] = {
901 "RESET", "MASTER_VOLUME", "HEADPHONE_VOLUME", "MASTER_VOLUME_MONO",
902 "MASTER_TONE", "PCBEEP_VOLUME", "PHONE_VOLUME", "MIC_VOLUME",
903 "LINEIN_VOLUME", "CD_VOLUME", "VIDEO_VOLUME", "AUX_VOLUME",
904 "PCMOUT_VOLUME", "RECORD_SELECT", "RECORD_GATIN", "RECORD_GAIN_MIC",
905 "GP", "3D_CONTROL", "AUDIO_INT", "POWER",
906 "EXT_AUDIO_ID", "EXT_AUDIO_CTRL", "PCM_FRONT_DAC_RATE", "PCM_SURR_DAC_RATE",
907 "PCM_LFE_DAC_RATE", "PCM_LR_ADC_RATE", "PCM_MIC_ADC_RATE", "CENTER_LFE_MASTER",
908 "SURR_MASTER", "SPDIF_CTRL", "EXT_MODEM_ID", "EXT_MODEM_CTRL",
909 "LINE1_RATE", "LINE2_RATE", "HANDSET_RATE", "LINE1_LEVEL",
910 "LINE2_LEVEL", "HANDSET_LEVEL", "GPIO_PIN_CONFIG", "GPIO_PIN_POLARITY",
911 "GPIO_PIN_STICKY", "GPIO_PIN_WAKEUP", "GPIO_PIN_STATUS", "MISC_MODEM_CTRL",
912 "0x58", "VENDOR-5A", "VENDOR-5C", "VENDOR-5E",
913 "0x60", "0x62", "0x64", "0x66",
914 "0x68", "0x6a", "0x6c", "0x6e",
915 "VENDOR-70", "VENDOR-72", "VENDOR-74", "VENDOR-76",
916 "VENDOR-78", "VENDOR-7A", "VENDOR_ID1", "VENDOR_ID2"
921 * XXX Some cards have an inverted AC97_POWER_EAMP bit.
922 * These cards will produce no sound unless AC97_HOST_INVERTED_EAMP is set.
925 #define POWER_EAMP_ON(as) ((as->host_flags & AC97_HOST_INVERTED_EAMP) \
926 ? AC97_POWER_EAMP : 0)
927 #define POWER_EAMP_OFF(as) ((as->host_flags & AC97_HOST_INVERTED_EAMP) \
928 ? 0 : AC97_POWER_EAMP)
931 ac97_read(struct ac97_softc
*as
, uint8_t reg
, uint16_t *val
)
933 if (as
->host_flags
& AC97_HOST_DONT_READ
&&
934 (reg
!= AC97_REG_VENDOR_ID1
&& reg
!= AC97_REG_VENDOR_ID2
&&
935 reg
!= AC97_REG_RESET
)) {
936 *val
= as
->shadow_reg
[reg
>> 1];
940 if (as
->host_if
->read(as
->host_if
->arg
, reg
, val
)) {
941 *val
= as
->shadow_reg
[reg
>> 1];
946 ac97_write(struct ac97_softc
*as
, uint8_t reg
, uint16_t val
)
948 #ifndef AC97_IO_DEBUG
949 as
->shadow_reg
[reg
>> 1] = val
;
950 return as
->host_if
->write(as
->host_if
->arg
, reg
, val
);
955 as
->shadow_reg
[reg
>> 1] = val
;
956 ret
= as
->host_if
->write(as
->host_if
->arg
, reg
, val
);
957 as
->host_if
->read(as
->host_if
->arg
, reg
, &actual
);
958 if (val
!= actual
&& reg
< 0x80) {
959 printf("ac97_write: reg=%s, written=0x%04x, read=0x%04x\n",
960 ac97_register_names
[reg
/ 2], val
, actual
);
967 ac97_setup_defaults(struct ac97_softc
*as
)
970 const struct ac97_source_info
*si
;
972 memset(as
->shadow_reg
, 0, sizeof(as
->shadow_reg
));
974 for (idx
= 0; idx
< AUDIO_SOURCE_INFO_SIZE
; idx
++) {
975 si
= &audio_source_info
[idx
];
976 if (si
->default_value
>= 0)
977 ac97_write(as
, si
->reg
, si
->default_value
);
979 for (idx
= 0; idx
< MODEM_SOURCE_INFO_SIZE
; idx
++) {
980 si
= &modem_source_info
[idx
];
981 if (si
->default_value
>= 0)
982 ac97_write(as
, si
->reg
, si
->default_value
);
987 ac97_restore_shadow(struct ac97_codec_if
*self
)
989 struct ac97_softc
*as
;
990 const struct ac97_source_info
*si
;
994 as
= (struct ac97_softc
*) self
;
996 if (as
->type
== AC97_CODEC_TYPE_AUDIO
) {
997 /* restore AC97_REG_POWER */
998 ac97_write(as
, AC97_REG_POWER
, as
->power_reg
);
999 /* make sure chip is fully operational */
1000 for (idx
= 50000; idx
>= 0; idx
--) {
1001 ac97_read(as
, AC97_REG_POWER
, &val
);
1002 if ((val
& as
->power_all
) == as
->power_all
)
1008 * actually try changing a value!
1009 * The default value of AC97_REG_MASTER_VOLUME is 0x8000.
1011 for (idx
= 50000; idx
>= 0; idx
--) {
1012 ac97_write(as
, AC97_REG_MASTER_VOLUME
, 0x1010);
1013 ac97_read(as
, AC97_REG_MASTER_VOLUME
, &val
);
1020 for (idx
= 0; idx
< SOURCE_INFO_SIZE(as
); idx
++) {
1021 if (as
->type
== AC97_CODEC_TYPE_MODEM
)
1022 si
= &modem_source_info
[idx
];
1024 si
= &audio_source_info
[idx
];
1025 /* don't "restore" to the reset reg! */
1026 if (si
->reg
!= AC97_REG_RESET
)
1027 ac97_write(as
, si
->reg
, as
->shadow_reg
[si
->reg
>> 1]);
1030 if (as
->ext_id
& (AC97_EXT_AUDIO_VRA
| AC97_EXT_AUDIO_DRA
1031 | AC97_EXT_AUDIO_SPDIF
| AC97_EXT_AUDIO_VRM
1032 | AC97_EXT_AUDIO_CDAC
| AC97_EXT_AUDIO_SDAC
1033 | AC97_EXT_AUDIO_LDAC
)) {
1034 ac97_write(as
, AC97_REG_EXT_AUDIO_CTRL
,
1035 as
->shadow_reg
[AC97_REG_EXT_AUDIO_CTRL
>> 1]);
1037 if (as
->ext_mid
& (AC97_EXT_MODEM_LINE1
| AC97_EXT_MODEM_LINE2
1038 | AC97_EXT_MODEM_HANDSET
| AC97_EXT_MODEM_CID1
1039 | AC97_EXT_MODEM_CID2
| AC97_EXT_MODEM_ID0
1040 | AC97_EXT_MODEM_ID1
)) {
1041 ac97_write(as
, AC97_REG_EXT_MODEM_CTRL
,
1042 as
->shadow_reg
[AC97_REG_EXT_MODEM_CTRL
>> 1]);
1047 ac97_str_equal(const char *a
, const char *b
)
1049 return (a
== b
) || (a
&& b
&& (!strcmp(a
, b
)));
1053 ac97_check_capability(struct ac97_softc
*as
, int check
)
1058 case CHECK_SURROUND
:
1059 return as
->ext_id
& AC97_EXT_AUDIO_SDAC
;
1061 return as
->ext_id
& AC97_EXT_AUDIO_CDAC
;
1063 return as
->ext_id
& AC97_EXT_AUDIO_LDAC
;
1065 return as
->ext_id
& AC97_EXT_AUDIO_SPDIF
;
1066 case CHECK_HEADPHONES
:
1067 return as
->caps
& AC97_CAPS_HEADPHONES
;
1069 return as
->caps
& AC97_CAPS_TONECTRL
;
1071 return as
->caps
& AC97_CAPS_MICIN
;
1072 case CHECK_LOUDNESS
:
1073 return as
->caps
& AC97_CAPS_LOUDNESS
;
1075 return AC97_CAPS_ENHANCEMENT(as
->caps
) != 0;
1077 return as
->ext_mid
& AC97_EXT_MODEM_LINE1
;
1079 return as
->ext_mid
& AC97_EXT_MODEM_LINE2
;
1081 return as
->ext_mid
& AC97_EXT_MODEM_HANDSET
;
1083 printf("%s: internal error: feature=%d\n", __func__
, check
);
1089 ac97_setup_source_info(struct ac97_softc
*as
)
1092 struct ac97_source_info
*si
, *si2
;
1093 uint16_t value1
, value2
, value3
;
1095 for (idx
= 0, ouridx
= 0; idx
< SOURCE_INFO_SIZE(as
); idx
++) {
1096 si
= &as
->source_info
[ouridx
];
1097 if (as
->type
== AC97_CODEC_TYPE_MODEM
) {
1098 memcpy(si
, &modem_source_info
[idx
], sizeof(*si
));
1100 memcpy(si
, &audio_source_info
[idx
], sizeof(*si
));
1102 if (!ac97_check_capability(as
, si
->req_feature
))
1104 if (si
->checkbits
) {
1105 /* read the register value */
1106 ac97_read(as
, si
->reg
, &value1
);
1107 /* write 0b100000 */
1108 value2
= value1
& 0xffc0;
1110 ac97_write(as
, si
->reg
, value2
);
1112 ac97_read(as
, si
->reg
, &value3
);
1113 if (value2
== value3
) {
1118 DPRINTF(("%s: register=%02x bits=%d\n",
1119 __func__
, si
->reg
, si
->bits
));
1120 ac97_write(as
, si
->reg
, value1
);
1124 case AUDIO_MIXER_CLASS
:
1125 si
->mixer_class
= ouridx
;
1128 case AUDIO_MIXER_VALUE
:
1129 /* Todo - Test to see if it works */
1132 /* Add an entry for mute, if necessary */
1134 si
= &as
->source_info
[ouridx
];
1135 if (as
->type
== AC97_CODEC_TYPE_MODEM
)
1136 memcpy(si
, &modem_source_info
[idx
],
1139 memcpy(si
, &audio_source_info
[idx
],
1141 si
->qualifier
= AudioNmute
;
1142 si
->type
= AUDIO_MIXER_ENUM
;
1143 si
->info
= &ac97_on_off
;
1144 si
->info_size
= sizeof(ac97_on_off
);
1152 case AUDIO_MIXER_ENUM
:
1153 /* Todo - Test to see if it works */
1157 aprint_error ("ac97: shouldn't get here\n");
1162 as
->num_source_info
= ouridx
;
1164 for (idx
= 0; idx
< as
->num_source_info
; idx
++) {
1167 si
= &as
->source_info
[idx
];
1169 /* Find mixer class */
1170 for (idx2
= 0; idx2
< as
->num_source_info
; idx2
++) {
1171 si2
= &as
->source_info
[idx2
];
1173 if (si2
->type
== AUDIO_MIXER_CLASS
&&
1174 ac97_str_equal(si
->class,
1176 si
->mixer_class
= idx2
;
1181 /* Setup prev and next pointers */
1188 si
->prev
= AUDIO_MIXER_LAST
;
1191 for (idx2
= 0; idx2
< as
->num_source_info
; idx2
++) {
1195 si2
= &as
->source_info
[idx2
];
1198 ac97_str_equal(si
->class, si2
->class) &&
1199 ac97_str_equal(si
->device
, si2
->device
)) {
1200 as
->source_info
[previdx
].next
= idx2
;
1201 as
->source_info
[idx2
].prev
= previdx
;
1207 as
->source_info
[previdx
].next
= AUDIO_MIXER_LAST
;
1211 /* backward compatibility */
1213 ac97_attach(struct ac97_host_if
*host_if
, device_t sc_dev
)
1215 return ac97_attach_type(host_if
, sc_dev
, AC97_CODEC_TYPE_AUDIO
);
1219 ac97_attach_type(struct ac97_host_if
*host_if
, device_t sc_dev
, int type
)
1221 struct ac97_softc
*as
;
1225 uint16_t extstat
, rate
;
1228 void (*initfunc
)(struct ac97_softc
*);
1229 #define FLAGBUFLEN 140
1230 char flagbuf
[FLAGBUFLEN
];
1233 as
= malloc(sizeof(struct ac97_softc
), M_DEVBUF
, M_WAITOK
|M_ZERO
);
1238 as
->codec_if
.vtbl
= &ac97civ
;
1239 as
->host_if
= host_if
;
1242 if ((error
= host_if
->attach(host_if
->arg
, &as
->codec_if
))) {
1247 if (host_if
->reset
!= NULL
) {
1248 if ((error
= host_if
->reset(host_if
->arg
))) {
1255 as
->host_flags
= host_if
->flags(host_if
->arg
);
1258 * Assume codec has all four power bits.
1259 * XXXSCW: what to do for modems?
1261 as
->power_all
= AC97_POWER_REF
| AC97_POWER_ANL
| AC97_POWER_DAC
|
1263 if (as
->type
== AC97_CODEC_TYPE_AUDIO
) {
1264 host_if
->write(host_if
->arg
, AC97_REG_RESET
, 0);
1267 * Power-up everything except the analogue mixer.
1268 * If this codec doesn't support analogue mixer power-down,
1269 * AC97_POWER_MIXER will read back as zero.
1271 host_if
->write(host_if
->arg
, AC97_REG_POWER
, AC97_POWER_MIXER
);
1272 ac97_read(as
, AC97_REG_POWER
, &val
);
1273 if ((val
& AC97_POWER_MIXER
) == 0) {
1274 /* Codec doesn't support analogue mixer power-down */
1275 as
->power_all
&= ~AC97_POWER_ANL
;
1277 host_if
->write(host_if
->arg
, AC97_REG_POWER
, POWER_EAMP_ON(as
));
1279 for (i
= 500000; i
>= 0; i
--) {
1280 ac97_read(as
, AC97_REG_POWER
, &val
);
1281 if ((val
& as
->power_all
) == as
->power_all
)
1286 /* save AC97_REG_POWER so that we can restore it later */
1287 ac97_read(as
, AC97_REG_POWER
, &as
->power_reg
);
1288 } else if (as
->type
== AC97_CODEC_TYPE_MODEM
) {
1289 host_if
->write(host_if
->arg
, AC97_REG_EXT_MODEM_ID
, 0);
1292 ac97_setup_defaults(as
);
1293 if (as
->type
== AC97_CODEC_TYPE_AUDIO
)
1294 ac97_read(as
, AC97_REG_RESET
, &as
->caps
);
1295 ac97_read(as
, AC97_REG_VENDOR_ID1
, &id1
);
1296 ac97_read(as
, AC97_REG_VENDOR_ID2
, &id2
);
1298 id
= (id1
<< 16) | id2
;
1299 aprint_normal_dev(sc_dev
, "ac97: ");
1301 for (i
= 0; ; i
++) {
1302 if (ac97codecid
[i
].id
== 0) {
1305 AC97_GET_CODEC_ID(id
, pnp
);
1306 #define ISASCII(c) ((c) >= ' ' && (c) < 0x7f)
1307 if (ISASCII(pnp
[0]) && ISASCII(pnp
[1]) &&
1309 aprint_normal("%c%c%c%d",
1310 pnp
[0], pnp
[1], pnp
[2], pnp
[3]);
1312 aprint_normal("unknown (0x%08x)", id
);
1315 if (ac97codecid
[i
].id
== (id
& ac97codecid
[i
].mask
)) {
1316 aprint_normal("%s", ac97codecid
[i
].name
);
1317 if (ac97codecid
[i
].mask
== AC97_VENDOR_ID_MASK
) {
1318 aprint_normal(" (0x%08x)", id
);
1320 initfunc
= ac97codecid
[i
].init
;
1324 aprint_normal(" codec; ");
1325 for (i
= j
= 0; i
< 10; i
++) {
1326 if (as
->caps
& (1 << i
)) {
1327 aprint_normal("%s%s", j
? ", " : "", ac97feature
[i
]);
1331 aprint_normal("%s%s\n", j
? ", " : "",
1332 ac97enhancement
[AC97_CAPS_ENHANCEMENT(as
->caps
)]);
1334 as
->ac97_clock
= AC97_STANDARD_CLOCK
;
1336 if (as
->type
== AC97_CODEC_TYPE_AUDIO
) {
1337 ac97_read(as
, AC97_REG_EXT_AUDIO_ID
, &as
->ext_id
);
1338 if (as
->ext_id
!= 0) {
1339 /* Print capabilities */
1340 snprintb(flagbuf
, sizeof(flagbuf
),
1341 "\20\20SECONDARY10\17SECONDARY01"
1342 "\14AC97_23\13AC97_22\12AMAP\11LDAC\10SDAC"
1343 "\7CDAC\4VRM\3SPDIF\2DRA\1VRA", as
->ext_id
);
1344 aprint_normal_dev(sc_dev
, "ac97: ext id %s\n",
1347 /* Print unusual settings */
1348 if (as
->ext_id
& AC97_EXT_AUDIO_DSA_MASK
) {
1349 aprint_normal_dev(sc_dev
, "ac97: Slot assignment: ");
1350 switch (as
->ext_id
& AC97_EXT_AUDIO_DSA_MASK
) {
1351 case AC97_EXT_AUDIO_DSA01
:
1352 aprint_normal("7&8, 6&9, 10&11.\n");
1354 case AC97_EXT_AUDIO_DSA10
:
1355 aprint_normal("6&9, 10&11, 3&4.\n");
1357 case AC97_EXT_AUDIO_DSA11
:
1358 aprint_normal("10&11, 3&4, 7&8.\n");
1362 if (as
->host_flags
& AC97_HOST_INVERTED_EAMP
) {
1363 aprint_normal_dev(sc_dev
, "ac97: using inverted "
1364 "AC97_POWER_EAMP bit\n");
1367 /* Enable and disable features */
1368 ac97_read(as
, AC97_REG_EXT_AUDIO_CTRL
, &extstat
);
1369 extstat
&= ~AC97_EXT_AUDIO_DRA
;
1370 if (as
->ext_id
& AC97_EXT_AUDIO_LDAC
)
1371 extstat
|= AC97_EXT_AUDIO_LDAC
;
1372 if (as
->ext_id
& AC97_EXT_AUDIO_SDAC
)
1373 extstat
|= AC97_EXT_AUDIO_SDAC
;
1374 if (as
->ext_id
& AC97_EXT_AUDIO_CDAC
)
1375 extstat
|= AC97_EXT_AUDIO_CDAC
;
1376 if (as
->ext_id
& AC97_EXT_AUDIO_VRM
)
1377 extstat
|= AC97_EXT_AUDIO_VRM
;
1378 if (as
->ext_id
& AC97_EXT_AUDIO_SPDIF
) {
1379 /* Output the same data as DAC to SPDIF output */
1380 extstat
&= ~AC97_EXT_AUDIO_SPSA_MASK
;
1381 extstat
|= AC97_EXT_AUDIO_SPSA34
;
1382 ac97_read(as
, AC97_REG_SPDIF_CTRL
, &val
);
1383 val
= (val
& ~AC97_SPDIF_SPSR_MASK
)
1384 | AC97_SPDIF_SPSR_48K
;
1385 ac97_write(as
, AC97_REG_SPDIF_CTRL
, val
);
1387 if (as
->ext_id
& AC97_EXT_AUDIO_VRA
)
1388 extstat
|= AC97_EXT_AUDIO_VRA
;
1389 ac97_write(as
, AC97_REG_EXT_AUDIO_CTRL
, extstat
);
1390 if (as
->ext_id
& AC97_EXT_AUDIO_VRA
) {
1391 /* VRA should be enabled. */
1392 /* so it claims to do variable rate, let's make sure */
1393 ac97_write(as
, AC97_REG_PCM_FRONT_DAC_RATE
,
1395 ac97_read(as
, AC97_REG_PCM_FRONT_DAC_RATE
,
1397 if (rate
!= 44100) {
1398 /* We can't believe ext_id */
1400 aprint_normal_dev(sc_dev
,
1401 "Ignore these capabilities.\n");
1403 /* restore the default value */
1404 ac97_write(as
, AC97_REG_PCM_FRONT_DAC_RATE
,
1408 } else if (as
->type
== AC97_CODEC_TYPE_MODEM
) {
1409 const struct sysctlnode
*node
;
1410 const struct sysctlnode
*node_line1
;
1411 const struct sysctlnode
*node_line2
;
1412 uint16_t xrate
= 8000;
1416 ac97_read(as
, AC97_REG_EXT_MODEM_ID
, &as
->ext_mid
);
1417 if (as
->ext_mid
== 0 || as
->ext_mid
== 0xffff) {
1418 aprint_normal_dev(sc_dev
, "no modem codec found\n");
1421 as
->type
= AC97_CODEC_TYPE_MODEM
;
1423 /* Print capabilities */
1424 snprintb(flagbuf
, sizeof(flagbuf
),
1425 "\20\5CID2\4CID1\3HANDSET\2LINE2\1LINE1", as
->ext_mid
);
1426 aprint_normal_dev(sc_dev
, "ac97: ext mid %s",
1428 aprint_normal(", %s codec\n",
1429 (as
->ext_mid
& 0xc000) == 0 ?
1430 "primary" : "secondary");
1432 /* Setup modem and sysctls */
1433 err
= sysctl_createv(&as
->log
, 0, NULL
, NULL
, 0, CTLTYPE_NODE
,
1434 "hw", NULL
, NULL
, 0, NULL
, 0, CTL_HW
,
1438 err
= sysctl_createv(&as
->log
, 0, NULL
, &node
, 0,
1439 CTLTYPE_NODE
, device_xname(sc_dev
), NULL
,
1440 NULL
, 0, NULL
, 0, CTL_HW
, CTL_CREATE
,
1446 ac97_write(as
, AC97_REG_EXT_MODEM_ID
, 1);
1449 xval
= 0xff00 & ~AC97_EXT_MODEM_CTRL_PRA
;
1450 if (as
->ext_mid
& AC97_EXT_MODEM_LINE1
) {
1451 ac97_write(as
, AC97_REG_LINE1_RATE
, xrate
);
1452 xval
&= ~(AC97_EXT_MODEM_CTRL_PRC
|
1453 AC97_EXT_MODEM_CTRL_PRD
);
1455 if (as
->ext_mid
& AC97_EXT_MODEM_LINE2
) {
1456 ac97_write(as
, AC97_REG_LINE2_RATE
, xrate
);
1457 xval
&= ~(AC97_EXT_MODEM_CTRL_PRE
|
1458 AC97_EXT_MODEM_CTRL_PRF
);
1460 if (as
->ext_mid
& AC97_EXT_MODEM_HANDSET
) {
1461 ac97_write(as
, AC97_REG_HANDSET_RATE
, xrate
);
1462 xval
&= ~(AC97_EXT_MODEM_CTRL_PRG
|
1463 AC97_EXT_MODEM_CTRL_PRH
);
1466 /* power-up everything */
1467 ac97_write(as
, AC97_REG_EXT_MODEM_CTRL
, 0);
1468 for (i
= 5000; i
>= 0; i
--) {
1469 ac97_read(as
, AC97_REG_EXT_MODEM_CTRL
, ®
);
1470 if ((reg
& /*XXXval*/0xf) == /*XXXval*/0xf)
1475 printf("%s: codec not responding, status=0x%x\n",
1476 device_xname(sc_dev
), reg
);
1481 if (as
->ext_mid
& AC97_EXT_MODEM_LINE1
) {
1482 ac97_read(as
, AC97_REG_GPIO_CFG
, ®
);
1483 reg
&= ~AC97_GPIO_LINE1_OH
;
1484 ac97_write(as
, AC97_REG_GPIO_CFG
, reg
);
1485 ac97_read(as
, AC97_REG_GPIO_POLARITY
, ®
);
1486 reg
&= ~AC97_GPIO_LINE1_OH
;
1487 ac97_write(as
, AC97_REG_GPIO_POLARITY
, reg
);
1489 err
= sysctl_createv(&as
->log
, 0, NULL
, &node_line1
,
1490 CTLFLAG_READWRITE
, CTLTYPE_INT
,
1492 SYSCTL_DESCR("off-hook line1"),
1493 ac97_sysctl_verify
, 0, as
, 0,
1494 CTL_HW
, node
->sysctl_num
,
1495 CTL_CREATE
, CTL_EOL
);
1498 as
->offhook_line1_mib
= node_line1
->sysctl_num
;
1500 if (as
->ext_mid
& AC97_EXT_MODEM_LINE2
) {
1501 ac97_read(as
, AC97_REG_GPIO_CFG
, ®
);
1502 reg
&= ~AC97_GPIO_LINE2_OH
;
1503 ac97_write(as
, AC97_REG_GPIO_CFG
, reg
);
1504 ac97_read(as
, AC97_REG_GPIO_POLARITY
, ®
);
1505 reg
&= ~AC97_GPIO_LINE2_OH
;
1506 ac97_write(as
, AC97_REG_GPIO_POLARITY
, reg
);
1508 err
= sysctl_createv(&as
->log
, 0, NULL
, &node_line2
,
1509 CTLFLAG_READWRITE
, CTLTYPE_INT
,
1511 SYSCTL_DESCR("off-hook line2"),
1512 ac97_sysctl_verify
, 0, as
, 0,
1513 CTL_HW
, node
->sysctl_num
,
1514 CTL_CREATE
, CTL_EOL
);
1517 as
->offhook_line2_mib
= node_line2
->sysctl_num
;
1521 ac97_write(as
, AC97_REG_GPIO_STICKY
, 0xffff);
1522 ac97_write(as
, AC97_REG_GPIO_WAKEUP
, 0x0);
1523 ac97_write(as
, AC97_REG_MISC_AFE
, 0x0);
1526 as
->source_info
= (as
->type
== AC97_CODEC_TYPE_MODEM
?
1527 as
->modem_source_info
: as
->audio_source_info
);
1528 ac97_setup_source_info(as
);
1530 memset(&ctl
, 0, sizeof(ctl
));
1532 for (i
= 0; i
< 11; i
++) {
1534 const char *class, *device
;
1536 { AudioCoutputs
, AudioNmaster
},
1537 { AudioCoutputs
, AudioNheadphone
},
1538 { AudioCoutputs
, AudioNsurround
},
1539 { AudioCoutputs
, AudioNcenter
},
1540 { AudioCoutputs
, AudioNlfe
},
1541 { AudioCinputs
, AudioNdac
},
1542 { AudioCinputs
, AudioNcd
},
1543 { AudioCinputs
, AudioNline
},
1544 { AudioCinputs
, AudioNaux
},
1545 { AudioCinputs
, AudioNvideo
},
1546 { AudioCrecord
, AudioNvolume
},
1549 ctl
.type
= AUDIO_MIXER_ENUM
;
1552 ctl
.dev
= ac97_get_portnum_by_name(&as
->codec_if
,
1553 d
[i
].class, d
[i
].device
, AudioNmute
);
1554 ac97_mixer_set_port(&as
->codec_if
, &ctl
);
1556 ctl
.type
= AUDIO_MIXER_ENUM
;
1558 ctl
.dev
= ac97_get_portnum_by_name(&as
->codec_if
, AudioCrecord
,
1559 AudioNsource
, NULL
);
1560 ac97_mixer_set_port(&as
->codec_if
, &ctl
);
1562 /* set a reasonable default volume */
1563 ctl
.type
= AUDIO_MIXER_VALUE
;
1564 ctl
.un
.value
.num_channels
= 2;
1565 ctl
.un
.value
.level
[AUDIO_MIXER_LEVEL_LEFT
] = \
1566 ctl
.un
.value
.level
[AUDIO_MIXER_LEVEL_RIGHT
] = 127;
1567 ctl
.dev
= ac97_get_portnum_by_name(&as
->codec_if
, AudioCoutputs
,
1568 AudioNmaster
, NULL
);
1569 ac97_mixer_set_port(&as
->codec_if
, &ctl
);
1570 ctl
.dev
= ac97_get_portnum_by_name(&as
->codec_if
, AudioCoutputs
,
1571 AudioNsurround
, NULL
);
1572 ac97_mixer_set_port(&as
->codec_if
, &ctl
);
1573 ctl
.un
.value
.num_channels
= 1;
1574 ctl
.dev
= ac97_get_portnum_by_name(&as
->codec_if
, AudioCoutputs
,
1575 AudioNcenter
, NULL
);
1576 ac97_mixer_set_port(&as
->codec_if
, &ctl
);
1577 ctl
.dev
= ac97_get_portnum_by_name(&as
->codec_if
, AudioCoutputs
,
1579 ac97_mixer_set_port(&as
->codec_if
, &ctl
);
1581 if (initfunc
!= NULL
)
1584 /* restore AC97_REG_POWER */
1585 if (as
->type
== AC97_CODEC_TYPE_AUDIO
)
1586 ac97_write(as
, AC97_REG_POWER
, as
->power_reg
);
1592 ac97_detach(struct ac97_codec_if
*codec_if
)
1594 struct ac97_softc
*as
;
1596 as
= (struct ac97_softc
*)codec_if
;
1597 ac97_write(as
, AC97_REG_POWER
, AC97_POWER_IN
| AC97_POWER_OUT
1598 | AC97_POWER_MIXER
| AC97_POWER_MIXER_VREF
1599 | AC97_POWER_ACLINK
| AC97_POWER_CLK
| AC97_POWER_AUX
1600 | POWER_EAMP_OFF(as
));
1605 ac97_lock(struct ac97_codec_if
*codec_if
)
1607 struct ac97_softc
*as
;
1609 as
= (struct ac97_softc
*)codec_if
;
1614 ac97_unlock(struct ac97_codec_if
*codec_if
)
1616 struct ac97_softc
*as
;
1618 as
= (struct ac97_softc
*)codec_if
;
1623 ac97_query_devinfo(struct ac97_codec_if
*codec_if
, mixer_devinfo_t
*dip
)
1625 struct ac97_softc
*as
;
1626 struct ac97_source_info
*si
;
1629 as
= (struct ac97_softc
*)codec_if
;
1630 if (dip
->index
< as
->num_source_info
) {
1631 si
= &as
->source_info
[dip
->index
];
1632 dip
->type
= si
->type
;
1633 dip
->mixer_class
= si
->mixer_class
;
1634 dip
->prev
= si
->prev
;
1635 dip
->next
= si
->next
;
1638 name
= si
->qualifier
;
1639 else if (si
->device
)
1647 strcpy(dip
->label
.name
, name
);
1649 memcpy(&dip
->un
, si
->info
, si
->info_size
);
1651 /* Set the delta for volume sources */
1652 if (dip
->type
== AUDIO_MIXER_VALUE
)
1653 dip
->un
.v
.delta
= 1 << (8 - si
->bits
);
1662 ac97_mixer_set_port(struct ac97_codec_if
*codec_if
, mixer_ctrl_t
*cp
)
1664 struct ac97_softc
*as
;
1665 struct ac97_source_info
*si
;
1667 uint16_t val
, newval
;
1671 as
= (struct ac97_softc
*)codec_if
;
1672 if (cp
->dev
< 0 || cp
->dev
>= as
->num_source_info
)
1674 si
= &as
->source_info
[cp
->dev
];
1676 if (cp
->type
== AUDIO_MIXER_CLASS
|| cp
->type
!= si
->type
)
1678 spdif
= si
->req_feature
== CHECK_SPDIF
&& si
->reg
== AC97_REG_EXT_AUDIO_CTRL
;
1679 if (spdif
&& as
->lock_counter
>= 0) {
1680 /* When the value of lock_counter is the default 0,
1681 * it is not allowed to change the SPDIF mode. */
1685 ac97_read(as
, si
->reg
, &val
);
1687 DPRINTFN(5, ("read(%x) = %x\n", si
->reg
, val
));
1689 mask
= (1 << si
->bits
) - 1;
1692 case AUDIO_MIXER_ENUM
:
1693 if (cp
->un
.ord
> mask
|| cp
->un
.ord
< 0)
1696 newval
= (cp
->un
.ord
<< si
->ofs
);
1697 if (si
->reg
== AC97_REG_RECORD_SELECT
) {
1698 newval
|= (newval
<< (8 + si
->ofs
));
1699 mask
|= (mask
<< 8);
1700 mask
= mask
<< si
->ofs
;
1701 } else if (si
->reg
== AC97_REG_SURR_MASTER
) {
1702 newval
= cp
->un
.ord
? 0x8080 : 0x0000;
1705 mask
= mask
<< si
->ofs
;
1707 case AUDIO_MIXER_VALUE
:
1709 const struct audio_mixer_value
*value
= si
->info
;
1710 uint16_t l
, r
, ol
, or;
1713 if ((cp
->un
.value
.num_channels
<= 0) ||
1714 (cp
->un
.value
.num_channels
> value
->num_channels
))
1717 if (cp
->un
.value
.num_channels
== 1) {
1718 l
= r
= cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_MONO
];
1720 if (!(as
->host_flags
& AC97_HOST_SWAPPED_CHANNELS
)) {
1721 l
= cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_LEFT
];
1722 r
= cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_RIGHT
];
1723 } else { /* left/right is reversed here */
1724 r
= cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_LEFT
];
1725 l
= cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_RIGHT
];
1730 if (!si
->polarity
) {
1735 ol
= (val
>> (8+si
->ofs
)) & mask
;
1736 or = (val
>> si
->ofs
) & mask
;
1738 deltal
= (ol
<< (8 - si
->bits
)) - l
;
1739 deltar
= (or << (8 - si
->bits
)) - r
;
1741 l
= l
>> (8 - si
->bits
);
1742 r
= r
>> (8 - si
->bits
);
1744 if (deltal
&& ol
== l
)
1745 l
+= (deltal
> 0) ? (l
? -1 : 0) : (l
< mask
? 1 : 0);
1746 if (deltar
&& or == r
)
1747 r
+= (deltar
> 0) ? (r
? -1 : 0) : (r
< mask
? 1 : 0);
1749 newval
= ((r
& mask
) << si
->ofs
);
1750 if (value
->num_channels
== 2) {
1751 newval
= newval
| ((l
& mask
) << (si
->ofs
+8));
1752 mask
|= (mask
<< 8);
1754 mask
= mask
<< si
->ofs
;
1761 error
= ac97_write(as
, si
->reg
, (val
& ~mask
) | newval
);
1765 if (spdif
&& as
->host_if
->spdif_event
!= NULL
) {
1766 DPRINTF(("%s: call spdif_event(%d)\n", __func__
, cp
->un
.ord
));
1767 as
->host_if
->spdif_event(as
->host_if
->arg
, cp
->un
.ord
);
1773 ac97_get_portnum_by_name(struct ac97_codec_if
*codec_if
, const char *class,
1774 const char *device
, const char *qualifier
)
1776 struct ac97_softc
*as
;
1779 as
= (struct ac97_softc
*)codec_if
;
1780 for (idx
= 0; idx
< as
->num_source_info
; idx
++) {
1781 struct ac97_source_info
*si
= &as
->source_info
[idx
];
1782 if (ac97_str_equal(class, si
->class) &&
1783 ac97_str_equal(device
, si
->device
) &&
1784 ac97_str_equal(qualifier
, si
->qualifier
))
1792 ac97_mixer_get_port(struct ac97_codec_if
*codec_if
, mixer_ctrl_t
*cp
)
1794 struct ac97_softc
*as
;
1795 struct ac97_source_info
*si
;
1799 as
= (struct ac97_softc
*)codec_if
;
1800 si
= &as
->source_info
[cp
->dev
];
1801 if (cp
->dev
< 0 || cp
->dev
>= as
->num_source_info
)
1804 if (cp
->type
!= si
->type
)
1807 ac97_read(as
, si
->reg
, &val
);
1809 DPRINTFN(5, ("read(%x) = %x\n", si
->reg
, val
));
1811 mask
= (1 << si
->bits
) - 1;
1814 case AUDIO_MIXER_ENUM
:
1815 cp
->un
.ord
= (val
>> si
->ofs
) & mask
;
1816 DPRINTFN(4, ("AUDIO_MIXER_ENUM: %x %d %x %d\n",
1817 val
, si
->ofs
, mask
, cp
->un
.ord
));
1819 case AUDIO_MIXER_VALUE
:
1821 const struct audio_mixer_value
*value
= si
->info
;
1824 if ((cp
->un
.value
.num_channels
<= 0) ||
1825 (cp
->un
.value
.num_channels
> value
->num_channels
))
1828 if (value
->num_channels
== 1) {
1829 l
= r
= (val
>> si
->ofs
) & mask
;
1831 if (!(as
->host_flags
& AC97_HOST_SWAPPED_CHANNELS
)) {
1832 l
= (val
>> (si
->ofs
+ 8)) & mask
;
1833 r
= (val
>> si
->ofs
) & mask
;
1834 } else { /* host has reversed channels */
1835 r
= (val
>> (si
->ofs
+ 8)) & mask
;
1836 l
= (val
>> si
->ofs
) & mask
;
1840 l
= (l
<< (8 - si
->bits
));
1841 r
= (r
<< (8 - si
->bits
));
1842 if (!si
->polarity
) {
1847 /* The EAP driver averages l and r for stereo
1848 channels that are requested in MONO mode. Does this
1850 if (cp
->un
.value
.num_channels
== 1) {
1851 cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_MONO
] = l
;
1852 } else if (cp
->un
.value
.num_channels
== 2) {
1853 cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_LEFT
] = l
;
1854 cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_RIGHT
] = r
;
1868 ac97_set_rate(struct ac97_codec_if
*codec_if
, int target
, u_int
*rate
)
1870 struct ac97_softc
*as
;
1877 as
= (struct ac97_softc
*)codec_if
;
1878 if (target
== AC97_REG_PCM_MIC_ADC_RATE
) {
1879 if (!(as
->ext_id
& AC97_EXT_AUDIO_VRM
)) {
1880 *rate
= AC97_SINGLE_RATE
;
1884 if (!(as
->ext_id
& AC97_EXT_AUDIO_VRA
)) {
1885 *rate
= AC97_SINGLE_RATE
;
1889 value
= *rate
* AC97_STANDARD_CLOCK
/ as
->ac97_clock
;
1892 * PCM_FRONT_DAC_RATE/PCM_SURR_DAC_RATE/PCM_LFE_DAC_RATE
1900 case AC97_REG_PCM_FRONT_DAC_RATE
:
1901 case AC97_REG_PCM_SURR_DAC_RATE
:
1902 case AC97_REG_PCM_LFE_DAC_RATE
:
1903 power_bit
= AC97_POWER_OUT
;
1904 if (!(as
->ext_id
& AC97_EXT_AUDIO_VRA
)) {
1905 *rate
= AC97_SINGLE_RATE
;
1908 if (as
->ext_id
& AC97_EXT_AUDIO_DRA
) {
1909 ac97_read(as
, AC97_REG_EXT_AUDIO_CTRL
, &ext_stat
);
1910 if (value
> 0x1ffff) {
1912 } else if (value
> 0xffff) {
1914 ext_stat
|= AC97_EXT_AUDIO_DRA
;
1915 ac97_write(as
, AC97_REG_EXT_AUDIO_CTRL
, ext_stat
);
1919 ext_stat
&= ~AC97_EXT_AUDIO_DRA
;
1920 ac97_write(as
, AC97_REG_EXT_AUDIO_CTRL
, ext_stat
);
1927 case AC97_REG_PCM_LR_ADC_RATE
:
1928 power_bit
= AC97_POWER_IN
;
1929 if (!(as
->ext_id
& AC97_EXT_AUDIO_VRA
)) {
1930 *rate
= AC97_SINGLE_RATE
;
1936 case AC97_REG_PCM_MIC_ADC_RATE
:
1937 power_bit
= AC97_POWER_IN
;
1938 if (!(as
->ext_id
& AC97_EXT_AUDIO_VRM
)) {
1939 *rate
= AC97_SINGLE_RATE
;
1946 printf("%s: Unknown register: 0x%x\n", __func__
, target
);
1950 ac97_read(as
, AC97_REG_POWER
, &power
);
1951 ac97_write(as
, AC97_REG_POWER
, power
| power_bit
);
1953 ac97_write(as
, target
, (uint16_t)value
);
1954 ac97_read(as
, target
, &actual
);
1955 actual
= (uint32_t)actual
* as
->ac97_clock
/ AC97_STANDARD_CLOCK
;
1957 ac97_write(as
, AC97_REG_POWER
, power
);
1958 if (ext_stat
& AC97_EXT_AUDIO_DRA
) {
1967 ac97_set_clock(struct ac97_codec_if
*codec_if
, unsigned int clock
)
1969 struct ac97_softc
*as
;
1971 as
= (struct ac97_softc
*)codec_if
;
1972 as
->ac97_clock
= clock
;
1976 ac97_get_extcaps(struct ac97_codec_if
*codec_if
)
1978 struct ac97_softc
*as
;
1980 as
= (struct ac97_softc
*)codec_if
;
1985 ac97_add_port(struct ac97_softc
*as
, const struct ac97_source_info
*src
)
1987 struct ac97_source_info
*si
;
1990 if ((as
->type
== AC97_CODEC_TYPE_AUDIO
&&
1991 as
->num_source_info
>= AUDIO_MAX_SOURCES
) ||
1992 (as
->type
== AC97_CODEC_TYPE_MODEM
&&
1993 as
->num_source_info
>= MODEM_MAX_SOURCES
)) {
1994 printf("%s: internal error: increase MAX_SOURCES in %s\n",
1995 __func__
, __FILE__
);
1998 if (!ac97_check_capability(as
, src
->req_feature
))
2000 ouridx
= as
->num_source_info
;
2001 si
= &as
->source_info
[ouridx
];
2002 memcpy(si
, src
, sizeof(*si
));
2005 case AUDIO_MIXER_CLASS
:
2006 case AUDIO_MIXER_VALUE
:
2007 printf("%s: adding class/value is not supported yet.\n",
2010 case AUDIO_MIXER_ENUM
:
2013 printf("%s: unknown type: %d\n", __func__
, si
->type
);
2016 as
->num_source_info
++;
2018 si
->mixer_class
= ac97_get_portnum_by_name(&as
->codec_if
, si
->class,
2020 /* Find the root of the device */
2021 idx
= ac97_get_portnum_by_name(&as
->codec_if
, si
->class,
2023 /* Find the last item */
2024 while (as
->source_info
[idx
].next
!= AUDIO_MIXER_LAST
)
2025 idx
= as
->source_info
[idx
].next
;
2027 as
->source_info
[idx
].next
= ouridx
;
2029 si
->next
= AUDIO_MIXER_LAST
;
2035 * Codec-dependent initialization
2038 #define AD1980_REG_MISC 0x76
2039 #define AD1980_MISC_MBG0 0x0001 /* 0 1888/1980/1981 /1985 */
2040 #define AD1980_MISC_MBG1 0x0002 /* 1 1888/1980/1981 /1985 */
2041 #define AD1980_MISC_VREFD 0x0004 /* 2 1888/1980/1981 /1985 */
2042 #define AD1980_MISC_VREFH 0x0008 /* 3 1888/1980/1981 /1985 */
2043 #define AD1980_MISC_SRU 0x0010 /* 4 1888/1980 /1985 */
2044 #define AD1980_MISC_LOSEL 0x0020 /* 5 1888/1980/1981 /1985 */
2045 #define AD1980_MISC_2CMIC 0x0040 /* 6 1980/1981B/1985 */
2046 #define AD1980_MISC_SPRD 0x0080 /* 7 1888/1980 /1985 */
2047 #define AD1980_MISC_DMIX0 0x0100 /* 8 1888/1980 /1985 */
2048 #define AD1980_MISC_DMIX1 0x0200 /* 9 1888/1980 /1985 */
2049 #define AD1980_MISC_HPSEL 0x0400 /*10 1888/1980 /1985 */
2050 #define AD1980_MISC_CLDIS 0x0800 /*11 1888/1980 /1985 */
2051 #define AD1980_MISC_LODIS 0x1000 /*12 1888/1980/1981 /1985 */
2052 #define AD1980_MISC_MSPLT 0x2000 /*13 1888/1980/1981 /1985 */
2053 #define AD1980_MISC_AC97NC 0x4000 /*14 1888/1980 /1985 */
2054 #define AD1980_MISC_DACZ 0x8000 /*15 1888/1980/1981 /1985 */
2055 #define AD1981_REG_MISC 0x76
2056 #define AD1981_MISC_MADST 0x0010 /* 4 */
2057 #define AD1981A_MISC_MADPD 0x0040 /* 6 */
2058 #define AD1981B_MISC_MADPD 0x0080 /* 7 */
2059 #define AD1981_MISC_FMXE 0x0200 /* 9 */
2060 #define AD1981_MISC_DAM 0x0800 /*11 */
2062 ac97_ad198x_init(struct ac97_softc
*as
)
2067 ac97_read(as
, AD1980_REG_MISC
, &misc
);
2068 ac97_write(as
, AD1980_REG_MISC
,
2069 misc
| AD1980_MISC_LOSEL
| AD1980_MISC_HPSEL
);
2071 for (i
= 0; i
< as
->num_source_info
; i
++) {
2072 if (as
->source_info
[i
].type
!= AUDIO_MIXER_VALUE
)
2075 if (as
->source_info
[i
].reg
== AC97_REG_MASTER_VOLUME
)
2076 as
->source_info
[i
].reg
= AC97_REG_SURR_MASTER
;
2077 else if (as
->source_info
[i
].reg
== AC97_REG_SURR_MASTER
)
2078 as
->source_info
[i
].reg
= AC97_REG_MASTER_VOLUME
;
2082 #define ALC650_REG_MULTI_CHANNEL_CONTROL 0x6a
2083 #define ALC650_MCC_SLOT_MODIFY_MASK 0xc000
2084 #define ALC650_MCC_FRONTDAC_FROM_SPDIFIN 0x2000 /* 13 */
2085 #define ALC650_MCC_SPDIFOUT_FROM_ADC 0x1000 /* 12 */
2086 #define ALC650_MCC_PCM_FROM_SPDIFIN 0x0800 /* 11 */
2087 #define ALC650_MCC_MIC_OR_CENTERLFE 0x0400 /* 10 */
2088 #define ALC650_MCC_LINEIN_OR_SURROUND 0x0200 /* 9 */
2089 #define ALC650_MCC_INDEPENDENT_MASTER_L 0x0080 /* 7 */
2090 #define ALC650_MCC_INDEPENDENT_MASTER_R 0x0040 /* 6 */
2091 #define ALC650_MCC_ANALOG_TO_CENTERLFE 0x0020 /* 5 */
2092 #define ALC650_MCC_ANALOG_TO_SURROUND 0x0010 /* 4 */
2093 #define ALC650_MCC_EXCHANGE_CENTERLFE 0x0008 /* 3 */
2094 #define ALC650_MCC_CENTERLFE_DOWNMIX 0x0004 /* 2 */
2095 #define ALC650_MCC_SURROUND_DOWNMIX 0x0002 /* 1 */
2096 #define ALC650_MCC_LINEOUT_TO_SURROUND 0x0001 /* 0 */
2098 ac97_alc650_init(struct ac97_softc
*as
)
2100 static const struct ac97_source_info sources
[6] = {
2101 { AudioCoutputs
, AudioNsurround
, "lineinjack",
2102 AUDIO_MIXER_ENUM
, WRAP(ac97_on_off
),
2103 ALC650_REG_MULTI_CHANNEL_CONTROL
,
2104 0x0000, 1, 9, 0, 0, 0, CHECK_SURROUND
, 0, 0, 0, },
2105 { AudioCoutputs
, AudioNsurround
, "mixtofront",
2106 AUDIO_MIXER_ENUM
, WRAP(ac97_on_off
),
2107 ALC650_REG_MULTI_CHANNEL_CONTROL
,
2108 0x0000, 1, 1, 0, 0, 0, CHECK_SURROUND
, 0, 0, 0, },
2109 { AudioCoutputs
, AudioNcenter
, "micjack",
2110 AUDIO_MIXER_ENUM
, WRAP(ac97_on_off
),
2111 ALC650_REG_MULTI_CHANNEL_CONTROL
,
2112 0x0000, 1, 10, 0, 0, 0, CHECK_CENTER
, 0, 0, 0, },
2113 { AudioCoutputs
, AudioNlfe
, "micjack",
2114 AUDIO_MIXER_ENUM
, WRAP(ac97_on_off
),
2115 ALC650_REG_MULTI_CHANNEL_CONTROL
,
2116 0x0000, 1, 10, 0, 0, 0, CHECK_LFE
, 0, 0, 0, },
2117 { AudioCoutputs
, AudioNcenter
, "mixtofront",
2118 AUDIO_MIXER_ENUM
, WRAP(ac97_on_off
),
2119 ALC650_REG_MULTI_CHANNEL_CONTROL
,
2120 0x0000, 1, 2, 0, 0, 0, CHECK_CENTER
, 0, 0, 0, },
2121 { AudioCoutputs
, AudioNlfe
, "mixtofront",
2122 AUDIO_MIXER_ENUM
, WRAP(ac97_on_off
),
2123 ALC650_REG_MULTI_CHANNEL_CONTROL
,
2124 0x0000, 1, 2, 0, 0, 0, CHECK_LFE
, 0, 0, 0, },
2127 ac97_add_port(as
, &sources
[0]);
2128 ac97_add_port(as
, &sources
[1]);
2129 ac97_add_port(as
, &sources
[2]);
2130 ac97_add_port(as
, &sources
[3]);
2131 ac97_add_port(as
, &sources
[4]);
2132 ac97_add_port(as
, &sources
[5]);
2135 #define UCB1400_REG_FEATURE_CSR1 0x6a
2136 #define UCB1400_BB(bb) (((bb) & 0xf) << 11)
2137 #define UCB1400_TR(tr) (((tr) & 0x3) << 9)
2138 #define UCB1400_M_MAXIMUM (3 << 7)
2139 #define UCB1400_M_MINIMUM (1 << 7)
2140 #define UCB1400_M_FLAT (0 << 7)
2141 #define UCB1400_HPEN (1 << 6)
2142 #define UCB1400_DE (1 << 5)
2143 #define UCB1400_DC (1 << 4)
2144 #define UCB1400_HIPS (1 << 3)
2145 #define UCB1400_GIEN (1 << 2)
2146 #define UCB1400_OVFL (1 << 0)
2147 #define UCB1400_REG_FEATURE_CSR2 0x6c
2148 #define UCB1400_SMT (1 << 15) /* Must be 0 */
2149 #define UCB1400_SUEV1 (1 << 14) /* Must be 0 */
2150 #define UCB1400_SUEV0 (1 << 13) /* Must be 0 */
2151 #define UCB1400_AVE (1 << 12)
2152 #define UCB1400_AVEN1 (1 << 11) /* Must be 0 */
2153 #define UCB1400_AVEN0 (1 << 10) /* Must be 0 */
2154 #define UCB1400_SLP_ON \
2155 (UCB1400_SLP_PLL | UCB1400_SLP_CODEC)
2156 #define UCB1400_SLP_PLL (2 << 4)
2157 #define UCB1400_SLP_CODEC (1 << 4)
2158 #define UCB1400_SLP_NO (0 << 4)
2159 #define UCB1400_EV2 (1 << 2) /* Must be 0 */
2160 #define UCB1400_EV1 (1 << 1) /* Must be 0 */
2161 #define UCB1400_EV0 (1 << 0) /* Must be 0 */
2163 ac97_ucb1400_init(struct ac97_softc
*as
)
2166 ac97_write(as
, UCB1400_REG_FEATURE_CSR1
,
2167 UCB1400_HPEN
| UCB1400_DC
| UCB1400_HIPS
| UCB1400_OVFL
);
2168 ac97_write(as
, UCB1400_REG_FEATURE_CSR2
, UCB1400_AVE
| UCB1400_SLP_ON
);
2171 #define VT1616_REG_IO_CONTROL 0x5a
2172 #define VT1616_IC_LVL (1 << 15)
2173 #define VT1616_IC_LFECENTER_TO_FRONT (1 << 12)
2174 #define VT1616_IC_SURROUND_TO_FRONT (1 << 11)
2175 #define VT1616_IC_BPDC (1 << 10)
2176 #define VT1616_IC_DC (1 << 9)
2177 #define VT1616_IC_IB_MASK 0x000c
2179 ac97_vt1616_init(struct ac97_softc
*as
)
2181 static const struct ac97_source_info sources
[3] = {
2182 { AudioCoutputs
, AudioNsurround
, "mixtofront",
2183 AUDIO_MIXER_ENUM
, WRAP(ac97_on_off
),
2184 VT1616_REG_IO_CONTROL
,
2185 0x0000, 1, 11, 0, 0, 0, CHECK_SURROUND
, 0, 0, 0, },
2186 { AudioCoutputs
, AudioNcenter
, "mixtofront",
2187 AUDIO_MIXER_ENUM
, WRAP(ac97_on_off
),
2188 VT1616_REG_IO_CONTROL
,
2189 0x0000, 1, 12, 0, 0, 0, CHECK_CENTER
, 0, 0, 0, },
2190 { AudioCoutputs
, AudioNlfe
, "mixtofront",
2191 AUDIO_MIXER_ENUM
, WRAP(ac97_on_off
),
2192 VT1616_REG_IO_CONTROL
,
2193 0x0000, 1, 12, 0, 0, 0, CHECK_LFE
, 0, 0, 0, },
2196 ac97_add_port(as
, &sources
[0]);
2197 ac97_add_port(as
, &sources
[1]);
2198 ac97_add_port(as
, &sources
[2]);
2202 ac97_modem_offhook_set(struct ac97_softc
*as
, int line
, int newval
)
2206 val
= as
->shadow_reg
[AC97_REG_GPIO_STATUS
>> 1];
2215 ac97_write(as
, AC97_REG_GPIO_STATUS
, val
);
2221 ac97_sysctl_verify(SYSCTLFN_ARGS
)
2224 struct sysctlnode node
;
2225 struct ac97_softc
*as
;
2228 as
= rnode
->sysctl_data
;
2229 if (node
.sysctl_num
== as
->offhook_line1_mib
) {
2230 tmp
= as
->offhook_line1
;
2231 node
.sysctl_data
= &tmp
;
2232 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
2233 if (error
|| newp
== NULL
)
2236 if (tmp
< 0 || tmp
> 1)
2239 as
->offhook_line1
= tmp
;
2240 ac97_modem_offhook_set(as
, AC97_GPIO_LINE1_OH
, tmp
);
2241 } else if (node
.sysctl_num
== as
->offhook_line2_mib
) {
2242 tmp
= as
->offhook_line2
;
2243 node
.sysctl_data
= &tmp
;
2244 error
= sysctl_lookup(SYSCTLFN_CALL(&node
));
2245 if (error
|| newp
== NULL
)
2248 if (tmp
< 0 || tmp
> 1)
2251 as
->offhook_line2
= tmp
;
2252 ac97_modem_offhook_set(as
, AC97_GPIO_LINE2_OH
, tmp
);