xref: /freebsd/sys/dev/sound/pci/t4dwave.c (revision 5521ff5a4d1929056e7ffc982fac3341ca54df7c)
1 /*
2  * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
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$
27  */
28 
29 #include <dev/sound/pcm/sound.h>
30 #include <dev/sound/pcm/ac97.h>
31 #include <dev/sound/pci/t4dwave.h>
32 
33 #include <pci/pcireg.h>
34 #include <pci/pcivar.h>
35 
36 /* -------------------------------------------------------------------- */
37 
38 #define TDX_PCI_ID 	0x20001023
39 #define TNX_PCI_ID 	0x20011023
40 
41 #define TR_BUFFSIZE 	0x1000
42 #define TR_TIMEOUT_CDC	0xffff
43 #define TR_MAXPLAYCH	4
44 
45 struct tr_info;
46 
47 /* channel registers */
48 struct tr_chinfo {
49 	u_int32_t cso, alpha, fms, fmc, ec;
50 	u_int32_t lba;
51 	u_int32_t eso, delta;
52 	u_int32_t rvol, cvol;
53 	u_int32_t gvsel, pan, vol, ctrl;
54 	int index, bufhalf;
55 	struct snd_dbuf *buffer;
56 	struct pcm_channel *channel;
57 	struct tr_info *parent;
58 };
59 
60 struct tr_rchinfo {
61 	u_int32_t delta;
62 	struct snd_dbuf *buffer;
63 	struct pcm_channel *channel;
64 	struct tr_info *parent;
65 };
66 
67 /* device private data */
68 struct tr_info {
69 	u_int32_t type;
70 
71 	bus_space_tag_t st;
72 	bus_space_handle_t sh;
73 	bus_dma_tag_t parent_dmat;
74 
75 	struct resource *reg, *irq;
76 	int		regtype, regid, irqid;
77 	void		*ih;
78 
79 	void *lock;
80 
81 	u_int32_t playchns;
82 	struct tr_chinfo chinfo[TR_MAXPLAYCH];
83 	struct tr_rchinfo recchinfo;
84 };
85 
86 /* -------------------------------------------------------------------- */
87 
88 static u_int32_t tr_recfmt[] = {
89 	AFMT_U8,
90 	AFMT_STEREO | AFMT_U8,
91 	AFMT_S8,
92 	AFMT_STEREO | AFMT_S8,
93 	AFMT_S16_LE,
94 	AFMT_STEREO | AFMT_S16_LE,
95 	AFMT_U16_LE,
96 	AFMT_STEREO | AFMT_U16_LE,
97 	0
98 };
99 static struct pcmchan_caps tr_reccaps = {4000, 48000, tr_recfmt, 0};
100 
101 static u_int32_t tr_playfmt[] = {
102 	AFMT_U8,
103 	AFMT_STEREO | AFMT_U8,
104 	AFMT_S8,
105 	AFMT_STEREO | AFMT_S8,
106 	AFMT_S16_LE,
107 	AFMT_STEREO | AFMT_S16_LE,
108 	AFMT_U16_LE,
109 	AFMT_STEREO | AFMT_U16_LE,
110 	0
111 };
112 static struct pcmchan_caps tr_playcaps = {4000, 48000, tr_playfmt, 0};
113 
114 /* -------------------------------------------------------------------- */
115 
116 /* Hardware */
117 
118 static u_int32_t
119 tr_rd(struct tr_info *tr, int regno, int size)
120 {
121 	switch(size) {
122 	case 1:
123 		return bus_space_read_1(tr->st, tr->sh, regno);
124 	case 2:
125 		return bus_space_read_2(tr->st, tr->sh, regno);
126 	case 4:
127 		return bus_space_read_4(tr->st, tr->sh, regno);
128 	default:
129 		return 0xffffffff;
130 	}
131 }
132 
133 static void
134 tr_wr(struct tr_info *tr, int regno, u_int32_t data, int size)
135 {
136 	switch(size) {
137 	case 1:
138 		bus_space_write_1(tr->st, tr->sh, regno, data);
139 		break;
140 	case 2:
141 		bus_space_write_2(tr->st, tr->sh, regno, data);
142 		break;
143 	case 4:
144 		bus_space_write_4(tr->st, tr->sh, regno, data);
145 		break;
146 	}
147 }
148 
149 /* -------------------------------------------------------------------- */
150 /* ac97 codec */
151 
152 static int
153 tr_rdcd(kobj_t obj, void *devinfo, int regno)
154 {
155 	struct tr_info *tr = (struct tr_info *)devinfo;
156 	int i, j, treg, trw;
157 
158 	switch (tr->type) {
159 	case TDX_PCI_ID:
160 		treg=TDX_REG_CODECRD;
161 		trw=TDX_CDC_RWSTAT;
162 		break;
163 	case TNX_PCI_ID:
164 		treg=(regno & 0x100)? TNX_REG_CODEC2RD : TNX_REG_CODEC1RD;
165 		trw=TNX_CDC_RWSTAT;
166 		break;
167 	default:
168 		printf("!!! tr_rdcd defaulted !!!\n");
169 		return -1;
170 	}
171 
172 	regno &= 0x7f;
173 	snd_mtxlock(tr->lock);
174 	tr_wr(tr, treg, regno | trw, 4);
175 	j=trw;
176 	for (i=TR_TIMEOUT_CDC; (i > 0) && (j & trw); i--) j=tr_rd(tr, treg, 4);
177 	snd_mtxunlock(tr->lock);
178 	if (i == 0) printf("codec timeout during read of register %x\n", regno);
179 	return (j >> TR_CDC_DATA) & 0xffff;
180 }
181 
182 static int
183 tr_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data)
184 {
185 	struct tr_info *tr = (struct tr_info *)devinfo;
186 	int i, j, treg, trw;
187 
188 	switch (tr->type) {
189 	case TDX_PCI_ID:
190 		treg=TDX_REG_CODECWR;
191 		trw=TDX_CDC_RWSTAT;
192 		break;
193 	case TNX_PCI_ID:
194 		treg=TNX_REG_CODECWR;
195 		trw=TNX_CDC_RWSTAT | ((regno & 0x100)? TNX_CDC_SEC : 0);
196 		break;
197 	default:
198 		printf("!!! tr_wrcd defaulted !!!");
199 		return -1;
200 	}
201 
202 	regno &= 0x7f;
203 #if 0
204 	printf("tr_wrcd: reg %x was %x", regno, tr_rdcd(devinfo, regno));
205 #endif
206 	j=trw;
207 	snd_mtxlock(tr->lock);
208 	for (i=TR_TIMEOUT_CDC; (i>0) && (j & trw); i--) j=tr_rd(tr, treg, 4);
209 	tr_wr(tr, treg, (data << TR_CDC_DATA) | regno | trw, 4);
210 #if 0
211 	printf(" - wrote %x, now %x\n", data, tr_rdcd(devinfo, regno));
212 #endif
213 	snd_mtxunlock(tr->lock);
214 	if (i==0) printf("codec timeout writing %x, data %x\n", regno, data);
215 	return (i > 0)? 0 : -1;
216 }
217 
218 static kobj_method_t tr_ac97_methods[] = {
219     	KOBJMETHOD(ac97_read,		tr_rdcd),
220     	KOBJMETHOD(ac97_write,		tr_wrcd),
221 	{ 0, 0 }
222 };
223 AC97_DECLARE(tr_ac97);
224 
225 /* -------------------------------------------------------------------- */
226 /* playback channel interrupts */
227 
228 #if 0
229 static u_int32_t
230 tr_testint(struct tr_chinfo *ch)
231 {
232 	struct tr_info *tr = ch->parent;
233 	int bank, chan;
234 
235 	bank = (ch->index & 0x20) ? 1 : 0;
236 	chan = ch->index & 0x1f;
237 	return tr_rd(tr, bank? TR_REG_ADDRINTB : TR_REG_ADDRINTA, 4) & (1 << chan);
238 }
239 #endif
240 
241 static void
242 tr_clrint(struct tr_chinfo *ch)
243 {
244 	struct tr_info *tr = ch->parent;
245 	int bank, chan;
246 
247 	bank = (ch->index & 0x20) ? 1 : 0;
248 	chan = ch->index & 0x1f;
249 	tr_wr(tr, bank? TR_REG_ADDRINTB : TR_REG_ADDRINTA, 1 << chan, 4);
250 }
251 
252 static void
253 tr_enaint(struct tr_chinfo *ch, int enable)
254 {
255 	struct tr_info *tr = ch->parent;
256        	u_int32_t i, reg;
257 	int bank, chan;
258 
259 	snd_mtxlock(tr->lock);
260 	bank = (ch->index & 0x20) ? 1 : 0;
261 	chan = ch->index & 0x1f;
262 	reg = bank? TR_REG_INTENB : TR_REG_INTENA;
263 
264 	i = tr_rd(tr, reg, 4);
265 	i &= ~(1 << chan);
266 	i |= (enable? 1 : 0) << chan;
267 
268 	tr_clrint(ch);
269 	tr_wr(tr, reg, i, 4);
270 	snd_mtxunlock(tr->lock);
271 }
272 
273 /* playback channels */
274 
275 static void
276 tr_selch(struct tr_chinfo *ch)
277 {
278 	struct tr_info *tr = ch->parent;
279 	int i;
280 
281 	i = tr_rd(tr, TR_REG_CIR, 4);
282 	i &= ~TR_CIR_MASK;
283 	i |= ch->index & 0x3f;
284 	tr_wr(tr, TR_REG_CIR, i, 4);
285 }
286 
287 static void
288 tr_startch(struct tr_chinfo *ch)
289 {
290 	struct tr_info *tr = ch->parent;
291 	int bank, chan;
292 
293 	bank = (ch->index & 0x20) ? 1 : 0;
294 	chan = ch->index & 0x1f;
295 	tr_wr(tr, bank? TR_REG_STARTB : TR_REG_STARTA, 1 << chan, 4);
296 }
297 
298 static void
299 tr_stopch(struct tr_chinfo *ch)
300 {
301 	struct tr_info *tr = ch->parent;
302 	int bank, chan;
303 
304 	bank = (ch->index & 0x20) ? 1 : 0;
305 	chan = ch->index & 0x1f;
306 	tr_wr(tr, bank? TR_REG_STOPB : TR_REG_STOPA, 1 << chan, 4);
307 }
308 
309 static void
310 tr_wrch(struct tr_chinfo *ch)
311 {
312 	struct tr_info *tr = ch->parent;
313 	u_int32_t cr[TR_CHN_REGS], i;
314 
315 	ch->gvsel 	&= 0x00000001;
316 	ch->fmc		&= 0x00000003;
317 	ch->fms		&= 0x0000000f;
318 	ch->ctrl	&= 0x0000000f;
319 	ch->pan 	&= 0x0000007f;
320 	ch->rvol	&= 0x0000007f;
321 	ch->cvol 	&= 0x0000007f;
322 	ch->vol		&= 0x000000ff;
323 	ch->ec		&= 0x00000fff;
324 	ch->alpha	&= 0x00000fff;
325 	ch->delta	&= 0x0000ffff;
326 	ch->lba		&= 0x3fffffff;
327 
328 	cr[1]=ch->lba;
329 	cr[3]=(ch->fmc<<14) | (ch->rvol<<7) | (ch->cvol);
330 	cr[4]=(ch->gvsel<<31) | (ch->pan<<24) | (ch->vol<<16) | (ch->ctrl<<12) | (ch->ec);
331 
332 	switch (tr->type) {
333 	case TDX_PCI_ID:
334 		ch->cso &= 0x0000ffff;
335 		ch->eso &= 0x0000ffff;
336 		cr[0]=(ch->cso<<16) | (ch->alpha<<4) | (ch->fms);
337 		cr[2]=(ch->eso<<16) | (ch->delta);
338 		break;
339 	case TNX_PCI_ID:
340 		ch->cso &= 0x00ffffff;
341 		ch->eso &= 0x00ffffff;
342 		cr[0]=((ch->delta & 0xff)<<24) | (ch->cso);
343 		cr[2]=((ch->delta>>16)<<24) | (ch->eso);
344 		cr[3]|=(ch->alpha<<20) | (ch->fms<<16) | (ch->fmc<<14);
345 		break;
346 	}
347 	snd_mtxlock(tr->lock);
348 	tr_selch(ch);
349 	for (i=0; i<TR_CHN_REGS; i++)
350 		tr_wr(tr, TR_REG_CHNBASE+(i<<2), cr[i], 4);
351 	snd_mtxunlock(tr->lock);
352 }
353 
354 static void
355 tr_rdch(struct tr_chinfo *ch)
356 {
357 	struct tr_info *tr = ch->parent;
358 	u_int32_t cr[5], i;
359 
360 	snd_mtxlock(tr->lock);
361 	tr_selch(ch);
362 	for (i=0; i<5; i++)
363 		cr[i]=tr_rd(tr, TR_REG_CHNBASE+(i<<2), 4);
364 	snd_mtxunlock(tr->lock);
365 
366 
367 	ch->lba=	(cr[1] & 0x3fffffff);
368 	ch->fmc=	(cr[3] & 0x0000c000) >> 14;
369 	ch->rvol=	(cr[3] & 0x00003f80) >> 7;
370 	ch->cvol=	(cr[3] & 0x0000007f);
371 	ch->gvsel=	(cr[4] & 0x80000000) >> 31;
372 	ch->pan=	(cr[4] & 0x7f000000) >> 24;
373 	ch->vol=	(cr[4] & 0x00ff0000) >> 16;
374 	ch->ctrl=	(cr[4] & 0x0000f000) >> 12;
375 	ch->ec=		(cr[4] & 0x00000fff);
376 	switch(tr->type) {
377 	case TDX_PCI_ID:
378 		ch->cso=	(cr[0] & 0xffff0000) >> 16;
379 		ch->alpha=	(cr[0] & 0x0000fff0) >> 4;
380 		ch->fms=	(cr[0] & 0x0000000f);
381 		ch->eso=	(cr[2] & 0xffff0000) >> 16;
382 		ch->delta=	(cr[2] & 0x0000ffff);
383 		break;
384 	case TNX_PCI_ID:
385 		ch->cso=	(cr[0] & 0x00ffffff);
386 		ch->eso=	(cr[2] & 0x00ffffff);
387 		ch->delta=	((cr[2] & 0xff000000) >> 16) | ((cr[0] & 0xff000000) >> 24);
388 		ch->alpha=	(cr[3] & 0xfff00000) >> 20;
389 		ch->fms=	(cr[3] & 0x000f0000) >> 16;
390 		break;
391 	}
392 }
393 
394 static u_int32_t
395 tr_fmttobits(u_int32_t fmt)
396 {
397 	u_int32_t bits;
398 
399 	bits = 0;
400 	bits |= (fmt & AFMT_SIGNED)? 0x2 : 0;
401 	bits |= (fmt & AFMT_STEREO)? 0x4 : 0;
402 	bits |= (fmt & AFMT_16BIT)? 0x8 : 0;
403 
404 	return bits;
405 }
406 
407 /* -------------------------------------------------------------------- */
408 /* channel interface */
409 
410 static void *
411 trpchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
412 {
413 	struct tr_info *tr = devinfo;
414 	struct tr_chinfo *ch;
415 
416 	KASSERT(dir == PCMDIR_PLAY, ("trpchan_init: bad direction"));
417 	ch = &tr->chinfo[tr->playchns];
418 	ch->index = tr->playchns++;
419 	ch->buffer = b;
420 	ch->parent = tr;
421 	ch->channel = c;
422 	if (sndbuf_alloc(ch->buffer, tr->parent_dmat, TR_BUFFSIZE) == -1)
423 		return NULL;
424 
425 	return ch;
426 }
427 
428 static int
429 trpchan_setformat(kobj_t obj, void *data, u_int32_t format)
430 {
431 	struct tr_chinfo *ch = data;
432 
433 	ch->ctrl = tr_fmttobits(format) | 0x01;
434 
435 	return 0;
436 }
437 
438 static int
439 trpchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
440 {
441 	struct tr_chinfo *ch = data;
442 
443 	ch->delta = (speed << 12) / 48000;
444 	return (ch->delta * 48000) >> 12;
445 }
446 
447 static int
448 trpchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
449 {
450 	struct tr_chinfo *ch = data;
451 
452 	sndbuf_resize(ch->buffer, 2, blocksize);
453 	return blocksize;
454 }
455 
456 static int
457 trpchan_trigger(kobj_t obj, void *data, int go)
458 {
459 	struct tr_chinfo *ch = data;
460 
461 	if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
462 		return 0;
463 
464 	if (go == PCMTRIG_START) {
465 		ch->fmc = 3;
466 		ch->fms = 0;
467 		ch->ec = 0;
468 		ch->alpha = 0;
469 		ch->lba = vtophys(sndbuf_getbuf(ch->buffer));
470 		ch->cso = 0;
471 		ch->eso = (sndbuf_getsize(ch->buffer) / sndbuf_getbps(ch->buffer)) - 1;
472 		ch->rvol = ch->cvol = 0x7f;
473 		ch->gvsel = 0;
474 		ch->pan = 0;
475 		ch->vol = 0;
476 		ch->bufhalf = 0;
477    		tr_wrch(ch);
478 		tr_enaint(ch, 1);
479 		tr_startch(ch);
480 	} else
481 		tr_stopch(ch);
482 
483 	return 0;
484 }
485 
486 static int
487 trpchan_getptr(kobj_t obj, void *data)
488 {
489 	struct tr_chinfo *ch = data;
490 
491 	tr_rdch(ch);
492 	return ch->cso * sndbuf_getbps(ch->buffer);
493 }
494 
495 static struct pcmchan_caps *
496 trpchan_getcaps(kobj_t obj, void *data)
497 {
498 	return &tr_playcaps;
499 }
500 
501 static kobj_method_t trpchan_methods[] = {
502     	KOBJMETHOD(channel_init,		trpchan_init),
503     	KOBJMETHOD(channel_setformat,		trpchan_setformat),
504     	KOBJMETHOD(channel_setspeed,		trpchan_setspeed),
505     	KOBJMETHOD(channel_setblocksize,	trpchan_setblocksize),
506     	KOBJMETHOD(channel_trigger,		trpchan_trigger),
507     	KOBJMETHOD(channel_getptr,		trpchan_getptr),
508     	KOBJMETHOD(channel_getcaps,		trpchan_getcaps),
509 	{ 0, 0 }
510 };
511 CHANNEL_DECLARE(trpchan);
512 
513 /* -------------------------------------------------------------------- */
514 /* rec channel interface */
515 
516 static void *
517 trrchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
518 {
519 	struct tr_info *tr = devinfo;
520 	struct tr_rchinfo *ch;
521 
522 	KASSERT(dir == PCMDIR_REC, ("trrchan_init: bad direction"));
523 	ch = &tr->recchinfo;
524 	ch->buffer = b;
525 	ch->parent = tr;
526 	ch->channel = c;
527 	if (sndbuf_alloc(ch->buffer, tr->parent_dmat, TR_BUFFSIZE) == -1)
528 		return NULL;
529 
530 	return ch;
531 }
532 
533 static int
534 trrchan_setformat(kobj_t obj, void *data, u_int32_t format)
535 {
536 	struct tr_rchinfo *ch = data;
537 	struct tr_info *tr = ch->parent;
538 	u_int32_t i, bits;
539 
540 	bits = tr_fmttobits(format);
541 	/* set # of samples between interrupts */
542 	i = (sndbuf_runsz(ch->buffer) >> ((bits & 0x08)? 1 : 0)) - 1;
543 	tr_wr(tr, TR_REG_SBBL, i | (i << 16), 4);
544 	/* set sample format */
545 	i = 0x18 | (bits << 4);
546 	tr_wr(tr, TR_REG_SBCTRL, i, 1);
547 
548 	return 0;
549 
550 }
551 
552 static int
553 trrchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
554 {
555 	struct tr_rchinfo *ch = data;
556 	struct tr_info *tr = ch->parent;
557 
558 	/* setup speed */
559 	ch->delta = (48000 << 12) / speed;
560 	tr_wr(tr, TR_REG_SBDELTA, ch->delta, 2);
561 
562 	/* return closest possible speed */
563 	return (48000 << 12) / ch->delta;
564 }
565 
566 static int
567 trrchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
568 {
569 	struct tr_rchinfo *ch = data;
570 
571 	sndbuf_resize(ch->buffer, 2, blocksize);
572 
573 	return blocksize;
574 }
575 
576 static int
577 trrchan_trigger(kobj_t obj, void *data, int go)
578 {
579 	struct tr_rchinfo *ch = data;
580 	struct tr_info *tr = ch->parent;
581 	u_int32_t i;
582 
583 	if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
584 		return 0;
585 
586 	if (go == PCMTRIG_START) {
587 		/* set up dma mode regs */
588 		tr_wr(tr, TR_REG_DMAR15, 0, 1);
589 		i = tr_rd(tr, TR_REG_DMAR11, 1) & 0x03;
590 		tr_wr(tr, TR_REG_DMAR11, i | 0x54, 1);
591 		/* set up base address */
592 	   	tr_wr(tr, TR_REG_DMAR0, vtophys(sndbuf_getbuf(ch->buffer)), 4);
593 		/* set up buffer size */
594 		i = tr_rd(tr, TR_REG_DMAR4, 4) & ~0x00ffffff;
595 		tr_wr(tr, TR_REG_DMAR4, i | (sndbuf_runsz(ch->buffer) - 1), 4);
596 		/* start */
597 		tr_wr(tr, TR_REG_SBCTRL, tr_rd(tr, TR_REG_SBCTRL, 1) | 1, 1);
598 	} else
599 		tr_wr(tr, TR_REG_SBCTRL, tr_rd(tr, TR_REG_SBCTRL, 1) & ~7, 1);
600 
601 	/* return 0 if ok */
602 	return 0;
603 }
604 
605 static int
606 trrchan_getptr(kobj_t obj, void *data)
607 {
608  	struct tr_rchinfo *ch = data;
609 	struct tr_info *tr = ch->parent;
610 
611 	/* return current byte offset of channel */
612 	return tr_rd(tr, TR_REG_DMAR0, 4) - vtophys(sndbuf_getbuf(ch->buffer));
613 }
614 
615 static struct pcmchan_caps *
616 trrchan_getcaps(kobj_t obj, void *data)
617 {
618 	return &tr_reccaps;
619 }
620 
621 static kobj_method_t trrchan_methods[] = {
622     	KOBJMETHOD(channel_init,		trrchan_init),
623     	KOBJMETHOD(channel_setformat,		trrchan_setformat),
624     	KOBJMETHOD(channel_setspeed,		trrchan_setspeed),
625     	KOBJMETHOD(channel_setblocksize,	trrchan_setblocksize),
626     	KOBJMETHOD(channel_trigger,		trrchan_trigger),
627     	KOBJMETHOD(channel_getptr,		trrchan_getptr),
628     	KOBJMETHOD(channel_getcaps,		trrchan_getcaps),
629 	{ 0, 0 }
630 };
631 CHANNEL_DECLARE(trrchan);
632 
633 /* -------------------------------------------------------------------- */
634 /* The interrupt handler */
635 
636 static void
637 tr_intr(void *p)
638 {
639 	struct tr_info *tr = (struct tr_info *)p;
640 	struct tr_chinfo *ch;
641 	u_int32_t active, mask, bufhalf, chnum, intsrc;
642 	int tmp;
643 
644 	intsrc = tr_rd(tr, TR_REG_MISCINT, 4);
645 	if (intsrc & TR_INT_ADDR) {
646 		chnum = 0;
647 		while (chnum < 64) {
648 			mask = 0x00000001;
649 			active = tr_rd(tr, (chnum < 32)? TR_REG_ADDRINTA : TR_REG_ADDRINTB, 4);
650 			bufhalf = tr_rd(tr, (chnum < 32)? TR_REG_CSPF_A : TR_REG_CSPF_B, 4);
651 			if (active) {
652 				do {
653 					if (active & mask) {
654 						tmp = (bufhalf & mask)? 1 : 0;
655 						if (chnum < tr->playchns) {
656 							ch = &tr->chinfo[chnum];
657 							/* printf("%d @ %d, ", chnum, trpchan_getptr(NULL, ch)); */
658 							if (ch->bufhalf != tmp) {
659 								chn_intr(ch->channel);
660 								ch->bufhalf = tmp;
661 							}
662 						}
663 					}
664 					chnum++;
665 					mask <<= 1;
666 				} while (chnum & 31);
667 			} else
668 				chnum += 32;
669 
670 			tr_wr(tr, (chnum <= 32)? TR_REG_ADDRINTA : TR_REG_ADDRINTB, active, 4);
671 		}
672 	}
673 	if (intsrc & TR_INT_SB) {
674 		chn_intr(tr->recchinfo.channel);
675 		tr_rd(tr, TR_REG_SBR9, 1);
676 		tr_rd(tr, TR_REG_SBR10, 1);
677 	}
678 }
679 
680 /* -------------------------------------------------------------------- */
681 
682 /*
683  * Probe and attach the card
684  */
685 
686 static int
687 tr_init(struct tr_info *tr)
688 {
689 	if (tr->type == TDX_PCI_ID) {
690 		tr_wr(tr, TDX_REG_CODECST, TDX_CDC_ON, 4);
691 	} else tr_wr(tr, TNX_REG_CODECST, TNX_CDC_ON, 4);
692 
693 	tr_wr(tr, TR_REG_CIR, TR_CIR_MIDENA | TR_CIR_ADDRENA, 4);
694 	tr->playchns = 0;
695 	return 0;
696 }
697 
698 static int
699 tr_pci_probe(device_t dev)
700 {
701 	if (pci_get_devid(dev) == TDX_PCI_ID) {
702 		device_set_desc(dev, "Trident 4DWave DX");
703 		return 0;
704 	}
705 	if (pci_get_devid(dev) == TNX_PCI_ID) {
706 		device_set_desc(dev, "Trident 4DWave NX");
707 		return 0;
708 	}
709 
710 	return ENXIO;
711 }
712 
713 static int
714 tr_pci_attach(device_t dev)
715 {
716 	u_int32_t	data;
717 	struct tr_info *tr;
718 	struct ac97_info *codec = 0;
719 	int		i;
720 	char 		status[SND_STATUSLEN];
721 
722 	if ((tr = malloc(sizeof(*tr), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
723 		device_printf(dev, "cannot allocate softc\n");
724 		return ENXIO;
725 	}
726 
727 	tr->type = pci_get_devid(dev);
728 	tr->lock = snd_mtxcreate(device_get_nameunit(dev));
729 
730 	data = pci_read_config(dev, PCIR_COMMAND, 2);
731 	data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
732 	pci_write_config(dev, PCIR_COMMAND, data, 2);
733 	data = pci_read_config(dev, PCIR_COMMAND, 2);
734 
735 	tr->regid = PCIR_MAPS;
736 	tr->regtype = SYS_RES_IOPORT;
737 	tr->reg = bus_alloc_resource(dev, tr->regtype, &tr->regid, 0, ~0, 1, RF_ACTIVE);
738 	if (tr->reg) {
739 		tr->st = rman_get_bustag(tr->reg);
740 		tr->sh = rman_get_bushandle(tr->reg);
741 	} else {
742 		device_printf(dev, "unable to map register space\n");
743 		goto bad;
744 	}
745 
746 	if (tr_init(tr) == -1) {
747 		device_printf(dev, "unable to initialize the card\n");
748 		goto bad;
749 	}
750 
751 	codec = AC97_CREATE(dev, tr, tr_ac97);
752 	if (codec == NULL) goto bad;
753 	if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) goto bad;
754 
755 	tr->irqid = 0;
756 	tr->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &tr->irqid,
757 				 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
758 	if (!tr->irq || snd_setup_intr(dev, tr->irq, INTR_MPSAFE, tr_intr, tr, &tr->ih)) {
759 		device_printf(dev, "unable to map interrupt\n");
760 		goto bad;
761 	}
762 
763 	if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
764 		/*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
765 		/*highaddr*/BUS_SPACE_MAXADDR,
766 		/*filter*/NULL, /*filterarg*/NULL,
767 		/*maxsize*/TR_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff,
768 		/*flags*/0, &tr->parent_dmat) != 0) {
769 		device_printf(dev, "unable to create dma tag\n");
770 		goto bad;
771 	}
772 
773 	snprintf(status, 64, "at io 0x%lx irq %ld",
774 		 rman_get_start(tr->reg), rman_get_start(tr->irq));
775 
776 	if (pcm_register(dev, tr, TR_MAXPLAYCH, 1)) goto bad;
777 	pcm_addchan(dev, PCMDIR_REC, &trrchan_class, tr);
778 	for (i = 0; i < TR_MAXPLAYCH; i++)
779 		pcm_addchan(dev, PCMDIR_PLAY, &trpchan_class, tr);
780 	pcm_setstatus(dev, status);
781 
782 	return 0;
783 
784 bad:
785 	if (codec) ac97_destroy(codec);
786 	if (tr->reg) bus_release_resource(dev, tr->regtype, tr->regid, tr->reg);
787 	if (tr->ih) bus_teardown_intr(dev, tr->irq, tr->ih);
788 	if (tr->irq) bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq);
789 	if (tr->parent_dmat) bus_dma_tag_destroy(tr->parent_dmat);
790 	if (tr->lock) snd_mtxfree(tr->lock);
791 	free(tr, M_DEVBUF);
792 	return ENXIO;
793 }
794 
795 static int
796 tr_pci_detach(device_t dev)
797 {
798 	int r;
799 	struct tr_info *tr;
800 
801 	r = pcm_unregister(dev);
802 	if (r)
803 		return r;
804 
805 	tr = pcm_getdevinfo(dev);
806 	bus_release_resource(dev, tr->regtype, tr->regid, tr->reg);
807 	bus_teardown_intr(dev, tr->irq, tr->ih);
808 	bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq);
809 	bus_dma_tag_destroy(tr->parent_dmat);
810 	snd_mtxfree(tr->lock);
811 	free(tr, M_DEVBUF);
812 
813 	return 0;
814 }
815 
816 static device_method_t tr_methods[] = {
817 	/* Device interface */
818 	DEVMETHOD(device_probe,		tr_pci_probe),
819 	DEVMETHOD(device_attach,	tr_pci_attach),
820 	DEVMETHOD(device_detach,	tr_pci_detach),
821 
822 	{ 0, 0 }
823 };
824 
825 static driver_t tr_driver = {
826 	"pcm",
827 	tr_methods,
828 	sizeof(struct snddev_info),
829 };
830 
831 DRIVER_MODULE(snd_t4dwave, pci, tr_driver, pcm_devclass, 0, 0);
832 MODULE_DEPEND(snd_t4dwave, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
833 MODULE_VERSION(snd_t4dwave, 1);
834