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