Deleted Added
full compact
t4dwave.c (50724) t4dwave.c (50733)
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 *
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 * $Id$
26 * $FreeBSD: head/sys/dev/sound/pci/t4dwave.c 50733 1999-09-01 06:58:27Z peter $
27 */
28
29#include "pci.h"
30#include "pcm.h"
31
32#include <dev/pcm/sound.h>
33#include <dev/pcm/ac97.h>
34#include <dev/pcm/pci/t4dwave.h>
35
36#include <pci/pcireg.h>
37#include <pci/pcivar.h>
38
39#if NPCI != 0
40
41/* -------------------------------------------------------------------- */
42
43struct tr_info;
44
45/* channel registers */
46struct tr_chinfo {
47 u_int32_t cso, alpha, fms, fmc, ec;
48 u_int32_t lba;
49 u_int32_t eso, delta;
50 u_int32_t rvol, cvol;
51 u_int32_t gvsel, pan, vol, ctrl;
52 int index;
53 snd_dbuf *buffer;
54 pcm_channel *channel;
55 struct tr_info *parent;
56};
57
58/* device private data */
59struct tr_info {
60 u_int32_t type;
61
62 bus_space_tag_t st;
63 bus_space_handle_t sh;
64 bus_dma_tag_t parent_dmat;
65
66 struct resource *reg, *irq;
67 int regtype, regid, irqid;
68 void *ih;
69
70 u_int32_t playchns;
71 struct tr_chinfo chinfo[TR_MAXPLAYCH];
72 struct tr_chinfo recchinfo;
73};
74
75/* -------------------------------------------------------------------- */
76
77/*
78 * prototypes
79 */
80
81/* channel interface */
82static void *trchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir);
83static int trchan_setdir(void *data, int dir);
84static int trchan_setformat(void *data, u_int32_t format);
85static int trchan_setspeed(void *data, u_int32_t speed);
86static int trchan_setblocksize(void *data, u_int32_t blocksize);
87static int trchan_trigger(void *data, int go);
88static int trchan_getptr(void *data);
89static pcmchan_caps *trchan_getcaps(void *data);
90
91/* talk to the codec - called from ac97.c */
92static u_int32_t tr_rdcd(void *, int);
93static void tr_wrcd(void *, int, u_int32_t);
94
95/* stuff */
96static int tr_init(struct tr_info *);
97static void tr_intr(void *);
98
99/* talk to the card */
100static u_int32_t tr_rd(struct tr_info *, int, int);
101static void tr_wr(struct tr_info *, int, u_int32_t, int);
102
103/* manipulate playback channels */
104static void tr_clrint(struct tr_info *, char);
105static void tr_enaint(struct tr_info *, char, int);
106static u_int32_t tr_testint(struct tr_info *, char);
107static void tr_rdch(struct tr_info *, char, struct tr_chinfo *);
108static void tr_wrch(struct tr_info *, char, struct tr_chinfo *);
109static void tr_selch(struct tr_info *, char);
110static void tr_startch(struct tr_info *, char);
111static void tr_stopch(struct tr_info *, char);
112
113/* -------------------------------------------------------------------- */
114
115static pcmchan_caps tr_reccaps = {
116 4000, 48000,
117 AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_S16_LE | AFMT_U16_LE,
118 AFMT_STEREO | AFMT_S16_LE
119};
120
121static pcmchan_caps tr_playcaps = {
122 4000, 48000,
123 AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_S16_LE | AFMT_U16_LE,
124 AFMT_U16_LE
125};
126
127static pcm_channel tr_chantemplate = {
128 trchan_init,
129 trchan_setdir,
130 trchan_setformat,
131 trchan_setspeed,
132 trchan_setblocksize,
133 trchan_trigger,
134 trchan_getptr,
135 trchan_getcaps,
136};
137
138/* -------------------------------------------------------------------- */
139
140static u_int32_t
141tr_fmttobits(u_int32_t fmt)
142{
143 u_int32_t bits = 0;
144 bits |= (fmt & AFMT_STEREO)? 0x4 : 0;
145 bits |= (fmt & (AFMT_S8 | AFMT_S16_LE))? 0x2 : 0;
146 bits |= (fmt & (AFMT_S16_LE | AFMT_U16_LE))? 0x8 : 0;
147 return bits;
148}
149
150/* Hardware */
151
152static u_int32_t
153tr_rd(struct tr_info *tr, int regno, int size)
154{
155 switch(size) {
156 case 1:
157 return bus_space_read_1(tr->st, tr->sh, regno);
158 case 2:
159 return bus_space_read_2(tr->st, tr->sh, regno);
160 case 4:
161 return bus_space_read_4(tr->st, tr->sh, regno);
162 default:
163 return 0xffffffff;
164 }
165}
166
167static void
168tr_wr(struct tr_info *tr, int regno, u_int32_t data, int size)
169{
170 switch(size) {
171 case 1:
172 bus_space_write_1(tr->st, tr->sh, regno, data);
173 break;
174 case 2:
175 bus_space_write_2(tr->st, tr->sh, regno, data);
176 break;
177 case 4:
178 bus_space_write_4(tr->st, tr->sh, regno, data);
179 break;
180 }
181}
182
183/* ac97 codec */
184
185static u_int32_t
186tr_rdcd(void *devinfo, int regno)
187{
188 struct tr_info *tr = (struct tr_info *)devinfo;
189 int i, j, treg, trw;
190
191 switch (tr->type) {
192 case TDX_PCI_ID:
193 treg=TDX_REG_CODECRD;
194 trw=TDX_CDC_RWSTAT;
195 break;
196 case TNX_PCI_ID:
197 treg=(regno & 0x100)? TNX_REG_CODEC2RD : TNX_REG_CODEC1RD;
198 trw=TNX_CDC_RWSTAT;
199 break;
200 default:
201 printf("!!! tr_rdcd defaulted !!!\n");
202 return 0xffffffff;
203 }
204
205 regno &= 0x7f;
206 tr_wr(tr, treg, regno | trw, 4);
207 j=trw;
208 for (i=TR_TIMEOUT_CDC; (i > 0) && (j & trw); i--) j=tr_rd(tr, treg, 4);
209 if (i == 0) printf("codec timeout during read of register %x\n", regno);
210 return (j >> TR_CDC_DATA) & 0xffff;
211}
212
213static void
214tr_wrcd(void *devinfo, int regno, u_int32_t data)
215{
216 struct tr_info *tr = (struct tr_info *)devinfo;
217 int i, j, treg, trw;
218
219 switch (tr->type) {
220 case TDX_PCI_ID:
221 treg=TDX_REG_CODECWR;
222 trw=TDX_CDC_RWSTAT;
223 break;
224 case TNX_PCI_ID:
225 treg=TNX_REG_CODECWR;
226 trw=TNX_CDC_RWSTAT | ((regno & 0x100)? TNX_CDC_SEC : 0);
227 break;
228 default:
229 printf("!!! tr_wrcd defaulted !!!");
230 return;
231 }
232
233 regno &= 0x7f;
234#if 0
235 printf("tr_wrcd: reg %x was %x", regno, tr_rdcd(devinfo, regno));
236#endif
237 j=trw;
238 for (i=TR_TIMEOUT_CDC; (i>0) && (j & trw); i--) j=tr_rd(tr, treg, 4);
239 tr_wr(tr, treg, (data << TR_CDC_DATA) | regno | trw, 4);
240#if 0
241 printf(" - wrote %x, now %x\n", data, tr_rdcd(devinfo, regno));
242#endif
243 if (i==0) printf("codec timeout writing %x, data %x\n", regno, data);
244}
245
246/* playback channel interrupts */
247
248static u_int32_t
249tr_testint(struct tr_info *tr, char channel)
250{
251 return tr_rd(tr, (channel & 0x20)? TR_REG_ADDRINTB : TR_REG_ADDRINTA,
252 4) & (1<<(channel & 0x1f));
253}
254
255static void
256tr_clrint(struct tr_info *tr, char channel)
257{
258 tr_wr(tr, (channel & 0x20)? TR_REG_ADDRINTB : TR_REG_ADDRINTA,
259 1<<(channel & 0x1f), 4);
260}
261
262static void
263tr_enaint(struct tr_info *tr, char channel, int enable)
264{
265 u_int32_t reg = (channel & 0x20)? TR_REG_INTENB : TR_REG_INTENA;
266 u_int32_t i = tr_rd(tr, reg, 4);
267 channel &= 0x1f;
268 i &= ~(1 << channel);
269 i |= (enable? 1 : 0) << channel;
270 tr_clrint(tr, channel);
271 tr_wr(tr, reg, i, 4);
272}
273
274/* playback channels */
275
276static void
277tr_selch(struct tr_info *tr, char channel)
278{
279 int i=tr_rd(tr, TR_REG_CIR, 4);
280 i &= ~TR_CIR_MASK;
281 i |= channel & 0x3f;
282 tr_wr(tr, TR_REG_CIR, i, 4);
283}
284
285static void
286tr_startch(struct tr_info *tr, char channel)
287{
288 tr_wr(tr, (channel & 0x20)? TR_REG_STARTB : TR_REG_STARTA,
289 1<<(channel & 0x1f), 4);
290}
291
292static void
293tr_stopch(struct tr_info *tr, char channel)
294{
295 tr_wr(tr, (channel & 0x20)? TR_REG_STOPB : TR_REG_STOPA,
296 1<<(channel & 0x1f), 4);
297}
298
299static void
300tr_wrch(struct tr_info *tr, char channel, struct tr_chinfo *ch)
301{
302 u_int32_t cr[TR_CHN_REGS], i;
303
304 ch->gvsel &= 0x00000001;
305 ch->fmc &= 0x00000003;
306 ch->fms &= 0x0000000f;
307 ch->ctrl &= 0x0000000f;
308 ch->pan &= 0x0000007f;
309 ch->rvol &= 0x0000007f;
310 ch->cvol &= 0x0000007f;
311 ch->vol &= 0x000000ff;
312 ch->ec &= 0x00000fff;
313 ch->alpha &= 0x00000fff;
314 ch->delta &= 0x0000ffff;
315 ch->lba &= 0x3fffffff;
316
317 cr[1]=ch->lba;
318 cr[3]=(ch->rvol<<7) | (ch->cvol);
319 cr[4]=(ch->gvsel<<31)|(ch->pan<<24)|(ch->vol<<16)|(ch->ctrl<<12)|(ch->ec);
320
321 switch (tr->type) {
322 case TDX_PCI_ID:
323 ch->cso &= 0x0000ffff;
324 ch->eso &= 0x0000ffff;
325 cr[0]=(ch->cso<<16) | (ch->alpha<<4) | (ch->fms);
326 cr[2]=(ch->eso<<16) | (ch->delta);
327 cr[3]|=0x0000c000;
328 break;
329 case TNX_PCI_ID:
330 ch->cso &= 0x00ffffff;
331 ch->eso &= 0x00ffffff;
332 cr[0]=((ch->delta & 0xff)<<24) | (ch->cso);
333 cr[2]=((ch->delta>>16)<<24) | (ch->eso);
334 cr[3]|=(ch->alpha<<20) | (ch->fms<<16) | (ch->fmc<<14);
335 break;
336 }
337 tr_selch(tr, channel);
338 for (i=0; i<TR_CHN_REGS; i++)
339 tr_wr(tr, TR_REG_CHNBASE+(i<<2), cr[i], 4);
340}
341
342static void
343tr_rdch(struct tr_info *tr, char channel, struct tr_chinfo *ch)
344{
345 u_int32_t cr[5], i;
346 tr_selch(tr, channel);
347 for (i=0; i<5; i++) cr[i]=tr_rd(tr, TR_REG_CHNBASE+(i<<2), 4);
348 ch->lba= (cr[1] & 0x3fffffff);
349 ch->fmc= (cr[3] & 0x0000c000) >> 14;
350 ch->rvol= (cr[3] & 0x00003f80) >> 7;
351 ch->cvol= (cr[3] & 0x0000007f);
352 ch->gvsel= (cr[4] & 0x80000000) >> 31;
353 ch->pan= (cr[4] & 0x7f000000) >> 24;
354 ch->vol= (cr[4] & 0x00ff0000) >> 16;
355 ch->ctrl= (cr[4] & 0x0000f000) >> 12;
356 ch->ec= (cr[4] & 0x00000fff);
357 switch(tr->type) {
358 case TDX_PCI_ID:
359 ch->cso= (cr[0] & 0xffff0000) >> 16;
360 ch->alpha= (cr[0] & 0x0000fff0) >> 4;
361 ch->fms= (cr[0] & 0x0000000f);
362 ch->eso= (cr[2] & 0xffff0000) >> 16;
363 ch->delta= (cr[2] & 0x0000ffff);
364 break;
365 case TNX_PCI_ID:
366 ch->cso= (cr[0] & 0x00ffffff);
367 ch->eso= (cr[2] & 0x00ffffff);
368 ch->delta= ((cr[2] & 0xff000000) >> 16) |
369 ((cr[0] & 0xff000000) >> 24);
370 ch->alpha= (cr[3] & 0xfff00000) >> 20;
371 ch->fms= (cr[3] & 0x000f0000) >> 16;
372 break;
373 }
374}
375
376/* channel interface */
377
378void *
379trchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
380{
381 struct tr_info *tr = devinfo;
382 struct tr_chinfo *ch;
383 if (dir == PCMDIR_PLAY) {
384 ch = &tr->chinfo[tr->playchns];
385 ch->index = tr->playchns++;
386 } else {
387 ch = &tr->recchinfo;
388 ch->index = -1;
389 }
390 ch->buffer = b;
391 ch->buffer->bufsize = TR_BUFFSIZE;
392 ch->parent = tr;
393 ch->channel = c;
394 if (chn_allocbuf(ch->buffer, tr->parent_dmat) == -1) return NULL;
395 else return ch;
396}
397
398static int
399trchan_setdir(void *data, int dir)
400{
401 struct tr_chinfo *ch = data;
402 struct tr_info *tr = ch->parent;
403 if (dir == PCMDIR_PLAY && ch->index >= 0) {
404 ch->fmc = ch->fms = ch->ec = ch->alpha = 0;
405 ch->lba = vtophys(ch->buffer->buf);
406 ch->cso = 0;
407 ch->eso = ch->buffer->bufsize - 1;
408 ch->rvol = ch->cvol = 0;
409 ch->gvsel = 0;
410 ch->pan = 0;
411 ch->vol = 0;
412 ch->ctrl = 0x01;
413 ch->delta = 0;
414 tr_wrch(tr, ch->index, ch);
415 tr_enaint(tr, ch->index, 1);
416 } else if (dir == PCMDIR_REC && ch->index == -1) {
417 /* set up dma mode regs */
418 u_int32_t i;
419 tr_wr(tr, TR_REG_DMAR15, 0, 1);
420 i = tr_rd(tr, TR_REG_DMAR11, 1) & 0x03;
421 tr_wr(tr, TR_REG_DMAR11, i | 0x54, 1);
422 /* set up base address */
423 tr_wr(tr, TR_REG_DMAR0, vtophys(ch->buffer->buf), 4);
424 /* set up buffer size */
425 i = tr_rd(tr, TR_REG_DMAR4, 4) & ~0x00ffffff;
426 tr_wr(tr, TR_REG_DMAR4, i | (ch->buffer->bufsize - 1), 4);
427 } else return -1;
428 return 0;
429}
430
431static int
432trchan_setformat(void *data, u_int32_t format)
433{
434 struct tr_chinfo *ch = data;
435 struct tr_info *tr = ch->parent;
436 u_int32_t bits = tr_fmttobits(format);
437
438 if (ch->index >= 0) {
439 tr_rdch(tr, ch->index, ch);
440 ch->eso = (ch->buffer->bufsize / ch->buffer->sample_size) - 1;
441 ch->ctrl = bits | 0x01;
442 tr_wrch(tr, ch->index, ch);
443 } else {
444 u_int32_t i;
445 /* set # of samples between interrupts */
446 i = (TR_INTSAMPLES >> ((bits & 0x08)? 1 : 0)) - 1;
447 tr_wr(tr, TR_REG_SBBL, i | (i << 16), 4);
448 /* set sample format */
449 i = 0x18 | (bits << 4);
450 tr_wr(tr, TR_REG_SBCTRL, i, 1);
451 }
452 return 0;
453}
454
455static int
456trchan_setspeed(void *data, u_int32_t speed)
457{
458 struct tr_chinfo *ch = data;
459 struct tr_info *tr = ch->parent;
460
461 if (ch->index >= 0) {
462 tr_rdch(tr, ch->index, ch);
463 ch->delta = (speed << 12) / 48000;
464 tr_wrch(tr, ch->index, ch);
465 return (ch->delta * 48000) >> 12;
466 } else {
467 /* setup speed */
468 ch->delta = (48000 << 12) / speed;
469 tr_wr(tr, TR_REG_SBDELTA, ch->delta, 2);
470 return (48000 << 12) / ch->delta;
471 }
472 return 0;
473}
474
475static int
476trchan_setblocksize(void *data, u_int32_t blocksize)
477{
478 struct tr_chinfo *ch = data;
479 return ch->buffer->bufsize / 2;
480}
481
482static int
483trchan_trigger(void *data, int go)
484{
485 struct tr_chinfo *ch = data;
486 struct tr_info *tr = ch->parent;
487 if (ch->index >= 0) {
488 if (go == PCMTRIG_START) tr_startch(tr, ch->index);
489 else tr_stopch(tr, ch->index);
490 } else {
491 u_int32_t i = tr_rd(tr, TR_REG_SBCTRL, 1) & ~7;
492 tr_wr(tr, TR_REG_SBCTRL, i | (go == PCMTRIG_START)? 1 : 0, 1);
493 }
494 return 0;
495}
496
497static int
498trchan_getptr(void *data)
499{
500 struct tr_chinfo *ch = data;
501 struct tr_info *tr = ch->parent;
502 if (ch->index >= 0) {
503 tr_rdch(tr, ch->index, ch);
504 return ch->cso * ch->buffer->sample_size;
505 } else return tr_rd(tr, TR_REG_DMAR0, 4) - vtophys(ch->buffer->buf);
506}
507
508static pcmchan_caps *
509trchan_getcaps(void *data)
510{
511 struct tr_chinfo *ch = data;
512 return (ch->index >= 0)? &tr_playcaps : &tr_reccaps;
513}
514
515/* The interrupt handler */
516
517static void
518tr_intr(void *p)
519{
520 struct tr_info *tr = (struct tr_info *)p;
521 u_int32_t intsrc = tr_rd(tr, TR_REG_MISCINT, 4);
522
523 if (intsrc & TR_INT_ADDR) {
524 int i;
525 for (i = 0; i < tr->playchns; i++) {
526 if (tr_testint(tr, i)) {
527 chn_intr(tr->chinfo[i].channel);
528 tr_clrint(tr, i);
529 }
530 }
531 }
532 if (intsrc & TR_INT_SB) {
533 chn_intr(tr->recchinfo.channel);
534 tr_rd(tr, TR_REG_SBR9, 1);
535 tr_rd(tr, TR_REG_SBR10, 1);
536 }
537}
538
539/* -------------------------------------------------------------------- */
540
541/*
542 * Probe and attach the card
543 */
544
545static int
546tr_init(struct tr_info *tr)
547{
548 if (tr->type == TDX_PCI_ID) {
549 tr_wr(tr, TDX_REG_CODECST, TDX_CDC_ON, 4);
550 } else tr_wr(tr, TNX_REG_CODECST, TNX_CDC_ON, 4);
551
552 tr_wr(tr, TR_REG_CIR, TR_CIR_MIDENA | TR_CIR_ADDRENA, 4);
553 tr->playchns = 0;
554 return 0;
555}
556
557static int
558tr_pci_probe(device_t dev)
559{
560 if (pci_get_devid(dev) == TDX_PCI_ID) {
561 device_set_desc(dev, "Trident 4DWave DX");
562 return 0;
563 }
564 if (pci_get_devid(dev) == TNX_PCI_ID) {
565 device_set_desc(dev, "Trident 4DWave NX");
566 return 0;
567 }
568
569 return ENXIO;
570}
571
572static int
573tr_pci_attach(device_t dev)
574{
575 snddev_info *d;
576 u_int32_t data;
577 struct tr_info *tr;
578 struct ac97_info *codec;
579 int i;
580 int mapped;
581 char status[SND_STATUSLEN];
582
583 d = device_get_softc(dev);
584 if ((tr = malloc(sizeof(*tr), M_DEVBUF, M_NOWAIT)) == NULL) {
585 device_printf(dev, "cannot allocate softc\n");
586 return ENXIO;
587 }
588
589 bzero(tr, sizeof(*tr));
590 tr->type = pci_get_devid(dev);
591
592 data = pci_read_config(dev, PCIR_COMMAND, 2);
593 data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
594 pci_write_config(dev, PCIR_COMMAND, data, 2);
595 data = pci_read_config(dev, PCIR_COMMAND, 2);
596
597 mapped = 0;
598 /* XXX dfr: is this strictly necessary? */
599 for (i = 0; (mapped == 0) && (i < PCI_MAXMAPS_0); i++) {
600 tr->regid = PCIR_MAPS + i*4;
601 tr->regtype = SYS_RES_MEMORY;
602 tr->reg = bus_alloc_resource(dev, tr->regtype, &tr->regid,
603 0, ~0, 1, RF_ACTIVE);
604 if (!tr->reg) {
605 tr->regtype = SYS_RES_IOPORT;
606 tr->reg = bus_alloc_resource(dev, tr->regtype,
607 &tr->regid, 0, ~0, 1,
608 RF_ACTIVE);
609 }
610 if (tr->reg) {
611 tr->st = rman_get_bustag(tr->reg);
612 tr->sh = rman_get_bushandle(tr->reg);
613 mapped++;
614 }
615 }
616
617 if (mapped == 0) {
618 device_printf(dev, "unable to map register space\n");
619 goto bad;
620 }
621
622 if (tr_init(tr) == -1) {
623 device_printf(dev, "unable to initialize the card\n");
624 goto bad;
625 }
626
627 codec = ac97_create(tr, tr_rdcd, tr_wrcd);
628 if (codec == NULL) goto bad;
629 mixer_init(d, &ac97_mixer, codec);
630
631 tr->irqid = 0;
632 tr->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &tr->irqid,
633 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
634 if (!tr->irq ||
635 bus_setup_intr(dev, tr->irq, INTR_TYPE_TTY, tr_intr, tr, &tr->ih)) {
636 device_printf(dev, "unable to map interrupt\n");
637 goto bad;
638 }
639
640 if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
641 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
642 /*highaddr*/BUS_SPACE_MAXADDR,
643 /*filter*/NULL, /*filterarg*/NULL,
644 /*maxsize*/TR_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff,
645 /*flags*/0, &tr->parent_dmat) != 0) {
646 device_printf(dev, "unable to create dma tag\n");
647 goto bad;
648 }
649
650 snprintf(status, 64, "at %s 0x%lx irq %ld",
651 (tr->regtype == SYS_RES_IOPORT)? "io" : "memory",
652 rman_get_start(tr->reg), rman_get_start(tr->irq));
653
654 if (pcm_register(dev, tr, TR_MAXPLAYCH, 1)) goto bad;
655 pcm_addchan(dev, PCMDIR_REC, &tr_chantemplate, tr);
656 for (i = 0; i < TR_MAXPLAYCH; i++)
657 pcm_addchan(dev, PCMDIR_PLAY, &tr_chantemplate, tr);
658 pcm_setstatus(dev, status);
659
660 return 0;
661
662bad:
663 if (tr->reg) bus_release_resource(dev, tr->regtype, tr->regid, tr->reg);
664 if (tr->ih) bus_teardown_intr(dev, tr->irq, tr->ih);
665 if (tr->irq) bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq);
666 free(tr, M_DEVBUF);
667 return ENXIO;
668}
669
670static device_method_t tr_methods[] = {
671 /* Device interface */
672 DEVMETHOD(device_probe, tr_pci_probe),
673 DEVMETHOD(device_attach, tr_pci_attach),
674
675 { 0, 0 }
676};
677
678static driver_t tr_driver = {
679 "pcm",
680 tr_methods,
681 sizeof(snddev_info),
682};
683
684static devclass_t pcm_devclass;
685
686DRIVER_MODULE(tr, pci, tr_driver, pcm_devclass, 0, 0);
687
688#endif /* NPCI != 0 */
27 */
28
29#include "pci.h"
30#include "pcm.h"
31
32#include <dev/pcm/sound.h>
33#include <dev/pcm/ac97.h>
34#include <dev/pcm/pci/t4dwave.h>
35
36#include <pci/pcireg.h>
37#include <pci/pcivar.h>
38
39#if NPCI != 0
40
41/* -------------------------------------------------------------------- */
42
43struct tr_info;
44
45/* channel registers */
46struct tr_chinfo {
47 u_int32_t cso, alpha, fms, fmc, ec;
48 u_int32_t lba;
49 u_int32_t eso, delta;
50 u_int32_t rvol, cvol;
51 u_int32_t gvsel, pan, vol, ctrl;
52 int index;
53 snd_dbuf *buffer;
54 pcm_channel *channel;
55 struct tr_info *parent;
56};
57
58/* device private data */
59struct tr_info {
60 u_int32_t type;
61
62 bus_space_tag_t st;
63 bus_space_handle_t sh;
64 bus_dma_tag_t parent_dmat;
65
66 struct resource *reg, *irq;
67 int regtype, regid, irqid;
68 void *ih;
69
70 u_int32_t playchns;
71 struct tr_chinfo chinfo[TR_MAXPLAYCH];
72 struct tr_chinfo recchinfo;
73};
74
75/* -------------------------------------------------------------------- */
76
77/*
78 * prototypes
79 */
80
81/* channel interface */
82static void *trchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir);
83static int trchan_setdir(void *data, int dir);
84static int trchan_setformat(void *data, u_int32_t format);
85static int trchan_setspeed(void *data, u_int32_t speed);
86static int trchan_setblocksize(void *data, u_int32_t blocksize);
87static int trchan_trigger(void *data, int go);
88static int trchan_getptr(void *data);
89static pcmchan_caps *trchan_getcaps(void *data);
90
91/* talk to the codec - called from ac97.c */
92static u_int32_t tr_rdcd(void *, int);
93static void tr_wrcd(void *, int, u_int32_t);
94
95/* stuff */
96static int tr_init(struct tr_info *);
97static void tr_intr(void *);
98
99/* talk to the card */
100static u_int32_t tr_rd(struct tr_info *, int, int);
101static void tr_wr(struct tr_info *, int, u_int32_t, int);
102
103/* manipulate playback channels */
104static void tr_clrint(struct tr_info *, char);
105static void tr_enaint(struct tr_info *, char, int);
106static u_int32_t tr_testint(struct tr_info *, char);
107static void tr_rdch(struct tr_info *, char, struct tr_chinfo *);
108static void tr_wrch(struct tr_info *, char, struct tr_chinfo *);
109static void tr_selch(struct tr_info *, char);
110static void tr_startch(struct tr_info *, char);
111static void tr_stopch(struct tr_info *, char);
112
113/* -------------------------------------------------------------------- */
114
115static pcmchan_caps tr_reccaps = {
116 4000, 48000,
117 AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_S16_LE | AFMT_U16_LE,
118 AFMT_STEREO | AFMT_S16_LE
119};
120
121static pcmchan_caps tr_playcaps = {
122 4000, 48000,
123 AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_S16_LE | AFMT_U16_LE,
124 AFMT_U16_LE
125};
126
127static pcm_channel tr_chantemplate = {
128 trchan_init,
129 trchan_setdir,
130 trchan_setformat,
131 trchan_setspeed,
132 trchan_setblocksize,
133 trchan_trigger,
134 trchan_getptr,
135 trchan_getcaps,
136};
137
138/* -------------------------------------------------------------------- */
139
140static u_int32_t
141tr_fmttobits(u_int32_t fmt)
142{
143 u_int32_t bits = 0;
144 bits |= (fmt & AFMT_STEREO)? 0x4 : 0;
145 bits |= (fmt & (AFMT_S8 | AFMT_S16_LE))? 0x2 : 0;
146 bits |= (fmt & (AFMT_S16_LE | AFMT_U16_LE))? 0x8 : 0;
147 return bits;
148}
149
150/* Hardware */
151
152static u_int32_t
153tr_rd(struct tr_info *tr, int regno, int size)
154{
155 switch(size) {
156 case 1:
157 return bus_space_read_1(tr->st, tr->sh, regno);
158 case 2:
159 return bus_space_read_2(tr->st, tr->sh, regno);
160 case 4:
161 return bus_space_read_4(tr->st, tr->sh, regno);
162 default:
163 return 0xffffffff;
164 }
165}
166
167static void
168tr_wr(struct tr_info *tr, int regno, u_int32_t data, int size)
169{
170 switch(size) {
171 case 1:
172 bus_space_write_1(tr->st, tr->sh, regno, data);
173 break;
174 case 2:
175 bus_space_write_2(tr->st, tr->sh, regno, data);
176 break;
177 case 4:
178 bus_space_write_4(tr->st, tr->sh, regno, data);
179 break;
180 }
181}
182
183/* ac97 codec */
184
185static u_int32_t
186tr_rdcd(void *devinfo, int regno)
187{
188 struct tr_info *tr = (struct tr_info *)devinfo;
189 int i, j, treg, trw;
190
191 switch (tr->type) {
192 case TDX_PCI_ID:
193 treg=TDX_REG_CODECRD;
194 trw=TDX_CDC_RWSTAT;
195 break;
196 case TNX_PCI_ID:
197 treg=(regno & 0x100)? TNX_REG_CODEC2RD : TNX_REG_CODEC1RD;
198 trw=TNX_CDC_RWSTAT;
199 break;
200 default:
201 printf("!!! tr_rdcd defaulted !!!\n");
202 return 0xffffffff;
203 }
204
205 regno &= 0x7f;
206 tr_wr(tr, treg, regno | trw, 4);
207 j=trw;
208 for (i=TR_TIMEOUT_CDC; (i > 0) && (j & trw); i--) j=tr_rd(tr, treg, 4);
209 if (i == 0) printf("codec timeout during read of register %x\n", regno);
210 return (j >> TR_CDC_DATA) & 0xffff;
211}
212
213static void
214tr_wrcd(void *devinfo, int regno, u_int32_t data)
215{
216 struct tr_info *tr = (struct tr_info *)devinfo;
217 int i, j, treg, trw;
218
219 switch (tr->type) {
220 case TDX_PCI_ID:
221 treg=TDX_REG_CODECWR;
222 trw=TDX_CDC_RWSTAT;
223 break;
224 case TNX_PCI_ID:
225 treg=TNX_REG_CODECWR;
226 trw=TNX_CDC_RWSTAT | ((regno & 0x100)? TNX_CDC_SEC : 0);
227 break;
228 default:
229 printf("!!! tr_wrcd defaulted !!!");
230 return;
231 }
232
233 regno &= 0x7f;
234#if 0
235 printf("tr_wrcd: reg %x was %x", regno, tr_rdcd(devinfo, regno));
236#endif
237 j=trw;
238 for (i=TR_TIMEOUT_CDC; (i>0) && (j & trw); i--) j=tr_rd(tr, treg, 4);
239 tr_wr(tr, treg, (data << TR_CDC_DATA) | regno | trw, 4);
240#if 0
241 printf(" - wrote %x, now %x\n", data, tr_rdcd(devinfo, regno));
242#endif
243 if (i==0) printf("codec timeout writing %x, data %x\n", regno, data);
244}
245
246/* playback channel interrupts */
247
248static u_int32_t
249tr_testint(struct tr_info *tr, char channel)
250{
251 return tr_rd(tr, (channel & 0x20)? TR_REG_ADDRINTB : TR_REG_ADDRINTA,
252 4) & (1<<(channel & 0x1f));
253}
254
255static void
256tr_clrint(struct tr_info *tr, char channel)
257{
258 tr_wr(tr, (channel & 0x20)? TR_REG_ADDRINTB : TR_REG_ADDRINTA,
259 1<<(channel & 0x1f), 4);
260}
261
262static void
263tr_enaint(struct tr_info *tr, char channel, int enable)
264{
265 u_int32_t reg = (channel & 0x20)? TR_REG_INTENB : TR_REG_INTENA;
266 u_int32_t i = tr_rd(tr, reg, 4);
267 channel &= 0x1f;
268 i &= ~(1 << channel);
269 i |= (enable? 1 : 0) << channel;
270 tr_clrint(tr, channel);
271 tr_wr(tr, reg, i, 4);
272}
273
274/* playback channels */
275
276static void
277tr_selch(struct tr_info *tr, char channel)
278{
279 int i=tr_rd(tr, TR_REG_CIR, 4);
280 i &= ~TR_CIR_MASK;
281 i |= channel & 0x3f;
282 tr_wr(tr, TR_REG_CIR, i, 4);
283}
284
285static void
286tr_startch(struct tr_info *tr, char channel)
287{
288 tr_wr(tr, (channel & 0x20)? TR_REG_STARTB : TR_REG_STARTA,
289 1<<(channel & 0x1f), 4);
290}
291
292static void
293tr_stopch(struct tr_info *tr, char channel)
294{
295 tr_wr(tr, (channel & 0x20)? TR_REG_STOPB : TR_REG_STOPA,
296 1<<(channel & 0x1f), 4);
297}
298
299static void
300tr_wrch(struct tr_info *tr, char channel, struct tr_chinfo *ch)
301{
302 u_int32_t cr[TR_CHN_REGS], i;
303
304 ch->gvsel &= 0x00000001;
305 ch->fmc &= 0x00000003;
306 ch->fms &= 0x0000000f;
307 ch->ctrl &= 0x0000000f;
308 ch->pan &= 0x0000007f;
309 ch->rvol &= 0x0000007f;
310 ch->cvol &= 0x0000007f;
311 ch->vol &= 0x000000ff;
312 ch->ec &= 0x00000fff;
313 ch->alpha &= 0x00000fff;
314 ch->delta &= 0x0000ffff;
315 ch->lba &= 0x3fffffff;
316
317 cr[1]=ch->lba;
318 cr[3]=(ch->rvol<<7) | (ch->cvol);
319 cr[4]=(ch->gvsel<<31)|(ch->pan<<24)|(ch->vol<<16)|(ch->ctrl<<12)|(ch->ec);
320
321 switch (tr->type) {
322 case TDX_PCI_ID:
323 ch->cso &= 0x0000ffff;
324 ch->eso &= 0x0000ffff;
325 cr[0]=(ch->cso<<16) | (ch->alpha<<4) | (ch->fms);
326 cr[2]=(ch->eso<<16) | (ch->delta);
327 cr[3]|=0x0000c000;
328 break;
329 case TNX_PCI_ID:
330 ch->cso &= 0x00ffffff;
331 ch->eso &= 0x00ffffff;
332 cr[0]=((ch->delta & 0xff)<<24) | (ch->cso);
333 cr[2]=((ch->delta>>16)<<24) | (ch->eso);
334 cr[3]|=(ch->alpha<<20) | (ch->fms<<16) | (ch->fmc<<14);
335 break;
336 }
337 tr_selch(tr, channel);
338 for (i=0; i<TR_CHN_REGS; i++)
339 tr_wr(tr, TR_REG_CHNBASE+(i<<2), cr[i], 4);
340}
341
342static void
343tr_rdch(struct tr_info *tr, char channel, struct tr_chinfo *ch)
344{
345 u_int32_t cr[5], i;
346 tr_selch(tr, channel);
347 for (i=0; i<5; i++) cr[i]=tr_rd(tr, TR_REG_CHNBASE+(i<<2), 4);
348 ch->lba= (cr[1] & 0x3fffffff);
349 ch->fmc= (cr[3] & 0x0000c000) >> 14;
350 ch->rvol= (cr[3] & 0x00003f80) >> 7;
351 ch->cvol= (cr[3] & 0x0000007f);
352 ch->gvsel= (cr[4] & 0x80000000) >> 31;
353 ch->pan= (cr[4] & 0x7f000000) >> 24;
354 ch->vol= (cr[4] & 0x00ff0000) >> 16;
355 ch->ctrl= (cr[4] & 0x0000f000) >> 12;
356 ch->ec= (cr[4] & 0x00000fff);
357 switch(tr->type) {
358 case TDX_PCI_ID:
359 ch->cso= (cr[0] & 0xffff0000) >> 16;
360 ch->alpha= (cr[0] & 0x0000fff0) >> 4;
361 ch->fms= (cr[0] & 0x0000000f);
362 ch->eso= (cr[2] & 0xffff0000) >> 16;
363 ch->delta= (cr[2] & 0x0000ffff);
364 break;
365 case TNX_PCI_ID:
366 ch->cso= (cr[0] & 0x00ffffff);
367 ch->eso= (cr[2] & 0x00ffffff);
368 ch->delta= ((cr[2] & 0xff000000) >> 16) |
369 ((cr[0] & 0xff000000) >> 24);
370 ch->alpha= (cr[3] & 0xfff00000) >> 20;
371 ch->fms= (cr[3] & 0x000f0000) >> 16;
372 break;
373 }
374}
375
376/* channel interface */
377
378void *
379trchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
380{
381 struct tr_info *tr = devinfo;
382 struct tr_chinfo *ch;
383 if (dir == PCMDIR_PLAY) {
384 ch = &tr->chinfo[tr->playchns];
385 ch->index = tr->playchns++;
386 } else {
387 ch = &tr->recchinfo;
388 ch->index = -1;
389 }
390 ch->buffer = b;
391 ch->buffer->bufsize = TR_BUFFSIZE;
392 ch->parent = tr;
393 ch->channel = c;
394 if (chn_allocbuf(ch->buffer, tr->parent_dmat) == -1) return NULL;
395 else return ch;
396}
397
398static int
399trchan_setdir(void *data, int dir)
400{
401 struct tr_chinfo *ch = data;
402 struct tr_info *tr = ch->parent;
403 if (dir == PCMDIR_PLAY && ch->index >= 0) {
404 ch->fmc = ch->fms = ch->ec = ch->alpha = 0;
405 ch->lba = vtophys(ch->buffer->buf);
406 ch->cso = 0;
407 ch->eso = ch->buffer->bufsize - 1;
408 ch->rvol = ch->cvol = 0;
409 ch->gvsel = 0;
410 ch->pan = 0;
411 ch->vol = 0;
412 ch->ctrl = 0x01;
413 ch->delta = 0;
414 tr_wrch(tr, ch->index, ch);
415 tr_enaint(tr, ch->index, 1);
416 } else if (dir == PCMDIR_REC && ch->index == -1) {
417 /* set up dma mode regs */
418 u_int32_t i;
419 tr_wr(tr, TR_REG_DMAR15, 0, 1);
420 i = tr_rd(tr, TR_REG_DMAR11, 1) & 0x03;
421 tr_wr(tr, TR_REG_DMAR11, i | 0x54, 1);
422 /* set up base address */
423 tr_wr(tr, TR_REG_DMAR0, vtophys(ch->buffer->buf), 4);
424 /* set up buffer size */
425 i = tr_rd(tr, TR_REG_DMAR4, 4) & ~0x00ffffff;
426 tr_wr(tr, TR_REG_DMAR4, i | (ch->buffer->bufsize - 1), 4);
427 } else return -1;
428 return 0;
429}
430
431static int
432trchan_setformat(void *data, u_int32_t format)
433{
434 struct tr_chinfo *ch = data;
435 struct tr_info *tr = ch->parent;
436 u_int32_t bits = tr_fmttobits(format);
437
438 if (ch->index >= 0) {
439 tr_rdch(tr, ch->index, ch);
440 ch->eso = (ch->buffer->bufsize / ch->buffer->sample_size) - 1;
441 ch->ctrl = bits | 0x01;
442 tr_wrch(tr, ch->index, ch);
443 } else {
444 u_int32_t i;
445 /* set # of samples between interrupts */
446 i = (TR_INTSAMPLES >> ((bits & 0x08)? 1 : 0)) - 1;
447 tr_wr(tr, TR_REG_SBBL, i | (i << 16), 4);
448 /* set sample format */
449 i = 0x18 | (bits << 4);
450 tr_wr(tr, TR_REG_SBCTRL, i, 1);
451 }
452 return 0;
453}
454
455static int
456trchan_setspeed(void *data, u_int32_t speed)
457{
458 struct tr_chinfo *ch = data;
459 struct tr_info *tr = ch->parent;
460
461 if (ch->index >= 0) {
462 tr_rdch(tr, ch->index, ch);
463 ch->delta = (speed << 12) / 48000;
464 tr_wrch(tr, ch->index, ch);
465 return (ch->delta * 48000) >> 12;
466 } else {
467 /* setup speed */
468 ch->delta = (48000 << 12) / speed;
469 tr_wr(tr, TR_REG_SBDELTA, ch->delta, 2);
470 return (48000 << 12) / ch->delta;
471 }
472 return 0;
473}
474
475static int
476trchan_setblocksize(void *data, u_int32_t blocksize)
477{
478 struct tr_chinfo *ch = data;
479 return ch->buffer->bufsize / 2;
480}
481
482static int
483trchan_trigger(void *data, int go)
484{
485 struct tr_chinfo *ch = data;
486 struct tr_info *tr = ch->parent;
487 if (ch->index >= 0) {
488 if (go == PCMTRIG_START) tr_startch(tr, ch->index);
489 else tr_stopch(tr, ch->index);
490 } else {
491 u_int32_t i = tr_rd(tr, TR_REG_SBCTRL, 1) & ~7;
492 tr_wr(tr, TR_REG_SBCTRL, i | (go == PCMTRIG_START)? 1 : 0, 1);
493 }
494 return 0;
495}
496
497static int
498trchan_getptr(void *data)
499{
500 struct tr_chinfo *ch = data;
501 struct tr_info *tr = ch->parent;
502 if (ch->index >= 0) {
503 tr_rdch(tr, ch->index, ch);
504 return ch->cso * ch->buffer->sample_size;
505 } else return tr_rd(tr, TR_REG_DMAR0, 4) - vtophys(ch->buffer->buf);
506}
507
508static pcmchan_caps *
509trchan_getcaps(void *data)
510{
511 struct tr_chinfo *ch = data;
512 return (ch->index >= 0)? &tr_playcaps : &tr_reccaps;
513}
514
515/* The interrupt handler */
516
517static void
518tr_intr(void *p)
519{
520 struct tr_info *tr = (struct tr_info *)p;
521 u_int32_t intsrc = tr_rd(tr, TR_REG_MISCINT, 4);
522
523 if (intsrc & TR_INT_ADDR) {
524 int i;
525 for (i = 0; i < tr->playchns; i++) {
526 if (tr_testint(tr, i)) {
527 chn_intr(tr->chinfo[i].channel);
528 tr_clrint(tr, i);
529 }
530 }
531 }
532 if (intsrc & TR_INT_SB) {
533 chn_intr(tr->recchinfo.channel);
534 tr_rd(tr, TR_REG_SBR9, 1);
535 tr_rd(tr, TR_REG_SBR10, 1);
536 }
537}
538
539/* -------------------------------------------------------------------- */
540
541/*
542 * Probe and attach the card
543 */
544
545static int
546tr_init(struct tr_info *tr)
547{
548 if (tr->type == TDX_PCI_ID) {
549 tr_wr(tr, TDX_REG_CODECST, TDX_CDC_ON, 4);
550 } else tr_wr(tr, TNX_REG_CODECST, TNX_CDC_ON, 4);
551
552 tr_wr(tr, TR_REG_CIR, TR_CIR_MIDENA | TR_CIR_ADDRENA, 4);
553 tr->playchns = 0;
554 return 0;
555}
556
557static int
558tr_pci_probe(device_t dev)
559{
560 if (pci_get_devid(dev) == TDX_PCI_ID) {
561 device_set_desc(dev, "Trident 4DWave DX");
562 return 0;
563 }
564 if (pci_get_devid(dev) == TNX_PCI_ID) {
565 device_set_desc(dev, "Trident 4DWave NX");
566 return 0;
567 }
568
569 return ENXIO;
570}
571
572static int
573tr_pci_attach(device_t dev)
574{
575 snddev_info *d;
576 u_int32_t data;
577 struct tr_info *tr;
578 struct ac97_info *codec;
579 int i;
580 int mapped;
581 char status[SND_STATUSLEN];
582
583 d = device_get_softc(dev);
584 if ((tr = malloc(sizeof(*tr), M_DEVBUF, M_NOWAIT)) == NULL) {
585 device_printf(dev, "cannot allocate softc\n");
586 return ENXIO;
587 }
588
589 bzero(tr, sizeof(*tr));
590 tr->type = pci_get_devid(dev);
591
592 data = pci_read_config(dev, PCIR_COMMAND, 2);
593 data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
594 pci_write_config(dev, PCIR_COMMAND, data, 2);
595 data = pci_read_config(dev, PCIR_COMMAND, 2);
596
597 mapped = 0;
598 /* XXX dfr: is this strictly necessary? */
599 for (i = 0; (mapped == 0) && (i < PCI_MAXMAPS_0); i++) {
600 tr->regid = PCIR_MAPS + i*4;
601 tr->regtype = SYS_RES_MEMORY;
602 tr->reg = bus_alloc_resource(dev, tr->regtype, &tr->regid,
603 0, ~0, 1, RF_ACTIVE);
604 if (!tr->reg) {
605 tr->regtype = SYS_RES_IOPORT;
606 tr->reg = bus_alloc_resource(dev, tr->regtype,
607 &tr->regid, 0, ~0, 1,
608 RF_ACTIVE);
609 }
610 if (tr->reg) {
611 tr->st = rman_get_bustag(tr->reg);
612 tr->sh = rman_get_bushandle(tr->reg);
613 mapped++;
614 }
615 }
616
617 if (mapped == 0) {
618 device_printf(dev, "unable to map register space\n");
619 goto bad;
620 }
621
622 if (tr_init(tr) == -1) {
623 device_printf(dev, "unable to initialize the card\n");
624 goto bad;
625 }
626
627 codec = ac97_create(tr, tr_rdcd, tr_wrcd);
628 if (codec == NULL) goto bad;
629 mixer_init(d, &ac97_mixer, codec);
630
631 tr->irqid = 0;
632 tr->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &tr->irqid,
633 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
634 if (!tr->irq ||
635 bus_setup_intr(dev, tr->irq, INTR_TYPE_TTY, tr_intr, tr, &tr->ih)) {
636 device_printf(dev, "unable to map interrupt\n");
637 goto bad;
638 }
639
640 if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
641 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
642 /*highaddr*/BUS_SPACE_MAXADDR,
643 /*filter*/NULL, /*filterarg*/NULL,
644 /*maxsize*/TR_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff,
645 /*flags*/0, &tr->parent_dmat) != 0) {
646 device_printf(dev, "unable to create dma tag\n");
647 goto bad;
648 }
649
650 snprintf(status, 64, "at %s 0x%lx irq %ld",
651 (tr->regtype == SYS_RES_IOPORT)? "io" : "memory",
652 rman_get_start(tr->reg), rman_get_start(tr->irq));
653
654 if (pcm_register(dev, tr, TR_MAXPLAYCH, 1)) goto bad;
655 pcm_addchan(dev, PCMDIR_REC, &tr_chantemplate, tr);
656 for (i = 0; i < TR_MAXPLAYCH; i++)
657 pcm_addchan(dev, PCMDIR_PLAY, &tr_chantemplate, tr);
658 pcm_setstatus(dev, status);
659
660 return 0;
661
662bad:
663 if (tr->reg) bus_release_resource(dev, tr->regtype, tr->regid, tr->reg);
664 if (tr->ih) bus_teardown_intr(dev, tr->irq, tr->ih);
665 if (tr->irq) bus_release_resource(dev, SYS_RES_IRQ, tr->irqid, tr->irq);
666 free(tr, M_DEVBUF);
667 return ENXIO;
668}
669
670static device_method_t tr_methods[] = {
671 /* Device interface */
672 DEVMETHOD(device_probe, tr_pci_probe),
673 DEVMETHOD(device_attach, tr_pci_attach),
674
675 { 0, 0 }
676};
677
678static driver_t tr_driver = {
679 "pcm",
680 tr_methods,
681 sizeof(snddev_info),
682};
683
684static devclass_t pcm_devclass;
685
686DRIVER_MODULE(tr, pci, tr_driver, pcm_devclass, 0, 0);
687
688#endif /* NPCI != 0 */