Annotation of sys/dev/pci/cs4281.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: cs4281.c,v 1.19 2005/11/29 05:42:17 tedu Exp $ */
2: /* $Tera: cs4281.c,v 1.18 2000/12/27 14:24:45 tacha Exp $ */
3:
4: /*
5: * Copyright (c) 2000 Tatoku Ogaito. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by Tatoku Ogaito
18: * for the NetBSD Project.
19: * 4. The name of the author may not be used to endorse or promote products
20: * derived from this software without specific prior written permission
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32: */
33:
34: /*
35: * Cirrus Logic CS4281 driver.
36: * Data sheets can be found
37: * http://www.cirrus.com/pubs/4281.pdf?DocumentID=30
38: * ftp://ftp.alsa-project.org/pub/manuals/cirrus/cs4281tm.pdf
39: *
40: * TODO:
41: * 1: midi and FM support
42: */
43:
44: #include <sys/param.h>
45: #include <sys/systm.h>
46: #include <sys/kernel.h>
47: #include <sys/malloc.h>
48: #include <sys/fcntl.h>
49: #include <sys/device.h>
50:
51: #include <dev/pci/pcidevs.h>
52: #include <dev/pci/pcivar.h>
53: #include <dev/pci/cs4281reg.h>
54:
55: #include <sys/audioio.h>
56: #include <dev/audio_if.h>
57: #include <dev/midi_if.h>
58: #include <dev/mulaw.h>
59: #include <dev/auconv.h>
60:
61: #include <dev/ic/ac97.h>
62:
63: #include <machine/bus.h>
64:
65: #define CSCC_PCI_BA0 0x10
66: #define CSCC_PCI_BA1 0x14
67:
68: struct cs4281_dma {
69: bus_dmamap_t map;
70: caddr_t addr; /* real dma buffer */
71: caddr_t dum; /* dummy buffer for audio driver */
72: bus_dma_segment_t segs[1];
73: int nsegs;
74: size_t size;
75: struct cs4281_dma *next;
76: };
77: #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr)
78: #define BUFADDR(p) ((void *)((p)->dum))
79: #define KERNADDR(p) ((void *)((p)->addr))
80:
81: /*
82: * Software state
83: */
84: struct cs4281_softc {
85: struct device sc_dev;
86:
87: pci_intr_handle_t *sc_ih;
88:
89: /* I/O (BA0) */
90: bus_space_tag_t ba0t;
91: bus_space_handle_t ba0h;
92:
93: /* BA1 */
94: bus_space_tag_t ba1t;
95: bus_space_handle_t ba1h;
96:
97: /* DMA */
98: bus_dma_tag_t sc_dmatag;
99: struct cs4281_dma *sc_dmas;
100: size_t dma_size;
101: size_t dma_align;
102:
103: int hw_blocksize;
104:
105: /* playback */
106: void (*sc_pintr)(void *); /* dma completion intr handler */
107: void *sc_parg; /* arg for sc_intr() */
108: char *sc_ps, *sc_pe, *sc_pn;
109: int sc_pcount;
110: int sc_pi;
111: struct cs4281_dma *sc_pdma;
112: char *sc_pbuf;
113: int (*halt_output)(void *);
114: #ifdef DIAGNOSTIC
115: char sc_prun;
116: #endif
117:
118: /* capturing */
119: void (*sc_rintr)(void *); /* dma completion intr handler */
120: void *sc_rarg; /* arg for sc_intr() */
121: char *sc_rs, *sc_re, *sc_rn;
122: int sc_rcount;
123: int sc_ri;
124: struct cs4281_dma *sc_rdma;
125: char *sc_rbuf;
126: int sc_rparam; /* record format */
127: int (*halt_input)(void *);
128: #ifdef DIAGNOSTIC
129: char sc_rrun;
130: #endif
131:
132: #if NMIDI > 0
133: void (*sc_iintr)(void *, int); /* midi input ready handler */
134: void (*sc_ointr)(void *); /* midi output ready handler */
135: void *sc_arg;
136: #endif
137:
138: /* AC97 CODEC */
139: struct ac97_codec_if *codec_if;
140: struct ac97_host_if host_if;
141:
142: /* Power Management */
143: char sc_suspend;
144: void *sc_powerhook; /* Power hook */
145: u_int16_t ac97_reg[CS4281_SAVE_REG_MAX + 1]; /* Save ac97 registers */
146: };
147:
148: #define BA0READ4(sc, r) bus_space_read_4((sc)->ba0t, (sc)->ba0h, (r))
149: #define BA0WRITE4(sc, r, x) bus_space_write_4((sc)->ba0t, (sc)->ba0h, (r), (x))
150:
151: #if defined(ENABLE_SECONDARY_CODEC)
152: #define MAX_CHANNELS (4)
153: #define MAX_FIFO_SIZE 32 /* 128/4 channels */
154: #else
155: #define MAX_CHANNELS (2)
156: #define MAX_FIFO_SIZE 64 /* 128/2 channels */
157: #endif
158:
159: int cs4281_match(struct device *, void *, void *);
160: void cs4281_attach(struct device *, struct device *, void *);
161: int cs4281_intr(void *);
162: int cs4281_query_encoding(void *, struct audio_encoding *);
163: int cs4281_set_params(void *, int, int, struct audio_params *,
164: struct audio_params *);
165: int cs4281_halt_output(void *);
166: int cs4281_halt_input(void *);
167: int cs4281_getdev(void *, struct audio_device *);
168: int cs4281_trigger_output(void *, void *, void *, int, void (*)(void *),
169: void *, struct audio_params *);
170: int cs4281_trigger_input(void *, void *, void *, int, void (*)(void *),
171: void *, struct audio_params *);
172: u_int8_t cs4281_sr2regval(int);
173: void cs4281_set_dac_rate(struct cs4281_softc *, int);
174: void cs4281_set_adc_rate(struct cs4281_softc *, int);
175: int cs4281_init(struct cs4281_softc *);
176:
177: int cs4281_open(void *, int);
178: void cs4281_close(void *);
179: int cs4281_round_blocksize(void *, int);
180: int cs4281_get_props(void *);
181: int cs4281_attach_codec(void *, struct ac97_codec_if *);
182: int cs4281_read_codec(void *, u_int8_t , u_int16_t *);
183: int cs4281_write_codec(void *, u_int8_t, u_int16_t);
184: void cs4281_reset_codec(void *);
185:
186: void cs4281_power(int, void *);
187:
188: int cs4281_mixer_set_port(void *, mixer_ctrl_t *);
189: int cs4281_mixer_get_port(void *, mixer_ctrl_t *);
190: int cs4281_query_devinfo(void *, mixer_devinfo_t *);
191: void *cs4281_malloc(void *, int, size_t, int, int);
192: size_t cs4281_round_buffersize(void *, int, size_t);
193: void cs4281_free(void *, void *, int);
194: paddr_t cs4281_mappage(void *, void *, off_t, int);
195:
196: int cs4281_allocmem(struct cs4281_softc *, size_t, int, int,
197: struct cs4281_dma *);
198: int cs4281_src_wait(struct cs4281_softc *);
199:
200: #if defined(CS4281_DEBUG)
201: #undef DPRINTF
202: #undef DPRINTFN
203: #define DPRINTF(x) if (cs4281_debug) printf x
204: #define DPRINTFN(n,x) if (cs4281_debug>(n)) printf x
205: int cs4281_debug = 5;
206: #else
207: #define DPRINTF(x)
208: #define DPRINTFN(n,x)
209: #endif
210:
211: struct audio_hw_if cs4281_hw_if = {
212: cs4281_open,
213: cs4281_close,
214: NULL,
215: cs4281_query_encoding,
216: cs4281_set_params,
217: cs4281_round_blocksize,
218: NULL,
219: NULL,
220: NULL,
221: NULL,
222: NULL,
223: cs4281_halt_output,
224: cs4281_halt_input,
225: NULL,
226: cs4281_getdev,
227: NULL,
228: cs4281_mixer_set_port,
229: cs4281_mixer_get_port,
230: cs4281_query_devinfo,
231: cs4281_malloc,
232: cs4281_free,
233: cs4281_round_buffersize,
234: NULL, /* cs4281_mappage, */
235: cs4281_get_props,
236: cs4281_trigger_output,
237: cs4281_trigger_input,
238: };
239:
240: #if NMIDI > 0
241: /* Midi Interface */
242: void cs4281_midi_close(void *);
243: void cs4281_midi_getinfo(void *, struct midi_info *);
244: int cs4281_midi_open(void *, int, void (*)(void *, int),
245: void (*)(void *), void *);
246: int cs4281_midi_output(void *, int);
247:
248: struct midi_hw_if cs4281_midi_hw_if = {
249: cs4281_midi_open,
250: cs4281_midi_close,
251: cs4281_midi_output,
252: cs4281_midi_getinfo,
253: 0,
254: };
255: #endif
256:
257: struct cfattach clct_ca = {
258: sizeof(struct cs4281_softc), cs4281_match, cs4281_attach
259: };
260:
261: struct cfdriver clct_cd = {
262: NULL, "clct", DV_DULL
263: };
264:
265: struct audio_device cs4281_device = {
266: "CS4281",
267: "",
268: "cs4281"
269: };
270:
271:
272: int
273: cs4281_match(parent, match, aux)
274: struct device *parent;
275: void *match;
276: void *aux;
277: {
278: struct pci_attach_args *pa = (struct pci_attach_args *)aux;
279:
280: if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_CIRRUS ||
281: PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_CIRRUS_CS4281)
282: return (0);
283:
284: return (1);
285: }
286:
287: void
288: cs4281_attach(parent, self, aux)
289: struct device *parent;
290: struct device *self;
291: void *aux;
292: {
293: struct cs4281_softc *sc = (struct cs4281_softc *)self;
294: struct pci_attach_args *pa = (struct pci_attach_args *)aux;
295: pci_chipset_tag_t pc = pa->pa_pc;
296: char const *intrstr;
297: pci_intr_handle_t ih;
298: int pci_pwrmgmt_cap_reg, pci_pwrmgmt_csr_reg;
299:
300: /* Map I/O register */
301: if (pci_mapreg_map(pa, CSCC_PCI_BA0,
302: PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0, &sc->ba0t,
303: &sc->ba0h, NULL, NULL, 0)) {
304: printf("%s: can't map BA0 space\n", sc->sc_dev.dv_xname);
305: return;
306: }
307: if (pci_mapreg_map(pa, CSCC_PCI_BA1,
308: PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0, &sc->ba1t,
309: &sc->ba1h, NULL, NULL, 0)) {
310: printf("%s: can't map BA1 space\n", sc->sc_dev.dv_xname);
311: return;
312: }
313:
314: sc->sc_dmatag = pa->pa_dmat;
315:
316: /*
317: * Set Power State D0.
318: * Without doing this, 0xffffffff is read from all registers after
319: * using Windows and rebooting into OpenBSD.
320: * On my IBM ThinkPad X20, it is set to D3 after using Windows2000.
321: */
322: if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_PWRMGMT,
323: &pci_pwrmgmt_cap_reg, 0)) {
324: pcireg_t reg;
325:
326: pci_pwrmgmt_csr_reg = pci_pwrmgmt_cap_reg + PCI_PMCSR;
327: reg = pci_conf_read(pa->pa_pc, pa->pa_tag, pci_pwrmgmt_csr_reg);
328: if ((reg & PCI_PMCSR_STATE_MASK) != PCI_PMCSR_STATE_D0) {
329: pci_conf_write(pc, pa->pa_tag, pci_pwrmgmt_csr_reg,
330: (reg & ~PCI_PMCSR_STATE_MASK) |
331: PCI_PMCSR_STATE_D0);
332: }
333: }
334:
335: /* Map and establish the interrupt. */
336: if (pci_intr_map(pa, &ih)) {
337: printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
338: return;
339: }
340: intrstr = pci_intr_string(pc, ih);
341:
342: sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, cs4281_intr, sc,
343: sc->sc_dev.dv_xname);
344: if (sc->sc_ih == NULL) {
345: printf("%s: couldn't establish interrupt",sc->sc_dev.dv_xname);
346: if (intrstr != NULL)
347: printf(" at %s", intrstr);
348: printf("\n");
349: return;
350: }
351: printf(" %s\n", intrstr);
352:
353: /*
354: * Sound System start-up
355: */
356: if (cs4281_init(sc) != 0)
357: return;
358:
359: sc->halt_input = cs4281_halt_input;
360: sc->halt_output = cs4281_halt_output;
361:
362: sc->dma_size = CS4281_BUFFER_SIZE / MAX_CHANNELS;
363: sc->dma_align = 0x10;
364: sc->hw_blocksize = sc->dma_size / 2;
365:
366: /* AC 97 attachment */
367: sc->host_if.arg = sc;
368: sc->host_if.attach = cs4281_attach_codec;
369: sc->host_if.read = cs4281_read_codec;
370: sc->host_if.write = cs4281_write_codec;
371: sc->host_if.reset = cs4281_reset_codec;
372: if (ac97_attach(&sc->host_if) != 0) {
373: printf("%s: ac97_attach failed\n", sc->sc_dev.dv_xname);
374: return;
375: }
376: audio_attach_mi(&cs4281_hw_if, sc, &sc->sc_dev);
377:
378: #if NMIDI > 0
379: midi_attach_mi(&cs4281_midi_hw_if, sc, &sc->sc_dev);
380: #endif
381:
382: sc->sc_suspend = PWR_RESUME;
383: sc->sc_powerhook = powerhook_establish(cs4281_power, sc);
384: }
385:
386:
387: int
388: cs4281_intr(p)
389: void *p;
390: {
391: struct cs4281_softc *sc = p;
392: u_int32_t intr, val;
393: char *empty_dma;
394:
395: intr = BA0READ4(sc, CS4281_HISR);
396: if (!(intr & (HISR_DMA0 | HISR_DMA1 | HISR_MIDI))) {
397: BA0WRITE4(sc, CS4281_HICR, HICR_IEV | HICR_CHGM);
398: return (0);
399: }
400: DPRINTF(("cs4281_intr:"));
401:
402: if (intr & HISR_DMA0)
403: val = BA0READ4(sc, CS4281_HDSR0); /* clear intr condition */
404: if (intr & HISR_DMA1)
405: val = BA0READ4(sc, CS4281_HDSR1); /* clear intr condition */
406: BA0WRITE4(sc, CS4281_HICR, HICR_IEV | HICR_CHGM);
407:
408: /* Playback Interrupt */
409: if (intr & HISR_DMA0) {
410: DPRINTF((" PB DMA 0x%x(%d)", (int)BA0READ4(sc, CS4281_DCA0),
411: (int)BA0READ4(sc, CS4281_DCC0)));
412: if (sc->sc_pintr) {
413: if ((sc->sc_pi%sc->sc_pcount) == 0)
414: sc->sc_pintr(sc->sc_parg);
415: } else {
416: printf("unexpected play intr\n");
417: }
418: /* copy buffer */
419: ++sc->sc_pi;
420: empty_dma = sc->sc_pdma->addr;
421: if (sc->sc_pi&1)
422: empty_dma += sc->hw_blocksize;
423: memcpy(empty_dma, sc->sc_pn, sc->hw_blocksize);
424: sc->sc_pn += sc->hw_blocksize;
425: if (sc->sc_pn >= sc->sc_pe)
426: sc->sc_pn = sc->sc_ps;
427: }
428: if (intr & HISR_DMA1) {
429: val = BA0READ4(sc, CS4281_HDSR1);
430: /* copy from dma */
431: DPRINTF((" CP DMA 0x%x(%d)", (int)BA0READ4(sc, CS4281_DCA1),
432: (int)BA0READ4(sc, CS4281_DCC1)));
433: ++sc->sc_ri;
434: empty_dma = sc->sc_rdma->addr;
435: if ((sc->sc_ri & 1) == 0)
436: empty_dma += sc->hw_blocksize;
437: memcpy(sc->sc_rn, empty_dma, sc->hw_blocksize);
438: if (sc->sc_rn >= sc->sc_re)
439: sc->sc_rn = sc->sc_rs;
440: if (sc->sc_rintr) {
441: if ((sc->sc_ri % sc->sc_rcount) == 0)
442: sc->sc_rintr(sc->sc_rarg);
443: } else {
444: printf("unexpected record intr\n");
445: }
446: }
447: DPRINTF(("\n"));
448: return (1);
449: }
450:
451: int
452: cs4281_query_encoding(addr, fp)
453: void *addr;
454: struct audio_encoding *fp;
455: {
456: switch (fp->index) {
457: case 0:
458: strlcpy(fp->name, AudioEulinear, sizeof fp->name);
459: fp->encoding = AUDIO_ENCODING_ULINEAR;
460: fp->precision = 8;
461: fp->flags = 0;
462: break;
463: case 1:
464: strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
465: fp->encoding = AUDIO_ENCODING_ULAW;
466: fp->precision = 8;
467: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
468: break;
469: case 2:
470: strlcpy(fp->name, AudioEalaw, sizeof fp->name);
471: fp->encoding = AUDIO_ENCODING_ALAW;
472: fp->precision = 8;
473: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
474: break;
475: case 3:
476: strlcpy(fp->name, AudioEslinear, sizeof fp->name);
477: fp->encoding = AUDIO_ENCODING_SLINEAR;
478: fp->precision = 8;
479: fp->flags = 0;
480: break;
481: case 4:
482: strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
483: fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
484: fp->precision = 16;
485: fp->flags = 0;
486: break;
487: case 5:
488: strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
489: fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
490: fp->precision = 16;
491: fp->flags = 0;
492: break;
493: case 6:
494: strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
495: fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
496: fp->precision = 16;
497: fp->flags = 0;
498: break;
499: case 7:
500: strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
501: fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
502: fp->precision = 16;
503: fp->flags = 0;
504: break;
505: default:
506: return EINVAL;
507: }
508: return (0);
509: }
510:
511: int
512: cs4281_set_params(addr, setmode, usemode, play, rec)
513: void *addr;
514: int setmode, usemode;
515: struct audio_params *play, *rec;
516: {
517: struct cs4281_softc *sc = addr;
518: struct audio_params *p;
519: int mode;
520:
521: for (mode = AUMODE_RECORD; mode != -1;
522: mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
523: if ((setmode & mode) == 0)
524: continue;
525:
526: p = mode == AUMODE_PLAY ? play : rec;
527:
528: if (p == play) {
529: DPRINTFN(5,("play: samp=%ld precision=%d channels=%d\n",
530: p->sample_rate, p->precision, p->channels));
531: if (p->sample_rate < 6023 || p->sample_rate > 48000 ||
532: (p->precision != 8 && p->precision != 16) ||
533: (p->channels != 1 && p->channels != 2)) {
534: return (EINVAL);
535: }
536: } else {
537: DPRINTFN(5,("rec: samp=%ld precision=%d channels=%d\n",
538: p->sample_rate, p->precision, p->channels));
539: if (p->sample_rate < 6023 || p->sample_rate > 48000 ||
540: (p->precision != 8 && p->precision != 16) ||
541: (p->channels != 1 && p->channels != 2)) {
542: return (EINVAL);
543: }
544: }
545: p->factor = 1;
546: p->sw_code = 0;
547:
548: switch (p->encoding) {
549: case AUDIO_ENCODING_SLINEAR_BE:
550: break;
551: case AUDIO_ENCODING_SLINEAR_LE:
552: break;
553: case AUDIO_ENCODING_ULINEAR_BE:
554: break;
555: case AUDIO_ENCODING_ULINEAR_LE:
556: break;
557: case AUDIO_ENCODING_ULAW:
558: if (mode == AUMODE_PLAY) {
559: p->sw_code = mulaw_to_slinear8;
560: } else {
561: p->sw_code = slinear8_to_mulaw;
562: }
563: break;
564: case AUDIO_ENCODING_ALAW:
565: if (mode == AUMODE_PLAY) {
566: p->sw_code = alaw_to_slinear8;
567: } else {
568: p->sw_code = slinear8_to_alaw;
569: }
570: break;
571: default:
572: return (EINVAL);
573: }
574: }
575:
576: /* set sample rate */
577: cs4281_set_dac_rate(sc, play->sample_rate);
578: cs4281_set_adc_rate(sc, rec->sample_rate);
579: return (0);
580: }
581:
582: int
583: cs4281_halt_output(addr)
584: void *addr;
585: {
586: struct cs4281_softc *sc = addr;
587:
588: BA0WRITE4(sc, CS4281_DCR0, BA0READ4(sc, CS4281_DCR0) | DCRn_MSK);
589: #ifdef DIAGNOSTIC
590: sc->sc_prun = 0;
591: #endif
592: return (0);
593: }
594:
595: int
596: cs4281_halt_input(addr)
597: void *addr;
598: {
599: struct cs4281_softc *sc = addr;
600:
601: BA0WRITE4(sc, CS4281_DCR1, BA0READ4(sc, CS4281_DCR1) | DCRn_MSK);
602: #ifdef DIAGNOSTIC
603: sc->sc_rrun = 0;
604: #endif
605: return (0);
606: }
607:
608: /* trivial */
609: int
610: cs4281_getdev(addr, retp)
611: void *addr;
612: struct audio_device *retp;
613: {
614: *retp = cs4281_device;
615: return (0);
616: }
617:
618:
619: int
620: cs4281_trigger_output(addr, start, end, blksize, intr, arg, param)
621: void *addr;
622: void *start, *end;
623: int blksize;
624: void (*intr)(void *);
625: void *arg;
626: struct audio_params *param;
627: {
628: struct cs4281_softc *sc = addr;
629: u_int32_t fmt=0;
630: struct cs4281_dma *p;
631: int dma_count;
632:
633: #ifdef DIAGNOSTIC
634: if (sc->sc_prun)
635: printf("cs4281_trigger_output: already running\n");
636: sc->sc_prun = 1;
637: #endif
638:
639: DPRINTF(("cs4281_trigger_output: sc=%p start=%p end=%p "
640: "blksize=%d intr=%p(%p)\n", addr, start, end, blksize, intr, arg));
641: sc->sc_pintr = intr;
642: sc->sc_parg = arg;
643:
644: /* stop playback DMA */
645: BA0WRITE4(sc, CS4281_DCR0, BA0READ4(sc, CS4281_DCR0) | DCRn_MSK);
646:
647: DPRINTF(("param: precision=%d factor=%d channels=%d encoding=%d\n",
648: param->precision, param->factor, param->channels,
649: param->encoding));
650: for (p = sc->sc_dmas; p != NULL && BUFADDR(p) != start; p = p->next)
651: ;
652: if (p == NULL) {
653: printf("cs4281_trigger_output: bad addr %p\n", start);
654: return (EINVAL);
655: }
656:
657: sc->sc_pcount = blksize / sc->hw_blocksize;
658: sc->sc_ps = (char *)start;
659: sc->sc_pe = (char *)end;
660: sc->sc_pdma = p;
661: sc->sc_pbuf = KERNADDR(p);
662: sc->sc_pi = 0;
663: sc->sc_pn = sc->sc_ps;
664: if (blksize >= sc->dma_size) {
665: sc->sc_pn = sc->sc_ps + sc->dma_size;
666: memcpy(sc->sc_pbuf, start, sc->dma_size);
667: ++sc->sc_pi;
668: } else {
669: sc->sc_pn = sc->sc_ps + sc->hw_blocksize;
670: memcpy(sc->sc_pbuf, start, sc->hw_blocksize);
671: }
672:
673: dma_count = sc->dma_size;
674: if (param->precision * param->factor != 8)
675: dma_count /= 2; /* 16 bit */
676: if (param->channels > 1)
677: dma_count /= 2; /* Stereo */
678:
679: DPRINTF(("cs4281_trigger_output: DMAADDR(p)=0x%x count=%d\n",
680: (int)DMAADDR(p), dma_count));
681: BA0WRITE4(sc, CS4281_DBA0, DMAADDR(p));
682: BA0WRITE4(sc, CS4281_DBC0, dma_count-1);
683:
684: /* set playback format */
685: fmt = BA0READ4(sc, CS4281_DMR0) & ~DMRn_FMTMSK;
686: if (param->precision * param->factor == 8)
687: fmt |= DMRn_SIZE8;
688: if (param->channels == 1)
689: fmt |= DMRn_MONO;
690: if (param->encoding == AUDIO_ENCODING_ULINEAR_BE ||
691: param->encoding == AUDIO_ENCODING_SLINEAR_BE)
692: fmt |= DMRn_BEND;
693: if (param->encoding == AUDIO_ENCODING_ULINEAR_BE ||
694: param->encoding == AUDIO_ENCODING_ULINEAR_LE)
695: fmt |= DMRn_USIGN;
696: BA0WRITE4(sc, CS4281_DMR0, fmt);
697:
698: /* set sample rate */
699: cs4281_set_dac_rate(sc, param->sample_rate);
700:
701: /* start DMA */
702: BA0WRITE4(sc, CS4281_DCR0, BA0READ4(sc, CS4281_DCR0) & ~DCRn_MSK);
703: /* Enable interrupts */
704: BA0WRITE4(sc, CS4281_HICR, HICR_IEV | HICR_CHGM);
705:
706: BA0WRITE4(sc, CS4281_PPRVC, 7);
707: BA0WRITE4(sc, CS4281_PPLVC, 7);
708:
709: DPRINTF(("HICR =0x%08x(expected 0x00000001)\n", BA0READ4(sc, CS4281_HICR)));
710: DPRINTF(("HIMR =0x%08x(expected 0x00f0fc3f)\n", BA0READ4(sc, CS4281_HIMR)));
711: DPRINTF(("DMR0 =0x%08x(expected 0x2???0018)\n", BA0READ4(sc, CS4281_DMR0)));
712: DPRINTF(("DCR0 =0x%08x(expected 0x00030000)\n", BA0READ4(sc, CS4281_DCR0)));
713: DPRINTF(("FCR0 =0x%08x(expected 0x81000f00)\n", BA0READ4(sc, CS4281_FCR0)));
714: DPRINTF(("DACSR=0x%08x(expected 1 for 44kHz 5 for 8kHz)\n",
715: BA0READ4(sc, CS4281_DACSR)));
716: DPRINTF(("SRCSA=0x%08x(expected 0x0b0a0100)\n", BA0READ4(sc, CS4281_SRCSA)));
717: DPRINTF(("SSPM&SSPM_PSRCEN =0x%08x(expected 0x00000010)\n",
718: BA0READ4(sc, CS4281_SSPM) & SSPM_PSRCEN));
719:
720: return (0);
721: }
722:
723: int
724: cs4281_trigger_input(addr, start, end, blksize, intr, arg, param)
725: void *addr;
726: void *start, *end;
727: int blksize;
728: void (*intr)(void *);
729: void *arg;
730: struct audio_params *param;
731: {
732: struct cs4281_softc *sc = addr;
733: struct cs4281_dma *p;
734: u_int32_t fmt=0;
735: int dma_count;
736:
737: printf("cs4281_trigger_input: not implemented yet\n");
738: #ifdef DIAGNOSTIC
739: if (sc->sc_rrun)
740: printf("cs4281_trigger_input: already running\n");
741: sc->sc_rrun = 1;
742: #endif
743: DPRINTF(("cs4281_trigger_input: sc=%p start=%p end=%p "
744: "blksize=%d intr=%p(%p)\n", addr, start, end, blksize, intr, arg));
745: sc->sc_rintr = intr;
746: sc->sc_rarg = arg;
747:
748: /* stop recording DMA */
749: BA0WRITE4(sc, CS4281_DCR1, BA0READ4(sc, CS4281_DCR1) | DCRn_MSK);
750:
751: for (p = sc->sc_dmas; p && BUFADDR(p) != start; p = p->next)
752: ;
753: if (!p) {
754: printf("cs4281_trigger_input: bad addr %p\n", start);
755: return (EINVAL);
756: }
757:
758: sc->sc_rcount = blksize / sc->hw_blocksize;
759: sc->sc_rs = (char *)start;
760: sc->sc_re = (char *)end;
761: sc->sc_rdma = p;
762: sc->sc_rbuf = KERNADDR(p);
763: sc->sc_ri = 0;
764: sc->sc_rn = sc->sc_rs;
765:
766: dma_count = sc->dma_size;
767: if (param->precision * param->factor == 8)
768: dma_count /= 2;
769: if (param->channels > 1)
770: dma_count /= 2;
771:
772: DPRINTF(("cs4281_trigger_input: DMAADDR(p)=0x%x count=%d\n",
773: (int)DMAADDR(p), dma_count));
774: BA0WRITE4(sc, CS4281_DBA1, DMAADDR(p));
775: BA0WRITE4(sc, CS4281_DBC1, dma_count-1);
776:
777: /* set recording format */
778: fmt = BA0READ4(sc, CS4281_DMR1) & ~DMRn_FMTMSK;
779: if (param->precision * param->factor == 8)
780: fmt |= DMRn_SIZE8;
781: if (param->channels == 1)
782: fmt |= DMRn_MONO;
783: if (param->encoding == AUDIO_ENCODING_ULINEAR_BE ||
784: param->encoding == AUDIO_ENCODING_SLINEAR_BE)
785: fmt |= DMRn_BEND;
786: if (param->encoding == AUDIO_ENCODING_ULINEAR_BE ||
787: param->encoding == AUDIO_ENCODING_ULINEAR_LE)
788: fmt |= DMRn_USIGN;
789: BA0WRITE4(sc, CS4281_DMR1, fmt);
790:
791: /* set sample rate */
792: cs4281_set_adc_rate(sc, param->sample_rate);
793:
794: /* Start DMA */
795: BA0WRITE4(sc, CS4281_DCR1, BA0READ4(sc, CS4281_DCR1) & ~DCRn_MSK);
796: /* Enable interrupts */
797: BA0WRITE4(sc, CS4281_HICR, HICR_IEV | HICR_CHGM);
798:
799: DPRINTF(("HICR=0x%08x\n", BA0READ4(sc, CS4281_HICR)));
800: DPRINTF(("HIMR=0x%08x\n", BA0READ4(sc, CS4281_HIMR)));
801: DPRINTF(("DMR1=0x%08x\n", BA0READ4(sc, CS4281_DMR1)));
802: DPRINTF(("DCR1=0x%08x\n", BA0READ4(sc, CS4281_DCR1)));
803:
804: return (0);
805: }
806:
807: /* convert sample rate to register value */
808: u_int8_t
809: cs4281_sr2regval(rate)
810: int rate;
811: {
812: u_int8_t retval;
813:
814: /* We don't have to change here. but anyway ... */
815: if (rate > 48000)
816: rate = 48000;
817: if (rate < 6023)
818: rate = 6023;
819:
820: switch (rate) {
821: case 8000:
822: retval = 5;
823: break;
824: case 11025:
825: retval = 4;
826: break;
827: case 16000:
828: retval = 3;
829: break;
830: case 22050:
831: retval = 2;
832: break;
833: case 44100:
834: retval = 1;
835: break;
836: case 48000:
837: retval = 0;
838: break;
839: default:
840: retval = 1536000/rate; /* == 24576000/(rate*16) */
841: }
842: return (retval);
843: }
844:
845:
846: void
847: cs4281_set_dac_rate(sc, rate)
848: struct cs4281_softc *sc;
849: int rate;
850: {
851: BA0WRITE4(sc, CS4281_DACSR, cs4281_sr2regval(rate));
852: }
853:
854: void
855: cs4281_set_adc_rate(sc, rate)
856: struct cs4281_softc *sc;
857: int rate;
858: {
859: BA0WRITE4(sc, CS4281_ADCSR, cs4281_sr2regval(rate));
860: }
861:
862: int
863: cs4281_init(sc)
864: struct cs4281_softc *sc;
865: {
866: int n;
867: u_int16_t data;
868: u_int32_t dat32;
869:
870: /* set "Configuration Write Protect" register to
871: * 0x4281 to allow to write */
872: BA0WRITE4(sc, CS4281_CWPR, 0x4281);
873:
874: /*
875: * Unset "Full Power-Down bit of Extended PCI Power Management
876: * Control" register to release the reset state.
877: */
878: dat32 = BA0READ4(sc, CS4281_EPPMC);
879: if (dat32 & EPPMC_FPDN)
880: BA0WRITE4(sc, CS4281_EPPMC, dat32 & ~EPPMC_FPDN);
881:
882: /* Start PLL out in known state */
883: BA0WRITE4(sc, CS4281_CLKCR1, 0);
884: /* Start serial ports out in known state */
885: BA0WRITE4(sc, CS4281_SERMC, 0);
886:
887: /* Reset codec */
888: BA0WRITE4(sc, CS4281_ACCTL, 0);
889: delay(50); /* delay 50us */
890:
891: BA0WRITE4(sc, CS4281_SPMC, 0);
892: delay(100); /* delay 100us */
893: BA0WRITE4(sc, CS4281_SPMC, SPMC_RSTN);
894: #if defined(ENABLE_SECONDARY_CODEC)
895: BA0WRITE4(sc, CS4281_SPMC, SPMC_RSTN | SPCM_ASDIN2E);
896: BA0WRITE4(sc, CS4281_SERMC, SERMC_TCID);
897: #endif
898: delay(50000); /* XXX: delay 50ms */
899:
900: /* Turn on Sound System clocks based on ABITCLK */
901: BA0WRITE4(sc, CS4281_CLKCR1, CLKCR1_DLLP);
902: delay(50000); /* XXX: delay 50ms */
903: BA0WRITE4(sc, CS4281_CLKCR1, CLKCR1_SWCE | CLKCR1_DLLP);
904:
905: /* Set enables for sections that are needed in the SSPM registers */
906: BA0WRITE4(sc, CS4281_SSPM,
907: SSPM_MIXEN | /* Mixer */
908: SSPM_CSRCEN | /* Capture SRC */
909: SSPM_PSRCEN | /* Playback SRC */
910: SSPM_JSEN | /* Joystick */
911: SSPM_ACLEN | /* AC LINK */
912: SSPM_FMEN /* FM */
913: );
914:
915: /* Wait for clock stabilization */
916: n = 0;
917: while ((BA0READ4(sc, CS4281_CLKCR1)& (CLKCR1_DLLRDY | CLKCR1_CLKON))
918: != (CLKCR1_DLLRDY | CLKCR1_CLKON)) {
919: delay(100);
920: if (++n > 1000)
921: return (-1);
922: }
923:
924: /* Enable ASYNC generation */
925: BA0WRITE4(sc, CS4281_ACCTL, ACCTL_ESYN);
926:
927: /* Wait for Codec ready. Linux driver wait 50ms here */
928: n = 0;
929: while((BA0READ4(sc, CS4281_ACSTS) & ACSTS_CRDY) == 0) {
930: delay(100);
931: if (++n > 1000)
932: return (-1);
933: }
934:
935: #if defined(ENABLE_SECONDARY_CODEC)
936: /* secondary codec ready*/
937: n = 0;
938: while((BA0READ4(sc, CS4281_ACSTS2) & ACSTS2_CRDY2) == 0) {
939: delay(100);
940: if (++n > 1000)
941: return (-1);
942: }
943: #endif
944:
945: /* Set the serial timing configuration */
946: /* XXX: undocumented but the Linux driver do this */
947: BA0WRITE4(sc, CS4281_SERMC, SERMC_PTCAC97);
948:
949: /* Wait for Codec ready signal */
950: n = 0;
951: do {
952: delay(1000);
953: if (++n > 1000) {
954: printf("%s: Timeout waiting for Codec ready\n",
955: sc->sc_dev.dv_xname);
956: return -1;
957: }
958: dat32 = BA0READ4(sc, CS4281_ACSTS) & ACSTS_CRDY;
959: } while (dat32 == 0);
960:
961: /* Enable Valid Frame output on ASDOUT */
962: BA0WRITE4(sc, CS4281_ACCTL, ACCTL_ESYN | ACCTL_VFRM);
963:
964: /* Wait until Codec Calibration is finished. Codec register 26h */
965: n = 0;
966: do {
967: delay(1);
968: if (++n > 1000) {
969: printf("%s: Timeout waiting for Codec calibration\n",
970: sc->sc_dev.dv_xname);
971: return -1;
972: }
973: cs4281_read_codec(sc, AC97_REG_POWER, &data);
974: } while ((data & 0x0f) != 0x0f);
975:
976: /* Set the serial timing configuration again */
977: /* XXX: undocumented but the Linux driver do this */
978: BA0WRITE4(sc, CS4281_SERMC, SERMC_PTCAC97);
979:
980: /* Wait until we've sampled input slots 3 & 4 as valid */
981: n = 0;
982: do {
983: delay(1000);
984: if (++n > 1000) {
985: printf("%s: Timeout waiting for sampled input slots as valid\n",
986: sc->sc_dev.dv_xname);
987: return -1;
988: }
989: dat32 = BA0READ4(sc, CS4281_ACISV) & (ACISV_ISV3 | ACISV_ISV4);
990: } while (dat32 != (ACISV_ISV3 | ACISV_ISV4));
991:
992: /* Start digital data transfer of audio data to the codec */
993: BA0WRITE4(sc, CS4281_ACOSV, (ACOSV_SLV3 | ACOSV_SLV4));
994:
995: cs4281_write_codec(sc, AC97_REG_HEADPHONE_VOLUME, 0);
996: cs4281_write_codec(sc, AC97_REG_MASTER_VOLUME, 0);
997:
998: /* Power on the DAC */
999: cs4281_read_codec(sc, AC97_REG_POWER, &data);
1000: cs4281_write_codec(sc, AC97_REG_POWER, data &= 0xfdff);
1001:
1002: /* Wait until we sample a DAC ready state.
1003: * Not documented, but Linux driver does.
1004: */
1005: for (n = 0; n < 32; ++n) {
1006: delay(1000);
1007: cs4281_read_codec(sc, AC97_REG_POWER, &data);
1008: if (data & 0x02)
1009: break;
1010: }
1011:
1012: /* Power on the ADC */
1013: cs4281_read_codec(sc, AC97_REG_POWER, &data);
1014: cs4281_write_codec(sc, AC97_REG_POWER, data &= 0xfeff);
1015:
1016: /* Wait until we sample ADC ready state.
1017: * Not documented, but Linux driver does.
1018: */
1019: for (n = 0; n < 32; ++n) {
1020: delay(1000);
1021: cs4281_read_codec(sc, AC97_REG_POWER, &data);
1022: if (data & 0x01)
1023: break;
1024: }
1025:
1026: #if 0
1027: /* Initialize SSCR register features */
1028: /* XXX: hardware volume setting */
1029: BA0WRITE4(sc, CS4281_SSCR, ~SSCR_HVC); /* disable HW volume setting */
1030: #endif
1031:
1032: /* disable Sound Blaster Pro emulation */
1033: /* XXX:
1034: * Cannot set since the documents does not describe which bit is
1035: * correspond to SSCR_SB. Since the reset value of SSCR is 0,
1036: * we can ignore it.*/
1037: #if 0
1038: BA0WRITE4(sc, CS4281_SSCR, SSCR_SB);
1039: #endif
1040:
1041: /* map AC97 PCM playback to DMA Channel 0 */
1042: /* Reset FEN bit to setup first */
1043: BA0WRITE4(sc, CS4281_FCR0, (BA0READ4(sc,CS4281_FCR0) & ~FCRn_FEN));
1044: /*
1045: *| RS[4:0]/| |
1046: *| LS[4:0] | AC97 | Slot Function
1047: *|---------+--------+--------------------
1048: *| 0 | 3 | Left PCM Playback
1049: *| 1 | 4 | Right PCM Playback
1050: *| 2 | 5 | Phone Line 1 DAC
1051: *| 3 | 6 | Center PCM Playback
1052: *....
1053: * quoted from Table 29(p109)
1054: */
1055: dat32 = 0x01 << 24 | /* RS[4:0] = 1 see above */
1056: 0x00 << 16 | /* LS[4:0] = 0 see above */
1057: 0x0f << 8 | /* SZ[6:0] = 15 size of buffer */
1058: 0x00 << 0 ; /* OF[6:0] = 0 offset */
1059: BA0WRITE4(sc, CS4281_FCR0, dat32);
1060: BA0WRITE4(sc, CS4281_FCR0, dat32 | FCRn_FEN);
1061:
1062: /* map AC97 PCM record to DMA Channel 1 */
1063: /* Reset FEN bit to setup first */
1064: BA0WRITE4(sc, CS4281_FCR1, (BA0READ4(sc,CS4281_FCR1) & ~FCRn_FEN));
1065: /*
1066: *| RS[4:0]/|
1067: *| LS[4:0] | AC97 | Slot Function
1068: *|---------+------+-------------------
1069: *| 10 | 3 | Left PCM Record
1070: *| 11 | 4 | Right PCM Record
1071: *| 12 | 5 | Phone Line 1 ADC
1072: *| 13 | 6 | Mic ADC
1073: *....
1074: * quoted from Table 30(p109)
1075: */
1076: dat32 = 0x0b << 24 | /* RS[4:0] = 11 See above */
1077: 0x0a << 16 | /* LS[4:0] = 10 See above */
1078: 0x0f << 8 | /* SZ[6:0] = 15 Size of buffer */
1079: 0x10 << 0 ; /* OF[6:0] = 16 offset */
1080:
1081: /* XXX: I cannot understand why FCRn_PSH is needed here. */
1082: BA0WRITE4(sc, CS4281_FCR1, dat32 | FCRn_PSH);
1083: BA0WRITE4(sc, CS4281_FCR1, dat32 | FCRn_FEN);
1084:
1085: #if 0
1086: /* Disable DMA Channel 2, 3 */
1087: BA0WRITE4(sc, CS4281_FCR2, (BA0READ4(sc,CS4281_FCR2) & ~FCRn_FEN));
1088: BA0WRITE4(sc, CS4281_FCR3, (BA0READ4(sc,CS4281_FCR3) & ~FCRn_FEN));
1089: #endif
1090:
1091: /* Set the SRC Slot Assignment accordingly */
1092: /*| PLSS[4:0]/
1093: *| PRSS[4:0] | AC97 | Slot Function
1094: *|-----------+------+----------------
1095: *| 0 | 3 | Left PCM Playback
1096: *| 1 | 4 | Right PCM Playback
1097: *| 2 | 5 | phone line 1 DAC
1098: *| 3 | 6 | Center PCM Playback
1099: *| 4 | 7 | Left Surround PCM Playback
1100: *| 5 | 8 | Right Surround PCM Playback
1101: *......
1102: *
1103: *| CLSS[4:0]/
1104: *| CRSS[4:0] | AC97 | Codec |Slot Function
1105: *|-----------+------+-------+-----------------
1106: *| 10 | 3 |Primary| Left PCM Record
1107: *| 11 | 4 |Primary| Right PCM Record
1108: *| 12 | 5 |Primary| Phone Line 1 ADC
1109: *| 13 | 6 |Primary| Mic ADC
1110: *|.....
1111: *| 20 | 3 | Sec. | Left PCM Record
1112: *| 21 | 4 | Sec. | Right PCM Record
1113: *| 22 | 5 | Sec. | Phone Line 1 ADC
1114: *| 23 | 6 | Sec. | Mic ADC
1115: */
1116: dat32 = 0x0b << 24 | /* CRSS[4:0] Right PCM Record(primary) */
1117: 0x0a << 16 | /* CLSS[4:0] Left PCM Record(primary) */
1118: 0x01 << 8 | /* PRSS[4:0] Right PCM Playback */
1119: 0x00 << 0; /* PLSS[4:0] Left PCM Playback */
1120: BA0WRITE4(sc, CS4281_SRCSA, dat32);
1121:
1122: /* Set interrupt to occurred at Half and Full terminal
1123: * count interrupt enable for DMA channel 0 and 1.
1124: * To keep DMA stop, set MSK.
1125: */
1126: dat32 = DCRn_HTCIE | DCRn_TCIE | DCRn_MSK;
1127: BA0WRITE4(sc, CS4281_DCR0, dat32);
1128: BA0WRITE4(sc, CS4281_DCR1, dat32);
1129:
1130: /* Set Auto-Initialize Control enable */
1131: BA0WRITE4(sc, CS4281_DMR0,
1132: DMRn_DMA | DMRn_AUTO | DMRn_TR_READ);
1133: BA0WRITE4(sc, CS4281_DMR1,
1134: DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE);
1135:
1136: /* Clear DMA Mask in HIMR */
1137: dat32 = BA0READ4(sc, CS4281_HIMR) & 0xfffbfcff;
1138: BA0WRITE4(sc, CS4281_HIMR, dat32);
1139: return (0);
1140: }
1141:
1142: void
1143: cs4281_power(why, v)
1144: int why;
1145: void *v;
1146: {
1147: struct cs4281_softc *sc = (struct cs4281_softc *)v;
1148: int i;
1149:
1150: DPRINTF(("%s: cs4281_power why=%d\n", sc->sc_dev.dv_xname, why));
1151: if (why != PWR_RESUME) {
1152: sc->sc_suspend = why;
1153:
1154: cs4281_halt_output(sc);
1155: cs4281_halt_input(sc);
1156: /* Save AC97 registers */
1157: for (i = 1; i <= CS4281_SAVE_REG_MAX; i++) {
1158: if (i == 0x04) /* AC97_REG_MASTER_TONE */
1159: continue;
1160: cs4281_read_codec(sc, 2*i, &sc->ac97_reg[i>>1]);
1161: }
1162: /* should I powerdown here ? */
1163: cs4281_write_codec(sc, AC97_REG_POWER, CS4281_POWER_DOWN_ALL);
1164: } else {
1165: if (sc->sc_suspend == PWR_RESUME) {
1166: printf("cs4281_power: odd, resume without suspend.\n");
1167: sc->sc_suspend = why;
1168: return;
1169: }
1170: sc->sc_suspend = why;
1171: cs4281_init(sc);
1172: cs4281_reset_codec(sc);
1173:
1174: /* restore ac97 registers */
1175: for (i = 1; i <= CS4281_SAVE_REG_MAX; i++) {
1176: if (i == 0x04) /* AC97_REG_MASTER_TONE */
1177: continue;
1178: cs4281_write_codec(sc, 2*i, sc->ac97_reg[i>>1]);
1179: }
1180: }
1181: }
1182:
1183: void
1184: cs4281_reset_codec(void *addr)
1185: {
1186: struct cs4281_softc *sc;
1187: u_int16_t data;
1188: u_int32_t dat32;
1189: int n;
1190:
1191: sc = addr;
1192:
1193: DPRINTFN(3,("cs4281_reset_codec\n"));
1194:
1195: /* Reset codec */
1196: BA0WRITE4(sc, CS4281_ACCTL, 0);
1197: delay(50); /* delay 50us */
1198:
1199: BA0WRITE4(sc, CS4281_SPMC, 0);
1200: delay(100); /* delay 100us */
1201: BA0WRITE4(sc, CS4281_SPMC, SPMC_RSTN);
1202: #if defined(ENABLE_SECONDARY_CODEC)
1203: BA0WRITE4(sc, CS4281_SPMC, SPMC_RSTN | SPCM_ASDIN2E);
1204: BA0WRITE4(sc, CS4281_SERMC, SERMC_TCID);
1205: #endif
1206: delay(50000); /* XXX: delay 50ms */
1207:
1208: /* Enable ASYNC generation */
1209: BA0WRITE4(sc, CS4281_ACCTL, ACCTL_ESYN);
1210:
1211: /* Wait for Codec ready. Linux driver wait 50ms here */
1212: n = 0;
1213: while((BA0READ4(sc, CS4281_ACSTS) & ACSTS_CRDY) == 0) {
1214: delay(100);
1215: if (++n > 1000) {
1216: printf("reset_codec: AC97 codec ready timeout\n");
1217: return;
1218: }
1219: }
1220: #if defined(ENABLE_SECONDARY_CODEC)
1221: /* secondary codec ready*/
1222: n = 0;
1223: while((BA0READ4(sc, CS4281_ACSTS2) & ACSTS2_CRDY2) == 0) {
1224: delay(100);
1225: if (++n > 1000)
1226: return;
1227: }
1228: #endif
1229: /* Set the serial timing configuration */
1230: /* XXX: undocumented but the Linux driver do this */
1231: BA0WRITE4(sc, CS4281_SERMC, SERMC_PTCAC97);
1232:
1233: /* Wait for Codec ready signal */
1234: n = 0;
1235: do {
1236: delay(1000);
1237: if (++n > 1000) {
1238: printf("%s: Timeout waiting for Codec ready\n",
1239: sc->sc_dev.dv_xname);
1240: return;
1241: }
1242: dat32 = BA0READ4(sc, CS4281_ACSTS) & ACSTS_CRDY;
1243: } while (dat32 == 0);
1244:
1245: /* Enable Valid Frame output on ASDOUT */
1246: BA0WRITE4(sc, CS4281_ACCTL, ACCTL_ESYN | ACCTL_VFRM);
1247:
1248: /* Wait until Codec Calibration is finished. Codec register 26h */
1249: n = 0;
1250: do {
1251: delay(1);
1252: if (++n > 1000) {
1253: printf("%s: Timeout waiting for Codec calibration\n",
1254: sc->sc_dev.dv_xname);
1255: return ;
1256: }
1257: cs4281_read_codec(sc, AC97_REG_POWER, &data);
1258: } while ((data & 0x0f) != 0x0f);
1259:
1260: /* Set the serial timing configuration again */
1261: /* XXX: undocumented but the Linux driver do this */
1262: BA0WRITE4(sc, CS4281_SERMC, SERMC_PTCAC97);
1263:
1264: /* Wait until we've sampled input slots 3 & 4 as valid */
1265: n = 0;
1266: do {
1267: delay(1000);
1268: if (++n > 1000) {
1269: printf("%s: Timeout waiting for sampled input slots as valid\n",
1270: sc->sc_dev.dv_xname);
1271: return;
1272: }
1273: dat32 = BA0READ4(sc, CS4281_ACISV) & (ACISV_ISV3 | ACISV_ISV4) ;
1274: } while (dat32 != (ACISV_ISV3 | ACISV_ISV4));
1275:
1276: /* Start digital data transfer of audio data to the codec */
1277: BA0WRITE4(sc, CS4281_ACOSV, (ACOSV_SLV3 | ACOSV_SLV4));
1278: }
1279:
1280: int
1281: cs4281_open(void *addr, int flags)
1282: {
1283: return (0);
1284: }
1285:
1286: void
1287: cs4281_close(void *addr)
1288: {
1289: struct cs4281_softc *sc;
1290:
1291: sc = addr;
1292:
1293: (*sc->halt_output)(sc);
1294: (*sc->halt_input)(sc);
1295:
1296: sc->sc_pintr = 0;
1297: sc->sc_rintr = 0;
1298: }
1299:
1300: int
1301: cs4281_round_blocksize(void *addr, int blk)
1302: {
1303: struct cs4281_softc *sc;
1304: int retval;
1305:
1306: DPRINTFN(5,("cs4281_round_blocksize blk=%d -> ", blk));
1307:
1308: sc=addr;
1309: if (blk < sc->hw_blocksize)
1310: retval = sc->hw_blocksize;
1311: else
1312: retval = blk & -(sc->hw_blocksize);
1313:
1314: DPRINTFN(5,("%d\n", retval));
1315:
1316: return (retval);
1317: }
1318:
1319: int
1320: cs4281_mixer_set_port(void *addr, mixer_ctrl_t *cp)
1321: {
1322: struct cs4281_softc *sc;
1323: int val;
1324:
1325: sc = addr;
1326: val = sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp);
1327: DPRINTFN(3,("mixer_set_port: val=%d\n", val));
1328: return (val);
1329: }
1330:
1331: int
1332: cs4281_mixer_get_port(void *addr, mixer_ctrl_t *cp)
1333: {
1334: struct cs4281_softc *sc;
1335:
1336: sc = addr;
1337: return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp));
1338: }
1339:
1340:
1341: int
1342: cs4281_query_devinfo(void *addr, mixer_devinfo_t *dip)
1343: {
1344: struct cs4281_softc *sc;
1345:
1346: sc = addr;
1347: return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip));
1348: }
1349:
1350: void *
1351: cs4281_malloc(void *addr, int direction, size_t size, int pool, int flags)
1352: {
1353: struct cs4281_softc *sc;
1354: struct cs4281_dma *p;
1355: int error;
1356:
1357: sc = addr;
1358:
1359: p = malloc(sizeof(*p), pool, flags);
1360: if (!p)
1361: return (0);
1362:
1363: error = cs4281_allocmem(sc, size, pool, flags, p);
1364:
1365: if (error) {
1366: free(p, pool);
1367: return (0);
1368: }
1369:
1370: p->next = sc->sc_dmas;
1371: sc->sc_dmas = p;
1372: return (BUFADDR(p));
1373: }
1374:
1375:
1376:
1377: void
1378: cs4281_free(void *addr, void *ptr, int pool)
1379: {
1380: struct cs4281_softc *sc;
1381: struct cs4281_dma **pp, *p;
1382:
1383: sc = addr;
1384: for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) {
1385: if (BUFADDR(p) == ptr) {
1386: bus_dmamap_unload(sc->sc_dmatag, p->map);
1387: bus_dmamap_destroy(sc->sc_dmatag, p->map);
1388: bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size);
1389: bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
1390: free(p->dum, pool);
1391: *pp = p->next;
1392: free(p, pool);
1393: return;
1394: }
1395: }
1396: }
1397:
1398: size_t
1399: cs4281_round_buffersize(void *addr, int direction, size_t size)
1400: {
1401: /* The real dma buffersize are 4KB for CS4280
1402: * and 64kB/MAX_CHANNELS for CS4281.
1403: * But they are too small for high quality audio,
1404: * let the upper layer(audio) use a larger buffer.
1405: * (originally suggested by Lennart Augustsson.)
1406: */
1407: return (size);
1408: }
1409:
1410: paddr_t
1411: cs4281_mappage(void *addr, void *mem, off_t off, int prot)
1412: {
1413: struct cs4281_softc *sc;
1414: struct cs4281_dma *p;
1415:
1416: sc = addr;
1417: if (off < 0)
1418: return -1;
1419:
1420: for (p = sc->sc_dmas; p && BUFADDR(p) != mem; p = p->next)
1421: ;
1422:
1423: if (!p) {
1424: DPRINTF(("cs4281_mappage: bad buffer address\n"));
1425: return (-1);
1426: }
1427:
1428: return (bus_dmamem_mmap(sc->sc_dmatag, p->segs, p->nsegs, off, prot,
1429: BUS_DMA_WAITOK));
1430: }
1431:
1432:
1433: int
1434: cs4281_get_props(void *addr)
1435: {
1436: int retval;
1437:
1438: retval = AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
1439: #ifdef MMAP_READY
1440: retval |= AUDIO_PROP_MMAP;
1441: #endif
1442: return (retval);
1443: }
1444:
1445: /* AC97 */
1446: int
1447: cs4281_attach_codec(void *addr, struct ac97_codec_if *codec_if)
1448: {
1449: struct cs4281_softc *sc;
1450:
1451: DPRINTF(("cs4281_attach_codec:\n"));
1452: sc = addr;
1453: sc->codec_if = codec_if;
1454: return (0);
1455: }
1456:
1457:
1458: int
1459: cs4281_read_codec(void *addr, u_int8_t ac97_addr, u_int16_t *ac97_data)
1460: {
1461: struct cs4281_softc *sc;
1462: u_int32_t acctl;
1463: int n;
1464:
1465: sc = addr;
1466:
1467: DPRINTFN(5,("read_codec: add=0x%02x ", ac97_addr));
1468: /*
1469: * Make sure that there is not data sitting around from a preivous
1470: * uncompleted access.
1471: */
1472: BA0READ4(sc, CS4281_ACSDA);
1473:
1474: /* Set up AC97 control registers. */
1475: BA0WRITE4(sc, CS4281_ACCAD, ac97_addr);
1476: BA0WRITE4(sc, CS4281_ACCDA, 0);
1477:
1478: acctl = ACCTL_ESYN | ACCTL_VFRM | ACCTL_CRW | ACCTL_DCV;
1479: BA0WRITE4(sc, CS4281_ACCTL, acctl);
1480:
1481: if (cs4281_src_wait(sc) < 0) {
1482: printf("%s: AC97 read prob. (DCV!=0) for add=0x%0x\n",
1483: sc->sc_dev.dv_xname, ac97_addr);
1484: return 1;
1485: }
1486:
1487: /* wait for valid status bit is active */
1488: n = 0;
1489: while ((BA0READ4(sc, CS4281_ACSTS) & ACSTS_VSTS) == 0) {
1490: delay(1);
1491: while (++n > 1000) {
1492: printf("%s: AC97 read fail (VSTS==0) for add=0x%0x\n",
1493: sc->sc_dev.dv_xname, ac97_addr);
1494: return 1;
1495: }
1496: }
1497: *ac97_data = BA0READ4(sc, CS4281_ACSDA);
1498: DPRINTFN(5,("data=0x%04x\n", *ac97_data));
1499: return (0);
1500: }
1501:
1502: int
1503: cs4281_write_codec(void *addr, u_int8_t ac97_addr, u_int16_t ac97_data)
1504: {
1505: struct cs4281_softc *sc;
1506: u_int32_t acctl;
1507:
1508: sc = addr;
1509:
1510: DPRINTFN(5,("write_codec: add=0x%02x data=0x%04x\n", ac97_addr, ac97_data));
1511: BA0WRITE4(sc, CS4281_ACCAD, ac97_addr);
1512: BA0WRITE4(sc, CS4281_ACCDA, ac97_data);
1513:
1514: acctl = ACCTL_ESYN | ACCTL_VFRM | ACCTL_DCV;
1515: BA0WRITE4(sc, CS4281_ACCTL, acctl);
1516:
1517: if (cs4281_src_wait(sc) < 0) {
1518: printf("%s: AC97 write fail (DCV!=0) for add=0x%02x data="
1519: "0x%04x\n", sc->sc_dev.dv_xname, ac97_addr, ac97_data);
1520: return (1);
1521: }
1522: return (0);
1523: }
1524:
1525: int
1526: cs4281_allocmem(struct cs4281_softc *sc, size_t size, int pool, int flags,
1527: struct cs4281_dma *p)
1528: {
1529: int error;
1530: size_t align;
1531:
1532: align = sc->dma_align;
1533: p->size = sc->dma_size;
1534: /* allocate memory for upper audio driver */
1535: p->dum = malloc(size, pool, flags);
1536: if (!p->dum)
1537: return (1);
1538: error = bus_dmamem_alloc(sc->sc_dmatag, p->size, align, 0,
1539: p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
1540: &p->nsegs, BUS_DMA_NOWAIT);
1541: if (error) {
1542: printf("%s: unable to allocate dma. error=%d\n",
1543: sc->sc_dev.dv_xname, error);
1544: return (error);
1545: }
1546:
1547: error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size,
1548: &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
1549: if (error) {
1550: printf("%s: unable to map dma, error=%d\n",
1551: sc->sc_dev.dv_xname, error);
1552: goto free;
1553: }
1554:
1555: error = bus_dmamap_create(sc->sc_dmatag, p->size, 1, p->size,
1556: 0, BUS_DMA_NOWAIT, &p->map);
1557: if (error) {
1558: printf("%s: unable to create dma map, error=%d\n",
1559: sc->sc_dev.dv_xname, error);
1560: goto unmap;
1561: }
1562:
1563: error = bus_dmamap_load(sc->sc_dmatag, p->map, p->addr, p->size, NULL,
1564: BUS_DMA_NOWAIT);
1565: if (error) {
1566: printf("%s: unable to load dma map, error=%d\n",
1567: sc->sc_dev.dv_xname, error);
1568: goto destroy;
1569: }
1570: return (0);
1571:
1572: destroy:
1573: bus_dmamap_destroy(sc->sc_dmatag, p->map);
1574: unmap:
1575: bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size);
1576: free:
1577: bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
1578: return (error);
1579: }
1580:
1581:
1582: int
1583: cs4281_src_wait(sc)
1584: struct cs4281_softc *sc;
1585: {
1586: int n;
1587:
1588: n = 0;
1589: while ((BA0READ4(sc, CS4281_ACCTL) & ACCTL_DCV)) {
1590: delay(1000);
1591: if (++n > 1000)
1592: return (-1);
1593: }
1594: return (0);
1595: }
CVSweb