48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore/*
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * CDDL HEADER START
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore *
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * The contents of this file are subject to the terms of the
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Common Development and Distribution License (the "License").
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * You may not use this file except in compliance with the License.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore *
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * or http://www.opensolaris.org/os/licensing.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * See the License for the specific language governing permissions
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * and limitations under the License.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore *
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore *
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * CDDL HEADER END
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore/*
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore/*
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Purpose: Driver for the Creative Audigy LS sound card
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore/*
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Copyright (C) 4Front Technologies 1996-2009.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#include <sys/types.h>
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#include <sys/modctl.h>
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#include <sys/kmem.h>
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#include <sys/conf.h>
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#include <sys/ddi.h>
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#include <sys/sunddi.h>
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#include <sys/pci.h>
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#include <sys/note.h>
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#include <sys/audio/audio_driver.h>
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#include <sys/audio/ac97.h>
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#include "audiols.h"
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic struct ddi_device_acc_attr dev_attr = {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore DDI_DEVICE_ATTR_V0,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore DDI_STRUCTURE_LE_ACC,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore DDI_STRICTORDER_ACC
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore};
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic struct ddi_device_acc_attr buf_attr = {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore DDI_DEVICE_ATTR_V0,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore DDI_NEVERSWAP_ACC,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore DDI_STRICTORDER_ACC
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore};
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic ddi_dma_attr_t dma_attr_buf = {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore DMA_ATTR_V0, /* version number */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 0x00000000, /* low DMA address range */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 0xffffffff, /* high DMA address range */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 0x000fffff, /* DMA counter (16 bits only in Audigy LS) */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 4, /* DMA address alignment */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 0x3c, /* DMA burstsizes */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 4, /* min effective DMA size */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 0xffffffff, /* max DMA xfer size */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 0xffffffff, /* segment boundary */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 1, /* s/g length */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 4, /* granularity of device */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 0 /* Bus specific DMA flags */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore};
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_attach(dev_info_t *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_resume(dev_info_t *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_detach(audigyls_dev_t *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_suspend(audigyls_dev_t *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amorestatic int audigyls_open(void *, int, unsigned *, caddr_t *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void audigyls_close(void *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_start(void *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void audigyls_stop(void *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_format(void *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_channels(void *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_rate(void *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic uint64_t audigyls_count(void *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void audigyls_sync(void *, unsigned);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void audigyls_chinfo(void *, int, unsigned *, unsigned *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic uint16_t audigyls_read_ac97(void *, uint8_t);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void audigyls_write_ac97(void *, uint8_t, uint16_t);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_alloc_port(audigyls_dev_t *, int);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void audigyls_destroy(audigyls_dev_t *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void audigyls_hwinit(audigyls_dev_t *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void audigyls_configure_mixer(audigyls_dev_t *dev);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic audio_engine_ops_t audigyls_engine_ops = {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore AUDIO_ENGINE_VERSION,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_open,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_close,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_start,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_stop,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_count,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_format,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_channels,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_rate,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_sync,
f9ead4a57883f3ef04ef20d83cc47987d98c0687Garrett D'Amore NULL,
f9ead4a57883f3ef04ef20d83cc47987d98c0687Garrett D'Amore audigyls_chinfo,
f9ead4a57883f3ef04ef20d83cc47987d98c0687Garrett D'Amore NULL
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore};
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore/*
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Audigy LS uses AC'97 strictly for the recording side of things.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * While the chip can supposedly route output to AC'97 for playback,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * the PCI devices use a separate I2S DAC instead. As a result we
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * need to suppress controls that the AC'97 codec registers.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore *
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Furthermore, even then the AC'97 codec offers inputs that we just
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * aren't interested in.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreconst char *audigyls_remove_ac97[] = {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore AUDIO_CTRL_ID_VOLUME,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore AUDIO_CTRL_ID_LINEOUT,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore AUDIO_CTRL_ID_HEADPHONE,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore AUDIO_CTRL_ID_CD,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore AUDIO_CTRL_ID_VIDEO,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore AUDIO_CTRL_ID_3DDEPTH,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore AUDIO_CTRL_ID_3DENHANCE,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore AUDIO_CTRL_ID_BEEP,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore AUDIO_CTRL_ID_RECGAIN,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore AUDIO_CTRL_ID_RECSRC,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore AUDIO_CTRL_ID_LOOPBACK,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore NULL,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore};
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore/*
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * AC'97 sources we don't want to expose.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreconst char *audigyls_badsrcs[] = {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore AUDIO_PORT_VIDEO,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore AUDIO_PORT_CD,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore AUDIO_PORT_STEREOMIX,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore AUDIO_PORT_MONOMIX,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore NULL,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore};
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic unsigned int
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreread_chan(audigyls_dev_t *dev, int reg, int chn)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore uint32_t val;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_enter(&dev->low_mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* Pointer */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore OUTL(dev, PR, (reg << 16) | (chn & 0xffff));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* Data */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore val = INL(dev, DR);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_exit(&dev->low_mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (val);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorewrite_chan(audigyls_dev_t *dev, int reg, int chn, uint32_t value)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_enter(&dev->low_mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* Pointer */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore OUTL(dev, PR, (reg << 16) | (chn & 0x7));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* Data */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore OUTL(dev, DR, value);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_exit(&dev->low_mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic unsigned int
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreread_reg(audigyls_dev_t *dev, int reg)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (read_chan(dev, reg, 0));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorewrite_reg(audigyls_dev_t *dev, int reg, uint32_t value)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, reg, 0, value);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic uint16_t
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_read_ac97(void *arg, uint8_t index)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_dev_t *dev = arg;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore uint16_t dtemp = 0;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore int i;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_enter(&dev->low_mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore OUTB(dev, AC97A, index);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore for (i = 0; i < 10000; i++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (INB(dev, AC97A) & 0x80)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (i == 10000) { /* Timeout */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_exit(&dev->low_mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (0xffff);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore dtemp = INW(dev, AC97D);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_exit(&dev->low_mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (dtemp);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_write_ac97(void *arg, uint8_t index, uint16_t data)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_dev_t *dev = arg;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore int i;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_enter(&dev->low_mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore OUTB(dev, AC97A, index);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore for (i = 0; i < 50000; i++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (INB(dev, AC97A) & 0x80)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (i == 50000) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_exit(&dev->low_mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore OUTW(dev, AC97D, data);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_exit(&dev->low_mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreselect_digital_enable(audigyls_dev_t *dev, int mode)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /*
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Set the out3/spdif combo jack format.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * mode0=analog rear/center, 1=spdif
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (mode == 0) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, SPC, 0x00000f00);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore } else {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, SPC, 0x0000000f);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore/* only for SBLive 7.1 */
a60cc674f1dd8c4fd3fb0e319c3d8b6b26524067Garrett D'Amorevoid
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_i2c_write(audigyls_dev_t *dev, int reg, int data)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore int i, timeout, tmp;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore tmp = (reg << 9 | data) << 16; /* set the upper 16 bits */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* first write the command to the data reg */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, I2C_1, tmp);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore for (i = 0; i < 20; i++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore tmp = read_reg(dev, I2C_A) & ~0x6fe;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* see audigyls.pdf for bits */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore tmp |= 0x400 | 0x100 | 0x34;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, I2C_A, tmp);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* now wait till controller sets valid bit (0x100) to 0 */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore timeout = 0;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore for (;;) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore tmp = read_reg(dev, I2C_A);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if ((tmp & 0x100) == 0)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (timeout > 100)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore timeout++;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* transaction aborted */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (tmp & 0x200)
a60cc674f1dd8c4fd3fb0e319c3d8b6b26524067Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreint
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_spi_write(audigyls_dev_t *dev, int data)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore unsigned int orig;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore unsigned int tmp;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore int i, valid;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore tmp = read_reg(dev, SPI);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore orig = (tmp & ~0x3ffff) | 0x30000;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, SPI, orig | data);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore valid = 0;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* Wait for status bit to return to 0 */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore for (i = 0; i < 1000; i++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore drv_usecwait(100);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore tmp = read_reg(dev, SPI);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (!(tmp & 0x10000)) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore valid = 1;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (!valid) /* Timed out */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (1);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore/*
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Audio routines
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreint
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amoreaudigyls_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_port_t *port = arg;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_dev_t *dev = port->dev;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore _NOTE(ARGUNUSED(flag));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_enter(&dev->mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore port->count = 0;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore *nframesp = port->buf_frames;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore *bufp = port->buf_kaddr;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_exit(&dev->mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorevoid
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_close(void *arg)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore _NOTE(ARGUNUSED(arg));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreint
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_start(void *arg)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_port_t *port = arg;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_dev_t *dev = port->dev;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore uint32_t tmp;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_enter(&dev->mutex);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore port->offset = 0;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore switch (port->direction) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore case AUDIGYLS_PLAY_PORT:
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore write_chan(dev, PTCA, 0, 0);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore write_chan(dev, CPFA, 0, 0);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore write_chan(dev, CPCAV, 0, 0);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore write_chan(dev, PTCA, 1, 0);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore write_chan(dev, CPFA, 1, 0);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore write_chan(dev, CPCAV, 1, 0);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore write_chan(dev, PTCA, 3, 0);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore write_chan(dev, CPFA, 3, 0);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore write_chan(dev, CPCAV, 3, 0);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore tmp = read_reg(dev, SA);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore tmp |= SA_SPA(0);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore tmp |= SA_SPA(1);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore tmp |= SA_SPA(3);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore write_reg(dev, SA, tmp);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore break;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore case AUDIGYLS_REC_PORT:
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore write_chan(dev, CRFA, 2, 0);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore write_chan(dev, CRCAV, 2, 0);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore tmp = read_reg(dev, SA);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore tmp |= SA_SRA(2);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore write_reg(dev, SA, tmp);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_exit(&dev->mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorevoid
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_stop(void *arg)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_port_t *port = arg;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_dev_t *dev = port->dev;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore uint32_t tmp;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_enter(&dev->mutex);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore switch (port->direction) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore case AUDIGYLS_PLAY_PORT:
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore tmp = read_reg(dev, SA);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore tmp &= ~SA_SPA(0);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore tmp &= ~SA_SPA(1);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore tmp &= ~SA_SPA(3);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore write_reg(dev, SA, tmp);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore break;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore case AUDIGYLS_REC_PORT:
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore tmp = read_reg(dev, SA);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore tmp &= ~SA_SRA(2);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore write_reg(dev, SA, tmp);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_exit(&dev->mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreint
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_format(void *arg)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore _NOTE(ARGUNUSED(arg));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (AUDIO_FORMAT_S16_LE);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreint
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_channels(void *arg)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_port_t *port = arg;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (port->nchan);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreint
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_rate(void *arg)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore _NOTE(ARGUNUSED(arg));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (48000);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorevoid
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_sync(void *arg, unsigned nframes)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_port_t *port = arg;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore _NOTE(ARGUNUSED(nframes));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore (void) ddi_dma_sync(port->buf_dmah, 0, 0, port->syncdir);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreuint64_t
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_count(void *arg)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_port_t *port = arg;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_dev_t *dev = port->dev;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore uint64_t count;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore uint32_t offset, n;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_enter(&dev->mutex);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore if (port->direction == AUDIGYLS_PLAY_PORT) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore offset = read_chan(dev, CPFA, 0);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore } else {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore offset = read_chan(dev, CRFA, 2);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore }
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore /* get the offset, and switch to frames */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore offset /= (2 * sizeof (uint16_t));
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore if (offset >= port->offset) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore n = offset - port->offset;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore } else {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore n = offset + (port->buf_frames - port->offset);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore }
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore port->offset = offset;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore port->count += n;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore count = port->count;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_exit(&dev->mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (count);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_chinfo(void *arg, int chan, unsigned *offset, unsigned *incr)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_port_t *port = arg;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (port->direction == AUDIGYLS_PLAY_PORT) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore *offset = (port->buf_frames * 2 * (chan / 2)) + (chan % 2);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore *incr = 2;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore } else {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore *offset = chan;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore *incr = 2;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore/* private implementation bits */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreint
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_alloc_port(audigyls_dev_t *dev, int num)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_port_t *port;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore size_t len;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore ddi_dma_cookie_t cookie;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore uint_t count;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore int dir;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore unsigned caps;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_t *adev;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore adev = dev->adev;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore port = kmem_zalloc(sizeof (*port), KM_SLEEP);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore dev->port[num] = port;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore port->dev = dev;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore port->direction = num;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore switch (num) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case AUDIGYLS_REC_PORT:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore port->syncdir = DDI_DMA_SYNC_FORKERNEL;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore caps = ENGINE_INPUT_CAP;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore dir = DDI_DMA_READ;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore port->nchan = 2;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case AUDIGYLS_PLAY_PORT:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore port->syncdir = DDI_DMA_SYNC_FORDEV;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore caps = ENGINE_OUTPUT_CAP;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore dir = DDI_DMA_WRITE;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore port->nchan = 6;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore default:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (DDI_FAILURE);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore port->buf_frames = 2048;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore port->buf_size = port->buf_frames * port->nchan * sizeof (int16_t);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* Alloc buffers */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (ddi_dma_alloc_handle(dev->dip, &dma_attr_buf, DDI_DMA_SLEEP, NULL,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore &port->buf_dmah) != DDI_SUCCESS) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_warn(adev, "failed to allocate BUF handle");
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (DDI_FAILURE);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (ddi_dma_mem_alloc(port->buf_dmah, port->buf_size,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore &buf_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore &port->buf_kaddr, &len, &port->buf_acch) != DDI_SUCCESS) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_warn(adev, "failed to allocate BUF memory");
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (DDI_FAILURE);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (ddi_dma_addr_bind_handle(port->buf_dmah, NULL, port->buf_kaddr,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore len, DDI_DMA_CONSISTENT | dir, DDI_DMA_SLEEP, NULL, &cookie,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore &count) != DDI_SUCCESS) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_warn(adev, "failed binding BUF DMA handle");
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (DDI_FAILURE);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore port->buf_paddr = cookie.dmac_address;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore port->engine = audio_engine_alloc(&audigyls_engine_ops, caps);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (port->engine == NULL) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_warn(adev, "audio_engine_alloc failed");
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (DDI_FAILURE);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_engine_set_private(port->engine, port);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_add_engine(adev, port->engine);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (DDI_SUCCESS);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
4a20ca87c19352fb04bb75918ba0231663faa6a8Garrett D'Amorevoid
4a20ca87c19352fb04bb75918ba0231663faa6a8Garrett D'Amoreaudigyls_del_controls(audigyls_dev_t *dev)
4a20ca87c19352fb04bb75918ba0231663faa6a8Garrett D'Amore{
4a20ca87c19352fb04bb75918ba0231663faa6a8Garrett D'Amore for (int i = 0; i < CTL_NUM; i++) {
4a20ca87c19352fb04bb75918ba0231663faa6a8Garrett D'Amore if (dev->controls[i].ctrl) {
4a20ca87c19352fb04bb75918ba0231663faa6a8Garrett D'Amore audio_dev_del_control(dev->controls[i].ctrl);
4a20ca87c19352fb04bb75918ba0231663faa6a8Garrett D'Amore dev->controls[i].ctrl = NULL;
4a20ca87c19352fb04bb75918ba0231663faa6a8Garrett D'Amore }
4a20ca87c19352fb04bb75918ba0231663faa6a8Garrett D'Amore }
4a20ca87c19352fb04bb75918ba0231663faa6a8Garrett D'Amore}
4a20ca87c19352fb04bb75918ba0231663faa6a8Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorevoid
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_destroy(audigyls_dev_t *dev)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_destroy(&dev->mutex);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_destroy(&dev->low_mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore for (int i = 0; i < AUDIGYLS_NUM_PORT; i++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_port_t *port = dev->port[i];
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (!port)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore continue;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (port->engine) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_remove_engine(dev->adev, port->engine);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_engine_free(port->engine);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (port->buf_paddr) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore (void) ddi_dma_unbind_handle(port->buf_dmah);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (port->buf_acch) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore ddi_dma_mem_free(&port->buf_acch);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (port->buf_dmah) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore ddi_dma_free_handle(&port->buf_dmah);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore kmem_free(port, sizeof (*port));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (dev->ac97 != NULL) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore ac97_free(dev->ac97);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
4a20ca87c19352fb04bb75918ba0231663faa6a8Garrett D'Amore
4a20ca87c19352fb04bb75918ba0231663faa6a8Garrett D'Amore audigyls_del_controls(dev);
4a20ca87c19352fb04bb75918ba0231663faa6a8Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (dev->adev != NULL) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_free(dev->adev);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (dev->regsh != NULL) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore ddi_regs_map_free(&dev->regsh);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (dev->pcih != NULL) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore pci_config_teardown(&dev->pcih);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore kmem_free(dev, sizeof (*dev));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorevoid
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_hwinit(audigyls_dev_t *dev)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore static unsigned int spi_dac[] = {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 0x00ff, 0x02ff, 0x0400, 0x520, 0x0620, 0x08ff, 0x0aff, 0x0cff,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 0x0eff, 0x10ff, 0x1200, 0x1400, 0x1800, 0x1aff, 0x1cff,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 0x1e00, 0x0530, 0x0602, 0x0622, 0x1400,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore };
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore uint32_t tmp;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore int i, tries;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore uint32_t paddr;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore uint32_t chunksz;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_port_t *port;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* Set the orange jack to be analog out or S/PDIF */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore select_digital_enable(dev, dev->digital_enable);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /*
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * In P17, there's 8 GPIO pins.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * GPIO register: 0x00XXYYZZ
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * XX: Configure GPIO to be either GPI (0) or GPO (1).
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * YY: GPO values, applicable if the pin is configure to be GPO.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * ZZ: GPI values, applicable if the pin is configure to be GPI.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore *
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * in SB570, pin 0-4 and 6 is used as GPO and pin 5 and 7 is
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * used as GPI.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore *
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * GPO0:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 1 ==> Analog output
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 0 ==> Digital output
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * GPO1:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 1 ==> Enable output on card
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 0 ==> Disable output on card
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * GPO2:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 1 ==> Enable Mic Bias and Mic Path
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 0 ==> Disable Mic Bias and Mic Path
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * GPO3:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 1 ==> Disable SPDIF-IO output
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 0 ==> Enable SPDIF-IO output
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * GPO4 and GPO6:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * DAC sampling rate selection:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Not applicable to SB570 since DAC is controlled through SPI
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * GPI5:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 1 ==> Front Panel is not connected
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 0 ==> Front Panel is connected
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * GPI7:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 1 ==> Front Panel Headphone is not connected
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 0 ==> Front Panel Headphone is connected
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (dev->ac97)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore OUTL(dev, GPIO, 0x005f03a3);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore else {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* for SBLive 7.1 */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore OUTL(dev, GPIO, 0x005f4301);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_i2c_write(dev, 0x15, 0x2);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore tries = 0;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore again:
2a7bf89ee47466b3389ff63ab2831d3b73e0b8deGarrett D'Amore for (i = 0; i < (sizeof (spi_dac) / sizeof (spi_dac[0])); i++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (!audigyls_spi_write(dev, spi_dac[i]) &&
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore tries < 100) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore tries++;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore goto again;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore OUTL(dev, IER, 0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore OUTL(dev, HC, 0x00000009); /* Enable audio, use 48 kHz */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore tmp = read_chan(dev, SRCTL, 0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (dev->ac97)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore tmp |= 0xf0c81000; /* Record src0/src1 from ac97 */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore else
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore tmp |= 0x50c81000; /* Record src0/src1 from I2SIN */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore tmp &= ~0x0303c00f; /* Set sample rates to 48 kHz */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, SRCTL, 0, tmp);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, HMIXMAP_I2S, 0x76543210); /* Default out route */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, AUDCTL, 0x0f0f003f); /* Enable all outputs */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* All audio stopped! */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, SA, 0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore for (i = 0; i < 4; i++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /*
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Reset DMA pointers and counters. Note that we do
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * not use scatter/gather.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, PTBA, i, 0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, PTBS, i, 0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, PTCA, i, 0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, CPFA, i, 0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, PFEA, i, 0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, CPCAV, i, 0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, CRFA, i, 0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, CRCAV, i, 0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /*
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * The 5.1 play port made up channels 0, 1, and 3. The record
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * port is channel 2.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore port = dev->port[AUDIGYLS_PLAY_PORT];
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore paddr = port->buf_paddr;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore chunksz = port->buf_frames * 4;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, PFBA, 0, paddr);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, PFBS, 0, chunksz << 16);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore paddr += chunksz;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, PFBA, 1, paddr);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, PFBS, 1, chunksz << 16);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore paddr += chunksz;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, PFBA, 3, paddr);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, PFBS, 3, chunksz << 16);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* Record */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore port = dev->port[AUDIGYLS_REC_PORT];
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore paddr = port->buf_paddr;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore chunksz = port->buf_frames * 4;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, RFBA, 2, paddr);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, RFBS, 2, chunksz << 16);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* Set sample rates to 48 kHz. */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore tmp = read_chan(dev, SRCTL, 0) & ~0x0303c00f;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, SRCTL, 0, tmp);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, SCS0, 0x02108004); /* Audio */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, SCS1, 0x02108004); /* Audio */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, SCS2, 0x02108004); /* Audio */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, SCS3, 0x02108004); /* Audio */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#define PLAYCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_PLAY)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#define RECCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_REC)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#define MONCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_MONITOR)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#define PCMVOL (PLAYCTL | AUDIO_CTRL_FLAG_PCMVOL)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#define MAINVOL (PLAYCTL | AUDIO_CTRL_FLAG_MAINVOL)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#define RECVOL (RECCTL | AUDIO_CTRL_FLAG_RECVOL)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#define MONVOL (MONCTL | AUDIO_CTRL_FLAG_MONVOL)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#define MASK(nbits) ((1 << (nbits)) - 1)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#define SCALE(val, nbits) \
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore ((uint8_t)((((val) * MASK(nbits)) / 100)) << (8 - (nbits)))
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic uint32_t
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_stereo_scale(uint32_t value, uint8_t bits)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore uint8_t left, right;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore uint32_t val;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore left = (value >> 8) & 0xff;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore right = value & 0xff;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore val = (((left * ((1 << bits) - 1) / 100) << 8) |
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore (right * ((1 << bits) - 1) / 100));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (val);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_configure_mixer(audigyls_dev_t *dev)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore unsigned int r, v1, v2;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* output items */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* front */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore r = 0xffff - audigyls_stereo_scale(dev->controls[CTL_FRONT].val, 8);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore r = (r << 16) | r;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, MIXVOL_I2S, 0, r);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* surround */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore r = 0xffff - audigyls_stereo_scale(dev->controls[CTL_SURROUND].val, 8);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore r = (r << 16) | r;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, MIXVOL_I2S, 3, r);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* center/lfe */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore v1 = 255 - SCALE(dev->controls[CTL_CENTER].val, 8);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore v2 = 255 - SCALE(dev->controls[CTL_LFE].val, 8);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore r = (v1 << 8) | v2;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore r = (r << 16) | r;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, MIXVOL_I2S, 1, r);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* spread */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore r = dev->controls[CTL_SPREAD].val ? 0x10101010 : 0x76543210;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, HMIXMAP_I2S, r);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* input items */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* recgain */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore v1 = dev->controls[CTL_RECORDVOL].val;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (dev->ac97_recgain && !dev->controls[CTL_LOOP].val) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /*
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * For AC'97, we use the AC'97 record gain, unless we are
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * in loopback.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore */
a60cc674f1dd8c4fd3fb0e319c3d8b6b26524067Garrett D'Amore (void) ac97_control_set(dev->ac97_recgain, v1);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, P17RECVOLL, 0x30303030);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, P17RECVOLH, 0x30303030);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore } else {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /*
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Otherwise we set the P17 gain.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore r = 0xffff - audigyls_stereo_scale(v1, 8);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore r = r << 16 | r;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, P17RECVOLL, r);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, P17RECVOLH, r);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* monitor gain */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (dev->ac97) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* AC'97 monitor gain is done by the AC'97 codec */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, SRCTL, 1, 0x30303030);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, SMIXMAP_I2S, 0x10101076);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore } else {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* For non-AC'97 devices, just a single master monitor gain */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore r = 255 - SCALE(dev->controls[CTL_MONGAIN].val, 8);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, SRCTL, 1, 0xffff0000 | r << 8 | r);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (r != 0xff) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, SMIXMAP_I2S, 0x10101076);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore } else {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, SMIXMAP_I2S, 0x10101010);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* record source */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (dev->ac97_recsrc != NULL) {
a60cc674f1dd8c4fd3fb0e319c3d8b6b26524067Garrett D'Amore (void) ac97_control_set(dev->ac97_recsrc,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore dev->controls[CTL_RECSRC].val);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore v1 = RECSEL_AC97; /* Audigy LS */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore } else {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore switch (dev->controls[CTL_RECSRC].val) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 1:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_i2c_write(dev, 0x15, 0x2); /* Mic */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore OUTL(dev, GPIO, INL(dev, GPIO) | 0x400);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 2:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_i2c_write(dev, 0x15, 0x4); /* Line */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore OUTL(dev, GPIO, INL(dev, GPIO) & ~0x400);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore v1 = RECSEL_I2SIN; /* SB 7.1 value */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* If loopback, record what you hear instead */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (dev->controls[CTL_LOOP].val) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore r = 0;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore v1 = RECSEL_I2SOUT;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore r |= (v1 << 28) | (v1 << 24) | (v1 << 20) | (v1 << 16) | v1;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore } else {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /*
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * You'd think this would be the same as the logic
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * above, but experience shows that what you need for
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * loopback is different. This whole thing looks
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * particularly fishy to me. I suspect someone has
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * made a mistake somewhere. But I can't seem to
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * figure out where it lies.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore */
e7437094ebbbd4d60375f3927c017ff00cbab1deGarrett D'Amore if (dev->ac97_recsrc != NULL) {
e7437094ebbbd4d60375f3927c017ff00cbab1deGarrett D'Amore r = 0xe4;
e7437094ebbbd4d60375f3927c017ff00cbab1deGarrett D'Amore for (int i = 0; i < 4; i++)
e7437094ebbbd4d60375f3927c017ff00cbab1deGarrett D'Amore r |= v1 << (16 + i * 3); /* Select input */
e7437094ebbbd4d60375f3927c017ff00cbab1deGarrett D'Amore } else {
e7437094ebbbd4d60375f3927c017ff00cbab1deGarrett D'Amore r = (v1 << 28) | (v1 << 24) | (v1 << 20) | (v1 << 16) |
e7437094ebbbd4d60375f3927c017ff00cbab1deGarrett D'Amore v1;
e7437094ebbbd4d60375f3927c017ff00cbab1deGarrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, P17RECSEL, r);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_set_control(void *arg, uint64_t val)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_ctrl_t *pc = arg;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_dev_t *dev = pc->dev;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore switch (pc->num) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case CTL_FRONT:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case CTL_SURROUND:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case CTL_RECORDVOL:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (((val & 0xff) > 100) ||
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore (((val & 0xff00) >> 8) > 100) ||
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore ((val & ~0xffff) != 0)) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (EINVAL);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case CTL_CENTER:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case CTL_LFE:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case CTL_MONGAIN:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (val > 100) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (EINVAL);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case CTL_RECSRC:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (((1U << val) & (dev->recmask)) == 0) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (EINVAL);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case CTL_SPREAD:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case CTL_LOOP:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore switch (val) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 0:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 1:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore default:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (EINVAL);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_enter(&dev->mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore pc->val = val;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audigyls_configure_mixer(dev);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_exit(&dev->mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_get_control(void *arg, uint64_t *val)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_ctrl_t *pc = arg;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_dev_t *dev = pc->dev;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_enter(&dev->mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore *val = pc->val;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore mutex_exit(&dev->mutex);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_alloc_ctrl(audigyls_dev_t *dev, uint32_t num, uint64_t val)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_ctrl_desc_t desc;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_ctrl_t *pc;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore bzero(&desc, sizeof (desc));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore pc = &dev->controls[num];
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore pc->num = num;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore pc->dev = dev;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore switch (num) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case CTL_FRONT:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_FRONT;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_minvalue = 0;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_maxvalue = 100;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_flags = MAINVOL;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case CTL_SURROUND:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_SURROUND;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_minvalue = 0;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_maxvalue = 100;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_flags = MAINVOL;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case CTL_CENTER:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_CENTER;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_MONO;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_minvalue = 0;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_maxvalue = 100;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_flags = MAINVOL;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case CTL_LFE:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_LFE;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_MONO;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_minvalue = 0;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_maxvalue = 100;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_flags = MAINVOL;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case CTL_RECORDVOL:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_RECGAIN;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_minvalue = 0;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_maxvalue = 100;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_flags = RECVOL;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case CTL_RECSRC:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_RECSRC;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_ENUM;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_flags = RECCTL;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /*
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * For AC'97 devices, we want to expose the reasonable
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * AC'97 input sources, but suppress the stereomix,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * because we use loopback instead.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (dev->ac97_recsrc) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore int i, j;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore const char *n;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore const audio_ctrl_desc_t *adp;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore adp = ac97_control_desc(dev->ac97_recsrc);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore for (i = 0; i < 64; i++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore n = adp->acd_enum[i];
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (((adp->acd_minvalue & (1 << i)) == 0) ||
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore (n == NULL)) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore continue;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore for (j = 0; audigyls_badsrcs[j]; j++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (strcmp(n, audigyls_badsrcs[j])
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore == 0) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore n = NULL;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (n) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_enum[i] = n;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore dev->recmask |= (1 << i);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_minvalue = desc.acd_maxvalue = dev->recmask;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore } else {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore dev->recmask = 3;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_minvalue = 3;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_maxvalue = 3;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_enum[0] = AUDIO_PORT_MIC;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_enum[1] = AUDIO_PORT_LINEIN;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case CTL_MONGAIN:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore ASSERT(!dev->ac97);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_MONGAIN;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_MONO;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_minvalue = 0;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_maxvalue = 100;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_flags = MONVOL;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case CTL_SPREAD:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_SPREAD;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_BOOLEAN;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_minvalue = 0;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_maxvalue = 1;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_flags = PLAYCTL;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case CTL_LOOP:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_LOOPBACK;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_BOOLEAN;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_minvalue = 0;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_maxvalue = 1;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_flags = RECCTL;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore pc->val = val;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore pc->ctrl = audio_dev_add_control(dev->adev, &desc,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_get_control, audigyls_set_control, pc);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
a60cc674f1dd8c4fd3fb0e319c3d8b6b26524067Garrett D'Amorestatic void
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_add_controls(audigyls_dev_t *dev)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore audio_dev_add_soft_volume(dev->adev);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_alloc_ctrl(dev, CTL_FRONT, 75 | (75 << 8));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_alloc_ctrl(dev, CTL_SURROUND, 75 | (75 << 8));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_alloc_ctrl(dev, CTL_CENTER, 75);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_alloc_ctrl(dev, CTL_LFE, 75);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_alloc_ctrl(dev, CTL_RECORDVOL, 75 | (75 << 8));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_alloc_ctrl(dev, CTL_RECSRC, 1);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_alloc_ctrl(dev, CTL_SPREAD, 0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_alloc_ctrl(dev, CTL_LOOP, 0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (!dev->ac97) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_alloc_ctrl(dev, CTL_MONGAIN, 0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreint
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_attach(dev_info_t *dip)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore uint16_t pci_command, vendor, device;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore uint32_t subdevice;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_dev_t *dev;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore ddi_acc_handle_t pcih;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore const char *name, *version;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore boolean_t ac97 = B_FALSE;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore dev = kmem_zalloc(sizeof (*dev), KM_SLEEP);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore dev->dip = dip;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore ddi_set_driver_private(dip, dev);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, NULL);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_init(&dev->low_mutex, NULL, MUTEX_DRIVER, NULL);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if ((dev->adev = audio_dev_alloc(dip, 0)) == NULL) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore cmn_err(CE_WARN, "audio_dev_alloc failed");
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore goto error;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_warn(dev->adev, "pci_config_setup failed");
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore goto error;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore dev->pcih = pcih;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore vendor = pci_config_get16(pcih, PCI_CONF_VENID);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore device = pci_config_get16(pcih, PCI_CONF_DEVID);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore subdevice = pci_config_get16(pcih, PCI_CONF_SUBVENID);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore subdevice <<= 16;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore subdevice |= pci_config_get16(pcih, PCI_CONF_SUBSYSID);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (vendor != PCI_VENDOR_ID_CREATIVE ||
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore device != PCI_DEVICE_ID_CREATIVE_AUDIGYLS) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_warn(dev->adev, "Hardware not recognized "
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore "(vendor=%x, dev=%x)", vendor, device);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore goto error;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore pci_command = pci_config_get16(pcih, PCI_CONF_COMM);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore pci_command |= PCI_COMM_ME | PCI_COMM_IO;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore pci_config_put16(pcih, PCI_CONF_COMM, pci_command);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if ((ddi_regs_map_setup(dip, 1, &dev->base, 0, 0, &dev_attr,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore &dev->regsh)) != DDI_SUCCESS) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_warn(dev->adev, "failed to map registers");
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore goto error;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* Function of the orange jack: 0=analog, 1=digital */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore dev->digital_enable = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore DDI_PROP_DONTPASS, "digital-enable", 0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore switch (subdevice) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 0x11021001: /* SB0310 */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 0x11021002: /* SB0310 */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 0x11021005: /* SB0310b */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore name = "Creative Audigy LS";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore version = "SB0310"; /* could also be SB0312 */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore ac97 = B_TRUE;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 0x11021006:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore name = "Creative Sound Blaster Live! 24 bit";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore version = "SB0410";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 0x11021007: /* Dell OEM version */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore name = "Creative Sound Blaster Live! 24 bit";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore version = "SB0413";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 0x1102100a:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore name = "Creative Audigy SE";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore version = "SB0570";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 0x11021011:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore name = "Creative Audigy SE OEM";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore version = "SB0570a";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 0x11021012:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore name = "Creative X-Fi Extreme Audio";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore version = "SB0790";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 0x14621009:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore name = "MSI K8N Diamond MB";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore version = "SB0438";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 0x12973038:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore name = "Shuttle XPC SD31P";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore version = "SD31P";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 0x12973041:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore name = "Shuttle XPC SD11G5";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore version = "SD11G5";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore default:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore name = "Creative Audigy LS";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore version = NULL;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore break;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_set_description(dev->adev, name);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (version)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_set_version(dev->adev, version);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (ac97) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore ac97_ctrl_t *ctrl;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* Original Audigy LS revision (AC97 based) */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore dev->ac97 = ac97_allocate(dev->adev, dip,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_read_ac97, audigyls_write_ac97, dev);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (dev->ac97 == NULL) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_warn(dev->adev,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore "failed to allocate ac97 handle");
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore goto error;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore ac97_probe_controls(dev->ac97);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* remove the AC'97 controls we don't want to expose */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore for (int i = 0; audigyls_remove_ac97[i]; i++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore ctrl = ac97_control_find(dev->ac97,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_remove_ac97[i]);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (ctrl != NULL) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore ac97_control_unregister(ctrl);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore dev->ac97_recgain = ac97_control_find(dev->ac97,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore AUDIO_CTRL_ID_RECGAIN);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore dev->ac97_recsrc = ac97_control_find(dev->ac97,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore AUDIO_CTRL_ID_RECSRC);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_add_controls(dev);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (dev->ac97) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore ac97_register_controls(dev->ac97);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (audigyls_alloc_port(dev, AUDIGYLS_PLAY_PORT) != DDI_SUCCESS)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore goto error;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (audigyls_alloc_port(dev, AUDIGYLS_REC_PORT) != DDI_SUCCESS)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore goto error;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_hwinit(dev);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_configure_mixer(dev);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (audio_dev_register(dev->adev) != DDI_SUCCESS) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_warn(dev->adev, "unable to register with framework");
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore goto error;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore ddi_report_dev(dip);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (DDI_SUCCESS);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreerror:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_destroy(dev);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (DDI_FAILURE);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreint
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_resume(dev_info_t *dip)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_dev_t *dev;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore dev = ddi_get_driver_private(dip);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_hwinit(dev);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* allow ac97 operations again */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (dev->ac97)
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ac97_reset(dev->ac97);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audio_dev_resume(dev->adev);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (DDI_SUCCESS);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreint
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_detach(audigyls_dev_t *dev)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (audio_dev_unregister(dev->adev) != DDI_SUCCESS)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (DDI_FAILURE);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_destroy(dev);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (DDI_SUCCESS);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreint
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_suspend(audigyls_dev_t *dev)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audio_dev_suspend(dev->adev);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (DDI_SUCCESS);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_ddi_attach(dev_info_t *, ddi_attach_cmd_t);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_ddi_detach(dev_info_t *, ddi_detach_cmd_t);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_ddi_quiesce(dev_info_t *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic struct dev_ops audigyls_dev_ops = {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore DEVO_REV, /* rev */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 0, /* refcnt */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore NULL, /* getinfo */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore nulldev, /* identify */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore nulldev, /* probe */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_ddi_attach, /* attach */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_ddi_detach, /* detach */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore nodev, /* reset */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore NULL, /* cb_ops */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore NULL, /* bus_ops */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore NULL, /* power */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_ddi_quiesce, /* quiesce */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore};
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic struct modldrv audigyls_modldrv = {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore &mod_driverops, /* drv_modops */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore "Creative Audigy LS Audio", /* linkinfo */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore &audigyls_dev_ops, /* dev_ops */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore};
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic struct modlinkage modlinkage = {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore MODREV_1,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore { &audigyls_modldrv, NULL }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore};
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreint
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore_init(void)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore int rv;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_init_ops(&audigyls_dev_ops, AUDIGYLS_NAME);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if ((rv = mod_install(&modlinkage)) != 0) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_fini_ops(&audigyls_dev_ops);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (rv);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreint
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore_fini(void)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore int rv;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if ((rv = mod_remove(&modlinkage)) == 0) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_fini_ops(&audigyls_dev_ops);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (rv);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreint
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore_info(struct modinfo *modinfop)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (mod_info(&modlinkage, modinfop));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreint
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore switch (cmd) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case DDI_ATTACH:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (audigyls_attach(dip));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case DDI_RESUME:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (audigyls_resume(dip));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore default:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (DDI_FAILURE);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreint
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_dev_t *dev;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore dev = ddi_get_driver_private(dip);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore switch (cmd) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case DDI_DETACH:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (audigyls_detach(dev));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case DDI_SUSPEND:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (audigyls_suspend(dev));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore default:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (DDI_FAILURE);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore }
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreint
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_ddi_quiesce(dev_info_t *dip)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore{
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_dev_t *dev;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore uint32_t status;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /*
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Turn off the hardware
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore dev = ddi_get_driver_private(dip);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, SA, 0);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore OUTL(dev, IER, 0); /* Interrupt disable */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, AIE, 0); /* Disable audio interrupts */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore status = INL(dev, IPR);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore OUTL(dev, IPR, status); /* Acknowledge */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (DDI_SUCCESS);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore}