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