xref: /illumos-gate/usr/src/uts/common/io/audio/drv/audiop16x/audiop16x.c (revision 46b592853d0f4f11781b6b0a7533f267c6aee132)
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 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Purpose: Driver for the Creative P16X AC97 audio controller
29  */
30 /*
31  *
32  * Copyright (C) 4Front Technologies 1996-2009.
33  *
34  * This software is released under CDDL 1.0 source license.
35  * See the COPYING file included in the main directory of this source
36  * distribution for the license terms and conditions.
37  */
38 
39 #include <sys/types.h>
40 #include <sys/modctl.h>
41 #include <sys/kmem.h>
42 #include <sys/conf.h>
43 #include <sys/ddi.h>
44 #include <sys/sunddi.h>
45 #include <sys/pci.h>
46 #include <sys/note.h>
47 #include <sys/audio/audio_driver.h>
48 #include <sys/audio/ac97.h>
49 
50 #include "audiop16x.h"
51 
52 /*
53  * These boards use an AC'97 codec, but don't have all of the
54  * various outputs that the AC'97 codec can offer.  We just
55  * suppress them for now.
56  */
57 static char *p16x_remove_ac97[] = {
58 	AUDIO_CTRL_ID_BEEP,
59 	AUDIO_CTRL_ID_VIDEO,
60 	AUDIO_CTRL_ID_MICSRC,
61 	AUDIO_CTRL_ID_SPEAKER,
62 	AUDIO_CTRL_ID_SPKSRC,
63 	NULL
64 };
65 
66 static struct ddi_device_acc_attr dev_attr = {
67 	DDI_DEVICE_ATTR_V0,
68 	DDI_STRUCTURE_LE_ACC,
69 	DDI_STRICTORDER_ACC
70 };
71 
72 static struct ddi_device_acc_attr buf_attr = {
73 	DDI_DEVICE_ATTR_V0,
74 	DDI_NEVERSWAP_ACC,
75 	DDI_STRICTORDER_ACC
76 };
77 
78 static ddi_dma_attr_t dma_attr_buf = {
79 	DMA_ATTR_V0,		/* version number */
80 	0x00000000,		/* low DMA address range */
81 	0xffffffff,		/* high DMA address range */
82 	0xfffffffe,		/* DMA counter register */
83 	4,			/* DMA address alignment */
84 	0x3c,			/* DMA burstsizes */
85 	4,			/* min effective DMA size */
86 	0xffffffff,		/* max DMA xfer size */
87 	0xffffffff,		/* segment boundary */
88 	1,			/* s/g length */
89 	4,			/* granularity of device */
90 	0			/* Bus specific DMA flags */
91 };
92 
93 static int p16x_attach(dev_info_t *);
94 static int p16x_resume(dev_info_t *);
95 static int p16x_detach(p16x_dev_t *);
96 static int p16x_suspend(p16x_dev_t *);
97 
98 static int p16x_open(void *, int, unsigned *, unsigned *, caddr_t *);
99 static void p16x_close(void *);
100 static int p16x_start(void *);
101 static void p16x_stop(void *);
102 static int p16x_format(void *);
103 static int p16x_channels(void *);
104 static int p16x_rate(void *);
105 static uint64_t p16x_count(void *);
106 static void p16x_sync(void *, unsigned);
107 static size_t p16x_qlen(void *);
108 static void p16x_chinfo(void *, int, unsigned *, unsigned *);
109 
110 static uint16_t p16x_read_ac97(void *, uint8_t);
111 static void p16x_write_ac97(void *, uint8_t, uint16_t);
112 static int p16x_alloc_port(p16x_dev_t *, int);
113 static void p16x_update_port(p16x_port_t *);
114 static void p16x_start_port(p16x_port_t *);
115 static void p16x_stop_port(p16x_port_t *);
116 static void p16x_destroy(p16x_dev_t *);
117 static int p16x_setup_intrs(p16x_dev_t *);
118 static void p16x_hwinit(p16x_dev_t *);
119 static uint_t p16x_intr(caddr_t, caddr_t);
120 
121 static audio_engine_ops_t p16x_engine_ops = {
122 	AUDIO_ENGINE_VERSION,
123 	p16x_open,
124 	p16x_close,
125 	p16x_start,
126 	p16x_stop,
127 	p16x_count,
128 	p16x_format,
129 	p16x_channels,
130 	p16x_rate,
131 	p16x_sync,
132 	p16x_qlen,
133 	p16x_chinfo,
134 };
135 
136 static unsigned int
137 read_reg(p16x_dev_t *dev, int reg, int chn)
138 {
139 	unsigned int val;
140 
141 	mutex_enter(&dev->low_mutex);
142 	OUTL(dev, (reg << 16) | (chn & 0xffff), PTR);	/* Pointer */
143 	val = INL(dev, DR);	/* Data */
144 	mutex_exit(&dev->low_mutex);
145 
146 	return (val);
147 }
148 
149 static void
150 write_reg(p16x_dev_t *dev, int reg, int chn, unsigned int value)
151 {
152 
153 	mutex_enter(&dev->low_mutex);
154 	OUTL(dev, (reg << 16) | (chn & 0xffff), PTR);	/* Pointer */
155 	OUTL(dev, value, DR);	/* Data */
156 	mutex_exit(&dev->low_mutex);
157 }
158 
159 static uint16_t
160 p16x_read_ac97(void *arg, uint8_t index)
161 {
162 	p16x_dev_t *dev = arg;
163 	uint16_t value;
164 	int i;
165 
166 	mutex_enter(&dev->low_mutex);
167 	OUTB(dev, index, AC97A);
168 	for (i = 0; i < 10000; i++)
169 		if (INB(dev, AC97A) & 0x80)
170 			break;
171 	value = INW(dev, AC97D);
172 	mutex_exit(&dev->low_mutex);
173 	return (value);
174 }
175 
176 static void
177 p16x_write_ac97(void *arg, uint8_t index, uint16_t data)
178 {
179 	p16x_dev_t *dev = arg;
180 	unsigned int i;
181 
182 	mutex_enter(&dev->low_mutex);
183 	OUTB(dev, index, AC97A);
184 	for (i = 0; i < 10000; i++)
185 		if (INB(dev, AC97A) & 0x80)
186 			break;
187 	OUTW(dev, data, AC97D);
188 	mutex_exit(&dev->low_mutex);
189 }
190 
191 static uint_t
192 p16x_intr(caddr_t argp, caddr_t nocare)
193 {
194 	p16x_dev_t	*dev = (void *)argp;
195 	unsigned int	status;
196 	audio_engine_t	*consume = NULL;
197 	audio_engine_t	*produce = NULL;
198 
199 	_NOTE(ARGUNUSED(nocare));
200 
201 	mutex_enter(&dev->mutex);
202 	if (dev->suspended) {
203 		mutex_exit(&dev->mutex);
204 		return (DDI_INTR_UNCLAIMED);
205 	}
206 	/* Read the interrupt status */
207 	status = INL(dev, IP);
208 	OUTL(dev, status, IP);	/* Acknowledge */
209 
210 	if (!(status & INTR_ALL)) {
211 		mutex_exit(&dev->mutex);
212 		return (DDI_INTR_UNCLAIMED);
213 	}
214 
215 	if (status & INTR_PCI) {
216 		audio_dev_warn(dev->adev, "PCI error triggered, PCI status %x",
217 		    pci_config_get16(dev->pcih, PCI_CONF_STAT));
218 	}
219 
220 	if ((status & (INTR_PFF | INTR_PFH)) &&
221 	    (dev->port[P16X_PLAY]->started)) {
222 		consume = dev->port[P16X_PLAY]->engine;
223 	}
224 
225 	if ((status & (INTR_RFF | INTR_RFH)) &&
226 	    (dev->port[P16X_REC]->started)) {
227 		produce = dev->port[P16X_REC]->engine;
228 	}
229 
230 	mutex_exit(&dev->mutex);
231 
232 	if (consume) {
233 		audio_engine_consume(consume);
234 	}
235 
236 	if (produce) {
237 		audio_engine_produce(produce);
238 	}
239 
240 	return (DDI_INTR_CLAIMED);
241 }
242 
243 /*
244  * Audio routines
245  */
246 
247 static void
248 p16x_init_port(p16x_port_t *port)
249 {
250 	p16x_dev_t	*dev = port->dev;
251 
252 	if (port->suspended)
253 		return;
254 
255 	if (port->port_num == P16X_REC) {
256 		write_reg(dev, CRFA, 0, 0);
257 		write_reg(dev, CRCAV, 0, 0);
258 
259 	} else {
260 		for (int i = 0; i < 3; i++) {
261 			write_reg(dev, PTBA, i, 0);
262 			write_reg(dev, PTBS, i, 0);
263 			write_reg(dev, PTCA, i, 0);
264 			write_reg(dev, PFEA, i, 0);
265 			write_reg(dev, CPFA, i, 0);
266 			write_reg(dev, CPCAV, i, 0);
267 		}
268 
269 	}
270 }
271 
272 
273 static int
274 p16x_open(void *arg, int flag, uint_t *fragfrp, uint_t *nfp, caddr_t *bufp)
275 {
276 	p16x_port_t	*port = arg;
277 	p16x_dev_t	*dev = port->dev;
278 
279 	_NOTE(ARGUNUSED(flag));
280 
281 	mutex_enter(&dev->mutex);
282 
283 	port->started = B_FALSE;
284 	port->count = 0;
285 	port->offset = 0;
286 
287 	p16x_init_port(port);
288 
289 	*fragfrp = port->fragfr;
290 	*nfp = port->nfrags;
291 	*bufp = port->buf_kaddr;
292 	mutex_exit(&dev->mutex);
293 
294 	return (0);
295 }
296 
297 void
298 p16x_close(void *arg)
299 {
300 	p16x_port_t	 *port = arg;
301 	p16x_dev_t	 *dev = port->dev;
302 
303 	mutex_enter(&dev->mutex);
304 	p16x_stop_port(port);
305 	port->started = B_FALSE;
306 	mutex_exit(&dev->mutex);
307 }
308 
309 int
310 p16x_start(void *arg)
311 {
312 	p16x_port_t	*port = arg;
313 	p16x_dev_t	*dev = port->dev;
314 
315 	mutex_enter(&dev->mutex);
316 	if (!port->started) {
317 		p16x_start_port(port);
318 		port->started = B_TRUE;
319 	}
320 	mutex_exit(&dev->mutex);
321 	return (0);
322 }
323 
324 void
325 p16x_stop(void *arg)
326 {
327 	p16x_port_t	*port = arg;
328 	p16x_dev_t	*dev = port->dev;
329 
330 	mutex_enter(&dev->mutex);
331 	if (port->started) {
332 		p16x_stop_port(port);
333 		port->started = B_FALSE;
334 	}
335 	mutex_exit(&dev->mutex);
336 }
337 
338 int
339 p16x_format(void *arg)
340 {
341 	_NOTE(ARGUNUSED(arg));
342 
343 	return (AUDIO_FORMAT_S16_LE);
344 }
345 
346 int
347 p16x_channels(void *arg)
348 {
349 	p16x_port_t *port = arg;
350 
351 	return (port->nchan);
352 }
353 
354 int
355 p16x_rate(void *arg)
356 {
357 	_NOTE(ARGUNUSED(arg));
358 
359 	return (48000);
360 }
361 
362 void
363 p16x_sync(void *arg, unsigned nframes)
364 {
365 	p16x_port_t *port = arg;
366 	_NOTE(ARGUNUSED(nframes));
367 
368 	(void) ddi_dma_sync(port->buf_dmah, 0, 0, port->syncdir);
369 }
370 
371 size_t
372 p16x_qlen(void *arg)
373 {
374 	_NOTE(ARGUNUSED(arg));
375 	return (0);
376 }
377 
378 uint64_t
379 p16x_count(void *arg)
380 {
381 	p16x_port_t	*port = arg;
382 	p16x_dev_t	*dev = port->dev;
383 	uint64_t	val;
384 
385 	mutex_enter(&dev->mutex);
386 	if (port->started && !dev->suspended)
387 		p16x_update_port(port);
388 	val = port->count;
389 	mutex_exit(&dev->mutex);
390 
391 	return (val);
392 }
393 
394 static void
395 p16x_chinfo(void *arg, int chan, unsigned *offset, unsigned *incr)
396 {
397 	p16x_port_t *port = arg;
398 	unsigned mult;
399 
400 	if (port->port_num == P16X_PLAY) {
401 		switch (chan) {
402 		case 0:	/* left front */
403 		case 1:	/* right front */
404 			mult = 0;
405 			break;
406 		case 2:	/* center */
407 		case 3:	/* lfe */
408 			mult = 2;
409 			break;
410 		case 4:	/* left surround */
411 		case 5:	/* right surround */
412 			mult = 1;
413 			break;
414 		}
415 		*offset = (port->buf_frames * 2 * mult) + (chan % 2);
416 		*incr = 2;
417 	} else {
418 		*offset = chan;
419 		*incr = 2;
420 	}
421 }
422 
423 /* private implementation bits */
424 
425 void
426 p16x_update_port(p16x_port_t *port)
427 {
428 	p16x_dev_t	*dev = port->dev;
429 	uint32_t	offset, n;
430 
431 	if (dev->suspended)
432 		return;
433 
434 	if (port->port_num == P16X_PLAY) {
435 		offset = read_reg(dev, CPFA, 0);
436 	} else {
437 		offset = read_reg(dev, CRFA, 0);
438 	}
439 
440 	/* get the offset, and switch to frames */
441 	offset /= (2 * sizeof (uint16_t));
442 
443 	if (offset >= port->offset) {
444 		n = offset - port->offset;
445 	} else {
446 		n = offset + (port->buf_frames - port->offset);
447 	}
448 	port->offset = offset;
449 	port->count += n;
450 }
451 
452 void
453 p16x_start_port(p16x_port_t *port)
454 {
455 	p16x_dev_t	*dev = port->dev;
456 	unsigned int	tmp;
457 
458 	ASSERT(mutex_owned(&dev->mutex));
459 
460 	if (dev->suspended)
461 		return;
462 
463 	if (port->port_num == P16X_REC) {
464 		/* Enable Rec Channel */
465 		tmp = read_reg(dev, SA, 0);
466 		tmp |= 0x100;
467 		write_reg(dev, SA, 0, tmp);
468 		tmp = INL(dev, IE);
469 		tmp |= INTR_REC;
470 		OUTL(dev, tmp, IE);
471 	} else {
472 		/* Enable play channel and go */
473 		tmp = read_reg(dev, SA, 0);
474 		tmp |= 7;
475 		write_reg(dev, SA, 0, tmp);
476 		tmp = INL(dev, IE);
477 		tmp |= INTR_PLAY;
478 		OUTL(dev, tmp, IE);
479 	}
480 }
481 
482 void
483 p16x_stop_port(p16x_port_t *port)
484 {
485 	p16x_dev_t	*dev = port->dev;
486 	unsigned int tmp;
487 
488 
489 	if (dev->suspended)
490 		return;
491 
492 	if (port->port_num == P16X_REC) {
493 		/* Disable rec channel */
494 		tmp = read_reg(dev, SA, 0);
495 		tmp &= ~0x100;
496 		write_reg(dev, SA, 0, tmp);
497 		tmp = INL(dev, IE);
498 		tmp &= ~INTR_REC;
499 		OUTL(dev, tmp, IE);
500 
501 	} else {
502 		/* Disable Play channel */
503 		tmp = read_reg(dev, SA, 0);
504 		tmp &= ~7;
505 		write_reg(dev, SA, 0, tmp);
506 		tmp = INL(dev, IE);
507 		tmp &= ~INTR_PLAY;
508 		OUTL(dev, tmp, IE);
509 	}
510 }
511 
512 int
513 p16x_alloc_port(p16x_dev_t *dev, int num)
514 {
515 	p16x_port_t		*port;
516 	size_t			len;
517 	ddi_dma_cookie_t	cookie;
518 	uint_t			count;
519 	int			dir;
520 	char			*prop;
521 	unsigned		caps;
522 	audio_dev_t		*adev;
523 
524 	adev = dev->adev;
525 	port = kmem_zalloc(sizeof (*port), KM_SLEEP);
526 	dev->port[num] = port;
527 	port->dev = dev;
528 	port->started = B_FALSE;
529 
530 	switch (num) {
531 	case P16X_REC:
532 		prop = "record-interrupts";
533 		port->syncdir = DDI_DMA_SYNC_FORKERNEL;
534 		caps = ENGINE_INPUT_CAP;
535 		dir = DDI_DMA_READ;
536 		port->port_num = P16X_REC;
537 		port->nchan = 2;
538 		break;
539 	case P16X_PLAY:
540 		prop = "play-interrupts";
541 		port->syncdir = DDI_DMA_SYNC_FORDEV;
542 		caps = ENGINE_OUTPUT_CAP;
543 		dir = DDI_DMA_WRITE;
544 		port->port_num = P16X_PLAY;
545 		port->nchan = 6;
546 		break;
547 	default:
548 		return (DDI_FAILURE);
549 	}
550 
551 	/* figure out fragment configuration */
552 	port->intrs = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
553 	    DDI_PROP_DONTPASS, prop, P16X_DEF_INTRS);
554 
555 	/* make sure the values are good */
556 	if (port->intrs < P16X_MIN_INTRS) {
557 		audio_dev_warn(adev, "%s too low, %d, reset to %d",
558 		    prop, port->intrs, P16X_MIN_INTRS);
559 		port->intrs = P16X_MIN_INTRS;
560 	} else if (port->intrs > P16X_MAX_INTRS) {
561 		audio_dev_warn(adev, "%s too high, %d, reset to %d",
562 		    prop, port->intrs, P16X_DEF_INTRS);
563 		port->intrs = P16X_DEF_INTRS;
564 	}
565 
566 	/*
567 	 * This needs the very latest Boomer changes.
568 	 */
569 	port->nfrags = 2;
570 	port->fragfr = 48000 / port->intrs;
571 	/*
572 	 * The device operates in pairs of dwords at a time, for
573 	 * performance reasons.	 So make sure that our buffer is
574 	 * arranged as a whole number of these.	 We could probably
575 	 * fine tune by just ensuring that the overall buffer was 128
576 	 * (64 for half and 64 for full), but this is simpler.
577 	 */
578 	port->fragfr = (port->fragfr + 63) & ~(63);
579 	port->fragsz = port->fragfr * port->nchan * 2; /* 16 bit frames */
580 	port->buf_size = port->nfrags * port->fragsz;
581 	port->buf_frames = port->fragfr * port->nfrags;
582 
583 	/* now allocate buffers */
584 	if (ddi_dma_alloc_handle(dev->dip, &dma_attr_buf, DDI_DMA_SLEEP, NULL,
585 	    &port->buf_dmah) != DDI_SUCCESS) {
586 		audio_dev_warn(adev, "failed to allocate BUF handle");
587 		return (DDI_FAILURE);
588 	}
589 
590 	if (ddi_dma_mem_alloc(port->buf_dmah, port->buf_size,
591 	    &buf_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
592 	    &port->buf_kaddr, &len, &port->buf_acch) != DDI_SUCCESS) {
593 		audio_dev_warn(adev, "failed to allocate BUF memory");
594 		return (DDI_FAILURE);
595 	}
596 
597 	if (ddi_dma_addr_bind_handle(port->buf_dmah, NULL, port->buf_kaddr,
598 	    len, DDI_DMA_CONSISTENT | dir, DDI_DMA_SLEEP, NULL, &cookie,
599 	    &count) != DDI_SUCCESS) {
600 		audio_dev_warn(adev, "failed binding BUF DMA handle");
601 		return (DDI_FAILURE);
602 	}
603 	port->buf_paddr = cookie.dmac_address;
604 
605 	port->engine = audio_engine_alloc(&p16x_engine_ops, caps);
606 	if (port->engine == NULL) {
607 		audio_dev_warn(adev, "audio_engine_alloc failed");
608 		return (DDI_FAILURE);
609 	}
610 
611 	audio_engine_set_private(port->engine, port);
612 	audio_dev_add_engine(adev, port->engine);
613 
614 	return (DDI_SUCCESS);
615 }
616 
617 void
618 p16x_destroy(p16x_dev_t *dev)
619 {
620 	if (dev->ih != NULL) {
621 		(void) ddi_intr_disable(dev->ih);
622 		(void) ddi_intr_remove_handler(dev->ih);
623 		(void) ddi_intr_free(dev->ih);
624 		mutex_destroy(&dev->mutex);
625 		mutex_destroy(&dev->low_mutex);
626 	}
627 
628 	if (dev->ksp) {
629 		kstat_delete(dev->ksp);
630 	}
631 
632 	for (int i = 0; i < P16X_NUM_PORT; i++) {
633 		p16x_port_t *port = dev->port[i];
634 		if (!port)
635 			continue;
636 		if (port->engine) {
637 			audio_dev_remove_engine(dev->adev, port->engine);
638 			audio_engine_free(port->engine);
639 		}
640 		if (port->buf_paddr) {
641 			(void) ddi_dma_unbind_handle(port->buf_dmah);
642 		}
643 		if (port->buf_acch) {
644 			ddi_dma_mem_free(&port->buf_acch);
645 		}
646 		if (port->buf_dmah) {
647 			ddi_dma_free_handle(&port->buf_dmah);
648 		}
649 		kmem_free(port, sizeof (*port));
650 	}
651 
652 	if (dev->ac97 != NULL) {
653 		ac97_free(dev->ac97);
654 	}
655 	if (dev->adev != NULL) {
656 		audio_dev_free(dev->adev);
657 	}
658 	if (dev->regsh != NULL) {
659 		ddi_regs_map_free(&dev->regsh);
660 	}
661 	if (dev->pcih != NULL) {
662 		pci_config_teardown(&dev->pcih);
663 	}
664 	kmem_free(dev, sizeof (*dev));
665 }
666 
667 void
668 p16x_hwinit(p16x_dev_t *dev)
669 {
670 	p16x_port_t		*port;
671 	uint32_t		paddr;
672 	uint32_t		chunksz;
673 	int i;
674 
675 	for (i = 0; i < 3; i++) {
676 		write_reg(dev, PTBA, i, 0);
677 		write_reg(dev, PTBS, i, 0);
678 		write_reg(dev, PTCA, i, 0);
679 		write_reg(dev, PFEA, i, 0);
680 		write_reg(dev, CPFA, i, 0);
681 		write_reg(dev, CPCAV, i, 0);
682 		write_reg(dev, CRFA, i, 0);
683 		write_reg(dev, CRCAV, i, 0);
684 	}
685 	write_reg(dev, SCS0, 0, 0x02108504);
686 	write_reg(dev, SCS1, 0, 0x02108504);
687 	write_reg(dev, SCS2, 0, 0x02108504);
688 
689 	/* set the spdif/analog combo jack to analog out */
690 	write_reg(dev, SPC, 0, 0x00000700);
691 	write_reg(dev, EA_aux, 0, 0x0001003f);
692 
693 	port = dev->port[P16X_REC];
694 	/* Set physical address of the DMA buffer */
695 	write_reg(dev, RFBA, 0, port->buf_paddr);
696 	write_reg(dev, RFBS, 0, (port->buf_size) << 16);
697 
698 	/* Set physical address of the DMA buffer */
699 	port = dev->port[P16X_PLAY];
700 	paddr = port->buf_paddr;
701 	chunksz = port->buf_frames * 4;
702 	write_reg(dev, PFBA, 0, paddr);
703 	write_reg(dev, PFBS, 0, chunksz << 16);
704 	paddr += chunksz;
705 	write_reg(dev, PFBA, 1, paddr);
706 	write_reg(dev, PFBS, 1, chunksz << 16);
707 	paddr += chunksz;
708 	write_reg(dev, PFBA, 2, paddr);
709 	write_reg(dev, PFBS, 2, chunksz << 16);
710 
711 	OUTL(dev, 0x1080, GPIO);	/* GPIO */
712 	/* Clear any pending interrupts */
713 	OUTL(dev, INTR_ALL, IP);
714 	OUTL(dev, 0, IE);
715 	OUTL(dev, 0x9, HC);	/* Enable audio */
716 }
717 
718 int
719 p16x_setup_intrs(p16x_dev_t *dev)
720 {
721 	uint_t			ipri;
722 	int			actual;
723 	int			rv;
724 	ddi_intr_handle_t	ih[1];
725 
726 	rv = ddi_intr_alloc(dev->dip, ih, DDI_INTR_TYPE_FIXED,
727 	    0, 1, &actual, DDI_INTR_ALLOC_STRICT);
728 	if ((rv != DDI_SUCCESS) || (actual != 1)) {
729 		audio_dev_warn(dev->adev,
730 		    "Can't alloc interrupt handle (rv %d actual %d)",
731 		    rv, actual);
732 		return (DDI_FAILURE);
733 	}
734 
735 	if (ddi_intr_get_pri(ih[0], &ipri) != DDI_SUCCESS) {
736 		audio_dev_warn(dev->adev, "Can't get interrupt priority");
737 		(void) ddi_intr_free(ih[0]);
738 		return (DDI_FAILURE);
739 	}
740 
741 	if (ddi_intr_add_handler(ih[0], p16x_intr, dev, NULL) !=
742 	    DDI_SUCCESS) {
743 		audio_dev_warn(dev->adev, "Can't add interrupt handler");
744 		(void) ddi_intr_free(ih[0]);
745 		return (DDI_FAILURE);
746 	}
747 
748 	dev->ih = ih[0];
749 	mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
750 	mutex_init(&dev->low_mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
751 	return (DDI_SUCCESS);
752 }
753 
754 int
755 p16x_attach(dev_info_t *dip)
756 {
757 	uint16_t	vendor, device;
758 	p16x_dev_t	*dev;
759 	ddi_acc_handle_t pcih;
760 
761 	dev = kmem_zalloc(sizeof (*dev), KM_SLEEP);
762 	dev->dip = dip;
763 	ddi_set_driver_private(dip, dev);
764 
765 	/* we don't support high level interrupts in the driver */
766 	if (ddi_intr_hilevel(dip, 0) != 0) {
767 		cmn_err(CE_WARN,
768 		    "!%s%d: unsupported high level interrupt",
769 		    ddi_driver_name(dip), ddi_get_instance(dip));
770 		return (DDI_FAILURE);
771 	}
772 
773 	if (ddi_get_iblock_cookie(dip, 0, &dev->iblock) != DDI_SUCCESS) {
774 		cmn_err(CE_WARN,
775 		    "!%s%d: cannot get iblock cookie",
776 		    ddi_driver_name(dip), ddi_get_instance(dip));
777 		kmem_free(dev, sizeof (*dev));
778 		return (DDI_FAILURE);
779 	}
780 	mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, dev->iblock);
781 	mutex_init(&dev->low_mutex, NULL, MUTEX_DRIVER, dev->iblock);
782 
783 	if ((dev->adev = audio_dev_alloc(dip, 0)) == NULL) {
784 		cmn_err(CE_WARN, "audio_dev_alloc failed");
785 		goto error;
786 	}
787 
788 	if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) {
789 		audio_dev_warn(dev->adev, "pci_config_setup failed");
790 		goto error;
791 	}
792 	dev->pcih = pcih;
793 
794 	vendor = pci_config_get16(pcih, PCI_CONF_VENID);
795 	device = pci_config_get16(pcih, PCI_CONF_DEVID);
796 	if (vendor != CREATIVE_VENDOR_ID ||
797 	    device != SB_P16X_ID) {
798 		audio_dev_warn(dev->adev, "Hardware not recognized "
799 		    "(vendor=%x, dev=%x)", vendor, device);
800 		goto error;
801 	}
802 
803 	/* set PCI command register */
804 	pci_config_put16(pcih, PCI_CONF_COMM,
805 	    pci_config_get16(pcih, PCI_CONF_COMM) |
806 	    PCI_COMM_MAE | PCI_COMM_IO);
807 
808 
809 	if ((ddi_regs_map_setup(dip, 1, &dev->base, 0, 0, &dev_attr,
810 	    &dev->regsh)) != DDI_SUCCESS) {
811 		audio_dev_warn(dev->adev, "failed to map registers");
812 		goto error;
813 	}
814 
815 	audio_dev_set_description(dev->adev, "Creative Sound Blaster Live!");
816 	audio_dev_set_version(dev->adev, "SBO200");
817 
818 	if ((p16x_alloc_port(dev, P16X_PLAY) != DDI_SUCCESS) ||
819 	    (p16x_alloc_port(dev, P16X_REC) != DDI_SUCCESS)) {
820 		goto error;
821 	}
822 
823 	p16x_hwinit(dev);
824 
825 	/* set up the interrupt handler */
826 	if (p16x_setup_intrs(dev) != DDI_SUCCESS) {
827 		goto error;
828 	}
829 
830 	/* Enable PCI interrupts */
831 	OUTL(dev, INTR_PCI, IE);
832 
833 	dev->ac97 = ac97_allocate(dev->adev, dip,
834 	    p16x_read_ac97, p16x_write_ac97, dev);
835 	if (dev->ac97 == NULL) {
836 		audio_dev_warn(dev->adev, "failed to allocate ac97 handle");
837 		goto error;
838 	}
839 
840 	ac97_probe_controls(dev->ac97);
841 
842 	/* remove the AC'97 controls we don't want to expose */
843 	for (int i = 0; p16x_remove_ac97[i]; i++) {
844 		ac97_ctrl_t *ctrl;
845 		ctrl = ac97_control_find(dev->ac97, p16x_remove_ac97[i]);
846 		if (ctrl != NULL) {
847 			ac97_control_unregister(ctrl);
848 		}
849 	}
850 
851 	ac97_register_controls(dev->ac97);
852 
853 	/* set up kernel statistics */
854 	if ((dev->ksp = kstat_create(P16X_NAME, ddi_get_instance(dip),
855 	    P16X_NAME, "controller", KSTAT_TYPE_INTR, 1,
856 	    KSTAT_FLAG_PERSISTENT)) != NULL) {
857 		kstat_install(dev->ksp);
858 	}
859 
860 	if (audio_dev_register(dev->adev) != DDI_SUCCESS) {
861 		audio_dev_warn(dev->adev, "unable to register with framework");
862 		goto error;
863 	}
864 
865 	(void) ddi_intr_enable(dev->ih);
866 	ddi_report_dev(dip);
867 
868 	return (DDI_SUCCESS);
869 
870 error:
871 	p16x_destroy(dev);
872 	return (DDI_FAILURE);
873 }
874 
875 int
876 p16x_resume(dev_info_t *dip)
877 {
878 	p16x_dev_t *dev;
879 
880 	dev = ddi_get_driver_private(dip);
881 
882 	p16x_hwinit(dev);
883 
884 	/* allow ac97 operations again */
885 	ac97_resume(dev->ac97);
886 
887 	mutex_enter(&dev->mutex);
888 	dev->suspended = B_FALSE;
889 
890 	for (int i = 0; i < P16X_NUM_PORT; i++) {
891 
892 		p16x_port_t *port = dev->port[i];
893 
894 		if (port->engine != NULL)
895 			audio_engine_reset(port->engine);
896 
897 		/* reset the port */
898 		p16x_init_port(port);
899 
900 		if (port->started) {
901 			p16x_start_port(port);
902 		} else {
903 			p16x_stop_port(port);
904 		}
905 	}
906 	mutex_exit(&dev->mutex);
907 	return (DDI_SUCCESS);
908 }
909 
910 int
911 p16x_detach(p16x_dev_t *dev)
912 {
913 	if (audio_dev_unregister(dev->adev) != DDI_SUCCESS)
914 		return (DDI_FAILURE);
915 
916 	p16x_destroy(dev);
917 	return (DDI_SUCCESS);
918 }
919 
920 int
921 p16x_suspend(p16x_dev_t *dev)
922 {
923 	ac97_suspend(dev->ac97);
924 
925 	mutex_enter(&dev->mutex);
926 	for (int i = 0; i < P16X_NUM_PORT; i++) {
927 
928 		p16x_port_t *port = dev->port[i];
929 		p16x_stop_port(port);
930 	}
931 
932 	write_reg(dev, SA, 0, 0);
933 	OUTL(dev, 0x00, IE);	/* Interrupt disable */
934 	OUTL(dev, 0x01, HC);
935 
936 	dev->suspended = B_TRUE;
937 	mutex_exit(&dev->mutex);
938 	return (DDI_SUCCESS);
939 }
940 
941 static int p16x_ddi_attach(dev_info_t *, ddi_attach_cmd_t);
942 static int p16x_ddi_detach(dev_info_t *, ddi_detach_cmd_t);
943 static int p16x_ddi_quiesce(dev_info_t *);
944 
945 static struct dev_ops p16x_dev_ops = {
946 	DEVO_REV,		/* rev */
947 	0,			/* refcnt */
948 	NULL,			/* getinfo */
949 	nulldev,		/* identify */
950 	nulldev,		/* probe */
951 	p16x_ddi_attach,	/* attach */
952 	p16x_ddi_detach,	/* detach */
953 	nodev,			/* reset */
954 	NULL,			/* cb_ops */
955 	NULL,			/* bus_ops */
956 	NULL,			/* power */
957 	p16x_ddi_quiesce,	/* quiesce */
958 };
959 
960 static struct modldrv p16x_modldrv = {
961 	&mod_driverops,		/* drv_modops */
962 	"Creative P16X Audio",	/* linkinfo */
963 	&p16x_dev_ops,		/* dev_ops */
964 };
965 
966 static struct modlinkage modlinkage = {
967 	MODREV_1,
968 	{ &p16x_modldrv, NULL }
969 };
970 
971 int
972 _init(void)
973 {
974 	int	rv;
975 
976 	audio_init_ops(&p16x_dev_ops, P16X_NAME);
977 	if ((rv = mod_install(&modlinkage)) != 0) {
978 		audio_fini_ops(&p16x_dev_ops);
979 	}
980 	return (rv);
981 }
982 
983 int
984 _fini(void)
985 {
986 	int	rv;
987 
988 	if ((rv = mod_remove(&modlinkage)) == 0) {
989 		audio_fini_ops(&p16x_dev_ops);
990 	}
991 	return (rv);
992 }
993 
994 int
995 _info(struct modinfo *modinfop)
996 {
997 	return (mod_info(&modlinkage, modinfop));
998 }
999 
1000 int
1001 p16x_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1002 {
1003 	switch (cmd) {
1004 	case DDI_ATTACH:
1005 		return (p16x_attach(dip));
1006 
1007 	case DDI_RESUME:
1008 		return (p16x_resume(dip));
1009 
1010 	default:
1011 		return (DDI_FAILURE);
1012 	}
1013 }
1014 
1015 int
1016 p16x_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1017 {
1018 	p16x_dev_t *dev;
1019 
1020 	dev = ddi_get_driver_private(dip);
1021 
1022 	switch (cmd) {
1023 	case DDI_DETACH:
1024 		return (p16x_detach(dev));
1025 
1026 	case DDI_SUSPEND:
1027 		return (p16x_suspend(dev));
1028 
1029 	default:
1030 		return (DDI_FAILURE);
1031 	}
1032 }
1033 
1034 int
1035 p16x_ddi_quiesce(dev_info_t *dip)
1036 {
1037 	p16x_dev_t	*dev;
1038 
1039 	dev = ddi_get_driver_private(dip);
1040 
1041 	for (int i = 0; i < P16X_NUM_PORT; i++) {
1042 
1043 		p16x_port_t *port = dev->port[i];
1044 		p16x_stop_port(port);
1045 	}
1046 
1047 	write_reg(dev, SA, 0, 0);
1048 	OUTL(dev, 0x00, IE);	    /* Interrupt disable */
1049 	OUTL(dev, 0x01, HC);
1050 
1051 	return (DDI_SUCCESS);
1052 }
1053