audioixp.c revision 48f21d36693650e32c51fc8474dca1acc9b7376c
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER START
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The contents of this file are subject to the terms of the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Common Development and Distribution License (the "License").
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * You may not use this file except in compliance with the License.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * or http://www.opensolaris.org/os/licensing.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * See the License for the specific language governing permissions
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * and limitations under the License.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER END
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Use is subject to license terms.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp Audio Driver
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This driver supports audio hardware integrated in ATI IXP400 chipset.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The IXP400 audio core is an AC'97 controller, which has independent
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * channels for PCM in, PCM out. The AC'97 controller is a PCI bus master
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * with scatter/gather support. Each channel has a DMA engine. Currently,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * we use only the PCM in and PCM out channels. Each DMA engine uses one
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * buffer descriptor list. Each entry contains a pointer to a data buffer,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * status, length of the buffer being pointed to and the pointer to the next
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * entry. Length of the buffer is in number of bytes. Interrupt will be
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * triggered each time a entry is processed by hardware.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * System power management is not yet supported by the driver.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This driver depends on the misc/ac97 and drv/audio modules being
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * loaded first.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/types.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/modctl.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/kmem.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/conf.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/ddi.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/sunddi.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/pci.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/note.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/audio/audio_driver.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/audio/ac97.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include "audioixp.h"
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Module linkage routines for the kernel
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioixp_ddi_attach(dev_info_t *, ddi_attach_cmd_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioixp_ddi_detach(dev_info_t *, ddi_detach_cmd_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioixp_quiesce(dev_info_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioixp_resume(dev_info_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioixp_suspend(dev_info_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Entry point routine prototypes
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioixp_open(void *, int, unsigned *, unsigned *, caddr_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audioixp_close(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioixp_start(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audioixp_stop(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioixp_format(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioixp_channels(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioixp_rate(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic uint64_t audioixp_count(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audioixp_sync(void *, unsigned);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic size_t audioixp_qlen(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic audio_engine_ops_t audioixp_engine_ops = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AUDIO_ENGINE_VERSION,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_open,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_close,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_start,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_stop,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_count,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_format,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_channels,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_rate,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_sync,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_qlen
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * interrupt handler
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic uint_t audioixp_intr(caddr_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Local Routine Prototypes
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioixp_attach(dev_info_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioixp_detach(dev_info_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioixp_alloc_port(audioixp_state_t *, int);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audioixp_start_port(audioixp_port_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audioixp_stop_port(audioixp_port_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audioixp_reset_port(audioixp_port_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audioixp_update_port(audioixp_port_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioixp_codec_sync(audioixp_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audioixp_wr97(void *, uint8_t, uint16_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic uint16_t audioixp_rd97(void *, uint8_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioixp_reset_ac97(audioixp_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioixp_map_regs(audioixp_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audioixp_unmap_regs(audioixp_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioixp_chip_init(audioixp_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audioixp_destroy(audioixp_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Global variables, but used only by this file.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI Structures
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* Device operations structure */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic struct dev_ops audioixp_dev_ops = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DEVO_REV, /* devo_rev */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0, /* devo_refcnt */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL, /* devo_getinfo */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore nulldev, /* devo_identify - obsolete */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore nulldev, /* devo_probe */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_ddi_attach, /* devo_attach */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_ddi_detach, /* devo_detach */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore nodev, /* devo_reset */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL, /* devi_cb_ops */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL, /* devo_bus_ops */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL, /* devo_power */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_quiesce, /* devo_quiesce */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* Linkage structure for loadable drivers */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic struct modldrv audioixp_modldrv = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &mod_driverops, /* drv_modops */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_MOD_NAME, /* drv_linkinfo */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &audioixp_dev_ops, /* drv_dev_ops */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* Module linkage structure */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic struct modlinkage audioixp_modlinkage = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore MODREV_1, /* ml_rev */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void *)&audioixp_modldrv, /* ml_linkage */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL /* NULL terminates the list */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * device access attributes for register mapping
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic struct ddi_device_acc_attr dev_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'Amorestatic struct ddi_device_acc_attr 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'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DMA attributes of buffer descriptor list
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic ddi_dma_attr_t bdlist_dma_attr = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DMA_ATTR_V0, /* version */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0, /* addr_lo */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0xffffffff, /* addr_hi */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0000ffff, /* count_max */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 8, /* align, BDL must be aligned on a 8-byte boundary */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x3c, /* burstsize */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 8, /* minxfer, set to the size of a BDlist entry */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0000ffff, /* maxxfer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x00000fff, /* seg, set to the RAM pagesize of intel platform */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 1, /* sgllen, there's no scatter-gather list */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 8, /* granular, set to the value of minxfer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0 /* flags, use virtual address */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DMA attributes of buffers to be used to receive/send audio data
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic ddi_dma_attr_t sample_buf_dma_attr = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DMA_ATTR_V0,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0, /* addr_lo */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0xffffffff, /* addr_hi */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0001fffe, /* count_max */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 4, /* align, data buffer is aligned on a 2-byte boundary */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x3c, /* burstsize */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 4, /* minxfer, set to the size of a sample data */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0001ffff, /* maxxfer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0001ffff, /* seg */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 1, /* sgllen, no scatter-gather */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 4, /* granular, set to the value of minxfer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0, /* flags, use virtual address */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * _init()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Driver initialization, called when driver is first loaded.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is how access is initially given to all the static structures.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * None
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ddi_soft_state_init() status, see ddi_soft_state_init(9f), or
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * mod_install() status, see mod_install(9f)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore_init(void)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_init_ops(&audioixp_dev_ops, IXP_NAME);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((error = mod_install(&audioixp_modlinkage)) != 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_fini_ops(&audioixp_dev_ops);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (error);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * _fini()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Module de-initialization, called when the driver is to be unloaded.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * None
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * mod_remove() status, see mod_remove(9f)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore_fini(void)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((error = mod_remove(&audioixp_modlinkage)) != 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (error);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_fini_ops(&audioixp_dev_ops);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * _info()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Module information, returns information about the driver.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * modinfo *modinfop Pointer to the opaque modinfo structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * mod_info() status, see mod_info(9f)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore_info(struct modinfo *modinfop)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (mod_info(&audioixp_modlinkage, modinfop));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* ******************* Driver Entry Points ********************************* */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_ddi_attach()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Attach an instance of the audioixp driver.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ddi_attach_cmd_t cmd Attach command
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS The driver was initialized properly
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The driver couldn't be initialized properly
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (cmd) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case DDI_ATTACH:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (audioixp_attach(dip));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * now, no suspend/resume supported. we'll do it in the future.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case DDI_RESUME:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (audioixp_resume(dip));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore default:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_ddi_detach()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Detach an instance of the audioixp driver.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ddi_detach_cmd_t cmd Detach command
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS The driver was detached
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The driver couldn't be detached
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (cmd) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case DDI_DETACH:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (audioixp_detach(dip));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * now, no suspend/resume supported. we'll do it in the future.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case DDI_SUSPEND:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (audioixp_suspend(dip));
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 void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_stop_dma(audioixp_state_t *statep)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT_DMA);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN_DMA);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_disable_intr(audioixp_state_t *statep)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_INT, GET32(IXP_AUDIO_INT));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_INT_EN, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * quiesce(9E) entry point.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This function is called when the system is single-threaded at high
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * PIL with preemption disabled. Therefore, this function must not be blocked.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE indicates an error condition and should almost never happen.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_quiesce(dev_info_t *dip)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_state_t *statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep = ddi_get_driver_private(dip);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(statep != NULL);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* disable HW interrupt */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_disable_intr(statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* stop DMA engines */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_stop_dma(statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_suspend(dev_info_t *dip)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_state_t *statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep = ddi_get_driver_private(dip);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(statep != NULL);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_suspend(statep->ac97);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep->suspended = B_TRUE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_disable_intr(statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_stop_dma(statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_resume_port(audioixp_port_t *port)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port != NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->engine != NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_engine_reset(port->engine);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_reset_port(port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->started) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_start_port(port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_stop_port(port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_resume(dev_info_t *dip)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_state_t *statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_t *adev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_port_t *rec_port, *play_port;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep = ddi_get_driver_private(dip);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore adev = statep->adev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(statep != NULL);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audioixp_chip_init(statep) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "DDI_RESUME failed to init chip");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_resume(statep->ac97);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep->suspended = B_FALSE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rec_port = statep->rec_port;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore play_port = statep->play_port;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_resume_port(rec_port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_resume_port(play_port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_intr()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Interrupt service routine for both play and record. For play we
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * get the next buffers worth of audio. For record we send it on to
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the mixer.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * There's a hardware pointer which indicate memory location where
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the hardware is processing. We check this pointer to decide whether
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * to handle the buffer and how many buffers should be handled.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Refer to ATI IXP400/450 Register Reference Manual, page 193,194.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * caddr_t arg Pointer to the interrupting device's state
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_INTR_CLAIMED Interrupt claimed and processed
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_INTR_UNCLAIMED Interrupt not claimed, and thus ignored
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic uint_t
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_intr(caddr_t arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_state_t *statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t sr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int claimed = DDI_INTR_UNCLAIMED;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep = (void *)arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore sr = GET32(IXP_AUDIO_INT);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* PCM in interrupt */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (sr & IXP_AUDIO_INT_IN_DMA) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore claimed = DDI_INTR_CLAIMED;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_INT, IXP_AUDIO_INT_IN_DMA);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* PCM out interrupt */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (sr & IXP_AUDIO_INT_OUT_DMA) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore claimed = DDI_INTR_CLAIMED;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_INT, IXP_AUDIO_INT_OUT_DMA);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* system is too busy to process the input stream, ignore it */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (sr & IXP_AUDIO_INT_IN_DMA_OVERFLOW) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore claimed = DDI_INTR_CLAIMED;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_INT, IXP_AUDIO_INT_IN_DMA_OVERFLOW);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* System is too busy, ignore it */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (sr & IXP_AUDIO_INT_OUT_DMA_UNDERFLOW) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore claimed = DDI_INTR_CLAIMED;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_INT, IXP_AUDIO_INT_OUT_DMA_UNDERFLOW);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* update the kernel interrupt statistics */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((claimed == DDI_INTR_CLAIMED) && statep->ksp) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_KIOP(statep)->intrs[KSTAT_INTR_HARD]++;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (sr & IXP_AUDIO_INT_IN_DMA) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_engine_produce(statep->rec_port->engine);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (sr & IXP_AUDIO_INT_OUT_DMA) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_engine_consume(statep->play_port->engine);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (claimed);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_open()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Opens a DMA engine for use.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to set up
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * int flag Open flags
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * unsigned *fragfrp Receives number of frames per fragment
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * unsigned *nfragsp Receives number of fragments
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * caddr_t *bufp Receives kernel data buffer
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0 on success
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * errno on failure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_open(void *arg, int flag,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore unsigned *fragfrp, unsigned *nfragsp, caddr_t *bufp)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore _NOTE(ARGUNUSED(flag));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->started = B_FALSE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->count = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->offset = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *fragfrp = port->fragfr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *nfragsp = IXP_BD_NUMS;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *bufp = port->samp_kaddr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&port->statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_reset_port(port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&port->statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_close()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Closes an audio DMA engine that was previously opened. Since
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * nobody is using it, we take this opportunity to possibly power
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * down the entire device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to shut down
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_close(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_state_t *statep = port->statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_stop_port(port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->started = B_FALSE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_stop()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to stop a port that is
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * transferring data.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to stop
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_stop(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_state_t *statep = port->statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->started) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_stop_port(port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->started = B_FALSE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_start()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to start a port transferring data.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to start
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0 on success (never fails, errno if it did)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_start(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_state_t *statep = port->statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!port->started) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_start_port(port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->started = B_TRUE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_format()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to query the format for the device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to query
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * AUDIO_FORMAT_S16_LE
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_format(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore _NOTE(ARGUNUSED(arg));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (AUDIO_FORMAT_S16_LE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_channels()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to query the channels for the device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to query
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Number of channels for the device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_channels(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (port->nchan);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_rate()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to query the rate of the device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to query
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 48000
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_rate(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore _NOTE(ARGUNUSED(arg));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (48000);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_count()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to get the engine's frame counter
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to query
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * frame count for current engine
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic uint64_t
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_count(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_state_t *statep = port->statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint64_t val;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_update_port(port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore val = port->count;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (val);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_sync()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to synchronize DMA caches.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to sync
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_sync(void *arg, unsigned nframes)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore _NOTE(ARGUNUSED(nframes));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) ddi_dma_sync(port->samp_dmah, 0, 0, port->sync_dir);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_qlen()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to determine on-device queue length.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to query
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * hardware queue length not reported by count (0 for this device)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic size_t
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_qlen(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore _NOTE(ARGUNUSED(arg));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* *********************** Local Routines *************************** */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_alloc_port()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine allocates the DMA handles and the memory for the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DMA engines to use. It also configures the BDL lists properly
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * for use.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dev_info_t *dip Pointer to the device's devinfo
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS Registers successfully mapped
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE Registers not successfully mapped
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_alloc_port(audioixp_state_t *statep, int num)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_dma_cookie_t cookie;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint_t count;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int dir;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore unsigned caps;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore char *prop;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_t *adev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_port_t *port;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t paddr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int rc;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dev_info_t *dip;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_bd_entry_t *bdentry;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore adev = statep->adev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dip = statep->dip;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port = kmem_zalloc(sizeof (*port), KM_SLEEP);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->statep = statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->started = B_FALSE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->num = num;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (num) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case IXP_REC:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep->rec_port = port;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore prop = "record-interrupts";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dir = DDI_DMA_READ;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore caps = ENGINE_INPUT_CAP;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->sync_dir = DDI_DMA_SYNC_FORKERNEL;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->nchan = 2;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case IXP_PLAY:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep->play_port = port;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore prop = "play-interrupts";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dir = DDI_DMA_WRITE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore caps = ENGINE_OUTPUT_CAP;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->sync_dir = DDI_DMA_SYNC_FORDEV;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* This could possibly be conditionalized */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->nchan = 6;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore default:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "bad port number (%d)!", num);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->intrs = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_PROP_DONTPASS, prop, IXP_INTS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* make sure the values are good */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->intrs < IXP_MIN_INTS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "%s too low, %d, resetting to %d",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore prop, port->intrs, IXP_INTS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->intrs = IXP_INTS;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else if (port->intrs > IXP_MAX_INTS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "%s too high, %d, resetting to %d",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore prop, port->intrs, IXP_INTS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->intrs = IXP_INTS;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Figure out how much space we need. Sample rate is 48kHz, and
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * we need to store 8 chunks. (Note that this means that low
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * interrupt frequencies will require more RAM.)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->fragfr = 48000 / port->intrs;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->fragfr = IXP_ROUNDUP(port->fragfr, IXP_MOD_SIZE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->fragsz = port->fragfr * port->nchan * 2;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->samp_size = port->fragsz * IXP_BD_NUMS;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* allocate dma handle */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rc = ddi_dma_alloc_handle(dip, &sample_buf_dma_attr, DDI_DMA_SLEEP,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL, &port->samp_dmah);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (rc != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "ddi_dma_alloc_handle failed: %d", rc);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* allocate DMA buffer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rc = ddi_dma_mem_alloc(port->samp_dmah, port->samp_size, &buf_attr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &port->samp_kaddr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &port->samp_size, &port->samp_acch);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (rc == DDI_FAILURE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "dma_mem_alloc failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* bind DMA buffer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rc = ddi_dma_addr_bind_handle(port->samp_dmah, NULL,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->samp_kaddr, port->samp_size, dir|DDI_DMA_CONSISTENT,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_DMA_SLEEP, NULL, &cookie, &count);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((rc != DDI_DMA_MAPPED) || (count != 1)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "ddi_dma_addr_bind_handle failed: %d", rc);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->samp_paddr = cookie.dmac_address;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * now, from here we allocate DMA memory for buffer descriptor list.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * we allocate adjacent DMA memory for all DMA engines.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rc = ddi_dma_alloc_handle(dip, &bdlist_dma_attr, DDI_DMA_SLEEP,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL, &port->bdl_dmah);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (rc != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "ddi_dma_alloc_handle(bdlist) failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * we allocate all buffer descriptors lists in continuous dma memory.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->bdl_size = sizeof (audioixp_bd_entry_t) * IXP_BD_NUMS;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rc = ddi_dma_mem_alloc(port->bdl_dmah, port->bdl_size,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &port->bdl_kaddr, &port->bdl_size, &port->bdl_acch);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (rc != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "ddi_dma_mem_alloc(bdlist) failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rc = ddi_dma_addr_bind_handle(port->bdl_dmah, NULL, port->bdl_kaddr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->bdl_size, DDI_DMA_WRITE|DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL, &cookie, &count);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((rc != DDI_DMA_MAPPED) || (count != 1)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "addr_bind_handle failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->bdl_paddr = cookie.dmac_address;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Wire up the BD list.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore paddr = port->samp_paddr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore bdentry = (void *)port->bdl_kaddr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; i < IXP_BD_NUMS; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* set base address of buffer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(port->bdl_acch, &bdentry->buf_base, paddr);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put16(port->bdl_acch, &bdentry->status, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put16(port->bdl_acch, &bdentry->buf_len, port->fragsz / 4);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(port->bdl_acch, &bdentry->next, port->bdl_paddr +
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (((i + 1) % IXP_BD_NUMS) * sizeof (audioixp_bd_entry_t)));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore paddr += port->fragsz;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore bdentry++;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
48f21d36693650e32c51fc8474dca1acc9b7376cGarrett D'Amore (void) ddi_dma_sync(port->bdl_dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->engine = audio_engine_alloc(&audioixp_engine_ops, caps);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->engine == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "audio_engine_alloc failed");
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(adev, port->engine);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_free_port()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine unbinds the DMA cookies, frees the DMA buffers,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * deallocates the DMA handles.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_port_t *port The port structure for a DMA engine.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_free_port(audioixp_port_t *port)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port == NULL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->engine) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_remove_engine(port->statep->adev, port->engine);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_engine_free(port->engine);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->bdl_paddr) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) ddi_dma_unbind_handle(port->bdl_dmah);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->bdl_acch) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_dma_mem_free(&port->bdl_acch);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->bdl_dmah) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_dma_free_handle(&port->bdl_dmah);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->samp_paddr) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) ddi_dma_unbind_handle(port->samp_dmah);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->samp_acch) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_dma_mem_free(&port->samp_acch);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->samp_dmah) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_dma_free_handle(&port->samp_dmah);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore kmem_free(port, sizeof (*port));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_start_port()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine starts the DMA engine.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_port_t *port Port of DMA engine to start.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_start_port(audioixp_port_t *port)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_state_t *statep = port->statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(mutex_owned(&statep->inst_lock));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* if suspended, then do nothing else */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->suspended) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->num == IXP_REC) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_stop_port()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine stops the DMA engine.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_port_t *port Port of DMA engine to stop.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_stop_port(audioixp_port_t *port)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_state_t *statep = port->statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(mutex_owned(&statep->inst_lock));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* if suspended, then do nothing else */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->suspended) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->num == IXP_REC) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_reset_port()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine resets the DMA engine pareparing it for work.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_port_t *port Port of DMA engine to reset.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_reset_port(audioixp_port_t *port)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_state_t *statep = port->statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(mutex_owned(&statep->inst_lock));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * XXX: reset counters.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->count = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->suspended)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Perform full reset of the engine, and enable its interrupts
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * but leave it turned off.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->num == IXP_REC) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_FIFO_FLUSH, IXP_AUDIO_FIFO_FLUSH_IN);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_INTER_IN);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN_DMA);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_IN_DMA_LINK_P,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->bdl_paddr | IXP_AUDIO_IN_DMA_LINK_P_EN);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t slot = GET32(IXP_AUDIO_OUT_DMA_SLOT_EN_THRESHOLD);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_FIFO_FLUSH, IXP_AUDIO_FIFO_FLUSH_OUT);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* clear all slots */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore slot &= ~ (IXP_AUDIO_OUT_DMA_SLOT_3 |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_OUT_DMA_SLOT_4 |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_OUT_DMA_SLOT_5 |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_OUT_DMA_SLOT_6 |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_OUT_DMA_SLOT_7 |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_OUT_DMA_SLOT_8 |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_OUT_DMA_SLOT_9 |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_OUT_DMA_SLOT_10 |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_OUT_DMA_SLOT_11 |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_OUT_DMA_SLOT_12);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* enable 6 channel out, unconditional for now */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore slot |= IXP_AUDIO_OUT_DMA_SLOT_3 |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_OUT_DMA_SLOT_4 |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_OUT_DMA_SLOT_6 |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_OUT_DMA_SLOT_9 |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_OUT_DMA_SLOT_7 |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_OUT_DMA_SLOT_8;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_OUT_DMA_SLOT_EN_THRESHOLD, slot);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_INTER_OUT);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT_DMA);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_OUT_DMA_LINK_P,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->bdl_paddr | IXP_AUDIO_OUT_DMA_LINK_P_EN);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_update_port()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine updates the ports frame counter from hardware, and
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * gracefully handles wraps.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_port_t *port The port to update.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_update_port(audioixp_port_t *port)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_state_t *statep = port->statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore unsigned regoff;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore unsigned n;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int loop;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t offset;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t paddr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->suspended) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->num == IXP_REC) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore regoff = IXP_AUDIO_IN_DMA_DT_CUR;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore regoff = IXP_AUDIO_OUT_DMA_DT_CUR;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Apparently it may take several tries to get an update on the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * position. Is this a hardware bug?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (loop = 100; loop; loop--) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore paddr = GET32(regoff);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* make sure address is reasonable */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((paddr < port->samp_paddr) ||
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (paddr >= (port->samp_paddr + port->samp_size))) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore continue;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore offset = paddr - port->samp_paddr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (offset >= port->offset) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore n = offset - port->offset;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore n = offset + (port->samp_size - port->offset);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->offset = offset;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->count += (n / (port->nchan * sizeof (uint16_t)));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "Unable to update count (h/w bug?)");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_map_regs()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The registers are mapped in.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS Registers successfully mapped
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE Registers not successfully mapped
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_map_regs(audioixp_state_t *statep)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dev_info_t *dip = statep->dip;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* map PCI config space */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (pci_config_setup(statep->dip, &statep->pcih) == DDI_FAILURE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "unable to map PCI config space");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* map audio mixer register */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((ddi_regs_map_setup(dip, IXP_IO_AM_REGS, &statep->regsp, 0, 0,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &dev_attr, &statep->regsh)) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "unable to map audio registers");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_unmap_regs()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine unmaps control registers.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_unmap_regs(audioixp_state_t *statep)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->regsh) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_regs_map_free(&statep->regsh);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->pcih) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pci_config_teardown(&statep->pcih);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_codec_ready()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine checks the state of codecs. It checks the flag to confirm
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * that primary codec is ready.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS codec is ready
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE codec is not ready
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_codec_ready(audioixp_state_t *statep)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t sr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_INT, 0xffffffff);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(1000);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore sr = GET32(IXP_AUDIO_INT);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (sr & IXP_AUDIO_INT_CODEC0_NOT_READY) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_INT, IXP_AUDIO_INT_CODEC0_NOT_READY);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "primary codec not ready");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_codec_sync()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Serialize access to the AC97 audio mixer registers.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS Ready for an I/O access to the codec
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE An I/O access is currently in progress, can't
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * perform another I/O access.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_codec_sync(audioixp_state_t *statep)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int i;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t cmd;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < 300; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmd = GET32(IXP_AUDIO_OUT_PHY_ADDR_DATA);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!(cmd & IXP_AUDIO_OUT_PHY_EN)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(10);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "unable to synchronize codec");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_rd97()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Get the specific AC97 Codec register.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * uint8_t reg AC97 register number
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Register value.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic uint16_t
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_rd97(void *arg, uint8_t reg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_state_t *statep = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t value;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t result;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audioixp_codec_sync(statep) != DDI_SUCCESS)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0xffff);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore value = IXP_AUDIO_OUT_PHY_PRIMARY_CODEC |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_OUT_PHY_READ |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_OUT_PHY_EN |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ((unsigned)reg << IXP_AUDIO_OUT_PHY_ADDR_SHIFT);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_OUT_PHY_ADDR_DATA, value);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audioixp_codec_sync(statep) != DDI_SUCCESS)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0xffff);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; i < 300; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore result = GET32(IXP_AUDIO_IN_PHY_ADDR_DATA);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (result & IXP_AUDIO_IN_PHY_READY) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (result >> IXP_AUDIO_IN_PHY_DATA_SHIFT);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(10);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoredone:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "time out reading codec reg %d", reg);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0xffff);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_wr97()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Set the specific AC97 Codec register.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * uint8_t reg AC97 register number
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * uint16_t data The data want to be set
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_wr97(void *arg, uint8_t reg, uint16_t data)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_state_t *statep = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t value;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audioixp_codec_sync(statep) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore value = IXP_AUDIO_OUT_PHY_PRIMARY_CODEC |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_OUT_PHY_WRITE |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_OUT_PHY_EN |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ((unsigned)reg << IXP_AUDIO_OUT_PHY_ADDR_SHIFT) |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ((unsigned)data << IXP_AUDIO_OUT_PHY_DATA_SHIFT);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_OUT_PHY_ADDR_DATA, value);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) audioixp_rd97(statep, reg);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_reset_ac97()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Reset AC97 Codec register.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS Reset the codec successfully
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE Failed to reset the codec
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_reset_ac97(audioixp_state_t *statep)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t cmd;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int i;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_POWER_DOWN);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(10);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* register reset */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_AC_SOFT_RESET);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* force a read to flush caches */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) GET32(IXP_AUDIO_CMD);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(10);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_AC_SOFT_RESET);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* cold reset */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < 300; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmd = GET32(IXP_AUDIO_CMD);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (cmd & IXP_AUDIO_CMD_AC_ACTIVE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmd |= IXP_AUDIO_CMD_AC_RESET | IXP_AUDIO_CMD_AC_SYNC;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_CMD, cmd);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmd &= ~IXP_AUDIO_CMD_AC_RESET;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmd |= IXP_AUDIO_CMD_AC_SYNC;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_CMD, cmd);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) GET32(IXP_AUDIO_CMD);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(10);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmd |= IXP_AUDIO_CMD_AC_RESET;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_CMD, cmd);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(10);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "AC'97 reset timed out");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_chip_init()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine initializes ATI IXP audio controller and the AC97
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * codec.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS The hardware was initialized properly
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The hardware couldn't be initialized properly
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_chip_init(audioixp_state_t *statep)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * put the audio controller into quiet state, everything off
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT_DMA);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN_DMA);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* AC97 reset */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audioixp_reset_ac97(statep) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "AC97 codec reset failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audioixp_codec_ready(statep) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "AC97 codec not ready");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* enable interrupts */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_INT, 0xffffffff);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_INT_EN,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_INT_EN_IN_DMA_OVERFLOW |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_INT_EN_STATUS |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_AUDIO_INT_EN_OUT_DMA_UNDERFLOW);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore} /* audioixp_chip_init() */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_attach()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Attach an instance of the audioixp driver. This routine does
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the device dependent attach tasks.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ddi_attach_cmd_t cmd Attach command
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS The driver was initialized properly
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The driver couldn't be initialized properly
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_attach(dev_info_t *dip)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t cmdeg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_state_t *statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_t *adev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t devid;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore const char *name;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore const char *rev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* we don't support high level interrupts in the driver */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_intr_hilevel(dip, 0) != 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmn_err(CE_WARN,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "!%s%d: unsupported high level interrupt",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_driver_name(dip), ddi_get_instance(dip));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* allocate the soft state structure */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep = kmem_zalloc(sizeof (*statep), KM_SLEEP);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep->dip = dip;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_set_driver_private(dip, statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_get_iblock_cookie(dip, 0, &statep->iblock) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmn_err(CE_WARN,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "!%s%d: cannot get iblock cookie",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_driver_name(dip), ddi_get_instance(dip));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore kmem_free(statep, sizeof (*statep));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_init(&statep->inst_lock, NULL, MUTEX_DRIVER, statep->iblock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* allocate framework audio device */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((adev = audio_dev_alloc(dip, 0)) == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmn_err(CE_WARN, "!%s%d: unable to allocate audio dev",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_driver_name(dip), ddi_get_instance(dip));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep->adev = adev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* map in the registers */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audioixp_map_regs(statep) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "couldn't map registers");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* set device information -- this could be smarter */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore devid = ((pci_config_get16(statep->pcih, PCI_CONF_VENID)) << 16) |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pci_config_get16(statep->pcih, PCI_CONF_DEVID);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "ATI AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (devid) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case IXP_PCI_ID_200:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rev = "IXP150";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case IXP_PCI_ID_300:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rev = "SB300";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case IXP_PCI_ID_400:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (pci_config_get8(statep->pcih, PCI_CONF_REVID) & 0x80) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rev = "SB450";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rev = "SB400";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case IXP_PCI_ID_SB600:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rev = "SB600";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore default:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rev = "Unknown";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_set_description(adev, name);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_set_version(adev, rev);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* allocate port structures */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((audioixp_alloc_port(statep, IXP_PLAY) != DDI_SUCCESS) ||
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (audioixp_alloc_port(statep, IXP_REC) != DDI_SUCCESS)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep->ac97 = ac97_alloc(dip, audioixp_rd97, audioixp_wr97, statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->ac97 == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "failed to allocate ac97 handle");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* set PCI command register */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmdeg = pci_config_get16(statep->pcih, PCI_CONF_COMM);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pci_config_put16(statep->pcih, PCI_CONF_COMM,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmdeg | PCI_COMM_IO | PCI_COMM_MAE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* set up kernel statistics */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((statep->ksp = kstat_create(IXP_NAME, ddi_get_instance(dip),
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore IXP_NAME, "controller", KSTAT_TYPE_INTR, 1,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore KSTAT_FLAG_PERSISTENT)) != NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore kstat_install(statep->ksp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audioixp_chip_init(statep) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "failed to init chip");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* initialize the AC'97 part */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ac97_init(statep->ac97, adev) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "ac'97 initialization failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* set up the interrupt handler */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_add_intr(dip, 0, &statep->iblock, NULL, audioixp_intr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (caddr_t)statep) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "bad interrupt specification");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep->intr_added = B_TRUE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audio_dev_register(adev) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "unable to register with framework");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_report_dev(dip);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreerror:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_destroy(statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_detach()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Detach an instance of the audioixp driver.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS The driver was detached
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The driver couldn't be detached
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_detach(dev_info_t *dip)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_state_t *statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep = ddi_get_driver_private(dip);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audio_dev_unregister(statep->adev) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_destroy(statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_destroy()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine releases all resources held by the device instance,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * as part of either detach or a failure in attach.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_state_t *state The device soft state.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorevoid
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_destroy(audioixp_state_t *statep)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!statep->suspended) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_INT, GET32(IXP_AUDIO_INT));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(IXP_AUDIO_INT_EN, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * put the audio controller into quiet state, everything off
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT_DMA);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN_DMA);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->intr_added) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_remove_intr(statep->dip, 0, statep->iblock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->ksp) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore kstat_delete(statep->ksp);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_free_port(statep->play_port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_free_port(statep->rec_port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audioixp_unmap_regs(statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->ac97) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_free(statep->ac97);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->adev) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_free(statep->adev);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_destroy(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore kmem_free(statep, sizeof (*statep));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}