ds1.c revision 111183
1251881Speter/*
2251881Speter * Copyright (c) 2000 Cameron Grant <cg@freebsd.org>
3251881Speter * All rights reserved.
4251881Speter *
5251881Speter * Redistribution and use in source and binary forms, with or without
6251881Speter * modification, are permitted provided that the following conditions
7251881Speter * are met:
8251881Speter * 1. Redistributions of source code must retain the above copyright
9251881Speter *    notice, this list of conditions and the following disclaimer.
10251881Speter * 2. Redistributions in binary form must reproduce the above copyright
11251881Speter *    notice, this list of conditions and the following disclaimer in the
12251881Speter *    documentation and/or other materials provided with the distribution.
13251881Speter *
14251881Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15251881Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16251881Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17251881Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18251881Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19251881Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20251881Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
22251881Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23251881Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
24251881Speter * SUCH DAMAGE.
25251881Speter */
26251881Speter
27251881Speter#include <dev/sound/pcm/sound.h>
28251881Speter#include <dev/sound/pcm/ac97.h>
29251881Speter
30251881Speter#include <pci/pcireg.h>
31251881Speter#include <pci/pcivar.h>
32251881Speter
33251881Speter#include <dev/sound/pci/ds1.h>
34251881Speter#include <dev/sound/pci/ds1-fw.h>
35251881Speter
36251881SpeterSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/ds1.c 111183 2003-02-20 17:31:12Z cognet $");
37251881Speter
38251881Speter/* -------------------------------------------------------------------- */
39251881Speter
40251881Speter#define	DS1_CHANS 4
41251881Speter#define DS1_RECPRIMARY 0
42251881Speter#define DS1_IRQHZ ((48000 << 8) / 256)
43251881Speter#define DS1_BUFFSIZE 4096
44251881Speter
45251881Speterstruct pbank {
46251881Speter	volatile u_int32_t	Format;
47251881Speter	volatile u_int32_t	LoopDefault;
48251881Speter	volatile u_int32_t	PgBase;
49251881Speter	volatile u_int32_t	PgLoop;
50251881Speter	volatile u_int32_t	PgLoopEnd;
51251881Speter	volatile u_int32_t	PgLoopFrac;
52251881Speter	volatile u_int32_t	PgDeltaEnd;
53251881Speter	volatile u_int32_t	LpfKEnd;
54251881Speter	volatile u_int32_t	EgGainEnd;
55251881Speter	volatile u_int32_t	LchGainEnd;
56251881Speter	volatile u_int32_t	RchGainEnd;
57251881Speter	volatile u_int32_t	Effect1GainEnd;
58251881Speter	volatile u_int32_t	Effect2GainEnd;
59251881Speter	volatile u_int32_t	Effect3GainEnd;
60251881Speter	volatile u_int32_t	LpfQ;
61251881Speter	volatile u_int32_t	Status;
62251881Speter	volatile u_int32_t	NumOfFrames;
63251881Speter	volatile u_int32_t	LoopCount;
64251881Speter	volatile u_int32_t	PgStart;
65251881Speter	volatile u_int32_t	PgStartFrac;
66251881Speter	volatile u_int32_t	PgDelta;
67251881Speter	volatile u_int32_t	LpfK;
68251881Speter	volatile u_int32_t	EgGain;
69251881Speter	volatile u_int32_t	LchGain;
70251881Speter	volatile u_int32_t	RchGain;
71251881Speter	volatile u_int32_t	Effect1Gain;
72251881Speter	volatile u_int32_t	Effect2Gain;
73251881Speter	volatile u_int32_t	Effect3Gain;
74251881Speter	volatile u_int32_t	LpfD1;
75251881Speter	volatile u_int32_t	LpfD2;
76251881Speter};
77251881Speter
78251881Speterstruct rbank {
79251881Speter	volatile u_int32_t	PgBase;
80251881Speter	volatile u_int32_t	PgLoopEnd;
81251881Speter	volatile u_int32_t	PgStart;
82251881Speter	volatile u_int32_t	NumOfLoops;
83251881Speter};
84251881Speter
85251881Speterstruct sc_info;
86251881Speter
87251881Speter/* channel registers */
88251881Speterstruct sc_pchinfo {
89251881Speter	int run, spd, dir, fmt;
90251881Speter	struct snd_dbuf *buffer;
91251881Speter	struct pcm_channel *channel;
92251881Speter	volatile struct pbank *lslot, *rslot;
93251881Speter	int lsnum, rsnum;
94251881Speter	struct sc_info *parent;
95251881Speter};
96251881Speter
97251881Speterstruct sc_rchinfo {
98251881Speter	int run, spd, dir, fmt, num;
99251881Speter	struct snd_dbuf *buffer;
100251881Speter	struct pcm_channel *channel;
101251881Speter	volatile struct rbank *slot;
102251881Speter	struct sc_info *parent;
103251881Speter};
104251881Speter
105251881Speter/* device private data */
106251881Speterstruct sc_info {
107251881Speter	device_t	dev;
108251881Speter	u_int32_t 	type, rev;
109251881Speter	u_int32_t	cd2id, ctrlbase;
110251881Speter
111251881Speter	bus_space_tag_t st;
112251881Speter	bus_space_handle_t sh;
113251881Speter	bus_dma_tag_t buffer_dmat, control_dmat;
114251881Speter	bus_dmamap_t map;
115251881Speter
116251881Speter	struct resource *reg, *irq;
117251881Speter	int		regid, irqid;
118251881Speter	void		*ih;
119251881Speter	struct mtx	*lock;
120251881Speter
121251881Speter	void *regbase;
122251881Speter	u_int32_t *pbase, pbankbase, pbanksize;
123251881Speter	volatile struct pbank *pbank[2 * 64];
124251881Speter	volatile struct rbank *rbank;
125251881Speter	int pslotfree, currbank, pchn, rchn;
126251881Speter	unsigned int bufsz;
127251881Speter
128251881Speter	struct sc_pchinfo pch[DS1_CHANS];
129251881Speter	struct sc_rchinfo rch[2];
130251881Speter};
131251881Speter
132251881Speterstruct {
133251881Speter	u_int32_t dev, subdev;
134251881Speter	char *name;
135251881Speter	u_int32_t *mcode;
136251881Speter} ds_devs[] = {
137251881Speter	{0x00041073, 0, 		"Yamaha DS-1 (YMF724)", CntrlInst},
138251881Speter	{0x000d1073, 0, 		"Yamaha DS-1E (YMF724F)", CntrlInst1E},
139251881Speter	{0x00051073, 0, 		"Yamaha DS-1? (YMF734)", CntrlInst},
140251881Speter	{0x00081073, 0, 		"Yamaha DS-1? (YMF737)", CntrlInst},
141251881Speter	{0x00201073, 0, 		"Yamaha DS-1? (YMF738)", CntrlInst},
142251881Speter	{0x00061073, 0, 		"Yamaha DS-1? (YMF738_TEG)", CntrlInst},
143251881Speter	{0x000a1073, 0x00041073, 	"Yamaha DS-1 (YMF740)", CntrlInst},
144251881Speter	{0x000a1073, 0x000a1073,  	"Yamaha DS-1 (YMF740B)", CntrlInst},
145251881Speter	{0x000a1073, 0x53328086,	"Yamaha DS-1 (YMF740I)", CntrlInst},
146251881Speter	{0x000a1073, 0, 		"Yamaha DS-1 (YMF740?)", CntrlInst},
147251881Speter	{0x000c1073, 0, 		"Yamaha DS-1E (YMF740C)", CntrlInst1E},
148251881Speter	{0x00101073, 0, 		"Yamaha DS-1E (YMF744)", CntrlInst1E},
149251881Speter	{0x00121073, 0, 		"Yamaha DS-1E (YMF754)", CntrlInst1E},
150251881Speter	{0, 0, NULL, NULL}
151251881Speter};
152251881Speter
153251881Speter/* -------------------------------------------------------------------- */
154251881Speter
155251881Speter/*
156251881Speter * prototypes
157251881Speter */
158251881Speter
159251881Speter/* stuff */
160251881Speterstatic int       ds_init(struct sc_info *);
161251881Speterstatic void      ds_intr(void *);
162251881Speter
163251881Speter/* talk to the card */
164251881Speterstatic u_int32_t ds_rd(struct sc_info *, int, int);
165251881Speterstatic void 	 ds_wr(struct sc_info *, int, u_int32_t, int);
166251881Speter
167251881Speter/* -------------------------------------------------------------------- */
168251881Speter
169251881Speterstatic u_int32_t ds_recfmt[] = {
170251881Speter	AFMT_U8,
171251881Speter	AFMT_STEREO | AFMT_U8,
172251881Speter	AFMT_S8,
173251881Speter	AFMT_STEREO | AFMT_S8,
174251881Speter	AFMT_S16_LE,
175251881Speter	AFMT_STEREO | AFMT_S16_LE,
176251881Speter	AFMT_U16_LE,
177251881Speter	AFMT_STEREO | AFMT_U16_LE,
178251881Speter	0
179251881Speter};
180251881Speterstatic struct pcmchan_caps ds_reccaps = {4000, 48000, ds_recfmt, 0};
181251881Speter
182251881Speterstatic u_int32_t ds_playfmt[] = {
183251881Speter	AFMT_U8,
184251881Speter	AFMT_STEREO | AFMT_U8,
185251881Speter	/* AFMT_S16_LE, */
186251881Speter	AFMT_STEREO | AFMT_S16_LE,
187251881Speter	0
188251881Speter};
189251881Speterstatic struct pcmchan_caps ds_playcaps = {4000, 96000, ds_playfmt, 0};
190251881Speter
191251881Speter/* -------------------------------------------------------------------- */
192251881Speter/* Hardware */
193251881Speterstatic u_int32_t
194251881Speterds_rd(struct sc_info *sc, int regno, int size)
195251881Speter{
196251881Speter	switch (size) {
197251881Speter	case 1:
198251881Speter		return bus_space_read_1(sc->st, sc->sh, regno);
199251881Speter	case 2:
200251881Speter		return bus_space_read_2(sc->st, sc->sh, regno);
201251881Speter	case 4:
202251881Speter		return bus_space_read_4(sc->st, sc->sh, regno);
203251881Speter	default:
204251881Speter		return 0xffffffff;
205251881Speter	}
206251881Speter}
207251881Speter
208251881Speterstatic void
209251881Speterds_wr(struct sc_info *sc, int regno, u_int32_t data, int size)
210251881Speter{
211251881Speter	switch (size) {
212251881Speter	case 1:
213251881Speter		bus_space_write_1(sc->st, sc->sh, regno, data);
214251881Speter		break;
215251881Speter	case 2:
216251881Speter		bus_space_write_2(sc->st, sc->sh, regno, data);
217251881Speter		break;
218251881Speter	case 4:
219251881Speter		bus_space_write_4(sc->st, sc->sh, regno, data);
220251881Speter		break;
221251881Speter	}
222251881Speter}
223251881Speter
224251881Speterstatic void
225251881Speterwrl(struct sc_info *sc, u_int32_t *ptr, u_int32_t val)
226251881Speter{
227251881Speter	*(volatile u_int32_t *)ptr = val;
228251881Speter	bus_space_barrier(sc->st, sc->sh, 0, 0, BUS_SPACE_BARRIER_WRITE);
229251881Speter}
230251881Speter
231251881Speter/* -------------------------------------------------------------------- */
232251881Speter/* ac97 codec */
233251881Speterstatic int
234251881Speterds_cdbusy(struct sc_info *sc, int sec)
235251881Speter{
236251881Speter	int i, reg;
237251881Speter
238251881Speter	reg = sec? YDSXGR_SECSTATUSADR : YDSXGR_PRISTATUSADR;
239251881Speter	i = YDSXG_AC97TIMEOUT;
240251881Speter	while (i > 0) {
241251881Speter		if (!(ds_rd(sc, reg, 2) & 0x8000))
242251881Speter			return 0;
243251881Speter		i--;
244251881Speter	}
245251881Speter	return ETIMEDOUT;
246251881Speter}
247251881Speter
248251881Speterstatic u_int32_t
249251881Speterds_initcd(kobj_t obj, void *devinfo)
250251881Speter{
251251881Speter	struct sc_info *sc = (struct sc_info *)devinfo;
252251881Speter	u_int32_t x;
253251881Speter
254251881Speter	x = pci_read_config(sc->dev, PCIR_DSXGCTRL, 1);
255251881Speter	if (x & 0x03) {
256251881Speter		pci_write_config(sc->dev, PCIR_DSXGCTRL, x & ~0x03, 1);
257251881Speter		pci_write_config(sc->dev, PCIR_DSXGCTRL, x | 0x03, 1);
258251881Speter		pci_write_config(sc->dev, PCIR_DSXGCTRL, x & ~0x03, 1);
259251881Speter		/*
260251881Speter		 * The YMF740 on some Intel motherboards requires a pretty
261251881Speter		 * hefty delay after this reset for some reason...  Otherwise:
262251881Speter		 * "pcm0: ac97 codec init failed"
263251881Speter		 * Maybe this is needed for all YMF740's?
264251881Speter		 * 400ms and 500ms here seem to work, 300ms does not.
265251881Speter		 *
266251881Speter		 * do it for all chips -cg
267251881Speter		 */
268251881Speter		DELAY(500000);
269251881Speter	}
270251881Speter
271251881Speter	return ds_cdbusy(sc, 0)? 0 : 1;
272251881Speter}
273251881Speter
274251881Speterstatic int
275251881Speterds_rdcd(kobj_t obj, void *devinfo, int regno)
276251881Speter{
277251881Speter	struct sc_info *sc = (struct sc_info *)devinfo;
278251881Speter	int sec, cid, i;
279251881Speter	u_int32_t cmd, reg;
280251881Speter
281251881Speter	sec = regno & 0x100;
282251881Speter	regno &= 0xff;
283251881Speter	cid = sec? (sc->cd2id << 8) : 0;
284251881Speter	reg = sec? YDSXGR_SECSTATUSDATA : YDSXGR_PRISTATUSDATA;
285251881Speter	if (sec && cid == 0)
286251881Speter		return 0xffffffff;
287251881Speter
288251881Speter	cmd = YDSXG_AC97READCMD | cid | regno;
289251881Speter	ds_wr(sc, YDSXGR_AC97CMDADR, cmd, 2);
290251881Speter
291251881Speter	if (ds_cdbusy(sc, sec))
292251881Speter		return 0xffffffff;
293251881Speter
294251881Speter	if (sc->type == 11 && sc->rev < 2)
295251881Speter		for (i = 0; i < 600; i++)
296251881Speter			ds_rd(sc, reg, 2);
297251881Speter
298251881Speter	return ds_rd(sc, reg, 2);
299251881Speter}
300251881Speter
301251881Speterstatic int
302251881Speterds_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data)
303251881Speter{
304251881Speter	struct sc_info *sc = (struct sc_info *)devinfo;
305251881Speter	int sec, cid;
306251881Speter	u_int32_t cmd;
307251881Speter
308251881Speter	sec = regno & 0x100;
309251881Speter	regno &= 0xff;
310251881Speter	cid = sec? (sc->cd2id << 8) : 0;
311251881Speter	if (sec && cid == 0)
312251881Speter		return ENXIO;
313251881Speter
314251881Speter	cmd = YDSXG_AC97WRITECMD | cid | regno;
315251881Speter	cmd <<= 16;
316251881Speter	cmd |= data;
317251881Speter	ds_wr(sc, YDSXGR_AC97CMDDATA, cmd, 4);
318251881Speter
319251881Speter	return ds_cdbusy(sc, sec);
320251881Speter}
321251881Speter
322251881Speterstatic kobj_method_t ds_ac97_methods[] = {
323251881Speter    	KOBJMETHOD(ac97_init,		ds_initcd),
324251881Speter    	KOBJMETHOD(ac97_read,		ds_rdcd),
325251881Speter    	KOBJMETHOD(ac97_write,		ds_wrcd),
326251881Speter	{ 0, 0 }
327251881Speter};
328251881SpeterAC97_DECLARE(ds_ac97);
329251881Speter
330251881Speter/* -------------------------------------------------------------------- */
331251881Speter
332251881Speterstatic void
333251881Speterds_enadsp(struct sc_info *sc, int on)
334251881Speter{
335251881Speter	u_int32_t v, i;
336251881Speter
337251881Speter	v = on? 1 : 0;
338251881Speter	if (on) {
339251881Speter		ds_wr(sc, YDSXGR_CONFIG, 0x00000001, 4);
340251881Speter	} else {
341251881Speter		if (ds_rd(sc, YDSXGR_CONFIG, 4))
342251881Speter			ds_wr(sc, YDSXGR_CONFIG, 0x00000000, 4);
343251881Speter		i = YDSXG_WORKBITTIMEOUT;
344251881Speter		while (i > 0) {
345251881Speter			if (!(ds_rd(sc, YDSXGR_CONFIG, 4) & 0x00000002))
346251881Speter				break;
347251881Speter			i--;
348251881Speter		}
349251881Speter	}
350251881Speter}
351251881Speter
352251881Speterstatic volatile struct pbank *
353251881Speterds_allocpslot(struct sc_info *sc)
354251881Speter{
355251881Speter	int slot;
356251881Speter
357251881Speter	if (sc->pslotfree > 63)
358251881Speter		return NULL;
359251881Speter	slot = sc->pslotfree++;
360251881Speter	return sc->pbank[slot * 2];
361251881Speter}
362251881Speter
363251881Speterstatic int
364251881Speterds_initpbank(volatile struct pbank *pb, int ch, int b16, int stereo, u_int32_t rate, bus_addr_t base, u_int32_t len)
365251881Speter{
366251881Speter	u_int32_t lv[] = {1, 1, 0, 0, 0};
367251881Speter	u_int32_t rv[] = {1, 0, 1, 0, 0};
368251881Speter	u_int32_t e1[] = {0, 0, 0, 0, 0};
369251881Speter	u_int32_t e2[] = {1, 0, 0, 1, 0};
370251881Speter	u_int32_t e3[] = {1, 0, 0, 0, 1};
371251881Speter	int ss, i;
372251881Speter	u_int32_t delta;
373251881Speter
374251881Speter	struct {
375251881Speter		int rate, fK, fQ;
376251881Speter	} speedinfo[] = {
377251881Speter		{  100, 0x00570000, 0x35280000},
378251881Speter		{ 2000, 0x06aa0000, 0x34a70000},
379251881Speter		{ 8000, 0x18b20000, 0x32020000},
380251881Speter		{11025, 0x20930000, 0x31770000},
381251881Speter		{16000, 0x2b9a0000, 0x31390000},
382251881Speter		{22050, 0x35a10000, 0x31c90000},
383251881Speter		{32000, 0x3eaa0000, 0x33d00000},
384251881Speter/*		{44100, 0x04646000, 0x370a0000},
385251881Speter*/		{48000, 0x40000000, 0x40000000},
386251881Speter	};
387251881Speter
388251881Speter	ss = b16? 1 : 0;
389251881Speter	ss += stereo? 1 : 0;
390251881Speter	delta = (65536 * rate) / 48000;
391251881Speter	i = 0;
392251881Speter	while (i < 7 && speedinfo[i].rate < rate)
393251881Speter		i++;
394251881Speter
395251881Speter	pb->Format = stereo? 0x00010000 : 0;
396251881Speter	pb->Format |= b16? 0 : 0x80000000;
397251881Speter	pb->Format |= (stereo && (ch == 2 || ch == 4))? 0x00000001 : 0;
398251881Speter	pb->LoopDefault = 0;
399251881Speter	pb->PgBase = base? base : 0;
400251881Speter	pb->PgLoop = 0;
401251881Speter	pb->PgLoopEnd = len >> ss;
402251881Speter	pb->PgLoopFrac = 0;
403251881Speter	pb->Status = 0;
404251881Speter	pb->NumOfFrames = 0;
405251881Speter	pb->LoopCount = 0;
406251881Speter	pb->PgStart = 0;
407251881Speter	pb->PgStartFrac = 0;
408251881Speter	pb->PgDelta = pb->PgDeltaEnd = delta << 12;
409251881Speter	pb->LpfQ = speedinfo[i].fQ;
410251881Speter	pb->LpfK = pb->LpfKEnd = speedinfo[i].fK;
411251881Speter	pb->LpfD1 = pb->LpfD2 = 0;
412251881Speter	pb->EgGain = pb->EgGainEnd = 0x40000000;
413251881Speter	pb->LchGain = pb->LchGainEnd = lv[ch] * 0x40000000;
414251881Speter	pb->RchGain = pb->RchGainEnd = rv[ch] * 0x40000000;
415251881Speter	pb->Effect1Gain = pb->Effect1GainEnd = e1[ch] * 0x40000000;
416251881Speter	pb->Effect2Gain = pb->Effect2GainEnd = e2[ch] * 0x40000000;
417251881Speter	pb->Effect3Gain = pb->Effect3GainEnd = e3[ch] * 0x40000000;
418251881Speter
419251881Speter	return 0;
420251881Speter}
421251881Speter
422251881Speterstatic void
423251881Speterds_enapslot(struct sc_info *sc, int slot, int go)
424251881Speter{
425251881Speter	wrl(sc, &sc->pbase[slot + 1], go? (sc->pbankbase + 2 * slot * sc->pbanksize) : 0);
426251881Speter	/* printf("pbase[%d] = 0x%x\n", slot + 1, go? (sc->pbankbase + 2 * slot * sc->pbanksize) : 0); */
427251881Speter}
428251881Speter
429251881Speterstatic void
430251881Speterds_setuppch(struct sc_pchinfo *ch)
431251881Speter{
432251881Speter	int stereo, b16, c, sz;
433251881Speter	bus_addr_t addr;
434251881Speter
435251881Speter	stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
436251881Speter	b16 = (ch->fmt & AFMT_16BIT)? 1 : 0;
437251881Speter	c = stereo? 1 : 0;
438251881Speter	addr = sndbuf_getbufaddr(ch->buffer);
439251881Speter	sz = sndbuf_getsize(ch->buffer);
440251881Speter
441251881Speter	ds_initpbank(ch->lslot, c, stereo, b16, ch->spd, addr, sz);
442251881Speter	ds_initpbank(ch->lslot + 1, c, stereo, b16, ch->spd, addr, sz);
443251881Speter	ds_initpbank(ch->rslot, 2, stereo, b16, ch->spd, addr, sz);
444251881Speter	ds_initpbank(ch->rslot + 1, 2, stereo, b16, ch->spd, addr, sz);
445251881Speter}
446251881Speter
447251881Speterstatic void
448251881Speterds_setuprch(struct sc_rchinfo *ch)
449251881Speter{
450251881Speter	struct sc_info *sc = ch->parent;
451251881Speter	int stereo, b16, i, sz, pri;
452251881Speter	u_int32_t x, y;
453251881Speter	bus_addr_t addr;
454251881Speter
455251881Speter	stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
456251881Speter	b16 = (ch->fmt & AFMT_16BIT)? 1 : 0;
457251881Speter	addr = sndbuf_getbufaddr(ch->buffer);
458251881Speter	sz = sndbuf_getsize(ch->buffer);
459251881Speter	pri = (ch->num == DS1_RECPRIMARY)? 1 : 0;
460251881Speter
461251881Speter	for (i = 0; i < 2; i++) {
462251881Speter		ch->slot[i].PgBase = addr;
463251881Speter		ch->slot[i].PgLoopEnd = sz;
464251881Speter		ch->slot[i].PgStart = 0;
465251881Speter		ch->slot[i].NumOfLoops = 0;
466251881Speter	}
467251881Speter	x = (b16? 0x00 : 0x01) | (stereo? 0x02 : 0x00);
468251881Speter	y = (48000 * 4096) / ch->spd;
469251881Speter	y--;
470251881Speter	/* printf("pri = %d, x = %d, y = %d\n", pri, x, y); */
471251881Speter	ds_wr(sc, pri? YDSXGR_ADCFORMAT : YDSXGR_RECFORMAT, x, 4);
472251881Speter	ds_wr(sc, pri? YDSXGR_ADCSLOTSR : YDSXGR_RECSLOTSR, y, 4);
473251881Speter}
474251881Speter
475251881Speter/* -------------------------------------------------------------------- */
476251881Speter/* play channel interface */
477251881Speterstatic void *
478251881Speterds1pchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
479251881Speter{
480251881Speter	struct sc_info *sc = devinfo;
481251881Speter	struct sc_pchinfo *ch;
482251881Speter
483251881Speter	KASSERT(dir == PCMDIR_PLAY, ("ds1pchan_init: bad direction"));
484251881Speter
485251881Speter	ch = &sc->pch[sc->pchn++];
486	ch->buffer = b;
487	ch->parent = sc;
488	ch->channel = c;
489	ch->dir = dir;
490	ch->fmt = AFMT_U8;
491	ch->spd = 8000;
492	ch->run = 0;
493	if (sndbuf_alloc(ch->buffer, sc->buffer_dmat, sc->bufsz) == -1)
494		return NULL;
495	else {
496		ch->lsnum = sc->pslotfree;
497		ch->lslot = ds_allocpslot(sc);
498		ch->rsnum = sc->pslotfree;
499		ch->rslot = ds_allocpslot(sc);
500		ds_setuppch(ch);
501		return ch;
502	}
503}
504
505static int
506ds1pchan_setformat(kobj_t obj, void *data, u_int32_t format)
507{
508	struct sc_pchinfo *ch = data;
509
510	ch->fmt = format;
511
512	return 0;
513}
514
515static int
516ds1pchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
517{
518	struct sc_pchinfo *ch = data;
519
520	ch->spd = speed;
521
522	return speed;
523}
524
525static int
526ds1pchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
527{
528	struct sc_pchinfo *ch = data;
529	int drate;
530
531	/* irq rate is fixed at 187.5hz */
532	drate = ch->spd * sndbuf_getbps(ch->buffer);
533	blocksize = (drate << 8) / DS1_IRQHZ;
534	sndbuf_resize(ch->buffer, DS1_BUFFSIZE / blocksize, blocksize);
535
536	return blocksize;
537}
538
539/* semantic note: must start at beginning of buffer */
540static int
541ds1pchan_trigger(kobj_t obj, void *data, int go)
542{
543	struct sc_pchinfo *ch = data;
544	struct sc_info *sc = ch->parent;
545	int stereo;
546
547	if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
548		return 0;
549	stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
550	if (go == PCMTRIG_START) {
551		ch->run = 1;
552		ds_setuppch(ch);
553		ds_enapslot(sc, ch->lsnum, 1);
554		ds_enapslot(sc, ch->rsnum, stereo);
555		snd_mtxlock(sc->lock);
556		ds_wr(sc, YDSXGR_MODE, 0x00000003, 4);
557		snd_mtxunlock(sc->lock);
558	} else {
559		ch->run = 0;
560		/* ds_setuppch(ch); */
561		ds_enapslot(sc, ch->lsnum, 0);
562		ds_enapslot(sc, ch->rsnum, 0);
563	}
564
565	return 0;
566}
567
568static int
569ds1pchan_getptr(kobj_t obj, void *data)
570{
571	struct sc_pchinfo *ch = data;
572	struct sc_info *sc = ch->parent;
573	volatile struct pbank *bank;
574	int ss;
575	u_int32_t ptr;
576
577	ss = (ch->fmt & AFMT_STEREO)? 1 : 0;
578	ss += (ch->fmt & AFMT_16BIT)? 1 : 0;
579
580	bank = ch->lslot + sc->currbank;
581	/* printf("getptr: %d\n", bank->PgStart << ss); */
582	ptr = bank->PgStart;
583	ptr <<= ss;
584	return ptr;
585}
586
587static struct pcmchan_caps *
588ds1pchan_getcaps(kobj_t obj, void *data)
589{
590	return &ds_playcaps;
591}
592
593static kobj_method_t ds1pchan_methods[] = {
594    	KOBJMETHOD(channel_init,		ds1pchan_init),
595    	KOBJMETHOD(channel_setformat,		ds1pchan_setformat),
596    	KOBJMETHOD(channel_setspeed,		ds1pchan_setspeed),
597    	KOBJMETHOD(channel_setblocksize,	ds1pchan_setblocksize),
598    	KOBJMETHOD(channel_trigger,		ds1pchan_trigger),
599    	KOBJMETHOD(channel_getptr,		ds1pchan_getptr),
600    	KOBJMETHOD(channel_getcaps,		ds1pchan_getcaps),
601	{ 0, 0 }
602};
603CHANNEL_DECLARE(ds1pchan);
604
605/* -------------------------------------------------------------------- */
606/* record channel interface */
607static void *
608ds1rchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
609{
610	struct sc_info *sc = devinfo;
611	struct sc_rchinfo *ch;
612
613	KASSERT(dir == PCMDIR_REC, ("ds1rchan_init: bad direction"));
614
615	ch = &sc->rch[sc->rchn];
616	ch->num = sc->rchn++;
617	ch->buffer = b;
618	ch->parent = sc;
619	ch->channel = c;
620	ch->dir = dir;
621	ch->fmt = AFMT_U8;
622	ch->spd = 8000;
623	if (sndbuf_alloc(ch->buffer, sc->buffer_dmat, sc->bufsz) == -1)
624		return NULL;
625	else {
626		ch->slot = (ch->num == DS1_RECPRIMARY)? sc->rbank + 2: sc->rbank;
627		ds_setuprch(ch);
628		return ch;
629	}
630}
631
632static int
633ds1rchan_setformat(kobj_t obj, void *data, u_int32_t format)
634{
635	struct sc_rchinfo *ch = data;
636
637	ch->fmt = format;
638
639	return 0;
640}
641
642static int
643ds1rchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
644{
645	struct sc_rchinfo *ch = data;
646
647	ch->spd = speed;
648
649	return speed;
650}
651
652static int
653ds1rchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
654{
655	struct sc_rchinfo *ch = data;
656	int drate;
657
658	/* irq rate is fixed at 187.5hz */
659	drate = ch->spd * sndbuf_getbps(ch->buffer);
660	blocksize = (drate << 8) / DS1_IRQHZ;
661	sndbuf_resize(ch->buffer, DS1_BUFFSIZE / blocksize, blocksize);
662
663	return blocksize;
664}
665
666/* semantic note: must start at beginning of buffer */
667static int
668ds1rchan_trigger(kobj_t obj, void *data, int go)
669{
670	struct sc_rchinfo *ch = data;
671	struct sc_info *sc = ch->parent;
672	u_int32_t x;
673
674	if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
675		return 0;
676	if (go == PCMTRIG_START) {
677		ch->run = 1;
678		ds_setuprch(ch);
679		snd_mtxlock(sc->lock);
680		x = ds_rd(sc, YDSXGR_MAPOFREC, 4);
681		x |= (ch->num == DS1_RECPRIMARY)? 0x02 : 0x01;
682		ds_wr(sc, YDSXGR_MAPOFREC, x, 4);
683		ds_wr(sc, YDSXGR_MODE, 0x00000003, 4);
684		snd_mtxunlock(sc->lock);
685	} else {
686		ch->run = 0;
687		snd_mtxlock(sc->lock);
688		x = ds_rd(sc, YDSXGR_MAPOFREC, 4);
689		x &= ~((ch->num == DS1_RECPRIMARY)? 0x02 : 0x01);
690		ds_wr(sc, YDSXGR_MAPOFREC, x, 4);
691		snd_mtxunlock(sc->lock);
692	}
693
694	return 0;
695}
696
697static int
698ds1rchan_getptr(kobj_t obj, void *data)
699{
700	struct sc_rchinfo *ch = data;
701	struct sc_info *sc = ch->parent;
702
703	return ch->slot[sc->currbank].PgStart;
704}
705
706static struct pcmchan_caps *
707ds1rchan_getcaps(kobj_t obj, void *data)
708{
709	return &ds_reccaps;
710}
711
712static kobj_method_t ds1rchan_methods[] = {
713    	KOBJMETHOD(channel_init,		ds1rchan_init),
714    	KOBJMETHOD(channel_setformat,		ds1rchan_setformat),
715    	KOBJMETHOD(channel_setspeed,		ds1rchan_setspeed),
716    	KOBJMETHOD(channel_setblocksize,	ds1rchan_setblocksize),
717    	KOBJMETHOD(channel_trigger,		ds1rchan_trigger),
718    	KOBJMETHOD(channel_getptr,		ds1rchan_getptr),
719    	KOBJMETHOD(channel_getcaps,		ds1rchan_getcaps),
720	{ 0, 0 }
721};
722CHANNEL_DECLARE(ds1rchan);
723
724/* -------------------------------------------------------------------- */
725/* The interrupt handler */
726static void
727ds_intr(void *p)
728{
729	struct sc_info *sc = (struct sc_info *)p;
730	u_int32_t i, x;
731
732	snd_mtxlock(sc->lock);
733	i = ds_rd(sc, YDSXGR_STATUS, 4);
734	if (i & 0x00008000)
735		device_printf(sc->dev, "timeout irq\n");
736	if (i & 0x80008000) {
737		ds_wr(sc, YDSXGR_STATUS, i & 0x80008000, 4);
738		sc->currbank = ds_rd(sc, YDSXGR_CTRLSELECT, 4) & 0x00000001;
739
740		x = 0;
741		for (i = 0; i < DS1_CHANS; i++) {
742			if (sc->pch[i].run) {
743				x = 1;
744				chn_intr(sc->pch[i].channel);
745			}
746		}
747		for (i = 0; i < 2; i++) {
748			if (sc->rch[i].run) {
749				x = 1;
750				chn_intr(sc->rch[i].channel);
751			}
752		}
753		i = ds_rd(sc, YDSXGR_MODE, 4);
754		if (x)
755			ds_wr(sc, YDSXGR_MODE, i | 0x00000002, 4);
756
757	}
758	snd_mtxunlock(sc->lock);
759}
760
761/* -------------------------------------------------------------------- */
762
763/*
764 * Probe and attach the card
765 */
766
767static void
768ds_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
769{
770	struct sc_info *sc = arg;
771
772	sc->ctrlbase = error? 0 : (u_int32_t)segs->ds_addr;
773
774	if (bootverbose) {
775		printf("ds1: setmap (%lx, %lx), nseg=%d, error=%d\n",
776		       (unsigned long)segs->ds_addr, (unsigned long)segs->ds_len,
777		       nseg, error);
778	}
779}
780
781static int
782ds_init(struct sc_info *sc)
783{
784	int i;
785	u_int32_t *ci, r, pcs, rcs, ecs, ws, memsz, cb;
786	u_int8_t *t;
787	void *buf;
788
789	ci = ds_devs[sc->type].mcode;
790
791	ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x00000000, 4);
792	ds_enadsp(sc, 0);
793	ds_wr(sc, YDSXGR_MODE, 0x00010000, 4);
794	ds_wr(sc, YDSXGR_MODE, 0x00000000, 4);
795	ds_wr(sc, YDSXGR_MAPOFREC, 0x00000000, 4);
796	ds_wr(sc, YDSXGR_MAPOFEFFECT, 0x00000000, 4);
797	ds_wr(sc, YDSXGR_PLAYCTRLBASE, 0x00000000, 4);
798	ds_wr(sc, YDSXGR_RECCTRLBASE, 0x00000000, 4);
799	ds_wr(sc, YDSXGR_EFFCTRLBASE, 0x00000000, 4);
800	r = ds_rd(sc, YDSXGR_GLOBALCTRL, 2);
801	ds_wr(sc, YDSXGR_GLOBALCTRL, r & ~0x0007, 2);
802
803	for (i = 0; i < YDSXG_DSPLENGTH; i += 4)
804		ds_wr(sc, YDSXGR_DSPINSTRAM + i, DspInst[i >> 2], 4);
805
806	for (i = 0; i < YDSXG_CTRLLENGTH; i += 4)
807		ds_wr(sc, YDSXGR_CTRLINSTRAM + i, ci[i >> 2], 4);
808
809	ds_enadsp(sc, 1);
810
811	pcs = 0;
812	for (i = 100; i > 0; i--) {
813		pcs = ds_rd(sc, YDSXGR_PLAYCTRLSIZE, 4) << 2;
814		if (pcs == sizeof(struct pbank))
815			break;
816		DELAY(1000);
817	}
818	if (pcs != sizeof(struct pbank)) {
819		device_printf(sc->dev, "preposterous playctrlsize (%d)\n", pcs);
820		return -1;
821	}
822	rcs = ds_rd(sc, YDSXGR_RECCTRLSIZE, 4) << 2;
823	ecs = ds_rd(sc, YDSXGR_EFFCTRLSIZE, 4) << 2;
824	ws = ds_rd(sc, YDSXGR_WORKSIZE, 4) << 2;
825
826	memsz = 64 * 2 * pcs + 2 * 2 * rcs + 5 * 2 * ecs + ws;
827	memsz += (64 + 1) * 4;
828
829	if (sc->regbase == NULL) {
830		if (bus_dma_tag_create(NULL, 2, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
831				       NULL, NULL, memsz, 1, 1, 0, &sc->control_dmat))
832			return -1;
833		if (bus_dmamem_alloc(sc->control_dmat, &buf, BUS_DMA_NOWAIT, &sc->map))
834			return -1;
835		if (bus_dmamap_load(sc->control_dmat, sc->map, buf, memsz, ds_setmap, sc, 0) || !sc->ctrlbase) {
836			device_printf(sc->dev, "pcs=%d, rcs=%d, ecs=%d, ws=%d, memsz=%d\n",
837			      	      pcs, rcs, ecs, ws, memsz);
838			return -1;
839		}
840		sc->regbase = buf;
841	} else
842		buf = sc->regbase;
843
844	cb = 0;
845	t = buf;
846	ds_wr(sc, YDSXGR_WORKBASE, sc->ctrlbase + cb, 4);
847	cb += ws;
848	sc->pbase = (u_int32_t *)(t + cb);
849	/* printf("pbase = %p -> 0x%x\n", sc->pbase, sc->ctrlbase + cb); */
850	ds_wr(sc, YDSXGR_PLAYCTRLBASE, sc->ctrlbase + cb, 4);
851	cb += (64 + 1) * 4;
852	sc->rbank = (struct rbank *)(t + cb);
853	ds_wr(sc, YDSXGR_RECCTRLBASE, sc->ctrlbase + cb, 4);
854	cb += 2 * 2 * rcs;
855	ds_wr(sc, YDSXGR_EFFCTRLBASE, sc->ctrlbase + cb, 4);
856	cb += 5 * 2 * ecs;
857
858	sc->pbankbase = sc->ctrlbase + cb;
859	sc->pbanksize = pcs;
860	for (i = 0; i < 64; i++) {
861		wrl(sc, &sc->pbase[i + 1], 0);
862		sc->pbank[i * 2] = (struct pbank *)(t + cb);
863		/* printf("pbank[%d] = %p -> 0x%x; ", i * 2, (struct pbank *)(t + cb), sc->ctrlbase + cb - vtophys(t + cb)); */
864		cb += pcs;
865		sc->pbank[i * 2 + 1] = (struct pbank *)(t + cb);
866		/* printf("pbank[%d] = %p -> 0x%x\n", i * 2 + 1, (struct pbank *)(t + cb), sc->ctrlbase + cb - vtophys(t + cb)); */
867		cb += pcs;
868	}
869	wrl(sc, &sc->pbase[0], DS1_CHANS * 2);
870
871	sc->pchn = sc->rchn = 0;
872	ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff, 4);
873	ds_wr(sc, YDSXGR_NATIVEADCINVOL, 0x3fff3fff, 4);
874	ds_wr(sc, YDSXGR_NATIVEDACINVOL, 0x3fff3fff, 4);
875
876	return 0;
877}
878
879static int
880ds_uninit(struct sc_info *sc)
881{
882	ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x00000000, 4);
883	ds_wr(sc, YDSXGR_NATIVEADCINVOL, 0, 4);
884	ds_wr(sc, YDSXGR_NATIVEDACINVOL, 0, 4);
885	ds_enadsp(sc, 0);
886	ds_wr(sc, YDSXGR_MODE, 0x00010000, 4);
887	ds_wr(sc, YDSXGR_MAPOFREC, 0x00000000, 4);
888	ds_wr(sc, YDSXGR_MAPOFEFFECT, 0x00000000, 4);
889	ds_wr(sc, YDSXGR_PLAYCTRLBASE, 0x00000000, 4);
890	ds_wr(sc, YDSXGR_RECCTRLBASE, 0x00000000, 4);
891	ds_wr(sc, YDSXGR_EFFCTRLBASE, 0x00000000, 4);
892	ds_wr(sc, YDSXGR_GLOBALCTRL, 0, 2);
893
894	bus_dmamap_unload(sc->control_dmat, sc->map);
895	bus_dmamem_free(sc->control_dmat, sc->regbase, sc->map);
896
897	return 0;
898}
899
900static int
901ds_finddev(u_int32_t dev, u_int32_t subdev)
902{
903	int i;
904
905	for (i = 0; ds_devs[i].dev; i++) {
906		if (ds_devs[i].dev == dev &&
907		    (ds_devs[i].subdev == subdev || ds_devs[i].subdev == 0))
908			return i;
909	}
910	return -1;
911}
912
913static int
914ds_pci_probe(device_t dev)
915{
916	int i;
917	u_int32_t subdev;
918
919	subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev);
920	i = ds_finddev(pci_get_devid(dev), subdev);
921	if (i >= 0) {
922		device_set_desc(dev, ds_devs[i].name);
923		return 0;
924	} else
925		return ENXIO;
926}
927
928static int
929ds_pci_attach(device_t dev)
930{
931	u_int32_t	data;
932	u_int32_t subdev, i;
933	struct sc_info *sc;
934	struct ac97_info *codec = NULL;
935	char 		status[SND_STATUSLEN];
936
937	if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO)) == NULL) {
938		device_printf(dev, "cannot allocate softc\n");
939		return ENXIO;
940	}
941
942	sc->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc");
943	sc->dev = dev;
944	subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev);
945	sc->type = ds_finddev(pci_get_devid(dev), subdev);
946	sc->rev = pci_get_revid(dev);
947
948	data = pci_read_config(dev, PCIR_COMMAND, 2);
949	data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
950	pci_write_config(dev, PCIR_COMMAND, data, 2);
951	data = pci_read_config(dev, PCIR_COMMAND, 2);
952
953	sc->regid = PCIR_MAPS;
954	sc->reg = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->regid,
955					     0, ~0, 1, RF_ACTIVE);
956	if (!sc->reg) {
957		device_printf(dev, "unable to map register space\n");
958		goto bad;
959	}
960
961	sc->st = rman_get_bustag(sc->reg);
962	sc->sh = rman_get_bushandle(sc->reg);
963
964	sc->bufsz = pcm_getbuffersize(dev, 4096, DS1_BUFFSIZE, 65536);
965
966	if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
967		/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
968		/*highaddr*/BUS_SPACE_MAXADDR,
969		/*filter*/NULL, /*filterarg*/NULL,
970		/*maxsize*/sc->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff,
971		/*flags*/0, &sc->buffer_dmat) != 0) {
972		device_printf(dev, "unable to create dma tag\n");
973		goto bad;
974	}
975
976	sc->regbase = NULL;
977	if (ds_init(sc) == -1) {
978		device_printf(dev, "unable to initialize the card\n");
979		goto bad;
980	}
981
982	codec = AC97_CREATE(dev, sc, ds_ac97);
983	if (codec == NULL)
984		goto bad;
985	mixer_init(dev, ac97_getmixerclass(), codec);
986
987	sc->irqid = 0;
988	sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irqid,
989				 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
990	if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, ds_intr, sc, &sc->ih)) {
991		device_printf(dev, "unable to map interrupt\n");
992		goto bad;
993	}
994
995	snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld",
996		 rman_get_start(sc->reg), rman_get_start(sc->irq));
997
998	if (pcm_register(dev, sc, DS1_CHANS, 2))
999		goto bad;
1000	for (i = 0; i < DS1_CHANS; i++)
1001		pcm_addchan(dev, PCMDIR_PLAY, &ds1pchan_class, sc);
1002	for (i = 0; i < 2; i++)
1003		pcm_addchan(dev, PCMDIR_REC, &ds1rchan_class, sc);
1004	pcm_setstatus(dev, status);
1005
1006	return 0;
1007
1008bad:
1009	if (codec)
1010		ac97_destroy(codec);
1011	if (sc->reg)
1012		bus_release_resource(dev, SYS_RES_MEMORY, sc->regid, sc->reg);
1013	if (sc->ih)
1014		bus_teardown_intr(dev, sc->irq, sc->ih);
1015	if (sc->irq)
1016		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
1017	if (sc->buffer_dmat)
1018		bus_dma_tag_destroy(sc->buffer_dmat);
1019	if (sc->control_dmat)
1020		bus_dma_tag_destroy(sc->control_dmat);
1021	if (sc->lock)
1022		snd_mtxfree(sc->lock);
1023	free(sc, M_DEVBUF);
1024	return ENXIO;
1025}
1026
1027static int
1028ds_pci_resume(device_t dev)
1029{
1030       struct sc_info *sc;
1031
1032       sc = pcm_getdevinfo(dev);
1033
1034       if (ds_init(sc) == -1) {
1035           device_printf(dev, "unable to reinitialize the card\n");
1036           return ENXIO;
1037       }
1038       if (mixer_reinit(dev) == -1) {
1039               device_printf(dev, "unable to reinitialize the mixer\n");
1040               return ENXIO;
1041       }
1042       return 0;
1043}
1044
1045static int
1046ds_pci_detach(device_t dev)
1047{
1048    	int r;
1049	struct sc_info *sc;
1050
1051	r = pcm_unregister(dev);
1052	if (r)
1053    		return r;
1054
1055	sc = pcm_getdevinfo(dev);
1056	ds_uninit(sc);
1057	bus_release_resource(dev, SYS_RES_MEMORY, sc->regid, sc->reg);
1058	bus_teardown_intr(dev, sc->irq, sc->ih);
1059	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
1060	bus_dma_tag_destroy(sc->buffer_dmat);
1061	bus_dma_tag_destroy(sc->control_dmat);
1062	snd_mtxfree(sc->lock);
1063	free(sc, M_DEVBUF);
1064       	return 0;
1065}
1066
1067static device_method_t ds1_methods[] = {
1068	/* Device interface */
1069	DEVMETHOD(device_probe,		ds_pci_probe),
1070	DEVMETHOD(device_attach,	ds_pci_attach),
1071	DEVMETHOD(device_detach,	ds_pci_detach),
1072	DEVMETHOD(device_resume,        ds_pci_resume),
1073	{ 0, 0 }
1074};
1075
1076static driver_t ds1_driver = {
1077	"pcm",
1078	ds1_methods,
1079	PCM_SOFTC_SIZE,
1080};
1081
1082DRIVER_MODULE(snd_ds1, pci, ds1_driver, pcm_devclass, 0, 0);
1083MODULE_DEPEND(snd_ds1, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
1084MODULE_VERSION(snd_ds1, 1);
1085