7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore/*
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore *
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * Redistribution and use in source and binary forms, with or without
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * modification, are permitted provided that the following conditions
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * are met:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * 1. Redistributions of source code must retain the above copyright
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * notice, this list of conditions and the following disclaimer.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * 2. Redistributions in binary form must reproduce the above copyright
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * notice, this list of conditions and the following disclaimer in the
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * documentation and/or other materials provided with the distribution.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore *
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * SUCH DAMAGE.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore/*
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * Use is subject to license terms.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore/*
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * Copyright (C) 4Front Technologies 1996-2008.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#include <sys/audio/audio_driver.h>
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#include <sys/note.h>
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#include <sys/pci.h>
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#include <sys/stdbool.h>
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore/*
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * NB: The Solo-1 is a bit schizophrenic compared to most devices.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * It has two separate DMA engines for PCM data. The first can do
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * either capture or playback, and supports various Sound Blaster
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * compatibility features. The second is dedicated to playback. The
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * two engines have very little in common when it comes to programming
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * them.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore *
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * We configure engine 1 for record, and engine 2 for playback. Both
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * are configured for 48 kHz stereo 16-bit signed PCM.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore/*
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * ESS Solo-1 only implements the low 24-bits on Audio1, and requires
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * 64KB alignment. For Audio2, it implements the full 32-bit address
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * space, but requires a 1MB address boundary. Audio1 is used for
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * recording, and Audio2 is used for playback.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic struct ddi_dma_attr dma_attr_audio1 = {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore DMA_ATTR_VERSION, /* dma_attr_version */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0x0, /* dma_attr_addr_lo */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0x00ffffffU, /* dma_attr_addr_hi */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0xffff, /* dma_attr_count_max */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0x10000, /* dma_attr_align */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0x7f, /* dma_attr_burstsizes */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0x4, /* dma_attr_minxfer */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0xffff, /* dma_attr_maxxfer */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0xffff, /* dma_attr_seg */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0x1, /* dma_attr_sgllen */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0x1, /* dma_attr_granular */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0 /* dma_attr_flags */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore};
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic struct ddi_dma_attr dma_attr_audio2 = {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore DMA_ATTR_VERSION, /* dma_attr_version */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0x0, /* dma_attr_addr_lo */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0xffffffffU, /* dma_attr_addr_hi */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0xfff0, /* dma_attr_count_max */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0x100000, /* dma_attr_align */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0x7f, /* dma_attr_burstsizes */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0x4, /* dma_attr_minxfer */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0xfff0, /* dma_attr_maxxfer */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0xffff, /* dma_attr_seg */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0x1, /* dma_attr_sgllen */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0x1, /* dma_attr_granular */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0 /* dma_attr_flags */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore};
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic ddi_device_acc_attr_t acc_attr = {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore DDI_DEVICE_ATTR_V0,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore DDI_STRUCTURE_LE_ACC,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore DDI_STRICTORDER_ACC
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore};
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic ddi_device_acc_attr_t buf_attr = {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore DDI_DEVICE_ATTR_V0,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore DDI_NEVERSWAP_ACC,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore DDI_STRICTORDER_ACC
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore};
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore/*
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * For the sake of simplicity, this driver fixes a few parameters with
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * constants.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define SOLO_RATE 48000
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore#define SOLO_FRAGFR 1024
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore#define SOLO_NFRAGS 2
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define SOLO_NCHAN 2
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define SOLO_SAMPSZ 2
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define SOLO_FRAGSZ (SOLO_FRAGFR * (SOLO_NCHAN * SOLO_SAMPSZ))
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define SOLO_BUFFR (SOLO_NFRAGS * SOLO_FRAGFR)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define SOLO_BUFSZ (SOLO_NFRAGS * SOLO_FRAGSZ)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define INPUT_MIC 0
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define INPUT_LINE 1
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define INPUT_CD 2
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define INPUT_AUX 3
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define INPUT_MONO 4
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define INSRCS 0x1f /* bits 0-4 */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define DRVNAME "audiosolo"
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic const char *solo_insrcs[] = {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore AUDIO_PORT_MIC,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore AUDIO_PORT_LINEIN,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore AUDIO_PORT_CD,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore AUDIO_PORT_AUX1IN,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore AUDIO_PORT_AUX2IN, /* this is really mono-in */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore NULL
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore};
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoretypedef struct solo_regs {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_acc_handle_t acch;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore caddr_t base;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore} solo_regs_t;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoretypedef struct solo_engine {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore struct solo_dev *dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_engine_t *engine;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_dma_handle_t dmah;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_acc_handle_t acch;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore caddr_t kaddr;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint32_t paddr;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore bool started;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore bool trigger;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint64_t count;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint16_t offset;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore int syncdir;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore int format;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore bool swapped;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore void (*start)(struct solo_engine *);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore void (*stop)(struct solo_engine *);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore void (*update)(struct solo_engine *);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore} solo_engine_t;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoretypedef enum {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore CTL_FRONT = 0,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore CTL_VOLUME,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore CTL_MIC,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore CTL_LINE,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore CTL_CD,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore CTL_AUX,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore CTL_MONO,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore CTL_MICBOOST,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore CTL_RECGAIN,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore CTL_RECSRC,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore CTL_MONSRC,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore CTL_SPEAKER,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore CTL_LOOPBACK,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore CTL_NUM, /* must be last */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore} solo_ctrl_num_t;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoretypedef struct solo_ctrl {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore struct solo_dev *dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_ctrl_t *ctrl;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_ctrl_num_t num;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint64_t val;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore} solo_ctrl_t;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoretypedef struct solo_dev {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore dev_info_t *dip;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_t *adev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore kmutex_t mutex;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_intr_handle_t ihandle;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore bool suspended;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /*
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * Audio engines
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_engine_t rec;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_engine_t play;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint32_t last_capture;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /*
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * Controls.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_ctrl_t ctrls[CTL_NUM];
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /*
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * Mapped registers
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_acc_handle_t pcih;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_regs_t io;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_regs_t sb;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_regs_t vc;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore} solo_dev_t;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore/*
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * Common code for the pcm function
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore *
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * solo_cmd write a single byte to the CMD port.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * solo_cmd1 write a CMD + 1 byte arg
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * ess_get_byte returns a single byte from the DSP data port
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore *
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * solo_write is actually solo_cmd1
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * solo_read access ext. regs via solo_cmd(0xc0, reg) followed by solo_get_byte
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define PORT_RD8(port, regno) \
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_get8(port.acch, (void *)(port.base + (regno)))
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define PORT_RD16(port, regno) \
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_get16(port.acch, (void *)(port.base + (regno)))
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define PORT_RD32(port, regno) \
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_get32(port.acch, (void *)(port.base + (regno)))
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define PORT_WR8(port, regno, data) \
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_put8(port.acch, (void *)(port.base + (regno)), data)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define PORT_WR16(port, regno, data) \
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_put16(port.acch, (void *)(port.base + (regno)), data)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define PORT_WR32(port, regno, data) \
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_put32(port.acch, (void *)(port.base + (regno)), data)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic bool
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_dspready(solo_dev_t *dev)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return ((PORT_RD8(dev->sb, 0xc) & 0x80) == 0 ? true : false);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic bool
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_dspwr(solo_dev_t *dev, uint8_t val)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore int i;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore for (i = 0; i < 1000; i++) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (solo_dspready(dev)) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR8(dev->sb, 0xc, val);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (true);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (i > 10)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore drv_usecwait((i > 100)? 1000 : 10);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_warn(dev->adev, "solo_dspwr(0x%02x) timed out", val);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (false);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic bool
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_cmd(solo_dev_t *dev, uint8_t val)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (solo_dspwr(dev, val));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic void
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_cmd1(solo_dev_t *dev, uint8_t cmd, uint8_t val)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (solo_dspwr(dev, cmd)) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore (void) solo_dspwr(dev, val);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic void
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_setmixer(solo_dev_t *dev, uint8_t port, uint8_t value)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR8(dev->sb, 0x4, port); /* Select register */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore drv_usecwait(10);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR8(dev->sb, 0x5, value);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore drv_usecwait(10);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic uint8_t
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_getmixer(solo_dev_t *dev, uint8_t port)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint8_t val;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR8(dev->sb, 0x4, port); /* Select register */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore drv_usecwait(10);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore val = PORT_RD8(dev->sb, 0x5);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore drv_usecwait(10);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (val);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic uint8_t
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_get_byte(solo_dev_t *dev)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore for (int i = 1000; i > 0; i--) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (PORT_RD8(dev->sb, 0xc) & 0x40)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (PORT_RD8(dev->sb, 0xa));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore else
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore drv_usecwait(20);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_warn(dev->adev, "timeout waiting to read DSP port");
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (0xff);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic void
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_write(solo_dev_t *dev, uint8_t reg, uint8_t val)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_cmd1(dev, reg, val);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic uint8_t
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_read(solo_dev_t *dev, uint8_t reg)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (solo_cmd(dev, 0xc0) && solo_cmd(dev, reg)) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (solo_get_byte(dev));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (0xff);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic bool
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_reset_dsp(solo_dev_t *dev)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR8(dev->sb, 0x6, 3);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore drv_usecwait(100);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR8(dev->sb, 0x6, 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (solo_get_byte(dev) != 0xAA) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_warn(dev->adev, "solo_reset_dsp failed");
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (false); /* Sorry */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (true);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic uint_t
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_intr(caddr_t arg1, caddr_t arg2)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev = (void *)arg1;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint8_t status;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint_t rv = DDI_INTR_UNCLAIMED;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore _NOTE(ARGUNUSED(arg2));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_enter(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (dev->suspended) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_exit(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (rv);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore status = PORT_RD8(dev->io, 0x7);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (status & 0x20) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore rv = DDI_INTR_CLAIMED;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* ack the interrupt */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x7a, solo_getmixer(dev, 0x7a) & ~0x80);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (status & 0x10) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore rv = DDI_INTR_CLAIMED;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* ack the interrupt */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore (void) PORT_RD8(dev->sb, 0xe);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_exit(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (rv);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic uint8_t
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_mixer_scale(solo_dev_t *dev, solo_ctrl_num_t num)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint32_t l, r;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint64_t value = dev->ctrls[num].val;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore l = (value >> 8) & 0xff;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore r = value & 0xff;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore l = (l * 15) / 100;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore r = (r * 15) / 100;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return ((uint8_t)((l << 4) | (r)));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic void
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_configure_mixer(solo_dev_t *dev)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint32_t v;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint32_t mon, rec;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /*
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * We disable hardware volume control (i.e. async updates to volume).
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * We could in theory support this, but making it work right can be
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * tricky, and we doubt it is widely used.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x64, solo_getmixer(dev, 0x64) | 0xc);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x66, 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* master volume has 6 bits per channel, bit 6 indicates mute */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* left */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = (dev->ctrls[CTL_FRONT].val >> 8) & 0xff;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = v ? (v * 63) / 100 : 64;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x60, v & 0xff);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* right */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = dev->ctrls[CTL_FRONT].val & 0xff;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = v ? (v * 63) / 100 : 64;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x62, v & 0xff);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = solo_mixer_scale(dev, CTL_VOLUME);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = v | (v << 4);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x7c, v & 0xff);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x14, v & 0xff);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mon = dev->ctrls[CTL_MONSRC].val;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore rec = dev->ctrls[CTL_RECSRC].val;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /*
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * The Solo-1 has dual stereo mixers (one for input and one for output),
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * with separate volume controls for each.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = solo_mixer_scale(dev, CTL_MIC);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x68, rec & (1 << INPUT_MIC) ? v : 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x1a, mon & (1 << INPUT_MIC) ? v : 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = solo_mixer_scale(dev, CTL_LINE);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x6e, rec & (1 << INPUT_LINE) ? v : 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x3e, mon & (1 << INPUT_LINE) ? v : 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = solo_mixer_scale(dev, CTL_CD);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x6a, rec & (1 << INPUT_CD) ? v : 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x38, mon & (1 << INPUT_CD) ? v : 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = solo_mixer_scale(dev, CTL_AUX);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x6c, rec & (1 << INPUT_AUX) ? v : 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x3a, mon & (1 << INPUT_AUX) ? v : 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = solo_mixer_scale(dev, CTL_MONO);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = v | (v << 4);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x6f, rec & (1 << INPUT_MONO) ? v : 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x6d, mon & (1 << INPUT_MONO) ? v : 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (dev->ctrls[CTL_MICBOOST].val) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x7d, solo_getmixer(dev, 0x7d) | 0x8);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore } else {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x7d, solo_getmixer(dev, 0x7d) & ~(0x8));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = solo_mixer_scale(dev, CTL_RECGAIN);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = v | (v << 4);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_write(dev, 0xb4, v & 0xff);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = dev->ctrls[CTL_SPEAKER].val & 0xff;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = (v * 7) / 100;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x3c, v & 0xff);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (dev->ctrls[CTL_LOOPBACK].val) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* record-what-you-hear mode */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x1c, 0x3);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore } else {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* use record mixer */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x1c, 0x5);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic int
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_set_mixsrc(void *arg, uint64_t val)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_ctrl_t *pc = arg;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev = pc->dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if ((val & ~INSRCS) != 0)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (EINVAL);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_enter(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore pc->val = val;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore solo_configure_mixer(dev);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_exit(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic int
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_set_mono(void *arg, uint64_t val)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_ctrl_t *pc = arg;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev = pc->dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore val &= 0xff;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (val > 100)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (EINVAL);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore val = (val & 0xff) | ((val & 0xff) << 8);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_enter(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore pc->val = val;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore solo_configure_mixer(dev);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_exit(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic int
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_set_stereo(void *arg, uint64_t val)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_ctrl_t *pc = arg;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev = pc->dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint8_t l;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint8_t r;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore l = (val & 0xff00) >> 8;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore r = val & 0xff;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if ((l > 100) || (r > 100))
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (EINVAL);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_enter(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore pc->val = val;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore solo_configure_mixer(dev);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_exit(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic int
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_set_bool(void *arg, uint64_t val)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_ctrl_t *pc = arg;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev = pc->dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_enter(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore pc->val = val;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore solo_configure_mixer(dev);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_exit(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic int
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_get_value(void *arg, uint64_t *val)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_ctrl_t *pc = arg;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev = pc->dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_enter(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore *val = pc->val;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_exit(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define PLAYCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_PLAY)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define RECCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_REC)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define MONCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_MONITOR)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define PCMVOL (PLAYCTL | AUDIO_CTRL_FLAG_PCMVOL)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define MAINVOL (PLAYCTL | AUDIO_CTRL_FLAG_MAINVOL)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define RECVOL (RECCTL | AUDIO_CTRL_FLAG_RECVOL)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic void
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_alloc_ctrl(solo_dev_t *dev, uint32_t num, uint64_t val)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_ctrl_desc_t desc;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_ctrl_wr_t fn;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_ctrl_t *pc;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore bzero(&desc, sizeof (desc));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore pc = &dev->ctrls[num];
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore pc->num = num;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore pc->dev = dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore switch (num) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore case CTL_VOLUME:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_VOLUME;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_MONO;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_minvalue = 0;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_maxvalue = 100;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_flags = PCMVOL;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore fn = solo_set_mono;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore break;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore case CTL_FRONT:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_LINEOUT;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_minvalue = 0;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_maxvalue = 100;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_flags = MAINVOL;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore fn = solo_set_stereo;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore break;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore case CTL_SPEAKER:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_SPEAKER;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_MONO;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_minvalue = 0;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_maxvalue = 100;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_flags = MAINVOL;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore fn = solo_set_mono;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore break;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore case CTL_MIC:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_MIC;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_minvalue = 0;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_maxvalue = 100;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_flags = RECVOL;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore fn = solo_set_stereo;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore break;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore case CTL_LINE:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_LINEIN;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_minvalue = 0;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_maxvalue = 100;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_flags = RECVOL;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore fn = solo_set_stereo;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore break;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore case CTL_CD:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_CD;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_minvalue = 0;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_maxvalue = 100;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_flags = RECVOL;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore fn = solo_set_stereo;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore break;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore case CTL_AUX:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_AUX1IN;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_minvalue = 0;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_maxvalue = 100;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_flags = RECVOL;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore fn = solo_set_stereo;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore break;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore case CTL_MONO:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_AUX2IN;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_MONO;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_minvalue = 0;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_maxvalue = 100;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_flags = RECVOL;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore fn = solo_set_mono;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore break;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore case CTL_RECSRC:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_RECSRC;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_ENUM;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_minvalue = INSRCS;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_maxvalue = INSRCS;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_flags = RECCTL | AUDIO_CTRL_FLAG_MULTI;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore for (int i = 0; solo_insrcs[i]; i++) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_enum[i] = solo_insrcs[i];
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore fn = solo_set_mixsrc;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore break;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore case CTL_MONSRC:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_MONSRC;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_ENUM;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_minvalue = INSRCS;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_maxvalue = INSRCS;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_flags = MONCTL | AUDIO_CTRL_FLAG_MULTI;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore for (int i = 0; solo_insrcs[i]; i++) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_enum[i] = solo_insrcs[i];
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore fn = solo_set_mixsrc;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore break;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore case CTL_MICBOOST:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_MICBOOST;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_BOOLEAN;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_minvalue = 0;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_maxvalue = 1;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_flags = RECCTL;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore fn = solo_set_bool;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore break;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore case CTL_LOOPBACK:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_LOOPBACK;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_BOOLEAN;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_minvalue = 0;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_maxvalue = 1;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_flags = RECCTL;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore fn = solo_set_bool;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore break;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore case CTL_RECGAIN:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_name = AUDIO_CTRL_ID_RECGAIN;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_minvalue = 0;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_maxvalue = 100;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc.acd_flags = RECCTL;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore fn = solo_set_stereo;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore break;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore pc->val = val;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore pc->ctrl = audio_dev_add_control(dev->adev, &desc,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_get_value, fn, pc);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic bool
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_add_controls(solo_dev_t *dev)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_alloc_ctrl(dev, CTL_VOLUME, 0x4b);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_alloc_ctrl(dev, CTL_FRONT, 0x5a5a);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_alloc_ctrl(dev, CTL_SPEAKER, 0x4b);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_alloc_ctrl(dev, CTL_MIC, 0x3232);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_alloc_ctrl(dev, CTL_LINE, 0x4b4b);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_alloc_ctrl(dev, CTL_CD, 0x4b4b);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_alloc_ctrl(dev, CTL_AUX, 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_alloc_ctrl(dev, CTL_MONO, 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_alloc_ctrl(dev, CTL_RECSRC, (1U << INPUT_MIC));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_alloc_ctrl(dev, CTL_MONSRC, 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_alloc_ctrl(dev, CTL_RECGAIN, 0x4b4b);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_alloc_ctrl(dev, CTL_MICBOOST, 1);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_alloc_ctrl(dev, CTL_LOOPBACK, 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (true);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore/* utility functions for ESS */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic uint8_t
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_calcfilter(int spd)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore int cutoff;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore cutoff = (spd * 9 * 82) / 20;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (256 - (7160000 / cutoff));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic void
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_aud1_update(solo_engine_t *e)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev = e->dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint16_t offset, n;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint32_t ptr;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint32_t count;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint32_t diff;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore int tries;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ASSERT(mutex_owned(&dev->mutex));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /*
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * During recording, this register is known to give back
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * garbage if it's not quiescent while being read. This hack
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * attempts to work around it. We also suspend the DMA
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * while we do this, to minimize record distortion.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore if (e->trigger) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore drv_usecwait(20);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore }
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore for (tries = 10; tries; tries--) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore drv_usecwait(10);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ptr = PORT_RD32(dev->vc, 0);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore count = PORT_RD16(dev->vc, 4);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore diff = e->paddr + SOLO_BUFSZ - ptr - count;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore if ((diff > 3) || (ptr < e->paddr) ||
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore (ptr >= (e->paddr + SOLO_BUFSZ))) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ptr = dev->last_capture;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore } else {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore break;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore }
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore }
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore if (e->trigger) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore PORT_WR8(dev->vc, 0xf, 0); /* restart DMA */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore if (!tries) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore /*
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Note, this is a pretty bad situation, because we'll
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * not have an accurate idea of our position. But its
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * better than making a bad alteration. If we had FMA
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * for audio devices, this would be a good point to
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * raise a fault.
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore return;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore }
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore dev->last_capture = ptr;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore offset = ptr - e->paddr;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore offset /= (SOLO_NCHAN * SOLO_SAMPSZ);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore n = offset >= e->offset ?
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore offset - e->offset :
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore offset + SOLO_BUFSZ - e->offset;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->offset = offset;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->count += n / (SOLO_NCHAN * SOLO_SAMPSZ);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic void
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_aud1_start(solo_engine_t *e)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev = e->dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore int len;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint32_t v;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ASSERT(mutex_owned(&dev->mutex));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7f8098eddd24ef5d0d43749a8f4c2c245bdcc077Garrett D'Amore e->offset = 0;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore len = SOLO_FRAGSZ / 2;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore len = -len;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* sample rate - 48 kHz */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_write(dev, 0xa1, 0xf0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* filter cutoff */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_write(dev, 0xa2, solo_calcfilter(SOLO_RATE));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* mono/stereo - bit 0 set, bit 1 clear */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_write(dev, 0xa8, (solo_read(dev, 0xa8) & ~0x03) | 1);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore (void) solo_cmd(dev, 0xd3); /* turn off DAC1 output */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* setup fifo for signed 16-bit stereo */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_write(dev, 0xb7, 0x71);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_write(dev, 0xb7, 0xbc);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = solo_mixer_scale(dev, CTL_RECGAIN);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = v | (v << 4);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_write(dev, 0xb4, v & 0xff);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR8(dev->vc, 0x8, 0xc4); /* command */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR8(dev->vc, 0xd, 0xff); /* clear DMA */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR8(dev->vc, 0xf, 0x01); /* stop DMA */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR8(dev->vc, 0xd, 0xff); /* reset */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR8(dev->vc, 0xf, 0x01); /* mask */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR8(dev->vc, 0xb, 0x14); /* mode */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR32(dev->vc, 0x0, e->paddr);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR16(dev->vc, 0x4, SOLO_BUFSZ - 1);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* transfer length low, high */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_write(dev, 0xa4, len & 0x00ff);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_write(dev, 0xa5, (len & 0xff00) >> 8);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* autoinit, dma dir, go for it */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_write(dev, 0xb8, 0x0f);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR8(dev->vc, 0xf, 0); /* start DMA */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore dev->last_capture = e->paddr;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore e->trigger = true;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic void
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_aud1_stop(solo_engine_t *e)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev = e->dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* NB: We might be in quiesce, without a lock held */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_write(dev, 0xb8, solo_read(dev, 0xb8) & ~0x01);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore e->trigger = false;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic void
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_aud2_update(solo_engine_t *e)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev = e->dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint16_t offset = 0, n;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ASSERT(mutex_owned(&dev->mutex));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore offset = SOLO_BUFSZ - PORT_RD16(dev->io, 0x4);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore offset /= (SOLO_NCHAN * SOLO_SAMPSZ);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore n = offset >= e->offset ?
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore offset - e->offset :
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore offset + SOLO_BUFFR - e->offset;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->offset = offset;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->count += n;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic void
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_aud2_start(solo_engine_t *e)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev = e->dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore int len;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint32_t v;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ASSERT(mutex_owned(&dev->mutex));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7f8098eddd24ef5d0d43749a8f4c2c245bdcc077Garrett D'Amore e->offset = 0;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore len = SOLO_FRAGSZ / 2;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore len = -len;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* program transfer type */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x78, 0x10);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* sample rate - 48 kHz */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x70, 0xf0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x72, solo_calcfilter(SOLO_RATE));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* transfer length low & high */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x74, len & 0x00ff);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x76, (len & 0xff00) >> 8);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* enable irq, set signed 16-bit stereo format */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x7a, 0x47);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR8(dev->io, 0x6, 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR32(dev->io, 0x0, e->paddr);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR16(dev->io, 0x4, SOLO_BUFSZ);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* this crazy initialization appears to help with fifo weirdness */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* start the engine running */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x78, 0x92);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore drv_usecwait(10);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x78, 0x93);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR8(dev->io, 0x6, 0x0a); /* autoinit, enable */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = solo_mixer_scale(dev, CTL_VOLUME);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore v = v | (v << 4);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x7c, v & 0xff);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore e->trigger = true;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic void
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_aud2_stop(solo_engine_t *e)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev = e->dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* NB: We might be in quiesce, without a lock held */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR8(dev->io, 0x6, 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x78, solo_getmixer(dev, 0x78) & ~0x03);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore e->trigger = false;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore/*
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * Audio entry points.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic int
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_format(void *arg)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_engine_t *e = arg;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (e->format);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic int
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_channels(void *arg)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore _NOTE(ARGUNUSED(arg));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (SOLO_NCHAN);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic int
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_rate(void *arg)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore _NOTE(ARGUNUSED(arg));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (SOLO_RATE);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic void
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_chinfo(void *arg, int chan, unsigned *offset, unsigned *incr)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_engine_t *e = arg;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (e->swapped) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore *offset = !chan;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore } else {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore *offset = chan;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore *incr = 2;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic void
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_sync(void *arg, unsigned nframes)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_engine_t *e = arg;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore _NOTE(ARGUNUSED(nframes));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore (void) ddi_dma_sync(e->dmah, 0, 0, e->syncdir);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic uint64_t
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_count(void *arg)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_engine_t *e = arg;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev = e->dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint64_t count;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_enter(&dev->mutex);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore e->update(e);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore count = e->count;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_exit(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (count);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic int
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amoresolo_open(void *arg, int f, unsigned *nframes, caddr_t *buf)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_engine_t *e = arg;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev = e->dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore _NOTE(ARGUNUSED(f));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore *nframes = SOLO_NFRAGS * SOLO_FRAGFR;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore *buf = e->kaddr;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_enter(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->started = false;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->count = 0;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_exit(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorevoid
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_close(void *arg)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_engine_t *e = arg;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev = e->dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_enter(&dev->mutex);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore e->stop(e);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->started = false;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_exit(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic int
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_start(void *arg)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_engine_t *e = arg;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev = e->dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_enter(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (!e->started) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore e->start(e);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->started = true;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_exit(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic void
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_stop(void *arg)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_engine_t *e = arg;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev = e->dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_enter(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (e->started) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore e->stop(e);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->started = false;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_exit(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic audio_engine_ops_t solo_engine_ops = {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore AUDIO_ENGINE_VERSION,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_open,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_close,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_start,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_stop,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_count,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_format,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_channels,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_rate,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_sync,
f9ead4a57883f3ef04ef20d83cc47987d98c0687Garrett D'Amore NULL,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_chinfo,
f9ead4a57883f3ef04ef20d83cc47987d98c0687Garrett D'Amore NULL,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore};
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic void
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_release_resources(solo_dev_t *dev)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (dev->ihandle != NULL) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore (void) ddi_intr_disable(dev->ihandle);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore (void) ddi_intr_remove_handler(dev->ihandle);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore (void) ddi_intr_free(dev->ihandle);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_destroy(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (dev->io.acch != NULL) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_regs_map_free(&dev->io.acch);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (dev->sb.acch != NULL) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_regs_map_free(&dev->sb.acch);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (dev->vc.acch != NULL) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_regs_map_free(&dev->vc.acch);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (dev->pcih != NULL) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore pci_config_teardown(&dev->pcih);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* release play resources */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (dev->play.paddr != 0)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore (void) ddi_dma_unbind_handle(dev->play.dmah);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (dev->play.acch != NULL)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_dma_mem_free(&dev->play.acch);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (dev->play.dmah != NULL)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_dma_free_handle(&dev->play.dmah);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (dev->play.engine != NULL) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_remove_engine(dev->adev, dev->play.engine);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_engine_free(dev->play.engine);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* release record resources */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (dev->rec.paddr != 0)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore (void) ddi_dma_unbind_handle(dev->rec.dmah);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (dev->rec.acch != NULL)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_dma_mem_free(&dev->rec.acch);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (dev->rec.dmah != NULL)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_dma_free_handle(&dev->rec.dmah);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (dev->rec.engine != NULL) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_remove_engine(dev->adev, dev->rec.engine);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_engine_free(dev->rec.engine);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7f8098eddd24ef5d0d43749a8f4c2c245bdcc077Garrett D'Amore for (int i = 0; i < CTL_NUM; i++) {
7f8098eddd24ef5d0d43749a8f4c2c245bdcc077Garrett D'Amore if (dev->ctrls[i].ctrl != NULL) {
7f8098eddd24ef5d0d43749a8f4c2c245bdcc077Garrett D'Amore audio_dev_del_control(dev->ctrls[i].ctrl);
7f8098eddd24ef5d0d43749a8f4c2c245bdcc077Garrett D'Amore }
7f8098eddd24ef5d0d43749a8f4c2c245bdcc077Garrett D'Amore }
7f8098eddd24ef5d0d43749a8f4c2c245bdcc077Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (dev->adev != NULL) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_free(dev->adev);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore kmem_free(dev, sizeof (*dev));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic bool
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_setup_interrupts(solo_dev_t *dev)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore int actual;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint_t ipri;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if ((ddi_intr_alloc(dev->dip, &dev->ihandle, DDI_INTR_TYPE_FIXED,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0, 1, &actual, DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) ||
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore (actual != 1)) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_warn(dev->adev, "can't alloc intr handle");
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (false);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (ddi_intr_get_pri(dev->ihandle, &ipri) != DDI_SUCCESS) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_warn(dev->adev, "can't determine intr priority");
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore (void) ddi_intr_free(dev->ihandle);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore dev->ihandle = NULL;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (false);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (ddi_intr_add_handler(dev->ihandle, solo_intr, dev,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore NULL) != DDI_SUCCESS) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_warn(dev->adev, "can't add intr handler");
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore (void) ddi_intr_free(dev->ihandle);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore dev->ihandle = NULL;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (false);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (true);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic bool
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_map_registers(solo_dev_t *dev)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore dev_info_t *dip = dev->dip;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* map registers */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (ddi_regs_map_setup(dip, 1, &dev->io.base, 0, 0, &acc_attr,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore &dev->io.acch) != DDI_SUCCESS) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_warn(dev->adev, "can't map IO registers");
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (false);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (ddi_regs_map_setup(dip, 2, &dev->sb.base, 0, 0, &acc_attr,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore &dev->sb.acch) != DDI_SUCCESS) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_warn(dev->adev, "can't map SB registers");
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (false);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (ddi_regs_map_setup(dip, 3, &dev->vc.base, 0, 0, &acc_attr,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore &dev->vc.acch) != DDI_SUCCESS) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_warn(dev->adev, "can't map VC registers");
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (false);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (true);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define ESS_PCI_LEGACYCONTROL 0x40
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define ESS_PCI_CONFIG 0x50
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore#define ESS_PCI_DDMACONTROL 0x60
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic bool
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_init_hw(solo_dev_t *dev)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint32_t data;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /*
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * Legacy audio register -- disable legacy audio. We also
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * arrange for 16-bit I/O address decoding.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* this version disables the MPU, FM synthesis (Adlib), and Game Port */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore pci_config_put16(dev->pcih, ESS_PCI_LEGACYCONTROL, 0x8041);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /*
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * Note that Solo-1 uses I/O space for all BARs, and hardwires
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * the upper 32-bits to zero.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore data = pci_config_get32(dev->pcih, PCI_CONF_BASE2);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore data |= 1;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore pci_config_put16(dev->pcih, ESS_PCI_DDMACONTROL, data & 0xffff);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /*
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * Make sure that legacy IRQ and DRQ are disbled. We disable most
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * other legacy features too.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore pci_config_put16(dev->pcih, ESS_PCI_CONFIG, 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (!solo_reset_dsp(dev))
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (false);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* enable extended mode */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore (void) solo_cmd(dev, 0xc6);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR8(dev->io, 0x7, 0x30); /* enable audio irqs */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* demand mode, 4 bytes/xfer */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_write(dev, 0xb9, 0x01);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /*
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * This sets Audio 2 (playback) to use its own independent
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * rate control, and gives us 48 kHz compatible divisors. It
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * also bypasses the switched capacitor filter.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0x71, 0x2a);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* irq control */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_write(dev, 0xb1, (solo_read(dev, 0xb1) & 0x0f) | 0x50);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* drq control */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_write(dev, 0xb2, (solo_read(dev, 0xb2) & 0x0f) | 0x50);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0, 0); /* reset mixer settings */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_configure_mixer(dev);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (true);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic bool
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_alloc_engine(solo_dev_t *dev, int engno)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore size_t rlen;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_dma_attr_t *dattr;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_dma_cookie_t c;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore unsigned ccnt;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore unsigned caps;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore unsigned dflags;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore const char *desc;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_engine_t *e;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ASSERT((engno == 1) || (engno = 2));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore switch (engno) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore case 1: /* record */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e = &dev->rec;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc = "record";
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore dattr = &dma_attr_audio1;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore caps = ENGINE_INPUT_CAP;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore dflags = DDI_DMA_READ | DDI_DMA_CONSISTENT;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->syncdir = DDI_DMA_SYNC_FORKERNEL;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->update = solo_aud1_update;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->start = solo_aud1_start;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->stop = solo_aud1_stop;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->format = AUDIO_FORMAT_S16_BE;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->swapped = true;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore break;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore case 2: /* playback */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e = &dev->play;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore desc = "playback";
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore dattr = &dma_attr_audio2;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore caps = ENGINE_OUTPUT_CAP;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore dflags = DDI_DMA_WRITE | DDI_DMA_CONSISTENT;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->syncdir = DDI_DMA_SYNC_FORDEV;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->update = solo_aud2_update;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->start = solo_aud2_start;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->stop = solo_aud2_stop;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->format = AUDIO_FORMAT_S16_LE;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->swapped = false;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore break;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore default:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_warn(dev->adev, "bad engine number!");
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (false);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->dev = dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (ddi_dma_alloc_handle(dev->dip, dattr, DDI_DMA_SLEEP, NULL,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore &e->dmah) != DDI_SUCCESS) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_warn(dev->adev, "%s dma handle alloc failed", desc);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (false);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (ddi_dma_mem_alloc(e->dmah, SOLO_BUFSZ, &buf_attr,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &e->kaddr,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore &rlen, &e->acch) != DDI_SUCCESS) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_warn(dev->adev, "%s dma memory alloc failed", desc);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (false);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* ensure that the buffer is zeroed out properly */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore bzero(e->kaddr, rlen);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (ddi_dma_addr_bind_handle(e->dmah, NULL, e->kaddr, SOLO_BUFSZ,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore dflags, DDI_DMA_SLEEP, NULL, &c, &ccnt) != DDI_DMA_MAPPED) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_warn(dev->adev, "%s dma binding failed", desc);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (false);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->paddr = c.dmac_address;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /*
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore * Allocate and configure audio engine.
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore e->engine = audio_engine_alloc(&solo_engine_ops, caps);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (e->engine == NULL) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_warn(dev->adev, "record audio_engine_alloc failed");
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (false);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_engine_set_private(e->engine, e);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_add_engine(dev->adev, e->engine);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (true);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic int
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_suspend(solo_dev_t *dev)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audio_dev_suspend(dev->adev);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_enter(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore dev->suspended = true;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_exit(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (DDI_SUCCESS);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic int
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_resume(solo_dev_t *dev)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_enter(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (!solo_init_hw(dev)) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore /* yikes! */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_warn(dev->adev, "unable to resume audio!");
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_warn(dev->adev, "reboot or reload driver to reset");
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore dev->suspended = false;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore mutex_exit(&dev->mutex);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audio_dev_resume(dev->adev);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (DDI_SUCCESS);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic int
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_attach(dev_info_t *dip)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore uint32_t data;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore dev = kmem_zalloc(sizeof (*dev), KM_SLEEP);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore dev->dip = dip;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_set_driver_private(dip, dev);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore dev->adev = audio_dev_alloc(dip, 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (dev->adev == NULL)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore goto no;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_set_description(dev->adev, "ESS Solo-1 PCI AudioDrive");
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_set_version(dev->adev, "ES1938");
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (pci_config_setup(dip, &dev->pcih) != DDI_SUCCESS) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_warn(NULL, "pci_config_setup failed");
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore goto no;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore data = pci_config_get16(dev->pcih, PCI_CONF_COMM);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore data |= PCI_COMM_ME | PCI_COMM_IO;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore pci_config_put16(dev->pcih, PCI_CONF_COMM, data);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if ((!solo_map_registers(dev)) ||
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore (!solo_setup_interrupts(dev)) ||
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore (!solo_alloc_engine(dev, 1)) ||
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore (!solo_alloc_engine(dev, 2)) ||
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore (!solo_add_controls(dev)) ||
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore (!solo_init_hw(dev))) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore goto no;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (audio_dev_register(dev->adev) != DDI_SUCCESS) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_dev_warn(dev->adev,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore "unable to register with audio framework");
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore goto no;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore (void) ddi_intr_enable(dev->ihandle);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore ddi_report_dev(dip);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (DDI_SUCCESS);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoreno:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_release_resources(dev);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (DDI_FAILURE);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic int
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_detach(solo_dev_t *dev)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if (audio_dev_unregister(dev->adev) != DDI_SUCCESS) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (DDI_FAILURE);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_release_resources(dev);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (DDI_SUCCESS);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic int
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore switch (cmd) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore case DDI_ATTACH:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (solo_attach(dip));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore case DDI_RESUME:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if ((dev = ddi_get_driver_private(dip)) == NULL) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (DDI_FAILURE);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (solo_resume(dev));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore default:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (DDI_FAILURE);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic int
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if ((dev = ddi_get_driver_private(dip)) == NULL) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (DDI_FAILURE);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore switch (cmd) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore case DDI_DETACH:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (solo_detach(dev));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore case DDI_SUSPEND:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (solo_suspend(dev));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore default:
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (DDI_FAILURE);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic int
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoresolo_quiesce(dev_info_t *dip)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_dev_t *dev;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore dev = ddi_get_driver_private(dip);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_aud1_stop(&dev->rec);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_aud2_stop(&dev->play);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_setmixer(dev, 0, 0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore PORT_WR8(dev->io, 0x7, 0); /* disable all irqs */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (0);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestruct dev_ops solo_dev_ops = {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore DEVO_REV, /* rev */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore 0, /* refcnt */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore NULL, /* getinfo */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore nulldev, /* identify */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore nulldev, /* probe */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_ddi_attach, /* attach */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_ddi_detach, /* detach */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore nodev, /* reset */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore NULL, /* cb_ops */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore NULL, /* bus_ops */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore NULL, /* power */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore solo_quiesce, /* quiesce */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore};
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic struct modldrv solo_modldrv = {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore &mod_driverops, /* drv_modops */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore "ESS Solo-1 Audio", /* linkinfo */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore &solo_dev_ops, /* dev_ops */
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore};
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amorestatic struct modlinkage modlinkage = {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore MODREV_1,
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore { &solo_modldrv, NULL }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore};
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoreint
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore_init(void)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore int rv;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_init_ops(&solo_dev_ops, DRVNAME);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if ((rv = mod_install(&modlinkage)) != 0) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_fini_ops(&solo_dev_ops);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (rv);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoreint
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore_fini(void)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore int rv;
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore if ((rv = mod_remove(&modlinkage)) == 0) {
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore audio_fini_ops(&solo_dev_ops);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore }
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (rv);
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amoreint
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore_info(struct modinfo *modinfop)
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore{
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore return (mod_info(&modlinkage, modinfop));
7a4f122cf63a91c2888629e433b5f5ee7536a802Garrett D'Amore}