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