1139749Simp/*-
2119853Scg * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
350724Scg * All rights reserved.
450724Scg *
550724Scg * Redistribution and use in source and binary forms, with or without
650724Scg * modification, are permitted provided that the following conditions
750724Scg * are met:
850724Scg * 1. Redistributions of source code must retain the above copyright
950724Scg *    notice, this list of conditions and the following disclaimer.
1050724Scg * 2. Redistributions in binary form must reproduce the above copyright
1150724Scg *    notice, this list of conditions and the following disclaimer in the
1250724Scg *    documentation and/or other materials provided with the distribution.
1350724Scg *
1450724Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1550724Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1650724Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1750724Scg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1850724Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1950724Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2050724Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2150724Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2250724Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2350724Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2450724Scg * SUCH DAMAGE.
2550724Scg */
2650724Scg
27193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
28193640Sariff#include "opt_snd.h"
29193640Sariff#endif
30193640Sariff
3153465Scg#include <dev/sound/pcm/sound.h>
3253465Scg#include <dev/sound/pcm/ac97.h>
3353465Scg#include <dev/sound/pci/aureal.h>
3450724Scg
35119287Simp#include <dev/pci/pcireg.h>
36119287Simp#include <dev/pci/pcivar.h>
3750724Scg
3882180ScgSND_DECLARE_FILE("$FreeBSD$");
3982180Scg
4050724Scg/* PCI IDs of supported chips */
4150724Scg#define AU8820_PCI_ID 0x000112eb
4250724Scg
4350724Scg/* channel interface */
4464881Scgstatic u_int32_t au_playfmt[] = {
45193640Sariff	SND_FORMAT(AFMT_U8, 1, 0),
46193640Sariff	SND_FORMAT(AFMT_U8, 2, 0),
47193640Sariff	SND_FORMAT(AFMT_S16_LE, 1, 0),
48193640Sariff	SND_FORMAT(AFMT_S16_LE, 2, 0),
4964881Scg	0
5050724Scg};
5174763Scgstatic struct pcmchan_caps au_playcaps = {4000, 48000, au_playfmt, 0};
5250724Scg
5364881Scgstatic u_int32_t au_recfmt[] = {
54193640Sariff	SND_FORMAT(AFMT_U8, 1, 0),
55193640Sariff	SND_FORMAT(AFMT_U8, 2, 0),
56193640Sariff	SND_FORMAT(AFMT_S16_LE, 1, 0),
57193640Sariff	SND_FORMAT(AFMT_S16_LE, 2, 0),
5864881Scg	0
5950724Scg};
6074763Scgstatic struct pcmchan_caps au_reccaps = {4000, 48000, au_recfmt, 0};
6150724Scg
6250724Scg/* -------------------------------------------------------------------- */
6350724Scg
6450724Scgstruct au_info;
6550724Scg
6650724Scgstruct au_chinfo {
6750724Scg	struct au_info *parent;
6874763Scg	struct pcm_channel *channel;
6974763Scg	struct snd_dbuf *buffer;
7050724Scg	int dir;
7150724Scg};
7250724Scg
7350724Scgstruct au_info {
7450724Scg	int unit;
7550724Scg
7650724Scg	bus_space_tag_t st[3];
7750724Scg	bus_space_handle_t sh[3];
7850724Scg
7950724Scg	bus_dma_tag_t	parent_dmat;
80107285Scg	struct mtx *lock;
8150724Scg
8250724Scg	u_int32_t	x[32], y[128];
8350724Scg	char		z[128];
8450724Scg	u_int32_t	routes[4], interrupts;
8550724Scg	struct au_chinfo pch;
8650724Scg};
8750724Scg
8850724Scgstatic int      au_init(device_t dev, struct au_info *au);
8950724Scgstatic void     au_intr(void *);
9050724Scg
9150724Scg/* -------------------------------------------------------------------- */
9250724Scg
9350724Scgstatic u_int32_t
9450724Scgau_rd(struct au_info *au, int mapno, int regno, int size)
9550724Scg{
9650724Scg	switch(size) {
9750724Scg	case 1:
9850724Scg		return bus_space_read_1(au->st[mapno], au->sh[mapno], regno);
9950724Scg	case 2:
10050724Scg		return bus_space_read_2(au->st[mapno], au->sh[mapno], regno);
10150724Scg	case 4:
10250724Scg		return bus_space_read_4(au->st[mapno], au->sh[mapno], regno);
10350724Scg	default:
10450724Scg		return 0xffffffff;
10550724Scg	}
10650724Scg}
10750724Scg
10850724Scgstatic void
10950724Scgau_wr(struct au_info *au, int mapno, int regno, u_int32_t data, int size)
11050724Scg{
11150724Scg	switch(size) {
11250724Scg	case 1:
11350724Scg		bus_space_write_1(au->st[mapno], au->sh[mapno], regno, data);
11450724Scg		break;
11550724Scg	case 2:
11650724Scg		bus_space_write_2(au->st[mapno], au->sh[mapno], regno, data);
11750724Scg		break;
11850724Scg	case 4:
11950724Scg		bus_space_write_4(au->st[mapno], au->sh[mapno], regno, data);
12050724Scg		break;
12150724Scg	}
12250724Scg}
12350724Scg
12470134Scg/* -------------------------------------------------------------------- */
12570134Scg
12670134Scgstatic int
12770134Scgau_rdcd(kobj_t obj, void *arg, int regno)
12850724Scg{
12950724Scg	struct au_info *au = (struct au_info *)arg;
13050724Scg	int i=0, j=0;
13150724Scg
13250724Scg	regno<<=16;
13350724Scg	au_wr(au, 0, AU_REG_CODECIO, regno, 4);
13450724Scg	while (j<50) {
13550724Scg		i=au_rd(au, 0, AU_REG_CODECIO, 4);
13650724Scg		if ((i & 0x00ff0000) == (regno | 0x00800000)) break;
13750724Scg		DELAY(j * 200 + 2000);
13850724Scg		j++;
13950724Scg	}
14050724Scg	if (j==50) printf("pcm%d: codec timeout reading register %x (%x)\n",
14150724Scg		au->unit, (regno & AU_CDC_REGMASK)>>16, i);
14250724Scg	return i & AU_CDC_DATAMASK;
14350724Scg}
14450724Scg
14570134Scgstatic int
14670134Scgau_wrcd(kobj_t obj, void *arg, int regno, u_int32_t data)
14750724Scg{
14850724Scg	struct au_info *au = (struct au_info *)arg;
14950724Scg	int i, j, tries;
15050724Scg	i=j=tries=0;
15150724Scg	do {
15250724Scg		while (j<50 && (i & AU_CDC_WROK) == 0) {
15350724Scg			i=au_rd(au, 0, AU_REG_CODECST, 4);
15450724Scg			DELAY(2000);
15550724Scg			j++;
15650724Scg		}
15750724Scg		if (j==50) printf("codec timeout during write of register %x, data %x\n",
15850724Scg				  regno, data);
15950724Scg		au_wr(au, 0, AU_REG_CODECIO, (regno<<16) | AU_CDC_REGSET | data, 4);
16050724Scg/*		DELAY(20000);
16150724Scg		i=au_rdcd(au, regno);
16250724Scg*/		tries++;
16350724Scg	} while (0); /* (i != data && tries < 3); */
16450724Scg	/*
16550724Scg	if (tries == 3) printf("giving up writing 0x%4x to codec reg %2x\n", data, regno);
16650724Scg	*/
16770134Scg
16870134Scg	return 0;
16950724Scg}
17050724Scg
17170134Scgstatic kobj_method_t au_ac97_methods[] = {
17270134Scg    	KOBJMETHOD(ac97_read,		au_rdcd),
17370134Scg    	KOBJMETHOD(ac97_write,		au_wrcd),
174193640Sariff	KOBJMETHOD_END
17570134Scg};
17670134ScgAC97_DECLARE(au_ac97);
17770134Scg
17870134Scg/* -------------------------------------------------------------------- */
17970134Scg
18050724Scgstatic void
18150724Scgau_setbit(u_int32_t *p, char bit, u_int32_t value)
18250724Scg{
18350724Scg	p += bit >> 5;
18450724Scg	bit &= 0x1f;
18550724Scg	*p &= ~ (1 << bit);
18650724Scg	*p |= (value << bit);
18750724Scg}
18850724Scg
18950724Scgstatic void
19050724Scgau_addroute(struct au_info *au, int a, int b, int route)
19150724Scg{
19250724Scg	int j = 0x1099c+(a<<2);
19350724Scg	if (au->x[a] != a+0x67) j = AU_REG_RTBASE+(au->x[a]<<2);
19450724Scg
19550724Scg	au_wr(au, 0, AU_REG_RTBASE+(route<<2), 0xffffffff, 4);
19650724Scg 	au_wr(au, 0, j, route | (b<<7), 4);
19750724Scg	au->y[route]=au->x[a];
19850724Scg	au->x[a]=route;
19950724Scg	au->z[route]=a & 0x000000ff;
20050724Scg	au_setbit(au->routes, route, 1);
20150724Scg}
20250724Scg
20350724Scgstatic void
20450724Scgau_delroute(struct au_info *au, int route)
20550724Scg{
20650724Scg	int i;
20750724Scg	int j=au->z[route];
20850724Scg
20950724Scg	au_setbit(au->routes, route, 0);
21050724Scg	au->z[route]=0x1f;
21150724Scg	i=au_rd(au, 0, AU_REG_RTBASE+(route<<2), 4);
21250724Scg	au_wr(au, 0, AU_REG_RTBASE+(au->y[route]<<2), i, 4);
21350724Scg	au->y[i & 0x7f]=au->y[route];
21450724Scg	au_wr(au, 0, AU_REG_RTBASE+(route<<2), 0xfffffffe, 4);
21550724Scg	if (au->x[j] == route) au->x[j]=au->y[route];
21650724Scg	au->y[route]=0x7f;
21750724Scg}
21850724Scg
21950724Scgstatic void
22050724Scgau_encodec(struct au_info *au, char channel)
22150724Scg{
22250724Scg	au_wr(au, 0, AU_REG_CODECEN,
22350724Scg	      au_rd(au, 0, AU_REG_CODECEN, 4) | (1 << (channel + 8)), 4);
22450724Scg}
22550724Scg
22650724Scgstatic void
22750724Scgau_clrfifo(struct au_info *au, u_int32_t c)
22850724Scg{
22950724Scg	u_int32_t i;
23050724Scg
23150724Scg	for (i=0; i<32; i++) au_wr(au, 0, AU_REG_FIFOBASE+(c<<7)+(i<<2), 0, 4);
23250724Scg}
23350724Scg
23450724Scgstatic void
23550724Scgau_setadb(struct au_info *au, u_int32_t c, u_int32_t enable)
23650724Scg{
23750724Scg	int x;
23850724Scg
23950724Scg	x = au_rd(au, 0, AU_REG_ADB, 4);
24050724Scg	x &= ~(1 << c);
24150724Scg	x |= (enable << c);
24250724Scg	au_wr(au, 0, AU_REG_ADB, x, 4);
24350724Scg}
24450724Scg
24550724Scgstatic void
24650724Scgau_prepareoutput(struct au_chinfo *ch, u_int32_t format)
24750724Scg{
24850724Scg	struct au_info *au = ch->parent;
249193640Sariff	int i, stereo = (AFMT_CHANNEL(format) > 1)? 1 : 0;
250111183Scognet	u_int32_t baseaddr = sndbuf_getbufaddr(ch->buffer);
25150724Scg
25250724Scg	au_wr(au, 0, 0x1061c, 0, 4);
25350724Scg	au_wr(au, 0, 0x10620, 0, 4);
25450724Scg	au_wr(au, 0, 0x10624, 0, 4);
255193640Sariff	switch(AFMT_ENCODING(format)) {
25650724Scg		case 1:
25750724Scg			i=0xb000;
25850724Scg			break;
25950724Scg		case 2:
26050724Scg			i=0xf000;
26150724Scg			break;
26250724Scg 		case 8:
26350724Scg			i=0x7000;
26450724Scg			break;
26550724Scg		case 16:
26650724Scg			i=0x23000;
26750724Scg			break;
26850724Scg		default:
26950724Scg			i=0x3000;
27050724Scg	}
27150724Scg	au_wr(au, 0, 0x10200, baseaddr, 4);
27250724Scg	au_wr(au, 0, 0x10204, baseaddr+0x1000, 4);
27350724Scg	au_wr(au, 0, 0x10208, baseaddr+0x2000, 4);
27450724Scg	au_wr(au, 0, 0x1020c, baseaddr+0x3000, 4);
27550724Scg
27650724Scg	au_wr(au, 0, 0x10400, 0xdeffffff, 4);
27750724Scg	au_wr(au, 0, 0x10404, 0xfcffffff, 4);
27850724Scg
27950724Scg	au_wr(au, 0, 0x10580, i, 4);
28050724Scg
28150724Scg	au_wr(au, 0, 0x10210, baseaddr, 4);
28250724Scg	au_wr(au, 0, 0x10214, baseaddr+0x1000, 4);
28350724Scg	au_wr(au, 0, 0x10218, baseaddr+0x2000, 4);
28450724Scg	au_wr(au, 0, 0x1021c, baseaddr+0x3000, 4);
28550724Scg
28650724Scg	au_wr(au, 0, 0x10408, 0x00fff000 | 0x56000000 | 0x00000fff, 4);
28750724Scg	au_wr(au, 0, 0x1040c, 0x00fff000 | 0x74000000 | 0x00000fff, 4);
28850724Scg
28950724Scg	au_wr(au, 0, 0x10584, i, 4);
29050724Scg
29150724Scg	au_wr(au, 0, 0x0f800, stereo? 0x00030032 : 0x00030030, 4);
29250724Scg	au_wr(au, 0, 0x0f804, stereo? 0x00030032 : 0x00030030, 4);
29350724Scg
29450724Scg	au_addroute(au, 0x11, 0, 0x58);
29550724Scg	au_addroute(au, 0x11, stereo? 0 : 1, 0x59);
29650724Scg}
29750724Scg
29870134Scg/* -------------------------------------------------------------------- */
29950724Scg/* channel interface */
30050724Scgstatic void *
30174763Scgauchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
30250724Scg{
30350724Scg	struct au_info *au = devinfo;
30450724Scg	struct au_chinfo *ch = (dir == PCMDIR_PLAY)? &au->pch : NULL;
30550724Scg
30650724Scg	ch->parent = au;
30750724Scg	ch->channel = c;
30850724Scg	ch->buffer = b;
30970134Scg	ch->dir = dir;
310168847Sariff	if (sndbuf_alloc(ch->buffer, au->parent_dmat, 0, AU_BUFFSIZE) != 0)
311136469Syongari		return NULL;
31250724Scg	return ch;
31350724Scg}
31450724Scg
31550724Scgstatic int
31670134Scgauchan_setformat(kobj_t obj, void *data, u_int32_t format)
31750724Scg{
31850724Scg	struct au_chinfo *ch = data;
31950724Scg
32050724Scg	if (ch->dir == PCMDIR_PLAY) au_prepareoutput(ch, format);
32150724Scg	return 0;
32250724Scg}
32350724Scg
32450724Scgstatic int
32570134Scgauchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
32650724Scg{
32750724Scg	struct au_chinfo *ch = data;
32850724Scg	if (ch->dir == PCMDIR_PLAY) {
32950724Scg	} else {
33050724Scg	}
33150724Scg	return speed;
33250724Scg}
33350724Scg
33450724Scgstatic int
33570134Scgauchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
33650724Scg{
33750724Scg	return blocksize;
33850724Scg}
33950724Scg
34050724Scgstatic int
34170134Scgauchan_trigger(kobj_t obj, void *data, int go)
34250724Scg{
34350724Scg	struct au_chinfo *ch = data;
34450724Scg	struct au_info *au = ch->parent;
34560958Scg
346170521Sariff	if (!PCMTRIG_COMMON(go))
34760958Scg		return 0;
34860958Scg
34950724Scg	if (ch->dir == PCMDIR_PLAY) {
35050724Scg		au_setadb(au, 0x11, (go)? 1 : 0);
351170521Sariff		if (go != PCMTRIG_START) {
35250724Scg			au_wr(au, 0, 0xf800, 0, 4);
35350724Scg			au_wr(au, 0, 0xf804, 0, 4);
35450724Scg			au_delroute(au, 0x58);
35550724Scg			au_delroute(au, 0x59);
35650724Scg		}
35750724Scg	} else {
35850724Scg	}
35950724Scg	return 0;
36050724Scg}
36150724Scg
36250724Scgstatic int
36370134Scgauchan_getptr(kobj_t obj, void *data)
36450724Scg{
36550724Scg	struct au_chinfo *ch = data;
36650724Scg	struct au_info *au = ch->parent;
36750724Scg	if (ch->dir == PCMDIR_PLAY) {
36850724Scg		return au_rd(au, 0, AU_REG_UNK2, 4) & (AU_BUFFSIZE-1);
36950724Scg	} else {
37050724Scg		return 0;
37150724Scg	}
37250724Scg}
37350724Scg
37474763Scgstatic struct pcmchan_caps *
37570134Scgauchan_getcaps(kobj_t obj, void *data)
37650724Scg{
37750724Scg	struct au_chinfo *ch = data;
37850724Scg	return (ch->dir == PCMDIR_PLAY)? &au_playcaps : &au_reccaps;
37950724Scg}
38050724Scg
38170134Scgstatic kobj_method_t auchan_methods[] = {
38270134Scg    	KOBJMETHOD(channel_init,		auchan_init),
38370134Scg    	KOBJMETHOD(channel_setformat,		auchan_setformat),
38470134Scg    	KOBJMETHOD(channel_setspeed,		auchan_setspeed),
38570134Scg    	KOBJMETHOD(channel_setblocksize,	auchan_setblocksize),
38670134Scg    	KOBJMETHOD(channel_trigger,		auchan_trigger),
38770134Scg    	KOBJMETHOD(channel_getptr,		auchan_getptr),
38870134Scg    	KOBJMETHOD(channel_getcaps,		auchan_getcaps),
389193640Sariff	KOBJMETHOD_END
39070134Scg};
39170134ScgCHANNEL_DECLARE(auchan);
39270134Scg
39370134Scg/* -------------------------------------------------------------------- */
39450724Scg/* The interrupt handler */
39550724Scgstatic void
39650724Scgau_intr (void *p)
39750724Scg{
39850724Scg	struct au_info *au = p;
39950724Scg	u_int32_t	intsrc, i;
40050724Scg
40150724Scg	au->interrupts++;
40250724Scg	intsrc=au_rd(au, 0, AU_REG_IRQSRC, 4);
40350724Scg	printf("pcm%d: interrupt with src %x\n", au->unit, intsrc);
40450724Scg	if (intsrc & AU_IRQ_FATAL) printf("pcm%d: fatal error irq\n", au->unit);
40550724Scg	if (intsrc & AU_IRQ_PARITY) printf("pcm%d: parity error irq\n", au->unit);
40650724Scg	if (intsrc & AU_IRQ_UNKNOWN) {
40750724Scg		(void)au_rd(au, 0, AU_REG_UNK1, 4);
40850724Scg		au_wr(au, 0, AU_REG_UNK1, 0, 4);
40950724Scg		au_wr(au, 0, AU_REG_UNK1, 0x10000, 4);
41050724Scg	}
41150724Scg	if (intsrc & AU_IRQ_PCMOUT) {
41250724Scg	       	i=au_rd(au, 0, AU_REG_UNK2, 4) & (AU_BUFFSIZE-1);
41350724Scg	       	chn_intr(au->pch.channel);
41450724Scg		(void)au_rd(au, 0, AU_REG_UNK3, 4);
41550724Scg		(void)au_rd(au, 0, AU_REG_UNK4, 4);
41650724Scg		(void)au_rd(au, 0, AU_REG_UNK5, 4);
41750724Scg	}
41850724Scg/* don't support midi
41950724Scg	if (intsrc & AU_IRQ_MIDI) {
42050724Scg		i=au_rd(au, 0, 0x11004, 4);
42150724Scg		j=10;
42250724Scg		while (i & 0xff) {
42350724Scg			if (j-- <= 0) break;
42450724Scg			i=au_rd(au, 0, 0x11000, 4);
42550724Scg			if ((au->midi_stat & 1) && (au->midi_out))
42650724Scg				au->midi_out(au->midi_devno, i);
42750724Scg			i=au_rd(au, 0, 0x11004);
42850724Scg		}
42950724Scg	}
43050724Scg*/
43150724Scg	au_wr(au, 0, AU_REG_IRQSRC, intsrc & 0x7ff, 4);
43250724Scg	au_rd(au, 0, AU_REG_IRQSRC, 4);
43350724Scg}
43450724Scg
43550724Scg
43650724Scg/* -------------------------------------------------------------------- */
43750724Scg
43850724Scg/* Probe and attach the card */
43950724Scg
44050724Scgstatic int
44150724Scgau_init(device_t dev, struct au_info *au)
44250724Scg{
44350724Scg	u_int32_t	i, j;
44450724Scg
44550724Scg	au_wr(au, 0, AU_REG_IRQGLOB, 0xffffffff, 4);
44650724Scg	DELAY(100000);
44750724Scg
44850724Scg	/* init codec */
44950724Scg	/* cold reset */
45050724Scg	for (i=0; i<32; i++) {
45150724Scg		au_wr(au, 0, AU_REG_CODECCHN+(i<<2), 0, 4);
45250724Scg		DELAY(10000);
45350724Scg	}
45450724Scg	if (1) {
45550724Scg		au_wr(au, 0, AU_REG_CODECST, 0x8068, 4);
45650724Scg		DELAY(10000);
45750724Scg		au_wr(au, 0, AU_REG_CODECST, 0x00e8, 4);
45850724Scg		DELAY(10000);
45950724Scg	} else {
46050724Scg		au_wr(au, 0, AU_REG_CODECST, 0x00a8, 4);
46150724Scg 		DELAY(100000);
46250724Scg		au_wr(au, 0, AU_REG_CODECST, 0x80a8, 4);
46350724Scg		DELAY(100000);
46450724Scg		au_wr(au, 0, AU_REG_CODECST, 0x80e8, 4);
46550724Scg		DELAY(100000);
46650724Scg		au_wr(au, 0, AU_REG_CODECST, 0x80a8, 4);
46750724Scg		DELAY(100000);
46850724Scg		au_wr(au, 0, AU_REG_CODECST, 0x00a8, 4);
46950724Scg		DELAY(100000);
47050724Scg		au_wr(au, 0, AU_REG_CODECST, 0x00e8, 4);
47150724Scg		DELAY(100000);
47250724Scg	}
47350724Scg
47450724Scg	/* init */
47550724Scg	for (i=0; i<32; i++) {
47650724Scg		au_wr(au, 0, AU_REG_CODECCHN+(i<<2), 0, 4);
47750724Scg		DELAY(10000);
47850724Scg	}
47950724Scg	au_wr(au, 0, AU_REG_CODECST, 0xe8, 4);
48050724Scg	DELAY(10000);
48150724Scg	au_wr(au, 0, AU_REG_CODECEN, 0, 4);
48250724Scg
48350724Scg	/* setup codec */
48450724Scg	i=j=0;
48550724Scg	while (j<100 && (i & AU_CDC_READY)==0) {
48650724Scg		i=au_rd(au, 0, AU_REG_CODECST, 4);
48750724Scg		DELAY(1000);
48850724Scg		j++;
48950724Scg	}
49050724Scg	if (j==100) device_printf(dev, "codec not ready, status 0x%x\n", i);
49150724Scg
49250724Scg   	/* init adb */
49350724Scg	/*au->x5c=0;*/
49450724Scg	for (i=0; i<32;  i++) au->x[i]=i+0x67;
49550724Scg	for (i=0; i<128; i++) au->y[i]=0x7f;
49650724Scg	for (i=0; i<128; i++) au->z[i]=0x1f;
49750724Scg	au_wr(au, 0, AU_REG_ADB, 0, 4);
49850724Scg	for (i=0; i<124; i++) au_wr(au, 0, AU_REG_RTBASE+(i<<2), 0xffffffff, 4);
49950724Scg
50050724Scg	/* test */
50150724Scg	i=au_rd(au, 0, 0x107c0, 4);
50250724Scg 	if (i!=0xdeadbeef) device_printf(dev, "dma check failed: 0x%x\n", i);
50350724Scg
50450724Scg	/* install mixer */
50550724Scg	au_wr(au, 0, AU_REG_IRQGLOB,
50650724Scg	      au_rd(au, 0, AU_REG_IRQGLOB, 4) | AU_IRQ_ENABLE, 4);
50750724Scg	/* braindead but it's what the oss/linux driver does
50850724Scg	 * for (i=0; i<0x80000000; i++) au_wr(au, 0, i<<2, 0, 4);
50950724Scg	 */
51050724Scg	au->routes[0]=au->routes[1]=au->routes[2]=au->routes[3]=0;
51150724Scg	/*au->x1e4=0;*/
51250724Scg
51350724Scg	/* attach channel */
51450724Scg	au_addroute(au, 0x11, 0x48, 0x02);
51550724Scg	au_addroute(au, 0x11, 0x49, 0x03);
51650724Scg	au_encodec(au, 0);
51750724Scg	au_encodec(au, 1);
51850724Scg
51950724Scg	for (i=0; i<48; i++) au_wr(au, 0, 0xf800+(i<<2), 0x20, 4);
52050724Scg	for (i=2; i<6; i++) au_wr(au, 0, 0xf800+(i<<2), 0, 4);
52150724Scg	au_wr(au, 0, 0xf8c0, 0x0843, 4);
52250724Scg	for (i=0; i<4; i++) au_clrfifo(au, i);
52350724Scg
52450724Scg	return (0);
52550724Scg}
52650724Scg
52750724Scgstatic int
52850724Scgau_testirq(struct au_info *au)
52950724Scg{
53050724Scg	au_wr(au, 0, AU_REG_UNK1, 0x80001000, 4);
53150724Scg	au_wr(au, 0, AU_REG_IRQEN, 0x00001030, 4);
53250724Scg	au_wr(au, 0, AU_REG_IRQSRC, 0x000007ff, 4);
53350724Scg	DELAY(1000000);
53450724Scg	if (au->interrupts==0) printf("pcm%d: irq test failed\n", au->unit);
53550724Scg	/* this apparently generates an irq */
53650724Scg	return 0;
53750724Scg}
53850724Scg
53950724Scgstatic int
54050724Scgau_pci_probe(device_t dev)
54150724Scg{
54250724Scg	if (pci_get_devid(dev) == AU8820_PCI_ID) {
54350724Scg		device_set_desc(dev, "Aureal Vortex 8820");
544142890Simp		return BUS_PROBE_DEFAULT;
54550724Scg	}
54650724Scg
54750724Scg	return ENXIO;
54850724Scg}
54950724Scg
55050724Scgstatic int
55150724Scgau_pci_attach(device_t dev)
55250724Scg{
55350724Scg	struct au_info *au;
55450724Scg	int		type[10];
55550724Scg	int		regid[10];
55650724Scg	struct resource *reg[10];
55750724Scg	int		i, j, mapped = 0;
55850724Scg	int		irqid;
55950724Scg	struct resource *irq = 0;
56050724Scg	void		*ih = 0;
56150724Scg	struct ac97_info *codec;
56250724Scg	char 		status[SND_STATUSLEN];
56350724Scg
564170873Sariff	au = malloc(sizeof(*au), M_DEVBUF, M_WAITOK | M_ZERO);
56550724Scg	au->unit = device_get_unit(dev);
56650724Scg
567254263Sscottl	pci_enable_busmaster(dev);
56850724Scg
56950724Scg	j=0;
57050724Scg	/* XXX dfr: is this strictly necessary? */
57150724Scg	for (i=0; i<PCI_MAXMAPS_0; i++) {
57250724Scg#if 0
57350724Scg		/* Slapped wrist: config_id and map are private structures */
57450724Scg		if (bootverbose) {
57550724Scg			printf("pcm%d: map %d - allocating ", unit, i+1);
57650724Scg			printf("0x%x bytes of ", 1<<config_id->map[i].ln2size);
57750724Scg			printf("%s space ", (config_id->map[i].type & PCI_MAPPORT)?
57850724Scg					    "io" : "memory");
57950724Scg			printf("at 0x%x...", config_id->map[i].base);
58050724Scg		}
58150724Scg#endif
582119690Sjhb		regid[j] = PCIR_BAR(i);
58350724Scg		type[j] = SYS_RES_MEMORY;
584127135Snjl		reg[j] = bus_alloc_resource_any(dev, type[j], &regid[j],
585127135Snjl						RF_ACTIVE);
58650724Scg		if (!reg[j]) {
58750724Scg			type[j] = SYS_RES_IOPORT;
588127135Snjl			reg[j] = bus_alloc_resource_any(dev, type[j],
589127135Snjl							&regid[j], RF_ACTIVE);
59050724Scg		}
59150724Scg		if (reg[j]) {
59250724Scg			au->st[i] = rman_get_bustag(reg[j]);
59350724Scg			au->sh[i] = rman_get_bushandle(reg[j]);
59450724Scg			mapped++;
59550724Scg		}
59650724Scg#if 0
59750724Scg		if (bootverbose) printf("%s\n", mapped? "ok" : "failed");
59850724Scg#endif
59950724Scg		if (mapped) j++;
60050724Scg		if (j == 10) {
60150724Scg			/* XXX */
60250724Scg			device_printf(dev, "too many resources");
60350724Scg			goto bad;
60450724Scg		}
60550724Scg	}
60650724Scg
60750724Scg#if 0
60850724Scg	if (j < config_id->nummaps) {
60950724Scg		printf("pcm%d: unable to map a required resource\n", unit);
61050724Scg		free(au, M_DEVBUF);
61150724Scg		return;
61250724Scg	}
61350724Scg#endif
61450724Scg
61550724Scg	au_wr(au, 0, AU_REG_IRQEN, 0, 4);
61650724Scg
61750724Scg	irqid = 0;
618127135Snjl	irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &irqid,
619127135Snjl				     RF_ACTIVE | RF_SHAREABLE);
62074763Scg	if (!irq || snd_setup_intr(dev, irq, 0, au_intr, au, &ih)) {
62150724Scg		device_printf(dev, "unable to map interrupt\n");
62250724Scg		goto bad;
62350724Scg	}
62450724Scg
62550724Scg	if (au_testirq(au)) device_printf(dev, "irq test failed\n");
62650724Scg
62750724Scg	if (au_init(dev, au) == -1) {
62850724Scg		device_printf(dev, "unable to initialize the card\n");
62950724Scg		goto bad;
63050724Scg	}
63150724Scg
63270134Scg	codec = AC97_CREATE(dev, au, au_ac97);
63350724Scg	if (codec == NULL) goto bad;
63470134Scg	if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) goto bad;
63550724Scg
636166904Snetchild	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
637166904Snetchild		/*boundary*/0,
63850724Scg		/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
63950724Scg		/*highaddr*/BUS_SPACE_MAXADDR,
64050724Scg		/*filter*/NULL, /*filterarg*/NULL,
64150724Scg		/*maxsize*/AU_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff,
642117126Sscottl		/*flags*/0, /*lockfunc*/busdma_lock_mutex,
643117126Sscottl		/*lockarg*/&Giant, &au->parent_dmat) != 0) {
64450724Scg		device_printf(dev, "unable to create dma tag\n");
64550724Scg		goto bad;
64650724Scg	}
64750724Scg
648126695Smatk	snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld %s",
64950724Scg		 (type[0] == SYS_RES_IOPORT)? "io" : "memory",
650126695Smatk		 rman_get_start(reg[0]), rman_get_start(irq),PCM_KLDSTRING(snd_aureal));
65150724Scg
65250724Scg	if (pcm_register(dev, au, 1, 1)) goto bad;
65350724Scg	/* pcm_addchan(dev, PCMDIR_REC, &au_chantemplate, au); */
65470134Scg	pcm_addchan(dev, PCMDIR_PLAY, &auchan_class, au);
65550724Scg	pcm_setstatus(dev, status);
65650724Scg
65750724Scg	return 0;
65850724Scg
65950724Scg bad:
66050724Scg	if (au) free(au, M_DEVBUF);
66150724Scg	for (i = 0; i < j; i++)
66250724Scg		bus_release_resource(dev, type[i], regid[i], reg[i]);
66350724Scg	if (ih) bus_teardown_intr(dev, irq, ih);
66450724Scg	if (irq) bus_release_resource(dev, SYS_RES_IRQ, irqid, irq);
66550724Scg	return ENXIO;
66650724Scg}
66750724Scg
66850724Scgstatic device_method_t au_methods[] = {
66950724Scg	/* Device interface */
67050724Scg	DEVMETHOD(device_probe,		au_pci_probe),
67150724Scg	DEVMETHOD(device_attach,	au_pci_attach),
67250724Scg
67350724Scg	{ 0, 0 }
67450724Scg};
67550724Scg
67650724Scgstatic driver_t au_driver = {
67750724Scg	"pcm",
67850724Scg	au_methods,
67982180Scg	PCM_SOFTC_SIZE,
68050724Scg};
68150724Scg
68262483ScgDRIVER_MODULE(snd_aureal, pci, au_driver, pcm_devclass, 0, 0);
683132236StanimuraMODULE_DEPEND(snd_aureal, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
68462483ScgMODULE_VERSION(snd_aureal, 1);
685