88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER START
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The contents of this file are subject to the terms of the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Common Development and Distribution License (the "License").
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * You may not use this file except in compliance with the License.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * or http://www.opensolaris.org/os/licensing.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * See the License for the specific language governing permissions
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * and limitations under the License.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER END
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Use is subject to license terms.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp Audio Driver
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This driver supports audio hardware integrated in ATI IXP400 chipset.
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 * System power management is not yet supported by the driver.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This driver depends on the misc/ac97 and drv/audio modules being
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * loaded first.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Module linkage routines for the kernel
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'Amore * Entry point routine prototypes
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amorestatic int audioixp_open(void *, int, 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 void audioixp_sync(void *, unsigned);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic audio_engine_ops_t audioixp_engine_ops = {
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore * We drive audioixp in stereo only, so we don't want to display controls
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore * that are used for multichannel codecs. Note that this multichannel
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore * configuration limitation is a problem for audioixp devices.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Local Routine Prototypes
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audioixp_alloc_port(audioixp_state_t *, int);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audioixp_update_port(audioixp_port_t *);
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 * Global variables, but used only by this file.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI Structures
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* Device operations structure */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0, /* devo_refcnt */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* Linkage structure for loadable drivers */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* Module linkage structure */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic struct modlinkage audioixp_modlinkage = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * device access attributes for register mapping
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic struct ddi_device_acc_attr dev_attr = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic struct ddi_device_acc_attr buf_attr = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DMA attributes of buffer descriptor list
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0, /* addr_lo */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 8, /* align, BDL must be aligned on a 8-byte boundary */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 8, /* minxfer, set to the size of a BDlist entry */
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 * DMA attributes of buffers to be used to receive/send audio data
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic ddi_dma_attr_t sample_buf_dma_attr = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0, /* addr_lo */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 4, /* align, data buffer is aligned on a 2-byte boundary */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 4, /* minxfer, set to the size of a sample data */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 4, /* granular, set to the value of minxfer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0, /* flags, use virtual address */
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 * 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 audio_init_ops(&audioixp_dev_ops, IXP_NAME);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((error = mod_install(&audioixp_modlinkage)) != 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Module de-initialization, called when the driver is to be unloaded.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * mod_remove() status, see mod_remove(9f)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((error = mod_remove(&audioixp_modlinkage)) != 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Module information, returns information about the driver.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * modinfo *modinfop Pointer to the opaque modinfo structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * mod_info() status, see mod_info(9f)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (mod_info(&audioixp_modlinkage, modinfop));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* ******************* Driver Entry Points ********************************* */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_ddi_attach()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Attach an instance of the audioixp driver.
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 * DDI_SUCCESS The driver was initialized properly
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The driver couldn't be initialized properly
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * now, no suspend/resume supported. we'll do it in the future.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_ddi_detach()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Detach an instance of the audioixp driver.
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 * DDI_SUCCESS The driver was detached
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The driver couldn't be detached
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * now, no suspend/resume supported. we'll do it in the future.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * quiesce(9E) entry point.
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 * 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 /* stop DMA engines */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT_DMA);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN_DMA);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audioixp_chip_init(statep) != DDI_SUCCESS) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audio_dev_warn(statep->adev, "DDI_RESUME failed to init chip");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_open()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Opens a DMA engine for use.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to set up
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * int flag Open flags
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * unsigned *nframesp Receives number of frames
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * caddr_t *bufp Receives kernel data buffer
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0 on success
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * errno on failure
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amoreaudioixp_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_close()
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 * void *arg The DMA engine to shut down
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_stop()
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 * void *arg The DMA engine to stop
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN_DMA);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT_DMA);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_start()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to start a port transferring data.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to start
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0 on success (never fails, errno if it did)
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore PUT32(IXP_AUDIO_FIFO_FLUSH, IXP_AUDIO_FIFO_FLUSH_IN);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_INTER_IN);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_IN_DMA);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore port->bdl_paddr | IXP_AUDIO_IN_DMA_LINK_P_EN);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore uint32_t slot = GET32(IXP_AUDIO_OUT_DMA_SLOT_EN_THRESHOLD);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore PUT32(IXP_AUDIO_FIFO_FLUSH, IXP_AUDIO_FIFO_FLUSH_OUT);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore /* clear all slots */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore /* enable AC'97 output slots (depending on output channels) */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore PUT32(IXP_AUDIO_OUT_DMA_SLOT_EN_THRESHOLD, slot);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_INTER_OUT);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore SET32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT_DMA);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore port->bdl_paddr | IXP_AUDIO_OUT_DMA_LINK_P_EN);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_format()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to query the format for the device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to query
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * AUDIO_FORMAT_S16_LE
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_channels()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to query the channels for the device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to query
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Number of channels for the device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_rate()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to query the rate of the device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to query
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (48000);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_count()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to get the engine's frame counter
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to query
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * frame count for current engine
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_sync()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to synchronize DMA caches.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to sync
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) ddi_dma_sync(port->samp_dmah, 0, 0, port->sync_dir);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* *********************** Local Routines *************************** */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_alloc_port()
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 * dev_info_t *dip Pointer to the device's devinfo
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS Registers successfully mapped
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE Registers not successfully mapped
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_alloc_port(audioixp_state_t *statep, int num)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port = kmem_zalloc(sizeof (*port), KM_SLEEP);
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore * We allow for end users to configure more channels
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore * than just two, but we default to just two. The
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore * default stereo configuration works well. On the
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore * configurations we have tested, we've found that
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore * more than two channels (or rather 6 channels) can
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore * cause inexplicable noise. The noise is more
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore * noticeable when the system is running under load.
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore * (Holding the space bar in "top" while playing an
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore * MP3 is an easy way to recreate it.) End users who
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore * want to experiment, or have configurations that
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore * don't suffer from this, may increase the channels
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore * by setting this max-channels property. We leave it
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore * undocumented for now.
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore port->nchan = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore port->nchan = min(ac97_num_channels(statep->ac97),
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore port->nchan &= ~1; /* make sure its an even number */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "bad port number (%d)!", num);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->fragsz = port->fragfr * port->nchan * 2;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore port->samp_size = port->nframes * port->nchan * 2;
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 audio_dev_warn(adev, "ddi_dma_alloc_handle failed: %d", rc);
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 audio_dev_warn(adev, "dma_mem_alloc failed");
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 if ((rc != DDI_DMA_MAPPED) || (count != 1)) {
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 rc = ddi_dma_alloc_handle(dip, &bdlist_dma_attr, DDI_DMA_SLEEP,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "ddi_dma_alloc_handle(bdlist) failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * we allocate all buffer descriptors lists in continuous dma memory.
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 audio_dev_warn(adev, "ddi_dma_mem_alloc(bdlist) failed");
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 if ((rc != DDI_DMA_MAPPED) || (count != 1)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "addr_bind_handle failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Wire up the BD list.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; i < IXP_BD_NUMS; i++) {
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)));
48f21d36693650e32c51fc8474dca1acc9b7376cGarrett D'Amore (void) ddi_dma_sync(port->bdl_dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->engine = audio_engine_alloc(&audioixp_engine_ops, caps);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "audio_engine_alloc failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_engine_set_private(port->engine, port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_free_port()
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 * audioixp_port_t *port The port structure for a DMA engine.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_remove_engine(port->statep->adev, port->engine);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) ddi_dma_unbind_handle(port->bdl_dmah);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) ddi_dma_unbind_handle(port->samp_dmah);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_update_port()
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 * audioixp_port_t *port The port to update.
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 /* make sure address is reasonable */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (paddr >= (port->samp_paddr + port->samp_size))) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore n = offset + (port->samp_size - port->offset);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->count += (n / (port->nchan * sizeof (uint16_t)));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "Unable to update count (h/w bug?)");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_map_regs()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The registers are mapped in.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS Registers successfully mapped
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE Registers not successfully mapped
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 /* 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 * audioixp_unmap_regs()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine unmaps control registers.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_unmap_regs(audioixp_state_t *statep)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_codec_ready()
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 * audioixp_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS codec is ready
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE codec is not ready
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_codec_ready(audioixp_state_t *statep)
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 * audioixp_codec_sync()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Serialize access to the AC97 audio mixer registers.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_state_t *state The device's state structure
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'Amoreaudioixp_codec_sync(audioixp_state_t *statep)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < 300; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "unable to synchronize codec");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_rd97()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Get the specific AC97 Codec register.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * uint8_t reg AC97 register number
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Register value.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audioixp_codec_sync(statep) != DDI_SUCCESS)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0xffff);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ((unsigned)reg << IXP_AUDIO_OUT_PHY_ADDR_SHIFT);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audioixp_codec_sync(statep) != DDI_SUCCESS)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0xffff);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; i < 300; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (result >> IXP_AUDIO_IN_PHY_DATA_SHIFT);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "time out reading codec reg %d", reg);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0xffff);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_wr97()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Set the specific AC97 Codec register.
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'Amoreaudioixp_wr97(void *arg, uint8_t reg, uint16_t data)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audioixp_codec_sync(statep) != DDI_SUCCESS) {
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 * audioixp_reset_ac97()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Reset AC97 Codec register.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS Reset the codec successfully
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE Failed to reset the codec
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudioixp_reset_ac97(audioixp_state_t *statep)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_POWER_DOWN);
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 CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_AC_SOFT_RESET);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* cold reset */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < 300; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmd |= IXP_AUDIO_CMD_AC_RESET | IXP_AUDIO_CMD_AC_SYNC;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "AC'97 reset timed out");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_chip_init()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine initializes ATI IXP audio controller and the AC97
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_state_t *state The device's state structure
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 * put the audio controller into quiet state, everything off
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 /* 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 if (audioixp_codec_ready(statep) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "AC97 codec not ready");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore} /* audioixp_chip_init() */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_attach()
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 * 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 * DDI_SUCCESS The driver was initialized properly
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The driver couldn't be initialized properly
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* allocate the soft state structure */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep = kmem_zalloc(sizeof (*statep), KM_SLEEP);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_init(&statep->inst_lock, NULL, MUTEX_DRIVER, NULL);
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 /* 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 /* 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 if (pci_config_get8(statep->pcih, PCI_CONF_REVID) & 0x80) {
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore /* set PCI command register */
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore cmdeg = pci_config_get16(statep->pcih, PCI_CONF_COMM);
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore pci_config_put16(statep->pcih, PCI_CONF_COMM,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep->ac97 = ac97_alloc(dip, audioixp_rd97, audioixp_wr97, statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "failed to allocate ac97 handle");
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore /* allocate port structures */
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore if ((audioixp_alloc_port(statep, IXP_PLAY) != DDI_SUCCESS) ||
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore (audioixp_alloc_port(statep, IXP_REC) != DDI_SUCCESS)) {
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore * If we have locked in a stereo configuration, then don't expose
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore * multichannel-specific AC'97 codec controls.
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore for (i = 0; (name = audioixp_remove_ac97[i]) != NULL; i++) {
d8a7fe16f62711cdc5c4267da8b34ff24a6b668cGarrett D'Amore ctrl = ac97_control_find(statep->ac97, name);
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 /* 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 if (audio_dev_register(adev) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "unable to register with framework");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_detach()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Detach an instance of the audioixp driver.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS The driver was detached
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The driver couldn't be detached
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audio_dev_unregister(statep->adev) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audioixp_destroy()
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 * audioixp_state_t *state The device soft state.
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * put the audio controller into quiet state, everything off
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore CLR32(IXP_AUDIO_CMD, IXP_AUDIO_CMD_EN_OUT_DMA);