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