88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER START
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The contents of this file are subject to the terms of the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Common Development and Distribution License (the "License").
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * You may not use this file except in compliance with the License.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * or http://www.opensolaris.org/os/licensing.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * See the License for the specific language governing permissions
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * and limitations under the License.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER END
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
239924d360a544a40689b6b360d1183a0a936d97Garrett D'Amore * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore * Copyright 2016 Garrett D'Amore <garrett@damore.org>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Purpose: Creative/Ensoniq AudioPCI97 driver (ES1371/ES1373)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This driver is used with the original Ensoniq AudioPCI97 card and many
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * PCI based Sound Blaster cards by Creative Technologies. For example
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Sound Blaster PCI128 and Creative/Ectiva EV1938.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This file is part of Open Sound System
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Copyright (C) 4Front Technologies 1996-2008.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This software is released under CDDL 1.0 source license.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * See the COPYING file included in the main directory of this source
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * distribution for the license terms and conditions.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/audio/audio_driver.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/audio/ac97.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/note.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/pci.h>
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore/*
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore * For VMWare platforms, we have to utilize the (emulated) hardware interrupts
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore * of the device. This is necessary for audio playback to function, as
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore * the toggling of the interrupt bits apparently triggers logic inside the
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore * emulated device. So we need to detect this platform, and conditionally
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore * wire up the interrupt handler.
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore */
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#ifdef __x86
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#include <sys/x86_archext.h>
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#endif
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include "audioens.h"
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Set the latency to 32, 64, 96, 128 clocks - some APCI97 devices exhibit
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * garbled audio in some cases and setting the latency to higer values fixes it
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Values: 32, 64, 96, 128 - Default: 64 (or defined by bios)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint audioens_latency = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Enable SPDIF port on SoundBlaster 128D or Sound Blaster Digital-4.1 models
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Values: 1=Enable 0=Disable Default: 0
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint audioens_spdif = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Note: Latest devices can support SPDIF with AC3 pass thru.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * However, in order to do this, one of the two DMA engines must be
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dedicated to this, which would prevent the card from supporting 4
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * channel audio. For now we don't bother with the AC3 pass through
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * mode, and instead just focus on 4 channel support. In the future,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * this could be selectable via a property.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define ENSONIQ_VENDOR_ID 0x1274
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define CREATIVE_VENDOR_ID 0x1102
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define ECTIVA_VENDOR_ID 0x1102
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define ENSONIQ_ES1371 0x1371
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define ENSONIQ_ES5880 0x8001
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define ENSONIQ_ES5880A 0x8002
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define ENSONIQ_ES5880B 0x5880
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define ECTIVA_ES1938 0x8938
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define DEFRATE 48000
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define DRVNAME "audioens"
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoretypedef struct audioens_port
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Audio parameters */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int speed;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int num;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define PORT_DAC 0
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define PORT_ADC 1
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define PORT_MAX PORT_ADC
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore caddr_t kaddr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t paddr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_acc_handle_t acch;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_dma_handle_t dmah;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int nchan;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore unsigned nframes;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore unsigned iframes;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore unsigned frameno;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint64_t count;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore struct audioens_dev *dev;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore audio_engine_t *engine;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore} audioens_port_t;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoretypedef struct audioens_dev
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_t *osdev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore kmutex_t mutex;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t devid;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint8_t revision;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dev_info_t *dip;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_port_t port[PORT_MAX + 1];
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_t *ac97;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore caddr_t regs;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_acc_handle_t acch;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore boolean_t suspended;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#ifdef __x86
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore boolean_t useintr;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore ddi_intr_handle_t intrh;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore uint_t intrpri;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#endif
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore} audioens_dev_t;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic ddi_device_acc_attr_t acc_attr = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_DEVICE_ATTR_V0,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_STRUCTURE_LE_ACC,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_STRICTORDER_ACC
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic ddi_device_acc_attr_t buf_attr = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_DEVICE_ATTR_V0,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_NEVERSWAP_ACC,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_STRICTORDER_ACC
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic ddi_dma_attr_t dma_attr = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DMA_ATTR_VERSION, /* dma_attr_version */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0, /* dma_attr_addr_lo */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0xffffffffU, /* dma_attr_addr_hi */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x3ffff, /* dma_attr_count_max */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x8, /* dma_attr_align */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x7f, /* dma_attr_burstsizes */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x1, /* dma_attr_minxfer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x3ffff, /* dma_attr_maxxfer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x3ffff, /* dma_attr_seg */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x1, /* dma_attr_sgllen */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x1, /* dma_attr_granular */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0 /* dma_attr_flags */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define GET8(dev, offset) \
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_get8(dev->acch, (uint8_t *)(dev->regs + (offset)))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define GET16(dev, offset) \
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_get16(dev->acch, (uint16_t *)(void *)(dev->regs + (offset)))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define GET32(dev, offset) \
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_get32(dev->acch, (uint32_t *)(void *)(dev->regs + (offset)))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define PUT8(dev, offset, v) \
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put8(dev->acch, (uint8_t *)(dev->regs + (offset)), v)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define PUT16(dev, offset, v) \
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put16(dev->acch, (uint16_t *)(void *)(dev->regs + (offset)), v)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define PUT32(dev, offset, v) \
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(dev->acch, (uint32_t *)(void *)(dev->regs + (offset)), v)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define CLR8(dev, offset, v) PUT8(dev, offset, GET8(dev, offset) & ~(v))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define SET8(dev, offset, v) PUT8(dev, offset, GET8(dev, offset) | (v))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define CLR32(dev, offset, v) PUT32(dev, offset, GET32(dev, offset) & ~(v))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define SET32(dev, offset, v) PUT32(dev, offset, GET32(dev, offset) | (v))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audioens_init_hw(audioens_dev_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic uint16_t
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_rd97(void *dev_, uint8_t wAddr)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_dev_t *dev = dev_;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int i, dtemp;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&dev->mutex);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dtemp = GET32(dev, CONC_dCODECCTL_OFF);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* wait for WIP to go away saving the current state for later */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < 0x100UL; ++i) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dtemp = GET32(dev, CONC_dCODECCTL_OFF);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((dtemp & (1UL << 30)) == 0)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* write addr w/data=0 and assert read request ... */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(dev, CONC_dCODECCTL_OFF, ((int)wAddr << 16) | (1UL << 23));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* now wait for the data (RDY) */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < 0x100UL; ++i) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dtemp = GET32(dev, CONC_dCODECCTL_OFF);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (dtemp & (1UL << 31))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dtemp = GET32(dev, CONC_dCODECCTL_OFF);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&dev->mutex);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (dtemp & 0xffff);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_wr97(void *dev_, uint8_t wAddr, uint16_t wData)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_dev_t *dev = dev_;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int i, dtemp;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&dev->mutex);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* wait for WIP to go away */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < 0x100UL; ++i) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dtemp = GET32(dev, CONC_dCODECCTL_OFF);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((dtemp & (1UL << 30)) == 0)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(dev, CONC_dCODECCTL_OFF, ((int)wAddr << 16) | wData);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&dev->mutex);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic unsigned short
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'AmoreSRCRegRead(audioens_dev_t *dev, unsigned short reg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int i, dtemp;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dtemp = GET32(dev, CONC_dSRCIO_OFF);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* wait for ready */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < SRC_IOPOLL_COUNT; ++i) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dtemp = GET32(dev, CONC_dSRCIO_OFF);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((dtemp & SRC_BUSY) == 0)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* assert a read request */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(dev, CONC_dSRCIO_OFF, (dtemp & SRC_CTLMASK) | ((int)reg << 25));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* now wait for the data */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < SRC_IOPOLL_COUNT; ++i) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dtemp = GET32(dev, CONC_dSRCIO_OFF);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((dtemp & SRC_BUSY) == 0)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return ((unsigned short) dtemp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'AmoreSRCRegWrite(audioens_dev_t *dev, unsigned short reg, unsigned short val)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int i, dtemp;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int writeval;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dtemp = GET32(dev, CONC_dSRCIO_OFF);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* wait for ready */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < SRC_IOPOLL_COUNT; ++i) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dtemp = GET32(dev, CONC_dSRCIO_OFF);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((dtemp & SRC_BUSY) == 0)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* assert the write request */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore writeval = (dtemp & SRC_CTLMASK) | SRC_WENABLE |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ((int)reg << 25) | val;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(dev, CONC_dSRCIO_OFF, writeval);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'AmoreSRCSetRate(audioens_dev_t *dev, unsigned char base, unsigned short rate)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int i, freq, dtemp;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore unsigned short N, truncM, truncStart;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (base != SRC_ADC_BASE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* freeze the channel */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dtemp = (base == SRC_DAC1_BASE) ?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRC_DAC1FREEZE : SRC_DAC2FREEZE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < SRC_IOPOLL_COUNT; ++i) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!(GET32(dev, CONC_dSRCIO_OFF) & SRC_BUSY))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(dev, CONC_dSRCIO_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (GET32(dev, CONC_dSRCIO_OFF) & SRC_CTLMASK) | dtemp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* calculate new frequency and write it - preserve accum */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore freq = ((int)rate << 16) / 3000U;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCRegWrite(dev, (unsigned short) base + SRC_INT_REGS_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (SRCRegRead(dev, (unsigned short) base + SRC_INT_REGS_OFF)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore & 0x00ffU) | ((unsigned short) (freq >> 6) & 0xfc00));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCRegWrite(dev, (unsigned short) base + SRC_VFREQ_FRAC_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (unsigned short) freq >> 1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* un-freeze the channel */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < SRC_IOPOLL_COUNT; ++i)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!(GET32(dev, CONC_dSRCIO_OFF) & SRC_BUSY))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(dev, CONC_dSRCIO_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (GET32(dev, CONC_dSRCIO_OFF) & SRC_CTLMASK) & ~dtemp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* derive oversample ratio */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore N = rate / 3000U;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (N == 15 || N == 13 || N == 11 || N == 9)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore --N;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* truncate the filter and write n/trunc_start */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore truncM = (21 * N - 1) | 1;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (rate >= 24000U) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (truncM > 239)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore truncM = 239;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore truncStart = (239 - truncM) >> 1;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCRegWrite(dev, base + SRC_TRUNC_N_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (truncStart << 9) | (N << 4));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (truncM > 119)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore truncM = 119;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore truncStart = (119 - truncM) >> 1;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCRegWrite(dev, base + SRC_TRUNC_N_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x8000U | (truncStart << 9) | (N << 4));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* calculate new frequency and write it - preserve accum */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore freq = ((48000UL << 16) / rate) * N;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCRegWrite(dev, base + SRC_INT_REGS_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (SRCRegRead(dev, (unsigned short) base + SRC_INT_REGS_OFF)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore & 0x00ff) | ((unsigned short) (freq >> 6) & 0xfc00));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCRegWrite(dev, base + SRC_VFREQ_FRAC_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (unsigned short) freq >> 1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCRegWrite(dev, SRC_ADC_VOL_L, N << 8);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCRegWrite(dev, SRC_ADC_VOL_R, N << 8);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'AmoreSRCInit(audioens_dev_t *dev)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int i;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Clear all SRC RAM then init - keep SRC disabled until done */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < SRC_IOPOLL_COUNT; ++i) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!(GET32(dev, CONC_dSRCIO_OFF) & SRC_BUSY))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(dev, CONC_dSRCIO_OFF, SRC_DISABLE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < 0x80; ++i)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCRegWrite(dev, (unsigned short) i, 0U);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCRegWrite(dev, SRC_DAC1_BASE + SRC_TRUNC_N_OFF, 16 << 4);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCRegWrite(dev, SRC_DAC1_BASE + SRC_INT_REGS_OFF, 16 << 10);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCRegWrite(dev, SRC_DAC2_BASE + SRC_TRUNC_N_OFF, 16 << 4);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCRegWrite(dev, SRC_DAC2_BASE + SRC_INT_REGS_OFF, 16 << 10);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCRegWrite(dev, SRC_DAC1_VOL_L, 1 << 12);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCRegWrite(dev, SRC_DAC1_VOL_R, 1 << 12);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCRegWrite(dev, SRC_DAC2_VOL_L, 1 << 12);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCRegWrite(dev, SRC_DAC2_VOL_R, 1 << 12);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCRegWrite(dev, SRC_ADC_VOL_L, 1 << 12);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCRegWrite(dev, SRC_ADC_VOL_R, 1 << 12);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* default some rates */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCSetRate(dev, SRC_DAC1_BASE, 48000);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCSetRate(dev, SRC_DAC2_BASE, 48000);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCSetRate(dev, SRC_ADC_BASE, 48000);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* now enable the whole deal */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < SRC_IOPOLL_COUNT; ++i) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!(GET32(dev, CONC_dSRCIO_OFF) & SRC_BUSY))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(dev, CONC_dSRCIO_OFF, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_writemem(audioens_dev_t *dev, uint32_t page, uint32_t offs,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t data)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Select memory page */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(dev, CONC_bMEMPAGE_OFF, page);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(dev, offs, data);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic uint32_t
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_readmem(audioens_dev_t *dev, uint32_t page, uint32_t offs)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(dev, CONC_bMEMPAGE_OFF, page); /* Select memory page */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (GET32(dev, offs));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#ifdef __x86
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amorestatic unsigned
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amoreaudioens_intr(caddr_t arg1, caddr_t arg2)
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore{
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore audioens_dev_t *dev = (void *)arg1;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore uint32_t status;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore uint32_t frameno;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore uint32_t n;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore audioens_port_t *port;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore _NOTE(ARGUNUSED(arg2));
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore mutex_enter(&dev->mutex);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore if (dev->suspended || !dev->useintr) {
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore mutex_exit(&dev->mutex);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore return (DDI_INTR_UNCLAIMED);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore }
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore status = GET32(dev, CONC_dSTATUS_OFF);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore if ((status & CONC_STATUS_PENDING) == 0) {
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore mutex_exit(&dev->mutex);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore return (DDI_INTR_UNCLAIMED);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore }
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore /* Three interrupts, DAC1, DAC2, and ADC. The UART we just toss. */
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore if (status & CONC_STATUS_DAC1INT) {
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore port = &dev->port[PORT_DAC];
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore /* current frame counter is in high nybble */
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore frameno = audioens_readmem(dev,
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore CONC_DAC1CTL_PAGE, CONC_wDAC1FC_OFF) >> 16;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore n = frameno >= port->frameno ?
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore frameno - port->frameno :
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore frameno + port->nframes - port->frameno;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore port->frameno = frameno;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore port->count += n;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore CLR8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_DAC1IE);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore SET8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_DAC1IE);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore }
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore if (status & CONC_STATUS_ADCINT) {
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore port = &dev->port[PORT_ADC];
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore /* current frame counter is in high nybble */
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore frameno = audioens_readmem(dev,
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore CONC_ADCCTL_PAGE, CONC_wADCFC_OFF) >> 16;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore n = frameno >= port->frameno ?
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore frameno - port->frameno :
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore frameno + port->nframes - port->frameno;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore port->frameno = frameno;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore port->count += n;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore CLR8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_ADCIE);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore SET8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_ADCIE);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore }
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore if (status & CONC_STATUS_DAC2INT) {
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore CLR8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_DAC2IE);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore SET8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_DAC2IE);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore }
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore if (status & CONC_STATUS_UARTINT) {
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore /*
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore * Consume data in the UART RX FIFO. We don't support
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore * the UART for now, so just eat it.
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore */
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore while (GET8(dev, CONC_bUARTCSTAT_OFF) & CONC_UART_RXRDY)
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore continue;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore }
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore mutex_exit(&dev->mutex);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore return (DDI_INTR_CLAIMED);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore}
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amorestatic int
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amoreaudioens_setup_intr(audioens_dev_t *dev)
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore{
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore int act;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore uint_t ipri;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore if ((ddi_intr_alloc(dev->dip, &dev->intrh, DDI_INTR_TYPE_FIXED, 0, 1,
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore &act, DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) || (act != 1)) {
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore audio_dev_warn(dev->osdev, "can't alloc intr handle");
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore goto fail;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore }
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore if (ddi_intr_get_pri(dev->intrh, &ipri) != DDI_SUCCESS) {
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore audio_dev_warn(dev->osdev, "can't get interrupt priority");
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore goto fail;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore }
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore if (ddi_intr_add_handler(dev->intrh, audioens_intr, dev, NULL) !=
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore DDI_SUCCESS) {
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore audio_dev_warn(dev->osdev, "cannot add interrupt handler");
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore goto fail;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore }
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore dev->intrpri = ipri;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore return (DDI_SUCCESS);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amorefail:
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore if (dev->intrh != NULL) {
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore (void) ddi_intr_free(dev->intrh);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore dev->intrh = NULL;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore }
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore return (DDI_FAILURE);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore}
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#endif /* __x86 */
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Audio routines
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_format(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore _NOTE(ARGUNUSED(arg));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* hardware can also do AUDIO_FORMAT_U8, but no need for it */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (AUDIO_FORMAT_S16_LE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_channels(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (port->nchan);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_rate(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (port->speed);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amorestatic int
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amoreaudioens_open(void *arg, int flag, unsigned *nframes, caddr_t *bufp)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audioens_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_dev_t *dev = port->dev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore _NOTE(ARGUNUSED(flag));
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_enter(&dev->mutex);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore port->count = 0;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore *nframes = port->nframes;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore *bufp = port->kaddr;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_exit(&dev->mutex);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore return (0);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore}
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amorestatic int
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amoreaudioens_start(void *arg)
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore{
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audioens_port_t *port = arg;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audioens_dev_t *dev = port->dev;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore uint32_t tmp;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_enter(&dev->mutex);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (port->num) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case PORT_DAC:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set physical address of the DMA buffer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_writemem(dev, CONC_DAC1CTL_PAGE, CONC_dDAC1PADDR_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->paddr);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_writemem(dev, CONC_DAC2CTL_PAGE, CONC_dDAC2PADDR_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->paddr + (port->nframes * sizeof (int16_t) * 2));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set DAC rate */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCSetRate(dev, SRC_DAC1_BASE, port->speed);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCSetRate(dev, SRC_DAC2_BASE, port->speed);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Configure the channel setup - SPDIF only uses front */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp = GET32(dev, CONC_dSTATUS_OFF);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp &= ~(CONC_STATUS_SPKR_MASK | CONC_STATUS_SPDIF_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp |= CONC_STATUS_SPKR_4CH | CONC_STATUS_SPDIF_P1;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(dev, CONC_dSTATUS_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set format */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bSKIPC_OFF, 0x10);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SET8(dev, CONC_bSERFMT_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CONC_PCM_DAC1_16BIT | CONC_PCM_DAC2_16BIT |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CONC_PCM_DAC1_STEREO | CONC_PCM_DAC2_STEREO);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set the frame count */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_writemem(dev, CONC_DAC1CTL_PAGE, CONC_wDAC1FC_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->nframes - 1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_writemem(dev, CONC_DAC2CTL_PAGE, CONC_wDAC2FC_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->nframes - 1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore PUT16(dev, CONC_wDAC1IC_OFF, port->iframes - 1);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore PUT16(dev, CONC_wDAC2IC_OFF, port->iframes - 1);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore SET8(dev, CONC_bDEVCTL_OFF,
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore CONC_DEVCTL_DAC2_EN | CONC_DEVCTL_DAC1_EN);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#ifdef __x86
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore if (dev->useintr) {
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore SET8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_DAC1IE);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore }
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#endif
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case PORT_ADC:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set physical address of the DMA buffer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_writemem(dev, CONC_ADCCTL_PAGE, CONC_dADCPADDR_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->paddr);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set ADC rate */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCSetRate(dev, SRC_ADC_BASE, port->speed);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set format - for input we only support 16 bit input */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp = GET8(dev, CONC_bSERFMT_OFF);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp |= CONC_PCM_ADC_16BIT;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp |= CONC_PCM_ADC_STEREO;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bSKIPC_OFF, 0x10);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bSERFMT_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set the frame count */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_writemem(dev, CONC_ADCCTL_PAGE, CONC_wADCFC_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->nframes - 1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set # of frames between interrupts */
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore PUT16(dev, CONC_wADCIC_OFF, port->iframes - 1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore SET8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_ADC_EN);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#ifdef __x86
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore if (dev->useintr) {
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore SET8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_ADCIE);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore }
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#endif
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->frameno = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&dev->mutex);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amoreaudioens_stop(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_dev_t *dev = port->dev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&dev->mutex);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore switch (port->num) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore case PORT_DAC:
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore CLR8(dev, CONC_bDEVCTL_OFF,
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore CONC_DEVCTL_DAC2_EN | CONC_DEVCTL_DAC1_EN);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore break;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore case PORT_ADC:
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore CLR8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_ADC_EN);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&dev->mutex);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amorestatic uint64_t
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amoreaudioens_count(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_dev_t *dev = port->dev;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore uint64_t val;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t page, offs;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int frameno, n;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (port->num) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case PORT_DAC:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore page = CONC_DAC1CTL_PAGE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore offs = CONC_wDAC1FC_OFF;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case PORT_ADC:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore page = CONC_ADCCTL_PAGE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore offs = CONC_wADCFC_OFF;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_enter(&dev->mutex);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#ifdef __x86
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore if (!dev->useintr) {
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#endif
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Note that the current frame counter is in the high nybble.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore frameno = audioens_readmem(port->dev, page, offs) >> 16;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore n = frameno >= port->frameno ?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore frameno - port->frameno :
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore frameno + port->nframes - port->frameno;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->frameno = frameno;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->count += n;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#ifdef __x86
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore }
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#endif
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore val = port->count;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&dev->mutex);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (val);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_close(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore _NOTE(ARGUNUSED(arg));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_sync(void *arg, unsigned nframes)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore _NOTE(ARGUNUSED(nframes));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->num == PORT_ADC) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore (void) ddi_dma_sync(port->dmah, 0, 0, DDI_DMA_SYNC_FORKERNEL);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) ddi_dma_sync(port->dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_chinfo(void *arg, int chan, unsigned *offset, unsigned *incr)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((port->num == PORT_DAC) && (chan >= 2)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *offset = (port->nframes * 2) + (chan % 2);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *incr = 2;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *offset = chan;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *incr = 2;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio_engine_ops_t audioens_engine_ops = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AUDIO_ENGINE_VERSION, /* version number */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_open,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_close,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_start,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_stop,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_count,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_format,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_channels,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_rate,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_sync,
f9ead4a57883f3ef04ef20d83cc47987d98c0687Garrett D'Amore NULL,
f9ead4a57883f3ef04ef20d83cc47987d98c0687Garrett D'Amore audioens_chinfo,
f9ead4a57883f3ef04ef20d83cc47987d98c0687Garrett D'Amore NULL,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorevoid
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_init_hw(audioens_dev_t *dev)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int tmp;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((dev->devid == ENSONIQ_ES5880) ||
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (dev->devid == ENSONIQ_ES5880A) ||
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (dev->devid == ENSONIQ_ES5880B) ||
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (dev->devid == 0x1371 && dev->revision == 7) ||
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (dev->devid == 0x1371 && dev->revision >= 9)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Have a ES5880 so enable the codec manually */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp = GET8(dev, CONC_bINTSUMM_OFF) & 0xff;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp |= 0x20;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bINTSUMM_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; i < 2000; i++)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(10);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SRCInit(dev);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Turn on CODEC (UART and joystick left disabled)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp = GET32(dev, CONC_bDEVCTL_OFF) & 0xff;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp &= ~(CONC_DEVCTL_PCICLK_DS | CONC_DEVCTL_XTALCLK_DS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bDEVCTL_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bUARTCSTAT_OFF, 0x00);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Perform AC97 codec warm reset */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp = GET8(dev, CONC_bMISCCTL_OFF) & 0xff;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bMISCCTL_OFF, tmp | CONC_MISCCTL_SYNC_RES);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(200);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bMISCCTL_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(200);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (dev->revision >= 4) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* XXX: enable SPDIF - PCM only for now */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audioens_spdif) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* enable SPDIF */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(dev, 0x04, GET32(dev, 0x04) | (1 << 18));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* SPDIF out = data from DAC */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(dev, 0x00, GET32(dev, 0x00) | (1 << 26));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CLR32(dev, CONC_dSPDIF_OFF, CONC_SPDIF_AC3);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* disable spdif out */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(dev, 0x04, GET32(dev, 0x04) & ~(1 << 18));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(dev, 0x00, GET32(dev, 0x00) & ~(1 << 26));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* we want to run each channel independently */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CLR32(dev, CONC_dSTATUS_OFF, CONC_STATUS_ECHO);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_init(audioens_dev_t *dev)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_init_hw(dev);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * On this hardware, we want to disable the internal speaker by
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * default, if it exists. (We don't have a speakerphone on any
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * of these cards, and no SPARC hardware uses it either!)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
505c7a699305ccafcfecc1ab0e7d4a25e2bfd1c2Garrett D'Amore (void) ddi_prop_update_int(DDI_DEV_T_NONE, dev->dip, AC97_PROP_SPEAKER,
505c7a699305ccafcfecc1ab0e7d4a25e2bfd1c2Garrett D'Amore 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Init mixer
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dev->ac97 = ac97_alloc(dev->dip, audioens_rd97, audioens_wr97, dev);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (dev->ac97 == NULL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ac97_init(dev->ac97, dev->osdev) != 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; i <= PORT_MAX; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_port_t *port;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore unsigned caps;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore unsigned dmaflags;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore size_t rlen;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_dma_cookie_t c;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore unsigned ccnt;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore size_t bufsz;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port = &dev->port[i];
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->dev = dev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore /*
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore * We have 48000Hz. At that rate, 128 frames will give
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore * us an interrupt rate of 375Hz. 2048 frames buys about
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore * 42ms of buffer. Note that interrupts are only enabled
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore * for platforms which need them (i.e. VMWare).
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore */
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (i) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case PORT_DAC:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->nchan = 4;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->speed = 48000;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore port->iframes = 128;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore port->nframes = 2048;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore caps = ENGINE_OUTPUT_CAP;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dmaflags = DDI_DMA_WRITE | DDI_DMA_CONSISTENT;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case PORT_ADC:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->nchan = 2;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->speed = 48000;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore port->iframes = 128;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore port->nframes = 2048;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore caps = ENGINE_INPUT_CAP;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dmaflags = DDI_DMA_READ | DDI_DMA_CONSISTENT;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->num = i;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore bufsz = port->nframes * port->nchan * sizeof (uint16_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Allocate DMA resources.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_dma_alloc_handle(dev->dip, &dma_attr, DDI_DMA_SLEEP,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL, &port->dmah) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(dev->osdev,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "port %d: dma handle allocation failed", i);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore if (ddi_dma_mem_alloc(port->dmah, bufsz, &buf_attr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &port->kaddr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &rlen, &port->acch) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(dev->osdev,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "port %d: dma memory allocation failed", i);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* ensure that the buffer is zeroed out properly */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore bzero(port->kaddr, rlen);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_dma_addr_bind_handle(port->dmah, NULL, port->kaddr,
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore bufsz, dmaflags, DDI_DMA_SLEEP, NULL,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &c, &ccnt) != DDI_DMA_MAPPED) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(dev->osdev,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "port %d: dma binding failed", i);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->paddr = c.dmac_address;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Allocate and configure audio engine.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->engine = audio_engine_alloc(&audioens_engine_ops, caps);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->engine == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(dev->osdev,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "port %d: audio_engine_alloc failed", i);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_engine_set_private(port->engine, port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_add_engine(dev->osdev, port->engine);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audio_dev_register(dev->osdev) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(dev->osdev,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "unable to register with audio framework");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorevoid
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_destroy(audioens_dev_t *dev)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int i;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#ifdef __x86
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore if (dev->useintr && dev->intrh != NULL) {
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore (void) ddi_intr_disable(dev->intrh);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore (void) ddi_intr_remove_handler(dev->intrh);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore (void) ddi_intr_free(dev->intrh);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore dev->intrh = NULL;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore }
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#endif
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_destroy(&dev->mutex);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* free up ports, including DMA resources for ports */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i <= PORT_MAX; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_port_t *port = &dev->port[i];
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->paddr != 0)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) ddi_dma_unbind_handle(port->dmah);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->acch != NULL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_dma_mem_free(&port->acch);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->dmah != NULL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_dma_free_handle(&port->dmah);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->engine != NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_remove_engine(dev->osdev, port->engine);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_engine_free(port->engine);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (dev->acch != NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_regs_map_free(&dev->acch);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (dev->ac97) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_free(dev->ac97);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (dev->osdev != NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_free(dev->osdev);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore kmem_free(dev, sizeof (*dev));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_attach(dev_info_t *dip)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t pci_command, vendor, device;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint8_t revision;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_dev_t *dev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_acc_handle_t pcih;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore const char *chip_name;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore const char *chip_vers;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dev = kmem_zalloc(sizeof (*dev), KM_SLEEP);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dev->dip = dip;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_set_driver_private(dip, dev);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, NULL);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(dev->osdev, "pci_config_setup failed");
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore goto err_exit;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vendor = pci_config_get16(pcih, PCI_CONF_VENID);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore device = pci_config_get16(pcih, PCI_CONF_DEVID);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore revision = pci_config_get8(pcih, PCI_CONF_REVID);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((vendor != ENSONIQ_VENDOR_ID && vendor != CREATIVE_VENDOR_ID) ||
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (device != ENSONIQ_ES1371 && device != ENSONIQ_ES5880 &&
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore device != ENSONIQ_ES5880A && device != ECTIVA_ES1938 &&
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore device != ENSONIQ_ES5880B)) {
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore audio_dev_warn(dev->osdev, "unrecognized device");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto err_exit;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore chip_name = "AudioPCI97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore chip_vers = "unknown";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (device) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case ENSONIQ_ES1371:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore chip_name = "AudioPCI97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (revision) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x02:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x09:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore default:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore chip_vers = "ES1371";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x04:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x06:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x08:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore chip_vers = "ES1373";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x07:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore chip_vers = "ES5880";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case ENSONIQ_ES5880:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore chip_name = "SB PCI128";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore chip_vers = "ES5880";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case ENSONIQ_ES5880A:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore chip_name = "SB PCI128";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore chip_vers = "ES5880A";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case ENSONIQ_ES5880B:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore chip_name = "SB PCI128";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore chip_vers = "ES5880B";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case ECTIVA_ES1938:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore chip_name = "AudioPCI";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore chip_vers = "ES1938";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dev->revision = revision;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dev->devid = device;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dev->osdev = audio_dev_alloc(dip, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (dev->osdev == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto err_exit;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_set_description(dev->osdev, chip_name);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_set_version(dev->osdev, chip_vers);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* set the PCI latency */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((audioens_latency == 32) || (audioens_latency == 64) ||
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (audioens_latency == 96))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pci_config_put8(pcih, PCI_CONF_LATENCY_TIMER,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_latency);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* activate the device */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pci_command = pci_config_get16(pcih, PCI_CONF_COMM);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pci_command |= PCI_COMM_ME | PCI_COMM_IO;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pci_config_put16(pcih, PCI_CONF_COMM, pci_command);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* map registers */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_regs_map_setup(dip, 1, &dev->regs, 0, 0, &acc_attr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &dev->acch) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(dev->osdev, "can't map registers");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto err_exit;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#ifdef __x86
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore /*
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore * Virtual platforms (mostly VMWare!) seem to need us to pulse
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore * the interrupt enables to make progress. So enable (emulated)
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore * hardware interrupts.
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore */
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore dev->useintr = B_FALSE;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore if (get_hwenv() & HW_VIRTUAL) {
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore dev->useintr = B_TRUE;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore if (audioens_setup_intr(dev) != DDI_SUCCESS) {
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore goto err_exit;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore }
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore /* Reinitialize the mutex with interrupt priority. */
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore mutex_destroy(&dev->mutex);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore mutex_init(&dev->mutex, NULL, MUTEX_DRIVER,
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore DDI_INTR_PRI(dev->intrpri));
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore }
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#endif
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* This allocates and configures the engines */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audioens_init(dev) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(dev->osdev, "can't init device");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto err_exit;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#ifdef __x86
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore if (dev->useintr) {
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore (void) ddi_intr_enable(dev->intrh);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore }
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore#endif
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pci_config_teardown(&pcih);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_report_dev(dip);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreerr_exit:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pci_config_teardown(&pcih);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_destroy(dev);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_detach(audioens_dev_t *dev)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int tmp;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* first unregister us from the DDI framework, might be busy */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audio_dev_unregister(dev->osdev) != DDI_SUCCESS)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&dev->mutex);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp = GET8(dev, CONC_bSERCTL_OFF) &
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ~(CONC_SERCTL_DAC2IE | CONC_SERCTL_DAC1IE | CONC_SERCTL_ADCIE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bSERCTL_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bSERCTL_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bSERCTL_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bSERCTL_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp = GET8(dev, CONC_bDEVCTL_OFF) &
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ~(CONC_DEVCTL_DAC2_EN | CONC_DEVCTL_ADC_EN | CONC_DEVCTL_DAC1_EN);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bDEVCTL_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bDEVCTL_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bDEVCTL_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bDEVCTL_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&dev->mutex);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_destroy(dev);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_resume(audioens_dev_t *dev)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore mutex_enter(&dev->mutex);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore dev->suspended = B_FALSE;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore mutex_exit(&dev->mutex);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* reinitialize hardware */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_init_hw(dev);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* restore AC97 state */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ac97_reset(dev->ac97);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audio_dev_resume(dev->osdev);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_suspend(audioens_dev_t *dev)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audio_dev_suspend(dev->osdev);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore mutex_enter(&dev->mutex);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore CLR8(dev, CONC_bDEVCTL_OFF,
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore CONC_DEVCTL_DAC2_EN | CONC_DEVCTL_DAC1_EN | CONC_DEVCTL_ADC_EN);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore dev->suspended = B_TRUE;
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore mutex_exit(&dev->mutex);
5b1627536384deb03449347af9c01bd4fc2d271eGarrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_quiesce(dev_info_t *dip)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_dev_t *dev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint8_t tmp;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((dev = ddi_get_driver_private(dip)) == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* This disables all DMA engines and interrupts */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp = GET8(dev, CONC_bSERCTL_OFF) &
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ~(CONC_SERCTL_DAC2IE | CONC_SERCTL_DAC1IE | CONC_SERCTL_ADCIE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bSERCTL_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bSERCTL_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bSERCTL_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bSERCTL_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp = GET8(dev, CONC_bDEVCTL_OFF) &
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ~(CONC_DEVCTL_DAC2_EN | CONC_DEVCTL_ADC_EN | CONC_DEVCTL_DAC1_EN);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bDEVCTL_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bDEVCTL_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bDEVCTL_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT8(dev, CONC_bDEVCTL_OFF, tmp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_dev_t *dev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (cmd) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case DDI_ATTACH:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (audioens_attach(dip));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case DDI_RESUME:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((dev = ddi_get_driver_private(dip)) == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (audioens_resume(dev));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore default:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioens_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_dev_t *dev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((dev = ddi_get_driver_private(dip)) == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (cmd) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case DDI_DETACH:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (audioens_detach(dev));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case DDI_SUSPEND:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (audioens_suspend(dev));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore default:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioens_ddi_attach(dev_info_t *, ddi_attach_cmd_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioens_ddi_detach(dev_info_t *, ddi_detach_cmd_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic struct dev_ops audioens_dev_ops = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DEVO_REV, /* rev */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0, /* refcnt */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL, /* getinfo */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore nulldev, /* identify */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore nulldev, /* probe */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_ddi_attach, /* attach */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_ddi_detach, /* detach */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore nodev, /* reset */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL, /* cb_ops */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL, /* bus_ops */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL, /* power */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioens_quiesce, /* quiesce */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic struct modldrv audioens_modldrv = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &mod_driverops, /* drv_modops */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "Ensoniq 1371/1373 Audio", /* linkinfo */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &audioens_dev_ops, /* dev_ops */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic struct modlinkage modlinkage = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore MODREV_1,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore { &audioens_modldrv, NULL }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore_init(void)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int rv;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_init_ops(&audioens_dev_ops, DRVNAME);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((rv = mod_install(&modlinkage)) != 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_fini_ops(&audioens_dev_ops);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (rv);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore_fini(void)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int rv;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((rv = mod_remove(&modlinkage)) == 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_fini_ops(&audioens_dev_ops);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (rv);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore_info(struct modinfo *modinfop)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (mod_info(&modlinkage, modinfop));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}