88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER START
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 * 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 * 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 * CDDL HEADER END
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Copyright (C) 4Front Technologies 1996-2008.
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Use is subject to license terms.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is the initial value for many controls. This is
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * a 75% level.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * In AC'97 v2.3, the registers are carved up as follows:
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 * 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#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 * Record source selection.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Per audio device state structure
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#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#define AC97_FLAG_AUX_HP (1 << 4) /* possible uses for AUX_OUT */
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 "Audio Codec '97 Support"
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (mod_info(&ac97_modlinkage, modinfop));
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 * 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 * 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 * 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 * Third it converts the value to the number of bits that a hardware
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * register needs to be.
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 * On return the following is returned:
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 * 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 * 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 return (((left * ((1 << bits) - 1) / 100) << 8) |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore val = 100 - val; /* convert to attenuation */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_get_prop(ac97_t *ac, char *prop, int defval)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rv = ddi_prop_get_int(DDI_DEV_T_ANY, ac->dip, DDI_PROP_DONTPASS,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This calls the Hardware drivers access write routine
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * to write to a device register.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define WR(r, v) (ac)->wr((ac)->private, (r), (v))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Probe routines for optional controls
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 * 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 * 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 /* get the original value */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* restore the original value */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have bass/treble controls?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Bass/Treble contols present */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If there is a loudness switch?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* loudness contol present */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a mono-mic input volume control?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* mono mic present */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a simulated stereo switch?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* simulated stereocontol present */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a PC beeper input volume control?
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore return (ac_probe_reg(ac, AC97_PC_BEEP_REGISTER));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have AUX output port volume control?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a mic?
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore (ac_probe_reg(ac, AC97_MIC_VOLUME_REGISTER))) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If this device has an AUX output port is it used for headphones?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* headphone control present */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have AUX output port volume control?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* ALT PCM control present */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have an AUX input port volume control?
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore (ac_probe_reg(ac, AC97_AUX_VOLUME_REGISTER))) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a phone input port with a volume control?
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore (ac_probe_reg(ac, AC97_PHONE_VOLUME_REGISTER))) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a mono output port with volume control?
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore if (ac_probe_reg(ac, AC97_MONO_MASTER_VOLUME_REGISTER)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a line input port with volume control?
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore (ac_probe_reg(ac, AC97_LINE_IN_VOLUME_REGISTER))) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a cdrom input port with volume control?
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore (ac_probe_reg(ac, AC97_CD_VOLUME_REGISTER))) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a video input port with volume control?
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore (ac_probe_reg(ac, AC97_VIDEO_VOLUME_REGISTER))) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a 3D sound enhancement?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* 3D control present */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((ac->caps & RR_3D_STEREO_ENHANCE_MASK) == 0)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* get the original value */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((RD(AC97_THREE_D_CONTROL_REGISTER) & mask) != 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* restore the original value */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore return (ac_probe_3d_impl(ac, TDCR_DEPTH_MASK));
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore return (ac_probe_3d_impl(ac, TDCR_CENTER_MASK));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a center output port with volume control?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* center volume present */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Does this device have a LFE (Sub-woofer) output port with
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * a volume control?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* We have LFE control */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Are we a multichannel codec?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Are any of the Surround, Center, or LFE dacs present? */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* if not multichannel, then use "lineout" instead of "front" label */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This calls the Hardware drivers access write routine
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * to write to a device register.
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 * To read a hardware register, use the RD() macro above.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This calls the hardware driver's access read/write routine
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * to set bits in a device register.
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_set(ac97_t *ac, uint8_t reg, uint16_t val)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_wr(ac, reg, ac->rd(ac->private, reg) | val);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This calls the hardware driver's access read/write routine
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * to clear bits in a device register.
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_clr(ac97_t *ac, uint8_t reg, uint16_t val)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_wr(ac, reg, ac->rd(ac->private, reg) & ~val);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Look for a control attached to this device based
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * on its control number.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If this control number is found the per controls state
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * structure is returned.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_control_find(ac97_t *ac, const char *name)
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 * This will update all the codec registers from the shadow table.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If we are restoring previous settings, just reload from the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * shadowed settings.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 2; i < LAST_SHADOW_REG; i += sizeof (uint16_t)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This will update all the hardware controls to the initial values at
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * start of day.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ctrl->actrl_write_fn(ctrl, ctrl->actrl_initval);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Select the input source for recording. This is the set routine
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * for the control AUDIO_CONTROL_INPUTS.
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_insrc_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_gpr_toggle(ac97_ctrl_t *ctrl, int bit, uint64_t onoff)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore v = SHADOW(ac, AC97_GENERAL_PURPOSE_REGISTER);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_wr(ac, AC97_GENERAL_PURPOSE_REGISTER, v);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_3donoff_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_gpr_toggle(ctrl, GPR_3D_STEREO_ENHANCE, value);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_loudness_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_loopback_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This will set simulated stereo control to on or off.
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_stsim_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This will set mic select control to mic1=0 or mic2=1.
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_selmic_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_gpr_toggle(ctrl, GPR_MS_MIC2, value & 2);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This will set mono source select control to mix=0 or mic=1.
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_monosrc_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_gpr_toggle(ctrl, GPR_MONO_MIC_IN, value & 2);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_stereo_set(ac97_ctrl_t *ctrl, uint64_t value, uint8_t reg)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_wr(ac, reg, ac_val_scale(left, right, ctrl->actrl_bits) | mute);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_mono_set(ac97_ctrl_t *ctrl, uint64_t value, uint8_t reg, int shift)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (((1 << ABS(ctrl->actrl_bits)) - 1) << shift);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore v &= ~mask; /* clear all of our bits, preserve others */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* now set the mute bit, and volume bits */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore v |= (ac_mono_scale(val, ctrl->actrl_bits) << shift);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_master_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_PCM_OUT_VOLUME_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_lineout_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_MASTER_VOLUME_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_surround_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_EXTENDED_LRS_VOLUME_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_aux1out_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_HEADPHONE_VOLUME_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_headphone_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_HEADPHONE_VOLUME_REGISTER);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_CD_VOLUME_REGISTER);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_video_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_VIDEO_VOLUME_REGISTER);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_auxin_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_AUX_VOLUME_REGISTER);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_linein_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_LINE_IN_VOLUME_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This will set mono mic gain control.
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_monomic_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_RECORD_GAIN_MIC_REGISTER, 0);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_phone_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_PHONE_VOLUME_REGISTER, 0);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_mic_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_MIC_VOLUME_REGISTER, 0);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_speaker_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_MONO_MASTER_VOLUME_REGISTER, 0);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_pcbeep_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_PC_BEEP_REGISTER, 1);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_recgain_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_stereo_set(ctrl, value, AC97_RECORD_GAIN_REGISTER);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_center_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_EXTENDED_C_LFE_VOLUME_REGISTER, 0);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_lfe_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_EXTENDED_C_LFE_VOLUME_REGISTER, 8);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_bass_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_MASTER_TONE_CONTROL_REGISTER, 8);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_treble_set(ac97_ctrl_t *ctrl, uint64_t value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_MASTER_TONE_CONTROL_REGISTER, 0);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_3ddepth_set(ac97_ctrl_t *ctrl, uint64_t value)
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.
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_THREE_D_CONTROL_REGISTER, 0);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_3dcent_set(ac97_ctrl_t *ctrl, uint64_t value)
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.
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_mono_set(ctrl, value, AC97_THREE_D_CONTROL_REGISTER, 8);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_micboost_set(ac97_ctrl_t *ctrl, uint64_t value)
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 * 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 * On success zero is returned.
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac97_control_get(ac97_ctrl_t *ctrl, uint64_t *value)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac97_control_set(ac97_ctrl_t *ctrl, uint64_t value)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* a bit of quick checking */
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 (ctrl->actrl_maxval & ~ctrl->actrl_minval)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Reset the analog codec hardware
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 /* Clear stale data and resync register accesses */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp = RD(AC97_POWERDOWN_CTRL_STAT_REGISTER);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* reset the codec */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* power up */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Wait for ADC/DAC/MIXER to become ready */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* 1 msec delay */
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) {
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore audio_dev_warn(ac->d, "AC'97 analog power up timed out");
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 * 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 * It re-initializes the device and reloads values with
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * last updated versions.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Fully Power up the device
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* power up - external amp powerd up */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_wr(ac, AC97_POWERDOWN_CTRL_STAT_REGISTER, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* power up - external amp powered down */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_wr(ac, AC97_POWERDOWN_CTRL_STAT_REGISTER, PCSR_EAPD);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_wr(ac, AC97_GENERAL_PURPOSE_REGISTER, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* non-inverted phase */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore /* ac_rd(ac, AC97_VENDOR_REGISTER_11) & ~0x8); */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* jack sense */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (RD(AC97_VENDOR_REGISTER_13) & ~0xEF) | 0x10);
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 /* set jacksense to mute line if headphone is plugged */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (RD(AC97_VENDOR_REGISTER_13) & ~0xe00) | 0x400);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* enable I2S */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore WR(AC97_VENDOR_REGISTER_01, RD(AC97_VENDOR_REGISTER_01) | 0x80);
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 /* set TX8 + 3AWE */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore WR(AC97_VENDOR_REGISTER_07, RD(AC97_VENDOR_REGISTER_07) | 0x9);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* call codec specific reset hook */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Turn off variable sampling rate support */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ac_clr(ac, AC97_EXTENDED_AUDIO_STAT_CTRL_REGISTER, EASCR_VRA);
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!
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore * Return the number of channels supported by this codec.
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.)
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 audio_dev_warn(ac->d, "AC97 %s alloc failed",
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac97_walk_controls(ac97_t *ac, ac97_ctrl_walk_t walker, void *arg)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_add_control(ac97_t *ac, ac97_ctrl_probe_t *cpt)
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore ctrl = kmem_zalloc(sizeof (ac97_ctrl_t), KM_SLEEP);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int e = 0; e < 64; e++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Warning for extended controls this field gets changed
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * by audio_dev_add_control() to be a unique value.
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
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * De-Register and free up a control
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#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 /* 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 /* 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 /* 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 /* 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 /* 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 /* 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 /* 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 /* 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 /* 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 /* 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 /* 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 /* 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 /* 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 /* 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 /* 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 /* 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 /* 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 /* BASS out level (note, zero is hardware bypass) */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_BASS, 0, 0, 100, AUDIO_CTRL_TYPE_MONO,
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 /* 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 /* 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 /* 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 /* 3D enhance on/off switch */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_3DENHANCE, 0, 0, 1, AUDIO_CTRL_TYPE_BOOLEAN,
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 /* Loopback on/off switch */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore {AUDIO_CTRL_ID_LOOPBACK, 0, 0, 1, AUDIO_CTRL_TYPE_BOOLEAN,
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 /* 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 /* Start of non-standard private controls */
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 /* 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 /* 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 /* 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 * Probe all possible controls and register existing
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ones and set initial values
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns zero on success
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac_probeinit_ctrls(ac97_t *ac, int vol_bits, int enh_bits)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Set some ports which are always present.
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 if (strcmp(my_cpt.cp_name, AUDIO_CTRL_ID_RECSRC) == 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (strcmp(my_cpt.cp_name, AUDIO_CTRL_ID_MICBOOST) == 0) {
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 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 if (!my_cpt.cp_probe || my_cpt.cp_probe(ac)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Allocate an AC97 instance for use by a hardware driver.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * returns an allocated and initialize ac97 structure.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreac97_alloc(dev_info_t *dip, ac97_rd_t rd, ac97_wr_t wr, void *priv)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac = kmem_zalloc(sizeof (ac97_t), KM_SLEEP);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore list_create(&ac->ctrls, sizeof (struct ac97_ctrl),
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, \
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 PROP_FLAG(AC97_PROP_AMPLIFIER, AC97_FLAG_AMPLIFIER, 1);
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 * 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 * It turns out that this problem exists for other signals as
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 * 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 * 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 * 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 PROP_FLAG(AC97_PROP_SPEAKER, AC97_FLAG_SPEAKER, 1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PROP_FLAG(AC97_PROP_SPEAKER, AC97_FLAG_SPEAKER, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Enable microphone boost (20dB normally) by default?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PROP_FLAG(AC97_PROP_MICBOOST, AC97_FLAG_MICBOOST, 0);
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore * Allocate an AC97 instance for use by a hardware driver.
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore * returns an allocated and initialize ac97 structure.
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amoreac97_allocate(audio_dev_t *adev, dev_info_t *dip, ac97_rd_t rd, ac97_wr_t wr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Free an AC97 instance.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Clear out any controls that are still attached */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore while ((ctrl = list_head(&ac->ctrls)) != NULL) {
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_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_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_CMI9738, "CMI9738", 0, cmi9738_init },
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { AC97_CODEC_CMI9739, "CMI9739", 0, cmi9739_init },
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 },
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore /* This is only valid when used with new style ac97_allocate(). */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore audio_dev_warn(ac->d, "AC'97 codec unresponsive");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Find out kind of codec we have and set any special case
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * settings needed.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((ac->vid & 0xffffff00) == vendors[i].id) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) snprintf(nmbuf, sizeof (nmbuf), "0x%04x%04x",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Populate the initial shadow table.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; i < LAST_SHADOW_REG; i += sizeof (uint16_t)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* detect the bit width of the master volume controls */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((RD(AC97_MASTER_VOLUME_REGISTER) & 0x1f) == 0x1f) {
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 /* 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 */
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore /* Read EAR just once. */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If not a headphone, is it 4CH_OUT (surround?)
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 * If neither, then maybe its an auxiliary line level output?
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)) {
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore * How many channels?
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore (void) snprintf(ac->name, sizeof (ac->name), "%s %s", vendor, name);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) snprintf(buf, sizeof (buf), "AC'97 codec: %s", ac->name);
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),
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Probe and register all known controls with framework
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 * Return zero on success.
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore /* Make sure we aren't using this with new style ac97_allocate(). */
33ab04ab97e6a2ee82971255446a0aa4eace756eGarrett D'Amore /* Save audio framework instance structure */