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