audiocmi.c revision 08045defdf65ee890fef6e20510a093a17feb8fe
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore/*
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * CDDL HEADER START
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore *
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * The contents of this file are subject to the terms of the
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * Common Development and Distribution License (the "License").
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * You may not use this file except in compliance with the License.
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore *
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * or http://www.opensolaris.org/os/licensing.
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * See the License for the specific language governing permissions
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * and limitations under the License.
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore *
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore *
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * CDDL HEADER END
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore/*
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * Use is subject to license terms.
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore/*
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * Purpose: Driver for CMEDIA CM8738 PCI audio controller.
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore/*
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * This file is part of Open Sound System
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore *
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * Copyright (C) 4Front Technologies 1996-2008.
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore *
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * This software is released under CDDL 1.0 source license.
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * See the COPYING file included in the main directory of this source
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * distribution for the license terms and conditions.
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore#include <sys/audio/audio_driver.h>
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore#include <sys/note.h>
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore#include <sys/pci.h>
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore#include "audiocmi.h"
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore/*
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * Note: The original 4Front driver had support SPDIF, dual dac, and
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * multichannel surround options. However, we haven't got any cards
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * with these advanced features available on them for testing, so
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * we're just going to support basic analog stereo for now.
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore *
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * Adding back support for the advanced features would be an
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * interesting project for someone with access to suitable hardware.
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore *
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * Note that each variant (CMI 8338, 8738-033, -037, -055, and 8768)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * seems to have significant differences in some of the registers.
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * While programming these parts for basic stereo is pretty much the
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * same on all parts, doing anything more than that can be
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * sigificantly different for each part.
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic ddi_device_acc_attr_t acc_attr = {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore DDI_DEVICE_ATTR_V0,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore DDI_STRUCTURE_LE_ACC,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore DDI_STRICTORDER_ACC
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore};
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic ddi_device_acc_attr_t buf_attr = {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore DDI_DEVICE_ATTR_V0,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore DDI_NEVERSWAP_ACC,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore DDI_STRICTORDER_ACC
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore};
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic ddi_dma_attr_t dma_attr = {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore DMA_ATTR_VERSION, /* dma_attr_version */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore 0x0, /* dma_attr_addr_lo */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore 0xffffffffU, /* dma_attr_addr_hi */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore 0x3ffff, /* dma_attr_count_max */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore 0x8, /* dma_attr_align */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore 0x7f, /* dma_attr_burstsizes */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore 0x1, /* dma_attr_minxfer */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore 0x3ffff, /* dma_attr_maxxfer */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore 0x3ffff, /* dma_attr_seg */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore 0x1, /* dma_attr_sgllen */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore 0x1, /* dma_attr_granular */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore 0 /* dma_attr_flags */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore};
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic uint_t
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_intr(caddr_t arg1, caddr_t arg2)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_dev_t *dev = (void *)arg1;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore uint32_t intstat, intctrl, intclear;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore void (*cb0)(audio_engine_t *) = NULL;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore void (*cb1)(audio_engine_t *) = NULL;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore uint_t rv;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore _NOTE(ARGUNUSED(arg2));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore rv = DDI_INTR_UNCLAIMED;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_enter(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (dev->suspended) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_exit(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (rv);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore intclear = 0;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore intstat = GET32(dev, REG_INTSTAT);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore intctrl = GET32(dev, REG_INTCTRL);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if ((intstat & INTSTAT_CH0_INT) && (intctrl & INTCTRL_CH0_EN)) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore intclear |= INTCTRL_CH0_EN;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cb0 = dev->port[0].callb;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if ((intstat & INTSTAT_CH1_INT) && (intctrl & INTCTRL_CH1_EN)) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore intclear |= INTCTRL_CH1_EN;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cb1 = dev->port[1].callb;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* toggle the bits that we are going to handle */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (intclear) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore CLR32(dev, REG_INTCTRL, intclear);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore SET32(dev, REG_INTCTRL, intclear);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore rv = DDI_INTR_CLAIMED;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore KSINTR(dev)->intrs[KSTAT_INTR_HARD]++;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_exit(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (cb0) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore (*cb0)(dev->port[0].engine);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (cb1) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore (*cb1)(dev->port[1].engine);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (rv);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic void
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_reset_port(cmpci_port_t *port)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_dev_t *dev = port->dev;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (dev->suspended)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->offset = 0;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* reset channel */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore SET32(dev, REG_FUNCTRL0, port->fc0_rst_bit);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore drv_usecwait(10);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore CLR32(dev, REG_FUNCTRL0, port->fc0_rst_bit);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore drv_usecwait(10);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* Set 48k 16-bit stereo -- these are just with all bits set. */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore SET32(dev, REG_FUNCTRL1, port->fc1_rate_mask);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore SET32(dev, REG_CHFORMAT, port->chformat_mask);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore PUT32(dev, port->reg_paddr, port->paddr);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore PUT16(dev, port->reg_bufsz, port->nframes - 1);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore PUT16(dev, port->reg_fragsz, port->fragfr - 1);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* Analog output */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (port->capture) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* Analog capture */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore SET32(dev, REG_FUNCTRL0, port->fc0_rec_bit);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore } else {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore CLR32(dev, REG_FUNCTRL0, port->fc0_rec_bit);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic void
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_start_port(cmpci_port_t *port)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_dev_t *dev = port->dev;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (dev->suspended)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore SET32(dev, REG_FUNCTRL0, port->fc0_en_bit);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore SET32(dev, REG_INTCTRL, port->int_en_bit);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic void
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_stop_port(cmpci_port_t *port)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_dev_t *dev = port->dev;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (dev->suspended)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore CLR32(dev, REG_FUNCTRL0, port->fc0_en_bit);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore CLR32(dev, REG_INTCTRL, port->int_en_bit);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic int
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_open(void *arg, int flag, uint_t *fragfrp, uint_t *nfp, caddr_t *bufp)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_port_t *port = arg;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_dev_t *dev = port->dev;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore int intrs;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_enter(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (flag & ENGINE_INPUT) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore intrs = dev->rintrs;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore } else {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore intrs = dev->pintrs;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /*
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * Calculate fragfr, nfrags, buf.
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore *
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * 48 as minimum is chosen to ensure that we will have at
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * least 4 fragments. 512 is just an arbitrary limit, and at
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * the smallest frame size will result in no more than 176
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * fragments.
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore intrs = min(512, max(48, intrs));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->fragfr = (48000 / intrs);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->nfrags = CMPCI_BUF_LEN / (port->fragfr * 4);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->nframes = port->nfrags * port->fragfr;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->count = 0;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->bufsz = port->nframes * 4;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore *fragfrp = port->fragfr;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore *nfp = port->nfrags;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore *bufp = port->kaddr;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->open = B_TRUE;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_reset_port(port);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_start_port(port);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_exit(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (0);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic void
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_close(void *arg)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_port_t *port = arg;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_dev_t *dev = port->dev;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_enter(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->open = B_FALSE;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_stop_port(port);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_exit(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic void
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_update_port(cmpci_port_t *port)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_dev_t *dev = port->dev;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore uint32_t count;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore uint32_t offset;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if ((dev->suspended) || (!port->open))
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore offset = GET32(dev, port->reg_paddr) - port->paddr;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* check for wrap */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (offset < port->offset) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore count = (port->bufsz - port->offset) + offset;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore } else {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore count = offset - port->offset;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->count += count;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->offset = offset;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic uint64_t
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_count(void *arg)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_port_t *port = arg;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_dev_t *dev = port->dev;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore uint64_t count;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_enter(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_update_port(port);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* 4 is from 16-bit stereo */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore count = port->count / 4;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_exit(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* NB: 2 because each sample is 2 bytes wide */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (count);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic int
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_setup_interrupts(cmpci_dev_t *dev)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore int actual;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore uint_t ipri;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if ((ddi_intr_alloc(dev->dip, &dev->ihandle, DDI_INTR_TYPE_FIXED,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore 0, 1, &actual, DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) ||
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore (actual != 1)) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_warn(dev->adev, "can't alloc intr handle");
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_FAILURE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (ddi_intr_get_pri(dev->ihandle, &ipri) != DDI_SUCCESS) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_warn(dev->adev, "can't determine intr priority");
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore (void) ddi_intr_free(dev->ihandle);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore dev->ihandle = NULL;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_FAILURE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (ddi_intr_add_handler(dev->ihandle, cmpci_intr, dev,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore NULL) != DDI_SUCCESS) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_warn(dev->adev, "can't add intr handler");
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore (void) ddi_intr_free(dev->ihandle);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore dev->ihandle = NULL;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_FAILURE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_SUCCESS);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore#define MASK(nbits) ((1 << (nbits)) - 1)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore#define SCALE(val, nbits) \
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore ((uint8_t)((((val) * MASK(nbits)) / 100)) << (8 - (nbits)))
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore#define LEFT(dev, ctl) min(((dev->controls[ctl].value) >> 8), 100)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore#define RIGHT(dev, ctl) min(((dev->controls[ctl].value) & 0xff), 100)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore#define MONO(dev, ctl) min(dev->controls[ctl].value, 100)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic void
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_setmixer(cmpci_dev_t *dev, uint8_t idx, uint8_t val)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore PUT8(dev, REG_IDXADDR, idx);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore PUT8(dev, REG_IDXDATA, val);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic uint8_t
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_getmixer(cmpci_dev_t *dev, uint8_t idx)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore PUT8(dev, REG_IDXADDR, idx);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (GET8(dev, REG_IDXDATA));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic void
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_configure_mixer(cmpci_dev_t *dev)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore uint64_t left, right;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore uint8_t outmix;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore uint8_t inmix[2];
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore uint64_t recsrcs;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore uint64_t monsrcs;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (dev->suspended)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* reset all mix values */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore outmix = inmix[0] = inmix[1] = 0;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore outmix = OUTMIX_MIC |
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore OUTMIX_CD_R | OUTMIX_CD_L | OUTMIX_LINE_R | OUTMIX_LINE_L;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore inmix[0] = INMIX_LINE_L | INMIX_CD_L | INMIX_MIC;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore inmix[1] = INMIX_LINE_R | INMIX_CD_R | INMIX_MIC;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore recsrcs = dev->controls[CTL_RECSRCS].value;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore monsrcs = dev->controls[CTL_MONSRCS].value;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* program PCM volume */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore left = MONO(dev, CTL_VOLUME);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (left) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* left and right are the same */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_VOICE_LEFT, SCALE(left, 5));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_VOICE_RIGHT, SCALE(left, 5));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore CLR8(dev, REG_MIX2, MIX2_WSMUTE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore } else {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_VOICE_LEFT, 0);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_VOICE_RIGHT, 0);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore SET8(dev, REG_MIX2, MIX2_WSMUTE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore left = LEFT(dev, CTL_LINEOUT);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore right = RIGHT(dev, CTL_LINEOUT);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* lineout/master volume - no separate mute */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_MASTER_LEFT, SCALE(left, 5));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_MASTER_RIGHT, SCALE(right, 5));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* speaker volume - mute in extension register, but we don't use */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore left = MONO(dev, CTL_SPEAKER);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_SPEAKER, SCALE(left, 2));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* mic gain */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore left = MONO(dev, CTL_MIC);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (left) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_MIC, SCALE(left, 5));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* set record mic gain */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore uint8_t v = GET8(dev, REG_MIX3);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore v &= ~(0x7 << 1);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore v |= ((left * 7) / 100) << 1;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore PUT8(dev, REG_MIX3, v);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, 0x3f, SCALE(100, 2));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, 0x40, SCALE(100, 2));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore } else {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_MIC, 0);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore outmix &= ~OUTMIX_MIC;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore inmix[0] &= ~INMIX_MIC;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore inmix[1] &= ~INMIX_MIC;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* line in */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore left = LEFT(dev, CTL_LINEOUT);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore right = RIGHT(dev, CTL_LINEOUT);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (left) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_LINEIN_LEFT, SCALE(left, 5));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore } else {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_LINEIN_LEFT, 0);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore inmix[0] &= ~INMIX_LINE_L;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore outmix &= ~OUTMIX_LINE_L;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (right) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_LINEIN_RIGHT, SCALE(left, 5));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore } else {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_LINEIN_RIGHT, 0);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore inmix[1] &= ~INMIX_LINE_R;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore outmix &= ~OUTMIX_LINE_R;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* cd */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore left = LEFT(dev, CTL_CD);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore right = RIGHT(dev, CTL_CD);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (left) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_CDDA_LEFT, SCALE(left, 5));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore } else {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_CDDA_LEFT, 0);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore inmix[0] &= ~INMIX_CD_L;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore outmix &= ~OUTMIX_CD_L;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (right) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_CDDA_RIGHT, SCALE(left, 5));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore } else {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_CDDA_RIGHT, 0);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore inmix[1] &= ~INMIX_CD_R;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore outmix &= ~OUTMIX_CD_R;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* aux - trickier because it doesn't use regular sbpro mixer */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore left = LEFT(dev, CTL_AUX);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore right = RIGHT(dev, CTL_AUX);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore PUT8(dev, REG_VAUX, (((left * 15) / 100) << 4) | ((right * 15) / 100));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* maybe enable recording */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if ((left || right) && (recsrcs & (1 << SRC_LINE))) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore SET8(dev, REG_MIX3, MIX3_RAUXREN | MIX3_RAUXLEN);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore } else {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore CLR8(dev, REG_MIX3, MIX3_RAUXREN | MIX3_RAUXLEN);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* maybe enable monitoring */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if ((left || right) && (monsrcs & (1 << SRC_AUX))) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore CLR8(dev, REG_MIX3, MIX3_VAUXRM | MIX3_VAUXLM);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore } else {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore SET8(dev, REG_MIX3, MIX3_VAUXRM | MIX3_VAUXLM);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* now do the recsrcs */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if ((recsrcs & (1 << SRC_MIC)) == 0) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore inmix[0] &= ~INMIX_MIC;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore inmix[1] &= ~INMIX_MIC;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if ((recsrcs & (1 << SRC_LINE)) == 0) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore inmix[0] &= ~INMIX_LINE_L;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore inmix[1] &= ~INMIX_LINE_R;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if ((recsrcs & (1 << SRC_CD)) == 0) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore inmix[0] &= ~INMIX_CD_L;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore inmix[1] &= ~INMIX_CD_R;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (recsrcs & (1 << SRC_MIX)) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore SET8(dev, REG_MIX2, MIX2_WAVEIN_L | MIX2_WAVEIN_R);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore } else {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore CLR8(dev, REG_MIX2, MIX2_WAVEIN_L | MIX2_WAVEIN_R);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_INMIX_L, inmix[0]);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_INMIX_R, inmix[1]);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* now the monsrcs */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if ((monsrcs & (1 << SRC_MIC)) == 0) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore outmix &= ~OUTMIX_MIC;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if ((monsrcs & (1 << SRC_LINE)) == 0) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore outmix &= ~(OUTMIX_LINE_L | OUTMIX_LINE_R);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if ((monsrcs & (1 << SRC_CD)) == 0) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore outmix &= ~(OUTMIX_CD_L | OUTMIX_CD_R);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_OUTMIX, outmix);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* micboost */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (dev->controls[CTL_MICBOOST].value != 0) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore CLR8(dev, REG_MIX3, MIX3_MICGAINZ);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_EXTENSION,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_getmixer(dev, IDX_EXTENSION) & ~0x1);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore } else {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore SET8(dev, REG_MIX3, MIX3_MICGAINZ);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_setmixer(dev, IDX_EXTENSION,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_getmixer(dev, IDX_EXTENSION) | 0x1);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic int
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_set_ctrl(void *arg, uint64_t val)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_ctrl_t *cc = arg;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_dev_t *dev = cc->dev;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /*
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * We don't bother to check for valid values - a bogus value
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * will give incorrect volumes, but is otherwise harmless.
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_enter(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cc->value = val;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_configure_mixer(dev);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_exit(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (0);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic int
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_get_ctrl(void *arg, uint64_t *val)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_ctrl_t *cc = arg;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_dev_t *dev = cc->dev;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_enter(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore *val = cc->value;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_exit(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (0);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore#define PLAYCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_PLAY)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore#define RECCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_REC)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore#define MONCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_MONITOR)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore#define PCMVOL (PLAYCTL | AUDIO_CTRL_FLAG_PCMVOL)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore#define MAINVOL (PLAYCTL | AUDIO_CTRL_FLAG_MAINVOL)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore#define RECVOL (RECCTL | AUDIO_CTRL_FLAG_RECVOL)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic void
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_alloc_ctrl(cmpci_dev_t *dev, uint32_t num, uint64_t val)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_ctrl_desc_t desc;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_ctrl_t *cc;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cc = &dev->controls[num];
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore bzero(&desc, sizeof (desc));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cc->dev = dev;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore switch (num) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore case CTL_VOLUME:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_name = AUDIO_CTRL_ID_VOLUME;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_MONO;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_minvalue = 0;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_maxvalue = 100;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_flags = PCMVOL;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore break;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore case CTL_LINEOUT:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_name = AUDIO_CTRL_ID_LINEOUT;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_minvalue = 0;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_maxvalue = 100;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_flags = MAINVOL;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore break;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore case CTL_SPEAKER:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_name = AUDIO_CTRL_ID_SPEAKER;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_MONO;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_minvalue = 0;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_maxvalue = 100;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_flags = MAINVOL;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore break;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore case CTL_MIC:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_name = AUDIO_CTRL_ID_MIC;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_MONO;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_minvalue = 0;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_maxvalue = 100;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_flags = RECVOL;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore break;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore case CTL_LINEIN:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_name = AUDIO_CTRL_ID_LINEIN;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_minvalue = 0;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_maxvalue = 100;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_flags = RECVOL;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore break;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore case CTL_CD:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_name = AUDIO_CTRL_ID_CD;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_minvalue = 0;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_maxvalue = 100;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_flags = RECVOL;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore break;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore case CTL_AUX:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_name = AUDIO_CTRL_ID_AUX1IN;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_minvalue = 0;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_maxvalue = 100;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_flags = RECVOL;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore break;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore case CTL_RECSRCS:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_name = AUDIO_CTRL_ID_RECSRC;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_ENUM;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_enum[SRC_MIC] = AUDIO_PORT_MIC;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_enum[SRC_LINE] = AUDIO_PORT_LINEIN;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_enum[SRC_CD] = AUDIO_PORT_CD;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_enum[SRC_AUX] = AUDIO_PORT_AUX1IN;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_enum[SRC_MIX] = AUDIO_PORT_STEREOMIX;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_minvalue = (1 << (SRC_MIX + 1)) - 1;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_maxvalue = desc.acd_minvalue;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_flags = RECCTL | AUDIO_CTRL_FLAG_MULTI;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore break;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore case CTL_MONSRCS:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_name = AUDIO_CTRL_ID_MONSRC;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_ENUM;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_enum[SRC_MIC] = AUDIO_PORT_MIC;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_enum[SRC_LINE] = AUDIO_PORT_LINEIN;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_enum[SRC_CD] = AUDIO_PORT_CD;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_enum[SRC_AUX] = AUDIO_PORT_AUX1IN;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_minvalue = ((1 << (SRC_AUX + 1)) - 1);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_maxvalue = desc.acd_minvalue;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_flags = MONCTL | AUDIO_CTRL_FLAG_MULTI;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore break;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore case CTL_MICBOOST:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_name = AUDIO_CTRL_ID_MICBOOST;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_BOOLEAN;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_minvalue = 0;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_maxvalue = 1;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore desc.acd_flags = RECCTL;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore break;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cc->value = val;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cc->ctrl = audio_dev_add_control(dev->adev, &desc,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_get_ctrl, cmpci_set_ctrl, cc);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic void
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_add_controls(cmpci_dev_t *dev)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_alloc_ctrl(dev, CTL_VOLUME, 75);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_alloc_ctrl(dev, CTL_LINEOUT, 90 | (90 << 8));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_alloc_ctrl(dev, CTL_SPEAKER, 75);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_alloc_ctrl(dev, CTL_MIC, 32);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_alloc_ctrl(dev, CTL_LINEIN, 64 | (64 << 8));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_alloc_ctrl(dev, CTL_CD, 75 | (75 << 8));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_alloc_ctrl(dev, CTL_AUX, 75 | (75 << 8));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_alloc_ctrl(dev, CTL_RECSRCS, (1 << SRC_MIC));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_alloc_ctrl(dev, CTL_MONSRCS, 0);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_alloc_ctrl(dev, CTL_MICBOOST, 0);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic void
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_del_controls(cmpci_dev_t *dev)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore for (int i = 0; i < CTL_NUM; i++) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (dev->controls[i].ctrl) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_del_control(dev->controls[i].ctrl);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore dev->controls[i].ctrl = NULL;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic void
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_reset(cmpci_dev_t *dev)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* Full reset */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore SET32(dev, REG_MISC, MISC_RESET);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore (void) GET32(dev, REG_MISC);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore drv_usecwait(100);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore CLR32(dev, REG_MISC, MISC_RESET);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* reset all channels */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore PUT32(dev, REG_FUNCTRL0, 0);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* disable interrupts and such */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore CLR32(dev, REG_FUNCTRL0, FUNCTRL0_CH0_EN | FUNCTRL0_CH1_EN);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore CLR32(dev, REG_INTCTRL, INTCTRL_CH0_EN | INTCTRL_CH1_EN);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* disable uart, joystick in Function Control Reg1 */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore CLR32(dev, REG_FUNCTRL1, FUNCTRL1_UART_EN | FUNCTRL1_JYSTK_EN);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /*
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * Set DAC and ADC rates to 48 kHz - note that both rates have
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * all bits set in them, so we can do this with a simple "set".
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore SET32(dev, REG_FUNCTRL1,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore FUNCTRL1_DAC_RATE_48K | FUNCTRL1_ADC_RATE_48K);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* Set 16-bit stereo -- also these are just with all bits set. */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore SET32(dev, REG_CHFORMAT, CHFORMAT_CH0_16ST | CHFORMAT_CH1_16ST);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic int
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_format(void *unused)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore _NOTE(ARGUNUSED(unused));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (AUDIO_FORMAT_S16_LE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic int
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_channels(void *unused)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore _NOTE(ARGUNUSED(unused));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (2);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic int
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_rate(void *unused)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore _NOTE(ARGUNUSED(unused));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (48000);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic void
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_sync(void *arg, unsigned nframes)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_port_t *port = arg;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore _NOTE(ARGUNUSED(nframes));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore (void) ddi_dma_sync(port->dmah, 0, 0, port->sync_dir);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic size_t
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_qlen(void *unused)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore _NOTE(ARGUNUSED(unused));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (0);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amoreaudio_engine_ops_t cmpci_engine_ops = {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore AUDIO_ENGINE_VERSION, /* version number */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_open,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_close,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore NULL, /* start */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore NULL, /* stop */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_count,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_format,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_channels,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_rate,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_sync,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_qlen,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore NULL,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore};
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic int
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_init(cmpci_dev_t *dev)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_t *adev = dev->adev;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore dev->pintrs = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore DDI_PROP_DONTPASS, "play-interrupts", DEFINTS);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore dev->rintrs = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore DDI_PROP_DONTPASS, "record-interrupts", DEFINTS);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore for (int i = 0; i < PORT_MAX; i++) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_port_t *port;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore unsigned dmaflags;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore unsigned caps;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore size_t rlen;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore ddi_dma_cookie_t c;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore unsigned ccnt;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port = &dev->port[i];
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->dev = dev;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->num = i;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /*
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * Channel 0 is recording channel, unless we are in
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * dual DAC mode. The reason for this is simple --
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * only channel "B" (which I presume to mean channel
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * 1) supports multichannel configuration.
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore *
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * However, if we're going to use SPDIF recording,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * then recording *must* occur on channel 1. Yes, the
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore * hardware is "strange".
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore switch (i) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore case 0:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore caps = ENGINE_INPUT_CAP;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore dmaflags = DDI_DMA_READ | DDI_DMA_CONSISTENT;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->callb = audio_engine_produce;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->reg_paddr = REG_CH0_PADDR;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->reg_bufsz = REG_CH0_BUFSZ;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->reg_fragsz = REG_CH0_FRAGSZ;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->fc0_rst_bit = FUNCTRL0_CH0_RST;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->fc0_rec_bit = FUNCTRL0_CH0_REC;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->fc0_en_bit = FUNCTRL0_CH0_EN;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->int_en_bit = INTCTRL_CH0_EN;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->sync_dir = DDI_DMA_SYNC_FORKERNEL;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->capture = B_TRUE;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->fc1_rate_mask = FUNCTRL1_ADC_RATE_48K;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->chformat_mask = CHFORMAT_CH0_16ST;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore break;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore case 1:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore caps = ENGINE_OUTPUT_CAP;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore dmaflags = DDI_DMA_WRITE | DDI_DMA_CONSISTENT;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->callb = audio_engine_consume;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->reg_paddr = REG_CH1_PADDR;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->reg_bufsz = REG_CH1_BUFSZ;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->reg_fragsz = REG_CH1_FRAGSZ;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->fc0_rst_bit = FUNCTRL0_CH1_RST;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->fc0_rec_bit = FUNCTRL0_CH1_REC;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->fc0_en_bit = FUNCTRL0_CH1_EN;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->int_en_bit = INTCTRL_CH1_EN;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->sync_dir = DDI_DMA_SYNC_FORDEV;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->capture = B_FALSE;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->fc1_rate_mask = FUNCTRL1_DAC_RATE_48K;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->chformat_mask = CHFORMAT_CH1_16ST;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore break;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (ddi_dma_alloc_handle(dev->dip, &dma_attr, DDI_DMA_DONTWAIT,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore NULL, &port->dmah) != DDI_SUCCESS) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_warn(adev, "ch%d: dma hdl alloc failed", i);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_FAILURE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (ddi_dma_mem_alloc(port->dmah, CMPCI_BUF_LEN, &buf_attr,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, &port->kaddr,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore &rlen, &port->acch) != DDI_SUCCESS) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_warn(adev, "ch%d: dma mem allcoc failed", i);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_FAILURE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore bzero(port->kaddr, rlen);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (ddi_dma_addr_bind_handle(port->dmah, NULL, port->kaddr,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore rlen, dmaflags, DDI_DMA_DONTWAIT, NULL, &c, &ccnt) !=
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore DDI_DMA_MAPPED) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_warn(adev, "ch%d: dma bind failed", i);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_FAILURE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->paddr = c.dmac_address;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore port->engine = audio_engine_alloc(&cmpci_engine_ops, caps);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (port->engine == NULL) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_warn(adev, "ch%d: alloc engine failed", i);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_FAILURE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_engine_set_private(port->engine, port);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_add_engine(adev, port->engine);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_add_controls(dev);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore dev->ksp = kstat_create(ddi_driver_name(dev->dip),
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore ddi_get_instance(dev->dip), ddi_driver_name(dev->dip),
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore "controller", KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (dev->ksp != NULL) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore kstat_install(dev->ksp);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_reset(dev);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_configure_mixer(dev);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (audio_dev_register(adev) != DDI_SUCCESS) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_warn(adev, "audio_dev_register failed");
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_FAILURE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_SUCCESS);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorevoid
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_destroy(cmpci_dev_t *dev)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (dev->ihandle != NULL) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore (void) ddi_intr_disable(dev->ihandle);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore (void) ddi_intr_remove_handler(dev->ihandle);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore (void) ddi_intr_free(dev->ihandle);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_destroy(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (dev->ksp != NULL) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore kstat_delete(dev->ksp);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* free up ports, including DMA resources for ports */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore for (int i = 0; i < PORT_MAX; i++) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_port_t *port = &dev->port[i];
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (port->paddr != 0)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore (void) ddi_dma_unbind_handle(port->dmah);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (port->acch != NULL)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore ddi_dma_mem_free(&port->acch);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (port->dmah != NULL)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore ddi_dma_free_handle(&port->dmah);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (port->engine != NULL) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_remove_engine(dev->adev, port->engine);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_engine_free(port->engine);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (dev->acch != NULL) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore ddi_regs_map_free(&dev->acch);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_del_controls(dev);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (dev->adev != NULL) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_free(dev->adev);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore kmem_free(dev, sizeof (*dev));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amoreint
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_attach(dev_info_t *dip)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore uint16_t vendor, device;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_dev_t *dev;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore ddi_acc_handle_t pcih;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_t *adev;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore uint32_t val;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_warn(NULL, "pci_config_setup failed");
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_FAILURE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore vendor = pci_config_get16(pcih, PCI_CONF_VENID);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore device = pci_config_get16(pcih, PCI_CONF_DEVID);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (vendor != CMEDIA_VENDOR_ID ||
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore ((device != CMEDIA_CM8738) && (device != CMEDIA_CM8338A) &&
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore (device != CMEDIA_CM8338B))) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore pci_config_teardown(&pcih);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_warn(NULL, "device not recognized");
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_FAILURE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* enable IO and Master accesses */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore pci_config_put16(pcih, PCI_CONF_COMM,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore pci_config_get16(pcih, PCI_CONF_COMM) |
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore PCI_COMM_MAE | PCI_COMM_IO);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore pci_config_teardown(&pcih);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore dev = kmem_zalloc(sizeof (*dev), KM_SLEEP);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore dev->dip = dip;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore ddi_set_driver_private(dip, dev);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if ((adev = audio_dev_alloc(dip, 0)) == NULL) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore goto err_exit;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore dev->adev = adev;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (ddi_regs_map_setup(dip, 1, &dev->regs, 0, 0, &acc_attr,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore &dev->acch) != DDI_SUCCESS) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_warn(adev, "can't map registers");
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore goto err_exit;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* setup some initial values */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_set_description(adev, "C-Media PCI Audio");
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore switch (device) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore case CMEDIA_CM8738:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* Crazy 8738 detection scheme */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore val = GET32(dev, REG_INTCTRL) & 0x1F000000;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (val == 0) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (GET32(dev, REG_CHFORMAT & 0x1F000000)) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_set_version(adev, "CM8738-037");
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore } else {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_set_version(adev, "CM8738-033");
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore } else if (val & 0x0C000000) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_set_version(adev, "CMI8768");
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore } else if (val & 0x08000000) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_set_version(adev, "CMI8738-055");
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore } else if (val & 0x04000000) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_set_version(adev, "CMI8738-039");
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore } else {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_set_version(adev, "CMI8738");
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore break;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore case CMEDIA_CM8338A:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_set_version(dev->adev, "CM8338A");
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore break;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore case CMEDIA_CM8338B:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_set_version(dev->adev, "CM8338B");
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore break;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (cmpci_setup_interrupts(dev) != DDI_SUCCESS) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_warn(dev->adev, "can't register interrupts");
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore goto err_exit;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (cmpci_init(dev) != DDI_SUCCESS) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_dev_warn(dev->adev, "can't init device");
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore goto err_exit;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore (void) ddi_intr_enable(dev->ihandle);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_SUCCESS);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amoreerr_exit:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_destroy(dev);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_FAILURE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic int
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_resume(cmpci_dev_t *dev)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_engine_reset(dev->port[0].engine);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_engine_reset(dev->port[1].engine);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_enter(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore dev->suspended = B_FALSE;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_reset(dev);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* wait one millisecond, to give reset a chance to get up */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore drv_usecwait(1000);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_configure_mixer(dev);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore for (int i = 0; i < PORT_MAX; i++) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_port_t *port = &dev->port[i];
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_reset_port(port);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (port->open) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_start_port(port);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_exit(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_SUCCESS);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic int
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_detach(cmpci_dev_t *dev)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if (audio_dev_unregister(dev->adev) != DDI_SUCCESS)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_FAILURE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_enter(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* disable interrupts */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore CLR32(dev, REG_INTCTRL, INTCTRL_CH1_EN | INTCTRL_CH0_EN);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* disable channels */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore PUT32(dev, REG_FUNCTRL0, 0);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_exit(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_destroy(dev);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_SUCCESS);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic int
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_suspend(cmpci_dev_t *dev)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_enter(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_update_port(&dev->port[0]);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_stop_port(&dev->port[0]);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_update_port(&dev->port[1]);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_stop_port(&dev->port[1]);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore dev->suspended = B_TRUE;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore mutex_exit(&dev->mutex);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_SUCCESS);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic int
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_quiesce(dev_info_t *dip)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_dev_t *dev;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if ((dev = ddi_get_driver_private(dip)) == NULL) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_FAILURE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* disable interrupts */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore PUT32(dev, REG_INTCTRL, 0);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore /* disable channels */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore PUT32(dev, REG_FUNCTRL0, 0);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_SUCCESS);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic int
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_dev_t *dev;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore switch (cmd) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore case DDI_ATTACH:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (cmpci_attach(dip));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore case DDI_RESUME:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if ((dev = ddi_get_driver_private(dip)) == NULL) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_FAILURE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (cmpci_resume(dev));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore default:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_FAILURE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic int
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorecmpci_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_dev_t *dev;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if ((dev = ddi_get_driver_private(dip)) == NULL) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_FAILURE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore switch (cmd) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore case DDI_DETACH:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (cmpci_detach(dev));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore case DDI_SUSPEND:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (cmpci_suspend(dev));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore default:
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (DDI_FAILURE);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic struct dev_ops cmpci_dev_ops = {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore DEVO_REV, /* rev */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore 0, /* refcnt */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore NULL, /* getinfo */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore nulldev, /* identify */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore nulldev, /* probe */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_ddi_attach, /* attach */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_ddi_detach, /* detach */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore nodev, /* reset */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore NULL, /* cb_ops */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore NULL, /* bus_ops */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore NULL, /* power */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore cmpci_quiesce, /* quiesce */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore};
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic struct modldrv cmpci_modldrv = {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore &mod_driverops, /* drv_modops */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore "C-Media PCI Audio", /* linkinfo */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore &cmpci_dev_ops, /* dev_ops */
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore};
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amorestatic struct modlinkage modlinkage = {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore MODREV_1,
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore { &cmpci_modldrv, NULL }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore};
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amoreint
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore_init(void)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore int rv;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_init_ops(&cmpci_dev_ops, "audiocmi");
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if ((rv = mod_install(&modlinkage)) != 0) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_fini_ops(&cmpci_dev_ops);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (rv);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amoreint
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore_fini(void)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore int rv;
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore if ((rv = mod_remove(&modlinkage)) == 0) {
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore audio_fini_ops(&cmpci_dev_ops);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore }
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (rv);
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amoreint
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore_info(struct modinfo *modinfop)
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore{
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore return (mod_info(&modlinkage, modinfop));
08045defdf65ee890fef6e20510a093a17feb8feGarrett D'Amore}