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