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