kernel tree reorganization stage 1: Major cvs repository work (not logged as
[dragonfly.git] / sys / dev / sound / pci / csapcm.c
1 /*
2  * Copyright (c) 1999 Seigo Tanimura
3  * All rights reserved.
4  *
5  * Portions of this source are based on cwcealdr.cpp and dhwiface.cpp in
6  * cwcealdr1.zip, the sample sources by Crystal Semiconductor.
7  * Copyright (c) 1996-1998 Crystal Semiconductor Corp.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $FreeBSD: src/sys/dev/sound/pci/csapcm.c,v 1.8.2.7 2002/04/22 15:49:32 cg Exp $
31  * $DragonFly: src/sys/dev/sound/pci/csapcm.c,v 1.3 2003/08/07 21:17:13 dillon Exp $
32  */
33
34 #include <sys/soundcard.h>
35 #include <dev/sound/pcm/sound.h>
36 #include <dev/sound/pcm/ac97.h>
37 #include <dev/sound/chip.h>
38 #include <dev/sound/pci/csareg.h>
39 #include <dev/sound/pci/csavar.h>
40
41 #include <bus/pci/pcireg.h>
42 #include <bus/pci/pcivar.h>
43
44 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pci/csapcm.c,v 1.3 2003/08/07 21:17:13 dillon Exp $");
45
46 /* Buffer size on dma transfer. Fixed for CS416x. */
47 #define CS461x_BUFFSIZE   (4 * 1024)
48
49 #define GOF_PER_SEC 200
50
51 /* device private data */
52 struct csa_info;
53
54 struct csa_chinfo {
55         struct csa_info *parent;
56         struct pcm_channel *channel;
57         struct snd_dbuf *buffer;
58         int dir;
59         u_int32_t fmt, spd;
60         int dma;
61 };
62
63 struct csa_info {
64         csa_res         res; /* resource */
65         void            *ih; /* Interrupt cookie */
66         bus_dma_tag_t   parent_dmat; /* DMA tag */
67         struct csa_bridgeinfo *binfo; /* The state of the parent. */
68         struct csa_card *card;
69
70         int active;
71         /* Contents of board's registers */
72         u_long          pfie;
73         u_long          pctl;
74         u_long          cctl;
75         struct csa_chinfo pch, rch;
76 };
77
78 /* -------------------------------------------------------------------- */
79
80 /* prototypes */
81 static int      csa_init(struct csa_info *);
82 static void     csa_intr(void *);
83 static void     csa_setplaysamplerate(csa_res *resp, u_long ulInRate);
84 static void     csa_setcapturesamplerate(csa_res *resp, u_long ulOutRate);
85 static void     csa_startplaydma(struct csa_info *csa);
86 static void     csa_startcapturedma(struct csa_info *csa);
87 static void     csa_stopplaydma(struct csa_info *csa);
88 static void     csa_stopcapturedma(struct csa_info *csa);
89 static int      csa_startdsp(csa_res *resp);
90 static int      csa_allocres(struct csa_info *scp, device_t dev);
91 static void     csa_releaseres(struct csa_info *scp, device_t dev);
92
93 static u_int32_t csa_playfmt[] = {
94         AFMT_U8,
95         AFMT_STEREO | AFMT_U8,
96         AFMT_S8,
97         AFMT_STEREO | AFMT_S8,
98         AFMT_S16_LE,
99         AFMT_STEREO | AFMT_S16_LE,
100         AFMT_S16_BE,
101         AFMT_STEREO | AFMT_S16_BE,
102         0
103 };
104 static struct pcmchan_caps csa_playcaps = {8000, 48000, csa_playfmt, 0};
105
106 static u_int32_t csa_recfmt[] = {
107         AFMT_S16_LE,
108         AFMT_STEREO | AFMT_S16_LE,
109         0
110 };
111 static struct pcmchan_caps csa_reccaps = {11025, 48000, csa_recfmt, 0};
112
113 /* -------------------------------------------------------------------- */
114
115 static int
116 csa_active(struct csa_info *csa, int run)
117 {
118         int old, go;
119
120         old = csa->active;
121         csa->active += run;
122
123         if ((csa->active == 0 && old == 1) || (csa->active == 1 && old == 0)) {
124                 go = csa->active;
125                 if (csa->card->active)
126                         return csa->card->active(go);
127         }
128         return 0;
129 }
130
131 /* -------------------------------------------------------------------- */
132 /* ac97 codec */
133
134 static int
135 csa_rdcd(kobj_t obj, void *devinfo, int regno)
136 {
137         u_int32_t data;
138         struct csa_info *csa = (struct csa_info *)devinfo;
139
140         csa_active(csa, 1);
141         if (csa_readcodec(&csa->res, regno + BA0_AC97_RESET, &data))
142                 data = 0;
143         csa_active(csa, -1);
144
145         return data;
146 }
147
148 static int
149 csa_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data)
150 {
151         struct csa_info *csa = (struct csa_info *)devinfo;
152
153         csa_active(csa, 1);
154         csa_writecodec(&csa->res, regno + BA0_AC97_RESET, data);
155         csa_active(csa, -1);
156
157         return 0;
158 }
159
160 static kobj_method_t csa_ac97_methods[] = {
161         KOBJMETHOD(ac97_read,           csa_rdcd),
162         KOBJMETHOD(ac97_write,          csa_wrcd),
163         { 0, 0 }
164 };
165 AC97_DECLARE(csa_ac97);
166
167 static void
168 csa_setplaysamplerate(csa_res *resp, u_long ulInRate)
169 {
170         u_long ulTemp1, ulTemp2;
171         u_long ulPhiIncr;
172         u_long ulCorrectionPerGOF, ulCorrectionPerSec;
173         u_long ulOutRate;
174
175         ulOutRate = 48000;
176
177         /*
178          * Compute the values used to drive the actual sample rate conversion.
179          * The following formulas are being computed, using inline assembly
180          * since we need to use 64 bit arithmetic to compute the values:
181          *
182          *     ulPhiIncr = floor((Fs,in * 2^26) / Fs,out)
183          *     ulCorrectionPerGOF = floor((Fs,in * 2^26 - Fs,out * ulPhiIncr) /
184          *                                GOF_PER_SEC)
185          *     ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -
186          *                          GOF_PER_SEC * ulCorrectionPerGOF
187          *
188          * i.e.
189          *
190          *     ulPhiIncr:ulOther = dividend:remainder((Fs,in * 2^26) / Fs,out)
191          *     ulCorrectionPerGOF:ulCorrectionPerSec =
192          *         dividend:remainder(ulOther / GOF_PER_SEC)
193          */
194         ulTemp1 = ulInRate << 16;
195         ulPhiIncr = ulTemp1 / ulOutRate;
196         ulTemp1 -= ulPhiIncr * ulOutRate;
197         ulTemp1 <<= 10;
198         ulPhiIncr <<= 10;
199         ulTemp2 = ulTemp1 / ulOutRate;
200         ulPhiIncr += ulTemp2;
201         ulTemp1 -= ulTemp2 * ulOutRate;
202         ulCorrectionPerGOF = ulTemp1 / GOF_PER_SEC;
203         ulTemp1 -= ulCorrectionPerGOF * GOF_PER_SEC;
204         ulCorrectionPerSec = ulTemp1;
205
206         /*
207          * Fill in the SampleRateConverter control block.
208          */
209         csa_writemem(resp, BA1_PSRC, ((ulCorrectionPerSec << 16) & 0xFFFF0000) | (ulCorrectionPerGOF & 0xFFFF));
210         csa_writemem(resp, BA1_PPI, ulPhiIncr);
211 }
212
213 static void
214 csa_setcapturesamplerate(csa_res *resp, u_long ulOutRate)
215 {
216         u_long ulPhiIncr, ulCoeffIncr, ulTemp1, ulTemp2;
217         u_long ulCorrectionPerGOF, ulCorrectionPerSec, ulInitialDelay;
218         u_long dwFrameGroupLength, dwCnt;
219         u_long ulInRate;
220
221         ulInRate = 48000;
222
223         /*
224          * We can only decimate by up to a factor of 1/9th the hardware rate.
225          * Return an error if an attempt is made to stray outside that limit.
226          */
227         if((ulOutRate * 9) < ulInRate)
228                 return;
229
230         /*
231          * We can not capture at at rate greater than the Input Rate (48000).
232          * Return an error if an attempt is made to stray outside that limit.
233          */
234         if(ulOutRate > ulInRate)
235                 return;
236
237         /*
238          * Compute the values used to drive the actual sample rate conversion.
239          * The following formulas are being computed, using inline assembly
240          * since we need to use 64 bit arithmetic to compute the values:
241          *
242          *     ulCoeffIncr = -floor((Fs,out * 2^23) / Fs,in)
243          *     ulPhiIncr = floor((Fs,in * 2^26) / Fs,out)
244          *     ulCorrectionPerGOF = floor((Fs,in * 2^26 - Fs,out * ulPhiIncr) /
245          *                                GOF_PER_SEC)
246          *     ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -
247          *                          GOF_PER_SEC * ulCorrectionPerGOF
248          *     ulInitialDelay = ceil((24 * Fs,in) / Fs,out)
249          *
250          * i.e.
251          *
252          *     ulCoeffIncr = neg(dividend((Fs,out * 2^23) / Fs,in))
253          *     ulPhiIncr:ulOther = dividend:remainder((Fs,in * 2^26) / Fs,out)
254          *     ulCorrectionPerGOF:ulCorrectionPerSec =
255          *         dividend:remainder(ulOther / GOF_PER_SEC)
256          *     ulInitialDelay = dividend(((24 * Fs,in) + Fs,out - 1) / Fs,out)
257          */
258         ulTemp1 = ulOutRate << 16;
259         ulCoeffIncr = ulTemp1 / ulInRate;
260         ulTemp1 -= ulCoeffIncr * ulInRate;
261         ulTemp1 <<= 7;
262         ulCoeffIncr <<= 7;
263         ulCoeffIncr += ulTemp1 / ulInRate;
264         ulCoeffIncr ^= 0xFFFFFFFF;
265         ulCoeffIncr++;
266         ulTemp1 = ulInRate << 16;
267         ulPhiIncr = ulTemp1 / ulOutRate;
268         ulTemp1 -= ulPhiIncr * ulOutRate;
269         ulTemp1 <<= 10;
270         ulPhiIncr <<= 10;
271         ulTemp2 = ulTemp1 / ulOutRate;
272         ulPhiIncr += ulTemp2;
273         ulTemp1 -= ulTemp2 * ulOutRate;
274         ulCorrectionPerGOF = ulTemp1 / GOF_PER_SEC;
275         ulTemp1 -= ulCorrectionPerGOF * GOF_PER_SEC;
276         ulCorrectionPerSec = ulTemp1;
277         ulInitialDelay = ((ulInRate * 24) + ulOutRate - 1) / ulOutRate;
278
279         /*
280          * Fill in the VariDecimate control block.
281          */
282         csa_writemem(resp, BA1_CSRC,
283                      ((ulCorrectionPerSec << 16) & 0xFFFF0000) | (ulCorrectionPerGOF & 0xFFFF));
284         csa_writemem(resp, BA1_CCI, ulCoeffIncr);
285         csa_writemem(resp, BA1_CD,
286              (((BA1_VARIDEC_BUF_1 + (ulInitialDelay << 2)) << 16) & 0xFFFF0000) | 0x80);
287         csa_writemem(resp, BA1_CPI, ulPhiIncr);
288
289         /*
290          * Figure out the frame group length for the write back task.  Basically,
291          * this is just the factors of 24000 (2^6*3*5^3) that are not present in
292          * the output sample rate.
293          */
294         dwFrameGroupLength = 1;
295         for(dwCnt = 2; dwCnt <= 64; dwCnt *= 2)
296         {
297                 if(((ulOutRate / dwCnt) * dwCnt) !=
298                    ulOutRate)
299                 {
300                         dwFrameGroupLength *= 2;
301                 }
302         }
303         if(((ulOutRate / 3) * 3) !=
304            ulOutRate)
305         {
306                 dwFrameGroupLength *= 3;
307         }
308         for(dwCnt = 5; dwCnt <= 125; dwCnt *= 5)
309         {
310                 if(((ulOutRate / dwCnt) * dwCnt) !=
311                    ulOutRate)
312                 {
313                         dwFrameGroupLength *= 5;
314                 }
315         }
316
317         /*
318          * Fill in the WriteBack control block.
319          */
320         csa_writemem(resp, BA1_CFG1, dwFrameGroupLength);
321         csa_writemem(resp, BA1_CFG2, (0x00800000 | dwFrameGroupLength));
322         csa_writemem(resp, BA1_CCST, 0x0000FFFF);
323         csa_writemem(resp, BA1_CSPB, ((65536 * ulOutRate) / 24000));
324         csa_writemem(resp, (BA1_CSPB + 4), 0x0000FFFF);
325 }
326
327 static void
328 csa_startplaydma(struct csa_info *csa)
329 {
330         csa_res *resp;
331         u_long ul;
332
333         if (!csa->pch.dma) {
334                 resp = &csa->res;
335                 ul = csa_readmem(resp, BA1_PCTL);
336                 ul &= 0x0000ffff;
337                 csa_writemem(resp, BA1_PCTL, ul | csa->pctl);
338                 csa_writemem(resp, BA1_PVOL, 0x80008000);
339                 csa->pch.dma = 1;
340         }
341 }
342
343 static void
344 csa_startcapturedma(struct csa_info *csa)
345 {
346         csa_res *resp;
347         u_long ul;
348
349         if (!csa->rch.dma) {
350                 resp = &csa->res;
351                 ul = csa_readmem(resp, BA1_CCTL);
352                 ul &= 0xffff0000;
353                 csa_writemem(resp, BA1_CCTL, ul | csa->cctl);
354                 csa_writemem(resp, BA1_CVOL, 0x80008000);
355                 csa->rch.dma = 1;
356         }
357 }
358
359 static void
360 csa_stopplaydma(struct csa_info *csa)
361 {
362         csa_res *resp;
363         u_long ul;
364
365         if (csa->pch.dma) {
366                 resp = &csa->res;
367                 ul = csa_readmem(resp, BA1_PCTL);
368                 csa->pctl = ul & 0xffff0000;
369                 csa_writemem(resp, BA1_PCTL, ul & 0x0000ffff);
370                 csa_writemem(resp, BA1_PVOL, 0xffffffff);
371                 csa->pch.dma = 0;
372
373                 /*
374                  * The bitwise pointer of the serial FIFO in the DSP
375                  * seems to make an error upon starting or stopping the
376                  * DSP. Clear the FIFO and correct the pointer if we
377                  * are not capturing.
378                  */
379                 if (!csa->rch.dma) {
380                         csa_clearserialfifos(resp);
381                         csa_writeio(resp, BA0_SERBSP, 0);
382                 }
383         }
384 }
385
386 static void
387 csa_stopcapturedma(struct csa_info *csa)
388 {
389         csa_res *resp;
390         u_long ul;
391
392         if (csa->rch.dma) {
393                 resp = &csa->res;
394                 ul = csa_readmem(resp, BA1_CCTL);
395                 csa->cctl = ul & 0x0000ffff;
396                 csa_writemem(resp, BA1_CCTL, ul & 0xffff0000);
397                 csa_writemem(resp, BA1_CVOL, 0xffffffff);
398                 csa->rch.dma = 0;
399
400                 /*
401                  * The bitwise pointer of the serial FIFO in the DSP
402                  * seems to make an error upon starting or stopping the
403                  * DSP. Clear the FIFO and correct the pointer if we
404                  * are not playing.
405                  */
406                 if (!csa->pch.dma) {
407                         csa_clearserialfifos(resp);
408                         csa_writeio(resp, BA0_SERBSP, 0);
409                 }
410         }
411 }
412
413 static int
414 csa_startdsp(csa_res *resp)
415 {
416         int i;
417         u_long ul;
418
419         /*
420          * Set the frame timer to reflect the number of cycles per frame.
421          */
422         csa_writemem(resp, BA1_FRMT, 0xadf);
423
424         /*
425          * Turn on the run, run at frame, and DMA enable bits in the local copy of
426          * the SP control register.
427          */
428         csa_writemem(resp, BA1_SPCR, SPCR_RUN | SPCR_RUNFR | SPCR_DRQEN);
429
430         /*
431          * Wait until the run at frame bit resets itself in the SP control
432          * register.
433          */
434         ul = 0;
435         for (i = 0 ; i < 25 ; i++) {
436                 /*
437                  * Wait a little bit, so we don't issue PCI reads too frequently.
438                  */
439                 DELAY(50);
440                 /*
441                  * Fetch the current value of the SP status register.
442                  */
443                 ul = csa_readmem(resp, BA1_SPCR);
444
445                 /*
446                  * If the run at frame bit has reset, then stop waiting.
447                  */
448                 if((ul & SPCR_RUNFR) == 0)
449                         break;
450         }
451         /*
452          * If the run at frame bit never reset, then return an error.
453          */
454         if((ul & SPCR_RUNFR) != 0)
455                 return (EAGAIN);
456
457         return (0);
458 }
459
460 static int
461 csa_setupchan(struct csa_chinfo *ch)
462 {
463         struct csa_info *csa = ch->parent;
464         csa_res *resp = &csa->res;
465         u_long pdtc, tmp;
466
467         if (ch->dir == PCMDIR_PLAY) {
468                 /* direction */
469                 csa_writemem(resp, BA1_PBA, vtophys(sndbuf_getbuf(ch->buffer)));
470
471                 /* format */
472                 csa->pfie = csa_readmem(resp, BA1_PFIE) & ~0x0000f03f;
473                 if (!(ch->fmt & AFMT_SIGNED))
474                         csa->pfie |= 0x8000;
475                 if (ch->fmt & AFMT_BIGENDIAN)
476                         csa->pfie |= 0x4000;
477                 if (!(ch->fmt & AFMT_STEREO))
478                         csa->pfie |= 0x2000;
479                 if (ch->fmt & AFMT_8BIT)
480                         csa->pfie |= 0x1000;
481                 csa_writemem(resp, BA1_PFIE, csa->pfie);
482
483                 tmp = 4;
484                 if (ch->fmt & AFMT_16BIT)
485                         tmp <<= 1;
486                 if (ch->fmt & AFMT_STEREO)
487                         tmp <<= 1;
488                 tmp--;
489
490                 pdtc = csa_readmem(resp, BA1_PDTC) & ~0x000001ff;
491                 pdtc |= tmp;
492                 csa_writemem(resp, BA1_PDTC, pdtc);
493
494                 /* rate */
495                 csa_setplaysamplerate(resp, ch->spd);
496         } else if (ch->dir == PCMDIR_REC) {
497                 /* direction */
498                 csa_writemem(resp, BA1_CBA, vtophys(sndbuf_getbuf(ch->buffer)));
499
500                 /* format */
501                 csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001);
502
503                 /* rate */
504                 csa_setcapturesamplerate(resp, ch->spd);
505         }
506         return 0;
507 }
508
509 /* -------------------------------------------------------------------- */
510 /* channel interface */
511
512 static void *
513 csachan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
514 {
515         struct csa_info *csa = devinfo;
516         struct csa_chinfo *ch = (dir == PCMDIR_PLAY)? &csa->pch : &csa->rch;
517
518         ch->parent = csa;
519         ch->channel = c;
520         ch->buffer = b;
521         ch->dir = dir;
522         if (sndbuf_alloc(ch->buffer, csa->parent_dmat, CS461x_BUFFSIZE) == -1) return NULL;
523         return ch;
524 }
525
526 static int
527 csachan_setformat(kobj_t obj, void *data, u_int32_t format)
528 {
529         struct csa_chinfo *ch = data;
530
531         ch->fmt = format;
532         return 0;
533 }
534
535 static int
536 csachan_setspeed(kobj_t obj, void *data, u_int32_t speed)
537 {
538         struct csa_chinfo *ch = data;
539
540         ch->spd = speed;
541         return ch->spd; /* XXX calc real speed */
542 }
543
544 static int
545 csachan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
546 {
547         return CS461x_BUFFSIZE / 2;
548 }
549
550 static int
551 csachan_trigger(kobj_t obj, void *data, int go)
552 {
553         struct csa_chinfo *ch = data;
554         struct csa_info *csa = ch->parent;
555
556         if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
557                 return 0;
558
559         if (go == PCMTRIG_START) {
560                 csa_active(csa, 1);
561                 csa_setupchan(ch);
562                 if (ch->dir == PCMDIR_PLAY)
563                         csa_startplaydma(csa);
564                 else
565                         csa_startcapturedma(csa);
566         } else {
567                 if (ch->dir == PCMDIR_PLAY)
568                         csa_stopplaydma(csa);
569                 else
570                         csa_stopcapturedma(csa);
571                 csa_active(csa, -1);
572         }
573         return 0;
574 }
575
576 static int
577 csachan_getptr(kobj_t obj, void *data)
578 {
579         struct csa_chinfo *ch = data;
580         struct csa_info *csa = ch->parent;
581         csa_res *resp;
582         int ptr;
583
584         resp = &csa->res;
585
586         if (ch->dir == PCMDIR_PLAY) {
587                 ptr = csa_readmem(resp, BA1_PBA) - vtophys(sndbuf_getbuf(ch->buffer));
588                 if ((ch->fmt & AFMT_U8) != 0 || (ch->fmt & AFMT_S8) != 0)
589                         ptr >>= 1;
590         } else {
591                 ptr = csa_readmem(resp, BA1_CBA) - vtophys(sndbuf_getbuf(ch->buffer));
592                 if ((ch->fmt & AFMT_U8) != 0 || (ch->fmt & AFMT_S8) != 0)
593                         ptr >>= 1;
594         }
595
596         return (ptr);
597 }
598
599 static struct pcmchan_caps *
600 csachan_getcaps(kobj_t obj, void *data)
601 {
602         struct csa_chinfo *ch = data;
603         return (ch->dir == PCMDIR_PLAY)? &csa_playcaps : &csa_reccaps;
604 }
605
606 static kobj_method_t csachan_methods[] = {
607         KOBJMETHOD(channel_init,                csachan_init),
608         KOBJMETHOD(channel_setformat,           csachan_setformat),
609         KOBJMETHOD(channel_setspeed,            csachan_setspeed),
610         KOBJMETHOD(channel_setblocksize,        csachan_setblocksize),
611         KOBJMETHOD(channel_trigger,             csachan_trigger),
612         KOBJMETHOD(channel_getptr,              csachan_getptr),
613         KOBJMETHOD(channel_getcaps,             csachan_getcaps),
614         { 0, 0 }
615 };
616 CHANNEL_DECLARE(csachan);
617
618 /* -------------------------------------------------------------------- */
619 /* The interrupt handler */
620 static void
621 csa_intr(void *p)
622 {
623         struct csa_info *csa = p;
624
625         if ((csa->binfo->hisr & HISR_VC0) != 0)
626                 chn_intr(csa->pch.channel);
627         if ((csa->binfo->hisr & HISR_VC1) != 0)
628                 chn_intr(csa->rch.channel);
629 }
630
631 /* -------------------------------------------------------------------- */
632
633 /*
634  * Probe and attach the card
635  */
636
637 static int
638 csa_init(struct csa_info *csa)
639 {
640         csa_res *resp;
641
642         resp = &csa->res;
643
644         csa->pfie = 0;
645         csa_stopplaydma(csa);
646         csa_stopcapturedma(csa);
647
648         if (csa_startdsp(resp))
649                 return (1);
650
651         /* Crank up the power on the DAC and ADC. */
652         csa_setplaysamplerate(resp, 8000);
653         csa_setcapturesamplerate(resp, 8000);
654
655         return 0;
656 }
657
658 /* Allocates resources. */
659 static int
660 csa_allocres(struct csa_info *csa, device_t dev)
661 {
662         csa_res *resp;
663
664         resp = &csa->res;
665         if (resp->io == NULL) {
666                 resp->io = bus_alloc_resource(dev, SYS_RES_MEMORY, &resp->io_rid, 0, ~0, 1, RF_ACTIVE);
667                 if (resp->io == NULL)
668                         return (1);
669         }
670         if (resp->mem == NULL) {
671                 resp->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &resp->mem_rid, 0, ~0, 1, RF_ACTIVE);
672                 if (resp->mem == NULL)
673                         return (1);
674         }
675         if (resp->irq == NULL) {
676                 resp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &resp->irq_rid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
677                 if (resp->irq == NULL)
678                         return (1);
679         }
680         if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/CS461x_BUFFSIZE, /*boundary*/CS461x_BUFFSIZE,
681                                /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
682                                /*highaddr*/BUS_SPACE_MAXADDR,
683                                /*filter*/NULL, /*filterarg*/NULL,
684                                /*maxsize*/CS461x_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff,
685                                /*flags*/0, &csa->parent_dmat) != 0)
686                 return (1);
687
688         return (0);
689 }
690
691 /* Releases resources. */
692 static void
693 csa_releaseres(struct csa_info *csa, device_t dev)
694 {
695         csa_res *resp;
696
697         resp = &csa->res;
698         if (resp->irq != NULL) {
699                 if (csa->ih)
700                         bus_teardown_intr(dev, resp->irq, csa->ih);
701                 bus_release_resource(dev, SYS_RES_IRQ, resp->irq_rid, resp->irq);
702                 resp->irq = NULL;
703         }
704         if (resp->io != NULL) {
705                 bus_release_resource(dev, SYS_RES_MEMORY, resp->io_rid, resp->io);
706                 resp->io = NULL;
707         }
708         if (resp->mem != NULL) {
709                 bus_release_resource(dev, SYS_RES_MEMORY, resp->mem_rid, resp->mem);
710                 resp->mem = NULL;
711         }
712         if (csa->parent_dmat != NULL) {
713                 bus_dma_tag_destroy(csa->parent_dmat);
714                 csa->parent_dmat = NULL;
715         }
716         if (csa != NULL) {
717                 free(csa, M_DEVBUF);
718                 csa = NULL;
719         }
720 }
721
722 static int
723 pcmcsa_probe(device_t dev)
724 {
725         char *s;
726         struct sndcard_func *func;
727
728         /* The parent device has already been probed. */
729
730         func = device_get_ivars(dev);
731         if (func == NULL || func->func != SCF_PCM)
732                 return (ENXIO);
733
734         s = "CS461x PCM Audio";
735
736         device_set_desc(dev, s);
737         return (0);
738 }
739
740 static int
741 pcmcsa_attach(device_t dev)
742 {
743         struct csa_info *csa;
744         csa_res *resp;
745         int unit;
746         char status[SND_STATUSLEN];
747         struct ac97_info *codec;
748         struct sndcard_func *func;
749
750         csa = malloc(sizeof(*csa), M_DEVBUF, M_NOWAIT | M_ZERO);
751         if (csa == NULL)
752                 return (ENOMEM);
753         unit = device_get_unit(dev);
754         func = device_get_ivars(dev);
755         csa->binfo = func->varinfo;
756         /*
757          * Fake the status of DMA so that the initial value of
758          * PCTL and CCTL can be stored into csa->pctl and csa->cctl,
759          * respectively.
760          */
761         csa->pch.dma = csa->rch.dma = 1;
762         csa->active = 0;
763         csa->card = csa->binfo->card;
764
765         /* Allocate the resources. */
766         resp = &csa->res;
767         resp->io_rid = PCIR_MAPS;
768         resp->mem_rid = PCIR_MAPS + 4;
769         resp->irq_rid = 0;
770         if (csa_allocres(csa, dev)) {
771                 csa_releaseres(csa, dev);
772                 return (ENXIO);
773         }
774
775         csa_active(csa, 1);
776         if (csa_init(csa)) {
777                 csa_releaseres(csa, dev);
778                 return (ENXIO);
779         }
780         codec = AC97_CREATE(dev, csa, csa_ac97);
781         if (codec == NULL) {
782                 csa_releaseres(csa, dev);
783                 return (ENXIO);
784         }
785         if (csa->card->inv_eapd)
786                 ac97_setflags(codec, AC97_F_EAPD_INV);
787         if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) {
788                 ac97_destroy(codec);
789                 csa_releaseres(csa, dev);
790                 return (ENXIO);
791         }
792
793         snprintf(status, SND_STATUSLEN, "at irq %ld", rman_get_start(resp->irq));
794
795         /* Enable interrupt. */
796         if (snd_setup_intr(dev, resp->irq, INTR_MPSAFE, csa_intr, csa, &csa->ih)) {
797                 ac97_destroy(codec);
798                 csa_releaseres(csa, dev);
799                 return (ENXIO);
800         }
801         csa_writemem(resp, BA1_PFIE, csa_readmem(resp, BA1_PFIE) & ~0x0000f03f);
802         csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001);
803         csa_active(csa, -1);
804
805         if (pcm_register(dev, csa, 1, 1)) {
806                 ac97_destroy(codec);
807                 csa_releaseres(csa, dev);
808                 return (ENXIO);
809         }
810         pcm_addchan(dev, PCMDIR_REC, &csachan_class, csa);
811         pcm_addchan(dev, PCMDIR_PLAY, &csachan_class, csa);
812         pcm_setstatus(dev, status);
813
814         return (0);
815 }
816
817 static int
818 pcmcsa_detach(device_t dev)
819 {
820         int r;
821         struct csa_info *csa;
822
823         r = pcm_unregister(dev);
824         if (r)
825                 return r;
826
827         csa = pcm_getdevinfo(dev);
828         csa_releaseres(csa, dev);
829
830         return 0;
831 }
832
833 static device_method_t pcmcsa_methods[] = {
834         /* Device interface */
835         DEVMETHOD(device_probe , pcmcsa_probe ),
836         DEVMETHOD(device_attach, pcmcsa_attach),
837         DEVMETHOD(device_detach, pcmcsa_detach),
838
839         { 0, 0 },
840 };
841
842 static driver_t pcmcsa_driver = {
843         "pcm",
844         pcmcsa_methods,
845         PCM_SOFTC_SIZE,
846 };
847
848 DRIVER_MODULE(snd_csapcm, csa, pcmcsa_driver, pcm_devclass, 0, 0);
849 MODULE_DEPEND(snd_csapcm, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
850 MODULE_DEPEND(snd_csapcm, snd_csa, 1, 1, 1);
851 MODULE_VERSION(snd_csapcm, 1);