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