aica.c revision 1.24.4.1 1 /* $NetBSD: aica.c,v 1.24.4.1 2019/06/10 22:06:01 christos Exp $ */
2
3 /*
4 * Copyright (c) 2003 SHIMIZU Ryo <ryo (at) misakimix.org>
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 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: aica.c,v 1.24.4.1 2019/06/10 22:06:01 christos Exp $");
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/device.h>
37 #include <sys/kernel.h>
38 #include <sys/proc.h>
39 #include <sys/audioio.h>
40 #include <sys/bus.h>
41
42 #include <dev/audio/audio_if.h>
43 #include <dev/audio/audiovar.h> /* AUDIO_MIN_FREQUENCY */
44
45 #include <machine/sysasicvar.h>
46
47 #include <dreamcast/dev/g2/g2busvar.h>
48 #include <dreamcast/dev/g2/aicavar.h>
49 #include <dreamcast/dev/microcode/aica_armcode.h>
50
51 #define AICA_REG_ADDR 0x00700000
52 #define AICA_RAM_START 0x00800000
53 #define AICA_RAM_SIZE 0x00200000
54 #define AICA_NCHAN 64
55 #define AICA_TIMEOUT 0x1800
56
57 struct aica_softc {
58 device_t sc_dev; /* base device */
59 kmutex_t sc_lock;
60 kmutex_t sc_intr_lock;
61 bus_space_tag_t sc_memt;
62 bus_space_handle_t sc_aica_regh;
63 bus_space_handle_t sc_aica_memh;
64
65 /* audio property */
66 int sc_open;
67 int sc_precision;
68 int sc_channels;
69 int sc_rate;
70 void (*sc_intr)(void *);
71 void *sc_intr_arg;
72
73 int sc_output_master;
74 int sc_output_gain[2];
75 #define AICA_VOLUME_LEFT 0
76 #define AICA_VOLUME_RIGHT 1
77
78 /* work for output */
79 void *sc_buffer;
80 void *sc_buffer_start;
81 void *sc_buffer_end;
82 int sc_blksize;
83 int sc_nextfill;
84 };
85
86 static const struct audio_format aica_formats[] = {
87 {
88 .mode = AUMODE_PLAY,
89 .encoding = AUDIO_ENCODING_SLINEAR_LE,
90 .validbits = 16,
91 .precision = 16,
92 .channels = 2,
93 .channel_mask = AUFMT_STEREO,
94 .frequency_type = 0,
95 .frequency = { AUDIO_MIN_FREQUENCY, 65536 },
96 },
97 };
98 #define AICA_NFORMATS __arraycount(aica_formats)
99
100 int aica_match(device_t, cfdata_t, void *);
101 void aica_attach(device_t, device_t, void *);
102 int aica_print(void *, const char *);
103
104 CFATTACH_DECL_NEW(aica, sizeof(struct aica_softc), aica_match, aica_attach,
105 NULL, NULL);
106
107 const struct audio_device aica_device = {
108 "Dreamcast Sound",
109 "",
110 "aica"
111 };
112
113 inline static void aica_g2fifo_wait(void);
114 void aica_enable(struct aica_softc *);
115 void aica_disable(struct aica_softc *);
116 void aica_memwrite(struct aica_softc *, bus_size_t, uint32_t *, int);
117 void aica_ch2p16write(struct aica_softc *, bus_size_t, uint16_t *, int);
118 void aica_ch2p8write(struct aica_softc *, bus_size_t, uint8_t *, int);
119 void aica_command(struct aica_softc *, uint32_t);
120 void aica_sendparam(struct aica_softc *, uint32_t, int, int);
121 void aica_play(struct aica_softc *, int, int, int, int);
122 void aica_fillbuffer(struct aica_softc *);
123
124 /* intr */
125 int aica_intr(void *);
126
127 /* for audio */
128 int aica_open(void *, int);
129 void aica_close(void *);
130 int aica_query_format(void *, audio_format_query_t *);
131 int aica_set_format(void *, int,
132 const audio_params_t *, const audio_params_t *,
133 audio_filter_reg_t *, audio_filter_reg_t *);
134 int aica_round_blocksize(void *, int, int, const audio_params_t *);
135 size_t aica_round_buffersize(void *, int, size_t);
136 int aica_trigger_output(void *, void *, void *, int, void (*)(void *), void *,
137 const audio_params_t *);
138 int aica_trigger_input(void *, void *, void *, int, void (*)(void *), void *,
139 const audio_params_t *);
140 int aica_halt_output(void *);
141 int aica_halt_input(void *);
142 int aica_getdev(void *, struct audio_device *);
143 int aica_set_port(void *, mixer_ctrl_t *);
144 int aica_get_port(void *, mixer_ctrl_t *);
145 int aica_query_devinfo(void *, mixer_devinfo_t *);
146 void aica_encode(int, int, int, int, u_char *, u_short **);
147 int aica_get_props(void *);
148 void aica_get_locks(void *, kmutex_t **, kmutex_t **);
149
150 const struct audio_hw_if aica_hw_if = {
151 .open = aica_open,
152 .close = aica_close,
153 .query_format = aica_query_format,
154 .set_format = aica_set_format,
155 .round_blocksize = aica_round_blocksize,
156 .halt_output = aica_halt_output,
157 .halt_input = aica_halt_input,
158 .getdev = aica_getdev,
159 .set_port = aica_set_port,
160 .get_port = aica_get_port,
161 .query_devinfo = aica_query_devinfo,
162 .round_buffersize = aica_round_buffersize,
163 .get_props = aica_get_props,
164 .trigger_output = aica_trigger_output,
165 .trigger_input = aica_trigger_input,
166 .get_locks = aica_get_locks,
167 };
168
169 int
170 aica_match(device_t parent, cfdata_t cf, void *aux)
171 {
172 static int aica_matched = 0;
173
174 if (aica_matched)
175 return 0;
176
177 aica_matched = 1;
178 return 1;
179 }
180
181 void
182 aica_attach(device_t parent, device_t self, void *aux)
183 {
184 struct aica_softc *sc;
185 struct g2bus_attach_args *ga;
186 int i;
187
188 sc = device_private(self);
189 ga = aux;
190 sc->sc_dev = self;
191 sc->sc_memt = ga->ga_memt;
192
193 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
194 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
195
196 if (bus_space_map(sc->sc_memt, AICA_REG_ADDR, 0x3000, 0,
197 &sc->sc_aica_regh) != 0) {
198 aprint_error(": can't map AICA register space\n");
199 return;
200 }
201
202 if (bus_space_map(sc->sc_memt, AICA_RAM_START, AICA_RAM_SIZE, 0,
203 &sc->sc_aica_memh) != 0) {
204 aprint_error(": can't map AICA memory space\n");
205 return;
206 }
207
208 aprint_normal(": ARM7 Sound Processing Unit\n");
209
210 aica_disable(sc);
211
212 for (i = 0; i < AICA_NCHAN; i++)
213 bus_space_write_4(sc->sc_memt,sc->sc_aica_regh, i << 7,
214 ((bus_space_read_4(sc->sc_memt, sc->sc_aica_regh, i << 7)
215 & ~0x4000) | 0x8000));
216
217 /* load microcode, and clear memory */
218 bus_space_set_region_4(sc->sc_memt, sc->sc_aica_memh,
219 0, 0, AICA_RAM_SIZE / 4);
220
221 aica_memwrite(sc, 0, aica_armcode, sizeof(aica_armcode));
222
223 aica_enable(sc);
224
225 aprint_normal_dev(self, "interrupting at %s\n",
226 sysasic_intr_string(SYSASIC_IRL9));
227 sysasic_intr_establish(SYSASIC_EVENT_AICA, IPL_BIO, SYSASIC_IRL9,
228 aica_intr, sc);
229
230 audio_attach_mi(&aica_hw_if, sc, self);
231
232 /* init parameters */
233 sc->sc_output_master = 255;
234 sc->sc_output_gain[AICA_VOLUME_LEFT] = 255;
235 sc->sc_output_gain[AICA_VOLUME_RIGHT] = 255;
236 }
237
238 void
239 aica_enable(struct aica_softc *sc)
240 {
241
242 bus_space_write_4(sc->sc_memt, sc->sc_aica_regh, 0x28a8, 24);
243 bus_space_write_4(sc->sc_memt, sc->sc_aica_regh, 0x2c00,
244 bus_space_read_4(sc->sc_memt, sc->sc_aica_regh, 0x2c00) & ~1);
245 }
246
247 void
248 aica_disable(struct aica_softc *sc)
249 {
250
251 bus_space_write_4(sc->sc_memt, sc->sc_aica_regh, 0x2c00,
252 bus_space_read_4(sc->sc_memt, sc->sc_aica_regh, 0x2c00) | 1);
253 }
254
255 inline static void
256 aica_g2fifo_wait(void)
257 {
258 int i;
259
260 i = AICA_TIMEOUT;
261 while (--i > 0)
262 if ((*(volatile uint32_t *)0xa05f688c) & 0x11)
263 break;
264 }
265
266 void
267 aica_memwrite(struct aica_softc *sc, bus_size_t offset, uint32_t *src, int len)
268 {
269 int n;
270
271 KASSERT((offset & 3) == 0);
272 n = (len + 3) / 4; /* uint32_t * n (aligned) */
273
274 aica_g2fifo_wait();
275 bus_space_write_region_4(sc->sc_memt, sc->sc_aica_memh,
276 offset, src, n);
277 }
278
279 void
280 aica_ch2p16write(struct aica_softc *sc, bus_size_t offset, uint16_t *src,
281 int len)
282 {
283 union {
284 uint32_t w[8];
285 uint16_t s[16];
286 } buf;
287 uint16_t *p;
288 int i;
289
290 KASSERT((offset & 3) == 0);
291
292 while (len >= 32) {
293 p = buf.s;
294 *p++ = *src++; src++;
295 *p++ = *src++; src++;
296 *p++ = *src++; src++;
297 *p++ = *src++; src++;
298 *p++ = *src++; src++;
299 *p++ = *src++; src++;
300 *p++ = *src++; src++;
301 *p++ = *src++; src++;
302 *p++ = *src++; src++;
303 *p++ = *src++; src++;
304 *p++ = *src++; src++;
305 *p++ = *src++; src++;
306 *p++ = *src++; src++;
307 *p++ = *src++; src++;
308 *p++ = *src++; src++;
309 *p++ = *src++; src++;
310
311 aica_g2fifo_wait();
312 bus_space_write_region_4(sc->sc_memt, sc->sc_aica_memh,
313 offset, buf.w , 32 / 4);
314
315 offset += sizeof(uint16_t) * 16;
316 len -= 32;
317 }
318
319 if (len / 2 > 0) {
320 p = buf.s;
321 for (i = 0; i < len / 2; i++) {
322 *p++ = *src++; src++;
323 }
324
325 aica_g2fifo_wait();
326 bus_space_write_region_4(sc->sc_memt, sc->sc_aica_memh,
327 offset, buf.w, len / 4);
328 }
329 }
330
331 void
332 aica_ch2p8write(struct aica_softc *sc, bus_size_t offset, uint8_t *src,
333 int len)
334 {
335 uint32_t buf[8];
336 uint8_t *p;
337 int i;
338
339 KASSERT((offset & 3) == 0);
340 while (len >= 32) {
341 p = (uint8_t *)buf;
342
343 *p++ = *src++; src++;
344 *p++ = *src++; src++;
345 *p++ = *src++; src++;
346 *p++ = *src++; src++;
347 *p++ = *src++; src++;
348 *p++ = *src++; src++;
349 *p++ = *src++; src++;
350 *p++ = *src++; src++;
351 *p++ = *src++; src++;
352 *p++ = *src++; src++;
353 *p++ = *src++; src++;
354 *p++ = *src++; src++;
355 *p++ = *src++; src++;
356 *p++ = *src++; src++;
357 *p++ = *src++; src++;
358 *p++ = *src++; src++;
359 *p++ = *src++; src++;
360 *p++ = *src++; src++;
361 *p++ = *src++; src++;
362 *p++ = *src++; src++;
363 *p++ = *src++; src++;
364 *p++ = *src++; src++;
365 *p++ = *src++; src++;
366 *p++ = *src++; src++;
367 *p++ = *src++; src++;
368 *p++ = *src++; src++;
369 *p++ = *src++; src++;
370 *p++ = *src++; src++;
371 *p++ = *src++; src++;
372 *p++ = *src++; src++;
373 *p++ = *src++; src++;
374 *p++ = *src++; src++;
375
376 aica_g2fifo_wait();
377 bus_space_write_region_4(sc->sc_memt, sc->sc_aica_memh,
378 offset, buf, 32 / 4);
379
380 offset += 32;
381 len -= 32;
382 }
383
384 if (len) {
385 p = (uint8_t *)buf;
386 for (i = 0; i < len; i++) {
387 *p++ = *src++; src++;
388 }
389
390 aica_g2fifo_wait();
391 bus_space_write_region_4(sc->sc_memt, sc->sc_aica_memh,
392 offset, buf, len / 4);
393 }
394 }
395
396 int
397 aica_open(void *addr, int flags)
398 {
399 struct aica_softc *sc;
400
401 sc = addr;
402 if (sc->sc_open)
403 return EBUSY;
404
405 sc->sc_intr = NULL;
406 sc->sc_open = 1;
407
408 return 0;
409 }
410
411 void
412 aica_close(void *addr)
413 {
414 struct aica_softc *sc;
415
416 sc = addr;
417 sc->sc_open = 0;
418 sc->sc_intr = NULL;
419 }
420
421 int
422 aica_query_format(void *addr, audio_format_query_t *afp)
423 {
424
425 return audio_query_format(aica_formats, AICA_NFORMATS, afp);
426 }
427
428 int
429 aica_set_format(void *addr, int setmode,
430 const audio_params_t *play, const audio_params_t *rec,
431 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
432 {
433 struct aica_softc *sc;
434
435 sc = addr;
436 sc->sc_precision = play->precision;
437 sc->sc_channels = play->channels;
438 sc->sc_rate = play->sample_rate;
439 return 0;
440 }
441
442 int
443 aica_round_blocksize(void *addr, int blk, int mode, const audio_params_t *param)
444 {
445 #if 0 /* XXX this has not worked since kent-audio1 merge? */
446 struct aica_softc *sc;
447
448 sc = addr;
449 switch (sc->sc_precision) {
450 case 4:
451 if (sc->sc_channels == 1)
452 return AICA_DMABUF_SIZE / 4;
453 else
454 return AICA_DMABUF_SIZE / 2;
455 break;
456 case 8:
457 if (sc->sc_channels == 1)
458 return AICA_DMABUF_SIZE / 2;
459 else
460 return AICA_DMABUF_SIZE;
461 break;
462 case 16:
463 if (sc->sc_channels == 1)
464 return AICA_DMABUF_SIZE;
465 else
466 return AICA_DMABUF_SIZE * 2;
467 break;
468 default:
469 break;
470 }
471
472 #endif
473 return AICA_DMABUF_SIZE / 4;
474 }
475
476 size_t
477 aica_round_buffersize(void *addr, int dir, size_t bufsize)
478 {
479 struct aica_softc *sc;
480
481 sc = addr;
482 if (bufsize > 65536 * sc->sc_channels)
483 return 65536 * sc->sc_channels;
484 return bufsize;
485 }
486
487 void
488 aica_command(struct aica_softc *sc, uint32_t command)
489 {
490
491 bus_space_write_4(sc->sc_memt, sc->sc_aica_memh,
492 AICA_ARM_CMD_COMMAND, command);
493 bus_space_write_4(sc->sc_memt,sc->sc_aica_memh, AICA_ARM_CMD_SERIAL,
494 bus_space_read_4(sc->sc_memt, sc->sc_aica_memh,
495 AICA_ARM_CMD_SERIAL) + 1);
496 }
497
498 void
499 aica_sendparam(struct aica_softc *sc, uint32_t command,
500 int32_t lparam, int32_t rparam)
501 {
502
503 bus_space_write_4(sc->sc_memt,sc->sc_aica_memh,
504 AICA_ARM_CMD_LPARAM, lparam);
505 bus_space_write_4(sc->sc_memt,sc->sc_aica_memh,
506 AICA_ARM_CMD_RPARAM, rparam);
507
508 aica_command(sc, command);
509 }
510
511 void
512 aica_play(struct aica_softc *sc, int blksize, int channel, int rate, int prec)
513 {
514
515 bus_space_write_4(sc->sc_memt,sc->sc_aica_memh,
516 AICA_ARM_CMD_BLOCKSIZE, blksize);
517 bus_space_write_4(sc->sc_memt,sc->sc_aica_memh,
518 AICA_ARM_CMD_CHANNEL, channel);
519 bus_space_write_4(sc->sc_memt,sc->sc_aica_memh,
520 AICA_ARM_CMD_RATE, rate);
521 bus_space_write_4(sc->sc_memt,sc->sc_aica_memh,
522 AICA_ARM_CMD_PRECISION, prec);
523
524 aica_command(sc, AICA_COMMAND_PLAY);
525 }
526
527 void
528 aica_fillbuffer(struct aica_softc *sc)
529 {
530
531 if (sc->sc_channels == 2) {
532 if (sc->sc_precision == 16) {
533 aica_ch2p16write(sc,
534 AICA_DMABUF_LEFT + sc->sc_nextfill,
535 (uint16_t *)sc->sc_buffer + 0, sc->sc_blksize / 2);
536 aica_ch2p16write(sc,
537 AICA_DMABUF_RIGHT + sc->sc_nextfill,
538 (uint16_t *)sc->sc_buffer + 1, sc->sc_blksize / 2);
539 } else if (sc->sc_precision == 8) {
540 aica_ch2p8write(sc, AICA_DMABUF_LEFT + sc->sc_nextfill,
541 (uint8_t *)sc->sc_buffer + 0, sc->sc_blksize / 2);
542 aica_ch2p8write(sc, AICA_DMABUF_RIGHT + sc->sc_nextfill,
543 (uint8_t *)sc->sc_buffer + 1, sc->sc_blksize / 2);
544 }
545 } else {
546 aica_memwrite(sc, AICA_DMABUF_MONO + sc->sc_nextfill,
547 sc->sc_buffer, sc->sc_blksize);
548 }
549
550 sc->sc_buffer = (int8_t *)sc->sc_buffer + sc->sc_blksize;
551 if (sc->sc_buffer >= sc->sc_buffer_end)
552 sc->sc_buffer = sc->sc_buffer_start;
553
554 sc->sc_nextfill ^= sc->sc_blksize / sc->sc_channels;
555 }
556
557 int
558 aica_intr(void *arg)
559 {
560 struct aica_softc *sc;
561
562 sc = arg;
563
564 mutex_spin_enter(&sc->sc_intr_lock);
565
566 aica_fillbuffer(sc);
567
568 /* call audio interrupt handler (audio_pint()) */
569 if (sc->sc_open && sc->sc_intr != NULL) {
570 (*(sc->sc_intr))(sc->sc_intr_arg);
571 }
572
573 /* clear SPU interrupt */
574 bus_space_write_4(sc->sc_memt, sc->sc_aica_regh, 0x28bc, 0x20);
575
576 mutex_spin_exit(&sc->sc_intr_lock);
577
578 return 1;
579 }
580
581 int
582 aica_trigger_output(void *addr, void *start, void *end, int blksize,
583 void (*intr)(void *), void *arg, const audio_params_t *param)
584 {
585 struct aica_softc *sc;
586
587 sc = addr;
588
589 sc->sc_buffer_start = sc->sc_buffer = start;
590 sc->sc_buffer_end = end;
591 sc->sc_blksize = blksize;
592 sc->sc_nextfill = 0;
593
594 sc->sc_intr = intr;
595 sc->sc_intr_arg = arg;
596
597 /*
598 * The aica arm side driver uses a double buffer to play sounds.
599 * we need to fill two buffers before playing.
600 */
601 aica_fillbuffer(sc);
602 aica_fillbuffer(sc);
603
604 /* ...and start playing */
605 aica_play(sc, blksize / sc->sc_channels, sc->sc_channels, sc->sc_rate,
606 sc->sc_precision);
607
608 return 0;
609 }
610
611 int
612 aica_trigger_input(void *addr, void *start, void *end, int blksize,
613 void (*intr)(void *), void *arg, const audio_params_t *param)
614 {
615
616 return ENODEV;
617 }
618
619 int
620 aica_halt_output(void *addr)
621 {
622 struct aica_softc *sc;
623
624 sc = addr;
625 aica_command(sc, AICA_COMMAND_STOP);
626 return 0;
627 }
628
629 int
630 aica_halt_input(void *addr)
631 {
632
633 return ENODEV;
634 }
635
636 int
637 aica_getdev(void *addr, struct audio_device *ret)
638 {
639
640 *ret = aica_device;
641 return 0;
642 }
643
644 int
645 aica_set_port(void *addr, mixer_ctrl_t *mc)
646 {
647 struct aica_softc *sc;
648
649 sc = addr;
650 switch (mc->dev) {
651 case AICA_MASTER_VOL:
652 sc->sc_output_master =
653 mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] & 0xff;
654 aica_sendparam(sc, AICA_COMMAND_MVOL,
655 sc->sc_output_master, sc->sc_output_master);
656 break;
657 case AICA_OUTPUT_GAIN:
658 sc->sc_output_gain[AICA_VOLUME_LEFT] =
659 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] & 0xff;
660 sc->sc_output_gain[AICA_VOLUME_RIGHT] =
661 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] & 0xff;
662 aica_sendparam(sc, AICA_COMMAND_VOL,
663 sc->sc_output_gain[AICA_VOLUME_LEFT],
664 sc->sc_output_gain[AICA_VOLUME_RIGHT]);
665 break;
666 default:
667 return EINVAL;
668 }
669
670 return 0;
671 }
672
673 int
674 aica_get_port(void *addr, mixer_ctrl_t *mc)
675 {
676 struct aica_softc *sc;
677
678 sc = addr;
679 switch (mc->dev) {
680 case AICA_MASTER_VOL:
681 if (mc->un.value.num_channels != 1)
682 return EINVAL;
683 mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
684 L16TO256(L256TO16(sc->sc_output_master));
685 break;
686 case AICA_OUTPUT_GAIN:
687 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
688 sc->sc_output_gain[AICA_VOLUME_LEFT];
689 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
690 sc->sc_output_gain[AICA_VOLUME_RIGHT];
691 break;
692 default:
693 return EINVAL;
694 }
695 return 0;
696 }
697
698 int
699 aica_query_devinfo(void *addr, mixer_devinfo_t *md)
700 {
701
702 switch (md->index) {
703 case AICA_MASTER_VOL:
704 md->type = AUDIO_MIXER_VALUE;
705 md->mixer_class = AICA_OUTPUT_CLASS;
706 md->prev = md->next = AUDIO_MIXER_LAST;
707 strcpy(md->label.name, AudioNmaster);
708 md->un.v.num_channels = 1;
709 strcpy(md->un.v.units.name, AudioNvolume);
710 return 0;
711 case AICA_OUTPUT_GAIN:
712 md->type = AUDIO_MIXER_VALUE;
713 md->mixer_class = AICA_OUTPUT_CLASS;
714 md->prev = md->next = AUDIO_MIXER_LAST;
715 strcpy(md->label.name, AudioNoutput);
716 md->un.v.num_channels = 2;
717 strcpy(md->label.name, AudioNvolume);
718 return 0;
719 case AICA_OUTPUT_CLASS:
720 md->type = AUDIO_MIXER_CLASS;
721 md->mixer_class = AICA_OUTPUT_CLASS;
722 md->next = md->prev = AUDIO_MIXER_LAST;
723 strcpy(md->label.name, AudioCoutputs);
724 return 0;
725 }
726
727 return ENXIO;
728 }
729
730 int
731 aica_get_props(void *addr)
732 {
733
734 return AUDIO_PROP_PLAYBACK;
735 }
736
737 void
738 aica_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
739 {
740 struct aica_softc *sc;
741
742 sc = addr;
743 *intr = &sc->sc_intr_lock;
744 *thread = &sc->sc_lock;
745 }
746