audioens.c revision 9484:fbd5ddc28e96
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25/*
26 * Purpose: Creative/Ensoniq AudioPCI97  driver (ES1371/ES1373)
27 *
28 * This driver is used with the original Ensoniq AudioPCI97 card and many
29 * PCI based Sound Blaster cards by Creative Technologies. For example
30 * Sound Blaster PCI128 and Creative/Ectiva EV1938.
31 */
32
33/*
34 * This file is part of Open Sound System
35 *
36 * Copyright (C) 4Front Technologies 1996-2008.
37 *
38 * This software is released under CDDL 1.0 source license.
39 * See the COPYING file included in the main directory of this source
40 * distribution for the license terms and conditions.
41 */
42
43#include <sys/audio/audio_driver.h>
44#include <sys/audio/ac97.h>
45#include <sys/note.h>
46#include <sys/pci.h>
47#include "audioens.h"
48
49/*
50 * The original OSS driver used a single duplex engine and a separate
51 * playback only engine.  Instead, we expose three engines, one for input
52 * and two for output.
53 */
54
55/*
56 * Set the latency to 32, 64, 96, 128 clocks - some APCI97 devices exhibit
57 * garbled audio in some cases and setting the latency to higer values fixes it
58 * Values: 32, 64, 96, 128 - Default: 64 (or defined by bios)
59 */
60int audioens_latency = 0;
61
62/*
63 * Enable SPDIF port on SoundBlaster 128D or Sound Blaster Digital-4.1 models
64 * Values: 1=Enable 0=Disable Default: 0
65 */
66int audioens_spdif = 0;
67
68/*
69 * Note: Latest devices can support SPDIF with AC3 pass thru.
70 * However, in order to do this, one of the two DMA engines must be
71 * dedicated to this, which would prevent the card from supporting 4
72 * channel audio.  For now we don't bother with the AC3 pass through
73 * mode, and instead just focus on 4 channel support.  In the future,
74 * this could be selectable via a property.
75 */
76
77#define	ENSONIQ_VENDOR_ID	0x1274
78#define	CREATIVE_VENDOR_ID	0x1102
79#define	ECTIVA_VENDOR_ID	0x1102
80#define	ENSONIQ_ES1371		0x1371
81#define	ENSONIQ_ES5880		0x8001
82#define	ENSONIQ_ES5880A		0x8002
83#define	ENSONIQ_ES5880B		0x5880
84#define	ECTIVA_ES1938		0x8938
85
86#define	DEFRATE			48000
87#define	DEFINTS			75
88#define	DRVNAME			"audioens"
89
90typedef struct audioens_port
91{
92	/* Audio parameters */
93	boolean_t		trigger;
94	boolean_t		suspended;
95
96	int			speed;
97
98	int			num;
99#define	PORT_DAC		0
100#define	PORT_ADC		1
101#define	PORT_MAX		PORT_ADC
102
103	caddr_t			kaddr;
104	uint32_t		paddr;
105	ddi_acc_handle_t	acch;
106	ddi_dma_handle_t	dmah;
107	int			nchan;
108	unsigned		fragfr;
109	unsigned		nfrags;
110	unsigned		nframes;
111	unsigned		frameno;
112	uint64_t		count;
113
114	struct audioens_dev	*dev;
115	audio_engine_t	*engine;
116} audioens_port_t;
117
118typedef struct audioens_dev
119{
120	audio_dev_t		*osdev;
121	kmutex_t		mutex;
122	uint16_t		devid;
123	uint8_t			revision;
124	dev_info_t		*dip;
125	boolean_t		enabled;
126
127
128	int			pintrs;
129	int			rintrs;
130
131	kstat_t			*ksp;
132
133	audioens_port_t		port[PORT_MAX + 1];
134
135	ac97_t			*ac97;
136
137	caddr_t			regs;
138	ddi_acc_handle_t	acch;
139	ddi_intr_handle_t	ihandle[1];
140} audioens_dev_t;
141
142static ddi_device_acc_attr_t acc_attr = {
143	DDI_DEVICE_ATTR_V0,
144	DDI_STRUCTURE_LE_ACC,
145	DDI_STRICTORDER_ACC
146};
147
148static ddi_device_acc_attr_t buf_attr = {
149	DDI_DEVICE_ATTR_V0,
150	DDI_NEVERSWAP_ACC,
151	DDI_STRICTORDER_ACC
152};
153
154/*
155 * The hardware appears to be able to address up to 16-bits worth of longwords,
156 * giving a total address space of 256K.  Note, however, that we will restrict
157 * this further when we do fragment and memory allocation.  At its very highest
158 * clock rate (48 kHz) and sample size (16-bit stereo), and lowest interrupt
159 * rate (32 Hz), we only need 6000 bytes per fragment.
160 *
161 * So with an allocated buffer size of 64K, we can support at least 10 frags,
162 * which is more than enough.  (The legacy Sun driver used only 2 fragments.)
163 */
164#define	AUDIOENS_BUF_LEN	(65536)
165
166static ddi_dma_attr_t dma_attr = {
167	DMA_ATTR_VERSION,	/* dma_attr_version */
168	0x0,			/* dma_attr_addr_lo */
169	0xffffffffU,		/* dma_attr_addr_hi */
170	0x3ffff,		/* dma_attr_count_max */
171	0x8,			/* dma_attr_align */
172	0x7f,			/* dma_attr_burstsizes */
173	0x1,			/* dma_attr_minxfer */
174	0x3ffff,		/* dma_attr_maxxfer */
175	0x3ffff,		/* dma_attr_seg */
176	0x1,			/* dma_attr_sgllen */
177	0x1,			/* dma_attr_granular */
178	0			/* dma_attr_flags */
179};
180
181#define	GET8(dev, offset)	\
182	ddi_get8(dev->acch, (uint8_t *)(dev->regs + (offset)))
183#define	GET16(dev, offset)	\
184	ddi_get16(dev->acch, (uint16_t *)(void *)(dev->regs + (offset)))
185#define	GET32(dev, offset)	\
186	ddi_get32(dev->acch, (uint32_t *)(void *)(dev->regs + (offset)))
187#define	PUT8(dev, offset, v)	\
188	ddi_put8(dev->acch, (uint8_t *)(dev->regs + (offset)), v)
189#define	PUT16(dev, offset, v)	\
190	ddi_put16(dev->acch, (uint16_t *)(void *)(dev->regs + (offset)), v)
191#define	PUT32(dev, offset, v)	\
192	ddi_put32(dev->acch, (uint32_t *)(void *)(dev->regs + (offset)), v)
193
194#define	CLR8(dev, offset, v)	PUT8(dev, offset, GET8(dev, offset) & ~(v))
195#define	SET8(dev, offset, v)	PUT8(dev, offset, GET8(dev, offset) | (v))
196#define	CLR32(dev, offset, v)	PUT32(dev, offset, GET32(dev, offset) & ~(v))
197#define	SET32(dev, offset, v)	PUT32(dev, offset, GET32(dev, offset) | (v))
198
199#define	KSINTR(dev)	((kstat_intr_t *)((dev)->ksp->ks_data))
200
201static void audioens_init_hw(audioens_dev_t *);
202static void audioens_init_port(audioens_port_t *);
203static void audioens_start_port(audioens_port_t *);
204static void audioens_stop_port(audioens_port_t *);
205static void audioens_update_port(audioens_port_t *);
206
207static uint16_t
208audioens_rd97(void *dev_, uint8_t wAddr)
209{
210	audioens_dev_t *dev = dev_;
211	int i, dtemp;
212
213	mutex_enter(&dev->mutex);
214	dtemp = GET32(dev, CONC_dCODECCTL_OFF);
215	/* wait for WIP to go away saving the current state for later */
216	for (i = 0; i < 0x100UL; ++i) {
217		dtemp = GET32(dev, CONC_dCODECCTL_OFF);
218		if ((dtemp & (1UL << 30)) == 0)
219			break;
220	}
221
222	/* write addr w/data=0 and assert read request ... */
223	PUT32(dev, CONC_dCODECCTL_OFF, ((int)wAddr << 16) | (1UL << 23));
224
225	/* now wait for the data (RDY) */
226	for (i = 0; i < 0x100UL; ++i) {
227		dtemp = GET32(dev, CONC_dCODECCTL_OFF);
228		if (dtemp & (1UL << 31))
229			break;
230	}
231	dtemp = GET32(dev, CONC_dCODECCTL_OFF);
232	mutex_exit(&dev->mutex);
233
234	return (dtemp & 0xffff);
235}
236
237static void
238audioens_wr97(void *dev_, uint8_t wAddr, uint16_t wData)
239{
240	audioens_dev_t *dev = dev_;
241	int i, dtemp;
242
243	mutex_enter(&dev->mutex);
244	/* wait for WIP to go away */
245	for (i = 0; i < 0x100UL; ++i) {
246		dtemp = GET32(dev, CONC_dCODECCTL_OFF);
247		if ((dtemp & (1UL << 30)) == 0)
248			break;
249	}
250
251	PUT32(dev, CONC_dCODECCTL_OFF, ((int)wAddr << 16) | wData);
252
253	mutex_exit(&dev->mutex);
254}
255
256static unsigned short
257SRCRegRead(audioens_dev_t *dev, unsigned short reg)
258{
259	int i, dtemp;
260
261	dtemp = GET32(dev, CONC_dSRCIO_OFF);
262	/* wait for ready */
263	for (i = 0; i < SRC_IOPOLL_COUNT; ++i) {
264		dtemp = GET32(dev, CONC_dSRCIO_OFF);
265		if ((dtemp & SRC_BUSY) == 0)
266			break;
267	}
268
269	/* assert a read request */
270	PUT32(dev, CONC_dSRCIO_OFF, (dtemp & SRC_CTLMASK) | ((int)reg << 25));
271
272	/* now wait for the data */
273	for (i = 0; i < SRC_IOPOLL_COUNT; ++i) {
274		dtemp = GET32(dev, CONC_dSRCIO_OFF);
275		if ((dtemp & SRC_BUSY) == 0)
276			break;
277	}
278
279	return ((unsigned short) dtemp);
280}
281
282static void
283SRCRegWrite(audioens_dev_t *dev, unsigned short reg, unsigned short val)
284{
285	int i, dtemp;
286	int writeval;
287
288	dtemp = GET32(dev, CONC_dSRCIO_OFF);
289	/* wait for ready */
290	for (i = 0; i < SRC_IOPOLL_COUNT; ++i) {
291		dtemp = GET32(dev, CONC_dSRCIO_OFF);
292		if ((dtemp & SRC_BUSY) == 0)
293			break;
294	}
295
296	/* assert the write request */
297	writeval = (dtemp & SRC_CTLMASK) | SRC_WENABLE |
298	    ((int)reg << 25) | val;
299	PUT32(dev, CONC_dSRCIO_OFF, writeval);
300}
301
302static void
303SRCSetRate(audioens_dev_t *dev, unsigned char base, unsigned short rate)
304{
305	int i, freq, dtemp;
306	unsigned short N, truncM, truncStart;
307
308	if (base != SRC_ADC_BASE) {
309		/* freeze the channel */
310		dtemp = (base == SRC_DAC1_BASE) ?
311		    SRC_DAC1FREEZE : SRC_DAC2FREEZE;
312		for (i = 0; i < SRC_IOPOLL_COUNT; ++i) {
313			if (!(GET32(dev, CONC_dSRCIO_OFF) & SRC_BUSY))
314				break;
315		}
316		PUT32(dev, CONC_dSRCIO_OFF,
317		    (GET32(dev, CONC_dSRCIO_OFF) & SRC_CTLMASK) | dtemp);
318
319		/* calculate new frequency and write it - preserve accum */
320		freq = ((int)rate << 16) / 3000U;
321		SRCRegWrite(dev, (unsigned short) base + SRC_INT_REGS_OFF,
322		    (SRCRegRead(dev, (unsigned short) base + SRC_INT_REGS_OFF)
323		    & 0x00ffU) | ((unsigned short) (freq >> 6) & 0xfc00));
324		SRCRegWrite(dev, (unsigned short) base + SRC_VFREQ_FRAC_OFF,
325		    (unsigned short) freq >> 1);
326
327		/* un-freeze the channel */
328		for (i = 0; i < SRC_IOPOLL_COUNT; ++i)
329			if (!(GET32(dev, CONC_dSRCIO_OFF) & SRC_BUSY))
330				break;
331		PUT32(dev, CONC_dSRCIO_OFF,
332		    (GET32(dev, CONC_dSRCIO_OFF) & SRC_CTLMASK) & ~dtemp);
333	} else {
334		/* derive oversample ratio */
335		N = rate / 3000U;
336		if (N == 15 || N == 13 || N == 11 || N == 9)
337			--N;
338
339		/* truncate the filter and write n/trunc_start */
340		truncM = (21 * N - 1) | 1;
341		if (rate >= 24000U) {
342			if (truncM > 239)
343				truncM = 239;
344			truncStart = (239 - truncM) >> 1;
345
346			SRCRegWrite(dev, base + SRC_TRUNC_N_OFF,
347			    (truncStart << 9) | (N << 4));
348		} else {
349			if (truncM > 119)
350				truncM = 119;
351			truncStart = (119 - truncM) >> 1;
352
353			SRCRegWrite(dev, base + SRC_TRUNC_N_OFF,
354			    0x8000U | (truncStart << 9) | (N << 4));
355		}
356
357		/* calculate new frequency and write it - preserve accum */
358		freq = ((48000UL << 16) / rate) * N;
359		SRCRegWrite(dev, base + SRC_INT_REGS_OFF,
360		    (SRCRegRead(dev, (unsigned short) base + SRC_INT_REGS_OFF)
361		    & 0x00ff) | ((unsigned short) (freq >> 6) & 0xfc00));
362		SRCRegWrite(dev, base + SRC_VFREQ_FRAC_OFF,
363		    (unsigned short) freq >> 1);
364
365		SRCRegWrite(dev, SRC_ADC_VOL_L, N << 8);
366		SRCRegWrite(dev, SRC_ADC_VOL_R, N << 8);
367	}
368}
369
370static void
371SRCInit(audioens_dev_t *dev)
372{
373	int i;
374
375	/* Clear all SRC RAM then init - keep SRC disabled until done */
376	for (i = 0; i < SRC_IOPOLL_COUNT; ++i) {
377		if (!(GET32(dev, CONC_dSRCIO_OFF) & SRC_BUSY))
378			break;
379	}
380	PUT32(dev, CONC_dSRCIO_OFF, SRC_DISABLE);
381
382	for (i = 0; i < 0x80; ++i)
383		SRCRegWrite(dev, (unsigned short) i, 0U);
384
385	SRCRegWrite(dev, SRC_DAC1_BASE + SRC_TRUNC_N_OFF, 16 << 4);
386	SRCRegWrite(dev, SRC_DAC1_BASE + SRC_INT_REGS_OFF, 16 << 10);
387	SRCRegWrite(dev, SRC_DAC2_BASE + SRC_TRUNC_N_OFF, 16 << 4);
388	SRCRegWrite(dev, SRC_DAC2_BASE + SRC_INT_REGS_OFF, 16 << 10);
389	SRCRegWrite(dev, SRC_DAC1_VOL_L, 1 << 12);
390	SRCRegWrite(dev, SRC_DAC1_VOL_R, 1 << 12);
391	SRCRegWrite(dev, SRC_DAC2_VOL_L, 1 << 12);
392	SRCRegWrite(dev, SRC_DAC2_VOL_R, 1 << 12);
393	SRCRegWrite(dev, SRC_ADC_VOL_L, 1 << 12);
394	SRCRegWrite(dev, SRC_ADC_VOL_R, 1 << 12);
395
396	/* default some rates */
397	SRCSetRate(dev, SRC_DAC1_BASE, 48000);
398	SRCSetRate(dev, SRC_DAC2_BASE, 48000);
399	SRCSetRate(dev, SRC_ADC_BASE, 48000);
400
401	/* now enable the whole deal */
402	for (i = 0; i < SRC_IOPOLL_COUNT; ++i) {
403		if (!(GET32(dev, CONC_dSRCIO_OFF) & SRC_BUSY))
404			break;
405	}
406	PUT32(dev, CONC_dSRCIO_OFF, 0);
407}
408
409static void
410audioens_writemem(audioens_dev_t *dev, uint32_t page, uint32_t offs,
411    uint32_t data)
412{
413	/* Select memory page */
414	PUT32(dev, CONC_bMEMPAGE_OFF, page);
415	PUT32(dev, offs, data);
416}
417
418static uint32_t
419audioens_readmem(audioens_dev_t *dev, uint32_t page, uint32_t offs)
420{
421	PUT32(dev, CONC_bMEMPAGE_OFF, page);	/* Select memory page */
422	return (GET32(dev, offs));
423}
424
425static uint_t
426audioens_intr(caddr_t arg1, caddr_t arg2)
427{
428	audioens_dev_t *dev = (void *)arg1;
429	int stats;
430	int tmp;
431	unsigned char ackbits = 0;
432	audioens_port_t *port;
433	audio_engine_t *do_dac, *do_adc;
434
435	_NOTE(ARGUNUSED(arg2));
436
437	/*
438	 * NB: The old audioens didn't report spurious interrupts.  On
439	 * a system with shared interrupts (typical!) there will
440	 * normally be lots of these (each time the "other" device
441	 * interrupts).
442	 *
443	 * Also, because of the way the interrupt chain handling
444	 * works, reporting of spurious interrupts is probably not
445	 * terribly useful.
446	 *
447	 * However, we can count interrupts where the master interrupt
448	 * bit is set but none of the ackbits that we are prepared to
449	 * process is set.  That is probably useful.
450	 */
451	mutex_enter(&dev->mutex);
452	if (!dev->enabled) {
453
454		mutex_exit(&dev->mutex);
455		return (DDI_INTR_UNCLAIMED);
456	}
457
458	stats = GET32(dev, CONC_dSTATUS_OFF);
459
460	if (!(stats & CONC_STATUS_PENDING)) {	/* No interrupt pending */
461		mutex_exit(&dev->mutex);
462		return (DDI_INTR_UNCLAIMED);
463	}
464
465	do_dac = do_adc = NULL;
466
467	/* DAC1 (synth) interrupt */
468	if (stats & CONC_STATUS_DAC1INT) {
469
470		ackbits |= CONC_SERCTL_DAC1IE;
471		port = &dev->port[PORT_DAC];
472		if (port->trigger) {
473			do_dac = port->engine;
474		}
475	}
476
477	/* DAC2 interrupt */
478	if (stats & CONC_STATUS_DAC2INT) {
479
480		ackbits |= CONC_SERCTL_DAC2IE;
481	}
482
483	/* ADC interrupt */
484	if (stats & CONC_STATUS_ADCINT) {
485
486		ackbits |= CONC_SERCTL_ADCIE;
487		port = &dev->port[PORT_ADC];
488
489		if (port->trigger) {
490			do_adc = port->engine;
491		}
492	}
493
494	/* UART interrupt - we shouldn't get this! */
495	if (stats & CONC_STATUS_UARTINT) {
496		uint8_t uart_stat = GET8(dev, CONC_bUARTCSTAT_OFF);
497		while (uart_stat & CONC_UART_RXRDY)
498			uart_stat = GET8(dev, CONC_bUARTCSTAT_OFF);
499	}
500
501	/* Ack the interrupt */
502	tmp = GET8(dev, CONC_bSERCTL_OFF);
503	PUT8(dev, CONC_bSERCTL_OFF, tmp & (~ackbits));	/* Clear bits */
504	PUT8(dev, CONC_bSERCTL_OFF, tmp | ackbits);	/* Turn them back on */
505
506	if (dev->ksp) {
507		if (ackbits == 0) {
508			KSINTR(dev)->intrs[KSTAT_INTR_SPURIOUS]++;
509		} else {
510			KSINTR(dev)->intrs[KSTAT_INTR_HARD]++;
511		}
512	}
513
514	mutex_exit(&dev->mutex);
515
516	if (do_dac)
517		audio_engine_consume(do_dac);
518	if (do_adc)
519		audio_engine_produce(do_adc);
520
521	return (DDI_INTR_CLAIMED);
522}
523
524/*
525 * Audio routines
526 */
527static int
528audioens_format(void *arg)
529{
530	_NOTE(ARGUNUSED(arg));
531
532	/* hardware can also do AUDIO_FORMAT_U8, but no need for it */
533	return (AUDIO_FORMAT_S16_LE);
534}
535
536static int
537audioens_channels(void *arg)
538{
539	audioens_port_t *port = arg;
540
541	return (port->nchan);
542}
543
544static int
545audioens_rate(void *arg)
546{
547	audioens_port_t *port = arg;
548
549	return (port->speed);
550}
551
552static void
553audioens_init_port(audioens_port_t *port)
554{
555	audioens_dev_t	*dev = port->dev;
556	unsigned tmp;
557
558	if (port->suspended)
559		return;
560
561	switch (port->num) {
562	case PORT_DAC:
563		/* Set physical address of the DMA buffer */
564		audioens_writemem(dev, CONC_DAC1CTL_PAGE, CONC_dDAC1PADDR_OFF,
565		    port->paddr);
566		audioens_writemem(dev, CONC_DAC2CTL_PAGE, CONC_dDAC2PADDR_OFF,
567		    port->paddr + (port->nframes * sizeof (int16_t) * 2));
568
569		/* Set DAC rate */
570		SRCSetRate(dev, SRC_DAC1_BASE, port->speed);
571		SRCSetRate(dev, SRC_DAC2_BASE, port->speed);
572
573		/* Configure the channel setup - SPDIF only uses front */
574		tmp = GET32(dev, CONC_dSTATUS_OFF);
575		tmp &= ~(CONC_STATUS_SPKR_MASK | CONC_STATUS_SPDIF_MASK);
576		tmp |= CONC_STATUS_SPKR_4CH | CONC_STATUS_SPDIF_P1;
577		PUT32(dev, CONC_dSTATUS_OFF, tmp);
578
579		/* Set format */
580		PUT8(dev, CONC_bSKIPC_OFF, 0x10);
581		SET8(dev, CONC_bSERFMT_OFF,
582		    CONC_PCM_DAC1_16BIT | CONC_PCM_DAC2_16BIT |
583		    CONC_PCM_DAC1_STEREO | CONC_PCM_DAC2_STEREO);
584
585		/* Set the frame count */
586		audioens_writemem(dev, CONC_DAC1CTL_PAGE, CONC_wDAC1FC_OFF,
587		    port->nframes - 1);
588		audioens_writemem(dev, CONC_DAC2CTL_PAGE, CONC_wDAC2FC_OFF,
589		    port->nframes - 1);
590
591		/* Set # of frames between interrupts */
592		PUT16(dev, CONC_wDAC1IC_OFF, port->fragfr - 1);
593		PUT16(dev, CONC_wDAC2IC_OFF, port->fragfr - 1);
594		break;
595
596	case PORT_ADC:
597		/* Set physical address of the DMA buffer */
598		audioens_writemem(dev, CONC_ADCCTL_PAGE, CONC_dADCPADDR_OFF,
599		    port->paddr);
600
601		/* Set ADC rate */
602		SRCSetRate(dev, SRC_ADC_BASE, port->speed);
603
604		/* Set format - for input we only support 16 bit input */
605		tmp = GET8(dev, CONC_bSERFMT_OFF);
606		tmp |= CONC_PCM_ADC_16BIT;
607		tmp |= CONC_PCM_ADC_STEREO;
608
609		PUT8(dev, CONC_bSKIPC_OFF, 0x10);
610
611		PUT8(dev, CONC_bSERFMT_OFF, tmp);
612
613		/* Set the frame count */
614		audioens_writemem(dev, CONC_ADCCTL_PAGE, CONC_wADCFC_OFF,
615		    port->nframes - 1);
616
617		/* Set # of frames between interrupts */
618		PUT16(dev, CONC_wADCIC_OFF, port->fragfr - 1);
619
620		break;
621	}
622
623	port->frameno = 0;
624}
625
626static int
627audioens_open(void *arg, int flag, unsigned *fragfrp, unsigned *nfragsp,
628    caddr_t *bufp)
629{
630	audioens_port_t	*port = arg;
631	audioens_dev_t	*dev = port->dev;
632	int intrs;
633
634	_NOTE(ARGUNUSED(flag));
635
636	mutex_enter(&dev->mutex);
637
638	if (port->num == PORT_ADC) {
639		intrs = dev->rintrs;
640	} else {
641		intrs = dev->pintrs;
642	}
643
644	/* interrupt at least at 25 Hz, and not more than 250 Hz */
645	intrs = min(250, max(25, intrs));
646
647	port->fragfr = (port->speed / intrs);
648	port->nfrags = AUDIOENS_BUF_LEN /
649	    (port->fragfr * port->nchan * sizeof (int16_t));
650	port->nfrags = max(4, min(port->nfrags, 1024));
651	port->nframes = port->nfrags * port->fragfr;
652	port->trigger = B_FALSE;
653	port->count = 0;
654
655	audioens_init_port(port);
656
657	*fragfrp = port->fragfr;
658	*nfragsp = port->nfrags;
659	*bufp = port->kaddr;
660	mutex_exit(&dev->mutex);
661
662	return (0);
663}
664
665static void
666audioens_start_port(audioens_port_t *port)
667{
668	audioens_dev_t *dev = port->dev;
669
670	if (!port->suspended) {
671		switch (port->num) {
672		case PORT_DAC:
673			SET8(dev, CONC_bDEVCTL_OFF,
674			    CONC_DEVCTL_DAC2_EN | CONC_DEVCTL_DAC1_EN);
675			SET8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_DAC1IE);
676			break;
677		case PORT_ADC:
678			SET8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_ADC_EN);
679			SET8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_ADCIE);
680			break;
681		}
682	}
683}
684
685static void
686audioens_stop_port(audioens_port_t *port)
687{
688	audioens_dev_t *dev = port->dev;
689
690	if (!port->suspended) {
691		switch (port->num) {
692		case PORT_DAC:
693			CLR8(dev, CONC_bDEVCTL_OFF,
694			    CONC_DEVCTL_DAC2_EN | CONC_DEVCTL_DAC1_EN);
695			CLR8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_DAC1IE);
696			break;
697		case PORT_ADC:
698			CLR8(dev, CONC_bDEVCTL_OFF, CONC_DEVCTL_ADC_EN);
699			CLR8(dev, CONC_bSERCTL_OFF, CONC_SERCTL_ADCIE);
700			break;
701		}
702	}
703}
704
705static int
706audioens_start(void *arg)
707{
708	audioens_port_t *port = arg;
709	audioens_dev_t *dev = port->dev;
710
711	mutex_enter(&dev->mutex);
712	if (!port->trigger) {
713		port->trigger = B_TRUE;
714		audioens_start_port(port);
715	}
716	mutex_exit(&dev->mutex);
717
718	return (0);
719}
720
721static void
722audioens_stop(void *arg)
723{
724	audioens_port_t *port = arg;
725	audioens_dev_t *dev = port->dev;
726
727	mutex_enter(&dev->mutex);
728	if (port->trigger) {
729		port->trigger = B_FALSE;
730		audioens_stop_port(port);
731	}
732	mutex_exit(&dev->mutex);
733}
734
735static void
736audioens_update_port(audioens_port_t *port)
737{
738	uint32_t page, offs;
739	int frameno, n;
740
741	switch (port->num) {
742	case PORT_DAC:
743		page = CONC_DAC1CTL_PAGE;
744		offs = CONC_wDAC1FC_OFF;
745		break;
746
747	case PORT_ADC:
748		page = CONC_ADCCTL_PAGE;
749		offs = CONC_wADCFC_OFF;
750		break;
751	}
752
753	/*
754	 * Note that the current frame counter is in the high nybble.
755	 */
756	frameno = audioens_readmem(port->dev, page, offs) >> 16;
757	n = frameno >= port->frameno ?
758	    frameno - port->frameno :
759	    frameno + port->nframes - port->frameno;
760	port->frameno = frameno;
761	port->count += n;
762}
763
764static uint64_t
765audioens_count(void *arg)
766{
767	audioens_port_t *port = arg;
768	audioens_dev_t *dev = port->dev;
769	uint64_t val;
770
771	mutex_enter(&dev->mutex);
772	if (!port->suspended) {
773		audioens_update_port(port);
774	}
775	val = port->count;
776	mutex_exit(&dev->mutex);
777	return (val);
778}
779
780static void
781audioens_close(void *arg)
782{
783	audioens_port_t *port = arg;
784
785	audioens_stop(port);
786}
787
788static void
789audioens_sync(void *arg, unsigned nframes)
790{
791	audioens_port_t *port = arg;
792
793	_NOTE(ARGUNUSED(nframes));
794
795	if (port->num == PORT_ADC) {
796		(void) ddi_dma_sync(port->dmah, 0, 0, DDI_DMA_SYNC_FORCPU);
797	} else {
798		(void) ddi_dma_sync(port->dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
799	}
800}
801
802static size_t
803audioens_qlen(void *arg)
804{
805	audioens_port_t *port = arg;
806
807	return (port->fragfr);
808}
809
810static void
811audioens_chinfo(void *arg, int chan, unsigned *offset, unsigned *incr)
812{
813	audioens_port_t *port = arg;
814
815	if ((port->num == PORT_DAC) && (chan >= 2)) {
816		*offset = (port->nframes * 2) + (chan % 2);
817		*incr = 2;
818	} else {
819		*offset = chan;
820		*incr = 2;
821	}
822}
823
824audio_engine_ops_t audioens_engine_ops = {
825	AUDIO_ENGINE_VERSION,		/* version number */
826	audioens_open,
827	audioens_close,
828	audioens_start,
829	audioens_stop,
830	audioens_count,
831	audioens_format,
832	audioens_channels,
833	audioens_rate,
834	audioens_sync,
835	audioens_qlen,
836	audioens_chinfo
837};
838
839void
840audioens_init_hw(audioens_dev_t *dev)
841{
842	int tmp;
843
844	if ((dev->devid == ENSONIQ_ES5880) ||
845	    (dev->devid == ENSONIQ_ES5880A) ||
846	    (dev->devid == ENSONIQ_ES5880B) ||
847	    (dev->devid == 0x1371 && dev->revision == 7) ||
848	    (dev->devid == 0x1371 && dev->revision >= 9)) {
849
850		/* Have a ES5880 so enable the codec manually */
851		tmp = GET8(dev, CONC_bINTSUMM_OFF) & 0xff;
852		tmp |= 0x20;
853		PUT8(dev, CONC_bINTSUMM_OFF, tmp);
854		for (int i = 0; i < 2000; i++)
855			drv_usecwait(10);
856	}
857
858	SRCInit(dev);
859
860#if 0
861	PUT8(dev, CONC_bSERCTL_OFF, 0x00);
862	PUT8(dev, CONC_bNMIENA_OFF, 0x00); /* NMI off */
863	PUT8(dev, CONC_wNMISTAT_OFF, 0x00); /* PUT8? */
864#endif
865
866	/*
867	 * Turn on CODEC (UART and joystick left disabled)
868	 */
869	tmp = GET32(dev, CONC_bDEVCTL_OFF) & 0xff;
870	tmp &= ~(CONC_DEVCTL_PCICLK_DS | CONC_DEVCTL_XTALCLK_DS);
871	PUT8(dev, CONC_bDEVCTL_OFF, tmp);
872	PUT8(dev, CONC_bUARTCSTAT_OFF, 0x00);
873
874	/* Perform AC97 codec warm reset */
875	tmp = GET8(dev, CONC_bMISCCTL_OFF) & 0xff;
876	PUT8(dev, CONC_bMISCCTL_OFF, tmp | CONC_MISCCTL_SYNC_RES);
877	drv_usecwait(200);
878	PUT8(dev, CONC_bMISCCTL_OFF, tmp);
879	drv_usecwait(200);
880
881	if (dev->revision >= 4) {
882		/* XXX: enable SPDIF - PCM only for now */
883		if (audioens_spdif) {
884			/* enable SPDIF */
885			PUT32(dev, 0x04, GET32(dev, 0x04) | (1 << 18));
886			/* SPDIF out = data from DAC */
887			PUT32(dev, 0x00, GET32(dev, 0x00) | (1 << 26));
888			CLR32(dev, CONC_dSPDIF_OFF, CONC_SPDIF_AC3);
889
890		} else {
891			/* disable spdif out */
892			PUT32(dev, 0x04, GET32(dev, 0x04) & ~(1 << 18));
893			PUT32(dev, 0x00, GET32(dev, 0x00) & ~(1 << 26));
894		}
895
896		/* we want to run each channel independently */
897		CLR32(dev, CONC_dSTATUS_OFF, CONC_STATUS_ECHO);
898	}
899
900	dev->enabled = B_TRUE;
901}
902
903static int
904audioens_init(audioens_dev_t *dev)
905{
906
907	audioens_init_hw(dev);
908
909	/*
910	 * On this hardware, we want to disable the internal speaker by
911	 * default, if it exists.  (We don't have a speakerphone on any
912	 * of these cards, and no SPARC hardware uses it either!)
913	 */
914	ddi_prop_update_int(DDI_DEV_T_NONE, dev->dip, AC97_PROP_SPEAKER, 0);
915
916	/*
917	 * Init mixer
918	 */
919
920	dev->ac97 = ac97_alloc(dev->dip, audioens_rd97, audioens_wr97, dev);
921	if (dev->ac97 == NULL)
922		return (DDI_FAILURE);
923
924	if (ac97_init(dev->ac97, dev->osdev) != 0) {
925		return (DDI_FAILURE);
926	}
927
928	dev->pintrs = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
929	    DDI_PROP_DONTPASS, "play-interrupts", DEFINTS);
930
931	dev->rintrs = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
932	    DDI_PROP_DONTPASS, "record-interrupts", DEFINTS);
933
934	for (int i = 0; i <= PORT_MAX; i++) {
935		audioens_port_t *port;
936		unsigned caps;
937		unsigned dmaflags;
938		size_t rlen;
939		ddi_dma_cookie_t c;
940		unsigned ccnt;
941
942		port = &dev->port[i];
943		port->dev = dev;
944
945		switch (i) {
946		case PORT_DAC:
947			port->nchan = 4;
948			port->speed = 48000;
949			caps = ENGINE_OUTPUT_CAP;
950			dmaflags = DDI_DMA_WRITE | DDI_DMA_CONSISTENT;
951			break;
952
953		case PORT_ADC:
954			port->nchan = 2;
955			port->speed = 48000;
956			caps = ENGINE_INPUT_CAP;
957			dmaflags = DDI_DMA_READ | DDI_DMA_CONSISTENT;
958			break;
959		}
960
961		port->num = i;
962
963		/*
964		 * Allocate DMA resources.
965		 */
966
967		if (ddi_dma_alloc_handle(dev->dip, &dma_attr, DDI_DMA_SLEEP,
968		    NULL, &port->dmah) != DDI_SUCCESS) {
969			audio_dev_warn(dev->osdev,
970			    "port %d: dma handle allocation failed", i);
971			return (DDI_FAILURE);
972		}
973		if (ddi_dma_mem_alloc(port->dmah, AUDIOENS_BUF_LEN, &buf_attr,
974		    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &port->kaddr,
975		    &rlen, &port->acch) != DDI_SUCCESS) {
976			audio_dev_warn(dev->osdev,
977			    "port %d: dma memory allocation failed", i);
978			return (DDI_FAILURE);
979		}
980		/* ensure that the buffer is zeroed out properly */
981		bzero(port->kaddr, rlen);
982		if (ddi_dma_addr_bind_handle(port->dmah, NULL, port->kaddr,
983		    AUDIOENS_BUF_LEN, dmaflags, DDI_DMA_SLEEP, NULL,
984		    &c, &ccnt) != DDI_DMA_MAPPED) {
985			audio_dev_warn(dev->osdev,
986			    "port %d: dma binding failed", i);
987			return (DDI_FAILURE);
988		}
989		port->paddr = c.dmac_address;
990
991		/*
992		 * Allocate and configure audio engine.
993		 */
994		port->engine = audio_engine_alloc(&audioens_engine_ops, caps);
995		if (port->engine == NULL) {
996			audio_dev_warn(dev->osdev,
997			    "port %d: audio_engine_alloc failed", i);
998			return (DDI_FAILURE);
999		}
1000
1001		audio_engine_set_private(port->engine, port);
1002		audio_dev_add_engine(dev->osdev, port->engine);
1003	}
1004
1005	/*
1006	 * Set up kstats for interrupt reporting.
1007	 */
1008	dev->ksp = kstat_create(ddi_driver_name(dev->dip),
1009	    ddi_get_instance(dev->dip), ddi_driver_name(dev->dip),
1010	    "controller", KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT);
1011	if (dev->ksp != NULL) {
1012		kstat_install(dev->ksp);
1013	}
1014
1015	if (audio_dev_register(dev->osdev) != DDI_SUCCESS) {
1016		audio_dev_warn(dev->osdev,
1017		    "unable to register with audio framework");
1018		return (DDI_FAILURE);
1019	}
1020
1021	return (DDI_SUCCESS);
1022}
1023
1024int
1025audioens_setup_interrupts(audioens_dev_t *dev)
1026{
1027	int actual;
1028	uint_t ipri;
1029
1030	if ((ddi_intr_alloc(dev->dip, dev->ihandle, DDI_INTR_TYPE_FIXED,
1031	    0, 1, &actual, DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) ||
1032	    (actual != 1)) {
1033		audio_dev_warn(dev->osdev, "can't alloc intr handle");
1034		return (DDI_FAILURE);
1035	}
1036
1037	if (ddi_intr_get_pri(dev->ihandle[0], &ipri) != DDI_SUCCESS) {
1038		audio_dev_warn(dev->osdev,  "can't determine intr priority");
1039		(void) ddi_intr_free(dev->ihandle[0]);
1040		dev->ihandle[0] = NULL;
1041		return (DDI_FAILURE);
1042	}
1043
1044	if (ddi_intr_add_handler(dev->ihandle[0], audioens_intr, dev,
1045	    NULL) != DDI_SUCCESS) {
1046		audio_dev_warn(dev->osdev, "can't add intr handler");
1047		(void) ddi_intr_free(dev->ihandle[0]);
1048		dev->ihandle[0] = NULL;
1049		return (DDI_FAILURE);
1050	}
1051
1052	mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
1053
1054	return (DDI_SUCCESS);
1055}
1056
1057void
1058audioens_destroy(audioens_dev_t *dev)
1059{
1060	int	i;
1061
1062	if (dev->ihandle[0] != NULL) {
1063		(void) ddi_intr_disable(dev->ihandle[0]);
1064		(void) ddi_intr_remove_handler(dev->ihandle[0]);
1065		(void) ddi_intr_free(dev->ihandle[0]);
1066		mutex_destroy(&dev->mutex);
1067	}
1068
1069	if (dev->ksp != NULL) {
1070		kstat_delete(dev->ksp);
1071	}
1072
1073	/* free up ports, including DMA resources for ports */
1074	for (i = 0; i <= PORT_MAX; i++) {
1075		audioens_port_t	*port = &dev->port[i];
1076
1077		if (port->paddr != 0)
1078			(void) ddi_dma_unbind_handle(port->dmah);
1079		if (port->acch != NULL)
1080			ddi_dma_mem_free(&port->acch);
1081		if (port->dmah != NULL)
1082			ddi_dma_free_handle(&port->dmah);
1083
1084		if (port->engine != NULL) {
1085			audio_dev_remove_engine(dev->osdev, port->engine);
1086			audio_engine_free(port->engine);
1087		}
1088	}
1089
1090	if (dev->acch != NULL) {
1091		ddi_regs_map_free(&dev->acch);
1092	}
1093
1094	if (dev->ac97) {
1095		ac97_free(dev->ac97);
1096	}
1097
1098	if (dev->osdev != NULL) {
1099		audio_dev_free(dev->osdev);
1100	}
1101
1102	kmem_free(dev, sizeof (*dev));
1103}
1104
1105int
1106audioens_attach(dev_info_t *dip)
1107{
1108	uint16_t pci_command, vendor, device;
1109	uint8_t revision;
1110	audioens_dev_t *dev;
1111	ddi_acc_handle_t pcih;
1112	const char *chip_name;
1113	const char *chip_vers;
1114
1115	dev = kmem_zalloc(sizeof (*dev), KM_SLEEP);
1116	dev->dip = dip;
1117	ddi_set_driver_private(dip, dev);
1118
1119	if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) {
1120		audio_dev_warn(dev->osdev, "pci_config_setup failed");
1121		kmem_free(dev, sizeof (*dev));
1122		return (DDI_FAILURE);
1123	}
1124
1125	vendor = pci_config_get16(pcih, PCI_CONF_VENID);
1126	device = pci_config_get16(pcih, PCI_CONF_DEVID);
1127	revision = pci_config_get8(pcih, PCI_CONF_REVID);
1128
1129	if ((vendor != ENSONIQ_VENDOR_ID && vendor != CREATIVE_VENDOR_ID) ||
1130	    (device != ENSONIQ_ES1371 && device != ENSONIQ_ES5880 &&
1131	    device != ENSONIQ_ES5880A && device != ECTIVA_ES1938 &&
1132	    device != ENSONIQ_ES5880B))
1133		goto err_exit;
1134
1135	chip_name = "AudioPCI97";
1136	chip_vers = "unknown";
1137
1138	switch (device) {
1139	case ENSONIQ_ES1371:
1140		chip_name = "AudioPCI97";
1141		switch (revision) {
1142		case 0x02:
1143		case 0x09:
1144		default:
1145			chip_vers = "ES1371";
1146			break;
1147		case 0x04:
1148		case 0x06:
1149		case 0x08:
1150			chip_vers = "ES1373";
1151			break;
1152		case 0x07:
1153			chip_vers = "ES5880";
1154			break;
1155		}
1156		break;
1157
1158	case ENSONIQ_ES5880:
1159		chip_name = "SB PCI128";
1160		chip_vers = "ES5880";
1161		break;
1162	case ENSONIQ_ES5880A:
1163		chip_name = "SB PCI128";
1164		chip_vers = "ES5880A";
1165		break;
1166	case ENSONIQ_ES5880B:
1167		chip_name = "SB PCI128";
1168		chip_vers = "ES5880B";
1169		break;
1170
1171	case ECTIVA_ES1938:
1172		chip_name = "AudioPCI";
1173		chip_vers = "ES1938";
1174		break;
1175	}
1176
1177	dev->revision = revision;
1178	dev->devid = device;
1179
1180	dev->osdev = audio_dev_alloc(dip, 0);
1181	if (dev->osdev == NULL) {
1182		goto err_exit;
1183	}
1184
1185	audio_dev_set_description(dev->osdev, chip_name);
1186	audio_dev_set_version(dev->osdev, chip_vers);
1187
1188	/* set the PCI latency */
1189	if ((audioens_latency == 32) || (audioens_latency == 64) ||
1190	    (audioens_latency == 96))
1191		pci_config_put8(pcih, PCI_CONF_LATENCY_TIMER,
1192		    audioens_latency);
1193
1194	/* activate the device */
1195	pci_command = pci_config_get16(pcih, PCI_CONF_COMM);
1196	pci_command |= PCI_COMM_ME | PCI_COMM_IO;
1197	pci_config_put16(pcih, PCI_CONF_COMM, pci_command);
1198
1199	/* map registers */
1200	if (ddi_regs_map_setup(dip, 1, &dev->regs, 0, 0, &acc_attr,
1201	    &dev->acch) != DDI_SUCCESS) {
1202		audio_dev_warn(dev->osdev, "can't map registers");
1203		goto err_exit;
1204	}
1205
1206	if (audioens_setup_interrupts(dev) != DDI_SUCCESS) {
1207		audio_dev_warn(dev->osdev, "can't register interrupts");
1208		goto err_exit;
1209	}
1210
1211	/* This allocates and configures the engines */
1212	if (audioens_init(dev) != DDI_SUCCESS) {
1213		audio_dev_warn(dev->osdev, "can't init device");
1214		goto err_exit;
1215	}
1216
1217	(void) ddi_intr_enable(dev->ihandle[0]);
1218
1219	pci_config_teardown(&pcih);
1220
1221	ddi_report_dev(dip);
1222
1223	return (DDI_SUCCESS);
1224
1225err_exit:
1226	pci_config_teardown(&pcih);
1227
1228	audioens_destroy(dev);
1229
1230	return (DDI_FAILURE);
1231}
1232
1233int
1234audioens_detach(audioens_dev_t *dev)
1235{
1236	int tmp;
1237
1238	/* first unregister us from the DDI framework, might be busy */
1239	if (audio_dev_unregister(dev->osdev) != DDI_SUCCESS)
1240		return (DDI_FAILURE);
1241
1242	mutex_enter(&dev->mutex);
1243
1244	tmp = GET8(dev, CONC_bSERCTL_OFF) &
1245	    ~(CONC_SERCTL_DAC2IE | CONC_SERCTL_DAC1IE | CONC_SERCTL_ADCIE);
1246	PUT8(dev, CONC_bSERCTL_OFF, tmp);
1247	PUT8(dev, CONC_bSERCTL_OFF, tmp);
1248	PUT8(dev, CONC_bSERCTL_OFF, tmp);
1249	PUT8(dev, CONC_bSERCTL_OFF, tmp);
1250
1251	tmp = GET8(dev, CONC_bDEVCTL_OFF) &
1252	    ~(CONC_DEVCTL_DAC2_EN | CONC_DEVCTL_ADC_EN | CONC_DEVCTL_DAC1_EN);
1253	PUT8(dev, CONC_bDEVCTL_OFF, tmp);
1254	PUT8(dev, CONC_bDEVCTL_OFF, tmp);
1255	PUT8(dev, CONC_bDEVCTL_OFF, tmp);
1256	PUT8(dev, CONC_bDEVCTL_OFF, tmp);
1257
1258	dev->enabled = B_FALSE;
1259
1260	mutex_exit(&dev->mutex);
1261
1262	audioens_destroy(dev);
1263
1264	return (DDI_SUCCESS);
1265}
1266
1267/*ARGSUSED*/
1268static int
1269audioens_resume(audioens_dev_t *dev)
1270{
1271	/* ask framework to reset/relocate engine data */
1272	for (int i = 0; i <= PORT_MAX; i++) {
1273		audio_engine_reset(dev->port[i].engine);
1274	}
1275
1276	/* reinitialize hardware */
1277	audioens_init_hw(dev);
1278
1279	/* restore AC97 state */
1280	ac97_resume(dev->ac97);
1281
1282	/* restart ports */
1283	mutex_enter(&dev->mutex);
1284	for (int i = 0; i < PORT_MAX; i++) {
1285		audioens_port_t	*port = &dev->port[i];
1286		port->suspended = B_FALSE;
1287		audioens_init_port(port);
1288		/* possibly start it up if was going when we suspended */
1289		if (port->trigger) {
1290			audioens_start_port(port);
1291
1292		}
1293	}
1294	mutex_exit(&dev->mutex);
1295	for (int i = 0; i < PORT_MAX; i++) {
1296		audioens_port_t	*port = &dev->port[i];
1297		/* signal callbacks on resume */
1298		if (!port->trigger)
1299			continue;
1300		if (port->num == PORT_ADC) {
1301			audio_engine_produce(port->engine);
1302		} else {
1303			audio_engine_consume(port->engine);
1304		}
1305	}
1306	return (DDI_SUCCESS);
1307}
1308
1309/*ARGSUSED*/
1310static int
1311audioens_suspend(audioens_dev_t *dev)
1312{
1313	/*
1314	 * Stop all engines/DMA data.
1315	 */
1316	mutex_enter(&dev->mutex);
1317	for (int i = 0; i <= PORT_MAX; i++) {
1318		audioens_stop_port(&dev->port[i]);
1319		audioens_update_port(&dev->port[i]);
1320		dev->port[i].suspended = B_TRUE;
1321	}
1322	dev->enabled = B_FALSE;
1323	mutex_exit(&dev->mutex);
1324
1325	/*
1326	 * Framework needs to save off AC'97 state.
1327	 */
1328	ac97_suspend(dev->ac97);
1329
1330	return (DDI_SUCCESS);
1331}
1332
1333static int
1334audioens_quiesce(dev_info_t *dip)
1335{
1336	audioens_dev_t	*dev;
1337	uint8_t		tmp;
1338
1339	if ((dev = ddi_get_driver_private(dip)) == NULL) {
1340		return (DDI_FAILURE);
1341	}
1342
1343	/* This disables all DMA engines and interrupts */
1344	tmp = GET8(dev, CONC_bSERCTL_OFF) &
1345	    ~(CONC_SERCTL_DAC2IE | CONC_SERCTL_DAC1IE | CONC_SERCTL_ADCIE);
1346	PUT8(dev, CONC_bSERCTL_OFF, tmp);
1347	PUT8(dev, CONC_bSERCTL_OFF, tmp);
1348	PUT8(dev, CONC_bSERCTL_OFF, tmp);
1349	PUT8(dev, CONC_bSERCTL_OFF, tmp);
1350
1351	tmp = GET8(dev, CONC_bDEVCTL_OFF) &
1352	    ~(CONC_DEVCTL_DAC2_EN | CONC_DEVCTL_ADC_EN | CONC_DEVCTL_DAC1_EN);
1353	PUT8(dev, CONC_bDEVCTL_OFF, tmp);
1354	PUT8(dev, CONC_bDEVCTL_OFF, tmp);
1355	PUT8(dev, CONC_bDEVCTL_OFF, tmp);
1356	PUT8(dev, CONC_bDEVCTL_OFF, tmp);
1357
1358	return (DDI_SUCCESS);
1359}
1360
1361
1362static int
1363audioens_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1364{
1365	audioens_dev_t *dev;
1366
1367	switch (cmd) {
1368	case DDI_ATTACH:
1369		return (audioens_attach(dip));
1370
1371	case DDI_RESUME:
1372		if ((dev = ddi_get_driver_private(dip)) == NULL) {
1373			return (DDI_FAILURE);
1374		}
1375		return (audioens_resume(dev));
1376
1377	default:
1378		return (DDI_FAILURE);
1379	}
1380}
1381
1382static int
1383audioens_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1384{
1385	audioens_dev_t *dev;
1386
1387	if ((dev = ddi_get_driver_private(dip)) == NULL) {
1388		return (DDI_FAILURE);
1389	}
1390
1391	switch (cmd) {
1392	case DDI_DETACH:
1393		return (audioens_detach(dev));
1394
1395	case DDI_SUSPEND:
1396		return (audioens_suspend(dev));
1397	default:
1398		return (DDI_FAILURE);
1399	}
1400}
1401
1402static int audioens_ddi_attach(dev_info_t *, ddi_attach_cmd_t);
1403static int audioens_ddi_detach(dev_info_t *, ddi_detach_cmd_t);
1404
1405static struct dev_ops audioens_dev_ops = {
1406	DEVO_REV,		/* rev */
1407	0,			/* refcnt */
1408	NULL,			/* getinfo */
1409	nulldev,		/* identify */
1410	nulldev,		/* probe */
1411	audioens_ddi_attach,	/* attach */
1412	audioens_ddi_detach,	/* detach */
1413	nodev,			/* reset */
1414	NULL,			/* cb_ops */
1415	NULL,			/* bus_ops */
1416	NULL,			/* power */
1417	audioens_quiesce,	/* quiesce */
1418};
1419
1420static struct modldrv audioens_modldrv = {
1421	&mod_driverops,			/* drv_modops */
1422	"Ensoniq 1371/1373 Audio",	/* linkinfo */
1423	&audioens_dev_ops,		/* dev_ops */
1424};
1425
1426static struct modlinkage modlinkage = {
1427	MODREV_1,
1428	{ &audioens_modldrv, NULL }
1429};
1430
1431int
1432_init(void)
1433{
1434	int	rv;
1435
1436	audio_init_ops(&audioens_dev_ops, DRVNAME);
1437	if ((rv = mod_install(&modlinkage)) != 0) {
1438		audio_fini_ops(&audioens_dev_ops);
1439	}
1440	return (rv);
1441}
1442
1443int
1444_fini(void)
1445{
1446	int	rv;
1447
1448	if ((rv = mod_remove(&modlinkage)) == 0) {
1449		audio_fini_ops(&audioens_dev_ops);
1450	}
1451	return (rv);
1452}
1453
1454int
1455_info(struct modinfo *modinfop)
1456{
1457	return (mod_info(&modlinkage, modinfop));
1458}
1459