1139749Simp/*-
261346Scg * Copyright (c) 2000 Cameron Grant <cg@freebsd.org>
361108Scg * All rights reserved.
461108Scg *
561108Scg * Redistribution and use in source and binary forms, with or without
661108Scg * modification, are permitted provided that the following conditions
761108Scg * are met:
861108Scg * 1. Redistributions of source code must retain the above copyright
961108Scg *    notice, this list of conditions and the following disclaimer.
1061108Scg * 2. Redistributions in binary form must reproduce the above copyright
1161108Scg *    notice, this list of conditions and the following disclaimer in the
1261108Scg *    documentation and/or other materials provided with the distribution.
1361108Scg *
1461108Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1561108Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1661108Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1761108Scg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1861108Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1961108Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2061108Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2161108Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
2261108Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2361108Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
2461108Scg * SUCH DAMAGE.
2561108Scg */
2661108Scg
27193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
28193640Sariff#include "opt_snd.h"
29193640Sariff#endif
30193640Sariff
3161108Scg#include <dev/sound/pcm/sound.h>
3261108Scg#include <dev/sound/pcm/ac97.h>
3361108Scg
34119287Simp#include <dev/pci/pcireg.h>
35119287Simp#include <dev/pci/pcivar.h>
3661108Scg
3761108Scg#include <dev/sound/pci/ds1.h>
3861108Scg#include <dev/sound/pci/ds1-fw.h>
3961108Scg
4082180ScgSND_DECLARE_FILE("$FreeBSD$");
4182180Scg
4261108Scg/* -------------------------------------------------------------------- */
4361108Scg
4461108Scg#define	DS1_CHANS 4
4561346Scg#define DS1_RECPRIMARY 0
4670343Scg#define DS1_IRQHZ ((48000 << 8) / 256)
4771504Scg#define DS1_BUFFSIZE 4096
4861108Scg
4961108Scgstruct pbank {
5061108Scg	volatile u_int32_t	Format;
5161108Scg	volatile u_int32_t	LoopDefault;
5261108Scg	volatile u_int32_t	PgBase;
5361108Scg	volatile u_int32_t	PgLoop;
5461108Scg	volatile u_int32_t	PgLoopEnd;
5561108Scg	volatile u_int32_t	PgLoopFrac;
5661108Scg	volatile u_int32_t	PgDeltaEnd;
5761108Scg	volatile u_int32_t	LpfKEnd;
5861108Scg	volatile u_int32_t	EgGainEnd;
5961108Scg	volatile u_int32_t	LchGainEnd;
6061108Scg	volatile u_int32_t	RchGainEnd;
6161108Scg	volatile u_int32_t	Effect1GainEnd;
6261108Scg	volatile u_int32_t	Effect2GainEnd;
6361108Scg	volatile u_int32_t	Effect3GainEnd;
6461108Scg	volatile u_int32_t	LpfQ;
6561108Scg	volatile u_int32_t	Status;
6661108Scg	volatile u_int32_t	NumOfFrames;
6761108Scg	volatile u_int32_t	LoopCount;
6861108Scg	volatile u_int32_t	PgStart;
6961108Scg	volatile u_int32_t	PgStartFrac;
7061108Scg	volatile u_int32_t	PgDelta;
7161108Scg	volatile u_int32_t	LpfK;
7261108Scg	volatile u_int32_t	EgGain;
7361108Scg	volatile u_int32_t	LchGain;
7461108Scg	volatile u_int32_t	RchGain;
7561108Scg	volatile u_int32_t	Effect1Gain;
7661108Scg	volatile u_int32_t	Effect2Gain;
7761108Scg	volatile u_int32_t	Effect3Gain;
7861108Scg	volatile u_int32_t	LpfD1;
7961108Scg	volatile u_int32_t	LpfD2;
8061108Scg};
8161108Scg
8261346Scgstruct rbank {
8361346Scg	volatile u_int32_t	PgBase;
8461346Scg	volatile u_int32_t	PgLoopEnd;
8561346Scg	volatile u_int32_t	PgStart;
8661346Scg	volatile u_int32_t	NumOfLoops;
8761346Scg};
8861346Scg
8961108Scgstruct sc_info;
9061108Scg
9161108Scg/* channel registers */
9261346Scgstruct sc_pchinfo {
9361108Scg	int run, spd, dir, fmt;
9474763Scg	struct snd_dbuf *buffer;
9574763Scg	struct pcm_channel *channel;
9661108Scg	volatile struct pbank *lslot, *rslot;
9761108Scg	int lsnum, rsnum;
9861108Scg	struct sc_info *parent;
9961108Scg};
10061108Scg
10161346Scgstruct sc_rchinfo {
10261346Scg	int run, spd, dir, fmt, num;
10374763Scg	struct snd_dbuf *buffer;
10474763Scg	struct pcm_channel *channel;
10561346Scg	volatile struct rbank *slot;
10661346Scg	struct sc_info *parent;
10761346Scg};
10861346Scg
10961108Scg/* device private data */
11061108Scgstruct sc_info {
11161108Scg	device_t	dev;
11261108Scg	u_int32_t 	type, rev;
11361108Scg	u_int32_t	cd2id, ctrlbase;
11461108Scg
11561108Scg	bus_space_tag_t st;
11661108Scg	bus_space_handle_t sh;
11784659Scg	bus_dma_tag_t buffer_dmat, control_dmat;
11865340Scg	bus_dmamap_t map;
11961108Scg
12061108Scg	struct resource *reg, *irq;
12161108Scg	int		regid, irqid;
12261108Scg	void		*ih;
123107285Scg	struct mtx	*lock;
12461108Scg
12565218Scg	void *regbase;
12661108Scg	u_int32_t *pbase, pbankbase, pbanksize;
12761108Scg	volatile struct pbank *pbank[2 * 64];
12861346Scg	volatile struct rbank *rbank;
12961108Scg	int pslotfree, currbank, pchn, rchn;
13084659Scg	unsigned int bufsz;
13161108Scg
13261346Scg	struct sc_pchinfo pch[DS1_CHANS];
13361346Scg	struct sc_rchinfo rch[2];
13461108Scg};
13561108Scg
13661108Scgstruct {
13761108Scg	u_int32_t dev, subdev;
13861108Scg	char *name;
13961108Scg	u_int32_t *mcode;
14061108Scg} ds_devs[] = {
14161108Scg	{0x00041073, 0, 		"Yamaha DS-1 (YMF724)", CntrlInst},
14261108Scg	{0x000d1073, 0, 		"Yamaha DS-1E (YMF724F)", CntrlInst1E},
14361108Scg	{0x00051073, 0, 		"Yamaha DS-1? (YMF734)", CntrlInst},
14461108Scg	{0x00081073, 0, 		"Yamaha DS-1? (YMF737)", CntrlInst},
14561108Scg	{0x00201073, 0, 		"Yamaha DS-1? (YMF738)", CntrlInst},
14661108Scg	{0x00061073, 0, 		"Yamaha DS-1? (YMF738_TEG)", CntrlInst},
14761108Scg	{0x000a1073, 0x00041073, 	"Yamaha DS-1 (YMF740)", CntrlInst},
14861108Scg	{0x000a1073, 0x000a1073,  	"Yamaha DS-1 (YMF740B)", CntrlInst},
14970134Scg	{0x000a1073, 0x53328086,	"Yamaha DS-1 (YMF740I)", CntrlInst},
15061146Speter	{0x000a1073, 0, 		"Yamaha DS-1 (YMF740?)", CntrlInst},
15161108Scg	{0x000c1073, 0, 		"Yamaha DS-1E (YMF740C)", CntrlInst1E},
15270134Scg	{0x00101073, 0, 		"Yamaha DS-1E (YMF744)", CntrlInst1E},
15361108Scg	{0x00121073, 0, 		"Yamaha DS-1E (YMF754)", CntrlInst1E},
15461108Scg	{0, 0, NULL, NULL}
15561108Scg};
15661108Scg
15761108Scg/* -------------------------------------------------------------------- */
15861108Scg
15961108Scg/*
16061108Scg * prototypes
16161108Scg */
16261108Scg
16361108Scg/* stuff */
164166919Sariffstatic int       ds_init(struct sc_info *);
16561108Scgstatic void      ds_intr(void *);
16661108Scg
16761108Scg/* talk to the card */
16861108Scgstatic u_int32_t ds_rd(struct sc_info *, int, int);
16961108Scgstatic void 	 ds_wr(struct sc_info *, int, u_int32_t, int);
17061108Scg
17161108Scg/* -------------------------------------------------------------------- */
17261108Scg
17364881Scgstatic u_int32_t ds_recfmt[] = {
174193640Sariff	SND_FORMAT(AFMT_U8, 1, 0),
175193640Sariff	SND_FORMAT(AFMT_U8, 2, 0),
176193640Sariff	SND_FORMAT(AFMT_S8, 1, 0),
177193640Sariff	SND_FORMAT(AFMT_S8, 2, 0),
178193640Sariff	SND_FORMAT(AFMT_S16_LE, 1, 0),
179193640Sariff	SND_FORMAT(AFMT_S16_LE, 2, 0),
180193640Sariff	SND_FORMAT(AFMT_U16_LE, 1, 0),
181193640Sariff	SND_FORMAT(AFMT_U16_LE, 2, 0),
18264881Scg	0
18361108Scg};
18474763Scgstatic struct pcmchan_caps ds_reccaps = {4000, 48000, ds_recfmt, 0};
18561108Scg
18664881Scgstatic u_int32_t ds_playfmt[] = {
187193640Sariff	SND_FORMAT(AFMT_U8, 1, 0),
188193640Sariff	SND_FORMAT(AFMT_U8, 2, 0),
189193640Sariff	/* SND_FORMAT(AFMT_S16_LE, 1, 0), */
190193640Sariff	SND_FORMAT(AFMT_S16_LE, 2, 0),
19164881Scg	0
19261108Scg};
19374763Scgstatic struct pcmchan_caps ds_playcaps = {4000, 96000, ds_playfmt, 0};
19461108Scg
19561108Scg/* -------------------------------------------------------------------- */
19661108Scg/* Hardware */
19761108Scgstatic u_int32_t
19861108Scgds_rd(struct sc_info *sc, int regno, int size)
19961108Scg{
20061108Scg	switch (size) {
20161108Scg	case 1:
20261108Scg		return bus_space_read_1(sc->st, sc->sh, regno);
20361108Scg	case 2:
20461108Scg		return bus_space_read_2(sc->st, sc->sh, regno);
20561108Scg	case 4:
20661108Scg		return bus_space_read_4(sc->st, sc->sh, regno);
20761108Scg	default:
20861108Scg		return 0xffffffff;
20961108Scg	}
21061108Scg}
21161108Scg
21261108Scgstatic void
21361108Scgds_wr(struct sc_info *sc, int regno, u_int32_t data, int size)
21461108Scg{
21561108Scg	switch (size) {
21661108Scg	case 1:
21761108Scg		bus_space_write_1(sc->st, sc->sh, regno, data);
21861108Scg		break;
21961108Scg	case 2:
22061108Scg		bus_space_write_2(sc->st, sc->sh, regno, data);
22161108Scg		break;
22261108Scg	case 4:
22361108Scg		bus_space_write_4(sc->st, sc->sh, regno, data);
22461108Scg		break;
22561108Scg	}
22661108Scg}
22761108Scg
22861108Scgstatic void
22961108Scgwrl(struct sc_info *sc, u_int32_t *ptr, u_int32_t val)
23061108Scg{
23161108Scg	*(volatile u_int32_t *)ptr = val;
23265171Sdfr	bus_space_barrier(sc->st, sc->sh, 0, 0, BUS_SPACE_BARRIER_WRITE);
23361108Scg}
23461108Scg
23570134Scg/* -------------------------------------------------------------------- */
23661108Scg/* ac97 codec */
23761108Scgstatic int
23861108Scgds_cdbusy(struct sc_info *sc, int sec)
23961108Scg{
24061108Scg	int i, reg;
24161108Scg
24261108Scg	reg = sec? YDSXGR_SECSTATUSADR : YDSXGR_PRISTATUSADR;
24361108Scg	i = YDSXG_AC97TIMEOUT;
24461108Scg	while (i > 0) {
24561108Scg		if (!(ds_rd(sc, reg, 2) & 0x8000))
24661108Scg			return 0;
24761108Scg		i--;
24861108Scg	}
24961108Scg	return ETIMEDOUT;
25061108Scg}
25161108Scg
25261108Scgstatic u_int32_t
25370134Scgds_initcd(kobj_t obj, void *devinfo)
25461108Scg{
25561108Scg	struct sc_info *sc = (struct sc_info *)devinfo;
25661108Scg	u_int32_t x;
25761108Scg
25861108Scg	x = pci_read_config(sc->dev, PCIR_DSXGCTRL, 1);
25961108Scg	if (x & 0x03) {
26061108Scg		pci_write_config(sc->dev, PCIR_DSXGCTRL, x & ~0x03, 1);
26161108Scg		pci_write_config(sc->dev, PCIR_DSXGCTRL, x | 0x03, 1);
26261108Scg		pci_write_config(sc->dev, PCIR_DSXGCTRL, x & ~0x03, 1);
26361146Speter		/*
26461146Speter		 * The YMF740 on some Intel motherboards requires a pretty
26561146Speter		 * hefty delay after this reset for some reason...  Otherwise:
26661146Speter		 * "pcm0: ac97 codec init failed"
26761146Speter		 * Maybe this is needed for all YMF740's?
26861146Speter		 * 400ms and 500ms here seem to work, 300ms does not.
26964015Scg		 *
27064015Scg		 * do it for all chips -cg
27161146Speter		 */
27264015Scg		DELAY(500000);
27361108Scg	}
27461108Scg
27565490Scg	return ds_cdbusy(sc, 0)? 0 : 1;
27661108Scg}
27761108Scg
27870134Scgstatic int
27970134Scgds_rdcd(kobj_t obj, void *devinfo, int regno)
28061108Scg{
28161108Scg	struct sc_info *sc = (struct sc_info *)devinfo;
28261108Scg	int sec, cid, i;
28361108Scg	u_int32_t cmd, reg;
28461108Scg
28561108Scg	sec = regno & 0x100;
28661108Scg	regno &= 0xff;
28761108Scg	cid = sec? (sc->cd2id << 8) : 0;
28861108Scg	reg = sec? YDSXGR_SECSTATUSDATA : YDSXGR_PRISTATUSDATA;
28961108Scg	if (sec && cid == 0)
29061108Scg		return 0xffffffff;
29161108Scg
29261108Scg	cmd = YDSXG_AC97READCMD | cid | regno;
29361108Scg	ds_wr(sc, YDSXGR_AC97CMDADR, cmd, 2);
29461108Scg
29561108Scg	if (ds_cdbusy(sc, sec))
29661108Scg		return 0xffffffff;
29761108Scg
29861146Speter	if (sc->type == 11 && sc->rev < 2)
29961108Scg		for (i = 0; i < 600; i++)
30061108Scg			ds_rd(sc, reg, 2);
30161108Scg
30261108Scg	return ds_rd(sc, reg, 2);
30361108Scg}
30461108Scg
30570134Scgstatic int
30670134Scgds_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data)
30761108Scg{
30861108Scg	struct sc_info *sc = (struct sc_info *)devinfo;
30961108Scg	int sec, cid;
31061108Scg	u_int32_t cmd;
31161108Scg
31261108Scg	sec = regno & 0x100;
31361108Scg	regno &= 0xff;
31461108Scg	cid = sec? (sc->cd2id << 8) : 0;
31561108Scg	if (sec && cid == 0)
31670134Scg		return ENXIO;
31761108Scg
31861108Scg	cmd = YDSXG_AC97WRITECMD | cid | regno;
31961108Scg	cmd <<= 16;
32061108Scg	cmd |= data;
32161108Scg	ds_wr(sc, YDSXGR_AC97CMDDATA, cmd, 4);
32261108Scg
32370134Scg	return ds_cdbusy(sc, sec);
32461108Scg}
32561108Scg
32670134Scgstatic kobj_method_t ds_ac97_methods[] = {
32770134Scg    	KOBJMETHOD(ac97_init,		ds_initcd),
32870134Scg    	KOBJMETHOD(ac97_read,		ds_rdcd),
32970134Scg    	KOBJMETHOD(ac97_write,		ds_wrcd),
330193640Sariff	KOBJMETHOD_END
33170134Scg};
33270134ScgAC97_DECLARE(ds_ac97);
33370134Scg
33470134Scg/* -------------------------------------------------------------------- */
33570134Scg
33661108Scgstatic void
33761108Scgds_enadsp(struct sc_info *sc, int on)
33861108Scg{
33961108Scg	u_int32_t v, i;
34061108Scg
34161108Scg	v = on? 1 : 0;
34261108Scg	if (on) {
34361108Scg		ds_wr(sc, YDSXGR_CONFIG, 0x00000001, 4);
34461108Scg	} else {
34561108Scg		if (ds_rd(sc, YDSXGR_CONFIG, 4))
34661108Scg			ds_wr(sc, YDSXGR_CONFIG, 0x00000000, 4);
34761108Scg		i = YDSXG_WORKBITTIMEOUT;
34861108Scg		while (i > 0) {
34961108Scg			if (!(ds_rd(sc, YDSXGR_CONFIG, 4) & 0x00000002))
35061108Scg				break;
35161108Scg			i--;
35261108Scg		}
35361108Scg	}
35461108Scg}
35561108Scg
35661108Scgstatic volatile struct pbank *
35761108Scgds_allocpslot(struct sc_info *sc)
35861108Scg{
35961108Scg	int slot;
36061108Scg
36161108Scg	if (sc->pslotfree > 63)
36261108Scg		return NULL;
36361108Scg	slot = sc->pslotfree++;
36461108Scg	return sc->pbank[slot * 2];
36561108Scg}
36661108Scg
36761108Scgstatic int
368111183Scognetds_initpbank(volatile struct pbank *pb, int ch, int b16, int stereo, u_int32_t rate, bus_addr_t base, u_int32_t len)
36961108Scg{
37061108Scg	u_int32_t lv[] = {1, 1, 0, 0, 0};
37161108Scg	u_int32_t rv[] = {1, 0, 1, 0, 0};
37261108Scg	u_int32_t e1[] = {0, 0, 0, 0, 0};
37361108Scg	u_int32_t e2[] = {1, 0, 0, 1, 0};
37461108Scg	u_int32_t e3[] = {1, 0, 0, 0, 1};
37561108Scg	int ss, i;
37661108Scg	u_int32_t delta;
37761108Scg
37861108Scg	struct {
37961108Scg		int rate, fK, fQ;
38061108Scg	} speedinfo[] = {
38161108Scg		{  100, 0x00570000, 0x35280000},
38261108Scg		{ 2000, 0x06aa0000, 0x34a70000},
38361108Scg		{ 8000, 0x18b20000, 0x32020000},
38461108Scg		{11025, 0x20930000, 0x31770000},
38561108Scg		{16000, 0x2b9a0000, 0x31390000},
38661108Scg		{22050, 0x35a10000, 0x31c90000},
38761108Scg		{32000, 0x3eaa0000, 0x33d00000},
38861108Scg/*		{44100, 0x04646000, 0x370a0000},
38961108Scg*/		{48000, 0x40000000, 0x40000000},
39061108Scg	};
39161108Scg
39261108Scg	ss = b16? 1 : 0;
39361108Scg	ss += stereo? 1 : 0;
39461108Scg	delta = (65536 * rate) / 48000;
39561108Scg	i = 0;
39661108Scg	while (i < 7 && speedinfo[i].rate < rate)
39761108Scg		i++;
39861108Scg
39961108Scg	pb->Format = stereo? 0x00010000 : 0;
40061108Scg	pb->Format |= b16? 0 : 0x80000000;
40161108Scg	pb->Format |= (stereo && (ch == 2 || ch == 4))? 0x00000001 : 0;
40261108Scg	pb->LoopDefault = 0;
403188424Scognet	pb->PgBase = base;
40461108Scg	pb->PgLoop = 0;
40561108Scg	pb->PgLoopEnd = len >> ss;
40661108Scg	pb->PgLoopFrac = 0;
40761108Scg	pb->Status = 0;
40861108Scg	pb->NumOfFrames = 0;
40961108Scg	pb->LoopCount = 0;
41061108Scg	pb->PgStart = 0;
41161108Scg	pb->PgStartFrac = 0;
41261108Scg	pb->PgDelta = pb->PgDeltaEnd = delta << 12;
41361108Scg	pb->LpfQ = speedinfo[i].fQ;
41461108Scg	pb->LpfK = pb->LpfKEnd = speedinfo[i].fK;
41561108Scg	pb->LpfD1 = pb->LpfD2 = 0;
41661108Scg	pb->EgGain = pb->EgGainEnd = 0x40000000;
41761108Scg	pb->LchGain = pb->LchGainEnd = lv[ch] * 0x40000000;
41861108Scg	pb->RchGain = pb->RchGainEnd = rv[ch] * 0x40000000;
41961108Scg	pb->Effect1Gain = pb->Effect1GainEnd = e1[ch] * 0x40000000;
42061108Scg	pb->Effect2Gain = pb->Effect2GainEnd = e2[ch] * 0x40000000;
42161108Scg	pb->Effect3Gain = pb->Effect3GainEnd = e3[ch] * 0x40000000;
42261108Scg
42361108Scg	return 0;
42461108Scg}
42561108Scg
42661108Scgstatic void
42761108Scgds_enapslot(struct sc_info *sc, int slot, int go)
42861108Scg{
42961108Scg	wrl(sc, &sc->pbase[slot + 1], go? (sc->pbankbase + 2 * slot * sc->pbanksize) : 0);
43061108Scg	/* printf("pbase[%d] = 0x%x\n", slot + 1, go? (sc->pbankbase + 2 * slot * sc->pbanksize) : 0); */
43161108Scg}
43261108Scg
43361108Scgstatic void
43461346Scgds_setuppch(struct sc_pchinfo *ch)
43561108Scg{
43661346Scg	int stereo, b16, c, sz;
437111183Scognet	bus_addr_t addr;
43861108Scg
439193640Sariff	stereo = (AFMT_CHANNEL(ch->fmt) > 1)? 1 : 0;
44061108Scg	b16 = (ch->fmt & AFMT_16BIT)? 1 : 0;
44161108Scg	c = stereo? 1 : 0;
442111183Scognet	addr = sndbuf_getbufaddr(ch->buffer);
44370291Scg	sz = sndbuf_getsize(ch->buffer);
44461108Scg
445111183Scognet	ds_initpbank(ch->lslot, c, stereo, b16, ch->spd, addr, sz);
446111183Scognet	ds_initpbank(ch->lslot + 1, c, stereo, b16, ch->spd, addr, sz);
447111183Scognet	ds_initpbank(ch->rslot, 2, stereo, b16, ch->spd, addr, sz);
448111183Scognet	ds_initpbank(ch->rslot + 1, 2, stereo, b16, ch->spd, addr, sz);
44961108Scg}
45061108Scg
45161346Scgstatic void
45261346Scgds_setuprch(struct sc_rchinfo *ch)
45361108Scg{
45461346Scg	struct sc_info *sc = ch->parent;
45561346Scg	int stereo, b16, i, sz, pri;
45661346Scg	u_int32_t x, y;
457111183Scognet	bus_addr_t addr;
45861346Scg
459193640Sariff	stereo = (AFMT_CHANNEL(ch->fmt) > 1)? 1 : 0;
46061346Scg	b16 = (ch->fmt & AFMT_16BIT)? 1 : 0;
461111183Scognet	addr = sndbuf_getbufaddr(ch->buffer);
46270291Scg	sz = sndbuf_getsize(ch->buffer);
46361346Scg	pri = (ch->num == DS1_RECPRIMARY)? 1 : 0;
46461346Scg
46561346Scg	for (i = 0; i < 2; i++) {
466111183Scognet		ch->slot[i].PgBase = addr;
46761346Scg		ch->slot[i].PgLoopEnd = sz;
46861346Scg		ch->slot[i].PgStart = 0;
46961346Scg		ch->slot[i].NumOfLoops = 0;
47061346Scg	}
47161346Scg	x = (b16? 0x00 : 0x01) | (stereo? 0x02 : 0x00);
47261346Scg	y = (48000 * 4096) / ch->spd;
47361346Scg	y--;
47461346Scg	/* printf("pri = %d, x = %d, y = %d\n", pri, x, y); */
47561346Scg	ds_wr(sc, pri? YDSXGR_ADCFORMAT : YDSXGR_RECFORMAT, x, 4);
47661346Scg	ds_wr(sc, pri? YDSXGR_ADCSLOTSR : YDSXGR_RECSLOTSR, y, 4);
47761346Scg}
47861346Scg
47970134Scg/* -------------------------------------------------------------------- */
48061346Scg/* play channel interface */
48161346Scgstatic void *
48274763Scgds1pchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
48361346Scg{
48461108Scg	struct sc_info *sc = devinfo;
48561346Scg	struct sc_pchinfo *ch;
48661108Scg
48761346Scg	KASSERT(dir == PCMDIR_PLAY, ("ds1pchan_init: bad direction"));
48861346Scg
48961346Scg	ch = &sc->pch[sc->pchn++];
49061108Scg	ch->buffer = b;
49161108Scg	ch->parent = sc;
49261108Scg	ch->channel = c;
49361346Scg	ch->dir = dir;
494193640Sariff	ch->fmt = SND_FORMAT(AFMT_U8, 1, 0);
49561108Scg	ch->spd = 8000;
49661108Scg	ch->run = 0;
497168847Sariff	if (sndbuf_alloc(ch->buffer, sc->buffer_dmat, 0, sc->bufsz) != 0)
49861108Scg		return NULL;
49961108Scg	else {
50061108Scg		ch->lsnum = sc->pslotfree;
50161108Scg		ch->lslot = ds_allocpslot(sc);
50261108Scg		ch->rsnum = sc->pslotfree;
50361108Scg		ch->rslot = ds_allocpslot(sc);
50461346Scg		ds_setuppch(ch);
50561108Scg		return ch;
50661108Scg	}
50761108Scg}
50861108Scg
50961108Scgstatic int
51070134Scgds1pchan_setformat(kobj_t obj, void *data, u_int32_t format)
51161108Scg{
51261346Scg	struct sc_pchinfo *ch = data;
51361108Scg
51461108Scg	ch->fmt = format;
51561108Scg
51661108Scg	return 0;
51761108Scg}
51861108Scg
519193640Sariffstatic u_int32_t
52070134Scgds1pchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
52161108Scg{
52261346Scg	struct sc_pchinfo *ch = data;
52361108Scg
52461108Scg	ch->spd = speed;
52561108Scg
52661108Scg	return speed;
52761108Scg}
52861108Scg
529193640Sariffstatic u_int32_t
53070134Scgds1pchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
53161108Scg{
53270343Scg	struct sc_pchinfo *ch = data;
533119362Siedowse	struct sc_info *sc = ch->parent;
53470343Scg	int drate;
53570343Scg
53670343Scg	/* irq rate is fixed at 187.5hz */
537193640Sariff	drate = ch->spd * sndbuf_getalign(ch->buffer);
538119362Siedowse	blocksize = roundup2((drate << 8) / DS1_IRQHZ, 4);
539119362Siedowse	sndbuf_resize(ch->buffer, sc->bufsz / blocksize, blocksize);
54071504Scg
54161108Scg	return blocksize;
54261108Scg}
54361108Scg
54461108Scg/* semantic note: must start at beginning of buffer */
54561108Scgstatic int
54670134Scgds1pchan_trigger(kobj_t obj, void *data, int go)
54761108Scg{
54861346Scg	struct sc_pchinfo *ch = data;
54961346Scg	struct sc_info *sc = ch->parent;
55061108Scg	int stereo;
55161108Scg
552170521Sariff	if (!PCMTRIG_COMMON(go))
55361108Scg		return 0;
554193640Sariff	stereo = (AFMT_CHANNEL(ch->fmt) > 1)? 1 : 0;
55561108Scg	if (go == PCMTRIG_START) {
55661108Scg		ch->run = 1;
55761346Scg		ds_setuppch(ch);
55861108Scg		ds_enapslot(sc, ch->lsnum, 1);
55961108Scg		ds_enapslot(sc, ch->rsnum, stereo);
56074763Scg		snd_mtxlock(sc->lock);
56161108Scg		ds_wr(sc, YDSXGR_MODE, 0x00000003, 4);
56274763Scg		snd_mtxunlock(sc->lock);
56361108Scg	} else {
56461108Scg		ch->run = 0;
56561346Scg		/* ds_setuppch(ch); */
56661108Scg		ds_enapslot(sc, ch->lsnum, 0);
56761108Scg		ds_enapslot(sc, ch->rsnum, 0);
56861108Scg	}
56961108Scg
57061108Scg	return 0;
57161108Scg}
57261108Scg
573193640Sariffstatic u_int32_t
57470134Scgds1pchan_getptr(kobj_t obj, void *data)
57561108Scg{
57661346Scg	struct sc_pchinfo *ch = data;
57761108Scg	struct sc_info *sc = ch->parent;
57861108Scg	volatile struct pbank *bank;
57961108Scg	int ss;
58061108Scg	u_int32_t ptr;
58161108Scg
582193640Sariff	ss = (AFMT_CHANNEL(ch->fmt) > 1)? 1 : 0;
58361108Scg	ss += (ch->fmt & AFMT_16BIT)? 1 : 0;
58461108Scg
58561108Scg	bank = ch->lslot + sc->currbank;
58661108Scg	/* printf("getptr: %d\n", bank->PgStart << ss); */
58761108Scg	ptr = bank->PgStart;
58861108Scg	ptr <<= ss;
58961108Scg	return ptr;
59061108Scg}
59161108Scg
59274763Scgstatic struct pcmchan_caps *
59370134Scgds1pchan_getcaps(kobj_t obj, void *data)
59461108Scg{
59561346Scg	return &ds_playcaps;
59661346Scg}
59761108Scg
59870134Scgstatic kobj_method_t ds1pchan_methods[] = {
59970134Scg    	KOBJMETHOD(channel_init,		ds1pchan_init),
60070134Scg    	KOBJMETHOD(channel_setformat,		ds1pchan_setformat),
60170134Scg    	KOBJMETHOD(channel_setspeed,		ds1pchan_setspeed),
60270134Scg    	KOBJMETHOD(channel_setblocksize,	ds1pchan_setblocksize),
60370134Scg    	KOBJMETHOD(channel_trigger,		ds1pchan_trigger),
60470134Scg    	KOBJMETHOD(channel_getptr,		ds1pchan_getptr),
60570134Scg    	KOBJMETHOD(channel_getcaps,		ds1pchan_getcaps),
606193640Sariff	KOBJMETHOD_END
60770134Scg};
60870134ScgCHANNEL_DECLARE(ds1pchan);
60970134Scg
61070134Scg/* -------------------------------------------------------------------- */
61161346Scg/* record channel interface */
61261346Scgstatic void *
61374763Scgds1rchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
61461346Scg{
61561346Scg	struct sc_info *sc = devinfo;
61661346Scg	struct sc_rchinfo *ch;
61761346Scg
61861346Scg	KASSERT(dir == PCMDIR_REC, ("ds1rchan_init: bad direction"));
61961346Scg
62061346Scg	ch = &sc->rch[sc->rchn];
62161346Scg	ch->num = sc->rchn++;
62261346Scg	ch->buffer = b;
62361346Scg	ch->parent = sc;
62461346Scg	ch->channel = c;
62561346Scg	ch->dir = dir;
626193640Sariff	ch->fmt = SND_FORMAT(AFMT_U8, 1, 0);
62761346Scg	ch->spd = 8000;
628168847Sariff	if (sndbuf_alloc(ch->buffer, sc->buffer_dmat, 0, sc->bufsz) != 0)
62961346Scg		return NULL;
63061346Scg	else {
63161346Scg		ch->slot = (ch->num == DS1_RECPRIMARY)? sc->rbank + 2: sc->rbank;
63261346Scg		ds_setuprch(ch);
63361346Scg		return ch;
63461346Scg	}
63561108Scg}
63661108Scg
63761346Scgstatic int
63870134Scgds1rchan_setformat(kobj_t obj, void *data, u_int32_t format)
63961346Scg{
64061346Scg	struct sc_rchinfo *ch = data;
64161346Scg
64261346Scg	ch->fmt = format;
64361346Scg
64461346Scg	return 0;
64561346Scg}
64661346Scg
647193640Sariffstatic u_int32_t
64870134Scgds1rchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
64961346Scg{
65061346Scg	struct sc_rchinfo *ch = data;
65161346Scg
65261346Scg	ch->spd = speed;
65361346Scg
65461346Scg	return speed;
65561346Scg}
65661346Scg
657193640Sariffstatic u_int32_t
65870134Scgds1rchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
65961346Scg{
66071504Scg	struct sc_rchinfo *ch = data;
661119362Siedowse	struct sc_info *sc = ch->parent;
66271504Scg	int drate;
66371504Scg
66471504Scg	/* irq rate is fixed at 187.5hz */
665193640Sariff	drate = ch->spd * sndbuf_getalign(ch->buffer);
666119362Siedowse	blocksize = roundup2((drate << 8) / DS1_IRQHZ, 4);
667119362Siedowse	sndbuf_resize(ch->buffer, sc->bufsz / blocksize, blocksize);
66871504Scg
66961346Scg	return blocksize;
67061346Scg}
67161346Scg
67261346Scg/* semantic note: must start at beginning of buffer */
67361346Scgstatic int
67470134Scgds1rchan_trigger(kobj_t obj, void *data, int go)
67561346Scg{
67661346Scg	struct sc_rchinfo *ch = data;
67761346Scg	struct sc_info *sc = ch->parent;
67861346Scg	u_int32_t x;
67961346Scg
680170521Sariff	if (!PCMTRIG_COMMON(go))
68161346Scg		return 0;
68261346Scg	if (go == PCMTRIG_START) {
68361346Scg		ch->run = 1;
68461346Scg		ds_setuprch(ch);
68574763Scg		snd_mtxlock(sc->lock);
68661346Scg		x = ds_rd(sc, YDSXGR_MAPOFREC, 4);
68761346Scg		x |= (ch->num == DS1_RECPRIMARY)? 0x02 : 0x01;
68861346Scg		ds_wr(sc, YDSXGR_MAPOFREC, x, 4);
68961346Scg		ds_wr(sc, YDSXGR_MODE, 0x00000003, 4);
69074763Scg		snd_mtxunlock(sc->lock);
69161346Scg	} else {
69261346Scg		ch->run = 0;
69374763Scg		snd_mtxlock(sc->lock);
69461346Scg		x = ds_rd(sc, YDSXGR_MAPOFREC, 4);
69561346Scg		x &= ~((ch->num == DS1_RECPRIMARY)? 0x02 : 0x01);
69661346Scg		ds_wr(sc, YDSXGR_MAPOFREC, x, 4);
69774763Scg		snd_mtxunlock(sc->lock);
69861346Scg	}
69961346Scg
70061346Scg	return 0;
70161346Scg}
70261346Scg
703193640Sariffstatic u_int32_t
70470134Scgds1rchan_getptr(kobj_t obj, void *data)
70561346Scg{
70661346Scg	struct sc_rchinfo *ch = data;
70761346Scg	struct sc_info *sc = ch->parent;
70861346Scg
70961346Scg	return ch->slot[sc->currbank].PgStart;
71061346Scg}
71161346Scg
71274763Scgstatic struct pcmchan_caps *
71370134Scgds1rchan_getcaps(kobj_t obj, void *data)
71461346Scg{
71561346Scg	return &ds_reccaps;
71661346Scg}
71761346Scg
71870134Scgstatic kobj_method_t ds1rchan_methods[] = {
71970134Scg    	KOBJMETHOD(channel_init,		ds1rchan_init),
72070134Scg    	KOBJMETHOD(channel_setformat,		ds1rchan_setformat),
72170134Scg    	KOBJMETHOD(channel_setspeed,		ds1rchan_setspeed),
72270134Scg    	KOBJMETHOD(channel_setblocksize,	ds1rchan_setblocksize),
72370134Scg    	KOBJMETHOD(channel_trigger,		ds1rchan_trigger),
72470134Scg    	KOBJMETHOD(channel_getptr,		ds1rchan_getptr),
72570134Scg    	KOBJMETHOD(channel_getcaps,		ds1rchan_getcaps),
726193640Sariff	KOBJMETHOD_END
72770134Scg};
72870134ScgCHANNEL_DECLARE(ds1rchan);
72970134Scg
73070134Scg/* -------------------------------------------------------------------- */
73161108Scg/* The interrupt handler */
73261108Scgstatic void
73361108Scgds_intr(void *p)
73461108Scg{
73561108Scg	struct sc_info *sc = (struct sc_info *)p;
73661108Scg	u_int32_t i, x;
73761108Scg
73874763Scg	snd_mtxlock(sc->lock);
73961108Scg	i = ds_rd(sc, YDSXGR_STATUS, 4);
74061346Scg	if (i & 0x00008000)
74161346Scg		device_printf(sc->dev, "timeout irq\n");
74261108Scg	if (i & 0x80008000) {
74361108Scg		ds_wr(sc, YDSXGR_STATUS, i & 0x80008000, 4);
74461108Scg		sc->currbank = ds_rd(sc, YDSXGR_CTRLSELECT, 4) & 0x00000001;
74561108Scg
74661108Scg		x = 0;
74761346Scg		for (i = 0; i < DS1_CHANS; i++) {
74861108Scg			if (sc->pch[i].run) {
74961108Scg				x = 1;
750154215Sariff				snd_mtxunlock(sc->lock);
75161108Scg				chn_intr(sc->pch[i].channel);
752154215Sariff				snd_mtxlock(sc->lock);
75361108Scg			}
75461346Scg		}
75561346Scg		for (i = 0; i < 2; i++) {
75661346Scg			if (sc->rch[i].run) {
75761346Scg				x = 1;
758154215Sariff				snd_mtxunlock(sc->lock);
75961346Scg				chn_intr(sc->rch[i].channel);
760154215Sariff				snd_mtxlock(sc->lock);
76161346Scg			}
76261346Scg		}
76361108Scg		i = ds_rd(sc, YDSXGR_MODE, 4);
76461108Scg		if (x)
76561108Scg			ds_wr(sc, YDSXGR_MODE, i | 0x00000002, 4);
76661108Scg
76761108Scg	}
76874763Scg	snd_mtxunlock(sc->lock);
76961108Scg}
77061108Scg
77161108Scg/* -------------------------------------------------------------------- */
77261108Scg
77361108Scg/*
77461108Scg * Probe and attach the card
77561108Scg */
77661108Scg
77761108Scgstatic void
77861108Scgds_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
77961108Scg{
78061108Scg	struct sc_info *sc = arg;
78161108Scg
78261108Scg	sc->ctrlbase = error? 0 : (u_int32_t)segs->ds_addr;
78361108Scg
78461108Scg	if (bootverbose) {
78561133Scg		printf("ds1: setmap (%lx, %lx), nseg=%d, error=%d\n",
78661133Scg		       (unsigned long)segs->ds_addr, (unsigned long)segs->ds_len,
78761133Scg		       nseg, error);
78861108Scg	}
78961108Scg}
79061108Scg
79161108Scgstatic int
792166919Sariffds_init(struct sc_info *sc)
79361108Scg{
79461108Scg	int i;
79561108Scg	u_int32_t *ci, r, pcs, rcs, ecs, ws, memsz, cb;
79661108Scg	u_int8_t *t;
79761108Scg	void *buf;
79861108Scg
79961108Scg	ci = ds_devs[sc->type].mcode;
80061108Scg
80161108Scg	ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x00000000, 4);
80261108Scg	ds_enadsp(sc, 0);
80361108Scg	ds_wr(sc, YDSXGR_MODE, 0x00010000, 4);
80461108Scg	ds_wr(sc, YDSXGR_MODE, 0x00000000, 4);
80561108Scg	ds_wr(sc, YDSXGR_MAPOFREC, 0x00000000, 4);
80661108Scg	ds_wr(sc, YDSXGR_MAPOFEFFECT, 0x00000000, 4);
80761108Scg	ds_wr(sc, YDSXGR_PLAYCTRLBASE, 0x00000000, 4);
80861108Scg	ds_wr(sc, YDSXGR_RECCTRLBASE, 0x00000000, 4);
80961108Scg	ds_wr(sc, YDSXGR_EFFCTRLBASE, 0x00000000, 4);
81061108Scg	r = ds_rd(sc, YDSXGR_GLOBALCTRL, 2);
81161108Scg	ds_wr(sc, YDSXGR_GLOBALCTRL, r & ~0x0007, 2);
81261108Scg
81361108Scg	for (i = 0; i < YDSXG_DSPLENGTH; i += 4)
81461108Scg		ds_wr(sc, YDSXGR_DSPINSTRAM + i, DspInst[i >> 2], 4);
81561108Scg
81661108Scg	for (i = 0; i < YDSXG_CTRLLENGTH; i += 4)
81761108Scg		ds_wr(sc, YDSXGR_CTRLINSTRAM + i, ci[i >> 2], 4);
81861108Scg
81961108Scg	ds_enadsp(sc, 1);
82061108Scg
82161142Scg	pcs = 0;
82261142Scg	for (i = 100; i > 0; i--) {
82361142Scg		pcs = ds_rd(sc, YDSXGR_PLAYCTRLSIZE, 4) << 2;
82461142Scg		if (pcs == sizeof(struct pbank))
82561142Scg			break;
82661456Sdan		DELAY(1000);
82761142Scg	}
82861142Scg	if (pcs != sizeof(struct pbank)) {
82961142Scg		device_printf(sc->dev, "preposterous playctrlsize (%d)\n", pcs);
83061142Scg		return -1;
83161142Scg	}
83261108Scg	rcs = ds_rd(sc, YDSXGR_RECCTRLSIZE, 4) << 2;
83361108Scg	ecs = ds_rd(sc, YDSXGR_EFFCTRLSIZE, 4) << 2;
83461108Scg	ws = ds_rd(sc, YDSXGR_WORKSIZE, 4) << 2;
83561108Scg
83661108Scg	memsz = 64 * 2 * pcs + 2 * 2 * rcs + 5 * 2 * ecs + ws;
83761108Scg	memsz += (64 + 1) * 4;
83861108Scg
83965218Scg	if (sc->regbase == NULL) {
840166919Sariff		if (bus_dma_tag_create(bus_get_dma_tag(sc->dev), 2, 0,
841166904Snetchild				       BUS_SPACE_MAXADDR_32BIT,
842166904Snetchild				       BUS_SPACE_MAXADDR,
843154494Sariff				       NULL, NULL, memsz, 1, memsz, 0, NULL,
844154494Sariff				       NULL, &sc->control_dmat))
84565218Scg			return -1;
84684659Scg		if (bus_dmamem_alloc(sc->control_dmat, &buf, BUS_DMA_NOWAIT, &sc->map))
84784659Scg			return -1;
84884659Scg		if (bus_dmamap_load(sc->control_dmat, sc->map, buf, memsz, ds_setmap, sc, 0) || !sc->ctrlbase) {
84965218Scg			device_printf(sc->dev, "pcs=%d, rcs=%d, ecs=%d, ws=%d, memsz=%d\n",
85084659Scg			      	      pcs, rcs, ecs, ws, memsz);
85165218Scg			return -1;
85265218Scg		}
85365218Scg		sc->regbase = buf;
85465218Scg	} else
85565218Scg		buf = sc->regbase;
85661108Scg
85761108Scg	cb = 0;
85861108Scg	t = buf;
85961108Scg	ds_wr(sc, YDSXGR_WORKBASE, sc->ctrlbase + cb, 4);
86061108Scg	cb += ws;
86161108Scg	sc->pbase = (u_int32_t *)(t + cb);
86261108Scg	/* printf("pbase = %p -> 0x%x\n", sc->pbase, sc->ctrlbase + cb); */
86361108Scg	ds_wr(sc, YDSXGR_PLAYCTRLBASE, sc->ctrlbase + cb, 4);
86461108Scg	cb += (64 + 1) * 4;
86561346Scg	sc->rbank = (struct rbank *)(t + cb);
86661108Scg	ds_wr(sc, YDSXGR_RECCTRLBASE, sc->ctrlbase + cb, 4);
86761108Scg	cb += 2 * 2 * rcs;
86861108Scg	ds_wr(sc, YDSXGR_EFFCTRLBASE, sc->ctrlbase + cb, 4);
86961108Scg	cb += 5 * 2 * ecs;
87061108Scg
87161108Scg	sc->pbankbase = sc->ctrlbase + cb;
87261108Scg	sc->pbanksize = pcs;
87361108Scg	for (i = 0; i < 64; i++) {
87461108Scg		wrl(sc, &sc->pbase[i + 1], 0);
87561108Scg		sc->pbank[i * 2] = (struct pbank *)(t + cb);
87661108Scg		/* printf("pbank[%d] = %p -> 0x%x; ", i * 2, (struct pbank *)(t + cb), sc->ctrlbase + cb - vtophys(t + cb)); */
87761108Scg		cb += pcs;
87861108Scg		sc->pbank[i * 2 + 1] = (struct pbank *)(t + cb);
87961108Scg		/* printf("pbank[%d] = %p -> 0x%x\n", i * 2 + 1, (struct pbank *)(t + cb), sc->ctrlbase + cb - vtophys(t + cb)); */
88061108Scg		cb += pcs;
88161108Scg	}
88261108Scg	wrl(sc, &sc->pbase[0], DS1_CHANS * 2);
88361108Scg
88461108Scg	sc->pchn = sc->rchn = 0;
88561108Scg	ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff, 4);
88661346Scg	ds_wr(sc, YDSXGR_NATIVEADCINVOL, 0x3fff3fff, 4);
88761346Scg	ds_wr(sc, YDSXGR_NATIVEDACINVOL, 0x3fff3fff, 4);
88870343Scg
88961108Scg	return 0;
89061108Scg}
89161108Scg
89261108Scgstatic int
89365340Scgds_uninit(struct sc_info *sc)
89465340Scg{
89565340Scg	ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x00000000, 4);
89665340Scg	ds_wr(sc, YDSXGR_NATIVEADCINVOL, 0, 4);
89765340Scg	ds_wr(sc, YDSXGR_NATIVEDACINVOL, 0, 4);
89865340Scg	ds_enadsp(sc, 0);
89965340Scg	ds_wr(sc, YDSXGR_MODE, 0x00010000, 4);
90065340Scg	ds_wr(sc, YDSXGR_MAPOFREC, 0x00000000, 4);
90165340Scg	ds_wr(sc, YDSXGR_MAPOFEFFECT, 0x00000000, 4);
90265340Scg	ds_wr(sc, YDSXGR_PLAYCTRLBASE, 0x00000000, 4);
90365340Scg	ds_wr(sc, YDSXGR_RECCTRLBASE, 0x00000000, 4);
90465340Scg	ds_wr(sc, YDSXGR_EFFCTRLBASE, 0x00000000, 4);
90565340Scg	ds_wr(sc, YDSXGR_GLOBALCTRL, 0, 2);
90665340Scg
90784659Scg	bus_dmamap_unload(sc->control_dmat, sc->map);
90884659Scg	bus_dmamem_free(sc->control_dmat, sc->regbase, sc->map);
90965340Scg
91065340Scg	return 0;
91165340Scg}
91265340Scg
91365340Scgstatic int
91461108Scgds_finddev(u_int32_t dev, u_int32_t subdev)
91561108Scg{
91661108Scg	int i;
91761108Scg
91861108Scg	for (i = 0; ds_devs[i].dev; i++) {
91961108Scg		if (ds_devs[i].dev == dev &&
92061108Scg		    (ds_devs[i].subdev == subdev || ds_devs[i].subdev == 0))
92161108Scg			return i;
92261108Scg	}
92361108Scg	return -1;
92461108Scg}
92561108Scg
92661108Scgstatic int
92761108Scgds_pci_probe(device_t dev)
92861108Scg{
92961108Scg	int i;
93061108Scg	u_int32_t subdev;
93161108Scg
93261108Scg	subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev);
93361108Scg	i = ds_finddev(pci_get_devid(dev), subdev);
93461108Scg	if (i >= 0) {
93561108Scg		device_set_desc(dev, ds_devs[i].name);
936142890Simp		return BUS_PROBE_DEFAULT;
93761108Scg	} else
93861108Scg		return ENXIO;
93961108Scg}
94061108Scg
94161108Scgstatic int
94261108Scgds_pci_attach(device_t dev)
94361108Scg{
94461108Scg	u_int32_t subdev, i;
94561108Scg	struct sc_info *sc;
94665644Scg	struct ac97_info *codec = NULL;
94761108Scg	char 		status[SND_STATUSLEN];
94861108Scg
949170873Sariff	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
950167608Sariff	sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_ds1 softc");
95161108Scg	sc->dev = dev;
95261108Scg	subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev);
95361108Scg	sc->type = ds_finddev(pci_get_devid(dev), subdev);
95461108Scg	sc->rev = pci_get_revid(dev);
95561108Scg
956254306Sscottl	pci_enable_busmaster(dev);
95761108Scg
958119690Sjhb	sc->regid = PCIR_BAR(0);
959127135Snjl	sc->reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->regid,
960127135Snjl					 RF_ACTIVE);
96161108Scg	if (!sc->reg) {
96261108Scg		device_printf(dev, "unable to map register space\n");
96361108Scg		goto bad;
96461108Scg	}
96561108Scg
96661108Scg	sc->st = rman_get_bustag(sc->reg);
96761108Scg	sc->sh = rman_get_bushandle(sc->reg);
96861108Scg
96984659Scg	sc->bufsz = pcm_getbuffersize(dev, 4096, DS1_BUFFSIZE, 65536);
97084659Scg
971166904Snetchild	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
972166904Snetchild		/*boundary*/0,
97361108Scg		/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
97461108Scg		/*highaddr*/BUS_SPACE_MAXADDR,
97561108Scg		/*filter*/NULL, /*filterarg*/NULL,
97684659Scg		/*maxsize*/sc->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff,
977154494Sariff		/*flags*/0, /*lockfunc*/NULL,
978154494Sariff		/*lockarg*/NULL, &sc->buffer_dmat) != 0) {
97961108Scg		device_printf(dev, "unable to create dma tag\n");
98061108Scg		goto bad;
98161108Scg	}
98261108Scg
98365218Scg	sc->regbase = NULL;
984166919Sariff	if (ds_init(sc) == -1) {
98561108Scg		device_printf(dev, "unable to initialize the card\n");
98661108Scg		goto bad;
98761108Scg	}
98861108Scg
98970134Scg	codec = AC97_CREATE(dev, sc, ds_ac97);
99061108Scg	if (codec == NULL)
99161108Scg		goto bad;
992154215Sariff	/*
993154215Sariff	 * Turn on inverted external amplifier sense flags for few
994154215Sariff	 * 'special' boards.
995154215Sariff	 */
996154215Sariff	switch (subdev) {
997154215Sariff	case 0x81171033:	/* NEC ValueStar (VT550/0) */
998154215Sariff		ac97_setflags(codec, ac97_getflags(codec) | AC97_F_EAPD_INV);
999154215Sariff		break;
1000154215Sariff	default:
1001154215Sariff		break;
1002154215Sariff	}
100370134Scg	mixer_init(dev, ac97_getmixerclass(), codec);
100461108Scg
100561108Scg	sc->irqid = 0;
1006127135Snjl	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
1007127135Snjl					 RF_ACTIVE | RF_SHAREABLE);
1008154215Sariff	if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, ds_intr, sc, &sc->ih)) {
100961108Scg		device_printf(dev, "unable to map interrupt\n");
101061108Scg		goto bad;
101161108Scg	}
101261108Scg
1013126695Smatk	snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld %s",
1014126695Smatk		 rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_ds1));
101561108Scg
101661346Scg	if (pcm_register(dev, sc, DS1_CHANS, 2))
101761108Scg		goto bad;
101861108Scg	for (i = 0; i < DS1_CHANS; i++)
101970134Scg		pcm_addchan(dev, PCMDIR_PLAY, &ds1pchan_class, sc);
102061346Scg	for (i = 0; i < 2; i++)
102170134Scg		pcm_addchan(dev, PCMDIR_REC, &ds1rchan_class, sc);
102261108Scg	pcm_setstatus(dev, status);
102361108Scg
102461108Scg	return 0;
102561108Scg
102661108Scgbad:
102765644Scg	if (codec)
102865644Scg		ac97_destroy(codec);
102961108Scg	if (sc->reg)
103061108Scg		bus_release_resource(dev, SYS_RES_MEMORY, sc->regid, sc->reg);
103161108Scg	if (sc->ih)
103261108Scg		bus_teardown_intr(dev, sc->irq, sc->ih);
103361108Scg	if (sc->irq)
103461108Scg		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
103584659Scg	if (sc->buffer_dmat)
103684659Scg		bus_dma_tag_destroy(sc->buffer_dmat);
103784659Scg	if (sc->control_dmat)
103884659Scg		bus_dma_tag_destroy(sc->control_dmat);
103974763Scg	if (sc->lock)
104074763Scg		snd_mtxfree(sc->lock);
104161108Scg	free(sc, M_DEVBUF);
104261108Scg	return ENXIO;
104361108Scg}
104461108Scg
104565218Scgstatic int
104665218Scgds_pci_resume(device_t dev)
104765218Scg{
104865218Scg       struct sc_info *sc;
104965218Scg
105065218Scg       sc = pcm_getdevinfo(dev);
105165218Scg
1052166919Sariff       if (ds_init(sc) == -1) {
105365218Scg           device_printf(dev, "unable to reinitialize the card\n");
105465218Scg           return ENXIO;
105565218Scg       }
105665340Scg       if (mixer_reinit(dev) == -1) {
105765218Scg               device_printf(dev, "unable to reinitialize the mixer\n");
105865218Scg               return ENXIO;
105965218Scg       }
106065218Scg       return 0;
106165218Scg}
106265218Scg
106365340Scgstatic int
106465340Scgds_pci_detach(device_t dev)
106565340Scg{
106665340Scg    	int r;
106765340Scg	struct sc_info *sc;
106865340Scg
106965340Scg	r = pcm_unregister(dev);
107065340Scg	if (r)
107165340Scg    		return r;
107265340Scg
107365340Scg	sc = pcm_getdevinfo(dev);
107465340Scg	ds_uninit(sc);
107565644Scg	bus_release_resource(dev, SYS_RES_MEMORY, sc->regid, sc->reg);
107665644Scg	bus_teardown_intr(dev, sc->irq, sc->ih);
107765644Scg	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
107884659Scg	bus_dma_tag_destroy(sc->buffer_dmat);
107984659Scg	bus_dma_tag_destroy(sc->control_dmat);
108074763Scg	snd_mtxfree(sc->lock);
108165340Scg	free(sc, M_DEVBUF);
108265340Scg       	return 0;
108365340Scg}
108465340Scg
108561108Scgstatic device_method_t ds1_methods[] = {
108661108Scg	/* Device interface */
108761108Scg	DEVMETHOD(device_probe,		ds_pci_probe),
108861108Scg	DEVMETHOD(device_attach,	ds_pci_attach),
108965340Scg	DEVMETHOD(device_detach,	ds_pci_detach),
109065340Scg	DEVMETHOD(device_resume,        ds_pci_resume),
109161108Scg	{ 0, 0 }
109261108Scg};
109361108Scg
109461108Scgstatic driver_t ds1_driver = {
109561108Scg	"pcm",
109661108Scg	ds1_methods,
109782180Scg	PCM_SOFTC_SIZE,
109861108Scg};
109961108Scg
110062483ScgDRIVER_MODULE(snd_ds1, pci, ds1_driver, pcm_devclass, 0, 0);
1101132236StanimuraMODULE_DEPEND(snd_ds1, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
110262483ScgMODULE_VERSION(snd_ds1, 1);
1103