Annotation of sys/arch/macppc/dev/awacs.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: awacs.c,v 1.19 2007/04/22 22:31:14 deraadt Exp $ */
2: /* $NetBSD: awacs.c,v 1.4 2001/02/26 21:07:51 wiz Exp $ */
3:
4: /*-
5: * Copyright (c) 2000 Tsubai Masanari. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. The name of the author may not be used to endorse or promote products
16: * derived from this software without specific prior written permission.
17: *
18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28: */
29:
30: #include <sys/param.h>
31: #include <sys/audioio.h>
32: #include <sys/device.h>
33: #include <sys/malloc.h>
34: #include <sys/systm.h>
35:
36: #include <dev/auconv.h>
37: #include <dev/audio_if.h>
38: #include <dev/mulaw.h>
39:
40: #include <machine/bus.h>
41: #include <machine/autoconf.h>
42: #include <macppc/dev/dbdma.h>
43:
44: #ifdef AWACS_DEBUG
45: # define DPRINTF printf
46: #else
47: # define DPRINTF while (0) printf
48: #endif
49:
50: #define AWACS_DMALIST_MAX 32
51: #define AWACS_DMASEG_MAX NBPG
52:
53: struct awacs_dma {
54: bus_dmamap_t map;
55: caddr_t addr;
56: bus_dma_segment_t segs[AWACS_DMALIST_MAX];
57: int nsegs;
58: size_t size;
59: struct awacs_dma *next;
60: };
61:
62:
63: struct awacs_softc {
64: struct device sc_dev;
65:
66: void (*sc_ointr)(void *); /* dma completion intr handler */
67: void *sc_oarg; /* arg for sc_ointr() */
68:
69: void (*sc_iintr)(void *); /* dma completion intr handler */
70: void *sc_iarg; /* arg for sc_iintr() */
71:
72: u_int sc_record_source; /* recording source mask */
73: u_int sc_output_mask; /* output source mask */
74:
75: char *sc_reg;
76: u_int sc_codecctl0;
77: u_int sc_codecctl1;
78: u_int sc_codecctl2;
79: u_int sc_codecctl4;
80: u_int sc_soundctl;
81:
82: bus_dma_tag_t sc_dmat;
83: struct dbdma_regmap *sc_odma;
84: struct dbdma_regmap *sc_idma;
85: struct dbdma_command *sc_odmacmd, *sc_odmap;
86: struct dbdma_command *sc_idmacmd, *sc_idmap;
87: dbdma_t sc_odbdma, sc_idbdma;
88:
89: struct awacs_dma *sc_dmas;
90: };
91:
92: int awacs_match(struct device *, void *, void *);
93: void awacs_attach(struct device *, struct device *, void *);
94: int awacs_intr(void *);
95: int awacs_tx_intr(void *);
96: int awacs_rx_intr(void *);
97:
98: int awacs_open(void *, int);
99: void awacs_close(void *);
100: int awacs_query_encoding(void *, struct audio_encoding *);
101: int awacs_set_params(void *, int, int, struct audio_params *,
102: struct audio_params *);
103: int awacs_round_blocksize(void *, int);
104: int awacs_trigger_output(void *, void *, void *, int, void (*)(void *),
105: void *, struct audio_params *);
106: int awacs_trigger_input(void *, void *, void *, int, void (*)(void *),
107: void *, struct audio_params *);
108: int awacs_halt_output(void *);
109: int awacs_halt_input(void *);
110: int awacs_getdev(void *, struct audio_device *);
111: int awacs_set_port(void *, mixer_ctrl_t *);
112: int awacs_get_port(void *, mixer_ctrl_t *);
113: int awacs_query_devinfo(void *, mixer_devinfo_t *);
114: size_t awacs_round_buffersize(void *, int, size_t);
115: paddr_t awacs_mappage(void *, void *, off_t, int);
116: int awacs_get_props(void *);
117: void *awacs_allocm(void *, int, size_t, int, int);
118:
119: static inline u_int awacs_read_reg(struct awacs_softc *, int);
120: static inline void awacs_write_reg(struct awacs_softc *, int, int);
121: void awacs_write_codec(struct awacs_softc *, int);
122: void awacs_set_speaker_volume(struct awacs_softc *, int, int);
123: void awacs_set_ext_volume(struct awacs_softc *, int, int);
124: void awacs_set_rate(struct awacs_softc *, struct audio_params *);
125: void awacs_mono16_to_stereo16(void *, u_char *, int);
126: void awacs_swap_bytes_mono16_to_stereo16(void *, u_char *, int);
127: void awacs_cvt_ulinear_mono_16_be(void *, u_char *, int);
128: void awacs_cvt_ulinear_mono_16_le(void *, u_char *, int);
129:
130: struct cfattach awacs_ca = {
131: sizeof(struct awacs_softc), awacs_match, awacs_attach
132: };
133:
134: struct cfdriver awacs_cd = {
135: NULL, "awacs", DV_DULL
136: };
137:
138: struct audio_hw_if awacs_hw_if = {
139: awacs_open,
140: awacs_close,
141: NULL, /* drain */
142: awacs_query_encoding,
143: awacs_set_params,
144: awacs_round_blocksize,
145: NULL, /* commit_setting */
146: NULL, /* init_output */
147: NULL, /* init_input */
148: NULL, /* start_output */
149: NULL, /* start_input */
150: awacs_halt_output,
151: awacs_halt_input,
152: NULL, /* speaker_ctl */
153: awacs_getdev,
154: NULL, /* getfd */
155: awacs_set_port,
156: awacs_get_port,
157: awacs_query_devinfo,
158: awacs_allocm, /* allocm */
159: NULL, /* freem */
160: awacs_round_buffersize, /* round_buffersize */
161: awacs_mappage,
162: awacs_get_props,
163: awacs_trigger_output,
164: awacs_trigger_input
165: };
166:
167: struct audio_device awacs_device = {
168: "AWACS",
169: "",
170: "awacs"
171: };
172:
173: /* register offset */
174: #define AWACS_SOUND_CTRL 0x00
175: #define AWACS_CODEC_CTRL 0x10
176: #define AWACS_CODEC_STATUS 0x20
177: #define AWACS_CLIP_COUNT 0x30
178: #define AWACS_BYTE_SWAP 0x40
179:
180: /* sound control */
181: #define AWACS_INPUT_SUBFRAME0 0x00000001
182: #define AWACS_INPUT_SUBFRAME1 0x00000002
183: #define AWACS_INPUT_SUBFRAME2 0x00000004
184: #define AWACS_INPUT_SUBFRAME3 0x00000008
185:
186: #define AWACS_OUTPUT_SUBFRAME0 0x00000010
187: #define AWACS_OUTPUT_SUBFRAME1 0x00000020
188: #define AWACS_OUTPUT_SUBFRAME2 0x00000040
189: #define AWACS_OUTPUT_SUBFRAME3 0x00000080
190:
191: #define AWACS_RATE_44100 0x00000000
192: #define AWACS_RATE_29400 0x00000100
193: #define AWACS_RATE_22050 0x00000200
194: #define AWACS_RATE_17640 0x00000300
195: #define AWACS_RATE_14700 0x00000400
196: #define AWACS_RATE_11025 0x00000500
197: #define AWACS_RATE_8820 0x00000600
198: #define AWACS_RATE_7350 0x00000700
199: #define AWACS_RATE_MASK 0x00000700
200:
201: #define AWACS_CTL_CNTRLERR (1 << 11)
202: #define AWACS_CTL_PORTCHG (1 << 12)
203: #define AWACS_INT_CNTRLERR (1 << 13)
204: #define AWACS_INT_PORTCHG (1 << 14)
205:
206: /* codec control */
207: #define AWACS_CODEC_ADDR0 0x00000000
208: #define AWACS_CODEC_ADDR1 0x00001000
209: #define AWACS_CODEC_ADDR2 0x00002000
210: #define AWACS_CODEC_ADDR4 0x00004000
211: #define AWACS_CODEC_EMSEL0 0x00000000
212: #define AWACS_CODEC_EMSEL1 0x00400000
213: #define AWACS_CODEC_EMSEL2 0x00800000
214: #define AWACS_CODEC_EMSEL4 0x00c00000
215: #define AWACS_CODEC_BUSY 0x01000000
216:
217: /* cc0 */
218: #define AWACS_DEFAULT_CD_GAIN 0x000000bb
219: #define AWACS_INPUT_CD 0x00000200
220: #define AWACS_INPUT_LINE 0x00000400
221: #define AWACS_INPUT_MICROPHONE 0x00000800
222: #define AWACS_INPUT_MASK 0x00000e00
223:
224: /* cc1 */
225: #define AWACS_MUTE_SPEAKER 0x00000080
226: #define AWACS_MUTE_HEADPHONE 0x00000200
227:
228: const struct awacs_speed_tab {
229: int rate;
230: u_int32_t bits;
231: } awacs_speeds[] = {
232: { 7350, AWACS_RATE_7350 },
233: { 8820, AWACS_RATE_8820 },
234: { 11025, AWACS_RATE_11025 },
235: { 14700, AWACS_RATE_14700 },
236: { 17640, AWACS_RATE_17640 },
237: { 22050, AWACS_RATE_22050 },
238: { 29400, AWACS_RATE_29400 },
239: { 44100, AWACS_RATE_44100 },
240: };
241:
242: int
243: awacs_match(struct device *parent, void *match, void *aux)
244: {
245: struct confargs *ca = aux;
246:
247: if (strcmp(ca->ca_name, "awacs") != 0 &&
248: strcmp(ca->ca_name, "davbus") != 0)
249: return 0;
250:
251: #ifdef DEBUG
252: printf("awacs: matched %s nreg %d nintr %d\n",
253: ca->ca_name, ca->ca_nreg, ca->ca_nintr);
254: #endif
255:
256: if (ca->ca_nreg < 24 || ca->ca_nintr < 12)
257: return 0;
258:
259: /* XXX for now
260: if (ca->ca_nintr > 12)
261: return 0;
262: */
263:
264: return 1;
265: }
266:
267: void
268: awacs_attach(struct device *parent, struct device *self, void *aux)
269: {
270: struct awacs_softc *sc = (struct awacs_softc *)self;
271: struct confargs *ca = aux;
272: int cirq, oirq, iirq;
273: int cirq_type, oirq_type, iirq_type;
274:
275: ca->ca_reg[0] += ca->ca_baseaddr;
276: ca->ca_reg[2] += ca->ca_baseaddr;
277: ca->ca_reg[4] += ca->ca_baseaddr;
278:
279: sc->sc_reg = mapiodev(ca->ca_reg[0], ca->ca_reg[1]);
280:
281: sc->sc_dmat = ca->ca_dmat;
282: sc->sc_odma = mapiodev(ca->ca_reg[2], ca->ca_reg[3]); /* out */
283: sc->sc_idma = mapiodev(ca->ca_reg[4], ca->ca_reg[5]); /* in */
284: sc->sc_odbdma = dbdma_alloc(sc->sc_dmat, AWACS_DMALIST_MAX);
285: sc->sc_odmacmd = sc->sc_odbdma->d_addr;
286: sc->sc_idbdma = dbdma_alloc(sc->sc_dmat, AWACS_DMALIST_MAX);
287: sc->sc_idmacmd = sc->sc_idbdma->d_addr;
288:
289: if (ca->ca_nintr == 24) {
290: cirq = ca->ca_intr[0];
291: oirq = ca->ca_intr[2];
292: iirq = ca->ca_intr[4];
293: cirq_type = ca->ca_intr[1] ? IST_LEVEL : IST_EDGE;
294: oirq_type = ca->ca_intr[3] ? IST_LEVEL : IST_EDGE;
295: iirq_type = ca->ca_intr[5] ? IST_LEVEL : IST_EDGE;
296: } else {
297: cirq = ca->ca_intr[0];
298: oirq = ca->ca_intr[1];
299: iirq = ca->ca_intr[2];
300: cirq_type = oirq_type = iirq_type = IST_LEVEL;
301: }
302: mac_intr_establish(parent, cirq, cirq_type, IPL_AUDIO, awacs_intr,
303: sc, sc->sc_dev.dv_xname);
304: mac_intr_establish(parent, oirq, oirq_type, IPL_AUDIO, awacs_tx_intr,
305: sc, sc->sc_dev.dv_xname);
306: mac_intr_establish(parent, iirq, iirq_type, IPL_AUDIO, awacs_rx_intr,
307: sc, sc->sc_dev.dv_xname);
308:
309: printf(": irq %d,%d,%d",
310: cirq, oirq, iirq);
311:
312: sc->sc_soundctl = AWACS_INPUT_SUBFRAME0 | AWACS_OUTPUT_SUBFRAME0 |
313: AWACS_RATE_44100 | AWACS_INT_PORTCHG;
314: awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl);
315:
316: sc->sc_codecctl0 = AWACS_CODEC_ADDR0 | AWACS_CODEC_EMSEL0;
317: sc->sc_codecctl1 = AWACS_CODEC_ADDR1 | AWACS_CODEC_EMSEL0;
318: sc->sc_codecctl2 = AWACS_CODEC_ADDR2 | AWACS_CODEC_EMSEL0;
319: sc->sc_codecctl4 = AWACS_CODEC_ADDR4 | AWACS_CODEC_EMSEL0;
320:
321: sc->sc_codecctl0 |= AWACS_INPUT_CD | AWACS_DEFAULT_CD_GAIN;
322: awacs_write_codec(sc, sc->sc_codecctl0);
323:
324: /* Set initial volume[s] */
325: awacs_set_speaker_volume(sc, 80, 80);
326: awacs_set_ext_volume(sc, 80, 80);
327:
328: /* Set loopback (for CD?) */
329: /* sc->sc_codecctl1 |= 0x440; */
330: sc->sc_codecctl1 |= 0x40;
331: awacs_write_codec(sc, sc->sc_codecctl1);
332:
333: /* check for headphone present */
334: if (awacs_read_reg(sc, AWACS_CODEC_STATUS) & 0x8) {
335: /* default output to speakers */
336: printf(" headphones");
337: sc->sc_output_mask = 1 << 1;
338: sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE;
339: sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER;
340: awacs_write_codec(sc, sc->sc_codecctl1);
341: } else {
342: /* default output to speakers */
343: printf(" speaker");
344: sc->sc_output_mask = 1 << 0;
345: sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER;
346: sc->sc_codecctl1 |= AWACS_MUTE_HEADPHONE;
347: awacs_write_codec(sc, sc->sc_codecctl1);
348: }
349:
350: /* default input from CD */
351: sc->sc_record_source = 1 << 0;
352: sc->sc_codecctl0 &= ~AWACS_INPUT_MASK;
353: sc->sc_codecctl0 |= AWACS_INPUT_CD;
354: awacs_write_codec(sc, sc->sc_codecctl0);
355:
356: /* Enable interrupts and looping mode. */
357: /* XXX ... */
358: awacs_halt_output(sc);
359: awacs_halt_input(sc);
360: printf("\n");
361:
362: audio_attach_mi(&awacs_hw_if, sc, &sc->sc_dev);
363: }
364:
365: u_int
366: awacs_read_reg(struct awacs_softc *sc, int reg)
367: {
368: char *addr = sc->sc_reg;
369:
370: return in32rb(addr + reg);
371: }
372:
373: void
374: awacs_write_reg(struct awacs_softc *sc, int reg, int val)
375: {
376: char *addr = sc->sc_reg;
377:
378: out32rb(addr + reg, val);
379: }
380:
381: void
382: awacs_write_codec(struct awacs_softc *sc, int value)
383: {
384: awacs_write_reg(sc, AWACS_CODEC_CTRL, value);
385: while (awacs_read_reg(sc, AWACS_CODEC_CTRL) & AWACS_CODEC_BUSY);
386: }
387:
388: int
389: awacs_intr(void *v)
390: {
391: int reason;
392: struct awacs_softc *sc = v;
393: reason = awacs_read_reg(sc, AWACS_SOUND_CTRL);
394:
395: if (reason & AWACS_CTL_CNTRLERR) {
396: /* change outputs ?? */
397: }
398: if (reason & AWACS_CTL_PORTCHG) {
399: #ifdef DEBUG
400: printf("status = %x\n", awacs_read_reg(sc, AWACS_CODEC_STATUS));
401: #endif
402:
403: if (awacs_read_reg(sc, AWACS_CODEC_STATUS) & 0x8) {
404: /* default output to speakers */
405: sc->sc_output_mask = 1 << 1;
406: sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE;
407: sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER;
408: awacs_write_codec(sc, sc->sc_codecctl1);
409: } else {
410: /* default output to speakers */
411: sc->sc_output_mask = 1 << 0;
412: sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER;
413: sc->sc_codecctl1 |= AWACS_MUTE_HEADPHONE;
414: awacs_write_codec(sc, sc->sc_codecctl1);
415: }
416: }
417:
418: awacs_write_reg(sc, AWACS_SOUND_CTRL, reason); /* clear interrupt */
419: return 1;
420: }
421:
422: int
423: awacs_tx_intr(void *v)
424: {
425: struct awacs_softc *sc = v;
426: struct dbdma_command *cmd = sc->sc_odmap;
427: u_int16_t c, status;
428:
429: /* if not set we are not running */
430: if (!cmd)
431: return (0);
432:
433: c = in16rb(&cmd->d_command);
434: status = in16rb(&cmd->d_status);
435:
436: if (c >> 12 == DBDMA_CMD_OUT_LAST)
437: sc->sc_odmap = sc->sc_odmacmd;
438: else
439: sc->sc_odmap++;
440:
441: if (c & (DBDMA_INT_ALWAYS << 4)) {
442: cmd->d_status = 0;
443: if (status) /* status == 0x8400 */
444: if (sc->sc_ointr)
445: (*sc->sc_ointr)(sc->sc_oarg);
446: }
447:
448: return (1);
449: }
450: int
451: awacs_rx_intr(void *v)
452: {
453: struct awacs_softc *sc = v;
454: struct dbdma_command *cmd = sc->sc_idmap;
455: u_int16_t c, status;
456:
457: /* if not set we are not running */
458: if (!cmd)
459: return (0);
460:
461: c = in16rb(&cmd->d_command);
462: status = in16rb(&cmd->d_status);
463:
464: if (c >> 12 == DBDMA_CMD_IN_LAST)
465: sc->sc_idmap = sc->sc_idmacmd;
466: else
467: sc->sc_idmap++;
468:
469: if (c & (DBDMA_INT_ALWAYS << 4)) {
470: cmd->d_status = 0;
471: if (status) /* status == 0x8400 */
472: if (sc->sc_iintr)
473: (*sc->sc_iintr)(sc->sc_iarg);
474: }
475:
476: return (1);
477: }
478:
479: int
480: awacs_open(void *h, int flags)
481: {
482: return 0;
483: }
484:
485: /*
486: * Close function is called at splaudio().
487: */
488: void
489: awacs_close(void *h)
490: {
491: struct awacs_softc *sc = h;
492:
493: awacs_halt_output(sc);
494: awacs_halt_input(sc);
495:
496: sc->sc_ointr = 0;
497: sc->sc_iintr = 0;
498: }
499:
500: int
501: awacs_query_encoding(void *h, struct audio_encoding *ae)
502: {
503: switch (ae->index) {
504: case 0:
505: strlcpy(ae->name, AudioEslinear, sizeof ae->name);
506: ae->encoding = AUDIO_ENCODING_SLINEAR;
507: ae->precision = 16;
508: ae->flags = 0;
509: break;
510: case 1:
511: strlcpy(ae->name, AudioEslinear_be, sizeof ae->name);
512: ae->encoding = AUDIO_ENCODING_SLINEAR_BE;
513: ae->precision = 16;
514: ae->flags = 0;
515: break;
516: case 2:
517: strlcpy(ae->name, AudioEslinear_le, sizeof ae->name);
518: ae->encoding = AUDIO_ENCODING_SLINEAR_LE;
519: ae->precision = 16;
520: ae->flags = 0;
521: break;
522: case 3:
523: strlcpy(ae->name, AudioEmulaw, sizeof ae->name);
524: ae->encoding = AUDIO_ENCODING_ULAW;
525: ae->precision = 8;
526: ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
527: break;
528: case 4:
529: strlcpy(ae->name, AudioEalaw, sizeof ae->name);
530: ae->encoding = AUDIO_ENCODING_ALAW;
531: ae->precision = 8;
532: ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
533: break;
534: case 5:
535: strlcpy(ae->name, AudioEulinear, sizeof ae->name);
536: ae->encoding = AUDIO_ENCODING_ULINEAR;
537: ae->precision = 16;
538: ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
539: break;
540: case 6:
541: strlcpy(ae->name, AudioEulinear_le, sizeof ae->name);
542: ae->encoding = AUDIO_ENCODING_ULINEAR_LE;
543: ae->precision = 16;
544: ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
545: break;
546: case 7:
547: strlcpy(ae->name, AudioEulinear_be, sizeof ae->name);
548: ae->encoding = AUDIO_ENCODING_ULINEAR_BE;
549: ae->precision = 16;
550: ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
551: break;
552: default:
553: return (EINVAL);
554: }
555: return (0);
556: }
557:
558: void
559: awacs_mono16_to_stereo16(void *v, u_char *p, int cc)
560: {
561: int x;
562: int16_t *src, *dst;
563:
564: src = (void *)(p + cc);
565: dst = (void *)(p + cc * 2);
566: while (cc > 0) {
567: x = *--src;
568: *--dst = x;
569: *--dst = x;
570: cc -= 2;
571: }
572: }
573:
574: void
575: awacs_swap_bytes_mono16_to_stereo16(void *v, u_char *p, int cc)
576: {
577: swap_bytes(v, p, cc);
578: awacs_mono16_to_stereo16(v, p, cc);
579: }
580:
581: void
582: awacs_cvt_ulinear_mono_16_le(void *v, u_char *p, int cc)
583: {
584: swap_bytes_change_sign16_be(v, p, cc);
585: awacs_mono16_to_stereo16(v, p, cc);
586: }
587:
588: void
589: awacs_cvt_ulinear_mono_16_be(void *v, u_char *p, int cc)
590: {
591: change_sign16_be(v, p, cc);
592: awacs_mono16_to_stereo16(v, p, cc);
593: }
594:
595: int
596: awacs_set_params(void *h, int setmode, int usemode, struct audio_params *play,
597: struct audio_params *rec)
598: {
599: struct awacs_softc *sc = h;
600: struct audio_params *p;
601: int mode;
602:
603: /*
604: * This device only has one clock, so make the sample rates match.
605: */
606: if (play->sample_rate != rec->sample_rate &&
607: usemode == (AUMODE_PLAY | AUMODE_RECORD)) {
608: if (setmode == AUMODE_PLAY) {
609: rec->sample_rate = play->sample_rate;
610: setmode |= AUMODE_RECORD;
611: } else if (setmode == AUMODE_RECORD) {
612: play->sample_rate = rec->sample_rate;
613: setmode |= AUMODE_PLAY;
614: } else
615: return EINVAL;
616: }
617:
618: for (mode = AUMODE_RECORD; mode != -1;
619: mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
620: if ((setmode & mode) == 0)
621: continue;
622:
623: p = mode == AUMODE_PLAY ? play : rec;
624:
625: if (p->sample_rate < 4000 || p->sample_rate > 50000 ||
626: (p->precision != 8 && p->precision != 16) ||
627: (p->channels != 1 && p->channels != 2))
628: return EINVAL;
629:
630: p->factor = 1;
631: p->sw_code = NULL;
632: awacs_write_reg(sc, AWACS_BYTE_SWAP, 0);
633:
634: switch (p->encoding) {
635:
636: case AUDIO_ENCODING_SLINEAR_LE:
637: if (p->channels == 2 && p->precision == 16) {
638: p->sw_code = swap_bytes;
639: break;
640: }
641: if (p->channels == 1 && p->precision == 16) {
642: p->factor = 2;
643: p->sw_code =
644: awacs_swap_bytes_mono16_to_stereo16;
645: break;
646: }
647: return (EINVAL);
648: case AUDIO_ENCODING_SLINEAR_BE:
649: if (p->channels == 2 && p->precision == 16)
650: break;
651: if (p->channels == 1 && p->precision == 16) {
652: p->factor = 2;
653: p->sw_code = awacs_mono16_to_stereo16;
654: break;
655: }
656: return (EINVAL);
657: case AUDIO_ENCODING_ULINEAR_LE:
658: if (p->channels == 2 && p->precision == 16) {
659: p->sw_code = swap_bytes_change_sign16_be;
660: break;
661: }
662: if (p->channels == 1 && p->precision == 16) {
663: p->factor = 2;
664: p->sw_code = awacs_cvt_ulinear_mono_16_le;
665: break;
666: }
667: return (EINVAL);
668: case AUDIO_ENCODING_ULINEAR_BE:
669: if (p->channels == 2 && p->precision == 16) {
670: p->sw_code = change_sign16_be;
671: break;
672: }
673: if (p->channels == 1 && p->precision == 16) {
674: p->factor = 2;
675: p->sw_code = awacs_cvt_ulinear_mono_16_be;
676: break;
677: }
678: return (EINVAL);
679: case AUDIO_ENCODING_ULAW:
680: if (mode == AUMODE_PLAY) {
681: p->factor = 2;
682: p->sw_code = mulaw_to_slinear16_be;
683: break;
684: } else
685: break; /* XXX */
686: return (EINVAL);
687: case AUDIO_ENCODING_ALAW:
688: if (mode == AUMODE_PLAY) {
689: p->factor = 2;
690: p->sw_code = alaw_to_slinear16_be;
691: break;
692: }
693: return (EINVAL);
694: default:
695: return (EINVAL);
696: }
697: }
698:
699: /* Set the speed */
700: awacs_set_rate(sc, p);
701:
702: return (0);
703: }
704:
705: int
706: awacs_round_blocksize(void *h, int size)
707: {
708: if (size < PAGE_SIZE)
709: size = PAGE_SIZE;
710: return (size + PAGE_SIZE / 2) & ~(PGOFSET);
711: }
712:
713: int
714: awacs_halt_output(void *h)
715: {
716: struct awacs_softc *sc = h;
717:
718: dbdma_stop(sc->sc_odma);
719: dbdma_reset(sc->sc_odma);
720: dbdma_stop(sc->sc_odma);
721: sc->sc_odmap = NULL;
722: return 0;
723: }
724:
725: int
726: awacs_halt_input(void *h)
727: {
728: struct awacs_softc *sc = h;
729:
730: dbdma_stop(sc->sc_idma);
731: dbdma_reset(sc->sc_idma);
732: return 0;
733: }
734:
735: int
736: awacs_getdev(void *h, struct audio_device *retp)
737: {
738: *retp = awacs_device;
739: return 0;
740: }
741:
742: enum {
743: AWACS_OUTPUT_SELECT,
744: AWACS_VOL_SPEAKER,
745: AWACS_VOL_HEADPHONE,
746: AWACS_OUTPUT_CLASS,
747: AWACS_MONITOR_CLASS,
748: AWACS_INPUT_SELECT,
749: AWACS_VOL_INPUT,
750: AWACS_INPUT_CLASS,
751: AWACS_RECORD_CLASS,
752: AWACS_ENUM_LAST
753: };
754:
755: int
756: awacs_set_port(void *h, mixer_ctrl_t *mc)
757: {
758: struct awacs_softc *sc = h;
759: int l, r;
760:
761: DPRINTF("awacs_set_port dev = %d, type = %d\n", mc->dev, mc->type);
762:
763: l = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
764: r = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
765:
766: switch (mc->dev) {
767: case AWACS_OUTPUT_SELECT:
768: /* no change necessary? */
769: if (mc->un.mask == sc->sc_output_mask)
770: return 0;
771: sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER | AWACS_MUTE_HEADPHONE;
772: if (mc->un.mask & 1 << 0)
773: sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER;
774: if (mc->un.mask & 1 << 1)
775: sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE;
776:
777: awacs_write_codec(sc, sc->sc_codecctl1);
778: sc->sc_output_mask = mc->un.mask;
779: return 0;
780:
781: case AWACS_VOL_SPEAKER:
782: awacs_set_speaker_volume(sc, l, r);
783: return 0;
784:
785: case AWACS_VOL_HEADPHONE:
786: awacs_set_ext_volume(sc, l, r);
787: return 0;
788:
789: case AWACS_VOL_INPUT:
790: sc->sc_codecctl0 &= ~0xff;
791: sc->sc_codecctl0 |= (l & 0xf0) | (r >> 4);
792: awacs_write_codec(sc, sc->sc_codecctl0);
793: return 0;
794:
795: case AWACS_INPUT_SELECT:
796: /* no change necessary? */
797: if (mc->un.mask == sc->sc_record_source)
798: return 0;
799: switch(mc->un.mask) {
800: case 1<<0: /* CD */
801: sc->sc_codecctl0 &= ~AWACS_INPUT_MASK;
802: sc->sc_codecctl0 |= AWACS_INPUT_CD;
803: awacs_write_codec(sc, sc->sc_codecctl0);
804: break;
805: case 1<<1: /* microphone */
806: sc->sc_codecctl0 &= ~AWACS_INPUT_MASK;
807: sc->sc_codecctl0 |= AWACS_INPUT_MICROPHONE;
808: awacs_write_codec(sc, sc->sc_codecctl0);
809: break;
810: case 1<<2: /* line in */
811: sc->sc_codecctl0 &= ~AWACS_INPUT_MASK;
812: sc->sc_codecctl0 |= AWACS_INPUT_LINE;
813: awacs_write_codec(sc, sc->sc_codecctl0);
814: break;
815: default: /* invalid argument */
816: return -1;
817: }
818: sc->sc_record_source = mc->un.mask;
819: return 0;
820: }
821:
822: return ENXIO;
823: }
824:
825: int
826: awacs_get_port(void *h, mixer_ctrl_t *mc)
827: {
828: struct awacs_softc *sc = h;
829: int vol, l, r;
830:
831: DPRINTF("awacs_get_port dev = %d, type = %d\n", mc->dev, mc->type);
832:
833: switch (mc->dev) {
834: case AWACS_OUTPUT_SELECT:
835: mc->un.mask = sc->sc_output_mask;
836: return 0;
837:
838: case AWACS_VOL_SPEAKER:
839: vol = sc->sc_codecctl4;
840: l = (15 - ((vol & 0x3c0) >> 6)) * 16;
841: r = (15 - (vol & 0x0f)) * 16;
842: mc->un.mask = 1 << 0;
843: mc->un.value.num_channels = 2;
844: mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
845: mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
846: return 0;
847:
848: case AWACS_VOL_HEADPHONE:
849: vol = sc->sc_codecctl2;
850: l = (15 - ((vol & 0x3c0) >> 6)) * 16;
851: r = (15 - (vol & 0x0f)) * 16;
852: mc->un.mask = 1 << 1;
853: mc->un.value.num_channels = 2;
854: mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
855: mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
856: return 0;
857:
858: case AWACS_INPUT_SELECT:
859: mc->un.mask = sc->sc_record_source;
860: return 0;
861:
862: case AWACS_VOL_INPUT:
863: vol = sc->sc_codecctl0 & 0xff;
864: l = (vol & 0xf0);
865: r = (vol & 0x0f) << 4;
866: mc->un.mask = sc->sc_record_source;
867: mc->un.value.num_channels = 2;
868: mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
869: mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
870: return 0;
871:
872: default:
873: return ENXIO;
874: }
875:
876: return 0;
877: }
878:
879: int
880: awacs_query_devinfo(void *h, mixer_devinfo_t *dip)
881: {
882: DPRINTF("query_devinfo %d\n", dip->index);
883:
884: switch (dip->index) {
885:
886: case AWACS_OUTPUT_SELECT:
887: dip->mixer_class = AWACS_OUTPUT_CLASS;
888: strlcpy(dip->label.name, AudioNselect, sizeof dip->label.name);
889: dip->type = AUDIO_MIXER_SET;
890: dip->prev = dip->next = AUDIO_MIXER_LAST;
891: dip->un.s.num_mem = 2;
892: strlcpy(dip->un.s.member[0].label.name, AudioNspeaker,
893: sizeof dip->un.s.member[0].label.name);
894: dip->un.s.member[0].mask = 1 << 0;
895: strlcpy(dip->un.s.member[1].label.name, AudioNheadphone,
896: sizeof dip->un.s.member[0].label.name);
897: dip->un.s.member[1].mask = 1 << 1;
898: return 0;
899:
900: case AWACS_VOL_SPEAKER:
901: dip->mixer_class = AWACS_OUTPUT_CLASS;
902: strlcpy(dip->label.name, AudioNspeaker,
903: sizeof dip->label.name);
904: dip->type = AUDIO_MIXER_VALUE;
905: dip->prev = dip->next = AUDIO_MIXER_LAST;
906: dip->un.v.num_channels = 2;
907: strlcpy(dip->un.v.units.name, AudioNvolume,
908: sizeof dip->un.v.units.name);
909: return 0;
910:
911: case AWACS_VOL_HEADPHONE:
912: dip->mixer_class = AWACS_OUTPUT_CLASS;
913: strlcpy(dip->label.name, AudioNheadphone,
914: sizeof dip->label.name);
915: dip->type = AUDIO_MIXER_VALUE;
916: dip->prev = dip->next = AUDIO_MIXER_LAST;
917: dip->un.v.num_channels = 2;
918: strlcpy(dip->un.v.units.name, AudioNvolume,
919: sizeof dip->un.v.units.name);
920: return 0;
921:
922: case AWACS_INPUT_SELECT:
923: dip->mixer_class = AWACS_RECORD_CLASS;
924: strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
925: dip->type = AUDIO_MIXER_SET;
926: dip->prev = dip->next = AUDIO_MIXER_LAST;
927: dip->un.s.num_mem = 3;
928: strlcpy(dip->un.s.member[0].label.name, AudioNcd,
929: sizeof dip->un.s.member[0].label.name);
930: dip->un.s.member[0].mask = 1 << 0;
931: strlcpy(dip->un.s.member[1].label.name, AudioNmicrophone,
932: sizeof dip->un.s.member[1].label.name);
933: dip->un.s.member[1].mask = 1 << 1;
934: strlcpy(dip->un.s.member[2].label.name, AudioNline,
935: sizeof dip->un.s.member[2].label.name);
936: dip->un.s.member[2].mask = 1 << 2;
937: return 0;
938:
939: case AWACS_VOL_INPUT:
940: dip->mixer_class = AWACS_RECORD_CLASS;
941: strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
942: dip->type = AUDIO_MIXER_VALUE;
943: dip->prev = dip->next = AUDIO_MIXER_LAST;
944: dip->un.v.num_channels = 2;
945: strlcpy(dip->un.v.units.name, AudioNvolume,
946: sizeof dip->un.v.units.name);
947: return 0;
948:
949: case AWACS_MONITOR_CLASS:
950: dip->mixer_class = AWACS_MONITOR_CLASS;
951: strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name);
952: dip->type = AUDIO_MIXER_CLASS;
953: dip->next = dip->prev = AUDIO_MIXER_LAST;
954: return 0;
955:
956: case AWACS_OUTPUT_CLASS:
957: dip->mixer_class = AWACS_OUTPUT_CLASS;
958: strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
959: dip->type = AUDIO_MIXER_CLASS;
960: dip->next = dip->prev = AUDIO_MIXER_LAST;
961: return 0;
962:
963: case AWACS_RECORD_CLASS:
964: dip->mixer_class = AWACS_MONITOR_CLASS;
965: strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
966: dip->type = AUDIO_MIXER_CLASS;
967: dip->next = dip->prev = AUDIO_MIXER_LAST;
968: return 0;
969: }
970:
971: return ENXIO;
972: }
973:
974: size_t
975: awacs_round_buffersize(void *h, int dir, size_t size)
976: {
977: size = (size + PGOFSET) & ~(PGOFSET);
978: if (size > AWACS_DMALIST_MAX * AWACS_DMASEG_MAX)
979: size = AWACS_DMALIST_MAX * AWACS_DMASEG_MAX;
980: return (size);
981: }
982:
983: void *
984: awacs_allocm(void *h, int dir, size_t size, int type, int flags)
985: {
986: struct awacs_softc *sc = h;
987: struct awacs_dma *p;
988: int error;
989:
990: if (size > AWACS_DMALIST_MAX * AWACS_DMASEG_MAX)
991: return (NULL);
992:
993: p = malloc(sizeof(*p), type, flags);
994: if (!p)
995: return (NULL);
996: bzero(p, sizeof(*p));
997:
998: /* convert to the bus.h style, not used otherwise */
999: if (flags & M_NOWAIT)
1000: flags = BUS_DMA_NOWAIT;
1001:
1002: p->size = size;
1003: if ((error = bus_dmamem_alloc(sc->sc_dmat, p->size, NBPG, 0, p->segs,
1004: 1, &p->nsegs, flags)) != 0) {
1005: printf("%s: unable to allocate dma, error = %d\n",
1006: sc->sc_dev.dv_xname, error);
1007: free(p, type);
1008: return NULL;
1009: }
1010:
1011: if ((error = bus_dmamem_map(sc->sc_dmat, p->segs, p->nsegs, p->size,
1012: &p->addr, flags | BUS_DMA_COHERENT)) != 0) {
1013: printf("%s: unable to map dma, error = %d\n",
1014: sc->sc_dev.dv_xname, error);
1015: bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
1016: free(p, type);
1017: return NULL;
1018: }
1019:
1020: if ((error = bus_dmamap_create(sc->sc_dmat, p->size, 1,
1021: p->size, 0, flags, &p->map)) != 0) {
1022: printf("%s: unable to create dma map, error = %d\n",
1023: sc->sc_dev.dv_xname, error);
1024: bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
1025: bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
1026: free(p, type);
1027: return NULL;
1028: }
1029:
1030: if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, p->size,
1031: NULL, flags)) != 0) {
1032: printf("%s: unable to load dma map, error = %d\n",
1033: sc->sc_dev.dv_xname, error);
1034: bus_dmamap_destroy(sc->sc_dmat, p->map);
1035: bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
1036: bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
1037: free(p, type);
1038: return NULL;
1039: }
1040:
1041: p->next = sc->sc_dmas;
1042: sc->sc_dmas = p;
1043:
1044: return p->addr;
1045: }
1046:
1047: paddr_t
1048: awacs_mappage(void *h, void *mem, off_t off, int prot)
1049: {
1050: if (off < 0)
1051: return -1;
1052: return -1; /* XXX */
1053: }
1054:
1055: int
1056: awacs_get_props(void *h)
1057: {
1058: return AUDIO_PROP_FULLDUPLEX /* | AUDIO_PROP_MMAP */;
1059: }
1060:
1061: int
1062: awacs_trigger_output(void *h, void *start, void *end, int bsize,
1063: void (*intr)(void *), void *arg, struct audio_params *param)
1064: {
1065: struct awacs_softc *sc = h;
1066: struct awacs_dma *p;
1067: struct dbdma_command *cmd = sc->sc_odmacmd;
1068: vaddr_t spa, pa, epa;
1069: int c;
1070:
1071: DPRINTF("trigger_output %p %p 0x%x\n", start, end, bsize);
1072:
1073: for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
1074: if (!p)
1075: return -1;
1076:
1077: sc->sc_ointr = intr;
1078: sc->sc_oarg = arg;
1079: sc->sc_odmap = sc->sc_odmacmd;
1080:
1081: spa = p->segs[0].ds_addr;
1082: c = DBDMA_CMD_OUT_MORE;
1083: for (pa = spa, epa = spa + (end - start);
1084: pa < epa; pa += bsize, cmd++) {
1085:
1086: if (pa + bsize == epa)
1087: c = DBDMA_CMD_OUT_LAST;
1088:
1089: DBDMA_BUILD(cmd, c, 0, bsize, pa, DBDMA_INT_ALWAYS,
1090: DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
1091: }
1092:
1093: DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0,
1094: DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS);
1095: dbdma_st32(&cmd->d_cmddep, sc->sc_odbdma->d_paddr);
1096:
1097: dbdma_start(sc->sc_odma, sc->sc_odbdma);
1098:
1099: return 0;
1100: }
1101:
1102: int
1103: awacs_trigger_input(void *h, void *start, void *end, int bsize,
1104: void (*intr)(void *), void *arg, struct audio_params *param)
1105: {
1106: struct awacs_softc *sc = h;
1107: struct awacs_dma *p;
1108: struct dbdma_command *cmd = sc->sc_idmacmd;
1109: vaddr_t spa, pa, epa;
1110: int c;
1111:
1112: printf("trigger_input %p %p 0x%x\n", start, end, bsize);
1113:
1114: for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
1115: if (!p)
1116: return -1;
1117:
1118: sc->sc_iintr = intr;
1119: sc->sc_iarg = arg;
1120: sc->sc_idmap = sc->sc_idmacmd;
1121:
1122: spa = p->segs[0].ds_addr;
1123: c = DBDMA_CMD_IN_MORE;
1124: for (pa = spa, epa = spa + (end - start);
1125: pa < epa; pa += bsize, cmd++) {
1126:
1127: if (pa + bsize == epa)
1128: c = DBDMA_CMD_IN_LAST;
1129:
1130: DBDMA_BUILD(cmd, c, 0, bsize, pa, DBDMA_INT_ALWAYS,
1131: DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
1132: }
1133:
1134: DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0,
1135: DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS);
1136: dbdma_st32(&cmd->d_cmddep, sc->sc_idbdma->d_paddr);
1137:
1138: dbdma_start(sc->sc_idma, sc->sc_idbdma);
1139:
1140: return 0;
1141: }
1142:
1143: void
1144: awacs_set_speaker_volume(struct awacs_softc *sc, int left, int right)
1145: {
1146: int lval = 15 - (left & 0xff) / 16;
1147: int rval = 15 - (right & 0xff) / 16;
1148:
1149: DPRINTF("speaker_volume %d %d\n", lval, rval);
1150:
1151: sc->sc_codecctl4 &= ~0x3cf;
1152: sc->sc_codecctl4 |= (lval << 6) | rval;
1153: awacs_write_codec(sc, sc->sc_codecctl4);
1154: }
1155:
1156: void
1157: awacs_set_ext_volume(struct awacs_softc *sc, int left, int right)
1158: {
1159: int lval = 15 - (left & 0xff) / 16;
1160: int rval = 15 - (right & 0xff) / 16;
1161:
1162: DPRINTF("ext_volume %d %d\n", lval, rval);
1163:
1164: sc->sc_codecctl2 &= ~0x3cf;
1165: sc->sc_codecctl2 |= (lval << 6) | rval;
1166: awacs_write_codec(sc, sc->sc_codecctl2);
1167: }
1168:
1169: void
1170: awacs_set_rate(struct awacs_softc *sc, struct audio_params *p)
1171: {
1172: int selected = -1;
1173: size_t n, i;
1174:
1175: n = sizeof(awacs_speeds)/sizeof(awacs_speeds[0]);
1176:
1177: if (p->sample_rate < awacs_speeds[0].rate)
1178: selected = 0;
1179: if (p->sample_rate > awacs_speeds[n - 1].rate)
1180: selected = n - 1;
1181:
1182: for (i = 1; selected == -1 && i < n; i++) {
1183: if (p->sample_rate == awacs_speeds[i].rate)
1184: selected = i;
1185: else if (p->sample_rate < awacs_speeds[i].rate) {
1186: u_int diff1, diff2;
1187:
1188: diff1 = p->sample_rate - awacs_speeds[i - 1].rate;
1189: diff2 = awacs_speeds[i].rate - p->sample_rate;
1190: selected = (diff1 < diff2) ? i - 1 : i;
1191: }
1192: }
1193:
1194: if (selected == -1)
1195: selected = 0;
1196:
1197: sc->sc_soundctl &= ~AWACS_RATE_MASK;
1198: sc->sc_soundctl |= awacs_speeds[selected].bits;
1199: p->sample_rate = awacs_speeds[selected].rate;
1200: awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl);
1201: }
CVSweb