audiop16x.c revision 11936:54dc8a89ba0d
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 2010 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 */
57static 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
66static struct ddi_device_acc_attr dev_attr = {
67	DDI_DEVICE_ATTR_V0,
68	DDI_STRUCTURE_LE_ACC,
69	DDI_STRICTORDER_ACC
70};
71
72static struct ddi_device_acc_attr buf_attr = {
73	DDI_DEVICE_ATTR_V0,
74	DDI_NEVERSWAP_ACC,
75	DDI_STRICTORDER_ACC
76};
77
78static 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
93static int p16x_attach(dev_info_t *);
94static int p16x_resume(dev_info_t *);
95static int p16x_detach(p16x_dev_t *);
96static int p16x_suspend(p16x_dev_t *);
97
98static int p16x_open(void *, int, unsigned *, caddr_t *);
99static void p16x_close(void *);
100static int p16x_start(void *);
101static void p16x_stop(void *);
102static int p16x_format(void *);
103static int p16x_channels(void *);
104static int p16x_rate(void *);
105static uint64_t p16x_count(void *);
106static void p16x_sync(void *, unsigned);
107static void p16x_chinfo(void *, int, unsigned *, unsigned *);
108
109static uint16_t p16x_read_ac97(void *, uint8_t);
110static void p16x_write_ac97(void *, uint8_t, uint16_t);
111static int p16x_alloc_port(p16x_dev_t *, int);
112static void p16x_destroy(p16x_dev_t *);
113static void p16x_hwinit(p16x_dev_t *);
114
115static audio_engine_ops_t p16x_engine_ops = {
116	AUDIO_ENGINE_VERSION,
117	p16x_open,
118	p16x_close,
119	p16x_start,
120	p16x_stop,
121	p16x_count,
122	p16x_format,
123	p16x_channels,
124	p16x_rate,
125	p16x_sync,
126	NULL,
127	p16x_chinfo,
128	NULL
129};
130
131static unsigned int
132read_reg(p16x_dev_t *dev, int reg, int chn)
133{
134	unsigned int val;
135
136	mutex_enter(&dev->mutex);
137	OUTL(dev, (reg << 16) | (chn & 0xffff), PTR);	/* Pointer */
138	val = INL(dev, DR);	/* Data */
139	mutex_exit(&dev->mutex);
140
141	return (val);
142}
143
144static void
145write_reg(p16x_dev_t *dev, int reg, int chn, unsigned int value)
146{
147
148	mutex_enter(&dev->mutex);
149	OUTL(dev, (reg << 16) | (chn & 0xffff), PTR);	/* Pointer */
150	OUTL(dev, value, DR);	/* Data */
151	mutex_exit(&dev->mutex);
152}
153
154static void
155set_reg_bits(p16x_dev_t *dev, int reg, int chn, unsigned int mask)
156{
157	unsigned int	val;
158	mutex_enter(&dev->mutex);
159	OUTL(dev, (reg << 16) | (chn & 0xffff), PTR);	/* Pointer */
160	val = INL(dev, DR);	/* Data */
161	val |= mask;
162	OUTL(dev, val, DR);	/* Data */
163	mutex_exit(&dev->mutex);
164}
165
166static void
167clear_reg_bits(p16x_dev_t *dev, int reg, int chn, unsigned int mask)
168{
169	unsigned int	val;
170	mutex_enter(&dev->mutex);
171	OUTL(dev, (reg << 16) | (chn & 0xffff), PTR);	/* Pointer */
172	val = INL(dev, DR);	/* Data */
173	val &= ~(mask);
174	OUTL(dev, val, DR);	/* Data */
175	mutex_exit(&dev->mutex);
176}
177
178static uint16_t
179p16x_read_ac97(void *arg, uint8_t index)
180{
181	p16x_dev_t *dev = arg;
182	uint16_t value;
183	int i;
184
185	OUTB(dev, index, AC97A);
186	for (i = 0; i < 10000; i++)
187		if (INB(dev, AC97A) & 0x80)
188			break;
189	value = INW(dev, AC97D);
190	return (value);
191}
192
193static void
194p16x_write_ac97(void *arg, uint8_t index, uint16_t data)
195{
196	p16x_dev_t *dev = arg;
197	unsigned int i;
198
199	OUTB(dev, index, AC97A);
200	for (i = 0; i < 10000; i++)
201		if (INB(dev, AC97A) & 0x80)
202			break;
203	OUTW(dev, data, AC97D);
204}
205
206/*
207 * Audio routines
208 */
209
210int
211p16x_open(void *arg, int flag, uint_t *nframes, caddr_t *bufp)
212{
213	p16x_port_t	*port = arg;
214
215	_NOTE(ARGUNUSED(flag));
216
217	port->count = 0;
218	*nframes = port->buf_frames;
219	*bufp = port->buf_kaddr;
220
221	return (0);
222}
223
224void
225p16x_close(void *arg)
226{
227	_NOTE(ARGUNUSED(arg));
228}
229
230int
231p16x_start(void *arg)
232{
233	p16x_port_t	*port = arg;
234	p16x_dev_t	*dev = port->dev;
235
236	port->offset = 0;
237
238	if (port->port_num == P16X_REC) {
239		write_reg(dev, CRFA, 0, 0);
240		write_reg(dev, CRCAV, 0, 0);
241
242		/* Enable rec channel */
243		set_reg_bits(dev, SA, 0, 0x100);
244	} else {
245		for (int i = 0; i < 3; i++) {
246			write_reg(dev, PTBA, i, 0);
247			write_reg(dev, PTBS, i, 0);
248			write_reg(dev, PTCA, i, 0);
249			write_reg(dev, PFEA, i, 0);
250			write_reg(dev, CPFA, i, 0);
251			write_reg(dev, CPCAV, i, 0);
252		}
253
254		/* Enable play channel */
255		set_reg_bits(dev, SA, 0, 0x7);
256	}
257
258	return (0);
259}
260
261void
262p16x_stop(void *arg)
263{
264	p16x_port_t	*port = arg;
265	p16x_dev_t	*dev = port->dev;
266
267	if (port->port_num == P16X_REC) {
268		/* Disable rec channel */
269		clear_reg_bits(dev, SA, 0, 0x100);
270
271	} else {
272		/* Disable Play channel */
273		clear_reg_bits(dev, SA, 0, 0x7);
274	}
275}
276
277int
278p16x_format(void *arg)
279{
280	_NOTE(ARGUNUSED(arg));
281
282	return (AUDIO_FORMAT_S16_LE);
283}
284
285int
286p16x_channels(void *arg)
287{
288	p16x_port_t *port = arg;
289
290	return (port->nchan);
291}
292
293int
294p16x_rate(void *arg)
295{
296	_NOTE(ARGUNUSED(arg));
297
298	return (48000);
299}
300
301void
302p16x_sync(void *arg, unsigned nframes)
303{
304	p16x_port_t *port = arg;
305	_NOTE(ARGUNUSED(nframes));
306
307	(void) ddi_dma_sync(port->buf_dmah, 0, 0, port->syncdir);
308}
309
310uint64_t
311p16x_count(void *arg)
312{
313	p16x_port_t	*port = arg;
314	p16x_dev_t	*dev = port->dev;
315	uint64_t	val;
316	uint32_t	offset, n;
317
318	if (port->port_num == P16X_PLAY) {
319		offset = read_reg(dev, CPFA, 0);
320	} else {
321		offset = read_reg(dev, CRFA, 0);
322	}
323
324	/* get the offset, and switch to frames */
325	offset /= (2 * sizeof (uint16_t));
326
327	if (offset >= port->offset) {
328		n = offset - port->offset;
329	} else {
330		n = offset + (port->buf_frames - port->offset);
331	}
332	port->offset = offset;
333	port->count += n;
334	val = port->count;
335
336	return (val);
337}
338
339static void
340p16x_chinfo(void *arg, int chan, unsigned *offset, unsigned *incr)
341{
342	p16x_port_t *port = arg;
343	unsigned mult;
344
345	if (port->port_num == P16X_PLAY) {
346		switch (chan) {
347		case 0:	/* left front */
348		case 1:	/* right front */
349			mult = 0;
350			break;
351		case 2:	/* center */
352		case 3:	/* lfe */
353			mult = 2;
354			break;
355		case 4:	/* left surround */
356		case 5:	/* right surround */
357			mult = 1;
358			break;
359		}
360		*offset = (port->buf_frames * 2 * mult) + (chan % 2);
361		*incr = 2;
362	} else {
363		*offset = chan;
364		*incr = 2;
365	}
366}
367
368/* private implementation bits */
369
370int
371p16x_alloc_port(p16x_dev_t *dev, int num)
372{
373	p16x_port_t		*port;
374	size_t			len;
375	ddi_dma_cookie_t	cookie;
376	uint_t			count;
377	int			dir;
378	unsigned		caps;
379	audio_dev_t		*adev;
380
381	adev = dev->adev;
382	port = kmem_zalloc(sizeof (*port), KM_SLEEP);
383	dev->port[num] = port;
384	port->dev = dev;
385
386	switch (num) {
387	case P16X_REC:
388		port->syncdir = DDI_DMA_SYNC_FORKERNEL;
389		caps = ENGINE_INPUT_CAP;
390		dir = DDI_DMA_READ;
391		port->port_num = P16X_REC;
392		port->nchan = 2;
393		break;
394	case P16X_PLAY:
395		port->syncdir = DDI_DMA_SYNC_FORDEV;
396		caps = ENGINE_OUTPUT_CAP;
397		dir = DDI_DMA_WRITE;
398		port->port_num = P16X_PLAY;
399		port->nchan = 6;
400		break;
401	default:
402		return (DDI_FAILURE);
403	}
404
405	/*
406	 * NB: The device operates in pairs of dwords at a time, for
407	 * performance reasons.  So make sure that our buffer is
408	 * arranged as a whole number of these.  The value below gives
409	 * a reasonably large buffer so we can support a deep
410	 * playahead if we need to (and we should avoid input
411	 * overruns.)
412	 */
413	port->buf_frames = 4096;
414	port->buf_size = port->buf_frames * port->nchan * sizeof (uint16_t);
415
416	/* now allocate buffers */
417	if (ddi_dma_alloc_handle(dev->dip, &dma_attr_buf, DDI_DMA_SLEEP, NULL,
418	    &port->buf_dmah) != DDI_SUCCESS) {
419		audio_dev_warn(adev, "failed to allocate BUF handle");
420		return (DDI_FAILURE);
421	}
422
423	if (ddi_dma_mem_alloc(port->buf_dmah, port->buf_size,
424	    &buf_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
425	    &port->buf_kaddr, &len, &port->buf_acch) != DDI_SUCCESS) {
426		audio_dev_warn(adev, "failed to allocate BUF memory");
427		return (DDI_FAILURE);
428	}
429
430	if (ddi_dma_addr_bind_handle(port->buf_dmah, NULL, port->buf_kaddr,
431	    len, DDI_DMA_CONSISTENT | dir, DDI_DMA_SLEEP, NULL, &cookie,
432	    &count) != DDI_SUCCESS) {
433		audio_dev_warn(adev, "failed binding BUF DMA handle");
434		return (DDI_FAILURE);
435	}
436	port->buf_paddr = cookie.dmac_address;
437
438	port->engine = audio_engine_alloc(&p16x_engine_ops, caps);
439	if (port->engine == NULL) {
440		audio_dev_warn(adev, "audio_engine_alloc failed");
441		return (DDI_FAILURE);
442	}
443
444	audio_engine_set_private(port->engine, port);
445	audio_dev_add_engine(adev, port->engine);
446
447	return (DDI_SUCCESS);
448}
449
450void
451p16x_destroy(p16x_dev_t *dev)
452{
453	mutex_destroy(&dev->mutex);
454
455	for (int i = 0; i < P16X_NUM_PORT; i++) {
456		p16x_port_t *port = dev->port[i];
457		if (!port)
458			continue;
459		if (port->engine) {
460			audio_dev_remove_engine(dev->adev, port->engine);
461			audio_engine_free(port->engine);
462		}
463		if (port->buf_paddr) {
464			(void) ddi_dma_unbind_handle(port->buf_dmah);
465		}
466		if (port->buf_acch) {
467			ddi_dma_mem_free(&port->buf_acch);
468		}
469		if (port->buf_dmah) {
470			ddi_dma_free_handle(&port->buf_dmah);
471		}
472		kmem_free(port, sizeof (*port));
473	}
474
475	if (dev->ac97 != NULL) {
476		ac97_free(dev->ac97);
477	}
478	if (dev->adev != NULL) {
479		audio_dev_free(dev->adev);
480	}
481	if (dev->regsh != NULL) {
482		ddi_regs_map_free(&dev->regsh);
483	}
484	if (dev->pcih != NULL) {
485		pci_config_teardown(&dev->pcih);
486	}
487	kmem_free(dev, sizeof (*dev));
488}
489
490void
491p16x_hwinit(p16x_dev_t *dev)
492{
493	p16x_port_t		*port;
494	uint32_t		paddr;
495	uint32_t		chunksz;
496	int i;
497
498	for (i = 0; i < 3; i++) {
499		write_reg(dev, PTBA, i, 0);
500		write_reg(dev, PTBS, i, 0);
501		write_reg(dev, PTCA, i, 0);
502		write_reg(dev, PFEA, i, 0);
503		write_reg(dev, CPFA, i, 0);
504		write_reg(dev, CPCAV, i, 0);
505		write_reg(dev, CRFA, i, 0);
506		write_reg(dev, CRCAV, i, 0);
507	}
508	write_reg(dev, SCS0, 0, 0x02108504);
509	write_reg(dev, SCS1, 0, 0x02108504);
510	write_reg(dev, SCS2, 0, 0x02108504);
511
512	/* set the spdif/analog combo jack to analog out */
513	write_reg(dev, SPC, 0, 0x00000700);
514	write_reg(dev, EA_aux, 0, 0x0001003f);
515
516	port = dev->port[P16X_REC];
517	/* Set physical address of the DMA buffer */
518	write_reg(dev, RFBA, 0, port->buf_paddr);
519	write_reg(dev, RFBS, 0, (port->buf_size) << 16);
520
521	/* Set physical address of the DMA buffer */
522	port = dev->port[P16X_PLAY];
523	paddr = port->buf_paddr;
524	chunksz = port->buf_frames * 4;
525	write_reg(dev, PFBA, 0, paddr);
526	write_reg(dev, PFBS, 0, chunksz << 16);
527	paddr += chunksz;
528	write_reg(dev, PFBA, 1, paddr);
529	write_reg(dev, PFBS, 1, chunksz << 16);
530	paddr += chunksz;
531	write_reg(dev, PFBA, 2, paddr);
532	write_reg(dev, PFBS, 2, chunksz << 16);
533
534	OUTL(dev, 0x1080, GPIO);	/* GPIO */
535	/* Clear any pending interrupts */
536	OUTL(dev, INTR_ALL, IP);
537	OUTL(dev, 0, IE);
538	OUTL(dev, 0x9, HC);	/* Enable audio */
539}
540
541int
542p16x_attach(dev_info_t *dip)
543{
544	uint16_t	vendor, device;
545	p16x_dev_t	*dev;
546	ddi_acc_handle_t pcih;
547
548	dev = kmem_zalloc(sizeof (*dev), KM_SLEEP);
549	dev->dip = dip;
550	ddi_set_driver_private(dip, dev);
551
552	mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, NULL);
553
554	if ((dev->adev = audio_dev_alloc(dip, 0)) == NULL) {
555		cmn_err(CE_WARN, "audio_dev_alloc failed");
556		goto error;
557	}
558
559	if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) {
560		audio_dev_warn(dev->adev, "pci_config_setup failed");
561		goto error;
562	}
563	dev->pcih = pcih;
564
565	vendor = pci_config_get16(pcih, PCI_CONF_VENID);
566	device = pci_config_get16(pcih, PCI_CONF_DEVID);
567	if (vendor != CREATIVE_VENDOR_ID ||
568	    device != SB_P16X_ID) {
569		audio_dev_warn(dev->adev, "Hardware not recognized "
570		    "(vendor=%x, dev=%x)", vendor, device);
571		goto error;
572	}
573
574	/* set PCI command register */
575	pci_config_put16(pcih, PCI_CONF_COMM,
576	    pci_config_get16(pcih, PCI_CONF_COMM) |
577	    PCI_COMM_MAE | PCI_COMM_IO);
578
579
580	if ((ddi_regs_map_setup(dip, 1, &dev->base, 0, 0, &dev_attr,
581	    &dev->regsh)) != DDI_SUCCESS) {
582		audio_dev_warn(dev->adev, "failed to map registers");
583		goto error;
584	}
585
586	audio_dev_set_description(dev->adev, "Creative Sound Blaster Live!");
587	audio_dev_set_version(dev->adev, "SBO200");
588
589	if ((p16x_alloc_port(dev, P16X_PLAY) != DDI_SUCCESS) ||
590	    (p16x_alloc_port(dev, P16X_REC) != DDI_SUCCESS)) {
591		goto error;
592	}
593
594	p16x_hwinit(dev);
595
596	dev->ac97 = ac97_allocate(dev->adev, dip,
597	    p16x_read_ac97, p16x_write_ac97, dev);
598	if (dev->ac97 == NULL) {
599		audio_dev_warn(dev->adev, "failed to allocate ac97 handle");
600		goto error;
601	}
602
603	ac97_probe_controls(dev->ac97);
604
605	/* remove the AC'97 controls we don't want to expose */
606	for (int i = 0; p16x_remove_ac97[i]; i++) {
607		ac97_ctrl_t *ctrl;
608		ctrl = ac97_control_find(dev->ac97, p16x_remove_ac97[i]);
609		if (ctrl != NULL) {
610			ac97_control_unregister(ctrl);
611		}
612	}
613
614	ac97_register_controls(dev->ac97);
615
616	if (audio_dev_register(dev->adev) != DDI_SUCCESS) {
617		audio_dev_warn(dev->adev, "unable to register with framework");
618		goto error;
619	}
620
621	ddi_report_dev(dip);
622
623	return (DDI_SUCCESS);
624
625error:
626	p16x_destroy(dev);
627	return (DDI_FAILURE);
628}
629
630int
631p16x_resume(dev_info_t *dip)
632{
633	p16x_dev_t *dev;
634
635	dev = ddi_get_driver_private(dip);
636
637	p16x_hwinit(dev);
638
639	ac97_reset(dev->ac97);
640
641	audio_dev_resume(dev->adev);
642
643	return (DDI_SUCCESS);
644}
645
646int
647p16x_detach(p16x_dev_t *dev)
648{
649	if (audio_dev_unregister(dev->adev) != DDI_SUCCESS)
650		return (DDI_FAILURE);
651
652	p16x_destroy(dev);
653	return (DDI_SUCCESS);
654}
655
656int
657p16x_suspend(p16x_dev_t *dev)
658{
659	audio_dev_suspend(dev->adev);
660
661	return (DDI_SUCCESS);
662}
663
664static int p16x_ddi_attach(dev_info_t *, ddi_attach_cmd_t);
665static int p16x_ddi_detach(dev_info_t *, ddi_detach_cmd_t);
666static int p16x_ddi_quiesce(dev_info_t *);
667
668static struct dev_ops p16x_dev_ops = {
669	DEVO_REV,		/* rev */
670	0,			/* refcnt */
671	NULL,			/* getinfo */
672	nulldev,		/* identify */
673	nulldev,		/* probe */
674	p16x_ddi_attach,	/* attach */
675	p16x_ddi_detach,	/* detach */
676	nodev,			/* reset */
677	NULL,			/* cb_ops */
678	NULL,			/* bus_ops */
679	NULL,			/* power */
680	p16x_ddi_quiesce,	/* quiesce */
681};
682
683static struct modldrv p16x_modldrv = {
684	&mod_driverops,		/* drv_modops */
685	"Creative P16X Audio",	/* linkinfo */
686	&p16x_dev_ops,		/* dev_ops */
687};
688
689static struct modlinkage modlinkage = {
690	MODREV_1,
691	{ &p16x_modldrv, NULL }
692};
693
694int
695_init(void)
696{
697	int	rv;
698
699	audio_init_ops(&p16x_dev_ops, P16X_NAME);
700	if ((rv = mod_install(&modlinkage)) != 0) {
701		audio_fini_ops(&p16x_dev_ops);
702	}
703	return (rv);
704}
705
706int
707_fini(void)
708{
709	int	rv;
710
711	if ((rv = mod_remove(&modlinkage)) == 0) {
712		audio_fini_ops(&p16x_dev_ops);
713	}
714	return (rv);
715}
716
717int
718_info(struct modinfo *modinfop)
719{
720	return (mod_info(&modlinkage, modinfop));
721}
722
723int
724p16x_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
725{
726	switch (cmd) {
727	case DDI_ATTACH:
728		return (p16x_attach(dip));
729
730	case DDI_RESUME:
731		return (p16x_resume(dip));
732
733	default:
734		return (DDI_FAILURE);
735	}
736}
737
738int
739p16x_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
740{
741	p16x_dev_t *dev;
742
743	dev = ddi_get_driver_private(dip);
744
745	switch (cmd) {
746	case DDI_DETACH:
747		return (p16x_detach(dev));
748
749	case DDI_SUSPEND:
750		return (p16x_suspend(dev));
751
752	default:
753		return (DDI_FAILURE);
754	}
755}
756
757int
758p16x_ddi_quiesce(dev_info_t *dip)
759{
760	p16x_dev_t	*dev;
761
762	dev = ddi_get_driver_private(dip);
763
764	write_reg(dev, SA, 0, 0);
765	OUTL(dev, 0x01, HC);
766
767	return (DDI_SUCCESS);
768}
769