xref: /illumos-gate/usr/src/uts/common/io/audio/drv/audiop16x/audiop16x.c (revision a4faba164aa153855d621c694fc5aa75dd183b81)
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 	 * We choose 6 fragments for a specific reason.	 Since the
568 	 * device only has full and half interrupts, and since the
569 	 * framework will try to queue up 4 frags automatically, this
570 	 * ensures that we will be able to queue all 4 fragments, and
571 	 * it avoids a potential underrun that you would get with 8
572 	 * fragments.  (More than 8 fragments is guaranteed to cause
573 	 * underruns in Boomer.)
574 	 *
575 	 * Boomer needs to get smarter about dealing with devices with
576 	 * fewer fragment counts.  This device, for instance, should
577 	 * really be represented with just two fragments.  That wll
578 	 * cause an infinite loop in Boomer, when Boomer tries to
579 	 * queue up 4 fragments.
580 	 */
581 	port->nfrags = 6;
582 	port->fragfr = 48000 / port->intrs;
583 	/*
584 	 * The device operates in pairs of dwords at a time, for
585 	 * performance reasons.	 So make sure that our buffer is
586 	 * arranged as a whole number of these.	 We could probably
587 	 * fine tune by just ensuring that the overall buffer was 128
588 	 * (64 for half and 64 for full), but this is simpler.
589 	 */
590 	port->fragfr = (port->fragfr + 63) & ~(63);
591 	port->fragsz = port->fragfr * port->nchan * 2; /* 16 bit frames */
592 	port->buf_size = port->nfrags * port->fragsz;
593 	port->buf_frames = port->fragfr * port->nfrags;
594 
595 	/* now allocate buffers */
596 	if (ddi_dma_alloc_handle(dev->dip, &dma_attr_buf, DDI_DMA_SLEEP, NULL,
597 	    &port->buf_dmah) != DDI_SUCCESS) {
598 		audio_dev_warn(adev, "failed to allocate BUF handle");
599 		return (DDI_FAILURE);
600 	}
601 
602 	if (ddi_dma_mem_alloc(port->buf_dmah, port->buf_size,
603 	    &buf_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
604 	    &port->buf_kaddr, &len, &port->buf_acch) != DDI_SUCCESS) {
605 		audio_dev_warn(adev, "failed to allocate BUF memory");
606 		return (DDI_FAILURE);
607 	}
608 
609 	if (ddi_dma_addr_bind_handle(port->buf_dmah, NULL, port->buf_kaddr,
610 	    len, DDI_DMA_CONSISTENT | dir, DDI_DMA_SLEEP, NULL, &cookie,
611 	    &count) != DDI_SUCCESS) {
612 		audio_dev_warn(adev, "failed binding BUF DMA handle");
613 		return (DDI_FAILURE);
614 	}
615 	port->buf_paddr = cookie.dmac_address;
616 
617 	port->engine = audio_engine_alloc(&p16x_engine_ops, caps);
618 	if (port->engine == NULL) {
619 		audio_dev_warn(adev, "audio_engine_alloc failed");
620 		return (DDI_FAILURE);
621 	}
622 
623 	audio_engine_set_private(port->engine, port);
624 	audio_dev_add_engine(adev, port->engine);
625 
626 	return (DDI_SUCCESS);
627 }
628 
629 void
630 p16x_destroy(p16x_dev_t *dev)
631 {
632 	if (dev->ih != NULL) {
633 		(void) ddi_intr_disable(dev->ih);
634 		(void) ddi_intr_remove_handler(dev->ih);
635 		(void) ddi_intr_free(dev->ih);
636 		mutex_destroy(&dev->mutex);
637 		mutex_destroy(&dev->low_mutex);
638 	}
639 
640 	if (dev->ksp) {
641 		kstat_delete(dev->ksp);
642 	}
643 
644 	for (int i = 0; i < P16X_NUM_PORT; i++) {
645 		p16x_port_t *port = dev->port[i];
646 		if (!port)
647 			continue;
648 		if (port->engine) {
649 			audio_dev_remove_engine(dev->adev, port->engine);
650 			audio_engine_free(port->engine);
651 		}
652 		if (port->buf_paddr) {
653 			(void) ddi_dma_unbind_handle(port->buf_dmah);
654 		}
655 		if (port->buf_acch) {
656 			ddi_dma_mem_free(&port->buf_acch);
657 		}
658 		if (port->buf_dmah) {
659 			ddi_dma_free_handle(&port->buf_dmah);
660 		}
661 		kmem_free(port, sizeof (*port));
662 	}
663 
664 	if (dev->ac97 != NULL) {
665 		ac97_free(dev->ac97);
666 	}
667 	if (dev->adev != NULL) {
668 		audio_dev_free(dev->adev);
669 	}
670 	if (dev->regsh != NULL) {
671 		ddi_regs_map_free(&dev->regsh);
672 	}
673 	if (dev->pcih != NULL) {
674 		pci_config_teardown(&dev->pcih);
675 	}
676 	kmem_free(dev, sizeof (*dev));
677 }
678 
679 void
680 p16x_hwinit(p16x_dev_t *dev)
681 {
682 	p16x_port_t		*port;
683 	uint32_t		paddr;
684 	uint32_t		chunksz;
685 	int i;
686 
687 	for (i = 0; i < 3; i++) {
688 		write_reg(dev, PTBA, i, 0);
689 		write_reg(dev, PTBS, i, 0);
690 		write_reg(dev, PTCA, i, 0);
691 		write_reg(dev, PFEA, i, 0);
692 		write_reg(dev, CPFA, i, 0);
693 		write_reg(dev, CPCAV, i, 0);
694 		write_reg(dev, CRFA, i, 0);
695 		write_reg(dev, CRCAV, i, 0);
696 	}
697 	write_reg(dev, SCS0, 0, 0x02108504);
698 	write_reg(dev, SCS1, 0, 0x02108504);
699 	write_reg(dev, SCS2, 0, 0x02108504);
700 
701 	/* set the spdif/analog combo jack to analog out */
702 	write_reg(dev, SPC, 0, 0x00000700);
703 	write_reg(dev, EA_aux, 0, 0x0001003f);
704 
705 	port = dev->port[P16X_REC];
706 	/* Set physical address of the DMA buffer */
707 	write_reg(dev, RFBA, 0, port->buf_paddr);
708 	write_reg(dev, RFBS, 0, (port->buf_size) << 16);
709 
710 	/* Set physical address of the DMA buffer */
711 	port = dev->port[P16X_PLAY];
712 	paddr = port->buf_paddr;
713 	chunksz = port->buf_frames * 4;
714 	write_reg(dev, PFBA, 0, paddr);
715 	write_reg(dev, PFBS, 0, chunksz << 16);
716 	paddr += chunksz;
717 	write_reg(dev, PFBA, 1, paddr);
718 	write_reg(dev, PFBS, 1, chunksz << 16);
719 	paddr += chunksz;
720 	write_reg(dev, PFBA, 2, paddr);
721 	write_reg(dev, PFBS, 2, chunksz << 16);
722 
723 	OUTL(dev, 0x1080, GPIO);	/* GPIO */
724 	/* Clear any pending interrupts */
725 	OUTL(dev, INTR_ALL, IP);
726 	OUTL(dev, 0, IE);
727 	OUTL(dev, 0x9, HC);	/* Enable audio */
728 }
729 
730 int
731 p16x_setup_intrs(p16x_dev_t *dev)
732 {
733 	uint_t			ipri;
734 	int			actual;
735 	int			rv;
736 	ddi_intr_handle_t	ih[1];
737 
738 	rv = ddi_intr_alloc(dev->dip, ih, DDI_INTR_TYPE_FIXED,
739 	    0, 1, &actual, DDI_INTR_ALLOC_STRICT);
740 	if ((rv != DDI_SUCCESS) || (actual != 1)) {
741 		audio_dev_warn(dev->adev,
742 		    "Can't alloc interrupt handle (rv %d actual %d)",
743 		    rv, actual);
744 		return (DDI_FAILURE);
745 	}
746 
747 	if (ddi_intr_get_pri(ih[0], &ipri) != DDI_SUCCESS) {
748 		audio_dev_warn(dev->adev, "Can't get interrupt priority");
749 		(void) ddi_intr_free(ih[0]);
750 		return (DDI_FAILURE);
751 	}
752 
753 	if (ddi_intr_add_handler(ih[0], p16x_intr, dev, NULL) !=
754 	    DDI_SUCCESS) {
755 		audio_dev_warn(dev->adev, "Can't add interrupt handler");
756 		(void) ddi_intr_free(ih[0]);
757 		return (DDI_FAILURE);
758 	}
759 
760 	dev->ih = ih[0];
761 	mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
762 	mutex_init(&dev->low_mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri));
763 	return (DDI_SUCCESS);
764 }
765 
766 int
767 p16x_attach(dev_info_t *dip)
768 {
769 	uint16_t	vendor, device;
770 	p16x_dev_t	*dev;
771 	ddi_acc_handle_t pcih;
772 
773 	dev = kmem_zalloc(sizeof (*dev), KM_SLEEP);
774 	dev->dip = dip;
775 	ddi_set_driver_private(dip, dev);
776 
777 	/* we don't support high level interrupts in the driver */
778 	if (ddi_intr_hilevel(dip, 0) != 0) {
779 		cmn_err(CE_WARN,
780 		    "!%s%d: unsupported high level interrupt",
781 		    ddi_driver_name(dip), ddi_get_instance(dip));
782 		return (DDI_FAILURE);
783 	}
784 
785 	if (ddi_get_iblock_cookie(dip, 0, &dev->iblock) != DDI_SUCCESS) {
786 		cmn_err(CE_WARN,
787 		    "!%s%d: cannot get iblock cookie",
788 		    ddi_driver_name(dip), ddi_get_instance(dip));
789 		kmem_free(dev, sizeof (*dev));
790 		return (DDI_FAILURE);
791 	}
792 	mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, dev->iblock);
793 	mutex_init(&dev->low_mutex, NULL, MUTEX_DRIVER, dev->iblock);
794 
795 	if ((dev->adev = audio_dev_alloc(dip, 0)) == NULL) {
796 		cmn_err(CE_WARN, "audio_dev_alloc failed");
797 		goto error;
798 	}
799 
800 	if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) {
801 		audio_dev_warn(dev->adev, "pci_config_setup failed");
802 		goto error;
803 	}
804 	dev->pcih = pcih;
805 
806 	vendor = pci_config_get16(pcih, PCI_CONF_VENID);
807 	device = pci_config_get16(pcih, PCI_CONF_DEVID);
808 	if (vendor != CREATIVE_VENDOR_ID ||
809 	    device != SB_P16X_ID) {
810 		audio_dev_warn(dev->adev, "Hardware not recognized "
811 		    "(vendor=%x, dev=%x)", vendor, device);
812 		goto error;
813 	}
814 
815 	/* set PCI command register */
816 	pci_config_put16(pcih, PCI_CONF_COMM,
817 	    pci_config_get16(pcih, PCI_CONF_COMM) |
818 	    PCI_COMM_MAE | PCI_COMM_IO);
819 
820 
821 	if ((ddi_regs_map_setup(dip, 1, &dev->base, 0, 0, &dev_attr,
822 	    &dev->regsh)) != DDI_SUCCESS) {
823 		audio_dev_warn(dev->adev, "failed to map registers");
824 		goto error;
825 	}
826 
827 	audio_dev_set_description(dev->adev, "Creative Sound Blaster Live!");
828 	audio_dev_set_version(dev->adev, "SBO200");
829 
830 	if ((p16x_alloc_port(dev, P16X_PLAY) != DDI_SUCCESS) ||
831 	    (p16x_alloc_port(dev, P16X_REC) != DDI_SUCCESS)) {
832 		goto error;
833 	}
834 
835 	p16x_hwinit(dev);
836 
837 	/* set up the interrupt handler */
838 	if (p16x_setup_intrs(dev) != DDI_SUCCESS) {
839 		goto error;
840 	}
841 
842 	/* Enable PCI interrupts */
843 	OUTL(dev, INTR_PCI, IE);
844 
845 	dev->ac97 = ac97_allocate(dev->adev, dip,
846 	    p16x_read_ac97, p16x_write_ac97, dev);
847 	if (dev->ac97 == NULL) {
848 		audio_dev_warn(dev->adev, "failed to allocate ac97 handle");
849 		goto error;
850 	}
851 
852 	ac97_probe_controls(dev->ac97);
853 
854 	/* remove the AC'97 controls we don't want to expose */
855 	for (int i = 0; p16x_remove_ac97[i]; i++) {
856 		ac97_ctrl_t *ctrl;
857 		ctrl = ac97_control_find(dev->ac97, p16x_remove_ac97[i]);
858 		if (ctrl != NULL) {
859 			ac97_control_unregister(ctrl);
860 		}
861 	}
862 
863 	ac97_register_controls(dev->ac97);
864 
865 	/* set up kernel statistics */
866 	if ((dev->ksp = kstat_create(P16X_NAME, ddi_get_instance(dip),
867 	    P16X_NAME, "controller", KSTAT_TYPE_INTR, 1,
868 	    KSTAT_FLAG_PERSISTENT)) != NULL) {
869 		kstat_install(dev->ksp);
870 	}
871 
872 	if (audio_dev_register(dev->adev) != DDI_SUCCESS) {
873 		audio_dev_warn(dev->adev, "unable to register with framework");
874 		goto error;
875 	}
876 
877 	(void) ddi_intr_enable(dev->ih);
878 	ddi_report_dev(dip);
879 
880 	return (DDI_SUCCESS);
881 
882 error:
883 	p16x_destroy(dev);
884 	return (DDI_FAILURE);
885 }
886 
887 int
888 p16x_resume(dev_info_t *dip)
889 {
890 	p16x_dev_t *dev;
891 
892 	dev = ddi_get_driver_private(dip);
893 
894 	p16x_hwinit(dev);
895 
896 	/* allow ac97 operations again */
897 	ac97_resume(dev->ac97);
898 
899 	mutex_enter(&dev->mutex);
900 	dev->suspended = B_FALSE;
901 
902 	for (int i = 0; i < P16X_NUM_PORT; i++) {
903 
904 		p16x_port_t *port = dev->port[i];
905 
906 		if (port->engine != NULL)
907 			audio_engine_reset(port->engine);
908 
909 		/* reset the port */
910 		p16x_init_port(port);
911 
912 		if (port->started) {
913 			p16x_start_port(port);
914 		} else {
915 			p16x_stop_port(port);
916 		}
917 	}
918 	mutex_exit(&dev->mutex);
919 	return (DDI_SUCCESS);
920 }
921 
922 int
923 p16x_detach(p16x_dev_t *dev)
924 {
925 	if (audio_dev_unregister(dev->adev) != DDI_SUCCESS)
926 		return (DDI_FAILURE);
927 
928 	p16x_destroy(dev);
929 	return (DDI_SUCCESS);
930 }
931 
932 int
933 p16x_suspend(p16x_dev_t *dev)
934 {
935 	ac97_suspend(dev->ac97);
936 
937 	mutex_enter(&dev->mutex);
938 	for (int i = 0; i < P16X_NUM_PORT; i++) {
939 
940 		p16x_port_t *port = dev->port[i];
941 		p16x_stop_port(port);
942 	}
943 
944 	write_reg(dev, SA, 0, 0);
945 	OUTL(dev, 0x00, IE);	/* Interrupt disable */
946 	OUTL(dev, 0x01, HC);
947 
948 	dev->suspended = B_TRUE;
949 	mutex_exit(&dev->mutex);
950 	return (DDI_SUCCESS);
951 }
952 
953 static int p16x_ddi_attach(dev_info_t *, ddi_attach_cmd_t);
954 static int p16x_ddi_detach(dev_info_t *, ddi_detach_cmd_t);
955 static int p16x_ddi_quiesce(dev_info_t *);
956 
957 static struct dev_ops p16x_dev_ops = {
958 	DEVO_REV,		/* rev */
959 	0,			/* refcnt */
960 	NULL,			/* getinfo */
961 	nulldev,		/* identify */
962 	nulldev,		/* probe */
963 	p16x_ddi_attach,	/* attach */
964 	p16x_ddi_detach,	/* detach */
965 	nodev,			/* reset */
966 	NULL,			/* cb_ops */
967 	NULL,			/* bus_ops */
968 	NULL,			/* power */
969 	p16x_ddi_quiesce,	/* quiesce */
970 };
971 
972 static struct modldrv p16x_modldrv = {
973 	&mod_driverops,		/* drv_modops */
974 	"Creative P16X Audio",	/* linkinfo */
975 	&p16x_dev_ops,		/* dev_ops */
976 };
977 
978 static struct modlinkage modlinkage = {
979 	MODREV_1,
980 	{ &p16x_modldrv, NULL }
981 };
982 
983 int
984 _init(void)
985 {
986 	int	rv;
987 
988 	audio_init_ops(&p16x_dev_ops, P16X_NAME);
989 	if ((rv = mod_install(&modlinkage)) != 0) {
990 		audio_fini_ops(&p16x_dev_ops);
991 	}
992 	return (rv);
993 }
994 
995 int
996 _fini(void)
997 {
998 	int	rv;
999 
1000 	if ((rv = mod_remove(&modlinkage)) == 0) {
1001 		audio_fini_ops(&p16x_dev_ops);
1002 	}
1003 	return (rv);
1004 }
1005 
1006 int
1007 _info(struct modinfo *modinfop)
1008 {
1009 	return (mod_info(&modlinkage, modinfop));
1010 }
1011 
1012 int
1013 p16x_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1014 {
1015 	switch (cmd) {
1016 	case DDI_ATTACH:
1017 		return (p16x_attach(dip));
1018 
1019 	case DDI_RESUME:
1020 		return (p16x_resume(dip));
1021 
1022 	default:
1023 		return (DDI_FAILURE);
1024 	}
1025 }
1026 
1027 int
1028 p16x_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1029 {
1030 	p16x_dev_t *dev;
1031 
1032 	dev = ddi_get_driver_private(dip);
1033 
1034 	switch (cmd) {
1035 	case DDI_DETACH:
1036 		return (p16x_detach(dev));
1037 
1038 	case DDI_SUSPEND:
1039 		return (p16x_suspend(dev));
1040 
1041 	default:
1042 		return (DDI_FAILURE);
1043 	}
1044 }
1045 
1046 int
1047 p16x_ddi_quiesce(dev_info_t *dip)
1048 {
1049 	p16x_dev_t	*dev;
1050 
1051 	dev = ddi_get_driver_private(dip);
1052 
1053 	for (int i = 0; i < P16X_NUM_PORT; i++) {
1054 
1055 		p16x_port_t *port = dev->port[i];
1056 		p16x_stop_port(port);
1057 	}
1058 
1059 	write_reg(dev, SA, 0, 0);
1060 	OUTL(dev, 0x00, IE);	    /* Interrupt disable */
1061 	OUTL(dev, 0x01, HC);
1062 
1063 	return (DDI_SUCCESS);
1064 }
1065