188447a05SGarrett D'Amore /* 288447a05SGarrett D'Amore * CDDL HEADER START 388447a05SGarrett D'Amore * 488447a05SGarrett D'Amore * The contents of this file are subject to the terms of the 588447a05SGarrett D'Amore * Common Development and Distribution License (the "License"). 688447a05SGarrett D'Amore * You may not use this file except in compliance with the License. 788447a05SGarrett D'Amore * 888447a05SGarrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 988447a05SGarrett D'Amore * or http://www.opensolaris.org/os/licensing. 1088447a05SGarrett D'Amore * See the License for the specific language governing permissions 1188447a05SGarrett D'Amore * and limitations under the License. 1288447a05SGarrett D'Amore * 1388447a05SGarrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each 1488447a05SGarrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1588447a05SGarrett D'Amore * If applicable, add the following below this CDDL HEADER, with the 1688447a05SGarrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying 1788447a05SGarrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner] 1888447a05SGarrett D'Amore * 1988447a05SGarrett D'Amore * CDDL HEADER END 2088447a05SGarrett D'Amore */ 2188447a05SGarrett D'Amore /* 22*239924d3SGarrett D'Amore * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 2388447a05SGarrett D'Amore */ 2488447a05SGarrett D'Amore /* 2588447a05SGarrett D'Amore * Purpose: Creative/Ensoniq AudioPCI97 driver (ES1371/ES1373) 2688447a05SGarrett D'Amore * 2788447a05SGarrett D'Amore * This driver is used with the original Ensoniq AudioPCI97 card and many 2888447a05SGarrett D'Amore * PCI based Sound Blaster cards by Creative Technologies. For example 2988447a05SGarrett D'Amore * Sound Blaster PCI128 and Creative/Ectiva EV1938. 3088447a05SGarrett D'Amore */ 3188447a05SGarrett D'Amore 3288447a05SGarrett D'Amore /* 3388447a05SGarrett D'Amore * This file is part of Open Sound System 3488447a05SGarrett D'Amore * 3588447a05SGarrett D'Amore * Copyright (C) 4Front Technologies 1996-2008. 3688447a05SGarrett D'Amore * 3788447a05SGarrett D'Amore * This software is released under CDDL 1.0 source license. 3888447a05SGarrett D'Amore * See the COPYING file included in the main directory of this source 3988447a05SGarrett D'Amore * distribution for the license terms and conditions. 4088447a05SGarrett D'Amore */ 4188447a05SGarrett D'Amore 4288447a05SGarrett D'Amore #include <sys/audio/audio_driver.h> 4388447a05SGarrett D'Amore #include <sys/audio/ac97.h> 4488447a05SGarrett D'Amore #include <sys/note.h> 4588447a05SGarrett D'Amore #include <sys/pci.h> 4688447a05SGarrett D'Amore #include "audioens.h" 4788447a05SGarrett D'Amore 4888447a05SGarrett D'Amore /* 4988447a05SGarrett D'Amore * Set the latency to 32, 64, 96, 128 clocks - some APCI97 devices exhibit 5088447a05SGarrett D'Amore * garbled audio in some cases and setting the latency to higer values fixes it 5188447a05SGarrett D'Amore * Values: 32, 64, 96, 128 - Default: 64 (or defined by bios) 5288447a05SGarrett D'Amore */ 5388447a05SGarrett D'Amore int audioens_latency = 0; 5488447a05SGarrett D'Amore 5588447a05SGarrett D'Amore /* 5688447a05SGarrett D'Amore * Enable SPDIF port on SoundBlaster 128D or Sound Blaster Digital-4.1 models 5788447a05SGarrett D'Amore * Values: 1=Enable 0=Disable Default: 0 5888447a05SGarrett D'Amore */ 5988447a05SGarrett D'Amore int audioens_spdif = 0; 6088447a05SGarrett D'Amore 6188447a05SGarrett D'Amore /* 6288447a05SGarrett D'Amore * Note: Latest devices can support SPDIF with AC3 pass thru. 6388447a05SGarrett D'Amore * However, in order to do this, one of the two DMA engines must be 6488447a05SGarrett D'Amore * dedicated to this, which would prevent the card from supporting 4 6588447a05SGarrett D'Amore * channel audio. For now we don't bother with the AC3 pass through 6688447a05SGarrett D'Amore * mode, and instead just focus on 4 channel support. In the future, 6788447a05SGarrett D'Amore * this could be selectable via a property. 6888447a05SGarrett D'Amore */ 6988447a05SGarrett D'Amore 7088447a05SGarrett D'Amore #define ENSONIQ_VENDOR_ID 0x1274 7188447a05SGarrett D'Amore #define CREATIVE_VENDOR_ID 0x1102 7288447a05SGarrett D'Amore #define ECTIVA_VENDOR_ID 0x1102 7388447a05SGarrett D'Amore #define ENSONIQ_ES1371 0x1371 7488447a05SGarrett D'Amore #define ENSONIQ_ES5880 0x8001 7588447a05SGarrett D'Amore #define ENSONIQ_ES5880A 0x8002 7688447a05SGarrett D'Amore #define ENSONIQ_ES5880B 0x5880 7788447a05SGarrett D'Amore #define ECTIVA_ES1938 0x8938 7888447a05SGarrett D'Amore 7988447a05SGarrett D'Amore #define DEFRATE 48000 8088447a05SGarrett D'Amore #define DRVNAME "audioens" 8188447a05SGarrett D'Amore 8288447a05SGarrett D'Amore typedef struct audioens_port 8388447a05SGarrett D'Amore { 8488447a05SGarrett D'Amore /* Audio parameters */ 8588447a05SGarrett D'Amore int speed; 8688447a05SGarrett D'Amore 8788447a05SGarrett D'Amore int num; 8888447a05SGarrett D'Amore #define PORT_DAC 0 8988447a05SGarrett D'Amore #define PORT_ADC 1 9088447a05SGarrett D'Amore #define PORT_MAX PORT_ADC 9188447a05SGarrett D'Amore 9288447a05SGarrett D'Amore caddr_t kaddr; 9388447a05SGarrett D'Amore uint32_t paddr; 9488447a05SGarrett D'Amore ddi_acc_handle_t acch; 9588447a05SGarrett D'Amore ddi_dma_handle_t dmah; 9688447a05SGarrett D'Amore int nchan; 9788447a05SGarrett D'Amore unsigned nframes; 9888447a05SGarrett D'Amore unsigned frameno; 9988447a05SGarrett D'Amore uint64_t count; 10088447a05SGarrett D'Amore 10188447a05SGarrett D'Amore struct audioens_dev *dev; 10288447a05SGarrett D'Amore audio_engine_t *engine; 10388447a05SGarrett D'Amore } audioens_port_t; 10488447a05SGarrett D'Amore 10588447a05SGarrett D'Amore typedef struct audioens_dev 10688447a05SGarrett D'Amore { 10788447a05SGarrett D'Amore audio_dev_t *osdev; 10888447a05SGarrett D'Amore kmutex_t mutex; 10988447a05SGarrett D'Amore uint16_t devid; 11088447a05SGarrett D'Amore uint8_t revision; 11188447a05SGarrett D'Amore dev_info_t *dip; 11288447a05SGarrett D'Amore 11388447a05SGarrett D'Amore audioens_port_t port[PORT_MAX + 1]; 11488447a05SGarrett D'Amore 11588447a05SGarrett D'Amore ac97_t *ac97; 11688447a05SGarrett D'Amore 11788447a05SGarrett D'Amore caddr_t regs; 11888447a05SGarrett D'Amore ddi_acc_handle_t acch; 11988447a05SGarrett D'Amore } audioens_dev_t; 12088447a05SGarrett D'Amore 12188447a05SGarrett D'Amore static ddi_device_acc_attr_t acc_attr = { 12288447a05SGarrett D'Amore DDI_DEVICE_ATTR_V0, 12388447a05SGarrett D'Amore DDI_STRUCTURE_LE_ACC, 12488447a05SGarrett D'Amore DDI_STRICTORDER_ACC 12588447a05SGarrett D'Amore }; 12688447a05SGarrett D'Amore 12788447a05SGarrett D'Amore static ddi_device_acc_attr_t buf_attr = { 12888447a05SGarrett D'Amore DDI_DEVICE_ATTR_V0, 12988447a05SGarrett D'Amore DDI_NEVERSWAP_ACC, 13088447a05SGarrett D'Amore DDI_STRICTORDER_ACC 13188447a05SGarrett D'Amore }; 13288447a05SGarrett D'Amore 13388447a05SGarrett D'Amore /* 13488447a05SGarrett D'Amore * The hardware appears to be able to address up to 16-bits worth of longwords, 13568c47f65SGarrett D'Amore * giving a total address space of 256K. But we need substantially less. 13688447a05SGarrett D'Amore */ 13768c47f65SGarrett D'Amore #define AUDIOENS_BUF_LEN (16384) 13888447a05SGarrett D'Amore 13988447a05SGarrett D'Amore static ddi_dma_attr_t dma_attr = { 14088447a05SGarrett D'Amore DMA_ATTR_VERSION, /* dma_attr_version */ 14188447a05SGarrett D'Amore 0x0, /* dma_attr_addr_lo */ 14288447a05SGarrett D'Amore 0xffffffffU, /* dma_attr_addr_hi */ 14388447a05SGarrett D'Amore 0x3ffff, /* dma_attr_count_max */ 14488447a05SGarrett D'Amore 0x8, /* dma_attr_align */ 14588447a05SGarrett D'Amore 0x7f, /* dma_attr_burstsizes */ 14688447a05SGarrett D'Amore 0x1, /* dma_attr_minxfer */ 14788447a05SGarrett D'Amore 0x3ffff, /* dma_attr_maxxfer */ 14888447a05SGarrett D'Amore 0x3ffff, /* dma_attr_seg */ 14988447a05SGarrett D'Amore 0x1, /* dma_attr_sgllen */ 15088447a05SGarrett D'Amore 0x1, /* dma_attr_granular */ 15188447a05SGarrett D'Amore 0 /* dma_attr_flags */ 15288447a05SGarrett D'Amore }; 15388447a05SGarrett D'Amore 15488447a05SGarrett D'Amore #define GET8(dev, offset) \ 15588447a05SGarrett D'Amore ddi_get8(dev->acch, (uint8_t *)(dev->regs + (offset))) 15688447a05SGarrett D'Amore #define GET16(dev, offset) \ 15788447a05SGarrett D'Amore ddi_get16(dev->acch, (uint16_t *)(void *)(dev->regs + (offset))) 15888447a05SGarrett D'Amore #define GET32(dev, offset) \ 15988447a05SGarrett D'Amore ddi_get32(dev->acch, (uint32_t *)(void *)(dev->regs + (offset))) 16088447a05SGarrett D'Amore #define PUT8(dev, offset, v) \ 16188447a05SGarrett D'Amore ddi_put8(dev->acch, (uint8_t *)(dev->regs + (offset)), v) 16288447a05SGarrett D'Amore #define PUT16(dev, offset, v) \ 16388447a05SGarrett D'Amore ddi_put16(dev->acch, (uint16_t *)(void *)(dev->regs + (offset)), v) 16488447a05SGarrett D'Amore #define PUT32(dev, offset, v) \ 16588447a05SGarrett D'Amore ddi_put32(dev->acch, (uint32_t *)(void *)(dev->regs + (offset)), v) 16688447a05SGarrett D'Amore 16788447a05SGarrett D'Amore #define CLR8(dev, offset, v) PUT8(dev, offset, GET8(dev, offset) & ~(v)) 16888447a05SGarrett D'Amore #define SET8(dev, offset, v) PUT8(dev, offset, GET8(dev, offset) | (v)) 16988447a05SGarrett D'Amore #define CLR32(dev, offset, v) PUT32(dev, offset, GET32(dev, offset) & ~(v)) 17088447a05SGarrett D'Amore #define SET32(dev, offset, v) PUT32(dev, offset, GET32(dev, offset) | (v)) 17188447a05SGarrett D'Amore 17288447a05SGarrett D'Amore static void audioens_init_hw(audioens_dev_t *); 17388447a05SGarrett D'Amore 17488447a05SGarrett D'Amore static uint16_t 17588447a05SGarrett D'Amore audioens_rd97(void *dev_, uint8_t wAddr) 17688447a05SGarrett D'Amore { 17788447a05SGarrett D'Amore audioens_dev_t *dev = dev_; 17888447a05SGarrett D'Amore int i, dtemp; 17988447a05SGarrett D'Amore 18088447a05SGarrett D'Amore mutex_enter(&dev->mutex); 18188447a05SGarrett D'Amore dtemp = GET32(dev, CONC_dCODECCTL_OFF); 18288447a05SGarrett D'Amore /* wait for WIP to go away saving the current state for later */ 18388447a05SGarrett D'Amore for (i = 0; i < 0x100UL; ++i) { 18488447a05SGarrett D'Amore dtemp = GET32(dev, CONC_dCODECCTL_OFF); 18588447a05SGarrett D'Amore if ((dtemp & (1UL << 30)) == 0) 18688447a05SGarrett D'Amore break; 18788447a05SGarrett D'Amore } 18888447a05SGarrett D'Amore 18988447a05SGarrett D'Amore /* write addr w/data=0 and assert read request ... */ 19088447a05SGarrett D'Amore PUT32(dev, CONC_dCODECCTL_OFF, ((int)wAddr << 16) | (1UL << 23)); 19188447a05SGarrett D'Amore 19288447a05SGarrett D'Amore /* now wait for the data (RDY) */ 19388447a05SGarrett D'Amore for (i = 0; i < 0x100UL; ++i) { 19488447a05SGarrett D'Amore dtemp = GET32(dev, CONC_dCODECCTL_OFF); 19588447a05SGarrett D'Amore if (dtemp & (1UL << 31)) 19688447a05SGarrett D'Amore break; 19788447a05SGarrett D'Amore } 19888447a05SGarrett D'Amore dtemp = GET32(dev, CONC_dCODECCTL_OFF); 19988447a05SGarrett D'Amore mutex_exit(&dev->mutex); 20088447a05SGarrett D'Amore 20188447a05SGarrett D'Amore return (dtemp & 0xffff); 20288447a05SGarrett D'Amore } 20388447a05SGarrett D'Amore 20488447a05SGarrett D'Amore static void 20588447a05SGarrett D'Amore audioens_wr97(void *dev_, uint8_t wAddr, uint16_t wData) 20688447a05SGarrett D'Amore { 20788447a05SGarrett D'Amore audioens_dev_t *dev = dev_; 20888447a05SGarrett D'Amore int i, dtemp; 20988447a05SGarrett D'Amore 21088447a05SGarrett D'Amore mutex_enter(&dev->mutex); 21188447a05SGarrett D'Amore /* wait for WIP to go away */ 21288447a05SGarrett D'Amore for (i = 0; i < 0x100UL; ++i) { 21388447a05SGarrett D'Amore dtemp = GET32(dev, CONC_dCODECCTL_OFF); 21488447a05SGarrett D'Amore if ((dtemp & (1UL << 30)) == 0) 21588447a05SGarrett D'Amore break; 21688447a05SGarrett D'Amore } 21788447a05SGarrett D'Amore 21888447a05SGarrett D'Amore PUT32(dev, CONC_dCODECCTL_OFF, ((int)wAddr << 16) | wData); 21988447a05SGarrett D'Amore 22088447a05SGarrett D'Amore mutex_exit(&dev->mutex); 22188447a05SGarrett D'Amore } 22288447a05SGarrett D'Amore 22388447a05SGarrett D'Amore static unsigned short 22488447a05SGarrett D'Amore SRCRegRead(audioens_dev_t *dev, unsigned short reg) 22588447a05SGarrett D'Amore { 22688447a05SGarrett D'Amore int i, dtemp; 22788447a05SGarrett D'Amore 22888447a05SGarrett D'Amore dtemp = GET32(dev, CONC_dSRCIO_OFF); 22988447a05SGarrett D'Amore /* wait for ready */ 23088447a05SGarrett D'Amore for (i = 0; i < SRC_IOPOLL_COUNT; ++i) { 23188447a05SGarrett D'Amore dtemp = GET32(dev, CONC_dSRCIO_OFF); 23288447a05SGarrett D'Amore if ((dtemp & SRC_BUSY) == 0) 23388447a05SGarrett D'Amore break; 23488447a05SGarrett D'Amore } 23588447a05SGarrett D'Amore 23688447a05SGarrett D'Amore /* assert a read request */ 23788447a05SGarrett D'Amore PUT32(dev, CONC_dSRCIO_OFF, (dtemp & SRC_CTLMASK) | ((int)reg << 25)); 23888447a05SGarrett D'Amore 23988447a05SGarrett D'Amore /* now wait for the data */ 24088447a05SGarrett D'Amore for (i = 0; i < SRC_IOPOLL_COUNT; ++i) { 24188447a05SGarrett D'Amore dtemp = GET32(dev, CONC_dSRCIO_OFF); 24288447a05SGarrett D'Amore if ((dtemp & SRC_BUSY) == 0) 24388447a05SGarrett D'Amore break; 24488447a05SGarrett D'Amore } 24588447a05SGarrett D'Amore 24688447a05SGarrett D'Amore return ((unsigned short) dtemp); 24788447a05SGarrett D'Amore } 24888447a05SGarrett D'Amore 24988447a05SGarrett D'Amore static void 25088447a05SGarrett D'Amore SRCRegWrite(audioens_dev_t *dev, unsigned short reg, unsigned short val) 25188447a05SGarrett D'Amore { 25288447a05SGarrett D'Amore int i, dtemp; 25388447a05SGarrett D'Amore int writeval; 25488447a05SGarrett D'Amore 25588447a05SGarrett D'Amore dtemp = GET32(dev, CONC_dSRCIO_OFF); 25688447a05SGarrett D'Amore /* wait for ready */ 25788447a05SGarrett D'Amore for (i = 0; i < SRC_IOPOLL_COUNT; ++i) { 25888447a05SGarrett D'Amore dtemp = GET32(dev, CONC_dSRCIO_OFF); 25988447a05SGarrett D'Amore if ((dtemp & SRC_BUSY) == 0) 26088447a05SGarrett D'Amore break; 26188447a05SGarrett D'Amore } 26288447a05SGarrett D'Amore 26388447a05SGarrett D'Amore /* assert the write request */ 26488447a05SGarrett D'Amore writeval = (dtemp & SRC_CTLMASK) | SRC_WENABLE | 26588447a05SGarrett D'Amore ((int)reg << 25) | val; 26688447a05SGarrett D'Amore PUT32(dev, CONC_dSRCIO_OFF, writeval); 26788447a05SGarrett D'Amore } 26888447a05SGarrett D'Amore 26988447a05SGarrett D'Amore static void 27088447a05SGarrett D'Amore SRCSetRate(audioens_dev_t *dev, unsigned char base, unsigned short rate) 27188447a05SGarrett D'Amore { 27288447a05SGarrett D'Amore int i, freq, dtemp; 27388447a05SGarrett D'Amore unsigned short N, truncM, truncStart; 27488447a05SGarrett D'Amore 27588447a05SGarrett D'Amore if (base != SRC_ADC_BASE) { 27688447a05SGarrett D'Amore /* freeze the channel */ 27788447a05SGarrett D'Amore dtemp = (base == SRC_DAC1_BASE) ? 27888447a05SGarrett D'Amore SRC_DAC1FREEZE : SRC_DAC2FREEZE; 27988447a05SGarrett D'Amore for (i = 0; i < SRC_IOPOLL_COUNT; ++i) { 28088447a05SGarrett D'Amore if (!(GET32(dev, CONC_dSRCIO_OFF) & SRC_BUSY)) 28188447a05SGarrett D'Amore break; 28288447a05SGarrett D'Amore } 28388447a05SGarrett D'Amore PUT32(dev, CONC_dSRCIO_OFF, 28488447a05SGarrett D'Amore (GET32(dev, CONC_dSRCIO_OFF) & SRC_CTLMASK) | dtemp); 28588447a05SGarrett D'Amore 28688447a05SGarrett D'Amore /* calculate new frequency and write it - preserve accum */ 28788447a05SGarrett D'Amore freq = ((int)rate << 16) / 3000U; 28888447a05SGarrett D'Amore SRCRegWrite(dev, (unsigned short) base + SRC_INT_REGS_OFF, 28988447a05SGarrett D'Amore (SRCRegRead(dev, (unsigned short) base + SRC_INT_REGS_OFF) 29088447a05SGarrett D'Amore & 0x00ffU) | ((unsigned short) (freq >> 6) & 0xfc00)); 29188447a05SGarrett D'Amore SRCRegWrite(dev, (unsigned short) base + SRC_VFREQ_FRAC_OFF, 29288447a05SGarrett D'Amore (unsigned short) freq >> 1); 29388447a05SGarrett D'Amore 29488447a05SGarrett D'Amore /* un-freeze the channel */ 29588447a05SGarrett D'Amore for (i = 0; i < SRC_IOPOLL_COUNT; ++i) 29688447a05SGarrett D'Amore if (!(GET32(dev, CONC_dSRCIO_OFF) & SRC_BUSY)) 29788447a05SGarrett D'Amore break; 29888447a05SGarrett D'Amore PUT32(dev, CONC_dSRCIO_OFF, 29988447a05SGarrett D'Amore (GET32(dev, CONC_dSRCIO_OFF) & SRC_CTLMASK) & ~dtemp); 30088447a05SGarrett D'Amore } else { 30188447a05SGarrett D'Amore /* derive oversample ratio */ 30288447a05SGarrett D'Amore N = rate / 3000U; 30388447a05SGarrett D'Amore if (N == 15 || N == 13 || N == 11 || N == 9) 30488447a05SGarrett D'Amore --N; 30588447a05SGarrett D'Amore 30688447a05SGarrett D'Amore /* truncate the filter and write n/trunc_start */ 30788447a05SGarrett D'Amore truncM = (21 * N - 1) | 1; 30888447a05SGarrett D'Amore if (rate >= 24000U) { 30988447a05SGarrett D'Amore if (truncM > 239) 31088447a05SGarrett D'Amore truncM = 239; 31188447a05SGarrett D'Amore truncStart = (239 - truncM) >> 1; 31288447a05SGarrett D'Amore 31388447a05SGarrett D'Amore SRCRegWrite(dev, base + SRC_TRUNC_N_OFF, 31488447a05SGarrett D'Amore (truncStart << 9) | (N << 4)); 31588447a05SGarrett D'Amore } else { 31688447a05SGarrett D'Amore if (truncM > 119) 31788447a05SGarrett D'Amore truncM = 119; 31888447a05SGarrett D'Amore truncStart = (119 - truncM) >> 1; 31988447a05SGarrett D'Amore 32088447a05SGarrett D'Amore SRCRegWrite(dev, base + SRC_TRUNC_N_OFF, 32188447a05SGarrett D'Amore 0x8000U | (truncStart << 9) | (N << 4)); 32288447a05SGarrett D'Amore } 32388447a05SGarrett D'Amore 32488447a05SGarrett D'Amore /* calculate new frequency and write it - preserve accum */ 32588447a05SGarrett D'Amore freq = ((48000UL << 16) / rate) * N; 32688447a05SGarrett D'Amore SRCRegWrite(dev, base + SRC_INT_REGS_OFF, 32788447a05SGarrett D'Amore (SRCRegRead(dev, (unsigned short) base + SRC_INT_REGS_OFF) 32888447a05SGarrett D'Amore & 0x00ff) | ((unsigned short) (freq >> 6) & 0xfc00)); 32988447a05SGarrett D'Amore SRCRegWrite(dev, base + SRC_VFREQ_FRAC_OFF, 33088447a05SGarrett D'Amore (unsigned short) freq >> 1); 33188447a05SGarrett D'Amore 33288447a05SGarrett D'Amore SRCRegWrite(dev, SRC_ADC_VOL_L, N << 8); 33388447a05SGarrett D'Amore SRCRegWrite(dev, SRC_ADC_VOL_R, N << 8); 33488447a05SGarrett D'Amore } 33588447a05SGarrett D'Amore } 33688447a05SGarrett D'Amore 33788447a05SGarrett D'Amore static void 33888447a05SGarrett D'Amore SRCInit(audioens_dev_t *dev) 33988447a05SGarrett D'Amore { 34088447a05SGarrett D'Amore int i; 34188447a05SGarrett D'Amore 34288447a05SGarrett D'Amore /* Clear all SRC RAM then init - keep SRC disabled until done */ 34388447a05SGarrett D'Amore for (i = 0; i < SRC_IOPOLL_COUNT; ++i) { 34488447a05SGarrett D'Amore if (!(GET32(dev, CONC_dSRCIO_OFF) & SRC_BUSY)) 34588447a05SGarrett D'Amore break; 34688447a05SGarrett D'Amore } 34788447a05SGarrett D'Amore PUT32(dev, CONC_dSRCIO_OFF, SRC_DISABLE); 34888447a05SGarrett D'Amore 34988447a05SGarrett D'Amore for (i = 0; i < 0x80; ++i) 35088447a05SGarrett D'Amore SRCRegWrite(dev, (unsigned short) i, 0U); 35188447a05SGarrett D'Amore 35288447a05SGarrett D'Amore SRCRegWrite(dev, SRC_DAC1_BASE + SRC_TRUNC_N_OFF, 16 << 4); 35388447a05SGarrett D'Amore SRCRegWrite(dev, SRC_DAC1_BASE + SRC_INT_REGS_OFF, 16 << 10); 35488447a05SGarrett D'Amore SRCRegWrite(dev, SRC_DAC2_BASE + SRC_TRUNC_N_OFF, 16 << 4); 35588447a05SGarrett D'Amore SRCRegWrite(dev, SRC_DAC2_BASE + SRC_INT_REGS_OFF, 16 << 10); 35688447a05SGarrett D'Amore SRCRegWrite(dev, SRC_DAC1_VOL_L, 1 << 12); 35788447a05SGarrett D'Amore SRCRegWrite(dev, SRC_DAC1_VOL_R, 1 << 12); 35888447a05SGarrett D'Amore SRCRegWrite(dev, SRC_DAC2_VOL_L, 1 << 12); 35988447a05SGarrett D'Amore SRCRegWrite(dev, SRC_DAC2_VOL_R, 1 << 12); 36088447a05SGarrett D'Amore SRCRegWrite(dev, SRC_ADC_VOL_L, 1 << 12); 36188447a05SGarrett D'Amore SRCRegWrite(dev, SRC_ADC_VOL_R, 1 << 12); 36288447a05SGarrett D'Amore 36388447a05SGarrett D'Amore /* default some rates */ 36488447a05SGarrett D'Amore SRCSetRate(dev, SRC_DAC1_BASE, 48000); 36588447a05SGarrett D'Amore SRCSetRate(dev, SRC_DAC2_BASE, 48000); 36688447a05SGarrett D'Amore SRCSetRate(dev, SRC_ADC_BASE, 48000); 36788447a05SGarrett D'Amore 36888447a05SGarrett D'Amore /* now enable the whole deal */ 36988447a05SGarrett D'Amore for (i = 0; i < SRC_IOPOLL_COUNT; ++i) { 37088447a05SGarrett D'Amore if (!(GET32(dev, CONC_dSRCIO_OFF) & SRC_BUSY)) 37188447a05SGarrett D'Amore break; 37288447a05SGarrett D'Amore } 37388447a05SGarrett D'Amore PUT32(dev, CONC_dSRCIO_OFF, 0); 37488447a05SGarrett D'Amore } 37588447a05SGarrett D'Amore 37688447a05SGarrett D'Amore static void 37788447a05SGarrett D'Amore audioens_writemem(audioens_dev_t *dev, uint32_t page, uint32_t offs, 37888447a05SGarrett D'Amore uint32_t data) 37988447a05SGarrett D'Amore { 38088447a05SGarrett D'Amore /* Select memory page */ 38188447a05SGarrett D'Amore PUT32(dev, CONC_bMEMPAGE_OFF, page); 38288447a05SGarrett D'Amore PUT32(dev, offs, data); 38388447a05SGarrett D'Amore } 38488447a05SGarrett D'Amore 38588447a05SGarrett D'Amore static uint32_t 38688447a05SGarrett D'Amore audioens_readmem(audioens_dev_t *dev, uint32_t page, uint32_t offs) 38788447a05SGarrett D'Amore { 38888447a05SGarrett D'Amore PUT32(dev, CONC_bMEMPAGE_OFF, page); /* Select memory page */ 38988447a05SGarrett D'Amore return (GET32(dev, offs)); 39088447a05SGarrett D'Amore } 39188447a05SGarrett D'Amore 39288447a05SGarrett D'Amore /* 39388447a05SGarrett D'Amore * Audio routines 39488447a05SGarrett D'Amore */ 39588447a05SGarrett D'Amore static int 39688447a05SGarrett D'Amore audioens_format(void *arg) 39788447a05SGarrett D'Amore { 39888447a05SGarrett D'Amore _NOTE(ARGUNUSED(arg)); 39988447a05SGarrett D'Amore 40088447a05SGarrett D'Amore /* hardware can also do AUDIO_FORMAT_U8, but no need for it */ 40188447a05SGarrett D'Amore return (AUDIO_FORMAT_S16_LE); 40288447a05SGarrett D'Amore } 40388447a05SGarrett D'Amore 40488447a05SGarrett D'Amore static int 40588447a05SGarrett D'Amore audioens_channels(void *arg) 40688447a05SGarrett D'Amore { 40788447a05SGarrett D'Amore audioens_port_t *port = arg; 40888447a05SGarrett D'Amore 40988447a05SGarrett D'Amore return (port->nchan); 41088447a05SGarrett D'Amore } 41188447a05SGarrett D'Amore 41288447a05SGarrett D'Amore static int 41388447a05SGarrett D'Amore audioens_rate(void *arg) 41488447a05SGarrett D'Amore { 41588447a05SGarrett D'Amore audioens_port_t *port = arg; 41688447a05SGarrett D'Amore 41788447a05SGarrett D'Amore return (port->speed); 41888447a05SGarrett D'Amore } 41988447a05SGarrett D'Amore 42068c47f65SGarrett D'Amore static int 42168c47f65SGarrett D'Amore audioens_open(void *arg, int flag, unsigned *nframes, caddr_t *bufp) 42288447a05SGarrett D'Amore { 42368c47f65SGarrett D'Amore audioens_port_t *port = arg; 42488447a05SGarrett D'Amore audioens_dev_t *dev = port->dev; 42588447a05SGarrett D'Amore 42668c47f65SGarrett D'Amore _NOTE(ARGUNUSED(flag)); 42768c47f65SGarrett D'Amore 42868c47f65SGarrett D'Amore mutex_enter(&dev->mutex); 42968c47f65SGarrett D'Amore 43068c47f65SGarrett D'Amore port->nframes = AUDIOENS_BUF_LEN / (port->nchan * sizeof (int16_t)); 43168c47f65SGarrett D'Amore port->count = 0; 43268c47f65SGarrett D'Amore 43368c47f65SGarrett D'Amore *nframes = port->nframes; 43468c47f65SGarrett D'Amore *bufp = port->kaddr; 43568c47f65SGarrett D'Amore mutex_exit(&dev->mutex); 43668c47f65SGarrett D'Amore 43768c47f65SGarrett D'Amore return (0); 43868c47f65SGarrett D'Amore } 43968c47f65SGarrett D'Amore 44068c47f65SGarrett D'Amore static int 44168c47f65SGarrett D'Amore audioens_start(void *arg) 44268c47f65SGarrett D'Amore { 44368c47f65SGarrett D'Amore audioens_port_t *port = arg; 44468c47f65SGarrett D'Amore audioens_dev_t *dev = port->dev; 44568c47f65SGarrett D'Amore uint32_t tmp; 44668c47f65SGarrett D'Amore 44768c47f65SGarrett D'Amore mutex_enter(&dev->mutex); 44888447a05SGarrett D'Amore 44988447a05SGarrett D'Amore switch (port->num) { 45088447a05SGarrett D'Amore case PORT_DAC: 45188447a05SGarrett D'Amore /* Set physical address of the DMA buffer */ 45288447a05SGarrett D'Amore audioens_writemem(dev, CONC_DAC1CTL_PAGE, CONC_dDAC1PADDR_OFF, 45388447a05SGarrett D'Amore port->paddr); 45488447a05SGarrett D'Amore audioens_writemem(dev, CONC_DAC2CTL_PAGE, CONC_dDAC2PADDR_OFF, 45588447a05SGarrett D'Amore port->paddr + (port->nframes * sizeof (int16_t) * 2)); 45688447a05SGarrett D'Amore 45788447a05SGarrett D'Amore /* Set DAC rate */ 45888447a05SGarrett D'Amore SRCSetRate(dev, SRC_DAC1_BASE, port->speed); 45988447a05SGarrett D'Amore SRCSetRate(dev, SRC_DAC2_BASE, port->speed); 46088447a05SGarrett D'Amore 46188447a05SGarrett D'Amore /* Configure the channel setup - SPDIF only uses front */ 46288447a05SGarrett D'Amore tmp = GET32(dev, CONC_dSTATUS_OFF); 46388447a05SGarrett D'Amore tmp &= ~(CONC_STATUS_SPKR_MASK | CONC_STATUS_SPDIF_MASK); 46488447a05SGarrett D'Amore tmp |= CONC_STATUS_SPKR_4CH | CONC_STATUS_SPDIF_P1; 46588447a05SGarrett D'Amore PUT32(dev, CONC_dSTATUS_OFF, tmp); 46688447a05SGarrett D'Amore 46788447a05SGarrett D'Amore /* Set format */ 46888447a05SGarrett D'Amore PUT8(dev, CONC_bSKIPC_OFF, 0x10); 46988447a05SGarrett D'Amore SET8(dev, CONC_bSERFMT_OFF, 47088447a05SGarrett D'Amore CONC_PCM_DAC1_16BIT | CONC_PCM_DAC2_16BIT | 47188447a05SGarrett D'Amore CONC_PCM_DAC1_STEREO | CONC_PCM_DAC2_STEREO); 47288447a05SGarrett D'Amore 47388447a05SGarrett D'Amore /* Set the frame count */ 47488447a05SGarrett D'Amore audioens_writemem(dev, CONC_DAC1CTL_PAGE, CONC_wDAC1FC_OFF, 47588447a05SGarrett D'Amore port->nframes - 1); 47688447a05SGarrett D'Amore audioens_writemem(dev, CONC_DAC2CTL_PAGE, CONC_wDAC2FC_OFF, 47788447a05SGarrett D'Amore port->nframes - 1); 47888447a05SGarrett D'Amore 47988447a05SGarrett D'Amore /* Set # of frames between interrupts */ 48068c47f65SGarrett D'Amore PUT16(dev, CONC_wDAC1IC_OFF, port->nframes - 1); 48168c47f65SGarrett D'Amore PUT16(dev, CONC_wDAC2IC_OFF, port->nframes - 1); 48268c47f65SGarrett D'Amore 48368c47f65SGarrett D'Amore SET8(dev, CONC_bDEVCTL_OFF, 48468c47f65SGarrett D'Amore CONC_DEVCTL_DAC2_EN | CONC_DEVCTL_DAC1_EN); 48568c47f65SGarrett D'Amore 48688447a05SGarrett D'Amore break; 48788447a05SGarrett D'Amore 48888447a05SGarrett D'Amore case PORT_ADC: 48988447a05SGarrett D'Amore /* Set physical address of the DMA buffer */ 49088447a05SGarrett D'Amore audioens_writemem(dev, CONC_ADCCTL_PAGE, CONC_dADCPADDR_OFF, 49188447a05SGarrett D'Amore port->paddr); 49288447a05SGarrett D'Amore 49388447a05SGarrett D'Amore /* Set ADC rate */ 49488447a05SGarrett D'Amore SRCSetRate(dev, SRC_ADC_BASE, port->speed); 49588447a05SGarrett D'Amore 49688447a05SGarrett D'Amore /* Set format - for input we only support 16 bit input */ 49788447a05SGarrett D'Amore tmp = GET8(dev, CONC_bSERFMT_OFF); 49888447a05SGarrett D'Amore tmp |= CONC_PCM_ADC_16BIT; 49988447a05SGarrett D'Amore tmp |= CONC_PCM_ADC_STEREO; 50088447a05SGarrett D'Amore 50188447a05SGarrett D'Amore PUT8(dev, CONC_bSKIPC_OFF, 0x10); 50288447a05SGarrett D'Amore 50388447a05SGarrett D'Amore PUT8(dev, CONC_bSERFMT_OFF, tmp); 50488447a05SGarrett D'Amore 50588447a05SGarrett D'Amore /* Set the frame count */ 50688447a05SGarrett D'Amore audioens_writemem(dev, CONC_ADCCTL_PAGE, CONC_wADCFC_OFF, 50788447a05SGarrett D'Amore port->nframes - 1); 50888447a05SGarrett D'Amore 50988447a05SGarrett D'Amore /* Set # of frames between interrupts */ 51068c47f65SGarrett D'Amore PUT16(dev, CONC_wADCIC_OFF, port->nframes - 1); 51188447a05SGarrett D'Amore 51268c47f65SGarrett D'Amore SET8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_ADC_EN); 51388447a05SGarrett D'Amore break; 51488447a05SGarrett D'Amore } 51588447a05SGarrett D'Amore 51688447a05SGarrett D'Amore port->frameno = 0; 51788447a05SGarrett D'Amore mutex_exit(&dev->mutex); 51888447a05SGarrett D'Amore 51988447a05SGarrett D'Amore return (0); 52088447a05SGarrett D'Amore } 52188447a05SGarrett D'Amore 52288447a05SGarrett D'Amore static void 52368c47f65SGarrett D'Amore audioens_stop(void *arg) 52488447a05SGarrett D'Amore { 52588447a05SGarrett D'Amore audioens_port_t *port = arg; 52688447a05SGarrett D'Amore audioens_dev_t *dev = port->dev; 52788447a05SGarrett D'Amore 52888447a05SGarrett D'Amore mutex_enter(&dev->mutex); 52968c47f65SGarrett D'Amore switch (port->num) { 53068c47f65SGarrett D'Amore case PORT_DAC: 53168c47f65SGarrett D'Amore CLR8(dev, CONC_bDEVCTL_OFF, 53268c47f65SGarrett D'Amore CONC_DEVCTL_DAC2_EN | CONC_DEVCTL_DAC1_EN); 53368c47f65SGarrett D'Amore break; 53468c47f65SGarrett D'Amore case PORT_ADC: 53568c47f65SGarrett D'Amore CLR8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_ADC_EN); 53668c47f65SGarrett D'Amore break; 53788447a05SGarrett D'Amore } 53888447a05SGarrett D'Amore mutex_exit(&dev->mutex); 53988447a05SGarrett D'Amore } 54088447a05SGarrett D'Amore 54168c47f65SGarrett D'Amore static uint64_t 54268c47f65SGarrett D'Amore audioens_count(void *arg) 54388447a05SGarrett D'Amore { 54488447a05SGarrett D'Amore audioens_port_t *port = arg; 54588447a05SGarrett D'Amore audioens_dev_t *dev = port->dev; 54668c47f65SGarrett D'Amore uint64_t val; 54788447a05SGarrett D'Amore uint32_t page, offs; 54888447a05SGarrett D'Amore int frameno, n; 54988447a05SGarrett D'Amore 55088447a05SGarrett D'Amore switch (port->num) { 55188447a05SGarrett D'Amore case PORT_DAC: 55288447a05SGarrett D'Amore page = CONC_DAC1CTL_PAGE; 55388447a05SGarrett D'Amore offs = CONC_wDAC1FC_OFF; 55488447a05SGarrett D'Amore break; 55588447a05SGarrett D'Amore 55688447a05SGarrett D'Amore case PORT_ADC: 55788447a05SGarrett D'Amore page = CONC_ADCCTL_PAGE; 55888447a05SGarrett D'Amore offs = CONC_wADCFC_OFF; 55988447a05SGarrett D'Amore break; 56088447a05SGarrett D'Amore } 56188447a05SGarrett D'Amore 56268c47f65SGarrett D'Amore mutex_enter(&dev->mutex); 56388447a05SGarrett D'Amore /* 56488447a05SGarrett D'Amore * Note that the current frame counter is in the high nybble. 56588447a05SGarrett D'Amore */ 56688447a05SGarrett D'Amore frameno = audioens_readmem(port->dev, page, offs) >> 16; 56788447a05SGarrett D'Amore n = frameno >= port->frameno ? 56888447a05SGarrett D'Amore frameno - port->frameno : 56988447a05SGarrett D'Amore frameno + port->nframes - port->frameno; 57088447a05SGarrett D'Amore port->frameno = frameno; 57188447a05SGarrett D'Amore port->count += n; 57288447a05SGarrett D'Amore 57388447a05SGarrett D'Amore val = port->count; 57488447a05SGarrett D'Amore mutex_exit(&dev->mutex); 57568c47f65SGarrett D'Amore 57688447a05SGarrett D'Amore return (val); 57788447a05SGarrett D'Amore } 57888447a05SGarrett D'Amore 57988447a05SGarrett D'Amore static void 58088447a05SGarrett D'Amore audioens_close(void *arg) 58188447a05SGarrett D'Amore { 58268c47f65SGarrett D'Amore _NOTE(ARGUNUSED(arg)); 58388447a05SGarrett D'Amore } 58488447a05SGarrett D'Amore 58588447a05SGarrett D'Amore static void 58688447a05SGarrett D'Amore audioens_sync(void *arg, unsigned nframes) 58788447a05SGarrett D'Amore { 58888447a05SGarrett D'Amore audioens_port_t *port = arg; 58988447a05SGarrett D'Amore 59088447a05SGarrett D'Amore _NOTE(ARGUNUSED(nframes)); 59188447a05SGarrett D'Amore 59288447a05SGarrett D'Amore if (port->num == PORT_ADC) { 59368c47f65SGarrett D'Amore (void) ddi_dma_sync(port->dmah, 0, 0, DDI_DMA_SYNC_FORKERNEL); 59488447a05SGarrett D'Amore } else { 59588447a05SGarrett D'Amore (void) ddi_dma_sync(port->dmah, 0, 0, DDI_DMA_SYNC_FORDEV); 59688447a05SGarrett D'Amore } 59788447a05SGarrett D'Amore } 59888447a05SGarrett D'Amore 59988447a05SGarrett D'Amore static void 60088447a05SGarrett D'Amore audioens_chinfo(void *arg, int chan, unsigned *offset, unsigned *incr) 60188447a05SGarrett D'Amore { 60288447a05SGarrett D'Amore audioens_port_t *port = arg; 60388447a05SGarrett D'Amore 60488447a05SGarrett D'Amore if ((port->num == PORT_DAC) && (chan >= 2)) { 60588447a05SGarrett D'Amore *offset = (port->nframes * 2) + (chan % 2); 60688447a05SGarrett D'Amore *incr = 2; 60788447a05SGarrett D'Amore } else { 60888447a05SGarrett D'Amore *offset = chan; 60988447a05SGarrett D'Amore *incr = 2; 61088447a05SGarrett D'Amore } 61188447a05SGarrett D'Amore } 61288447a05SGarrett D'Amore 61388447a05SGarrett D'Amore audio_engine_ops_t audioens_engine_ops = { 61488447a05SGarrett D'Amore AUDIO_ENGINE_VERSION, /* version number */ 61588447a05SGarrett D'Amore audioens_open, 61688447a05SGarrett D'Amore audioens_close, 61788447a05SGarrett D'Amore audioens_start, 61888447a05SGarrett D'Amore audioens_stop, 61988447a05SGarrett D'Amore audioens_count, 62088447a05SGarrett D'Amore audioens_format, 62188447a05SGarrett D'Amore audioens_channels, 62288447a05SGarrett D'Amore audioens_rate, 62388447a05SGarrett D'Amore audioens_sync, 624f9ead4a5SGarrett D'Amore NULL, 625f9ead4a5SGarrett D'Amore audioens_chinfo, 626f9ead4a5SGarrett D'Amore NULL, 62788447a05SGarrett D'Amore }; 62888447a05SGarrett D'Amore 62988447a05SGarrett D'Amore void 63088447a05SGarrett D'Amore audioens_init_hw(audioens_dev_t *dev) 63188447a05SGarrett D'Amore { 63288447a05SGarrett D'Amore int tmp; 63388447a05SGarrett D'Amore 63488447a05SGarrett D'Amore if ((dev->devid == ENSONIQ_ES5880) || 63588447a05SGarrett D'Amore (dev->devid == ENSONIQ_ES5880A) || 63688447a05SGarrett D'Amore (dev->devid == ENSONIQ_ES5880B) || 63788447a05SGarrett D'Amore (dev->devid == 0x1371 && dev->revision == 7) || 63888447a05SGarrett D'Amore (dev->devid == 0x1371 && dev->revision >= 9)) { 63988447a05SGarrett D'Amore 64088447a05SGarrett D'Amore /* Have a ES5880 so enable the codec manually */ 64188447a05SGarrett D'Amore tmp = GET8(dev, CONC_bINTSUMM_OFF) & 0xff; 64288447a05SGarrett D'Amore tmp |= 0x20; 64388447a05SGarrett D'Amore PUT8(dev, CONC_bINTSUMM_OFF, tmp); 64488447a05SGarrett D'Amore for (int i = 0; i < 2000; i++) 64588447a05SGarrett D'Amore drv_usecwait(10); 64688447a05SGarrett D'Amore } 64788447a05SGarrett D'Amore 64888447a05SGarrett D'Amore SRCInit(dev); 64988447a05SGarrett D'Amore 65088447a05SGarrett D'Amore /* 65188447a05SGarrett D'Amore * Turn on CODEC (UART and joystick left disabled) 65288447a05SGarrett D'Amore */ 65388447a05SGarrett D'Amore tmp = GET32(dev, CONC_bDEVCTL_OFF) & 0xff; 65488447a05SGarrett D'Amore tmp &= ~(CONC_DEVCTL_PCICLK_DS | CONC_DEVCTL_XTALCLK_DS); 65588447a05SGarrett D'Amore PUT8(dev, CONC_bDEVCTL_OFF, tmp); 65688447a05SGarrett D'Amore PUT8(dev, CONC_bUARTCSTAT_OFF, 0x00); 65788447a05SGarrett D'Amore 65888447a05SGarrett D'Amore /* Perform AC97 codec warm reset */ 65988447a05SGarrett D'Amore tmp = GET8(dev, CONC_bMISCCTL_OFF) & 0xff; 66088447a05SGarrett D'Amore PUT8(dev, CONC_bMISCCTL_OFF, tmp | CONC_MISCCTL_SYNC_RES); 66188447a05SGarrett D'Amore drv_usecwait(200); 66288447a05SGarrett D'Amore PUT8(dev, CONC_bMISCCTL_OFF, tmp); 66388447a05SGarrett D'Amore drv_usecwait(200); 66488447a05SGarrett D'Amore 66588447a05SGarrett D'Amore if (dev->revision >= 4) { 66688447a05SGarrett D'Amore /* XXX: enable SPDIF - PCM only for now */ 66788447a05SGarrett D'Amore if (audioens_spdif) { 66888447a05SGarrett D'Amore /* enable SPDIF */ 66988447a05SGarrett D'Amore PUT32(dev, 0x04, GET32(dev, 0x04) | (1 << 18)); 67088447a05SGarrett D'Amore /* SPDIF out = data from DAC */ 67188447a05SGarrett D'Amore PUT32(dev, 0x00, GET32(dev, 0x00) | (1 << 26)); 67288447a05SGarrett D'Amore CLR32(dev, CONC_dSPDIF_OFF, CONC_SPDIF_AC3); 67388447a05SGarrett D'Amore 67488447a05SGarrett D'Amore } else { 67588447a05SGarrett D'Amore /* disable spdif out */ 67688447a05SGarrett D'Amore PUT32(dev, 0x04, GET32(dev, 0x04) & ~(1 << 18)); 67788447a05SGarrett D'Amore PUT32(dev, 0x00, GET32(dev, 0x00) & ~(1 << 26)); 67888447a05SGarrett D'Amore } 67988447a05SGarrett D'Amore 68088447a05SGarrett D'Amore /* we want to run each channel independently */ 68188447a05SGarrett D'Amore CLR32(dev, CONC_dSTATUS_OFF, CONC_STATUS_ECHO); 68288447a05SGarrett D'Amore } 68388447a05SGarrett D'Amore } 68488447a05SGarrett D'Amore 68588447a05SGarrett D'Amore static int 68688447a05SGarrett D'Amore audioens_init(audioens_dev_t *dev) 68788447a05SGarrett D'Amore { 68888447a05SGarrett D'Amore 68988447a05SGarrett D'Amore audioens_init_hw(dev); 69088447a05SGarrett D'Amore 69188447a05SGarrett D'Amore /* 69288447a05SGarrett D'Amore * On this hardware, we want to disable the internal speaker by 69388447a05SGarrett D'Amore * default, if it exists. (We don't have a speakerphone on any 69488447a05SGarrett D'Amore * of these cards, and no SPARC hardware uses it either!) 69588447a05SGarrett D'Amore */ 696505c7a69SGarrett D'Amore (void) ddi_prop_update_int(DDI_DEV_T_NONE, dev->dip, AC97_PROP_SPEAKER, 697505c7a69SGarrett D'Amore 0); 69888447a05SGarrett D'Amore 69988447a05SGarrett D'Amore /* 70088447a05SGarrett D'Amore * Init mixer 70188447a05SGarrett D'Amore */ 70288447a05SGarrett D'Amore 70388447a05SGarrett D'Amore dev->ac97 = ac97_alloc(dev->dip, audioens_rd97, audioens_wr97, dev); 70488447a05SGarrett D'Amore if (dev->ac97 == NULL) 70588447a05SGarrett D'Amore return (DDI_FAILURE); 70688447a05SGarrett D'Amore 70788447a05SGarrett D'Amore if (ac97_init(dev->ac97, dev->osdev) != 0) { 70888447a05SGarrett D'Amore return (DDI_FAILURE); 70988447a05SGarrett D'Amore } 71088447a05SGarrett D'Amore 71188447a05SGarrett D'Amore for (int i = 0; i <= PORT_MAX; i++) { 71288447a05SGarrett D'Amore audioens_port_t *port; 71388447a05SGarrett D'Amore unsigned caps; 71488447a05SGarrett D'Amore unsigned dmaflags; 71588447a05SGarrett D'Amore size_t rlen; 71688447a05SGarrett D'Amore ddi_dma_cookie_t c; 71788447a05SGarrett D'Amore unsigned ccnt; 71888447a05SGarrett D'Amore 71988447a05SGarrett D'Amore port = &dev->port[i]; 72088447a05SGarrett D'Amore port->dev = dev; 72188447a05SGarrett D'Amore 72288447a05SGarrett D'Amore switch (i) { 72388447a05SGarrett D'Amore case PORT_DAC: 72488447a05SGarrett D'Amore port->nchan = 4; 72588447a05SGarrett D'Amore port->speed = 48000; 72688447a05SGarrett D'Amore caps = ENGINE_OUTPUT_CAP; 72788447a05SGarrett D'Amore dmaflags = DDI_DMA_WRITE | DDI_DMA_CONSISTENT; 72888447a05SGarrett D'Amore break; 72988447a05SGarrett D'Amore 73088447a05SGarrett D'Amore case PORT_ADC: 73188447a05SGarrett D'Amore port->nchan = 2; 73288447a05SGarrett D'Amore port->speed = 48000; 73388447a05SGarrett D'Amore caps = ENGINE_INPUT_CAP; 73488447a05SGarrett D'Amore dmaflags = DDI_DMA_READ | DDI_DMA_CONSISTENT; 73588447a05SGarrett D'Amore break; 73688447a05SGarrett D'Amore } 73788447a05SGarrett D'Amore 73888447a05SGarrett D'Amore port->num = i; 73988447a05SGarrett D'Amore 74088447a05SGarrett D'Amore /* 74188447a05SGarrett D'Amore * Allocate DMA resources. 74288447a05SGarrett D'Amore */ 74388447a05SGarrett D'Amore 74488447a05SGarrett D'Amore if (ddi_dma_alloc_handle(dev->dip, &dma_attr, DDI_DMA_SLEEP, 74588447a05SGarrett D'Amore NULL, &port->dmah) != DDI_SUCCESS) { 74688447a05SGarrett D'Amore audio_dev_warn(dev->osdev, 74788447a05SGarrett D'Amore "port %d: dma handle allocation failed", i); 74888447a05SGarrett D'Amore return (DDI_FAILURE); 74988447a05SGarrett D'Amore } 75088447a05SGarrett D'Amore if (ddi_dma_mem_alloc(port->dmah, AUDIOENS_BUF_LEN, &buf_attr, 75188447a05SGarrett D'Amore DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &port->kaddr, 75288447a05SGarrett D'Amore &rlen, &port->acch) != DDI_SUCCESS) { 75388447a05SGarrett D'Amore audio_dev_warn(dev->osdev, 75488447a05SGarrett D'Amore "port %d: dma memory allocation failed", i); 75588447a05SGarrett D'Amore return (DDI_FAILURE); 75688447a05SGarrett D'Amore } 75788447a05SGarrett D'Amore /* ensure that the buffer is zeroed out properly */ 75888447a05SGarrett D'Amore bzero(port->kaddr, rlen); 75988447a05SGarrett D'Amore if (ddi_dma_addr_bind_handle(port->dmah, NULL, port->kaddr, 76088447a05SGarrett D'Amore AUDIOENS_BUF_LEN, dmaflags, DDI_DMA_SLEEP, NULL, 76188447a05SGarrett D'Amore &c, &ccnt) != DDI_DMA_MAPPED) { 76288447a05SGarrett D'Amore audio_dev_warn(dev->osdev, 76388447a05SGarrett D'Amore "port %d: dma binding failed", i); 76488447a05SGarrett D'Amore return (DDI_FAILURE); 76588447a05SGarrett D'Amore } 76688447a05SGarrett D'Amore port->paddr = c.dmac_address; 76788447a05SGarrett D'Amore 76888447a05SGarrett D'Amore /* 76988447a05SGarrett D'Amore * Allocate and configure audio engine. 77088447a05SGarrett D'Amore */ 77188447a05SGarrett D'Amore port->engine = audio_engine_alloc(&audioens_engine_ops, caps); 77288447a05SGarrett D'Amore if (port->engine == NULL) { 77388447a05SGarrett D'Amore audio_dev_warn(dev->osdev, 77488447a05SGarrett D'Amore "port %d: audio_engine_alloc failed", i); 77588447a05SGarrett D'Amore return (DDI_FAILURE); 77688447a05SGarrett D'Amore } 77788447a05SGarrett D'Amore 77888447a05SGarrett D'Amore audio_engine_set_private(port->engine, port); 77988447a05SGarrett D'Amore audio_dev_add_engine(dev->osdev, port->engine); 78088447a05SGarrett D'Amore } 78188447a05SGarrett D'Amore 78288447a05SGarrett D'Amore /* 78388447a05SGarrett D'Amore * Set up kstats for interrupt reporting. 78488447a05SGarrett D'Amore */ 78588447a05SGarrett D'Amore if (audio_dev_register(dev->osdev) != DDI_SUCCESS) { 78688447a05SGarrett D'Amore audio_dev_warn(dev->osdev, 78788447a05SGarrett D'Amore "unable to register with audio framework"); 78888447a05SGarrett D'Amore return (DDI_FAILURE); 78988447a05SGarrett D'Amore } 79088447a05SGarrett D'Amore 79188447a05SGarrett D'Amore return (DDI_SUCCESS); 79288447a05SGarrett D'Amore } 79388447a05SGarrett D'Amore 79488447a05SGarrett D'Amore void 79588447a05SGarrett D'Amore audioens_destroy(audioens_dev_t *dev) 79688447a05SGarrett D'Amore { 79788447a05SGarrett D'Amore int i; 79888447a05SGarrett D'Amore 79968c47f65SGarrett D'Amore mutex_destroy(&dev->mutex); 80088447a05SGarrett D'Amore 80188447a05SGarrett D'Amore /* free up ports, including DMA resources for ports */ 80288447a05SGarrett D'Amore for (i = 0; i <= PORT_MAX; i++) { 80388447a05SGarrett D'Amore audioens_port_t *port = &dev->port[i]; 80488447a05SGarrett D'Amore 80588447a05SGarrett D'Amore if (port->paddr != 0) 80688447a05SGarrett D'Amore (void) ddi_dma_unbind_handle(port->dmah); 80788447a05SGarrett D'Amore if (port->acch != NULL) 80888447a05SGarrett D'Amore ddi_dma_mem_free(&port->acch); 80988447a05SGarrett D'Amore if (port->dmah != NULL) 81088447a05SGarrett D'Amore ddi_dma_free_handle(&port->dmah); 81188447a05SGarrett D'Amore 81288447a05SGarrett D'Amore if (port->engine != NULL) { 81388447a05SGarrett D'Amore audio_dev_remove_engine(dev->osdev, port->engine); 81488447a05SGarrett D'Amore audio_engine_free(port->engine); 81588447a05SGarrett D'Amore } 81688447a05SGarrett D'Amore } 81788447a05SGarrett D'Amore 81888447a05SGarrett D'Amore if (dev->acch != NULL) { 81988447a05SGarrett D'Amore ddi_regs_map_free(&dev->acch); 82088447a05SGarrett D'Amore } 82188447a05SGarrett D'Amore 82288447a05SGarrett D'Amore if (dev->ac97) { 82388447a05SGarrett D'Amore ac97_free(dev->ac97); 82488447a05SGarrett D'Amore } 82588447a05SGarrett D'Amore 82688447a05SGarrett D'Amore if (dev->osdev != NULL) { 82788447a05SGarrett D'Amore audio_dev_free(dev->osdev); 82888447a05SGarrett D'Amore } 82988447a05SGarrett D'Amore 83088447a05SGarrett D'Amore kmem_free(dev, sizeof (*dev)); 83188447a05SGarrett D'Amore } 83288447a05SGarrett D'Amore 83388447a05SGarrett D'Amore int 83488447a05SGarrett D'Amore audioens_attach(dev_info_t *dip) 83588447a05SGarrett D'Amore { 83688447a05SGarrett D'Amore uint16_t pci_command, vendor, device; 83788447a05SGarrett D'Amore uint8_t revision; 83888447a05SGarrett D'Amore audioens_dev_t *dev; 83988447a05SGarrett D'Amore ddi_acc_handle_t pcih; 84088447a05SGarrett D'Amore const char *chip_name; 84188447a05SGarrett D'Amore const char *chip_vers; 84288447a05SGarrett D'Amore 84388447a05SGarrett D'Amore dev = kmem_zalloc(sizeof (*dev), KM_SLEEP); 84488447a05SGarrett D'Amore dev->dip = dip; 84588447a05SGarrett D'Amore ddi_set_driver_private(dip, dev); 84668c47f65SGarrett D'Amore mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, NULL); 84788447a05SGarrett D'Amore 84888447a05SGarrett D'Amore if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) { 84988447a05SGarrett D'Amore audio_dev_warn(dev->osdev, "pci_config_setup failed"); 85068c47f65SGarrett D'Amore mutex_destroy(&dev->mutex); 851*239924d3SGarrett D'Amore kmem_free(dev, sizeof (*dev)); 85288447a05SGarrett D'Amore return (DDI_FAILURE); 85388447a05SGarrett D'Amore } 85488447a05SGarrett D'Amore 85588447a05SGarrett D'Amore vendor = pci_config_get16(pcih, PCI_CONF_VENID); 85688447a05SGarrett D'Amore device = pci_config_get16(pcih, PCI_CONF_DEVID); 85788447a05SGarrett D'Amore revision = pci_config_get8(pcih, PCI_CONF_REVID); 85888447a05SGarrett D'Amore 85988447a05SGarrett D'Amore if ((vendor != ENSONIQ_VENDOR_ID && vendor != CREATIVE_VENDOR_ID) || 86088447a05SGarrett D'Amore (device != ENSONIQ_ES1371 && device != ENSONIQ_ES5880 && 86188447a05SGarrett D'Amore device != ENSONIQ_ES5880A && device != ECTIVA_ES1938 && 86288447a05SGarrett D'Amore device != ENSONIQ_ES5880B)) 86388447a05SGarrett D'Amore goto err_exit; 86488447a05SGarrett D'Amore 86588447a05SGarrett D'Amore chip_name = "AudioPCI97"; 86688447a05SGarrett D'Amore chip_vers = "unknown"; 86788447a05SGarrett D'Amore 86888447a05SGarrett D'Amore switch (device) { 86988447a05SGarrett D'Amore case ENSONIQ_ES1371: 87088447a05SGarrett D'Amore chip_name = "AudioPCI97"; 87188447a05SGarrett D'Amore switch (revision) { 87288447a05SGarrett D'Amore case 0x02: 87388447a05SGarrett D'Amore case 0x09: 87488447a05SGarrett D'Amore default: 87588447a05SGarrett D'Amore chip_vers = "ES1371"; 87688447a05SGarrett D'Amore break; 87788447a05SGarrett D'Amore case 0x04: 87888447a05SGarrett D'Amore case 0x06: 87988447a05SGarrett D'Amore case 0x08: 88088447a05SGarrett D'Amore chip_vers = "ES1373"; 88188447a05SGarrett D'Amore break; 88288447a05SGarrett D'Amore case 0x07: 88388447a05SGarrett D'Amore chip_vers = "ES5880"; 88488447a05SGarrett D'Amore break; 88588447a05SGarrett D'Amore } 88688447a05SGarrett D'Amore break; 88788447a05SGarrett D'Amore 88888447a05SGarrett D'Amore case ENSONIQ_ES5880: 88988447a05SGarrett D'Amore chip_name = "SB PCI128"; 89088447a05SGarrett D'Amore chip_vers = "ES5880"; 89188447a05SGarrett D'Amore break; 89288447a05SGarrett D'Amore case ENSONIQ_ES5880A: 89388447a05SGarrett D'Amore chip_name = "SB PCI128"; 89488447a05SGarrett D'Amore chip_vers = "ES5880A"; 89588447a05SGarrett D'Amore break; 89688447a05SGarrett D'Amore case ENSONIQ_ES5880B: 89788447a05SGarrett D'Amore chip_name = "SB PCI128"; 89888447a05SGarrett D'Amore chip_vers = "ES5880B"; 89988447a05SGarrett D'Amore break; 90088447a05SGarrett D'Amore 90188447a05SGarrett D'Amore case ECTIVA_ES1938: 90288447a05SGarrett D'Amore chip_name = "AudioPCI"; 90388447a05SGarrett D'Amore chip_vers = "ES1938"; 90488447a05SGarrett D'Amore break; 90588447a05SGarrett D'Amore } 90688447a05SGarrett D'Amore 90788447a05SGarrett D'Amore dev->revision = revision; 90888447a05SGarrett D'Amore dev->devid = device; 90988447a05SGarrett D'Amore 91088447a05SGarrett D'Amore dev->osdev = audio_dev_alloc(dip, 0); 91188447a05SGarrett D'Amore if (dev->osdev == NULL) { 91288447a05SGarrett D'Amore goto err_exit; 91388447a05SGarrett D'Amore } 91488447a05SGarrett D'Amore 91588447a05SGarrett D'Amore audio_dev_set_description(dev->osdev, chip_name); 91688447a05SGarrett D'Amore audio_dev_set_version(dev->osdev, chip_vers); 91788447a05SGarrett D'Amore 91888447a05SGarrett D'Amore /* set the PCI latency */ 91988447a05SGarrett D'Amore if ((audioens_latency == 32) || (audioens_latency == 64) || 92088447a05SGarrett D'Amore (audioens_latency == 96)) 92188447a05SGarrett D'Amore pci_config_put8(pcih, PCI_CONF_LATENCY_TIMER, 92288447a05SGarrett D'Amore audioens_latency); 92388447a05SGarrett D'Amore 92488447a05SGarrett D'Amore /* activate the device */ 92588447a05SGarrett D'Amore pci_command = pci_config_get16(pcih, PCI_CONF_COMM); 92688447a05SGarrett D'Amore pci_command |= PCI_COMM_ME | PCI_COMM_IO; 92788447a05SGarrett D'Amore pci_config_put16(pcih, PCI_CONF_COMM, pci_command); 92888447a05SGarrett D'Amore 92988447a05SGarrett D'Amore /* map registers */ 93088447a05SGarrett D'Amore if (ddi_regs_map_setup(dip, 1, &dev->regs, 0, 0, &acc_attr, 93188447a05SGarrett D'Amore &dev->acch) != DDI_SUCCESS) { 93288447a05SGarrett D'Amore audio_dev_warn(dev->osdev, "can't map registers"); 93388447a05SGarrett D'Amore goto err_exit; 93488447a05SGarrett D'Amore } 93588447a05SGarrett D'Amore 93688447a05SGarrett D'Amore /* This allocates and configures the engines */ 93788447a05SGarrett D'Amore if (audioens_init(dev) != DDI_SUCCESS) { 93888447a05SGarrett D'Amore audio_dev_warn(dev->osdev, "can't init device"); 93988447a05SGarrett D'Amore goto err_exit; 94088447a05SGarrett D'Amore } 94188447a05SGarrett D'Amore 94288447a05SGarrett D'Amore pci_config_teardown(&pcih); 94388447a05SGarrett D'Amore 94488447a05SGarrett D'Amore ddi_report_dev(dip); 94588447a05SGarrett D'Amore 94688447a05SGarrett D'Amore return (DDI_SUCCESS); 94788447a05SGarrett D'Amore 94888447a05SGarrett D'Amore err_exit: 94988447a05SGarrett D'Amore pci_config_teardown(&pcih); 95088447a05SGarrett D'Amore 95188447a05SGarrett D'Amore audioens_destroy(dev); 95288447a05SGarrett D'Amore 95388447a05SGarrett D'Amore return (DDI_FAILURE); 95488447a05SGarrett D'Amore } 95588447a05SGarrett D'Amore 95688447a05SGarrett D'Amore int 95788447a05SGarrett D'Amore audioens_detach(audioens_dev_t *dev) 95888447a05SGarrett D'Amore { 95988447a05SGarrett D'Amore int tmp; 96088447a05SGarrett D'Amore 96188447a05SGarrett D'Amore /* first unregister us from the DDI framework, might be busy */ 96288447a05SGarrett D'Amore if (audio_dev_unregister(dev->osdev) != DDI_SUCCESS) 96388447a05SGarrett D'Amore return (DDI_FAILURE); 96488447a05SGarrett D'Amore 96588447a05SGarrett D'Amore mutex_enter(&dev->mutex); 96688447a05SGarrett D'Amore 96788447a05SGarrett D'Amore tmp = GET8(dev, CONC_bSERCTL_OFF) & 96888447a05SGarrett D'Amore ~(CONC_SERCTL_DAC2IE | CONC_SERCTL_DAC1IE | CONC_SERCTL_ADCIE); 96988447a05SGarrett D'Amore PUT8(dev, CONC_bSERCTL_OFF, tmp); 97088447a05SGarrett D'Amore PUT8(dev, CONC_bSERCTL_OFF, tmp); 97188447a05SGarrett D'Amore PUT8(dev, CONC_bSERCTL_OFF, tmp); 97288447a05SGarrett D'Amore PUT8(dev, CONC_bSERCTL_OFF, tmp); 97388447a05SGarrett D'Amore 97488447a05SGarrett D'Amore tmp = GET8(dev, CONC_bDEVCTL_OFF) & 97588447a05SGarrett D'Amore ~(CONC_DEVCTL_DAC2_EN | CONC_DEVCTL_ADC_EN | CONC_DEVCTL_DAC1_EN); 97688447a05SGarrett D'Amore PUT8(dev, CONC_bDEVCTL_OFF, tmp); 97788447a05SGarrett D'Amore PUT8(dev, CONC_bDEVCTL_OFF, tmp); 97888447a05SGarrett D'Amore PUT8(dev, CONC_bDEVCTL_OFF, tmp); 97988447a05SGarrett D'Amore PUT8(dev, CONC_bDEVCTL_OFF, tmp); 98088447a05SGarrett D'Amore 98188447a05SGarrett D'Amore mutex_exit(&dev->mutex); 98288447a05SGarrett D'Amore 98388447a05SGarrett D'Amore audioens_destroy(dev); 98488447a05SGarrett D'Amore 98588447a05SGarrett D'Amore return (DDI_SUCCESS); 98688447a05SGarrett D'Amore } 98788447a05SGarrett D'Amore 98888447a05SGarrett D'Amore static int 98988447a05SGarrett D'Amore audioens_resume(audioens_dev_t *dev) 99088447a05SGarrett D'Amore { 99188447a05SGarrett D'Amore /* reinitialize hardware */ 99288447a05SGarrett D'Amore audioens_init_hw(dev); 99388447a05SGarrett D'Amore 99488447a05SGarrett D'Amore /* restore AC97 state */ 99568c47f65SGarrett D'Amore ac97_reset(dev->ac97); 99688447a05SGarrett D'Amore 99768c47f65SGarrett D'Amore audio_dev_resume(dev->osdev); 99888447a05SGarrett D'Amore 99988447a05SGarrett D'Amore return (DDI_SUCCESS); 100088447a05SGarrett D'Amore } 100188447a05SGarrett D'Amore 100288447a05SGarrett D'Amore static int 100388447a05SGarrett D'Amore audioens_suspend(audioens_dev_t *dev) 100488447a05SGarrett D'Amore { 100568c47f65SGarrett D'Amore audio_dev_suspend(dev->osdev); 100688447a05SGarrett D'Amore 100788447a05SGarrett D'Amore return (DDI_SUCCESS); 100888447a05SGarrett D'Amore } 100988447a05SGarrett D'Amore 101088447a05SGarrett D'Amore static int 101188447a05SGarrett D'Amore audioens_quiesce(dev_info_t *dip) 101288447a05SGarrett D'Amore { 101388447a05SGarrett D'Amore audioens_dev_t *dev; 101488447a05SGarrett D'Amore uint8_t tmp; 101588447a05SGarrett D'Amore 101688447a05SGarrett D'Amore if ((dev = ddi_get_driver_private(dip)) == NULL) { 101788447a05SGarrett D'Amore return (DDI_FAILURE); 101888447a05SGarrett D'Amore } 101988447a05SGarrett D'Amore 102088447a05SGarrett D'Amore /* This disables all DMA engines and interrupts */ 102188447a05SGarrett D'Amore tmp = GET8(dev, CONC_bSERCTL_OFF) & 102288447a05SGarrett D'Amore ~(CONC_SERCTL_DAC2IE | CONC_SERCTL_DAC1IE | CONC_SERCTL_ADCIE); 102388447a05SGarrett D'Amore PUT8(dev, CONC_bSERCTL_OFF, tmp); 102488447a05SGarrett D'Amore PUT8(dev, CONC_bSERCTL_OFF, tmp); 102588447a05SGarrett D'Amore PUT8(dev, CONC_bSERCTL_OFF, tmp); 102688447a05SGarrett D'Amore PUT8(dev, CONC_bSERCTL_OFF, tmp); 102788447a05SGarrett D'Amore 102888447a05SGarrett D'Amore tmp = GET8(dev, CONC_bDEVCTL_OFF) & 102988447a05SGarrett D'Amore ~(CONC_DEVCTL_DAC2_EN | CONC_DEVCTL_ADC_EN | CONC_DEVCTL_DAC1_EN); 103088447a05SGarrett D'Amore PUT8(dev, CONC_bDEVCTL_OFF, tmp); 103188447a05SGarrett D'Amore PUT8(dev, CONC_bDEVCTL_OFF, tmp); 103288447a05SGarrett D'Amore PUT8(dev, CONC_bDEVCTL_OFF, tmp); 103388447a05SGarrett D'Amore PUT8(dev, CONC_bDEVCTL_OFF, tmp); 103488447a05SGarrett D'Amore 103588447a05SGarrett D'Amore return (DDI_SUCCESS); 103688447a05SGarrett D'Amore } 103788447a05SGarrett D'Amore 103888447a05SGarrett D'Amore 103988447a05SGarrett D'Amore static int 104088447a05SGarrett D'Amore audioens_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 104188447a05SGarrett D'Amore { 104288447a05SGarrett D'Amore audioens_dev_t *dev; 104388447a05SGarrett D'Amore 104488447a05SGarrett D'Amore switch (cmd) { 104588447a05SGarrett D'Amore case DDI_ATTACH: 104688447a05SGarrett D'Amore return (audioens_attach(dip)); 104788447a05SGarrett D'Amore 104888447a05SGarrett D'Amore case DDI_RESUME: 104988447a05SGarrett D'Amore if ((dev = ddi_get_driver_private(dip)) == NULL) { 105088447a05SGarrett D'Amore return (DDI_FAILURE); 105188447a05SGarrett D'Amore } 105288447a05SGarrett D'Amore return (audioens_resume(dev)); 105388447a05SGarrett D'Amore 105488447a05SGarrett D'Amore default: 105588447a05SGarrett D'Amore return (DDI_FAILURE); 105688447a05SGarrett D'Amore } 105788447a05SGarrett D'Amore } 105888447a05SGarrett D'Amore 105988447a05SGarrett D'Amore static int 106088447a05SGarrett D'Amore audioens_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 106188447a05SGarrett D'Amore { 106288447a05SGarrett D'Amore audioens_dev_t *dev; 106388447a05SGarrett D'Amore 106488447a05SGarrett D'Amore if ((dev = ddi_get_driver_private(dip)) == NULL) { 106588447a05SGarrett D'Amore return (DDI_FAILURE); 106688447a05SGarrett D'Amore } 106788447a05SGarrett D'Amore 106888447a05SGarrett D'Amore switch (cmd) { 106988447a05SGarrett D'Amore case DDI_DETACH: 107088447a05SGarrett D'Amore return (audioens_detach(dev)); 107188447a05SGarrett D'Amore 107288447a05SGarrett D'Amore case DDI_SUSPEND: 107388447a05SGarrett D'Amore return (audioens_suspend(dev)); 107488447a05SGarrett D'Amore default: 107588447a05SGarrett D'Amore return (DDI_FAILURE); 107688447a05SGarrett D'Amore } 107788447a05SGarrett D'Amore } 107888447a05SGarrett D'Amore 107988447a05SGarrett D'Amore static int audioens_ddi_attach(dev_info_t *, ddi_attach_cmd_t); 108088447a05SGarrett D'Amore static int audioens_ddi_detach(dev_info_t *, ddi_detach_cmd_t); 108188447a05SGarrett D'Amore 108288447a05SGarrett D'Amore static struct dev_ops audioens_dev_ops = { 108388447a05SGarrett D'Amore DEVO_REV, /* rev */ 108488447a05SGarrett D'Amore 0, /* refcnt */ 108588447a05SGarrett D'Amore NULL, /* getinfo */ 108688447a05SGarrett D'Amore nulldev, /* identify */ 108788447a05SGarrett D'Amore nulldev, /* probe */ 108888447a05SGarrett D'Amore audioens_ddi_attach, /* attach */ 108988447a05SGarrett D'Amore audioens_ddi_detach, /* detach */ 109088447a05SGarrett D'Amore nodev, /* reset */ 109188447a05SGarrett D'Amore NULL, /* cb_ops */ 109288447a05SGarrett D'Amore NULL, /* bus_ops */ 109388447a05SGarrett D'Amore NULL, /* power */ 109488447a05SGarrett D'Amore audioens_quiesce, /* quiesce */ 109588447a05SGarrett D'Amore }; 109688447a05SGarrett D'Amore 109788447a05SGarrett D'Amore static struct modldrv audioens_modldrv = { 109888447a05SGarrett D'Amore &mod_driverops, /* drv_modops */ 109988447a05SGarrett D'Amore "Ensoniq 1371/1373 Audio", /* linkinfo */ 110088447a05SGarrett D'Amore &audioens_dev_ops, /* dev_ops */ 110188447a05SGarrett D'Amore }; 110288447a05SGarrett D'Amore 110388447a05SGarrett D'Amore static struct modlinkage modlinkage = { 110488447a05SGarrett D'Amore MODREV_1, 110588447a05SGarrett D'Amore { &audioens_modldrv, NULL } 110688447a05SGarrett D'Amore }; 110788447a05SGarrett D'Amore 110888447a05SGarrett D'Amore int 110988447a05SGarrett D'Amore _init(void) 111088447a05SGarrett D'Amore { 111188447a05SGarrett D'Amore int rv; 111288447a05SGarrett D'Amore 111388447a05SGarrett D'Amore audio_init_ops(&audioens_dev_ops, DRVNAME); 111488447a05SGarrett D'Amore if ((rv = mod_install(&modlinkage)) != 0) { 111588447a05SGarrett D'Amore audio_fini_ops(&audioens_dev_ops); 111688447a05SGarrett D'Amore } 111788447a05SGarrett D'Amore return (rv); 111888447a05SGarrett D'Amore } 111988447a05SGarrett D'Amore 112088447a05SGarrett D'Amore int 112188447a05SGarrett D'Amore _fini(void) 112288447a05SGarrett D'Amore { 112388447a05SGarrett D'Amore int rv; 112488447a05SGarrett D'Amore 112588447a05SGarrett D'Amore if ((rv = mod_remove(&modlinkage)) == 0) { 112688447a05SGarrett D'Amore audio_fini_ops(&audioens_dev_ops); 112788447a05SGarrett D'Amore } 112888447a05SGarrett D'Amore return (rv); 112988447a05SGarrett D'Amore } 113088447a05SGarrett D'Amore 113188447a05SGarrett D'Amore int 113288447a05SGarrett D'Amore _info(struct modinfo *modinfop) 113388447a05SGarrett D'Amore { 113488447a05SGarrett D'Amore return (mod_info(&modlinkage, modinfop)); 113588447a05SGarrett D'Amore } 1136