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