audio810.c revision 0e7a77f3bec009d2e19415527920cc1c105cd24f
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/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810 Audio Driver
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The driver is primarily targeted at providing audio support for the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * W1100z and W2100z systems, which use the AMD 8111 audio core and
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the Realtek ALC 655 codec. The ALC 655 chip supports only fixed 48k
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * sample rate. However, the audio core of AMD 8111 is completely
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * compatible to the Intel ICHx chips (Intel 8x0 chipsets), so the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * driver can work for the ICHx. We only support the 48k maximum
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * rate, since we only have a single PCM out channel.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The AMD 8111 audio core, as an AC'97 controller, has independent
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * channels for PCM in, PCM out, mic in, modem in, and modem out.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The AC'97 controller is a PCI bus master with scatter/gather
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * support. Each channel has a DMA engine. Currently, we use only
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the PCM in and PCM out channels. Each DMA engine uses one buffer
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * descriptor list. And the buffer descriptor list is an array of up
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * to 32 entries, each of which describes a data buffer. Each entry
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * contains a pointer to a data buffer, control bits, and the length
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * of the buffer being pointed to, where the length is expressed as
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the number of samples. This, combined with the 16-bit sample size,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * gives the actual physical length of the buffer.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * A workaround for the AD1980 and AD1985 codec:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Most vendors connect the surr-out of the codecs to the line-out jack.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * So far we haven't found which vendors don't do that. So we assume that
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * all vendors swap the surr-out and the line-out outputs. So we need swap
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the two outputs. But we still internally process the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * "ad198x-swap-output" property. If someday some vendors do not swap the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * outputs, we would set "ad198x-swap-output = 0" in the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * /kernel/drv/audio810.conf file, and unload and reload the audio810
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * driver (or reboot).
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This driver depends on the drv/audio and misc/ac97
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * modules being 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 "audio810.h"
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Module linkage routines for the kernel
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audio810_ddi_attach(dev_info_t *, ddi_attach_cmd_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audio810_ddi_detach(dev_info_t *, ddi_detach_cmd_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audio810_ddi_quiesce(dev_info_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Entry point routine prototypes
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audio810_open(void *, int, unsigned *, unsigned *, caddr_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audio810_close(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audio810_start(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audio810_stop(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audio810_format(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audio810_channels(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audio810_rate(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic uint64_t audio810_count(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audio810_sync(void *, unsigned);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic size_t audio810_qlen(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic audio_engine_ops_t audio810_engine_ops = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AUDIO_ENGINE_VERSION,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_open,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_close,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_start,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_stop,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_count,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_format,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_channels,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_rate,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_sync,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_qlen
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * interrupt handler
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic uint_t audio810_intr(caddr_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Local Routine Prototypes
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audio810_attach(dev_info_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audio810_resume(dev_info_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audio810_detach(dev_info_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audio810_suspend(dev_info_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audio810_alloc_port(audio810_state_t *, int, uint8_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audio810_start_port(audio810_port_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audio810_stop_port(audio810_port_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audio810_reset_port(audio810_port_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audio810_update_port(audio810_port_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audio810_codec_sync(audio810_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audio810_write_ac97(void *, uint8_t, uint16_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic uint16_t audio810_read_ac97(void *, uint8_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audio810_map_regs(dev_info_t *, audio810_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audio810_unmap_regs(audio810_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audio810_stop_dma(audio810_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audio810_chip_init(audio810_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audio810_destroy(audio810_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/* driver name, so we don't have to call ddi_driver_name() or hard code strs */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic char *audio810_name = I810_NAME;
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 audio810_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 audio810_ddi_attach, /* devo_attach */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_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 audio810_ddi_quiesce, /* devo_quiesce */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* Linkage structure for loadable drivers */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic struct modldrv audio810_modldrv = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &mod_driverops, /* drv_modops */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_MOD_NAME, /* drv_linkinfo */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &audio810_dev_ops, /* drv_dev_ops */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* Module linkage structure */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic struct modlinkage audio810_modlinkage = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore MODREV_1, /* ml_rev */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void *)&audio810_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'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic struct ddi_device_acc_attr buf_attr = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_DEVICE_ATTR_V0,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_STRUCTURE_LE_ACC,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_STRICTORDER_ACC
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'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 0x0001ffff, /* count_max */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 4, /* align, data buffer is aligned on a 4-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 * 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(&audio810_dev_ops, I810_NAME);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((error = mod_install(&audio810_modlinkage)) != 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_fini_ops(&audio810_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(&audio810_modlinkage)) != 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (error);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* clean up ops */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_fini_ops(&audio810_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(&audio810_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 * audio810_ddi_attach()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Implements the DDI attach(9e) entry point.
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'Amoreaudio810_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 (audio810_attach(dip));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case DDI_RESUME:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (audio810_resume(dip));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_ddi_detach()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Implements the detach(9e) entry point.
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'Amoreaudio810_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 (audio810_detach(dip));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case DDI_SUSPEND:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (audio810_suspend(dip));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_ddi_quiesce()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Implements the quiesce(9e) entry point.
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 quiesced
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The driver couldn't be quiesced
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio810_ddi_quiesce(dev_info_t *dip)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_state_t *statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((statep = ddi_get_driver_private(dip)) == NULL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_stop_dma(statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_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 * Each of buffer descriptor has a field IOC(interrupt on completion)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * When both this and the IOC bit of correspondent dma control register
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * is set, it means that the controller should issue an interrupt upon
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * completion of this buffer.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * (AMD 8111 hypertransport I/O hub data sheet. 3.8.3 page 71)
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'Amoreaudio810_intr(caddr_t arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_state_t *statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t gsr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep = (void *)arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->suspended) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_INTR_UNCLAIMED);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore gsr = I810_BM_GET32(I810_REG_GSR);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* check if device is interrupting */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((gsr & I810_GSR_USE_INTR) == 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_INTR_UNCLAIMED);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int pnum = 0; pnum < I810_NUM_PORTS; pnum++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_port_t *port;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint8_t regoff, index;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port = statep->ports[pnum];
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore continue;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore regoff = port->regoff;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!(I810_BM_GET8(port->stsoff) & I810_BM_SR_BCIS))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore continue;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* update the LVI -- we just set it to the current value - 1 */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore index = I810_BM_GET8(regoff + I810_OFFSET_CIV);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore index = (index - 1) % I810_BD_NUMS;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT8(regoff + I810_OFFSET_LVI, index);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* clear any interrupt */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT8(port->stsoff,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_SR_LVBCI | I810_BM_SR_BCIS | I810_BM_SR_FIFOE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* update the kernel interrupt statistics */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->ksp) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_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 /* notify the framework */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (gsr & I810_GSR_INTR_PIN) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_engine_produce(statep->ports[I810_PCM_IN]->engine);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (gsr & I810_GSR_INTR_POUT) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_engine_consume(statep->ports[I810_PCM_OUT]->engine);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_INTR_CLAIMED);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_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'Amoreaudio810_open(void *arg, int flag, unsigned *fragfrp, unsigned *nfragsp,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore caddr_t *bufp)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_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 *fragfrp = port->fragfr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *nfragsp = port->nfrag;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *bufp = port->samp_kaddr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&port->statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_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 * audio810_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'Amoreaudio810_close(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_state_t *statep = port->statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_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 * audio810_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'Amoreaudio810_stop(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_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 audio810_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 * audio810_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'Amoreaudio810_start(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_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 audio810_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 * audio810_format()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to query the format 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 * Format of the device (fixed at AUDIO_FORMAT_S16_LE)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio810_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 * audio810_channels()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to query the num channels of
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 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 * 0 number of channels for device
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio810_channels(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_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 * audio810_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 * Rate of device (fixed at 48000 Hz)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio810_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 * audio810_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'Amoreaudio810_count(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_state_t *statep = port->statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint64_t val;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t picb;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint64_t count;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint8_t nchan;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_update_port(port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore count = port->count;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore picb = port->picb;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore nchan = port->nchan;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->quirk == QUIRK_SIS7012) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore val = count + picb / (2 * nchan);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore val = count + (picb / nchan);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (val);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_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'Amoreaudio810_sync(void *arg, unsigned nframes)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_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 * audio810_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'Amoreaudio810_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/* *********************** Local Routines *************************** */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_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 * audio810_port_t *port Port of DMA engine to start.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio810_start_port(audio810_port_t *port)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_state_t *statep = port->statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint8_t cr;
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 cr = I810_BM_GET8(port->regoff + I810_OFFSET_CR);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cr |= I810_BM_CR_IOCE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT8(port->regoff + I810_OFFSET_CR, cr);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cr |= I810_BM_CR_RUN;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT8(port->regoff + I810_OFFSET_CR, cr);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_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 * audio810_port_t *port Port of DMA engine to stop.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio810_stop_port(audio810_port_t *port)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_state_t *statep = port->statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint8_t cr;
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 cr = I810_BM_GET8(port->regoff + I810_OFFSET_CR);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cr &= ~I810_BM_CR_RUN;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT8(port->regoff + I810_OFFSET_CR, cr);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_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 * audio810_port_t *port Port of DMA engine to reset.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio810_reset_port(audio810_port_t *port)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_state_t *statep = port->statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t gcr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(mutex_owned(&statep->inst_lock));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->civ = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->picb = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->suspended)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Make sure we put once in stereo, to ensure we always start from
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * front left.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->num == I810_PCM_OUT) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->quirk == QUIRK_SIS7012) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * SiS 7012 needs its own special multichannel config.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore gcr = I810_BM_GET32(I810_REG_GCR);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore gcr &= ~I810_GCR_SIS_CHANNELS_MASK;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT32(I810_REG_GCR, gcr);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore delay(drv_usectohz(50000)); /* 50 msec */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (statep->maxch) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 2:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore gcr |= I810_GCR_SIS_2_CHANNELS;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 4:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore gcr |= I810_GCR_SIS_4_CHANNELS;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 6:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore gcr |= I810_GCR_SIS_6_CHANNELS;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT32(I810_REG_GCR, gcr);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore delay(drv_usectohz(50000)); /* 50 msec */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * SiS 7012 has special unmute bit.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT8(I810_REG_SISCTL, I810_SISCTL_UNMUTE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * All other devices work the same.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore gcr = I810_BM_GET32(I810_REG_GCR);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore gcr &= ~I810_GCR_CHANNELS_MASK;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT32(I810_REG_GCR, gcr);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore delay(drv_usectohz(50000)); /* 50 msec */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (statep->maxch) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 2:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore gcr |= I810_GCR_2_CHANNELS;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 4:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore gcr |= I810_GCR_4_CHANNELS;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 6:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore gcr |= I810_GCR_6_CHANNELS;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT32(I810_REG_GCR, gcr);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore delay(drv_usectohz(50000)); /* 50 msec */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Perform full reset of the engine, but leave it turned off.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT8(port->regoff + I810_OFFSET_CR, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT8(port->regoff + I810_OFFSET_CR, I810_BM_CR_RST);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* program the offset of the BD list */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT32(port->regoff + I810_OFFSET_BD_BASE, port->bdl_paddr);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* we set the last index to the full count -- all buffers are valid */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT8(port->regoff + I810_OFFSET_LVI, I810_BD_NUMS - 1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_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 * audio810_port_t *port The port to update.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio810_update_port(audio810_port_t *port)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_state_t *statep = port->statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint8_t regoff = port->regoff;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint8_t civ;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t picb;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore unsigned n;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->suspended) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore civ = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore picb = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * We read the position counters, but we're careful to avoid
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the situation where the position counter resets at the end
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * of a buffer.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; i < 2; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore civ = I810_BM_GET8(regoff + I810_OFFSET_CIV);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore picb = I810_BM_GET16(port->picboff);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (I810_BM_GET8(regoff + I810_OFFSET_CIV) == civ) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Chip did not start a new index,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * so the picb is valid.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (civ >= port->civ) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore n = civ - port->civ;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore n = civ + (I810_BD_NUMS - port->civ);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->count += (n * port->fragfr);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->civ = civ;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->picb = picb;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_attach()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Attach an instance of the audio810 driver. This routine does the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * device dependent attach tasks, and registers with the audio framework.
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'Amoreaudio810_attach(dev_info_t *dip)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t cmdreg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_state_t *statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_t *adev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_acc_handle_t pcih;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t devid;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t gsr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore const char *name;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore const char *vers;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint8_t nch;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int maxch;
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, "!%s: unsupported high level interrupt",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_name);
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 ddi_set_driver_private(dip, statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* get iblock cookie information */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_get_iblock_cookie(dip, 0, &statep->iblock) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmn_err(CE_WARN, "!%s: cannot get iblock cookie",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_name);
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 mutex_init(&statep->ac_lock, NULL, MUTEX_DRIVER, statep->iblock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((adev = audio_dev_alloc(dip, 0)) == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmn_err(CE_WARN, "!%s: unable to allocate audio dev",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_name);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep->adev = adev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep->dip = dip;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* map in the registers, allocate DMA buffers, etc. */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audio810_map_regs(dip, 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 PCI command register */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "pci conf mapping failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmdreg = pci_config_get16(pcih, PCI_CONF_COMM);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pci_config_put16(pcih, PCI_CONF_COMM,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmdreg | PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore devid = pci_config_get16(pcih, PCI_CONF_VENID);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore devid <<= 16;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore devid |= pci_config_get16(pcih, PCI_CONF_DEVID);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pci_config_teardown(&pcih);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "Unknown AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep->quirk = QUIRK_NONE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (devid) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x80862415:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "Intel AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "ICH";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x80862425:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "Intel AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "ICH0";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x80867195:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "Intel AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "440MX";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x80862445:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "Intel AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "ICH2";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x80862485:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "Intel AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "ICH3";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x808624C5:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "Intel AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "ICH4";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x808624D5:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "Intel AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "ICH5";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x8086266E:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "Intel AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "ICH6";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x808627DE:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "Intel AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "ICH7";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x808625A6:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "Intel AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "6300ESB";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x80862698:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "Intel AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "ESB2";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x10397012:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "SiS AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "7012";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep->quirk = QUIRK_SIS7012;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x10de01b1: /* nForce */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "NVIDIA AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "MCP1";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x10de006a: /* nForce 2 */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "NVIDIA AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "MCP2";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x10de00da: /* nForce 3 */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "NVIDIA AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "MCP3";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x10de00ea:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "NVIDIA AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "CK8S";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x10de0059:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "NVIDIA AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "CK804";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x10de008a:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "NVIDIA AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "CK8";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x10de003a: /* nForce 4 */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "NVIDIA AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "MCP4";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x10de026b:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "NVIDIA AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "MCP51";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x1022746d:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "AMD AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "8111";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x10227445:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "AMD AC'97";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vers = "AMD768";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* set device information */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_set_description(adev, name);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_set_version(adev, vers);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore /* initialize audio controller and AC97 codec */
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore if (audio810_chip_init(statep) != DDI_SUCCESS) {
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore audio_dev_warn(adev, "failed to init chip");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* allocate ac97 handle */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep->ac97 = ac97_alloc(dip, audio810_read_ac97, audio810_write_ac97,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 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 /* 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
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore /*
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore * Override "max-channels" property to prevent configuration
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore * of 4 or 6 (or possibly even 8!) channel audio. The default
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore * is to support as many channels as the hardware can do.
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore *
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore * (Hmmm... perhaps this should be driven in the common
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore * framework. The framework could even offer simplistic upmix
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore * and downmix for various standard configs.)
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore */
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore maxch = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore "max-channels", ac97_num_channels(statep->ac97));
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore if (maxch < 2) {
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore maxch = 2;
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore }
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore gsr = I810_BM_GET32(I810_REG_GSR);
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore if (gsr & I810_GSR_CAP6CH) {
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore nch = 6;
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore } else if (gsr & I810_GSR_CAP4CH) {
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore nch = 4;
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore } else {
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore nch = 2;
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore }
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore statep->maxch = (uint8_t)min(nch, maxch);
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore statep->maxch &= ~1;
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore /* allocate port structures */
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore if ((audio810_alloc_port(statep, I810_PCM_OUT, statep->maxch) !=
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore DDI_SUCCESS) ||
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore (audio810_alloc_port(statep, I810_PCM_IN, 2) != DDI_SUCCESS)) {
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore goto error;
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore }
0e7a77f3bec009d2e19415527920cc1c105cd24fGarrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* set up kernel statistics */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((statep->ksp = kstat_create(I810_NAME, ddi_get_instance(dip),
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_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 /* set up the interrupt handler */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_add_intr(dip, 0, &statep->iblock,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL, audio810_intr, (caddr_t)statep) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "bad interrupt specification");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
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 audio810_destroy(statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_resume()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Resume operation of the device after sleeping or hibernating.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Note that this should never fail, even if hardware goes wonky,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * because the current PM framework will panic if it does.
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 resumed.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio810_resume(dev_info_t *dip)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_state_t *statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_t *adev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* this should always be valid */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep = ddi_get_driver_private(dip);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore adev = statep->adev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(statep != NULL);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(dip == statep->dip);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Restore the audio810 chip's state */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audio810_chip_init(statep) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Note that PM gurus say we should return
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * success here. Failure of audio shouldn't
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * be considered FATAL to the system. The
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * upshot is that audio will not progress.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
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 /* allow ac97 operations again */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_resume(statep->ac97);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(statep->suspended);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep->suspended = B_FALSE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; i < I810_NUM_PORTS; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_port_t *port = statep->ports[i];
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port != NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* reset framework DMA engine buffer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->engine != NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_engine_reset(port->engine);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* reset and initialize hardware ports */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_reset_port(port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->started) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_start_port(port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_stop_port(port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_detach()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Detach an instance of the audio810 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'Amoreaudio810_detach(dev_info_t *dip)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_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 /* don't detach us if we are still in use */
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 audio810_destroy(statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_suspend()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Suspend an instance of the audio810 driver, in preparation for
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * sleep or hibernation.
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 suspended
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio810_suspend(dev_info_t *dip)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_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
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(statep->suspended == B_FALSE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep->suspended = B_TRUE; /* stop new ops */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* stop DMA engines */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_stop_dma(statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_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'Amoreaudio810_alloc_port(audio810_state_t *statep, int num, uint8_t nchan)
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 char *nfprop;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_t *adev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_port_t *port;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t paddr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int rc;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dev_info_t *dip;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore i810_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 statep->ports[num] = port;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->statep = statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->started = B_FALSE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->nchan = nchan;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->num = num;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (num) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case I810_PCM_IN:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore prop = "record-interrupts";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore nfprop = "record-fragments";
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->regoff = I810_BASE_PCM_IN;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case I810_PCM_OUT:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore prop = "play-interrupts";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore nfprop = "play-fragments";
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 port->regoff = I810_BASE_PCM_OUT;
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 /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * SiS 7012 swaps status and picb registers.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->quirk == QUIRK_SIS7012) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->stsoff = port->regoff + I810_OFFSET_PICB;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->picboff = port->regoff + I810_OFFSET_SR;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->stsoff = port->regoff + I810_OFFSET_SR;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->picboff = port->regoff + I810_OFFSET_PICB;
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, I810_INTS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* make sure the values are good */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->intrs < I810_MIN_INTS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "%s too low, %d, resetting to %d",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore prop, port->intrs, I810_INTS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->intrs = I810_INTS;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else if (port->intrs > I810_MAX_INTS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "%s too high, %d, resetting to %d",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore prop, port->intrs, I810_INTS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->intrs = I810_INTS;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->nfrag = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_PROP_DONTPASS, nfprop, I810_NFRAGS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Note that fragments must divide evenly into I810_BD_NUMS (32).
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->nfrag <= 4) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->nfrag = 4;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else if (port->nfrag <= 8) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->nfrag = 8;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else if (port->nfrag <= 16) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->nfrag = 16;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->nfrag = I810_BD_NUMS;
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 32 chunks. (Note that this means that low
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * interrupt frequencies will require more RAM. We could probably
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * do some cleverness to use a shorter BD list.)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->fragfr = 48000 / port->intrs;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->fragfr = I810_ROUNDUP(port->fragfr, I810_MOD_SIZE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->fragsz = port->fragfr * port->nchan * 2;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->samp_size = port->fragsz * port->nfrag;
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 (%d) failed: %d",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->samp_size, rc);
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 (i810_bd_entry_t) * I810_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 for (int i = 0; i < I810_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 /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * SiS 7012 counts samples in bytes, all other count
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * in words.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put16(port->bdl_acch, &bdentry->buf_len,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore statep->quirk == QUIRK_SIS7012 ? port->fragsz :
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->fragsz / 2);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put16(port->bdl_acch, &bdentry->buf_cmd,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore BUF_CMD_IOC | BUF_CMD_BUP);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore paddr += port->fragsz;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((i % port->nfrag) == (port->nfrag - 1)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* handle wrap */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore paddr = port->samp_paddr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore bdentry++;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett 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(&audio810_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 * audio810_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 * audio810_port_t *port The port structure for a DMA engine.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio810_free_port(audio810_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 * audio810_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 * 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'Amoreaudio810_map_regs(dev_info_t *dip, audio810_state_t *statep)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint_t nregs = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int *regs_list;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int i;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int pciBar1 = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int pciBar2 = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int pciBar3 = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int pciBar4 = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* check the "reg" property to get the length of memory-mapped I/O */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "reg", (int **)&regs_list, &nregs) != DDI_PROP_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "inquire regs property failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Some hardwares, such as Intel ICH0/ICH and AMD 8111, use PCI 0x10
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * and 0x14 BAR separately for native audio mixer BAR and native bus
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * mastering BAR. More advanced hardwares, such as Intel ICH4 and ICH5,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * support PCI memory BAR, via PCI 0x18 and 0x1C BAR, that allows for
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * higher performance access to the controller register. All features
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * can be accessed via this BAR making the I/O BAR (PCI 0x10 and 0x14
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * BAR) capabilities obsolete. However, these controller maintain the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * I/O BAR capability to allow for the reuse of legacy code maintaining
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * backward compatibility. The I/O BAR is disabled unless system BIOS
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * enables the simultaneous backward compatible capability on the 0x41
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * register.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * When I/O BAR is enabled, the value of "reg" property should be like
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * this,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * phys_hi phys_mid phys_lo size_hi size_lo
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * --------------------------------------------------------
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0000fd00 00000000 00000000 00000000 00000000
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0100fd10 00000000 00000000 00000000 00000100
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0100fd14 00000000 00000000 00000000 00000040
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0200fd18 00000000 00000000 00000000 00000200
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0200fd1c 00000000 00000000 00000000 00000100
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * When I/O BAR is disabled, the "reg" property of the device node does
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * not consist of the description for the I/O BAR. The following example
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * illustrates the vaule of "reg" property,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * phys_hi phys_mid phys_lo size_hi size_lo
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * --------------------------------------------------------
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0000fd00 00000000 00000000 00000000 00000000
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0200fd18 00000000 00000000 00000000 00000200
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0200fd1c 00000000 00000000 00000000 00000100
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If the hardware has memory-mapped I/O access, first try to use
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * this facility, otherwise we will try I/O access.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 1; i < nregs/I810_INTS_PER_REG_PROP; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (regs_list[I810_INTS_PER_REG_PROP * i] & 0x000000ff) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x10:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pciBar1 = i;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x14:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pciBar2 = i;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x18:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pciBar3 = i;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x1c:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pciBar4 = i;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore default: /* we don't care others */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((pciBar3 != 0) && (pciBar4 != 0)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* map audio mixer registers */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((ddi_regs_map_setup(dip, pciBar3, &statep->am_regs_base, 0,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0, &dev_attr, &statep->am_regs_handle)) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "memory am mapping failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* map bus master register */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((ddi_regs_map_setup(dip, pciBar4, &statep->bm_regs_base, 0,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0, &dev_attr, &statep->bm_regs_handle)) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "memory bm mapping failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else if ((pciBar1 != 0) && (pciBar2 != 0)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* map audio mixer registers */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((ddi_regs_map_setup(dip, pciBar1, &statep->am_regs_base, 0,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0, &dev_attr, &statep->am_regs_handle)) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "I/O am mapping failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* map bus master register */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((ddi_regs_map_setup(dip, pciBar2, &statep->bm_regs_base, 0,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0, &dev_attr, &statep->bm_regs_handle)) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "I/O bm mapping failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "map_regs() pci BAR error");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_prop_free(regs_list);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreerror:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (nregs > 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_prop_free(regs_list);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_unmap_regs(statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_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 * audio810_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio810_unmap_regs(audio810_state_t *statep)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->bm_regs_handle) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_regs_map_free(&statep->bm_regs_handle);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->am_regs_handle) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_regs_map_free(&statep->am_regs_handle);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_chip_init()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine initializes the AMD 8111 audio controller.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * codec.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_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'Amoreaudio810_chip_init(audio810_state_t *statep)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t gcr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t gsr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t codec_ready;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int loop;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore clock_t ticks;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore gcr = I810_BM_GET32(I810_REG_GCR);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ticks = drv_usectohz(100);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Clear the channels bits for now. We'll set them later in
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * reset port.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->quirk == QUIRK_SIS7012) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore gcr &= ~(I810_GCR_ACLINK_OFF | I810_GCR_SIS_CHANNELS_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore gcr &= ~(I810_GCR_ACLINK_OFF | I810_GCR_CHANNELS_MASK);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Datasheet(ICH5, document number of Intel: 252751-001):
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 3.6.5.5(page 37)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * if reset bit(bit1) is "0", driver must set it
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * to "1" to de-assert the AC_RESET# signal in AC
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * link, thus completing a cold reset. But if the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * bit is "1", then a warm reset is required.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore gcr |= (gcr & I810_GCR_COLD_RST) == 0 ?
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_GCR_COLD_RST:I810_GCR_WARM_RST;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT32(I810_REG_GCR, gcr);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* according AC'97 spec, wait for codec reset */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (loop = 6000; --loop >= 0; ) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore delay(ticks);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore gcr = I810_BM_GET32(I810_REG_GCR);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((gcr & I810_GCR_WARM_RST) == 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* codec reset failed */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (loop < 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "Failed to reset codec");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Wait for codec ready. The hardware can provide the state of
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * codec ready bit on SDATA_IN[0], SDATA_IN[1] or SDATA_IN[2]
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore codec_ready =
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_GSR_PRI_READY | I810_GSR_SEC_READY | I810_GSR_TRI_READY;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (loop = 7000; --loop >= 0; ) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore delay(ticks);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore gsr = I810_BM_GET32(I810_REG_GSR);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((gsr & codec_ready) != 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (loop < 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(statep->adev, "No codec ready signal received");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * put the audio controller into quiet state, everything off
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_stop_dma(statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_stop_dma()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine is used to put each DMA engine into the quiet state.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio810_stop_dma(audio810_state_t *statep)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->bm_regs_handle == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* pause bus master (needed for the following reset register) */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT8(I810_BASE_PCM_IN + I810_OFFSET_CR, 0x0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT8(I810_BASE_PCM_OUT + I810_OFFSET_CR, 0x0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT8(I810_BASE_MIC + I810_OFFSET_CR, 0x0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* and then reset the bus master registers for a three DMA engines */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT8(I810_BASE_PCM_IN + I810_OFFSET_CR, I810_BM_CR_RST);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT8(I810_BASE_PCM_OUT + I810_OFFSET_CR, I810_BM_CR_RST);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_BM_PUT8(I810_BASE_MIC + I810_OFFSET_CR, I810_BM_CR_RST);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_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 * audio810_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'Amoreaudio810_codec_sync(audio810_state_t *statep)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int i;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t casr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < 300; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore casr = I810_BM_GET8(I810_REG_CASR);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((casr & 1) == 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(10);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_write_ac97()
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'Amoreaudio810_write_ac97(void *arg, uint8_t reg, uint16_t data)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_state_t *statep = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&statep->ac_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audio810_codec_sync(statep) == DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore I810_AM_PUT16(reg, data);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&statep->ac_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) audio810_read_ac97(statep, reg);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_read_ac97()
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 * The register value.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic uint16_t
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio810_read_ac97(void *arg, uint8_t reg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_state_t *statep = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t val = 0xffff;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_enter(&statep->ac_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audio810_codec_sync(statep) == DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore val = I810_AM_GET16(reg);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_exit(&statep->ac_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (val);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio810_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 * audio810_state_t *state The device soft state.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorevoid
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudio810_destroy(audio810_state_t *statep)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* stop DMA engines */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_stop_dma(statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (statep->intr_added) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_remove_intr(statep->dip, 0, NULL);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
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 for (int i = 0; i < I810_NUM_PORTS; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_free_port(statep->ports[i]);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio810_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 if (statep->adev)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_free(statep->adev);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_destroy(&statep->inst_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore mutex_destroy(&statep->ac_lock);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore kmem_free(statep, sizeof (*statep));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}