Annotation of sys/arch/sparc/dev/cs4231.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: cs4231.c,v 1.26 2006/06/02 20:00:54 miod Exp $ */
2:
3: /*
4: * Copyright (c) 1999 Jason L. Wright (jason@thought.net)
5: * 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: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26: * POSSIBILITY OF SUCH DAMAGE.
27: */
28:
29: /*
30: * Driver for CS4231 based audio found in some sun4m systems (cs4231)
31: * based on ideas from the S/Linux project and the NetBSD project.
32: */
33:
34: #include <sys/param.h>
35: #include <sys/systm.h>
36: #include <sys/errno.h>
37: #include <sys/ioctl.h>
38: #include <sys/device.h>
39: #include <sys/proc.h>
40: #include <sys/malloc.h>
41:
42: #include <machine/autoconf.h>
43: #include <sparc/cpu.h>
44: #include <sparc/sparc/cpuvar.h>
45: #include <sparc/dev/sbusvar.h>
46: #include <sparc/dev/dmareg.h>
47:
48: #include <sys/audioio.h>
49: #include <dev/audio_if.h>
50: #include <dev/auconv.h>
51: #include <dev/ic/apcdmareg.h>
52: #include <dev/ic/ad1848reg.h>
53: #include <dev/ic/cs4231reg.h>
54: #include <sparc/dev/cs4231reg.h>
55: #include <sparc/dev/cs4231var.h>
56:
57: #define CSAUDIO_DAC_LVL 0
58: #define CSAUDIO_LINE_IN_LVL 1
59: #define CSAUDIO_MIC_LVL 2
60: #define CSAUDIO_CD_LVL 3
61: #define CSAUDIO_MONITOR_LVL 4
62: #define CSAUDIO_OUTPUT_LVL 5
63: #define CSAUDIO_LINE_IN_MUTE 6
64: #define CSAUDIO_DAC_MUTE 7
65: #define CSAUDIO_CD_MUTE 8
66: #define CSAUDIO_MIC_MUTE 9
67: #define CSAUDIO_MONITOR_MUTE 10
68: #define CSAUDIO_OUTPUT_MUTE 11
69: #define CSAUDIO_REC_LVL 12
70: #define CSAUDIO_RECORD_SOURCE 13
71: #define CSAUDIO_OUTPUT 14
72: #define CSAUDIO_INPUT_CLASS 15
73: #define CSAUDIO_OUTPUT_CLASS 16
74: #define CSAUDIO_RECORD_CLASS 17
75: #define CSAUDIO_MONITOR_CLASS 18
76:
77: #define CSPORT_AUX2 0
78: #define CSPORT_AUX1 1
79: #define CSPORT_DAC 2
80: #define CSPORT_LINEIN 3
81: #define CSPORT_MONO 4
82: #define CSPORT_MONITOR 5
83: #define CSPORT_SPEAKER 6
84: #define CSPORT_LINEOUT 7
85: #define CSPORT_HEADPHONE 8
86: #define CSPORT_MICROPHONE 9
87:
88: #define MIC_IN_PORT 0
89: #define LINE_IN_PORT 1
90: #define AUX1_IN_PORT 2
91: #define DAC_IN_PORT 3
92:
93: #ifdef AUDIO_DEBUG
94: #define DPRINTF(x) printf x
95: #else
96: #define DPRINTF(x)
97: #endif
98:
99: /* Sun uses these pins in pin control register as GPIO */
100: #define CS_PC_LINEMUTE XCTL0_ENABLE /* mute line */
101: #define CS_PC_HDPHMUTE XCTL1_ENABLE /* mute headphone */
102:
103: /* cs4231 playback interrupt */
104: #define CS_AFS_TI 0x40 /* timer interrupt */
105: #define CS_AFS_CI 0x20 /* capture interrupt */
106: #define CS_AFS_PI 0x10 /* playback interrupt */
107: #define CS_AFS_CU 0x08 /* capture underrun */
108: #define CS_AFS_CO 0x04 /* capture overrun */
109: #define CS_AFS_PO 0x02 /* playback overrun */
110: #define CS_AFS_PU 0x01 /* playback underrun */
111:
112: #define CS_TIMEOUT 90000 /* recalibration timeout */
113:
114: int cs4231_match(struct device *, void *, void *);
115: void cs4231_attach(struct device *, struct device *, void *);
116: int cs4231_intr(void *);
117:
118: int cs4231_set_speed(struct cs4231_softc *, u_long *);
119: void cs4231_setup_output(struct cs4231_softc *sc);
120:
121: /* Audio interface */
122: int cs4231_open(void *, int);
123: void cs4231_close(void *);
124: int cs4231_query_encoding(void *, struct audio_encoding *);
125: int cs4231_set_params(void *, int, int, struct audio_params *,
126: struct audio_params *);
127: int cs4231_round_blocksize(void *, int);
128: int cs4231_commit_settings(void *);
129: int cs4231_halt_output(void *);
130: int cs4231_halt_input(void *);
131: int cs4231_getdev(void *, struct audio_device *);
132: int cs4231_set_port(void *, mixer_ctrl_t *);
133: int cs4231_get_port(void *, mixer_ctrl_t *);
134: int cs4231_query_devinfo(void *addr, mixer_devinfo_t *);
135: void * cs4231_alloc(void *, int, size_t, int, int);
136: void cs4231_free(void *, void *, int);
137: int cs4231_get_props(void *);
138: int cs4231_trigger_output(void *, void *, void *, int,
139: void (*intr)(void *), void *arg, struct audio_params *);
140: int cs4231_trigger_input(void *, void *, void *, int,
141: void (*intr)(void *), void *arg, struct audio_params *);
142: void cs4231_write(struct cs4231_softc *, u_int8_t, u_int8_t);
143: u_int8_t cs4231_read(struct cs4231_softc *, u_int8_t);
144:
145: struct audio_hw_if cs4231_sa_hw_if = {
146: cs4231_open,
147: cs4231_close,
148: 0,
149: cs4231_query_encoding,
150: cs4231_set_params,
151: cs4231_round_blocksize,
152: cs4231_commit_settings,
153: 0,
154: 0,
155: 0,
156: 0,
157: cs4231_halt_output,
158: cs4231_halt_input,
159: 0,
160: cs4231_getdev,
161: 0,
162: cs4231_set_port,
163: cs4231_get_port,
164: cs4231_query_devinfo,
165: cs4231_alloc,
166: cs4231_free,
167: 0,
168: 0,
169: cs4231_get_props,
170: cs4231_trigger_output,
171: cs4231_trigger_input
172: };
173:
174: struct cfattach audiocs_ca = {
175: sizeof (struct cs4231_softc), cs4231_match, cs4231_attach
176: };
177:
178: struct cfdriver audiocs_cd = {
179: NULL, "audiocs", DV_DULL
180: };
181:
182: struct audio_device cs4231_device = {
183: "SUNW,CS4231",
184: "a", /* XXX b for ultra */
185: "onboard1", /* XXX unknown for ultra */
186: };
187:
188: int
189: cs4231_match(parent, vcf, aux)
190: struct device *parent;
191: void *vcf, *aux;
192: {
193: struct cfdata *cf = vcf;
194: struct confargs *ca = aux;
195: register struct romaux *ra = &ca->ca_ra;
196:
197: if (strcmp(cf->cf_driver->cd_name, ra->ra_name) &&
198: strcmp("SUNW,CS4231", ra->ra_name)) {
199: return (0);
200: }
201: return (1);
202: }
203:
204: void
205: cs4231_attach(parent, self, aux)
206: struct device *parent, *self;
207: void *aux;
208: {
209: struct confargs *ca = aux;
210: struct cs4231_softc *sc = (struct cs4231_softc *)self;
211: int pri;
212:
213: if (ca->ca_ra.ra_nintr != 1) {
214: printf(": expected 1 interrupt, got %d\n", ca->ca_ra.ra_nintr);
215: return;
216: }
217: pri = ca->ca_ra.ra_intr[0].int_pri;
218:
219: if (ca->ca_ra.ra_nreg != 1) {
220: printf(": expected 1 register set, got %d\n",
221: ca->ca_ra.ra_nreg);
222: return;
223: }
224: sc->sc_regs = mapiodev(&(ca->ca_ra.ra_reg[0]), 0,
225: ca->ca_ra.ra_reg[0].rr_len);
226:
227: sc->sc_node = ca->ca_ra.ra_node;
228:
229: sc->sc_burst = getpropint(ca->ca_ra.ra_node, "burst-sizes", -1);
230: if (sc->sc_burst == -1)
231: sc->sc_burst = ((struct sbus_softc *)parent)->sc_burst;
232:
233: /* Clamp at parent's burst sizes */
234: sc->sc_burst &= ((struct sbus_softc *)parent)->sc_burst;
235:
236: sc->sc_ih.ih_fun = cs4231_intr;
237: sc->sc_ih.ih_arg = sc;
238: intr_establish(ca->ca_ra.ra_intr[0].int_pri, &sc->sc_ih, IPL_AUHARD,
239: self->dv_xname);
240:
241: printf(" pri %d\n", pri);
242:
243: audio_attach_mi(&cs4231_sa_hw_if, sc, &sc->sc_dev);
244:
245: /* Default to speaker, unmuted, reasonable volume */
246: sc->sc_out_port = CSPORT_SPEAKER;
247: sc->sc_in_port = CSPORT_MICROPHONE;
248: sc->sc_mute[CSPORT_SPEAKER] = 1;
249: sc->sc_mute[CSPORT_MONITOR] = 1;
250: sc->sc_volume[CSPORT_SPEAKER].left = 192;
251: sc->sc_volume[CSPORT_SPEAKER].right = 192;
252: }
253:
254: void
255: cs4231_write(sc, r, v)
256: struct cs4231_softc *sc;
257: u_int8_t r, v;
258: {
259: sc->sc_regs->iar = r;
260: sc->sc_regs->idr = v;
261: }
262:
263: u_int8_t
264: cs4231_read(sc, r)
265: struct cs4231_softc *sc;
266: u_int8_t r;
267: {
268: sc->sc_regs->iar = r;
269: return (sc->sc_regs->idr);
270: }
271:
272: /*
273: * Hardware interrupt handler
274: */
275: int
276: cs4231_intr(v)
277: void *v;
278: {
279: struct cs4231_softc *sc = (struct cs4231_softc *)v;
280: struct cs4231_regs *regs = sc->sc_regs;
281: struct cs_channel *chan;
282: struct cs_dma *p;
283: u_int32_t csr;
284: u_int8_t reg, status;
285: int r = 0;
286:
287: csr = regs->dma_csr;
288: regs->dma_csr = csr;
289:
290: if ((csr & APC_CSR_EIE) && (csr & APC_CSR_EI)) {
291: printf("%s: error interrupt\n", sc->sc_dev.dv_xname);
292: r = 1;
293: }
294:
295: if ((csr & APC_CSR_PIE) && (csr & APC_CSR_PI)) {
296: /* playback interrupt */
297: r = 1;
298: }
299:
300: if ((csr & APC_CSR_GIE) && (csr & APC_CSR_GI)) {
301: /* general interrupt */
302: status = regs->status;
303: if (status & (INTERRUPT_STATUS | SAMPLE_ERROR)) {
304: regs->iar = CS_IRQ_STATUS;
305: reg = regs->idr;
306: if (reg & CS_AFS_PI) {
307: cs4231_write(sc, SP_LOWER_BASE_COUNT, 0xff);
308: cs4231_write(sc, SP_UPPER_BASE_COUNT, 0xff);
309: }
310: if (reg & CS_AFS_CI) {
311: cs4231_write(sc, CS_LOWER_REC_CNT, 0xff);
312: cs4231_write(sc, CS_UPPER_REC_CNT, 0xff);
313: }
314: regs->status = 0;
315: }
316: r = 1;
317: }
318:
319: if ((csr & APC_CSR_PMIE) && (csr & APC_CSR_PMI)) {
320: u_int32_t nextaddr, togo;
321:
322: chan = &sc->sc_playback;
323:
324: p = chan->cs_curdma;
325: togo = chan->cs_segsz - chan->cs_cnt;
326: if (togo == 0) {
327: nextaddr = (u_int32_t)p->addr_dva;
328: chan->cs_cnt = togo = chan->cs_blksz;
329: } else {
330: nextaddr = regs->dma_pnva + chan->cs_blksz;
331: if (togo > chan->cs_blksz)
332: togo = chan->cs_blksz;
333: chan->cs_cnt += togo;
334: }
335:
336: regs->dma_pnva = nextaddr;
337: regs->dma_pnc = togo;
338:
339: if (chan->cs_intr != NULL)
340: (*chan->cs_intr)(chan->cs_arg);
341: r = 1;
342: }
343:
344: if ((csr & APC_CSR_CIE) && (csr & APC_CSR_CI)) {
345: if (csr & APC_CSR_CD) {
346: u_int32_t nextaddr, togo;
347:
348: chan = &sc->sc_capture;
349: p = chan->cs_curdma;
350: togo = chan->cs_segsz - chan->cs_cnt;
351: if (togo == 0) {
352: nextaddr = (u_int32_t)p->addr_dva;
353: chan->cs_cnt = togo = chan->cs_blksz;
354: } else {
355: nextaddr = regs->dma_cnva + chan->cs_blksz;
356: if (togo > chan->cs_blksz)
357: togo = chan->cs_blksz;
358: chan->cs_cnt += togo;
359: }
360:
361: regs->dma_cnva = nextaddr;
362: regs->dma_cnc = togo;
363:
364: if (chan->cs_intr != NULL)
365: (*chan->cs_intr)(chan->cs_arg);
366: }
367: r = 1;
368: }
369:
370: if ((csr & APC_CSR_CMIE) && (csr & APC_CSR_CMI)) {
371: /* capture empty */
372: r = 1;
373: }
374:
375: return (r);
376: }
377:
378: int
379: cs4231_set_speed(sc, argp)
380: struct cs4231_softc *sc;
381: u_long *argp;
382:
383: {
384: /*
385: * The available speeds are in the following table. Keep the speeds in
386: * the increasing order.
387: */
388: typedef struct {
389: int speed;
390: u_char bits;
391: } speed_struct;
392: u_long arg = *argp;
393:
394: static speed_struct speed_table[] = {
395: {5510, (0 << 1) | CLOCK_XTAL2},
396: {5510, (0 << 1) | CLOCK_XTAL2},
397: {6620, (7 << 1) | CLOCK_XTAL2},
398: {8000, (0 << 1) | CLOCK_XTAL1},
399: {9600, (7 << 1) | CLOCK_XTAL1},
400: {11025, (1 << 1) | CLOCK_XTAL2},
401: {16000, (1 << 1) | CLOCK_XTAL1},
402: {18900, (2 << 1) | CLOCK_XTAL2},
403: {22050, (3 << 1) | CLOCK_XTAL2},
404: {27420, (2 << 1) | CLOCK_XTAL1},
405: {32000, (3 << 1) | CLOCK_XTAL1},
406: {33075, (6 << 1) | CLOCK_XTAL2},
407: {33075, (4 << 1) | CLOCK_XTAL2},
408: {44100, (5 << 1) | CLOCK_XTAL2},
409: {48000, (6 << 1) | CLOCK_XTAL1},
410: };
411:
412: int i, n, selected = -1;
413:
414: n = sizeof(speed_table) / sizeof(speed_struct);
415:
416: if (arg < speed_table[0].speed)
417: selected = 0;
418: if (arg > speed_table[n - 1].speed)
419: selected = n - 1;
420:
421: for (i = 1; selected == -1 && i < n; i++) {
422: if (speed_table[i].speed == arg)
423: selected = i;
424: else if (speed_table[i].speed > arg) {
425: int diff1, diff2;
426:
427: diff1 = arg - speed_table[i - 1].speed;
428: diff2 = speed_table[i].speed - arg;
429: if (diff1 < diff2)
430: selected = i - 1;
431: else
432: selected = i;
433: }
434: }
435:
436: if (selected == -1)
437: selected = 3;
438:
439: sc->sc_speed_bits = speed_table[selected].bits;
440: sc->sc_need_commit = 1;
441: *argp = speed_table[selected].speed;
442:
443: return (0);
444: }
445:
446: /*
447: * Audio interface functions
448: */
449: int
450: cs4231_open(addr, flags)
451: void *addr;
452: int flags;
453: {
454: struct cs4231_softc *sc = addr;
455: struct cs4231_regs *regs = sc->sc_regs;
456: int tries;
457:
458: if (sc->sc_open)
459: return (EBUSY);
460: sc->sc_open = 1;
461:
462: sc->sc_capture.cs_intr = NULL;
463: sc->sc_capture.cs_arg = NULL;
464: sc->sc_capture.cs_locked = 0;
465:
466: sc->sc_playback.cs_intr = NULL;
467: sc->sc_playback.cs_arg = NULL;
468: sc->sc_playback.cs_locked = 0;
469:
470: regs->dma_csr = APC_CSR_RESET;
471: DELAY(10);
472: regs->dma_csr = 0;
473: DELAY(10);
474: regs->dma_csr |= APC_CSR_CODEC_RESET;
475:
476: DELAY(20);
477:
478: regs->dma_csr &= ~(APC_CSR_CODEC_RESET);
479:
480: for (tries = CS_TIMEOUT; tries && regs->iar == SP_IN_INIT; tries--)
481: DELAY(10);
482: if (tries == 0)
483: printf("%s: timeout waiting for reset\n", sc->sc_dev.dv_xname);
484:
485: /* Turn on cs4231 mode */
486: cs4231_write(sc, SP_MISC_INFO,
487: cs4231_read(sc, SP_MISC_INFO) | MODE2);
488:
489: cs4231_setup_output(sc);
490:
491: cs4231_write(sc, SP_PIN_CONTROL,
492: cs4231_read(sc, SP_PIN_CONTROL) | INTERRUPT_ENABLE);
493:
494: return (0);
495: }
496:
497: void
498: cs4231_setup_output(sc)
499: struct cs4231_softc *sc;
500: {
501: u_int8_t pc, mi, rm, lm;
502:
503: pc = cs4231_read(sc, SP_PIN_CONTROL) | CS_PC_HDPHMUTE | CS_PC_LINEMUTE;
504:
505: mi = cs4231_read(sc, CS_MONO_IO_CONTROL) | MONO_OUTPUT_MUTE;
506:
507: lm = cs4231_read(sc, SP_LEFT_OUTPUT_CONTROL);
508: lm &= ~OUTPUT_ATTEN_BITS;
509: lm |= ((~(sc->sc_volume[CSPORT_SPEAKER].left >> 2)) &
510: OUTPUT_ATTEN_BITS) | OUTPUT_MUTE;
511:
512: rm = cs4231_read(sc, SP_RIGHT_OUTPUT_CONTROL);
513: rm &= ~OUTPUT_ATTEN_BITS;
514: rm |= ((~(sc->sc_volume[CSPORT_SPEAKER].right >> 2)) &
515: OUTPUT_ATTEN_BITS) | OUTPUT_MUTE;
516:
517: if (sc->sc_mute[CSPORT_MONITOR]) {
518: lm &= ~OUTPUT_MUTE;
519: rm &= ~OUTPUT_MUTE;
520: }
521:
522: switch (sc->sc_out_port) {
523: case CSPORT_HEADPHONE:
524: if (sc->sc_mute[CSPORT_SPEAKER])
525: pc &= ~CS_PC_HDPHMUTE;
526: break;
527: case CSPORT_SPEAKER:
528: if (sc->sc_mute[CSPORT_SPEAKER])
529: mi &= ~MONO_OUTPUT_MUTE;
530: break;
531: case CSPORT_LINEOUT:
532: if (sc->sc_mute[CSPORT_SPEAKER])
533: pc &= ~CS_PC_LINEMUTE;
534: break;
535: }
536:
537: cs4231_write(sc, SP_LEFT_OUTPUT_CONTROL, lm);
538: cs4231_write(sc, SP_RIGHT_OUTPUT_CONTROL, rm);
539: cs4231_write(sc, SP_PIN_CONTROL, pc);
540: cs4231_write(sc, CS_MONO_IO_CONTROL, mi);
541:
542: /* XXX doesn't really belong here... */
543: switch (sc->sc_in_port) {
544: case CSPORT_LINEIN:
545: pc = LINE_INPUT;
546: break;
547: case CSPORT_AUX1:
548: pc = AUX_INPUT;
549: break;
550: case CSPORT_DAC:
551: pc = MIXED_DAC_INPUT;
552: break;
553: case CSPORT_MICROPHONE:
554: default:
555: pc = MIC_INPUT;
556: break;
557: }
558: lm = cs4231_read(sc, SP_LEFT_INPUT_CONTROL);
559: rm = cs4231_read(sc, SP_RIGHT_INPUT_CONTROL);
560: lm &= ~(MIXED_DAC_INPUT | ATTEN_22_5);
561: rm &= ~(MIXED_DAC_INPUT | ATTEN_22_5);
562: lm |= pc | (sc->sc_adc.left >> 4);
563: rm |= pc | (sc->sc_adc.right >> 4);
564: cs4231_write(sc, SP_LEFT_INPUT_CONTROL, lm);
565: cs4231_write(sc, SP_RIGHT_INPUT_CONTROL, rm);
566: }
567:
568: void
569: cs4231_close(addr)
570: void *addr;
571: {
572: struct cs4231_softc *sc = addr;
573: struct cs4231_regs *regs = sc->sc_regs;
574:
575: cs4231_halt_input(sc);
576: cs4231_halt_output(sc);
577: regs->iar = SP_PIN_CONTROL;
578: regs->idr &= ~INTERRUPT_ENABLE;
579: sc->sc_open = 0;
580: }
581:
582: int
583: cs4231_query_encoding(addr, fp)
584: void *addr;
585: struct audio_encoding *fp;
586: {
587: int err = 0;
588:
589: switch (fp->index) {
590: case 0:
591: strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
592: fp->encoding = AUDIO_ENCODING_ULAW;
593: fp->precision = 8;
594: fp->flags = 0;
595: break;
596: case 1:
597: strlcpy(fp->name, AudioEalaw, sizeof fp->name);
598: fp->encoding = AUDIO_ENCODING_ALAW;
599: fp->precision = 8;
600: fp->flags = 0;
601: break;
602: case 2:
603: strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
604: fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
605: fp->precision = 16;
606: fp->flags = 0;
607: break;
608: case 3:
609: strlcpy(fp->name, AudioEulinear, sizeof fp->name);
610: fp->encoding = AUDIO_ENCODING_ULINEAR;
611: fp->precision = 8;
612: fp->flags = 0;
613: break;
614: case 4:
615: strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
616: fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
617: fp->precision = 16;
618: fp->flags = 0;
619: break;
620: case 5:
621: strlcpy(fp->name, AudioEslinear, sizeof fp->name);
622: fp->encoding = AUDIO_ENCODING_SLINEAR;
623: fp->precision = 8;
624: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
625: break;
626: case 6:
627: strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
628: fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
629: fp->precision = 16;
630: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
631: break;
632: case 7:
633: strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
634: fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
635: fp->precision = 16;
636: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
637: break;
638: case 8:
639: strlcpy(fp->name, AudioEadpcm, sizeof fp->name);
640: fp->encoding = AUDIO_ENCODING_ADPCM;
641: fp->precision = 8;
642: fp->flags = 0;
643: break;
644: default:
645: err = EINVAL;
646: }
647: return (err);
648: }
649:
650: int
651: cs4231_set_params(addr, setmode, usemode, p, r)
652: void *addr;
653: int setmode, usemode;
654: struct audio_params *p, *r;
655: {
656: struct cs4231_softc *sc = (struct cs4231_softc *)addr;
657: int err, bits, enc = p->encoding;
658: void (*pswcode)(void *, u_char *, int cnt) = NULL;
659: void (*rswcode)(void *, u_char *, int cnt) = NULL;
660:
661: switch (enc) {
662: case AUDIO_ENCODING_ULAW:
663: if (p->precision != 8)
664: return (EINVAL);
665: bits = FMT_ULAW >> 5;
666: break;
667: case AUDIO_ENCODING_ALAW:
668: if (p->precision != 8)
669: return (EINVAL);
670: bits = FMT_ALAW >> 5;
671: break;
672: case AUDIO_ENCODING_SLINEAR_LE:
673: if (p->precision == 8) {
674: bits = FMT_PCM8 >> 5;
675: pswcode = rswcode = change_sign8;
676: } else if (p->precision == 16)
677: bits = FMT_TWOS_COMP >> 5;
678: else
679: return (EINVAL);
680: break;
681: case AUDIO_ENCODING_ULINEAR:
682: if (p->precision != 8)
683: return (EINVAL);
684: bits = FMT_PCM8 >> 5;
685: break;
686: case AUDIO_ENCODING_SLINEAR_BE:
687: if (p->precision == 8) {
688: bits = FMT_PCM8 >> 5;
689: pswcode = rswcode = change_sign8;
690: } else if (p->precision == 16)
691: bits = FMT_TWOS_COMP_BE >> 5;
692: else
693: return (EINVAL);
694: break;
695: case AUDIO_ENCODING_SLINEAR:
696: if (p->precision != 8)
697: return (EINVAL);
698: bits = FMT_PCM8 >> 5;
699: pswcode = rswcode = change_sign8;
700: break;
701: case AUDIO_ENCODING_ULINEAR_LE:
702: if (p->precision == 8)
703: bits = FMT_PCM8 >> 5;
704: else if (p->precision == 16) {
705: bits = FMT_TWOS_COMP >> 5;
706: pswcode = rswcode = change_sign16_le;
707: } else
708: return (EINVAL);
709: break;
710: case AUDIO_ENCODING_ULINEAR_BE:
711: if (p->precision == 8)
712: bits = FMT_PCM8 >> 5;
713: else if (p->precision == 16) {
714: bits = FMT_TWOS_COMP_BE >> 5;
715: pswcode = rswcode = change_sign16_be;
716: } else
717: return (EINVAL);
718: break;
719: case AUDIO_ENCODING_ADPCM:
720: if (p->precision != 8)
721: return (EINVAL);
722: bits = FMT_ADPCM >> 5;
723: break;
724: default:
725: return (EINVAL);
726: }
727:
728: if (p->channels != 1 && p->channels != 2)
729: return (EINVAL);
730:
731: err = cs4231_set_speed(sc, &p->sample_rate);
732: if (err)
733: return (err);
734:
735: p->sw_code = pswcode;
736: r->sw_code = rswcode;
737:
738: sc->sc_format_bits = bits;
739: sc->sc_channels = p->channels;
740: sc->sc_precision = p->precision;
741: sc->sc_need_commit = 1;
742: return (0);
743: }
744:
745: int
746: cs4231_round_blocksize(addr, blk)
747: void *addr;
748: int blk;
749: {
750: return ((blk + 3) & (-4));
751: }
752:
753: int
754: cs4231_commit_settings(addr)
755: void *addr;
756: {
757: struct cs4231_softc *sc = (struct cs4231_softc *)addr;
758: struct cs4231_regs *regs = sc->sc_regs;
759: int s, tries;
760: u_int8_t r, fs;
761:
762: if (sc->sc_need_commit == 0)
763: return (0);
764:
765: fs = sc->sc_speed_bits | (sc->sc_format_bits << 5);
766: if (sc->sc_channels == 2)
767: fs |= FMT_STEREO;
768:
769: s = splaudio();
770:
771: r = cs4231_read(sc, SP_INTERFACE_CONFIG) | AUTO_CAL_ENABLE;
772: regs->iar = MODE_CHANGE_ENABLE;
773: regs->iar = MODE_CHANGE_ENABLE | SP_INTERFACE_CONFIG;
774: regs->idr = r;
775:
776: regs->iar = MODE_CHANGE_ENABLE | SP_CLOCK_DATA_FORMAT;
777: regs->idr = fs;
778: r = regs->idr;
779: r = regs->idr;
780: tries = CS_TIMEOUT;
781: for (tries = CS_TIMEOUT; tries && regs->iar == SP_IN_INIT; tries--)
782: DELAY(10);
783: if (tries == 0)
784: printf("%s: timeout committing fspb\n", sc->sc_dev.dv_xname);
785:
786: regs->iar = MODE_CHANGE_ENABLE | CS_REC_FORMAT;
787: regs->idr = fs;
788: r = regs->idr;
789: r = regs->idr;
790: for (tries = CS_TIMEOUT; tries && regs->iar == SP_IN_INIT; tries--)
791: DELAY(10);
792: if (tries == 0)
793: printf("%s: timeout committing cdf\n", sc->sc_dev.dv_xname);
794:
795: regs->iar = 0;
796: for (tries = CS_TIMEOUT; tries && regs->iar == SP_IN_INIT; tries--)
797: DELAY(10);
798: if (tries == 0)
799: printf("%s: timeout waiting for !mce\n", sc->sc_dev.dv_xname);
800:
801: regs->iar = SP_TEST_AND_INIT;
802: for (tries = CS_TIMEOUT; tries && regs->idr & AUTO_CAL_IN_PROG; tries--)
803: DELAY(10);
804: if (tries == 0)
805: printf("%s: timeout waiting for autocalibration\n",
806: sc->sc_dev.dv_xname);
807:
808: splx(s);
809:
810: sc->sc_need_commit = 0;
811: return (0);
812: }
813:
814: int
815: cs4231_halt_output(addr)
816: void *addr;
817: {
818: struct cs4231_softc *sc = (struct cs4231_softc *)addr;
819: struct cs4231_regs *regs = sc->sc_regs;
820: u_int8_t r;
821:
822: /* XXX Kills some capture bits */
823: regs->dma_csr &= ~(APC_CSR_EI | APC_CSR_GIE | APC_CSR_PIE |
824: APC_CSR_EIE | APC_CSR_PDMA_GO | APC_CSR_PMIE);
825: regs->iar = SP_INTERFACE_CONFIG;
826: r = regs->idr & (~PLAYBACK_ENABLE);
827: regs->iar = SP_INTERFACE_CONFIG;
828: regs->idr = r;
829: sc->sc_playback.cs_locked = 0;
830: return (0);
831: }
832:
833: int
834: cs4231_halt_input(addr)
835: void *addr;
836: {
837: struct cs4231_softc *sc = (struct cs4231_softc *)addr;
838: struct cs4231_regs *regs = sc->sc_regs;
839:
840: /* XXX Kills some playback bits */
841: regs->dma_csr = APC_CSR_CAPTURE_PAUSE;
842: regs->iar = SP_INTERFACE_CONFIG;
843: regs->idr &= ~CAPTURE_ENABLE;
844: sc->sc_capture.cs_locked = 0;
845: return (0);
846: }
847:
848: int
849: cs4231_getdev(addr, retp)
850: void *addr;
851: struct audio_device *retp;
852: {
853: *retp = cs4231_device;
854: return (0);
855: }
856:
857: int
858: cs4231_set_port(addr, cp)
859: void *addr;
860: mixer_ctrl_t *cp;
861: {
862: struct cs4231_softc *sc = (struct cs4231_softc *)addr;
863: int error = EINVAL;
864:
865: DPRINTF(("cs4231_set_port: port=%d type=%d\n", cp->dev, cp->type));
866:
867: switch (cp->dev) {
868: case CSAUDIO_DAC_LVL:
869: if (cp->type != AUDIO_MIXER_VALUE)
870: break;
871: if (cp->un.value.num_channels == 1) {
872: sc->sc_regs->iar = SP_LEFT_AUX1_CONTROL;
873: sc->sc_regs->idr =
874: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
875: AUX_INPUT_ATTEN_BITS;
876: }
877: else if (cp->un.value.num_channels == 2) {
878: sc->sc_regs->iar = SP_LEFT_AUX1_CONTROL;
879: sc->sc_regs->idr =
880: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
881: AUX_INPUT_ATTEN_BITS;
882: sc->sc_regs->iar = SP_RIGHT_AUX1_CONTROL;
883: sc->sc_regs->idr =
884: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
885: AUX_INPUT_ATTEN_BITS;
886: } else
887: break;
888: error = 0;
889: break;
890: case CSAUDIO_LINE_IN_LVL:
891: if (cp->type != AUDIO_MIXER_VALUE)
892: break;
893: if (cp->un.value.num_channels == 1) {
894: sc->sc_regs->iar = CS_LEFT_LINE_CONTROL;
895: sc->sc_regs->idr =
896: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
897: AUX_INPUT_ATTEN_BITS;
898: }
899: else if (cp->un.value.num_channels == 2) {
900: sc->sc_regs->iar = CS_LEFT_LINE_CONTROL;
901: sc->sc_regs->idr =
902: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
903: AUX_INPUT_ATTEN_BITS;
904: sc->sc_regs->iar = CS_RIGHT_LINE_CONTROL;
905: sc->sc_regs->idr =
906: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
907: AUX_INPUT_ATTEN_BITS;
908: } else
909: break;
910: error = 0;
911: break;
912: case CSAUDIO_MIC_LVL:
913: if (cp->type != AUDIO_MIXER_VALUE)
914: break;
915: if (cp->un.value.num_channels == 1) {
916: #if 0
917: sc->sc_regs->iar = CS_MONO_IO_CONTROL;
918: sc->sc_regs->idr =
919: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
920: MONO_INPUT_ATTEN_BITS;
921: #endif
922: } else
923: break;
924: error = 0;
925: break;
926: case CSAUDIO_CD_LVL:
927: if (cp->type != AUDIO_MIXER_VALUE)
928: break;
929: if (cp->un.value.num_channels == 1) {
930: sc->sc_regs->iar = SP_LEFT_AUX2_CONTROL;
931: sc->sc_regs->idr =
932: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
933: AUX_INPUT_ATTEN_BITS;
934: error = 0;
935: }
936: else if (cp->un.value.num_channels == 2) {
937: sc->sc_regs->iar = SP_LEFT_AUX2_CONTROL;
938: sc->sc_regs->idr =
939: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
940: AUX_INPUT_ATTEN_BITS;
941: sc->sc_regs->iar = SP_RIGHT_AUX2_CONTROL;
942: sc->sc_regs->idr =
943: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
944: AUX_INPUT_ATTEN_BITS;
945: error = 0;
946: }
947: else
948: break;
949: break;
950: case CSAUDIO_MONITOR_LVL:
951: if (cp->type != AUDIO_MIXER_VALUE)
952: break;
953: if (cp->un.value.num_channels == 1) {
954: sc->sc_regs->iar = SP_DIGITAL_MIX;
955: sc->sc_regs->idr =
956: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] << 2;
957: }
958: else
959: break;
960: error = 0;
961: break;
962: case CSAUDIO_OUTPUT_LVL:
963: if (cp->type != AUDIO_MIXER_VALUE)
964: break;
965: if (cp->un.value.num_channels == 1) {
966: sc->sc_volume[CSPORT_SPEAKER].left =
967: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
968: sc->sc_volume[CSPORT_SPEAKER].right =
969: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
970: }
971: else if (cp->un.value.num_channels == 2) {
972: sc->sc_volume[CSPORT_SPEAKER].left =
973: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
974: sc->sc_volume[CSPORT_SPEAKER].right =
975: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
976: }
977: else
978: break;
979:
980: cs4231_setup_output(sc);
981: error = 0;
982: break;
983: case CSAUDIO_OUTPUT:
984: if (cp->type != AUDIO_MIXER_ENUM)
985: break;
986: if (cp->un.ord != CSPORT_LINEOUT &&
987: cp->un.ord != CSPORT_SPEAKER &&
988: cp->un.ord != CSPORT_HEADPHONE)
989: return (EINVAL);
990: sc->sc_out_port = cp->un.ord;
991: cs4231_setup_output(sc);
992: error = 0;
993: break;
994: case CSAUDIO_LINE_IN_MUTE:
995: if (cp->type != AUDIO_MIXER_ENUM)
996: break;
997: sc->sc_mute[CSPORT_LINEIN] = cp->un.ord ? 1 : 0;
998: error = 0;
999: break;
1000: case CSAUDIO_DAC_MUTE:
1001: if (cp->type != AUDIO_MIXER_ENUM)
1002: break;
1003: sc->sc_mute[CSPORT_AUX1] = cp->un.ord ? 1 : 0;
1004: error = 0;
1005: break;
1006: case CSAUDIO_CD_MUTE:
1007: if (cp->type != AUDIO_MIXER_ENUM)
1008: break;
1009: sc->sc_mute[CSPORT_AUX2] = cp->un.ord ? 1 : 0;
1010: error = 0;
1011: break;
1012: case CSAUDIO_MIC_MUTE:
1013: if (cp->type != AUDIO_MIXER_ENUM)
1014: break;
1015: sc->sc_mute[CSPORT_MONO] = cp->un.ord ? 1 : 0;
1016: error = 0;
1017: break;
1018: case CSAUDIO_MONITOR_MUTE:
1019: if (cp->type != AUDIO_MIXER_ENUM)
1020: break;
1021: sc->sc_mute[CSPORT_MONITOR] = cp->un.ord ? 1 : 0;
1022: error = 0;
1023: break;
1024: case CSAUDIO_OUTPUT_MUTE:
1025: if (cp->type != AUDIO_MIXER_ENUM)
1026: break;
1027: sc->sc_mute[CSPORT_SPEAKER] = cp->un.ord ? 1 : 0;
1028: cs4231_setup_output(sc);
1029: error = 0;
1030: break;
1031: case CSAUDIO_REC_LVL:
1032: if (cp->type != AUDIO_MIXER_VALUE)
1033: break;
1034: if (cp->un.value.num_channels == 1) {
1035: sc->sc_adc.left =
1036: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
1037: sc->sc_adc.right =
1038: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
1039: } else if (cp->un.value.num_channels == 2) {
1040: sc->sc_adc.left =
1041: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1042: sc->sc_adc.right =
1043: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1044: } else
1045: break;
1046: cs4231_setup_output(sc);
1047: error = 0;
1048: break;
1049: case CSAUDIO_RECORD_SOURCE:
1050: if (cp->type != AUDIO_MIXER_ENUM)
1051: break;
1052: if (cp->un.ord == CSPORT_MICROPHONE ||
1053: cp->un.ord == CSPORT_LINEIN ||
1054: cp->un.ord == CSPORT_AUX1 ||
1055: cp->un.ord == CSPORT_DAC) {
1056: sc->sc_in_port = cp->un.ord;
1057: error = 0;
1058: cs4231_setup_output(sc);
1059: }
1060: break;
1061: }
1062:
1063: return (error);
1064: }
1065:
1066: int
1067: cs4231_get_port(addr, cp)
1068: void *addr;
1069: mixer_ctrl_t *cp;
1070: {
1071: struct cs4231_softc *sc = (struct cs4231_softc *)addr;
1072: int error = EINVAL;
1073:
1074: DPRINTF(("cs4231_get_port: port=%d type=%d\n", cp->dev, cp->type));
1075:
1076: switch (cp->dev) {
1077: case CSAUDIO_DAC_LVL:
1078: if (cp->type != AUDIO_MIXER_VALUE)
1079: break;
1080: if (cp->un.value.num_channels == 1) {
1081: sc->sc_regs->iar = SP_LEFT_AUX1_CONTROL;
1082: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
1083: sc->sc_regs->idr & AUX_INPUT_ATTEN_BITS;
1084: }
1085: else if (cp->un.value.num_channels == 2) {
1086: sc->sc_regs->iar = SP_LEFT_AUX1_CONTROL;
1087: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
1088: sc->sc_regs->idr & AUX_INPUT_ATTEN_BITS;
1089: sc->sc_regs->iar = SP_RIGHT_AUX1_CONTROL;
1090: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
1091: sc->sc_regs->idr & AUX_INPUT_ATTEN_BITS;
1092: } else
1093: break;
1094: error = 0;
1095: break;
1096: case CSAUDIO_LINE_IN_LVL:
1097: if (cp->type != AUDIO_MIXER_VALUE)
1098: break;
1099: if (cp->un.value.num_channels == 1) {
1100: sc->sc_regs->iar = CS_LEFT_LINE_CONTROL;
1101: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
1102: sc->sc_regs->idr & AUX_INPUT_ATTEN_BITS;
1103: }
1104: else if (cp->un.value.num_channels == 2) {
1105: sc->sc_regs->iar = CS_LEFT_LINE_CONTROL;
1106: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
1107: sc->sc_regs->idr & AUX_INPUT_ATTEN_BITS;
1108: sc->sc_regs->iar = CS_RIGHT_LINE_CONTROL;
1109: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
1110: sc->sc_regs->idr & AUX_INPUT_ATTEN_BITS;
1111: } else
1112: break;
1113: error = 0;
1114: break;
1115: case CSAUDIO_MIC_LVL:
1116: if (cp->type != AUDIO_MIXER_VALUE)
1117: break;
1118: if (cp->un.value.num_channels == 1) {
1119: #if 0
1120: sc->sc_regs->iar = CS_MONO_IO_CONTROL;
1121: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
1122: sc->sc_regs->idr & MONO_INPUT_ATTEN_BITS;
1123: #endif
1124: } else
1125: break;
1126: error = 0;
1127: break;
1128: case CSAUDIO_CD_LVL:
1129: if (cp->type != AUDIO_MIXER_VALUE)
1130: break;
1131: if (cp->un.value.num_channels == 1) {
1132: sc->sc_regs->iar = SP_LEFT_AUX2_CONTROL;
1133: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
1134: sc->sc_regs->idr & AUX_INPUT_ATTEN_BITS;
1135: error = 0;
1136: }
1137: else if (cp->un.value.num_channels == 2) {
1138: sc->sc_regs->iar = SP_LEFT_AUX2_CONTROL;
1139: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
1140: sc->sc_regs->idr & AUX_INPUT_ATTEN_BITS;
1141: sc->sc_regs->iar = SP_RIGHT_AUX2_CONTROL;
1142: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
1143: sc->sc_regs->idr & AUX_INPUT_ATTEN_BITS;
1144: error = 0;
1145: }
1146: else
1147: break;
1148: break;
1149: case CSAUDIO_MONITOR_LVL:
1150: if (cp->type != AUDIO_MIXER_VALUE)
1151: break;
1152: if (cp->un.value.num_channels == 1) {
1153: sc->sc_regs->iar = SP_DIGITAL_MIX;
1154: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
1155: sc->sc_regs->idr >> 2;
1156: }
1157: else
1158: break;
1159: error = 0;
1160: break;
1161: case CSAUDIO_OUTPUT_LVL:
1162: if (cp->type != AUDIO_MIXER_VALUE)
1163: break;
1164: if (cp->un.value.num_channels == 1)
1165: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
1166: sc->sc_volume[CSPORT_SPEAKER].left;
1167: else if (cp->un.value.num_channels == 2) {
1168: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
1169: sc->sc_volume[CSPORT_SPEAKER].left;
1170: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
1171: sc->sc_volume[CSPORT_SPEAKER].right;
1172: }
1173: else
1174: break;
1175: error = 0;
1176: break;
1177: case CSAUDIO_LINE_IN_MUTE:
1178: if (cp->type != AUDIO_MIXER_ENUM)
1179: break;
1180: cp->un.ord = sc->sc_mute[CSPORT_LINEIN] ? 1 : 0;
1181: error = 0;
1182: break;
1183: case CSAUDIO_DAC_MUTE:
1184: if (cp->type != AUDIO_MIXER_ENUM)
1185: break;
1186: cp->un.ord = sc->sc_mute[CSPORT_AUX1] ? 1 : 0;
1187: error = 0;
1188: break;
1189: case CSAUDIO_CD_MUTE:
1190: if (cp->type != AUDIO_MIXER_ENUM)
1191: break;
1192: cp->un.ord = sc->sc_mute[CSPORT_AUX2] ? 1 : 0;
1193: error = 0;
1194: break;
1195: case CSAUDIO_MIC_MUTE:
1196: if (cp->type != AUDIO_MIXER_ENUM)
1197: break;
1198: cp->un.ord = sc->sc_mute[CSPORT_MONO] ? 1 : 0;
1199: error = 0;
1200: break;
1201: case CSAUDIO_MONITOR_MUTE:
1202: if (cp->type != AUDIO_MIXER_ENUM)
1203: break;
1204: cp->un.ord = sc->sc_mute[CSPORT_MONITOR] ? 1 : 0;
1205: error = 0;
1206: break;
1207: case CSAUDIO_OUTPUT_MUTE:
1208: if (cp->type != AUDIO_MIXER_ENUM)
1209: break;
1210: cp->un.ord = sc->sc_mute[CSPORT_SPEAKER] ? 1 : 0;
1211: error = 0;
1212: break;
1213: case CSAUDIO_REC_LVL:
1214: if (cp->type != AUDIO_MIXER_VALUE)
1215: break;
1216: if (cp->un.value.num_channels == 1) {
1217: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
1218: sc->sc_adc.left;
1219: } else if (cp->un.value.num_channels == 2) {
1220: cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
1221: sc->sc_adc.left;
1222: cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
1223: sc->sc_adc.right;
1224: } else
1225: break;
1226: error = 0;
1227: break;
1228: case CSAUDIO_RECORD_SOURCE:
1229: if (cp->type != AUDIO_MIXER_ENUM)
1230: break;
1231: cp->un.ord = sc->sc_in_port;
1232: error = 0;
1233: break;
1234: case CSAUDIO_OUTPUT:
1235: if (cp->type != AUDIO_MIXER_ENUM)
1236: break;
1237: cp->un.ord = sc->sc_out_port;
1238: error = 0;
1239: break;
1240: }
1241: return (error);
1242: }
1243:
1244: int
1245: cs4231_query_devinfo(addr, dip)
1246: void *addr;
1247: mixer_devinfo_t *dip;
1248: {
1249: int err = 0;
1250:
1251: switch (dip->index) {
1252: case CSAUDIO_MIC_LVL: /* mono/microphone mixer */
1253: dip->type = AUDIO_MIXER_VALUE;
1254: dip->mixer_class = CSAUDIO_INPUT_CLASS;
1255: dip->prev = AUDIO_MIXER_LAST;
1256: dip->next = CSAUDIO_MIC_MUTE;
1257: strlcpy(dip->label.name, AudioNmicrophone,
1258: sizeof dip->label.name);
1259: dip->un.v.num_channels = 1;
1260: strlcpy(dip->un.v.units.name, AudioNvolume,
1261: sizeof dip->un.v.units.name);
1262: break;
1263: case CSAUDIO_DAC_LVL: /* dacout */
1264: dip->type = AUDIO_MIXER_VALUE;
1265: dip->mixer_class = CSAUDIO_INPUT_CLASS;
1266: dip->prev = AUDIO_MIXER_LAST;
1267: dip->next = CSAUDIO_DAC_MUTE;
1268: strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name);
1269: dip->un.v.num_channels = 2;
1270: strlcpy(dip->un.v.units.name, AudioNvolume,
1271: sizeof dip->un.v.units.name);
1272: break;
1273: case CSAUDIO_LINE_IN_LVL: /* line */
1274: dip->type = AUDIO_MIXER_VALUE;
1275: dip->mixer_class = CSAUDIO_INPUT_CLASS;
1276: dip->prev = AUDIO_MIXER_LAST;
1277: dip->next = CSAUDIO_LINE_IN_MUTE;
1278: strlcpy(dip->label.name, AudioNline, sizeof dip->label.name);
1279: dip->un.v.num_channels = 2;
1280: strlcpy(dip->un.v.units.name, AudioNvolume,
1281: sizeof dip->un.v.units.name);
1282: break;
1283: case CSAUDIO_CD_LVL: /* cd */
1284: dip->type = AUDIO_MIXER_VALUE;
1285: dip->mixer_class = CSAUDIO_INPUT_CLASS;
1286: dip->prev = AUDIO_MIXER_LAST;
1287: dip->next = CSAUDIO_CD_MUTE;
1288: strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
1289: dip->un.v.num_channels = 2;
1290: strlcpy(dip->un.v.units.name, AudioNvolume,
1291: sizeof dip->un.v.units.name);
1292: break;
1293: case CSAUDIO_MONITOR_LVL: /* monitor level */
1294: dip->type = AUDIO_MIXER_VALUE;
1295: dip->mixer_class = CSAUDIO_MONITOR_CLASS;
1296: dip->prev = AUDIO_MIXER_LAST;
1297: dip->next = CSAUDIO_MONITOR_MUTE;
1298: strlcpy(dip->label.name, AudioNmonitor, sizeof dip->label.name);
1299: dip->un.v.num_channels = 1;
1300: strlcpy(dip->un.v.units.name, AudioNvolume,
1301: sizeof dip->un.v.units.name);
1302: break;
1303: case CSAUDIO_OUTPUT_LVL:
1304: dip->type = AUDIO_MIXER_VALUE;
1305: dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1306: dip->prev = AUDIO_MIXER_LAST;
1307: dip->next = CSAUDIO_OUTPUT_MUTE;
1308: strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
1309: dip->un.v.num_channels = 2;
1310: strlcpy(dip->un.v.units.name, AudioNvolume,
1311: sizeof dip->un.v.units.name);
1312: break;
1313: case CSAUDIO_LINE_IN_MUTE:
1314: dip->type = AUDIO_MIXER_ENUM;
1315: dip->mixer_class = CSAUDIO_INPUT_CLASS;
1316: dip->prev = CSAUDIO_LINE_IN_LVL;
1317: dip->next = AUDIO_MIXER_LAST;
1318: goto mute;
1319: case CSAUDIO_DAC_MUTE:
1320: dip->type = AUDIO_MIXER_ENUM;
1321: dip->mixer_class = CSAUDIO_INPUT_CLASS;
1322: dip->prev = CSAUDIO_DAC_LVL;
1323: dip->next = AUDIO_MIXER_LAST;
1324: goto mute;
1325: case CSAUDIO_CD_MUTE:
1326: dip->type = AUDIO_MIXER_ENUM;
1327: dip->mixer_class = CSAUDIO_INPUT_CLASS;
1328: dip->prev = CSAUDIO_CD_LVL;
1329: dip->next = AUDIO_MIXER_LAST;
1330: goto mute;
1331: case CSAUDIO_MIC_MUTE:
1332: dip->type = AUDIO_MIXER_ENUM;
1333: dip->mixer_class = CSAUDIO_INPUT_CLASS;
1334: dip->prev = CSAUDIO_MIC_LVL;
1335: dip->next = AUDIO_MIXER_LAST;
1336: goto mute;
1337: case CSAUDIO_MONITOR_MUTE:
1338: dip->type = AUDIO_MIXER_ENUM;
1339: dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1340: dip->prev = CSAUDIO_MONITOR_LVL;
1341: dip->next = AUDIO_MIXER_LAST;
1342: goto mute;
1343: case CSAUDIO_OUTPUT_MUTE:
1344: dip->type = AUDIO_MIXER_ENUM;
1345: dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1346: dip->prev = CSAUDIO_OUTPUT_LVL;
1347: dip->next = AUDIO_MIXER_LAST;
1348: goto mute;
1349:
1350: mute:
1351: strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
1352: dip->un.e.num_mem = 2;
1353: strlcpy(dip->un.e.member[0].label.name, AudioNon,
1354: sizeof dip->un.e.member[0].label.name);
1355: dip->un.e.member[0].ord = 0;
1356: strlcpy(dip->un.e.member[1].label.name, AudioNoff,
1357: sizeof dip->un.e.member[1].label.name);
1358: dip->un.e.member[1].ord = 1;
1359: break;
1360: case CSAUDIO_REC_LVL: /* record level */
1361: dip->type = AUDIO_MIXER_VALUE;
1362: dip->mixer_class = CSAUDIO_RECORD_CLASS;
1363: dip->prev = AUDIO_MIXER_LAST;
1364: dip->next = CSAUDIO_RECORD_SOURCE;
1365: strlcpy(dip->label.name, AudioNrecord, sizeof dip->label.name);
1366: dip->un.v.num_channels = 2;
1367: strlcpy(dip->un.v.units.name, AudioNvolume,
1368: sizeof dip->un.v.units.name);
1369: break;
1370: case CSAUDIO_RECORD_SOURCE:
1371: dip->type = AUDIO_MIXER_ENUM;
1372: dip->mixer_class = CSAUDIO_RECORD_CLASS;
1373: dip->prev = CSAUDIO_REC_LVL;
1374: dip->next = AUDIO_MIXER_LAST;
1375: strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
1376: dip->un.e.num_mem = 4;
1377: strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone,
1378: sizeof dip->un.e.member[0].label.name);
1379: dip->un.e.member[0].ord = CSPORT_MICROPHONE;
1380: strlcpy(dip->un.e.member[1].label.name, AudioNline,
1381: sizeof dip->un.e.member[1].label.name);
1382: dip->un.e.member[1].ord = CSPORT_LINEIN;
1383: strlcpy(dip->un.e.member[2].label.name, AudioNcd,
1384: sizeof dip->un.e.member[2].label.name);
1385: dip->un.e.member[2].ord = CSPORT_AUX1;
1386: strlcpy(dip->un.e.member[3].label.name, AudioNdac,
1387: sizeof dip->un.e.member[3].label.name);
1388: dip->un.e.member[3].ord = CSPORT_DAC;
1389: break;
1390: case CSAUDIO_OUTPUT:
1391: dip->type = AUDIO_MIXER_ENUM;
1392: dip->mixer_class = CSAUDIO_MONITOR_CLASS;
1393: dip->prev = dip->next = AUDIO_MIXER_LAST;
1394: strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
1395: dip->un.e.num_mem = 3;
1396: strlcpy(dip->un.e.member[0].label.name, AudioNspeaker,
1397: sizeof dip->un.e.member[0].label.name);
1398: dip->un.e.member[0].ord = CSPORT_SPEAKER;
1399: strlcpy(dip->un.e.member[1].label.name, AudioNline,
1400: sizeof dip->un.e.member[1].label.name);
1401: dip->un.e.member[1].ord = CSPORT_LINEOUT;
1402: strlcpy(dip->un.e.member[2].label.name, AudioNheadphone,
1403: sizeof dip->un.e.member[2].label.name);
1404: dip->un.e.member[2].ord = CSPORT_HEADPHONE;
1405: break;
1406: case CSAUDIO_INPUT_CLASS: /* input class descriptor */
1407: dip->type = AUDIO_MIXER_CLASS;
1408: dip->mixer_class = CSAUDIO_INPUT_CLASS;
1409: dip->prev = AUDIO_MIXER_LAST;
1410: dip->next = AUDIO_MIXER_LAST;
1411: strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
1412: break;
1413: case CSAUDIO_OUTPUT_CLASS: /* output class descriptor */
1414: dip->type = AUDIO_MIXER_CLASS;
1415: dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
1416: dip->prev = AUDIO_MIXER_LAST;
1417: dip->next = AUDIO_MIXER_LAST;
1418: strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
1419: break;
1420: case CSAUDIO_MONITOR_CLASS: /* monitor class descriptor */
1421: dip->type = AUDIO_MIXER_CLASS;
1422: dip->mixer_class = CSAUDIO_MONITOR_CLASS;
1423: dip->prev = AUDIO_MIXER_LAST;
1424: dip->next = AUDIO_MIXER_LAST;
1425: strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name);
1426: break;
1427: case CSAUDIO_RECORD_CLASS: /* record class descriptor */
1428: dip->type = AUDIO_MIXER_CLASS;
1429: dip->mixer_class = CSAUDIO_RECORD_CLASS;
1430: dip->prev = AUDIO_MIXER_LAST;
1431: dip->next = AUDIO_MIXER_LAST;
1432: strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
1433: break;
1434: default:
1435: err = ENXIO;
1436: }
1437:
1438: return (err);
1439: }
1440:
1441: void *
1442: cs4231_alloc(addr, direction, size, pool, flags)
1443: void *addr;
1444: int direction;
1445: size_t size;
1446: int pool;
1447: int flags;
1448: {
1449: struct cs4231_softc *sc = (struct cs4231_softc *)addr;
1450: struct cs_dma *p;
1451:
1452: p = (struct cs_dma *)malloc(sizeof(struct cs_dma), pool, flags);
1453: if (p == NULL)
1454: return (NULL);
1455:
1456: p->addr_dva = dvma_malloc(size, &p->addr, flags);
1457: if (p->addr_dva == NULL) {
1458: free(p, pool);
1459: return (NULL);
1460: }
1461:
1462: p->size = size;
1463: p->next = sc->sc_dmas;
1464: sc->sc_dmas = p;
1465: return (p->addr);
1466: }
1467:
1468: void
1469: cs4231_free(addr, ptr, pool)
1470: void *addr;
1471: void *ptr;
1472: int pool;
1473: {
1474: struct cs4231_softc *sc = addr;
1475: struct cs_dma *p, **pp;
1476:
1477: for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &(*pp)->next) {
1478: if (p->addr != ptr)
1479: continue;
1480: dvma_free(p->addr_dva, 16*1024, &p->addr);
1481: *pp = p->next;
1482: free(p, pool);
1483: return;
1484: }
1485: printf("%s: attempt to free rogue pointer\n", sc->sc_dev.dv_xname);
1486: }
1487:
1488: int
1489: cs4231_get_props(addr)
1490: void *addr;
1491: {
1492: return (AUDIO_PROP_FULLDUPLEX);
1493: }
1494:
1495: int
1496: cs4231_trigger_output(addr, start, end, blksize, intr, arg, param)
1497: void *addr, *start, *end;
1498: int blksize;
1499: void (*intr)(void *);
1500: void *arg;
1501: struct audio_params *param;
1502: {
1503: struct cs4231_softc *sc = addr;
1504: struct cs4231_regs *regs = sc->sc_regs;
1505: struct cs_channel *chan = &sc->sc_playback;
1506: struct cs_dma *p;
1507: u_int8_t reg;
1508: u_int32_t n, csr;
1509:
1510: if (chan->cs_locked != 0) {
1511: printf("cs4231_trigger_output: already running\n");
1512: return (EINVAL);
1513: }
1514:
1515: chan->cs_locked = 1;
1516: chan->cs_intr = intr;
1517: chan->cs_arg = arg;
1518:
1519: p = sc->sc_dmas;
1520: while (p != NULL && p->addr != start)
1521: p = p->next;
1522: if (p == NULL) {
1523: printf("cs4231_trigger_output: bad addr: %p\n", start);
1524: return (EINVAL);
1525: }
1526:
1527: n = (char *)end - (char *)start;
1528:
1529: /*
1530: * Do only `blksize' at a time, so audio_pint() is kept
1531: * synchronous with us...
1532: */
1533: chan->cs_blksz = blksize;
1534: chan->cs_curdma = p;
1535: chan->cs_segsz = n;
1536:
1537: if (n > chan->cs_blksz)
1538: n = chan->cs_blksz;
1539:
1540: chan->cs_cnt = n;
1541:
1542: csr = regs->dma_csr;
1543: regs->dma_pnva = (u_int32_t)p->addr_dva;
1544: regs->dma_pnc = n;
1545:
1546: if ((csr & APC_CSR_PDMA_GO) == 0 || (csr & APC_CSR_PPAUSE) != 0) {
1547: regs->dma_csr &= ~(APC_CSR_PIE | APC_CSR_PPAUSE);
1548: regs->dma_csr |= APC_CSR_EI | APC_CSR_GIE |
1549: APC_CSR_PIE | APC_CSR_EIE |
1550: APC_CSR_PMIE | APC_CSR_PDMA_GO;
1551: regs->iar = SP_LOWER_BASE_COUNT;
1552: regs->idr = 0xff;
1553: regs->iar = SP_UPPER_BASE_COUNT;
1554: regs->idr = 0xff;
1555: regs->iar = SP_INTERFACE_CONFIG;
1556: reg = regs->idr | PLAYBACK_ENABLE;
1557: regs->iar = SP_INTERFACE_CONFIG;
1558: regs->idr = reg;
1559: }
1560: return (0);
1561: }
1562:
1563: int
1564: cs4231_trigger_input(addr, start, end, blksize, intr, arg, param)
1565: void *addr, *start, *end;
1566: int blksize;
1567: void (*intr)(void *);
1568: void *arg;
1569: struct audio_params *param;
1570: {
1571: struct cs4231_softc *sc = addr;
1572: struct cs_channel *chan = &sc->sc_capture;
1573: struct cs_dma *p;
1574: u_int32_t csr;
1575: u_long n;
1576:
1577: if (chan->cs_locked != 0) {
1578: printf("%s: trigger_input: already running\n",
1579: sc->sc_dev.dv_xname);
1580: return (EINVAL);
1581: }
1582: chan->cs_locked = 1;
1583: chan->cs_intr = intr;
1584: chan->cs_arg = arg;
1585:
1586: for (p = sc->sc_dmas; p->addr != start; p = p->next)
1587: /*EMPTY*/;
1588: if (p == NULL) {
1589: printf("%s: trigger_input: bad addr: %p\n",
1590: sc->sc_dev.dv_xname, start);
1591: return (EINVAL);
1592: }
1593:
1594: n = (char *)end - (char *)start;
1595:
1596: /*
1597: * Do only `blksize' at a time, so audio_cint() is kept
1598: * synchronous with us...
1599: */
1600: chan->cs_blksz = blksize;
1601: chan->cs_curdma = p;
1602: chan->cs_segsz = n;
1603:
1604: if (n > chan->cs_blksz)
1605: n = chan->cs_blksz;
1606: chan->cs_cnt = n;
1607:
1608: sc->sc_regs->dma_cnva = (u_int32_t)p->addr_dva;
1609: sc->sc_regs->dma_cnc = n;
1610:
1611: csr = sc->sc_regs->dma_csr;
1612: if ((csr & APC_CSR_CDMA_GO) == 0 || (csr & APC_CSR_CPAUSE) != 0) {
1613: csr &= APC_CSR_CPAUSE;
1614: csr |= APC_CSR_GIE | APC_CSR_CMIE | APC_CSR_CIE | APC_CSR_EI |
1615: APC_CSR_CDMA_GO;
1616: sc->sc_regs->dma_csr = csr;
1617: cs4231_write(sc, CS_LOWER_REC_CNT, 0xff);
1618: cs4231_write(sc, CS_UPPER_REC_CNT, 0xff);
1619: cs4231_write(sc, SP_INTERFACE_CONFIG,
1620: cs4231_read(sc, SP_INTERFACE_CONFIG) | CAPTURE_ENABLE);
1621: }
1622:
1623: if (sc->sc_regs->dma_csr & APC_CSR_CD) {
1624: u_long nextaddr, togo;
1625:
1626: p = chan->cs_curdma;
1627: togo = chan->cs_segsz - chan->cs_cnt;
1628: if (togo == 0) {
1629: nextaddr = (u_int32_t)p->addr_dva;
1630: chan->cs_cnt = togo = chan->cs_blksz;
1631: } else {
1632: nextaddr = sc->sc_regs->dma_cnva + chan->cs_blksz;
1633: if (togo > chan->cs_blksz)
1634: togo = chan->cs_blksz;
1635: chan->cs_cnt += togo;
1636: }
1637:
1638: sc->sc_regs->dma_cnva = nextaddr;
1639: sc->sc_regs->dma_cnc = togo;
1640: }
1641:
1642: return (0);
1643: }
CVSweb