88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER START
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The contents of this file are subject to the terms of the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Common Development and Distribution License (the "License").
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * You may not use this file except in compliance with the License.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * or http://www.opensolaris.org/os/licensing.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * See the License for the specific language governing permissions
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * and limitations under the License.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER END
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Copyright (C) 4Front Technologies 1996-2008.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Use is subject to license terms.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/types.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/list.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/sysmacros.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/ddi.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/sunddi.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/audio/audio_driver.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/audio/ac97.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/note.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include "ac97_impl.h"
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is the initial value for many controls. This is
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * a 75% level.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore#define INIT_VAL_MAIN 75
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define INIT_VAL_ST ((75 << 8) | 75)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define INIT_VAL_MN 75
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define INIT_IGAIN_ST ((50 << 8) | 50)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define INIT_IGAIN_MN 50
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * In AC'97 v2.3, the registers are carved up as follows:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Audio Base Registers: 0x00 - 0x26
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Audio Extended Registers: 0x28 - 0x3A
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Modem Extended Registers: 0x3C - 0x58
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Vendor Reserved Registers: 0x5A - 0x5F
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Page Registers: 0x60 - 0x6F
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Vendor Reserved Registers: 0x70 - 0x7A
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Vendor ID Registers: 0x7C - 0x7F
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * We only need to shadow the normal audio registers by default.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * TBD: Handling of codec-specific registers in vendor reserved space.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * We cannot necessarily meaningfully shadow them.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define LAST_SHADOW_REG 0x3A
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define NUM_SHADOW ((LAST_SHADOW_REG / sizeof (uint16_t)) + 1)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define SHADOW(ac, reg) ((ac)->shadow[((reg) / sizeof (uint16_t))])
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Record source selection.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define INPUT_MIC 0
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define INPUT_CD 1
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define INPUT_VIDEO 2
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define INPUT_AUXIN 3
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define INPUT_LINEIN 4
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define INPUT_STEREOMIX 5
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define INPUT_MONOMIX 6
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define INPUT_PHONE 7
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amorestatic const char *ac_insrcs[] = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AUDIO_PORT_MIC,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AUDIO_PORT_CD,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AUDIO_PORT_VIDEO,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AUDIO_PORT_AUX1IN,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AUDIO_PORT_LINEIN,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AUDIO_PORT_STEREOMIX,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AUDIO_PORT_MONOMIX,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AUDIO_PORT_PHONE,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Per audio device state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestruct ac97 {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dev_info_t *dip; /* DDI device instance */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_t *d;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore void *private; /* drivers devc */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_rd_t rd; /* drivers port read routine */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_wr_t wr; /* drivers port write routine */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore char name[128]; /* driver instance name */
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore uint8_t nchan;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t shadow[NUM_SHADOW];
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t flags;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define AC97_FLAG_AMPLIFIER (1 << 0) /* ext. amp on by default */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define AC97_FLAG_MICBOOST (1 << 1) /* micboost on by default */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define AC97_FLAG_SPEAKER (1 << 2) /* mono out on by default */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define AC97_FLAG_AUX_HP (1 << 4) /* possible uses for AUX_OUT */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define AC97_FLAG_AUX_4CH (1 << 5)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define AC97_FLAG_AUX_LVL (1 << 6)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define AC97_FLAG_SPEAKER_OK (1 << 7) /* expose mono out */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define AC97_FLAG_NO_HEADPHONE (1 << 8) /* do not expose headphone */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define AC97_FLAG_NO_CDROM (1 << 9) /* do not expose CDROM */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define AC97_FLAG_NO_PHONE (1 << 10) /* do not expose phone in */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define AC97_FLAG_NO_VIDEO (1 << 11) /* do not expose video in */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define AC97_FLAG_NO_AUXIN (1 << 12) /* do not expose aux in */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define AC97_FLAG_NO_AUXOUT (1 << 13) /* do not expose aux out */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define AC97_FLAG_NO_LINEIN (1 << 14) /* do not expose linein */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define AC97_FLAG_NO_MIC (1 << 15) /* do not expose mic */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t vid; /* Vendor ID for CODEC */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t caps;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore void (*codec_init)(ac97_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore void (*codec_reset)(ac97_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore list_t ctrls;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint64_t inputs;
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestruct modlmisc ac97_modlmisc = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &mod_miscops,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "Audio Codec '97 Support"
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestruct modlinkage ac97_modlinkage = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore MODREV_1,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { &ac97_modlmisc, NULL }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore_init(void)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (mod_install(&ac97_modlinkage));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore_fini(void)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (mod_install(&ac97_modlinkage));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore_info(struct modinfo *modinfop)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (mod_info(&ac97_modlinkage, modinfop));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#if 0
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The following table, and the code to scale it, works in percentages.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This may be convenient for humans, but it would be faster if the table
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * entries were rescaled to 256. (Division by 100 is painful. Divison by
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 256 is trivial.)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic const char ac97_val_cvt[101] = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0, 0, 3, 7, 10, 13, 16, 19,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 21, 23, 26, 28, 30, 32, 34, 35,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 37, 39, 40, 42, 43, 45, 46, 47,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 49, 50, 51, 52, 53, 55, 56, 57,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 58, 59, 60, 61, 62, 63, 64, 65,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 65, 66, 67, 68, 69, 70, 70, 71,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 72, 73, 73, 74, 75, 75, 76, 77,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 77, 78, 79, 79, 80, 81, 81, 82,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 82, 83, 84, 84, 85, 85, 86, 86,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 87, 87, 88, 88, 89, 89, 90, 90,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 91, 91, 92, 92, 93, 93, 94, 94,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 95, 95, 96, 96, 96, 97, 97, 98,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 98, 98, 99, 99, 100
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#endif
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This code has three main functions. All related to converting
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * a standard controls value to hardware specific values. All
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Standard passed in values are 0-100 as in percent.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * First it takes a value passed in as volume or gain and
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * converts to attenuation or gain correspondingly. Since this is
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * what the hardware needs.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Second it adjusts the value passed in to compensate for the none
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * linear nature of human hearing, sound loudness, sensitivity. It
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * converts the linear value to a logarithmic value. This gives users
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the perception that the controls are linear.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Third it converts the value to the number of bits that a hardware
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * register needs to be.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * On input the following are supplied:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * left - The gain or volume in percent for left channel.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * right - The gain or volume in percent for right channel.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * bits - The number of bits the hardware needs. If this value
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * is negetive then right and left are gain else they
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * are volume.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * On return the following is returned:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * bit: 15 8 7 0
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ----------------------------------
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * | left channel | right channel |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ----------------------------------
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ( each channel is "bits" wide )
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreuint16_t
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_val_scale(int left, int right, int bits)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(left <= 100);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(right <= 100);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (bits < 0) { /* This is gain not ATTN */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore left = 100 - left;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore right = 100 - right;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore bits = -bits;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#if 0
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 4Front's code used a table to smooth the transitions
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * somewhat. Without this change, the volume levels adjusted
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * near the top of the table seem to have less effect. Its
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * hard to notice a volume change from 100 to 95, without the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * val_cvt table, for example. However, the scaling has an
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ugly side effect, which is at the default volumes (75%), we
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * wind up having the level set too high for some
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * codec/amplifier combinations.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Legacy Sun code didn't have this table, and some
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * qualitative testing shows that it isn't really necessary.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore left = 100 - ac97_val_cvt[left];
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore right = 100 - ac97_val_cvt[right];
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#else
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore left = 100 - left;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore right = 100 - right;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#endif
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (((left * ((1 << bits) - 1) / 100) << 8) |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (right * ((1 << bits) - 1) / 100));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreuint16_t
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_mono_scale(int val, int bits)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(val <= 100);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (bits < 0) { /* This is gain not ATTN */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore bits = -bits;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore val = 100 - val; /* convert to attenuation */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (val * ((1 << bits) - 1) / 100);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio_dev_t *
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_get_dev(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (ac->d);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_get_prop(ac97_t *ac, char *prop, int defval)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int rv;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rv = ddi_prop_get_int(DDI_DEV_T_ANY, ac->dip, DDI_PROP_DONTPASS,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore prop, defval);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (rv);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This calls the Hardware drivers access write routine
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * to write to a device register.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define WR(r, v) (ac)->wr((ac)->private, (r), (v))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define RD(r) (ac)->rd((ac)->private, (r))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Probe routines for optional controls
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * These routines each probe one aspect of hardware
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * for controls presents.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If the control is present these routines should
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * return none zero.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Is the named register implemented? This routine saves and
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * restores the original value, and relies on the fact that the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * registers (if implemented) will have at least one bit that acts
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * as a mute (0x8000, 0x8080), so we can probe "silently".
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The probe logic is suggested by the AC'97 2.3 spec. (Unimplemented
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * registers are required to return zero to facilitate this sort of
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * detection.)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_reg(ac97_t *ac, uint8_t reg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t val;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int rv = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* get the original value */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore val = RD(reg);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore WR(reg, 0xffff);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (RD(reg) != 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rv = 1;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* restore the original value */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore WR(reg, val);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (rv);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have bass/treble controls?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_tone(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Bass/Treble contols present */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ac->caps & RR_BASS_TREBLE)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore else
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If there is a loudness switch?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_loud(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* loudness contol present */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ac->caps & RR_LOUDNESS_SUPPORT)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore else
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a mono-mic input volume control?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_mmic(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* mono mic present */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ac->caps & RR_DEDICATED_MIC)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore else
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a simulated stereo switch?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_stsim(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* simulated stereocontol present */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ac->caps & RR_PSEUDO_STEREO)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore else
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a PC beeper input volume control?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_pcbeep(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore return (ac_probe_reg(ac, AC97_PC_BEEP_REGISTER));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have AUX output port volume control?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_rear(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ac->flags & AC97_FLAG_AUX_4CH)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore else
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a mic?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_mic(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((!(ac->flags & AC97_FLAG_NO_MIC)) &&
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore (ac_probe_reg(ac, AC97_MIC_VOLUME_REGISTER))) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->inputs |= (1U << INPUT_MIC);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If this device has an AUX output port is it used for headphones?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_headphone(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* headphone control present */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((ac->flags & AC97_FLAG_AUX_HP) &&
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore !(ac->flags & AC97_FLAG_NO_HEADPHONE)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have AUX output port volume control?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_auxout(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* ALT PCM control present */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((ac->flags & AC97_FLAG_AUX_LVL) &&
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore !(ac->flags & AC97_FLAG_NO_AUXOUT)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have an AUX input port volume control?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_auxin(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((!(ac->flags & AC97_FLAG_NO_AUXIN)) &&
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore (ac_probe_reg(ac, AC97_AUX_VOLUME_REGISTER))) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->inputs |= (1U << INPUT_AUXIN);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a phone input port with a volume control?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_phone(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((!(ac->flags & AC97_FLAG_NO_PHONE)) &&
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore (ac_probe_reg(ac, AC97_PHONE_VOLUME_REGISTER))) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->inputs |= (1U << INPUT_PHONE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a mono output port with volume control?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_mono(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!(ac->flags & AC97_FLAG_SPEAKER_OK)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore if (ac_probe_reg(ac, AC97_MONO_MASTER_VOLUME_REGISTER)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a line input port with volume control?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_linein(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((!(ac->flags & AC97_FLAG_NO_LINEIN)) &&
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore (ac_probe_reg(ac, AC97_LINE_IN_VOLUME_REGISTER))) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->inputs |= (1U << INPUT_LINEIN);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a cdrom input port with volume control?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_cdrom(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((!(ac->flags & AC97_FLAG_NO_CDROM)) &&
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore (ac_probe_reg(ac, AC97_CD_VOLUME_REGISTER))) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->inputs |= (1U << INPUT_CD);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a video input port with volume control?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_video(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((!(ac->flags & AC97_FLAG_NO_VIDEO)) &&
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore (ac_probe_reg(ac, AC97_VIDEO_VOLUME_REGISTER))) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->inputs |= (1U << INPUT_VIDEO);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a 3D sound enhancement?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_3d(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* 3D control present */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ac->caps & RR_3D_STEREO_ENHANCE_MASK)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore else
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_3d_impl(ac97_t *ac, uint16_t mask)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int rv = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t val;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((ac->caps & RR_3D_STEREO_ENHANCE_MASK) == 0)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* get the original value */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore val = RD(AC97_THREE_D_CONTROL_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore WR(AC97_THREE_D_CONTROL_REGISTER, mask);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((RD(AC97_THREE_D_CONTROL_REGISTER) & mask) != 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rv = 1;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* restore the original value */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore WR(AC97_THREE_D_CONTROL_REGISTER, val);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (rv);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_3d_depth(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore return (ac_probe_3d_impl(ac, TDCR_DEPTH_MASK));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_3d_center(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore return (ac_probe_3d_impl(ac, TDCR_CENTER_MASK));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a center output port with volume control?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_center(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t val;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore val = RD(AC97_EXTENDED_AUDIO_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* center volume present */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (val & EAR_CDAC)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore else
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a LFE (Sub-woofer) output port with
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * a volume control?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_lfe(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t val;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore val = RD(AC97_EXTENDED_AUDIO_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* We have LFE control */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (val & EAR_LDAC)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore else
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Are we a multichannel codec?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_front(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t val;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore val = RD(AC97_EXTENDED_AUDIO_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Are any of the Surround, Center, or LFE dacs present? */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (val & (EAR_SDAC | EAR_CDAC | EAR_LDAC))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore else
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probe_lineout(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* if not multichannel, then use "lineout" instead of "front" label */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore return (!ac_probe_front(ac));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amorestatic const char *ac_mics[] = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AUDIO_PORT_MIC1,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AUDIO_PORT_MIC2,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amorestatic const char *ac_monos[] = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AUDIO_PORT_MONOMIX,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AUDIO_PORT_MIC,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This calls the Hardware drivers access write routine
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * to write to a device register.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorevoid
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_wr(ac97_t *ac, uint8_t reg, uint16_t val)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((reg < LAST_SHADOW_REG) && (reg > 0)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SHADOW(ac, reg) = val;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ac->wr(ac->private, reg, val);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This obtains the shadowed value of a register. If the register is
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * out of range, zero is returned.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * To read a hardware register, use the RD() macro above.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreuint16_t
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_rd(ac97_t *ac, uint8_t reg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((reg < LAST_SHADOW_REG) && (reg > 0)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (SHADOW(ac, reg));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore return (ac->rd(ac->private, reg));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This calls the hardware driver's access read/write routine
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * to set bits in a device register.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorevoid
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_set(ac97_t *ac, uint8_t reg, uint16_t val)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_wr(ac, reg, ac->rd(ac->private, reg) | val);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This calls the hardware driver's access read/write routine
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * to clear bits in a device register.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorevoid
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_clr(ac97_t *ac, uint8_t reg, uint16_t val)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_wr(ac, reg, ac->rd(ac->private, reg) & ~val);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Look for a control attached to this device based
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * on its control number.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If this control number is found the per controls state
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * structure is returned.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_ctrl_t *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_control_find(ac97_t *ac, const char *name)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_ctrl_t *ctrl;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore list_t *l = &ac->ctrls;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Validate that ctrlnum is real and usable */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (ctrl = list_head(l); ctrl; ctrl = list_next(l, ctrl)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (strcmp(ctrl->actrl_name, name) == 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (ctrl);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (NULL);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This will update all the codec registers from the shadow table.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_restore(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If we are restoring previous settings, just reload from the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * shadowed settings.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 2; i < LAST_SHADOW_REG; i += sizeof (uint16_t)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->wr(ac->private, i, SHADOW(ac, i));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This will update all the hardware controls to the initial values at
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * start of day.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_init_values(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_ctrl_t *ctrl;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (ctrl = list_head(&ac->ctrls); ctrl;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl = list_next(&ac->ctrls, ctrl)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->actrl_value = ctrl->actrl_initval;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->actrl_write_fn(ctrl, ctrl->actrl_initval);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Select the input source for recording. This is the set routine
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * for the control AUDIO_CONTROL_INPUTS.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_insrc_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_t *ac = ctrl->actrl_ac97;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t set_val;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore set_val = ddi_ffs(value & 0xffff);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((set_val > 0) && (set_val <= 8)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore set_val--;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_wr(ac, AC97_RECORD_SELECT_CTRL_REGISTER,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore set_val | (set_val << 8));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_gpr_toggle(ac97_ctrl_t *ctrl, int bit, uint64_t onoff)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_t *ac = ctrl->actrl_ac97;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t v;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore v = SHADOW(ac, AC97_GENERAL_PURPOSE_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (onoff) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore v |= bit;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore v &= ~bit;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_wr(ac, AC97_GENERAL_PURPOSE_REGISTER, v);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_3donoff_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_gpr_toggle(ctrl, GPR_3D_STEREO_ENHANCE, value);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_loudness_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_gpr_toggle(ctrl, GPR_BASS_BOOST, value);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_loopback_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_gpr_toggle(ctrl, GPR_LPBK, value);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This will set simulated stereo control to on or off.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_stsim_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_gpr_toggle(ctrl, GPR_ST, value);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This will set mic select control to mic1=0 or mic2=1.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_selmic_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_gpr_toggle(ctrl, GPR_MS_MIC2, value & 2);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This will set mono source select control to mix=0 or mic=1.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_monosrc_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_gpr_toggle(ctrl, GPR_MONO_MIC_IN, value & 2);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_stereo_set(ac97_ctrl_t *ctrl, uint64_t value, uint8_t reg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_t *ac = ctrl->actrl_ac97;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint8_t left, right;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t mute;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore left = (value >> 8) & 0xff;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore right = value & 0xff;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mute = value ? 0 : ctrl->actrl_muteable;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_wr(ac, reg, ac_val_scale(left, right, ctrl->actrl_bits) | mute);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_mono_set(ac97_ctrl_t *ctrl, uint64_t value, uint8_t reg, int shift)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_t *ac = ctrl->actrl_ac97;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint8_t val;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t mute, v;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t mask;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore val = value & 0xff;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mute = val ? 0 : ctrl->actrl_muteable;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mask = ctrl->actrl_muteable |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (((1 << ABS(ctrl->actrl_bits)) - 1) << shift);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore v = SHADOW(ac, reg);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore v &= ~mask; /* clear all of our bits, preserve others */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* now set the mute bit, and volume bits */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore v |= mute;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore v |= (ac_mono_scale(val, ctrl->actrl_bits) << shift);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_wr(ac, reg, v);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_master_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore value = value | (value << 8);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_PCM_OUT_VOLUME_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_lineout_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_MASTER_VOLUME_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_surround_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_EXTENDED_LRS_VOLUME_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_aux1out_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_HEADPHONE_VOLUME_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_headphone_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_HEADPHONE_VOLUME_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_cd_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_CD_VOLUME_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_video_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_VIDEO_VOLUME_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_auxin_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_AUX_VOLUME_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_linein_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_LINE_IN_VOLUME_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This will set mono mic gain control.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_monomic_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_RECORD_GAIN_MIC_REGISTER, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_phone_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_PHONE_VOLUME_REGISTER, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_mic_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_MIC_VOLUME_REGISTER, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_speaker_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_MONO_MASTER_VOLUME_REGISTER, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_pcbeep_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_PC_BEEP_REGISTER, 1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_recgain_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_RECORD_GAIN_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_center_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_EXTENDED_C_LFE_VOLUME_REGISTER, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_lfe_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_EXTENDED_C_LFE_VOLUME_REGISTER, 8);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_bass_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_MASTER_TONE_CONTROL_REGISTER, 8);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_treble_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_MASTER_TONE_CONTROL_REGISTER, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_3ddepth_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * XXX: This is all wrong... 3D depth/center cannot necessarily
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * be scaled, because the technology in use may vary. We
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * need more information about each of the options available
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * to do the right thing.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_THREE_D_CONTROL_REGISTER, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_3dcent_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * XXX: This is all wrong... 3D depth/center cannot necessarily
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * be scaled, because the technology in use may vary. We
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * need more information about each of the options available
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * to do the right thing.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_THREE_D_CONTROL_REGISTER, 8);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_micboost_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_t *ac = ctrl->actrl_ac97;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t v;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore v = SHADOW(ac, AC97_MIC_VOLUME_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (value) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore v |= MICVR_20dB_BOOST;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore v &= ~MICVR_20dB_BOOST;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_wr(ac, AC97_MIC_VOLUME_REGISTER, v);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This will return the stored value for any control that has been set.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Note this does not return the actual hardware value from a port. But
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * instead returns the cached value from the last write to the hardware
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * port.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * arg - This control structure for this control.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * value - This is a pointer to the location to put the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * controls value.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * On success zero is returned.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreint
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac97_control_get(ac97_ctrl_t *ctrl, uint64_t *value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *value = ctrl->actrl_value;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreint
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac97_control_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint8_t v1, v2;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* a bit of quick checking */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (ctrl->actrl_type) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AUDIO_CTRL_TYPE_STEREO:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore v1 = (value >> 8) & 0xff;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore v2 = value & 0xff;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((v1 < ctrl->actrl_minval) || (v1 > ctrl->actrl_maxval) ||
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (v2 < ctrl->actrl_minval) || (v2 > ctrl->actrl_maxval) ||
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (value > 0xffff)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (EINVAL);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AUDIO_CTRL_TYPE_ENUM:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((value & ~ctrl->actrl_minval) !=
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (ctrl->actrl_maxval & ~ctrl->actrl_minval)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (EINVAL);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AUDIO_CTRL_TYPE_MONO:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AUDIO_CTRL_TYPE_BOOLEAN:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((value < ctrl->actrl_minval) ||
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (value > ctrl->actrl_maxval)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (EINVAL);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->actrl_value = value;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->actrl_write_fn(ctrl, value);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_get_value(void *arg, uint64_t *value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore return (ac97_control_get(arg, value));
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore}
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amorestatic int
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_set_value(void *arg, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore return (ac97_control_set(arg, value));
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore}
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Reset the analog codec hardware
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Reset all analog AC97 hardware, input ADC's, output DAC's and MIXER.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Wait a resonable amount of time for hardware to become ready.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_analog_reset(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t tmp;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int wait = 1000; /* delay for up to 1s */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Clear stale data and resync register accesses */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp = RD(AC97_POWERDOWN_CTRL_STAT_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* reset the codec */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore WR(AC97_RESET_REGISTER, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp = RD(AC97_RESET_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* power up */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore WR(AC97_POWERDOWN_CTRL_STAT_REGISTER, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Wait for ADC/DAC/MIXER to become ready */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore while (wait--) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* 1 msec delay */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(1000);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* If all ready - end delay */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp = RD(AC97_POWERDOWN_CTRL_STAT_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SHADOW(ac, AC97_POWERDOWN_CTRL_STAT_REGISTER) = tmp;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((tmp & PCSR_POWERD_UP) == PCSR_POWERD_UP) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore audio_dev_warn(ac->d, "AC'97 analog power up timed out");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is the internal hardware reset routine.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * It has no locking and we must be locked before it is
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * called!
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This will reset and re-initialize the device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * It has two modes of operation that affect how it handles
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * all controls.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * It re-initializes the device and reloads values with
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * last updated versions.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_hw_reset(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Fully Power up the device
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ac->flags & AC97_FLAG_AMPLIFIER) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* power up - external amp powerd up */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_wr(ac, AC97_POWERDOWN_CTRL_STAT_REGISTER, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* power up - external amp powered down */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_wr(ac, AC97_POWERDOWN_CTRL_STAT_REGISTER, PCSR_EAPD);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_wr(ac, AC97_GENERAL_PURPOSE_REGISTER, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (ac->vid) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AC97_CODEC_STAC9708:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#if 0
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* non-inverted phase */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore /* ac_rd(ac, AC97_VENDOR_REGISTER_11) & ~0x8); */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#endif
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore WR(AC97_VENDOR_REGISTER_11, 8);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AC97_CODEC_AD1886:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* jack sense */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore WR(AC97_VENDOR_REGISTER_13,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (RD(AC97_VENDOR_REGISTER_13) & ~0xEF) | 0x10);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AC97_CODEC_AD1888:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore WR(AC97_VENDOR_REGISTER_15, 0xC420);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#if 0
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* GED: This looks fishy to me, so I'm nuking it for now */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* headphone/aux volume (?) */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_wr(ac, AC97_HEADPHONE_VOLUME_REGISTER, 0x0808);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#endif
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AC97_CODEC_AD1980:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#if 0
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* set jacksense to mute line if headphone is plugged */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore WR(AC97_VENDOR_REGISTER_13,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (RD(AC97_VENDOR_REGISTER_13) & ~0xe00) | 0x400);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#endif
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore WR(AC97_VENDOR_REGISTER_15, 0xC420);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AC97_CODEC_AD1985:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore WR(AC97_VENDOR_REGISTER_15, 0xC420);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AC97_CODEC_WM9704:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* enable I2S */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore WR(AC97_VENDOR_REGISTER_01, RD(AC97_VENDOR_REGISTER_01) | 0x80);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AC97_CODEC_VT1612A:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AC97_CODEC_VT1617A:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AC97_CODEC_VT1616:
992413f4053d9470046876b234fe094062b730b7Garrett D'Amore /* Turn on Center, Surround, and LFE DACs */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_clr(ac, AC97_EXTENDED_AUDIO_STAT_CTRL_REGISTER,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore EASCR_PRI | EASCR_PRJ | EASCR_PRK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore WR(AC97_VENDOR_REGISTER_01, 0x0230);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case AC97_CODEC_YMF753:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* set TX8 + 3AWE */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore WR(AC97_VENDOR_REGISTER_07, RD(AC97_VENDOR_REGISTER_07) | 0x9);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore default:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* call codec specific reset hook */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ac->codec_reset != NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->codec_reset(ac);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Turn off variable sampling rate support */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_clr(ac, AC97_EXTENDED_AUDIO_STAT_CTRL_REGISTER, EASCR_VRA);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * This will reset and re-initialize the device. It is still incumbent
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * on the caller (or the audio framework) to replay control settings!
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorevoid
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_reset(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_analog_reset(ac);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_hw_reset(ac);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_restore(ac);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore/*
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore * Return the number of channels supported by this codec.
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore */
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amoreint
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amoreac97_num_channels(ac97_t *ac)
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore{
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore return (ac->nchan);
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Register a control -- if it fails, it will generate a message to
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * syslog, but the driver muddles on. (Failure to register a control
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore * should never occur, but is generally benign if it happens.)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorevoid
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac97_control_register(ac97_ctrl_t *ctrl)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac97_t *ac = ctrl->actrl_ac97;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ASSERT(ac->d != NULL);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ctrl->actrl_suppress = B_FALSE;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore /* Register control with framework */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ctrl->actrl_ctrl = audio_dev_add_control(ac->d, &ctrl->actrl_desc,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_get_value, ac_set_value, ctrl);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore if (ctrl->actrl_ctrl == NULL) {
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore audio_dev_warn(ac->d, "AC97 %s alloc failed",
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ctrl->actrl_name);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore }
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore}
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amorevoid
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac97_control_unregister(ac97_ctrl_t *ctrl)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ctrl->actrl_suppress = B_TRUE;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore if (ctrl->actrl_ctrl != NULL) {
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore audio_dev_del_control(ctrl->actrl_ctrl);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ctrl->actrl_ctrl = NULL;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore }
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore}
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreconst char *
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac97_control_name(ac97_ctrl_t *ctrl)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore return (ctrl->actrl_name);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore}
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreconst audio_ctrl_desc_t *
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac97_control_desc(ac97_ctrl_t *ctrl)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore return (&ctrl->actrl_desc);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore}
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amorevoid
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac97_register_controls(ac97_t *ac)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac97_ctrl_t *ctrl;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore for (ctrl = list_head(&ac->ctrls); ctrl;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ctrl = list_next(&ac->ctrls, ctrl)) {
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore if (ctrl->actrl_suppress)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore continue;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac97_control_register(ctrl);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore }
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore}
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amorevoid
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac97_walk_controls(ac97_t *ac, ac97_ctrl_walk_t walker, void *arg)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac97_ctrl_t *ctrl;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore for (ctrl = list_head(&ac->ctrls); ctrl;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ctrl = list_next(&ac->ctrls, ctrl)) {
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore if (!(*walker)(ctrl, arg)) {
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore break;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore }
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore }
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore}
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amorevoid
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_add_control(ac97_t *ac, ac97_ctrl_probe_t *cpt)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_ctrl_t *ctrl;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore boolean_t is_new;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(ac);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(ac->d);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ctrl = ac97_control_find(ac, cpt->cp_name);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore if (ctrl != NULL) {
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore is_new = B_FALSE;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore } else {
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ctrl = kmem_zalloc(sizeof (ac97_ctrl_t), KM_SLEEP);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore is_new = B_TRUE;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore }
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ctrl->actrl_ac97 = ac;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ctrl->actrl_minval = cpt->cp_minval;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ctrl->actrl_maxval = cpt->cp_maxval;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ctrl->actrl_type = cpt->cp_type;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ctrl->actrl_name = cpt->cp_name;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ctrl->actrl_flags = cpt->cp_flags;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (cpt->cp_enum) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int e = 0; e < 64; e++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (cpt->cp_enum[e] == NULL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ctrl->actrl_enum[e] = cpt->cp_enum[e];
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Warning for extended controls this field gets changed
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * by audio_dev_add_control() to be a unique value.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->actrl_initval = cpt->cp_initval;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->actrl_muteable = cpt->cp_muteable;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->actrl_write_fn = cpt->cp_write_fn;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->actrl_bits = cpt->cp_bits;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore * Not that it can not be referenced until it is in the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * list. So again by adding to the list last we avoid the need
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore * for locks.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore if (is_new)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore list_insert_tail(&ac->ctrls, ctrl);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * De-Register and free up a control
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorevoid
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac97_control_remove(ac97_ctrl_t *ctrl)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_t *ac = ctrl->actrl_ac97;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore list_remove(&ac->ctrls, ctrl);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore if (ctrl->actrl_ctrl != NULL)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore audio_dev_del_control(ctrl->actrl_ctrl);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore kmem_free(ctrl, sizeof (ac97_ctrl_t));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is the master list of all controls known and handled by
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the AC97 framework. This is the list used to probe, allocate
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * and configure controls. If a control is not in this list it
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * will not be handled. If a control is in this list but does not
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * have a probe routine then it will always be included. If a
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * control in list has a probe routine then it must return true
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * for that control to be included.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define MONCTL (AC97_FLAGS | AUDIO_CTRL_FLAG_MONITOR)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define PLAYCTL (AC97_FLAGS | AUDIO_CTRL_FLAG_PLAY)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define RECCTL (AC97_FLAGS | AUDIO_CTRL_FLAG_REC)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define T3DCTL (AC97_FLAGS | AUDIO_CTRL_FLAG_3D)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define TONECTL (AC97_FLAGS | AUDIO_CTRL_FLAG_TONE)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define MAINVOL (PLAYCTL | AUDIO_CTRL_FLAG_MAINVOL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define PCMVOL (PLAYCTL | AUDIO_CTRL_FLAG_PCMVOL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define RECVOL (RECCTL | AUDIO_CTRL_FLAG_RECVOL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define MONVOL (MONCTL | AUDIO_CTRL_FLAG_MONVOL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_ctrl_probe_t ctrl_probe_tbl[] = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Master PCM Volume */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_VOLUME, INIT_VAL_MAIN, 0, 100, AUDIO_CTRL_TYPE_MONO,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PCMVOL, PCMOVR_MUTE, ac97_master_set, NULL, 5},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* LINE out volume */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_LINEOUT, INIT_VAL_ST, 0, 100, AUDIO_CTRL_TYPE_STEREO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore MAINVOL, 0x8080, ac97_lineout_set, ac_probe_lineout, 6},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Front volume */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_FRONT, INIT_VAL_ST, 0, 100, AUDIO_CTRL_TYPE_STEREO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore MAINVOL, 0x8080, ac97_lineout_set, ac_probe_front, 6},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* 4CH out volume (has one of three possible uses, first use) */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_SURROUND, INIT_VAL_ST, 0, 100, AUDIO_CTRL_TYPE_STEREO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore MAINVOL, 0x8080, ac97_surround_set, ac_probe_rear, 6},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* ALT out volume (has one of three possible uses, second use) */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_HEADPHONE, INIT_VAL_ST, 0, 100, AUDIO_CTRL_TYPE_STEREO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore MAINVOL, 0x8080, ac97_headphone_set, ac_probe_headphone, 6},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* ALT out volume (has one of three possible uses, third use) */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_AUX1OUT, INIT_VAL_ST, 0, 100, AUDIO_CTRL_TYPE_STEREO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore MAINVOL, 0x8080, ac97_aux1out_set, ac_probe_auxout, 6},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* center out volume */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_CENTER, INIT_VAL_MN, 0, 100, AUDIO_CTRL_TYPE_MONO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore MAINVOL, EXLFEVR_CENTER_MUTE, ac_center_set, ac_probe_center, 6},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* LFE out volume (sub-woofer) */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_LFE, INIT_VAL_MN, 0, 100, AUDIO_CTRL_TYPE_MONO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore MAINVOL, EXLFEVR_LFE_MUTE, ac_lfe_set, ac_probe_lfe, 6},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* MONO out volume */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_SPEAKER, INIT_VAL_MN, 0, 100, AUDIO_CTRL_TYPE_MONO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore MAINVOL, MMVR_MUTE, ac_speaker_set, ac_probe_mono, 6},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Record in GAIN */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_RECGAIN, INIT_IGAIN_ST, 0, 100, AUDIO_CTRL_TYPE_STEREO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore RECVOL, RGR_MUTE, ac_recgain_set, NULL, -4},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* MIC in volume */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_MIC, 0, 0, 100, AUDIO_CTRL_TYPE_STEREO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore MONVOL, MICVR_MUTE, ac_mic_set, ac_probe_mic, 5},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* LINE in volume */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_LINEIN, 0, 0, 100, AUDIO_CTRL_TYPE_STEREO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore MONVOL, LIVR_MUTE, ac_linein_set, ac_probe_linein, 5},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* CD in volume */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_CD, 0, 0, 100, AUDIO_CTRL_TYPE_STEREO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore MONVOL, CDVR_MUTE, ac_cd_set, ac_probe_cdrom, 5},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* VIDEO in volume */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_VIDEO, 0, 0, 100, AUDIO_CTRL_TYPE_STEREO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore MONVOL, VIDVR_MUTE, ac_video_set, ac_probe_video, 5},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* AUX in volume */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_AUX1IN, 0, 0, 100, AUDIO_CTRL_TYPE_STEREO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore MONVOL, AUXVR_MUTE, ac_auxin_set, ac_probe_auxin, 5},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* PHONE in volume */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_PHONE, 0, 0, 100, AUDIO_CTRL_TYPE_MONO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore MONVOL, PVR_MUTE, ac_phone_set, ac_probe_phone, 5},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* PC BEEPER in volume (motherboard speaker pins) */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_BEEP, INIT_VAL_MN, 0, 100, AUDIO_CTRL_TYPE_MONO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore AC97_RW, PCBR_MUTE, ac_pcbeep_set, ac_probe_pcbeep, 4},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* BASS out level (note, zero is hardware bypass) */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_BASS, 0, 0, 100, AUDIO_CTRL_TYPE_MONO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore TONECTL, 0, ac_bass_set, ac_probe_tone, 4},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* TREBLE out level (note, zero is hardware bypass) */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_TREBLE, 0, 0, 100, AUDIO_CTRL_TYPE_MONO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore TONECTL, 0, ac_treble_set, ac_probe_tone, 4},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Loudness on/off switch */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_LOUDNESS, 0, 0, 1, AUDIO_CTRL_TYPE_BOOLEAN,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore TONECTL, 0, ac_loudness_set, ac_probe_loud, 0},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* 3D depth out level */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_3DDEPTH, 0, 0, 100, AUDIO_CTRL_TYPE_MONO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore T3DCTL, 0, ac_3ddepth_set, ac_probe_3d_depth, 4},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* 3D center out level */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_3DCENT, 0, 0, 100, AUDIO_CTRL_TYPE_MONO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore T3DCTL, 0, ac_3dcent_set, ac_probe_3d_center, 4},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* 3D enhance on/off switch */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_3DENHANCE, 0, 0, 1, AUDIO_CTRL_TYPE_BOOLEAN,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore T3DCTL, 0, ac_3donoff_set, ac_probe_3d, 0},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* MIC BOOST switch */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_MICBOOST, 0, 0, 1, AUDIO_CTRL_TYPE_BOOLEAN,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore RECCTL, 0, ac97_micboost_set, ac_probe_mic, 0},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Loopback on/off switch */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_LOOPBACK, 0, 0, 1, AUDIO_CTRL_TYPE_BOOLEAN,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore AC97_RW, 0, ac_loopback_set, NULL, 0},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The following selectors *must* come after the others, as they rely
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * on the probe results of other controls.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* record src select (only one port at a time) */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_RECSRC, (1U << INPUT_MIC), 0, 0, AUDIO_CTRL_TYPE_ENUM,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore RECCTL, 0, ac_insrc_set, NULL, 0, ac_insrcs},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Start of non-standard private controls */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Simulated stereo on/off switch */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_STEREOSIM, 0, 0, 1, AUDIO_CTRL_TYPE_BOOLEAN,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore AC97_RW, 0, ac_stsim_set, ac_probe_stsim, 0},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* mono MIC GAIN */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_MICGAIN, INIT_IGAIN_MN, 0, 100, AUDIO_CTRL_TYPE_MONO,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore RECCTL, RGMR_MUTE, ac_monomic_set, ac_probe_mmic, -4},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* MIC select switch 0=mic1 1=mic2 */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_MICSRC, 1, 3, 3, AUDIO_CTRL_TYPE_ENUM,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore RECCTL, 0, ac_selmic_set, ac_probe_mic, 0, ac_mics},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* MONO out src select 0=mix 1=mic */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_SPKSRC, 1, 3, 3, AUDIO_CTRL_TYPE_ENUM,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore AC97_RW, 0, ac_monosrc_set, ac_probe_mono, 0, ac_monos},
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {NULL}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Probe all possible controls and register existing
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ones and set initial values
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns zero on success
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amorestatic void
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probeinit_ctrls(ac97_t *ac, int vol_bits, int enh_bits)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_ctrl_probe_t *cpt;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_ctrl_probe_t my_cpt;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(ac);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Set some ports which are always present.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->inputs = (1U << INPUT_STEREOMIX) | (1U << INPUT_MONOMIX);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (cpt = &ctrl_probe_tbl[0]; cpt->cp_name != NULL; cpt++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore bcopy(cpt, &my_cpt, sizeof (my_cpt));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (strcmp(my_cpt.cp_name, AUDIO_CTRL_ID_RECSRC) == 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore my_cpt.cp_minval |= ac->inputs;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore my_cpt.cp_maxval |= ac->inputs;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (strcmp(my_cpt.cp_name, AUDIO_CTRL_ID_MICBOOST) == 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ac->flags & AC97_FLAG_MICBOOST)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore my_cpt.cp_initval = 1;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((strcmp(my_cpt.cp_name, AUDIO_CTRL_ID_FRONT) == 0) ||
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (strcmp(my_cpt.cp_name, AUDIO_CTRL_ID_HEADPHONE) == 0) ||
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (strcmp(my_cpt.cp_name, AUDIO_CTRL_ID_SURROUND) == 0) ||
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (strcmp(my_cpt.cp_name, AUDIO_CTRL_ID_SPEAKER) == 0)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore my_cpt.cp_bits = vol_bits;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((strcmp(my_cpt.cp_name, AUDIO_CTRL_ID_3DDEPTH) == 0) ||
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (strcmp(my_cpt.cp_name, AUDIO_CTRL_ID_3DCENT) == 0)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore my_cpt.cp_bits = enh_bits;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!my_cpt.cp_probe || my_cpt.cp_probe(ac)) {
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_add_control(ac, &my_cpt);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ac->codec_init != NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->codec_init(ac);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Allocate an AC97 instance for use by a hardware driver.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * returns an allocated and initialize ac97 structure.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_t *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_alloc(dev_info_t *dip, ac97_rd_t rd, ac97_wr_t wr, void *priv)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_t *ac;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac = kmem_zalloc(sizeof (ac97_t), KM_SLEEP);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->dip = dip;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->rd = rd;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->wr = wr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->private = priv;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore list_create(&ac->ctrls, sizeof (struct ac97_ctrl),
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore offsetof(struct ac97_ctrl, actrl_linkage));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define PROP_FLAG(prop, flag, def) \
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, \
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (prop), (def))) { \
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->flags |= (flag); \
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else { \
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->flags &= ~(flag); \
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Engage the external amplifier by default, suppress with
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * a property of the form "ac97-amplifier=0".
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PROP_FLAG(AC97_PROP_AMPLIFIER, AC97_FLAG_AMPLIFIER, 1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * We cannot necessarily know if the headphone jack is present
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * or not. There's a technique to probe the codec for
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * headphone support, but many vendors seem to simply hang the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * headphone jack on the line out circuit, and have some kind
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * of jack sense detection to enable or disable it by default.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * None of this is visible in the AC'97 registers.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * We cannot do much about it, but what we can do is offer users
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * a way to suppress the option for a headphone port. Users and
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * administrators can then set a flag in the driver.conf to suppress
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the option from display.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * It turns out that this problem exists for other signals as
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * well.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PROP_FLAG(AC97_PROP_NO_HEADPHONE, AC97_FLAG_NO_HEADPHONE, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PROP_FLAG(AC97_PROP_NO_AUXOUT, AC97_FLAG_NO_AUXOUT, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PROP_FLAG(AC97_PROP_NO_CDROM, AC97_FLAG_NO_CDROM, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PROP_FLAG(AC97_PROP_NO_AUXIN, AC97_FLAG_NO_AUXIN, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PROP_FLAG(AC97_PROP_NO_VIDEO, AC97_FLAG_NO_VIDEO, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PROP_FLAG(AC97_PROP_NO_LINEIN, AC97_FLAG_NO_LINEIN, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PROP_FLAG(AC97_PROP_NO_MIC, AC97_FLAG_NO_MIC, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Most SPARC systems use the AC97 monoaural output for the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * built-in speaker. On these systems, we want to expose and
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * enable the built-in speaker by default.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * On most x86 systems, the mono output is not connected to
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * anything -- the AC'97 spec makes it pretty clear that the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * output was actually intended for use with speaker phones.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * So on those systems, we really don't want to activate the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * speaker -- we don't even want to expose it's presence
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * normally.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * However, there could be an exception to the rule here. To
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * facilitate this, we allow for the presence of the property
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * to indicate that the speaker should be exposed. Whether it
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * is enabled by default or not depends on the value of the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * property. (Generally on SPARC, we enable by default. On
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * other systems we do not.)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#ifdef __sparc
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->flags |= AC97_FLAG_SPEAKER_OK;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PROP_FLAG(AC97_PROP_SPEAKER, AC97_FLAG_SPEAKER, 1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#else
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AC97_PROP_SPEAKER)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->flags |= AC97_FLAG_SPEAKER_OK;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PROP_FLAG(AC97_PROP_SPEAKER, AC97_FLAG_SPEAKER, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#endif
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Enable microphone boost (20dB normally) by default?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PROP_FLAG(AC97_PROP_MICBOOST, AC97_FLAG_MICBOOST, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (ac);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore/*
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore * Allocate an AC97 instance for use by a hardware driver.
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore *
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore * returns an allocated and initialize ac97 structure.
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac97_t *
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac97_allocate(audio_dev_t *adev, dev_info_t *dip, ac97_rd_t rd, ac97_wr_t wr,
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore void *priv)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac97_t *ac;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac = ac97_alloc(dip, rd, wr, priv);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore if (ac != NULL) {
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac->d = adev;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore }
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore return (ac);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Free an AC97 instance.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorevoid
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_free(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_ctrl_t *ctrl;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Clear out any controls that are still attached */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore while ((ctrl = list_head(&ac->ctrls)) != NULL) {
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac97_control_remove(ctrl);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore list_destroy(&ac->ctrls);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore kmem_free(ac, sizeof (ac97_t));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic struct vendor {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore unsigned id;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore const char *name;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore} vendors[] = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_VENDOR_ADS, "Analog Devices" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_VENDOR_AKM, "Asahi Kasei" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_VENDOR_ALC, "Realtek" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_VENDOR_ALG, "Avance Logic" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_VENDOR_CMI, "C-Media" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_VENDOR_CRY, "Cirrus Logic" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_VENDOR_CXT, "Conexant" },
992413f4053d9470046876b234fe094062b730b7Garrett D'Amore { AC97_VENDOR_EMC, "eMicro" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_VENDOR_ESS, "ESS Technology" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_VENDOR_EV, "Ectiva" },
992413f4053d9470046876b234fe094062b730b7Garrett D'Amore { AC97_VENDOR_HRS, "Intersil" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_VENDOR_ICE, "ICEnsemble" },
992413f4053d9470046876b234fe094062b730b7Garrett D'Amore { AC97_VENDOR_ITE, "ITE, Inc." },
992413f4053d9470046876b234fe094062b730b7Garrett D'Amore { AC97_VENDOR_NSC, "National Semiconductor" },
992413f4053d9470046876b234fe094062b730b7Garrett D'Amore { AC97_VENDOR_PSC, "Philips Semiconductor" },
992413f4053d9470046876b234fe094062b730b7Garrett D'Amore { AC97_VENDOR_SIL, "Silicon Laboratories" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_VENDOR_ST, "SigmaTel" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_VENDOR_TRA, "TriTech", },
992413f4053d9470046876b234fe094062b730b7Garrett D'Amore { AC97_VENDOR_TXN, "Texas Instruments", },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_VENDOR_VIA, "VIA Technologies" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_VENDOR_WML, "Wolfson" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_VENDOR_YMH, "Yamaha" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { 0, NULL },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic struct codec {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore unsigned id;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore const char *name;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int enh_bits;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore void (*init)(ac97_t *ac);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore void (*reset)(ac97_t *ac);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore} codecs[] = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_AK4540, "AK4540" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_STAC9700, "STAC9700" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_STAC9701, "STAC9701" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_STAC9701_2, "STAC9701" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_STAC9704, "STAC9704" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_STAC9705, "STAC9705" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_STAC9721, "STAC9721" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_STAC9708, "STAC9708", 2 },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_STAC9744, "STAC9744" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_STAC9750, "STAC9750", 3 },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_STAC9752, "STAC9752", 3 },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_STAC9756, "STAC9756", 3 },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_STAC9758, "STAC9758", 3 },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_STAC9766, "STAC9766", 3 },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_TR28028, "TR28028" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_TR28028_2, "TR28028" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_TR28023, "TR28023" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_TR28023_2, "TR28023" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_EM28028, "EM28028" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_CX20468, "CX20468" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_CX20468_2, "CX20468" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_CX20468_21, "CX20468-21" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_CS4297, "CS4297" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_CS4297A, "CS4297A" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_CS4294, "CS4294" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_CS4299, "CS4299" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_CS4202, "CS4202" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_CS4205, "CS4205" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_AD1819B, "AD1819B" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_AD1881, "AD1881" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_AD1881A, "AD1881A" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_AD1885, "AD1885" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_AD1886, "AD1886" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_AD1887, "AD1887" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_AD1888, "AD1888" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_AD1980, "AD1980" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_AD1981, "AD1981" }, /* no data sheet */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_AD1981A, "AD1981A", 0, ad1981a_init },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_AD1981B, "AD1981B", 0, ad1981b_init },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_AD1985, "AD1985" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_WM9701A, "WM9701A" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_WM9703, "WM9703" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_WM9704, "WM9704" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_ES1921, "ES1921" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_ICE1232, "ICE1232/VT1611A" },
992413f4053d9470046876b234fe094062b730b7Garrett D'Amore { AC97_CODEC_LM4550, "LM4550" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_VT1612A, "VT1612A" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_VT1616, "VT1616" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_VT1616A, "VT1616A" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_VT1617A, "VT1617A" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_VT1618, "VT1618" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_ALC100, "ALC100", 2 },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_ALC200P, "ALC200P", 2 },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_ALC202, "ALC202", 2 },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_ALC203, "ALC203", 2 },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_ALC250, "ALC250", 2 },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_ALC250_2, "ALC250", 2 },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_ALC650, "ALC650", 2, alc650_init },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_ALC655, "ALC655", 2, alc650_init },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_ALC658, "ALC658", 2, alc650_init },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_ALC850, "ALC850", 2, alc850_init },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_EV1938, "EV1938" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_CMI9738, "CMI9738", 0, cmi9738_init },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_CMI9739, "CMI9739", 0, cmi9739_init },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_CMI9780, "CMI9780" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_CMI9761, "CMI9761A", 0, cmi9761_init },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_CMI9761_2, "CMI9761B", 0, cmi9761_init },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_CMI9761_3, "CMI9761A+", 0, cmi9761_init },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_YMF743, "YMF743" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_YMF753, "YMF753" },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { 0, NULL }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amorevoid
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac97_probe_controls(ac97_t *ac)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t vid1, vid2;
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore uint16_t ear;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore const char *name = NULL;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore const char *vendor = NULL;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int enh_bits;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int vol_bits;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t flags;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore char nmbuf[128];
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore char buf[128];
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore /* This is only valid when used with new style ac97_allocate(). */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ASSERT(ac->d);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_analog_reset(ac);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vid1 = RD(AC97_VENDOR_ID1_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vid2 = RD(AC97_VENDOR_ID2_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (vid1 == 0xffff) {
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore audio_dev_warn(ac->d, "AC'97 codec unresponsive");
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore return;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->vid = (vid1 << 16) | vid2;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Find out kind of codec we have and set any special case
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * settings needed.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; codecs[i].id; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ac->vid == codecs[i].id) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = codecs[i].name;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore enh_bits = codecs[i].enh_bits;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->codec_init = codecs[i].init;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; vendors[i].id; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((ac->vid & 0xffffff00) == vendors[i].id) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vendor = vendors[i].name;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (name == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) snprintf(nmbuf, sizeof (nmbuf), "0x%04x%04x",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vid1, vid2);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = nmbuf;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (vendor == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vendor = "Unknown";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Populate the initial shadow table.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; i < LAST_SHADOW_REG; i += sizeof (uint16_t)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SHADOW(ac, i) = RD(i);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->caps = RD(AC97_RESET_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore enh_bits = 4;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vol_bits = 6;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore flags = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* detect the bit width of the master volume controls */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore WR(AC97_MASTER_VOLUME_REGISTER, 0x20);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((RD(AC97_MASTER_VOLUME_REGISTER) & 0x1f) == 0x1f) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vol_bits = 5;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * AC'97 2.3 spec indicates three possible uses for AUX_OUT
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * (aka LNLVL_OUT aka HP_OUT). We have to figure out which one
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * is in use.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ac->caps & RR_HEADPHONE_SUPPORT) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* it looks like it is probably headphones */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore if (ac_probe_reg(ac, AC97_HEADPHONE_VOLUME_REGISTER)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* it is implemented */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->flags |= AC97_FLAG_AUX_HP;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore /* Read EAR just once. */
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore ear = RD(AC97_EXTENDED_AUDIO_REGISTER);
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If not a headphone, is it 4CH_OUT (surround?)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore if ((!(ac->flags & AC97_FLAG_AUX_HP)) && (ear & EAR_SDAC)) {
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore if (ac_probe_reg(ac, AC97_EXTENDED_LRS_VOLUME_REGISTER)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->flags |= AC97_FLAG_AUX_4CH;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If neither, then maybe its an auxiliary line level output?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!(ac->flags & (AC97_FLAG_AUX_HP | AC97_FLAG_AUX_4CH))) {
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore if (ac_probe_reg(ac, AC97_HEADPHONE_VOLUME_REGISTER)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->flags |= AC97_FLAG_AUX_LVL;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore /*
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore * How many channels?
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore */
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore ac->nchan = 2;
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore if (ear & EAR_SDAC) {
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore ac->nchan += 2;
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore }
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore if (ear & EAR_CDAC) {
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore ac->nchan++;
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore }
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore if (ear & EAR_LDAC) {
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore ac->nchan++;
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore }
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac->flags |= flags;
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore (void) snprintf(ac->name, sizeof (ac->name), "%s %s", vendor, name);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) snprintf(buf, sizeof (buf), "AC'97 codec: %s", ac->name);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore audio_dev_add_info(ac->d, buf);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore cmn_err(CE_CONT,
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore "?%s#%d: AC'97 codec id %s (%x, %d channels, caps %x)\n",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_driver_name(ac->dip), ddi_get_instance(ac->dip),
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore ac->name, ac->vid, ac->nchan, ac->caps);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Probe and register all known controls with framework
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_probeinit_ctrls(ac, vol_bits, enh_bits);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_hw_reset(ac);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_init_values(ac);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore}
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore/*
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore * Init the actual hardware related to a previously allocated instance
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore * of an AC97 device. This is a legacy function and should not be
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore * used in new code.
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore *
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore * Return zero on success.
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreint
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac97_init(ac97_t *ac, struct audio_dev *d)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore{
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore /* Make sure we aren't using this with new style ac97_allocate(). */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ASSERT(ac->d == NULL);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore /* Save audio framework instance structure */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac->d = d;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac97_probe_controls(ac);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac97_register_controls(ac);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}