88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER START
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The contents of this file are subject to the terms of the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Common Development and Distribution License (the "License").
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * You may not use this file except in compliance with the License.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * or http://www.opensolaris.org/os/licensing.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * See the License for the specific language governing permissions
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * and limitations under the License.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER END
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Use is subject to license terms.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Purpose: Creative/Ensoniq AudioPCI driver (ES1370)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This driver is used with the original Ensoniq AudioPCI.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This file is part of Open Sound System
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Copyright (C) 4Front Technologies 1996-2008.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This software is released under CDDL 1.0 source license.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * See the COPYING file included in the main directory of this source
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * distribution for the license terms and conditions.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The original OSS driver used a single duplex engine and a separate
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * playback only engine. Instead, we expose three engines, one for input
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * and two for output.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Audio parameters */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoretypedef enum {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The hardware appears to be able to address up to 16-bits worth of longwords,
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * giving a total address space of 256K. But we need substantially less.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0 /* dma_attr_flags */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_get8(dev->acch, (uint8_t *)(dev->regs + (offset)))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_get16(dev->acch, (uint16_t *)(void *)(dev->regs + (offset)))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_get32(dev->acch, (uint32_t *)(void *)(dev->regs + (offset)))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put8(dev->acch, (uint8_t *)(dev->regs + (offset)), v)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put16(dev->acch, (uint16_t *)(void *)(dev->regs + (offset)), v)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(dev->acch, (uint32_t *)(void *)(dev->regs + (offset)), v)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define CLR8(dev, offset, v) PUT8(dev, offset, GET8(dev, offset) & ~(v))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define SET8(dev, offset, v) PUT8(dev, offset, GET8(dev, offset) | (v))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define CLR16(dev, offset, v) PUT16(dev, offset, GET16(dev, offset) & ~(v))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define SET16(dev, offset, v) PUT16(dev, offset, GET16(dev, offset) | (v))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiopci_init_hw(audiopci_dev_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiopci_init_port(audiopci_port_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiopci_add_controls(audiopci_dev_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiopci_del_controls(audiopci_dev_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiopci_ak_write(audiopci_dev_t *, uint16_t, uint8_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiopci_ak_wait(audiopci_dev_t *dev, uint8_t wstat)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 4000; i; i--) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!(GET8(dev, CONC_bCODECSTAT_OFF) & wstat))
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; i < 5; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audiopci_ak_wait(dev, CONC_CSTAT_CSTAT) == DDI_SUCCESS)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(dev->adev, "timed out waiting for codec to idle");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiopci_ak_write(audiopci_dev_t *dev, uint16_t addr, uint8_t data)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* shadow the value */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore wstat = addr == CODEC_RESET_PWRD ? CONC_CSTAT_CWRIP : CONC_CSTAT_CSTAT;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* wait for codec to be available */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audiopci_ak_wait(dev, wstat) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(dev->adev, "timeout waiting for codec");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT16(dev, CONC_wCODECCTL_OFF, (addr << 8) | data);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiopci_writemem(audiopci_dev_t *dev, uint32_t page, uint32_t offs,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Select memory page */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiopci_readmem(audiopci_dev_t *dev, uint32_t page, uint32_t offs)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT32(dev, CONC_bMEMPAGE_OFF, page); /* Select memory page */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Audio routines
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set physical address of the DMA buffer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_writemem(dev, CONC_DACCTL_PAGE, CONC_dDACPADDR_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set DAC rate */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT16(dev, CONC_wDACRATE_OFF, audiopci_dac_rate(48000));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set format */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set the frame count */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_writemem(dev, CONC_DACCTL_PAGE, CONC_wDACFC_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set # of frames between interrupts */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore PUT16(dev, CONC_wDACIC_OFF, port->nframes - 1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set physical address of the DMA buffer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_writemem(dev, CONC_SYNCTL_PAGE, CONC_dSYNPADDR_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set rate - we force to 44.1 kHz */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SET8(dev, CONC_bMISCCTL_OFF, CONC_MISCCTL_SYN_44KHZ);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set format */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set the frame count */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_writemem(dev, CONC_SYNCTL_PAGE, CONC_wSYNFC_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set # of frames between interrupts */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore PUT16(dev, CONC_wSYNIC_OFF, port->nframes - 1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set physical address of the DMA buffer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_writemem(dev, CONC_ADCCTL_PAGE, CONC_dADCPADDR_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set ADC rate */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT16(dev, CONC_wDACRATE_OFF, audiopci_dac_rate(48000));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set format - for input we only support 16 bit input */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set the frame count */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_writemem(dev, CONC_ADCCTL_PAGE, CONC_wADCFC_OFF,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Set # of frames between interrupts */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore PUT16(dev, CONC_wADCIC_OFF, port->nframes - 1);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amoreaudiopci_open(void *arg, int flag, unsigned *nframes, caddr_t *bufp)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* NB: frame size = 4 (16-bit stereo) */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore SET8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_DAC_EN);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore SET8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_SYN_EN);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore SET8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_ADC_EN);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore CLR8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_DAC_EN);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore CLR8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_SYN_EN);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore CLR8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_ADC_EN);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Note that the current frame counter is in the high nybble.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore frameno = audiopci_readmem(port->dev, page, offs) >> 16;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) ddi_dma_sync(port->dmah, 0, 0, DDI_DMA_SYNC_FORCPU);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) ddi_dma_sync(port->dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* samPerSec /= 2; */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore usTemp = (unsigned short) ((DAC_CLOCK_DIVIDE / 8) / samPerSec);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* setup DAC frequency */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PUT16(dev, CONC_wDACRATE_OFF, audiopci_dac_rate(48000));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CLR8(dev, CONC_bMISCCTL_OFF, CONC_MISCCTL_CCB_INTRM);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore SET8(dev, CONC_bMISCCTL_OFF, CONC_MISCCTL_SYN_44KHZ);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Turn on CODEC (UART and joystick left disabled) */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Reset the UART */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Disable NMI */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Initialize serial interface */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Unmute codec */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CLR8(dev, CONC_bMISCCTL_OFF, CONC_MISCCTL_MUTE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* mixer initialization */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* power/reset down the codec */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_ak_write(dev, CODEC_RESET_PWRD, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* now powerup and bring out of reset */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_ak_write(dev, CODEC_RESET_PWRD, 0x3);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* enable PLL for DAC2 */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* select input mixer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* mark FM for output mixer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_ak_write(dev, CODEC_OUT_SW1, CODEC_OUT_ENABLE_SYNTH);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_ak_write(dev, CODEC_OUT_SW2, CODEC_OUT_ENABLE_WAVE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* initialize some reasonable values for the WAVE and SYNTH inputs */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_ak_write(dev, CODEC_VOL_WAVE_L, 6);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_ak_write(dev, CODEC_VOL_WAVE_R, 6);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_ak_write(dev, CODEC_VOL_SYNTH_L, 6);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_ak_write(dev, CODEC_VOL_SYNTH_R, 6);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* enable microphone phantom power */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; i <= PORT_MAX; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dmaflags = DDI_DMA_WRITE | DDI_DMA_CONSISTENT;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dmaflags = DDI_DMA_WRITE | DDI_DMA_CONSISTENT;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dmaflags = DDI_DMA_READ | DDI_DMA_CONSISTENT;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Allocate DMA resources.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_dma_alloc_handle(dev->dip, &dma_attr, DDI_DMA_SLEEP,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "port %d: dma handle allocation failed", i);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_dma_mem_alloc(port->dmah, AUDIOPCI_BUF_LEN, &buf_attr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &port->kaddr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "port %d: dma memory allocation failed", i);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* ensure that the buffer is zeroed out properly */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_dma_addr_bind_handle(port->dmah, NULL, port->kaddr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AUDIOPCI_BUF_LEN, dmaflags, DDI_DMA_SLEEP, NULL,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "port %d: dma binding failed", i);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Allocate and configure audio engine.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->engine = audio_engine_alloc(&audiopci_engine_ops, caps);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "port %d: audio_engine_alloc failed", i);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_engine_set_private(port->engine, port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_add_engine(dev->adev, port->engine);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Register audio controls.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audiopci_add_controls(dev) == DDI_FAILURE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audio_dev_register(dev->adev) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "unable to register with audio framework");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* free up ports, including DMA resources for ports */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i <= PORT_MAX; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_remove_engine(dev->adev, port->engine);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiopci_stereo(audiopci_dev_t *dev, audiopci_ctrl_num_t num, uint8_t lreg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* convert to attenuation & apply mute if appropriate */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore lval = ((((100U - lval) * CODEC_ATT_MAX) / 100) & 0xff) | lmute;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rval = ((((100U - rval) * CODEC_ATT_MAX) / 100) & 0xff) | rmute;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiopci_mono(audiopci_dev_t *dev, audiopci_ctrl_num_t num, uint8_t reg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint64_t val = (dev->controls[num].val & 0xff);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore val = ((((100U - val) * CODEC_ATT_MAX) / 100) & 0xff) | mute;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiopci_mono8(audiopci_dev_t *dev, audiopci_ctrl_num_t num, uint8_t reg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint64_t val = (dev->controls[num].val & 0xff);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore val = ((((100U - val) * CODEC_ATT_MONO) / 100) & 0xff) | mute;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiopci_configure_output(audiopci_dev_t *dev)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_mono(dev, CTL_VOLUME, CODEC_VOL_WAVE_L);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_mono(dev, CTL_VOLUME, CODEC_VOL_WAVE_R);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_mono(dev, CTL_VOLUME, CODEC_VOL_SYNTH_L);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_mono(dev, CTL_VOLUME, CODEC_VOL_SYNTH_R);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* front & mono outputs */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_stereo(dev, CTL_FRONT, CODEC_VOL_MASTER_L);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_mono8(dev, CTL_MONO, CODEC_VOL_MONO);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* setup output monitoring as well */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiopci_configure_input(audiopci_dev_t *dev)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint64_t val = dev->controls[CTL_RECSRC].val;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* configure volumes */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_mono(dev, CTL_PHONE, CODEC_VOL_TAD);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_stereo(dev, CTL_LINE, CODEC_VOL_AUX_L);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_stereo(dev, CTL_CD, CODEC_VOL_CD_L);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_stereo(dev, CTL_VID, CODEC_VOL_TV_L);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* activate 30dB mic boost */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiopci_set_reclevel(void *arg, uint64_t val)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiopci_set_micboost(void *arg, uint64_t val)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiopci_set_speaker(void *arg, uint64_t val)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define PLAYCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_PLAY)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define RECCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_REC)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define MONCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_MONITOR)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define PCMVOL (PLAYCTL | AUDIO_CTRL_FLAG_PCMVOL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define MAINVOL (PLAYCTL | AUDIO_CTRL_FLAG_MAINVOL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#define RECVOL (RECCTL | AUDIO_CTRL_FLAG_RECVOL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiopci_alloc_ctrl(audiopci_dev_t *dev, uint32_t num, uint64_t val)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore desc.acd_flags = RECCTL | AUDIO_CTRL_FLAG_MULTI;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; audiopci_insrcs[i]; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore desc.acd_flags = MONCTL | AUDIO_CTRL_FLAG_MULTI;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; audiopci_insrcs[i]; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pc->ctrl = audio_dev_add_control(dev->adev, &desc,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_alloc_ctrl(dev, CTL_FRONT, ((75) | (75 << 8)));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiopci_alloc_ctrl(dev, CTL_RECSRC, (1U << INPUT_MIC));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; i < CTL_NUM; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_del_control(dev->controls[i].ctrl);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, NULL);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(dev->adev, "pci_config_setup failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore vendor = pci_config_get16(pcih, PCI_CONF_VENID);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore device = pci_config_get16(pcih, PCI_CONF_DEVID);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((vendor != ENSONIQ_VENDOR_ID && vendor != CREATIVE_VENDOR_ID) ||
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_set_description(dev->adev, "AudioPCI");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_add_info(dev->adev, "Legacy codec: Asahi Kasei AK4531");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* activate the device */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pci_command = pci_config_get16(pcih, PCI_CONF_COMM);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pci_config_put16(pcih, PCI_CONF_COMM, pci_command);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* map registers */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_regs_map_setup(dip, 1, &dev->regs, 0, 0, &acc_attr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(dev->adev, "can't map registers");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* This allocates and configures the engines */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(dev->adev, "can't init device");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* first unregister us from the DDI framework, might be busy */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audio_dev_unregister(dev->adev) != DDI_SUCCESS)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ~(CONC_SERCTL_DACIE | CONC_SERCTL_SYNIE | CONC_SERCTL_ADCIE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ~(CONC_DEVCTL_DAC_EN | CONC_DEVCTL_ADC_EN | CONC_DEVCTL_SYN_EN);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* reinitialize hardware */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((dev = ddi_get_driver_private(dip)) == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* This disables all DMA engines and interrupts */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ~(CONC_SERCTL_DACIE | CONC_SERCTL_SYNIE | CONC_SERCTL_ADCIE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ~(CONC_DEVCTL_DAC_EN | CONC_DEVCTL_ADC_EN | CONC_DEVCTL_SYN_EN);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiopci_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((dev = ddi_get_driver_private(dip)) == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiopci_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((dev = ddi_get_driver_private(dip)) == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0, /* refcnt */