ds1.c revision 70343
1/*
2 * Copyright (c) 2000 Cameron Grant <cg@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/dev/sound/pci/ds1.c 70343 2000-12-25 01:42:13Z cg $
27 */
28
29#include <dev/sound/pcm/sound.h>
30#include <dev/sound/pcm/ac97.h>
31
32#include <pci/pcireg.h>
33#include <pci/pcivar.h>
34
35#include <dev/sound/pci/ds1.h>
36#include <dev/sound/pci/ds1-fw.h>
37
38/* -------------------------------------------------------------------- */
39
40#define	DS1_CHANS 4
41#define DS1_RECPRIMARY 0
42#define DS1_IRQHZ ((48000 << 8) / 256)
43
44struct pbank {
45	volatile u_int32_t	Format;
46	volatile u_int32_t	LoopDefault;
47	volatile u_int32_t	PgBase;
48	volatile u_int32_t	PgLoop;
49	volatile u_int32_t	PgLoopEnd;
50	volatile u_int32_t	PgLoopFrac;
51	volatile u_int32_t	PgDeltaEnd;
52	volatile u_int32_t	LpfKEnd;
53	volatile u_int32_t	EgGainEnd;
54	volatile u_int32_t	LchGainEnd;
55	volatile u_int32_t	RchGainEnd;
56	volatile u_int32_t	Effect1GainEnd;
57	volatile u_int32_t	Effect2GainEnd;
58	volatile u_int32_t	Effect3GainEnd;
59	volatile u_int32_t	LpfQ;
60	volatile u_int32_t	Status;
61	volatile u_int32_t	NumOfFrames;
62	volatile u_int32_t	LoopCount;
63	volatile u_int32_t	PgStart;
64	volatile u_int32_t	PgStartFrac;
65	volatile u_int32_t	PgDelta;
66	volatile u_int32_t	LpfK;
67	volatile u_int32_t	EgGain;
68	volatile u_int32_t	LchGain;
69	volatile u_int32_t	RchGain;
70	volatile u_int32_t	Effect1Gain;
71	volatile u_int32_t	Effect2Gain;
72	volatile u_int32_t	Effect3Gain;
73	volatile u_int32_t	LpfD1;
74	volatile u_int32_t	LpfD2;
75};
76
77struct rbank {
78	volatile u_int32_t	PgBase;
79	volatile u_int32_t	PgLoopEnd;
80	volatile u_int32_t	PgStart;
81	volatile u_int32_t	NumOfLoops;
82};
83
84struct sc_info;
85
86/* channel registers */
87struct sc_pchinfo {
88	int run, spd, dir, fmt;
89	snd_dbuf *buffer;
90	pcm_channel *channel;
91	volatile struct pbank *lslot, *rslot;
92	int lsnum, rsnum;
93	struct sc_info *parent;
94};
95
96struct sc_rchinfo {
97	int run, spd, dir, fmt, num;
98	snd_dbuf *buffer;
99	pcm_channel *channel;
100	volatile struct rbank *slot;
101	struct sc_info *parent;
102};
103
104/* device private data */
105struct sc_info {
106	device_t	dev;
107	u_int32_t 	type, rev;
108	u_int32_t	cd2id, ctrlbase;
109
110	bus_space_tag_t st;
111	bus_space_handle_t sh;
112	bus_dma_tag_t parent_dmat;
113	bus_dmamap_t map;
114
115	struct resource *reg, *irq;
116	int		regid, irqid;
117	void		*ih;
118
119	void *regbase;
120	u_int32_t *pbase, pbankbase, pbanksize;
121	volatile struct pbank *pbank[2 * 64];
122	volatile struct rbank *rbank;
123	int pslotfree, currbank, pchn, rchn;
124
125	struct sc_pchinfo pch[DS1_CHANS];
126	struct sc_rchinfo rch[2];
127};
128
129struct {
130	u_int32_t dev, subdev;
131	char *name;
132	u_int32_t *mcode;
133} ds_devs[] = {
134	{0x00041073, 0, 		"Yamaha DS-1 (YMF724)", CntrlInst},
135	{0x000d1073, 0, 		"Yamaha DS-1E (YMF724F)", CntrlInst1E},
136	{0x00051073, 0, 		"Yamaha DS-1? (YMF734)", CntrlInst},
137	{0x00081073, 0, 		"Yamaha DS-1? (YMF737)", CntrlInst},
138	{0x00201073, 0, 		"Yamaha DS-1? (YMF738)", CntrlInst},
139	{0x00061073, 0, 		"Yamaha DS-1? (YMF738_TEG)", CntrlInst},
140	{0x000a1073, 0x00041073, 	"Yamaha DS-1 (YMF740)", CntrlInst},
141	{0x000a1073, 0x000a1073,  	"Yamaha DS-1 (YMF740B)", CntrlInst},
142	{0x000a1073, 0x53328086,	"Yamaha DS-1 (YMF740I)", CntrlInst},
143	{0x000a1073, 0, 		"Yamaha DS-1 (YMF740?)", CntrlInst},
144	{0x000c1073, 0, 		"Yamaha DS-1E (YMF740C)", CntrlInst1E},
145	{0x00101073, 0, 		"Yamaha DS-1E (YMF744)", CntrlInst1E},
146	{0x00121073, 0, 		"Yamaha DS-1E (YMF754)", CntrlInst1E},
147	{0, 0, NULL, NULL}
148};
149
150/* -------------------------------------------------------------------- */
151
152/*
153 * prototypes
154 */
155
156/* stuff */
157static int       ds_init(struct sc_info *);
158static void      ds_intr(void *);
159
160/* talk to the card */
161static u_int32_t ds_rd(struct sc_info *, int, int);
162static void 	 ds_wr(struct sc_info *, int, u_int32_t, int);
163
164/* -------------------------------------------------------------------- */
165
166static u_int32_t ds_recfmt[] = {
167	AFMT_U8,
168	AFMT_STEREO | AFMT_U8,
169	AFMT_S8,
170	AFMT_STEREO | AFMT_S8,
171	AFMT_S16_LE,
172	AFMT_STEREO | AFMT_S16_LE,
173	AFMT_U16_LE,
174	AFMT_STEREO | AFMT_U16_LE,
175	0
176};
177static pcmchan_caps ds_reccaps = {4000, 48000, ds_recfmt, 0};
178
179static u_int32_t ds_playfmt[] = {
180	AFMT_U8,
181	AFMT_STEREO | AFMT_U8,
182	/* AFMT_S16_LE, */
183	AFMT_STEREO | AFMT_S16_LE,
184	0
185};
186static pcmchan_caps ds_playcaps = {4000, 96000, ds_playfmt, 0};
187
188/* -------------------------------------------------------------------- */
189/* Hardware */
190static u_int32_t
191ds_rd(struct sc_info *sc, int regno, int size)
192{
193	switch (size) {
194	case 1:
195		return bus_space_read_1(sc->st, sc->sh, regno);
196	case 2:
197		return bus_space_read_2(sc->st, sc->sh, regno);
198	case 4:
199		return bus_space_read_4(sc->st, sc->sh, regno);
200	default:
201		return 0xffffffff;
202	}
203}
204
205static void
206ds_wr(struct sc_info *sc, int regno, u_int32_t data, int size)
207{
208	switch (size) {
209	case 1:
210		bus_space_write_1(sc->st, sc->sh, regno, data);
211		break;
212	case 2:
213		bus_space_write_2(sc->st, sc->sh, regno, data);
214		break;
215	case 4:
216		bus_space_write_4(sc->st, sc->sh, regno, data);
217		break;
218	}
219}
220
221static void
222wrl(struct sc_info *sc, u_int32_t *ptr, u_int32_t val)
223{
224	*(volatile u_int32_t *)ptr = val;
225	bus_space_barrier(sc->st, sc->sh, 0, 0, BUS_SPACE_BARRIER_WRITE);
226}
227
228/* -------------------------------------------------------------------- */
229/* ac97 codec */
230static int
231ds_cdbusy(struct sc_info *sc, int sec)
232{
233	int i, reg;
234
235	reg = sec? YDSXGR_SECSTATUSADR : YDSXGR_PRISTATUSADR;
236	i = YDSXG_AC97TIMEOUT;
237	while (i > 0) {
238		if (!(ds_rd(sc, reg, 2) & 0x8000))
239			return 0;
240		i--;
241	}
242	return ETIMEDOUT;
243}
244
245static u_int32_t
246ds_initcd(kobj_t obj, void *devinfo)
247{
248	struct sc_info *sc = (struct sc_info *)devinfo;
249	u_int32_t x;
250
251	x = pci_read_config(sc->dev, PCIR_DSXGCTRL, 1);
252	if (x & 0x03) {
253		pci_write_config(sc->dev, PCIR_DSXGCTRL, x & ~0x03, 1);
254		pci_write_config(sc->dev, PCIR_DSXGCTRL, x | 0x03, 1);
255		pci_write_config(sc->dev, PCIR_DSXGCTRL, x & ~0x03, 1);
256		/*
257		 * The YMF740 on some Intel motherboards requires a pretty
258		 * hefty delay after this reset for some reason...  Otherwise:
259		 * "pcm0: ac97 codec init failed"
260		 * Maybe this is needed for all YMF740's?
261		 * 400ms and 500ms here seem to work, 300ms does not.
262		 *
263		 * do it for all chips -cg
264		 */
265		DELAY(500000);
266	}
267
268	return ds_cdbusy(sc, 0)? 0 : 1;
269}
270
271static int
272ds_rdcd(kobj_t obj, void *devinfo, int regno)
273{
274	struct sc_info *sc = (struct sc_info *)devinfo;
275	int sec, cid, i;
276	u_int32_t cmd, reg;
277
278	sec = regno & 0x100;
279	regno &= 0xff;
280	cid = sec? (sc->cd2id << 8) : 0;
281	reg = sec? YDSXGR_SECSTATUSDATA : YDSXGR_PRISTATUSDATA;
282	if (sec && cid == 0)
283		return 0xffffffff;
284
285	cmd = YDSXG_AC97READCMD | cid | regno;
286	ds_wr(sc, YDSXGR_AC97CMDADR, cmd, 2);
287
288	if (ds_cdbusy(sc, sec))
289		return 0xffffffff;
290
291	if (sc->type == 11 && sc->rev < 2)
292		for (i = 0; i < 600; i++)
293			ds_rd(sc, reg, 2);
294
295	return ds_rd(sc, reg, 2);
296}
297
298static int
299ds_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data)
300{
301	struct sc_info *sc = (struct sc_info *)devinfo;
302	int sec, cid;
303	u_int32_t cmd;
304
305	sec = regno & 0x100;
306	regno &= 0xff;
307	cid = sec? (sc->cd2id << 8) : 0;
308	if (sec && cid == 0)
309		return ENXIO;
310
311	cmd = YDSXG_AC97WRITECMD | cid | regno;
312	cmd <<= 16;
313	cmd |= data;
314	ds_wr(sc, YDSXGR_AC97CMDDATA, cmd, 4);
315
316	return ds_cdbusy(sc, sec);
317}
318
319static kobj_method_t ds_ac97_methods[] = {
320    	KOBJMETHOD(ac97_init,		ds_initcd),
321    	KOBJMETHOD(ac97_read,		ds_rdcd),
322    	KOBJMETHOD(ac97_write,		ds_wrcd),
323	{ 0, 0 }
324};
325AC97_DECLARE(ds_ac97);
326
327/* -------------------------------------------------------------------- */
328
329static void
330ds_enadsp(struct sc_info *sc, int on)
331{
332	u_int32_t v, i;
333
334	v = on? 1 : 0;
335	if (on) {
336		ds_wr(sc, YDSXGR_CONFIG, 0x00000001, 4);
337	} else {
338		if (ds_rd(sc, YDSXGR_CONFIG, 4))
339			ds_wr(sc, YDSXGR_CONFIG, 0x00000000, 4);
340		i = YDSXG_WORKBITTIMEOUT;
341		while (i > 0) {
342			if (!(ds_rd(sc, YDSXGR_CONFIG, 4) & 0x00000002))
343				break;
344			i--;
345		}
346	}
347}
348
349static volatile struct pbank *
350ds_allocpslot(struct sc_info *sc)
351{
352	int slot;
353
354	if (sc->pslotfree > 63)
355		return NULL;
356	slot = sc->pslotfree++;
357	return sc->pbank[slot * 2];
358}
359
360static int
361ds_initpbank(volatile struct pbank *pb, int ch, int b16, int stereo, u_int32_t rate, void *base, u_int32_t len)
362{
363	u_int32_t lv[] = {1, 1, 0, 0, 0};
364	u_int32_t rv[] = {1, 0, 1, 0, 0};
365	u_int32_t e1[] = {0, 0, 0, 0, 0};
366	u_int32_t e2[] = {1, 0, 0, 1, 0};
367	u_int32_t e3[] = {1, 0, 0, 0, 1};
368	int ss, i;
369	u_int32_t delta;
370
371	struct {
372		int rate, fK, fQ;
373	} speedinfo[] = {
374		{  100, 0x00570000, 0x35280000},
375		{ 2000, 0x06aa0000, 0x34a70000},
376		{ 8000, 0x18b20000, 0x32020000},
377		{11025, 0x20930000, 0x31770000},
378		{16000, 0x2b9a0000, 0x31390000},
379		{22050, 0x35a10000, 0x31c90000},
380		{32000, 0x3eaa0000, 0x33d00000},
381/*		{44100, 0x04646000, 0x370a0000},
382*/		{48000, 0x40000000, 0x40000000},
383	};
384
385	ss = b16? 1 : 0;
386	ss += stereo? 1 : 0;
387	delta = (65536 * rate) / 48000;
388	i = 0;
389	while (i < 7 && speedinfo[i].rate < rate)
390		i++;
391
392	pb->Format = stereo? 0x00010000 : 0;
393	pb->Format |= b16? 0 : 0x80000000;
394	pb->Format |= (stereo && (ch == 2 || ch == 4))? 0x00000001 : 0;
395	pb->LoopDefault = 0;
396	pb->PgBase = base? vtophys(base) : 0;
397	pb->PgLoop = 0;
398	pb->PgLoopEnd = len >> ss;
399	pb->PgLoopFrac = 0;
400	pb->Status = 0;
401	pb->NumOfFrames = 0;
402	pb->LoopCount = 0;
403	pb->PgStart = 0;
404	pb->PgStartFrac = 0;
405	pb->PgDelta = pb->PgDeltaEnd = delta << 12;
406	pb->LpfQ = speedinfo[i].fQ;
407	pb->LpfK = pb->LpfKEnd = speedinfo[i].fK;
408	pb->LpfD1 = pb->LpfD2 = 0;
409	pb->EgGain = pb->EgGainEnd = 0x40000000;
410	pb->LchGain = pb->LchGainEnd = lv[ch] * 0x40000000;
411	pb->RchGain = pb->RchGainEnd = rv[ch] * 0x40000000;
412	pb->Effect1Gain = pb->Effect1GainEnd = e1[ch] * 0x40000000;
413	pb->Effect2Gain = pb->Effect2GainEnd = e2[ch] * 0x40000000;
414	pb->Effect3Gain = pb->Effect3GainEnd = e3[ch] * 0x40000000;
415
416	return 0;
417}
418
419static void
420ds_enapslot(struct sc_info *sc, int slot, int go)
421{
422	wrl(sc, &sc->pbase[slot + 1], go? (sc->pbankbase + 2 * slot * sc->pbanksize) : 0);
423	/* printf("pbase[%d] = 0x%x\n", slot + 1, go? (sc->pbankbase + 2 * slot * sc->pbanksize) : 0); */
424}
425
426static void
427ds_setuppch(struct sc_pchinfo *ch)
428{
429	int stereo, b16, c, sz;
430	void *buf;
431
432	stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
433	b16 = (ch->fmt & AFMT_16BIT)? 1 : 0;
434	c = stereo? 1 : 0;
435	buf = sndbuf_getbuf(ch->buffer);
436	sz = sndbuf_getsize(ch->buffer);
437
438	ds_initpbank(ch->lslot, c, stereo, b16, ch->spd, buf, sz);
439	ds_initpbank(ch->lslot + 1, c, stereo, b16, ch->spd, buf, sz);
440	ds_initpbank(ch->rslot, 2, stereo, b16, ch->spd, buf, sz);
441	ds_initpbank(ch->rslot + 1, 2, stereo, b16, ch->spd, buf, sz);
442}
443
444static void
445ds_setuprch(struct sc_rchinfo *ch)
446{
447	struct sc_info *sc = ch->parent;
448	int stereo, b16, i, sz, pri;
449	u_int32_t x, y;
450	void *buf;
451
452	stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
453	b16 = (ch->fmt & AFMT_16BIT)? 1 : 0;
454	buf = sndbuf_getbuf(ch->buffer);
455	sz = sndbuf_getsize(ch->buffer);
456	pri = (ch->num == DS1_RECPRIMARY)? 1 : 0;
457
458	for (i = 0; i < 2; i++) {
459		ch->slot[i].PgBase = vtophys(buf);
460		ch->slot[i].PgLoopEnd = sz;
461		ch->slot[i].PgStart = 0;
462		ch->slot[i].NumOfLoops = 0;
463	}
464	x = (b16? 0x00 : 0x01) | (stereo? 0x02 : 0x00);
465	y = (48000 * 4096) / ch->spd;
466	y--;
467	/* printf("pri = %d, x = %d, y = %d\n", pri, x, y); */
468	ds_wr(sc, pri? YDSXGR_ADCFORMAT : YDSXGR_RECFORMAT, x, 4);
469	ds_wr(sc, pri? YDSXGR_ADCSLOTSR : YDSXGR_RECSLOTSR, y, 4);
470}
471
472/* -------------------------------------------------------------------- */
473/* play channel interface */
474static void *
475ds1pchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
476{
477	struct sc_info *sc = devinfo;
478	struct sc_pchinfo *ch;
479
480	KASSERT(dir == PCMDIR_PLAY, ("ds1pchan_init: bad direction"));
481
482	ch = &sc->pch[sc->pchn++];
483	ch->buffer = b;
484	ch->parent = sc;
485	ch->channel = c;
486	ch->dir = dir;
487	ch->fmt = AFMT_U8;
488	ch->spd = 8000;
489	ch->run = 0;
490	if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 4096) == -1)
491		return NULL;
492	else {
493		ch->lsnum = sc->pslotfree;
494		ch->lslot = ds_allocpslot(sc);
495		ch->rsnum = sc->pslotfree;
496		ch->rslot = ds_allocpslot(sc);
497		ds_setuppch(ch);
498		return ch;
499	}
500}
501
502static int
503ds1pchan_setformat(kobj_t obj, void *data, u_int32_t format)
504{
505	struct sc_pchinfo *ch = data;
506
507	ch->fmt = format;
508
509	return 0;
510}
511
512static int
513ds1pchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
514{
515	struct sc_pchinfo *ch = data;
516
517	ch->spd = speed;
518
519	return speed;
520}
521
522static int
523ds1pchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
524{
525	struct sc_pchinfo *ch = data;
526	int drate;
527
528	/* irq rate is fixed at 187.5hz */
529	drate = ch->spd * sndbuf_getbps(ch->buffer);
530	blocksize = (drate << 8) / DS1_IRQHZ;
531	return blocksize;
532}
533
534/* semantic note: must start at beginning of buffer */
535static int
536ds1pchan_trigger(kobj_t obj, void *data, int go)
537{
538	struct sc_pchinfo *ch = data;
539	struct sc_info *sc = ch->parent;
540	int stereo;
541
542	if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
543		return 0;
544	stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
545	if (go == PCMTRIG_START) {
546		ch->run = 1;
547		ds_setuppch(ch);
548		ds_enapslot(sc, ch->lsnum, 1);
549		ds_enapslot(sc, ch->rsnum, stereo);
550		ds_wr(sc, YDSXGR_MODE, 0x00000003, 4);
551	} else {
552		ch->run = 0;
553		/* ds_setuppch(ch); */
554		ds_enapslot(sc, ch->lsnum, 0);
555		ds_enapslot(sc, ch->rsnum, 0);
556	}
557
558	return 0;
559}
560
561static int
562ds1pchan_getptr(kobj_t obj, void *data)
563{
564	struct sc_pchinfo *ch = data;
565	struct sc_info *sc = ch->parent;
566	volatile struct pbank *bank;
567	int ss;
568	u_int32_t ptr;
569
570	ss = (ch->fmt & AFMT_STEREO)? 1 : 0;
571	ss += (ch->fmt & AFMT_16BIT)? 1 : 0;
572
573	bank = ch->lslot + sc->currbank;
574	/* printf("getptr: %d\n", bank->PgStart << ss); */
575	ptr = bank->PgStart;
576	ptr <<= ss;
577	return ptr;
578}
579
580static pcmchan_caps *
581ds1pchan_getcaps(kobj_t obj, void *data)
582{
583	return &ds_playcaps;
584}
585
586static kobj_method_t ds1pchan_methods[] = {
587    	KOBJMETHOD(channel_init,		ds1pchan_init),
588    	KOBJMETHOD(channel_setformat,		ds1pchan_setformat),
589    	KOBJMETHOD(channel_setspeed,		ds1pchan_setspeed),
590    	KOBJMETHOD(channel_setblocksize,	ds1pchan_setblocksize),
591    	KOBJMETHOD(channel_trigger,		ds1pchan_trigger),
592    	KOBJMETHOD(channel_getptr,		ds1pchan_getptr),
593    	KOBJMETHOD(channel_getcaps,		ds1pchan_getcaps),
594	{ 0, 0 }
595};
596CHANNEL_DECLARE(ds1pchan);
597
598/* -------------------------------------------------------------------- */
599/* record channel interface */
600static void *
601ds1rchan_init(kobj_t obj, void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
602{
603	struct sc_info *sc = devinfo;
604	struct sc_rchinfo *ch;
605
606	KASSERT(dir == PCMDIR_REC, ("ds1rchan_init: bad direction"));
607
608	ch = &sc->rch[sc->rchn];
609	ch->num = sc->rchn++;
610	ch->buffer = b;
611	ch->parent = sc;
612	ch->channel = c;
613	ch->dir = dir;
614	ch->fmt = AFMT_U8;
615	ch->spd = 8000;
616	if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 4096) == -1)
617		return NULL;
618	else {
619		ch->slot = (ch->num == DS1_RECPRIMARY)? sc->rbank + 2: sc->rbank;
620		ds_setuprch(ch);
621		return ch;
622	}
623}
624
625static int
626ds1rchan_setformat(kobj_t obj, void *data, u_int32_t format)
627{
628	struct sc_rchinfo *ch = data;
629
630	ch->fmt = format;
631
632	return 0;
633}
634
635static int
636ds1rchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
637{
638	struct sc_rchinfo *ch = data;
639
640	ch->spd = speed;
641
642	return speed;
643}
644
645static int
646ds1rchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
647{
648	return blocksize;
649}
650
651/* semantic note: must start at beginning of buffer */
652static int
653ds1rchan_trigger(kobj_t obj, void *data, int go)
654{
655	struct sc_rchinfo *ch = data;
656	struct sc_info *sc = ch->parent;
657	u_int32_t x;
658
659	if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
660		return 0;
661	if (go == PCMTRIG_START) {
662		ch->run = 1;
663		ds_setuprch(ch);
664		x = ds_rd(sc, YDSXGR_MAPOFREC, 4);
665		x |= (ch->num == DS1_RECPRIMARY)? 0x02 : 0x01;
666		ds_wr(sc, YDSXGR_MAPOFREC, x, 4);
667		ds_wr(sc, YDSXGR_MODE, 0x00000003, 4);
668	} else {
669		ch->run = 0;
670		x = ds_rd(sc, YDSXGR_MAPOFREC, 4);
671		x &= ~((ch->num == DS1_RECPRIMARY)? 0x02 : 0x01);
672		ds_wr(sc, YDSXGR_MAPOFREC, x, 4);
673	}
674
675	return 0;
676}
677
678static int
679ds1rchan_getptr(kobj_t obj, void *data)
680{
681	struct sc_rchinfo *ch = data;
682	struct sc_info *sc = ch->parent;
683
684	return ch->slot[sc->currbank].PgStart;
685}
686
687static pcmchan_caps *
688ds1rchan_getcaps(kobj_t obj, void *data)
689{
690	return &ds_reccaps;
691}
692
693static kobj_method_t ds1rchan_methods[] = {
694    	KOBJMETHOD(channel_init,		ds1rchan_init),
695    	KOBJMETHOD(channel_setformat,		ds1rchan_setformat),
696    	KOBJMETHOD(channel_setspeed,		ds1rchan_setspeed),
697    	KOBJMETHOD(channel_setblocksize,	ds1rchan_setblocksize),
698    	KOBJMETHOD(channel_trigger,		ds1rchan_trigger),
699    	KOBJMETHOD(channel_getptr,		ds1rchan_getptr),
700    	KOBJMETHOD(channel_getcaps,		ds1rchan_getcaps),
701	{ 0, 0 }
702};
703CHANNEL_DECLARE(ds1rchan);
704
705/* -------------------------------------------------------------------- */
706/* The interrupt handler */
707static void
708ds_intr(void *p)
709{
710	struct sc_info *sc = (struct sc_info *)p;
711	u_int32_t i, x;
712
713	i = ds_rd(sc, YDSXGR_STATUS, 4);
714	if (i & 0x00008000)
715		device_printf(sc->dev, "timeout irq\n");
716	if (i & 0x80008000) {
717		ds_wr(sc, YDSXGR_STATUS, i & 0x80008000, 4);
718		sc->currbank = ds_rd(sc, YDSXGR_CTRLSELECT, 4) & 0x00000001;
719
720		x = 0;
721		for (i = 0; i < DS1_CHANS; i++) {
722			if (sc->pch[i].run) {
723				x = 1;
724				chn_intr(sc->pch[i].channel);
725			}
726		}
727		for (i = 0; i < 2; i++) {
728			if (sc->rch[i].run) {
729				x = 1;
730				chn_intr(sc->rch[i].channel);
731			}
732		}
733		i = ds_rd(sc, YDSXGR_MODE, 4);
734		if (x)
735			ds_wr(sc, YDSXGR_MODE, i | 0x00000002, 4);
736
737	}
738}
739
740/* -------------------------------------------------------------------- */
741
742/*
743 * Probe and attach the card
744 */
745
746static void
747ds_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
748{
749	struct sc_info *sc = arg;
750
751	sc->ctrlbase = error? 0 : (u_int32_t)segs->ds_addr;
752
753	if (bootverbose) {
754		printf("ds1: setmap (%lx, %lx), nseg=%d, error=%d\n",
755		       (unsigned long)segs->ds_addr, (unsigned long)segs->ds_len,
756		       nseg, error);
757	}
758}
759
760static int
761ds_init(struct sc_info *sc)
762{
763	int i;
764	u_int32_t *ci, r, pcs, rcs, ecs, ws, memsz, cb;
765	u_int8_t *t;
766	void *buf;
767
768	ci = ds_devs[sc->type].mcode;
769
770	ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x00000000, 4);
771	ds_enadsp(sc, 0);
772	ds_wr(sc, YDSXGR_MODE, 0x00010000, 4);
773	ds_wr(sc, YDSXGR_MODE, 0x00000000, 4);
774	ds_wr(sc, YDSXGR_MAPOFREC, 0x00000000, 4);
775	ds_wr(sc, YDSXGR_MAPOFEFFECT, 0x00000000, 4);
776	ds_wr(sc, YDSXGR_PLAYCTRLBASE, 0x00000000, 4);
777	ds_wr(sc, YDSXGR_RECCTRLBASE, 0x00000000, 4);
778	ds_wr(sc, YDSXGR_EFFCTRLBASE, 0x00000000, 4);
779	r = ds_rd(sc, YDSXGR_GLOBALCTRL, 2);
780	ds_wr(sc, YDSXGR_GLOBALCTRL, r & ~0x0007, 2);
781
782	for (i = 0; i < YDSXG_DSPLENGTH; i += 4)
783		ds_wr(sc, YDSXGR_DSPINSTRAM + i, DspInst[i >> 2], 4);
784
785	for (i = 0; i < YDSXG_CTRLLENGTH; i += 4)
786		ds_wr(sc, YDSXGR_CTRLINSTRAM + i, ci[i >> 2], 4);
787
788	ds_enadsp(sc, 1);
789
790	pcs = 0;
791	for (i = 100; i > 0; i--) {
792		pcs = ds_rd(sc, YDSXGR_PLAYCTRLSIZE, 4) << 2;
793		if (pcs == sizeof(struct pbank))
794			break;
795		DELAY(1000);
796	}
797	if (pcs != sizeof(struct pbank)) {
798		device_printf(sc->dev, "preposterous playctrlsize (%d)\n", pcs);
799		return -1;
800	}
801	rcs = ds_rd(sc, YDSXGR_RECCTRLSIZE, 4) << 2;
802	ecs = ds_rd(sc, YDSXGR_EFFCTRLSIZE, 4) << 2;
803	ws = ds_rd(sc, YDSXGR_WORKSIZE, 4) << 2;
804
805	memsz = 64 * 2 * pcs + 2 * 2 * rcs + 5 * 2 * ecs + ws;
806	memsz += (64 + 1) * 4;
807
808	if (sc->regbase == NULL) {
809		if (bus_dmamem_alloc(sc->parent_dmat, &buf, BUS_DMA_NOWAIT, &sc->map))
810			return -1;
811		if (bus_dmamap_load(sc->parent_dmat, sc->map, buf, memsz, ds_setmap, sc, 0)
812	    	|| !sc->ctrlbase) {
813			device_printf(sc->dev, "pcs=%d, rcs=%d, ecs=%d, ws=%d, memsz=%d\n",
814			      	pcs, rcs, ecs, ws, memsz);
815			return -1;
816		}
817		sc->regbase = buf;
818	} else
819		buf = sc->regbase;
820
821	cb = 0;
822	t = buf;
823	ds_wr(sc, YDSXGR_WORKBASE, sc->ctrlbase + cb, 4);
824	cb += ws;
825	sc->pbase = (u_int32_t *)(t + cb);
826	/* printf("pbase = %p -> 0x%x\n", sc->pbase, sc->ctrlbase + cb); */
827	ds_wr(sc, YDSXGR_PLAYCTRLBASE, sc->ctrlbase + cb, 4);
828	cb += (64 + 1) * 4;
829	sc->rbank = (struct rbank *)(t + cb);
830	ds_wr(sc, YDSXGR_RECCTRLBASE, sc->ctrlbase + cb, 4);
831	cb += 2 * 2 * rcs;
832	ds_wr(sc, YDSXGR_EFFCTRLBASE, sc->ctrlbase + cb, 4);
833	cb += 5 * 2 * ecs;
834
835	sc->pbankbase = sc->ctrlbase + cb;
836	sc->pbanksize = pcs;
837	for (i = 0; i < 64; i++) {
838		wrl(sc, &sc->pbase[i + 1], 0);
839		sc->pbank[i * 2] = (struct pbank *)(t + cb);
840		/* printf("pbank[%d] = %p -> 0x%x; ", i * 2, (struct pbank *)(t + cb), sc->ctrlbase + cb - vtophys(t + cb)); */
841		cb += pcs;
842		sc->pbank[i * 2 + 1] = (struct pbank *)(t + cb);
843		/* printf("pbank[%d] = %p -> 0x%x\n", i * 2 + 1, (struct pbank *)(t + cb), sc->ctrlbase + cb - vtophys(t + cb)); */
844		cb += pcs;
845	}
846	wrl(sc, &sc->pbase[0], DS1_CHANS * 2);
847
848	sc->pchn = sc->rchn = 0;
849	ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff, 4);
850	ds_wr(sc, YDSXGR_NATIVEADCINVOL, 0x3fff3fff, 4);
851	ds_wr(sc, YDSXGR_NATIVEDACINVOL, 0x3fff3fff, 4);
852
853	return 0;
854}
855
856static int
857ds_uninit(struct sc_info *sc)
858{
859	ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x00000000, 4);
860	ds_wr(sc, YDSXGR_NATIVEADCINVOL, 0, 4);
861	ds_wr(sc, YDSXGR_NATIVEDACINVOL, 0, 4);
862	ds_enadsp(sc, 0);
863	ds_wr(sc, YDSXGR_MODE, 0x00010000, 4);
864	ds_wr(sc, YDSXGR_MAPOFREC, 0x00000000, 4);
865	ds_wr(sc, YDSXGR_MAPOFEFFECT, 0x00000000, 4);
866	ds_wr(sc, YDSXGR_PLAYCTRLBASE, 0x00000000, 4);
867	ds_wr(sc, YDSXGR_RECCTRLBASE, 0x00000000, 4);
868	ds_wr(sc, YDSXGR_EFFCTRLBASE, 0x00000000, 4);
869	ds_wr(sc, YDSXGR_GLOBALCTRL, 0, 2);
870
871	bus_dmamap_unload(sc->parent_dmat, sc->map);
872	bus_dmamem_free(sc->parent_dmat, sc->regbase, sc->map);
873
874	return 0;
875}
876
877static int
878ds_finddev(u_int32_t dev, u_int32_t subdev)
879{
880	int i;
881
882	for (i = 0; ds_devs[i].dev; i++) {
883		if (ds_devs[i].dev == dev &&
884		    (ds_devs[i].subdev == subdev || ds_devs[i].subdev == 0))
885			return i;
886	}
887	return -1;
888}
889
890static int
891ds_pci_probe(device_t dev)
892{
893	int i;
894	u_int32_t subdev;
895
896	subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev);
897	i = ds_finddev(pci_get_devid(dev), subdev);
898	if (i >= 0) {
899		device_set_desc(dev, ds_devs[i].name);
900		return 0;
901	} else
902		return ENXIO;
903}
904
905static int
906ds_pci_attach(device_t dev)
907{
908	u_int32_t	data;
909	u_int32_t subdev, i;
910	struct sc_info *sc;
911	struct ac97_info *codec = NULL;
912	char 		status[SND_STATUSLEN];
913
914	if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT)) == NULL) {
915		device_printf(dev, "cannot allocate softc\n");
916		return ENXIO;
917	}
918
919	bzero(sc, sizeof(*sc));
920	sc->dev = dev;
921	subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev);
922	sc->type = ds_finddev(pci_get_devid(dev), subdev);
923	sc->rev = pci_get_revid(dev);
924
925	data = pci_read_config(dev, PCIR_COMMAND, 2);
926	data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
927	pci_write_config(dev, PCIR_COMMAND, data, 2);
928	data = pci_read_config(dev, PCIR_COMMAND, 2);
929
930	sc->regid = PCIR_MAPS;
931	sc->reg = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->regid,
932					     0, ~0, 1, RF_ACTIVE);
933	if (!sc->reg) {
934		device_printf(dev, "unable to map register space\n");
935		goto bad;
936	}
937
938	sc->st = rman_get_bustag(sc->reg);
939	sc->sh = rman_get_bushandle(sc->reg);
940
941	if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
942		/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
943		/*highaddr*/BUS_SPACE_MAXADDR,
944		/*filter*/NULL, /*filterarg*/NULL,
945		/*maxsize*/65536, /*nsegments*/1, /*maxsegz*/0x3ffff,
946		/*flags*/0, &sc->parent_dmat) != 0) {
947		device_printf(dev, "unable to create dma tag\n");
948		goto bad;
949	}
950
951	sc->regbase = NULL;
952	if (ds_init(sc) == -1) {
953		device_printf(dev, "unable to initialize the card\n");
954		goto bad;
955	}
956
957	codec = AC97_CREATE(dev, sc, ds_ac97);
958	if (codec == NULL)
959		goto bad;
960	mixer_init(dev, ac97_getmixerclass(), codec);
961
962	sc->irqid = 0;
963	sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irqid,
964				 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
965	if (!sc->irq ||
966	    bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, ds_intr, sc, &sc->ih)) {
967		device_printf(dev, "unable to map interrupt\n");
968		goto bad;
969	}
970
971	snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld",
972		 rman_get_start(sc->reg), rman_get_start(sc->irq));
973
974	if (pcm_register(dev, sc, DS1_CHANS, 2))
975		goto bad;
976	for (i = 0; i < DS1_CHANS; i++)
977		pcm_addchan(dev, PCMDIR_PLAY, &ds1pchan_class, sc);
978	for (i = 0; i < 2; i++)
979		pcm_addchan(dev, PCMDIR_REC, &ds1rchan_class, sc);
980	pcm_setstatus(dev, status);
981
982	return 0;
983
984bad:
985	if (codec)
986		ac97_destroy(codec);
987	if (sc->reg)
988		bus_release_resource(dev, SYS_RES_MEMORY, sc->regid, sc->reg);
989	if (sc->ih)
990		bus_teardown_intr(dev, sc->irq, sc->ih);
991	if (sc->irq)
992		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
993	if (sc->parent_dmat)
994		bus_dma_tag_destroy(sc->parent_dmat);
995	free(sc, M_DEVBUF);
996	return ENXIO;
997}
998
999static int
1000ds_pci_resume(device_t dev)
1001{
1002       struct sc_info *sc;
1003
1004       sc = pcm_getdevinfo(dev);
1005
1006       if (ds_init(sc) == -1) {
1007           device_printf(dev, "unable to reinitialize the card\n");
1008           return ENXIO;
1009       }
1010       if (mixer_reinit(dev) == -1) {
1011               device_printf(dev, "unable to reinitialize the mixer\n");
1012               return ENXIO;
1013       }
1014       return 0;
1015}
1016
1017static int
1018ds_pci_detach(device_t dev)
1019{
1020    	int r;
1021	struct sc_info *sc;
1022
1023	r = pcm_unregister(dev);
1024	if (r)
1025    		return r;
1026
1027	sc = pcm_getdevinfo(dev);
1028	ds_uninit(sc);
1029	bus_release_resource(dev, SYS_RES_MEMORY, sc->regid, sc->reg);
1030	bus_teardown_intr(dev, sc->irq, sc->ih);
1031	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
1032	bus_dma_tag_destroy(sc->parent_dmat);
1033	free(sc, M_DEVBUF);
1034       	return 0;
1035}
1036
1037static device_method_t ds1_methods[] = {
1038	/* Device interface */
1039	DEVMETHOD(device_probe,		ds_pci_probe),
1040	DEVMETHOD(device_attach,	ds_pci_attach),
1041	DEVMETHOD(device_detach,	ds_pci_detach),
1042	DEVMETHOD(device_resume,        ds_pci_resume),
1043	{ 0, 0 }
1044};
1045
1046static driver_t ds1_driver = {
1047	"pcm",
1048	ds1_methods,
1049	sizeof(snddev_info),
1050};
1051
1052static devclass_t pcm_devclass;
1053
1054DRIVER_MODULE(snd_ds1, pci, ds1_driver, pcm_devclass, 0, 0);
1055MODULE_DEPEND(snd_ds1, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
1056MODULE_VERSION(snd_ds1, 1);
1057