aica.c revision 1.1 1 /* $NetBSD: aica.c,v 1.1 2003/08/24 17:33:29 marcus 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.1 2003/08/24 17:33:29 marcus Exp $");
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/proc.h>
38 #include <sys/audioio.h>
39
40 #include <dev/audio_if.h>
41 #include <dev/mulaw.h>
42 #include <dev/auconv.h>
43
44 #include <machine/bus.h>
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 struct device sc_dev; /* base device */
59 bus_space_tag_t sc_memt;
60 bus_space_handle_t sc_aica_regh;
61 bus_space_handle_t sc_aica_memh;
62
63 /* audio property */
64 int sc_open;
65 int sc_encodings;
66 int sc_precision;
67 int sc_channels;
68 int sc_rate;
69 void (*sc_intr)(void *);
70 void *sc_intr_arg;
71
72 int sc_output_master;
73 int sc_output_gain[2];
74 #define AICA_VOLUME_LEFT 0
75 #define AICA_VOLUME_RIGHT 1
76
77 /* work for output */
78 void *sc_buffer;
79 void *sc_buffer_start;
80 void *sc_buffer_end;
81 int sc_blksize;
82 int sc_nextfill;
83 };
84
85 struct {
86 char *name;
87 int encoding;
88 int precision;
89 } aica_encodings[] = {
90 {AudioEadpcm, AUDIO_ENCODING_ADPCM, 4},
91 {AudioEslinear, AUDIO_ENCODING_SLINEAR, 8},
92 {AudioEulinear, AUDIO_ENCODING_ULINEAR, 8},
93 {AudioEmulaw, AUDIO_ENCODING_ULAW, 8},
94 {AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16},
95 {AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 16},
96 };
97
98 int aica_match(struct device *, struct cfdata *, void *);
99 void aica_attach(struct device *, struct device *, void *);
100 int aica_print(void *, const char *);
101
102 CFATTACH_DECL(aica, sizeof(struct aica_softc), aica_match, aica_attach,
103 NULL, NULL);
104
105 struct audio_device aica_device = {
106 "Dreamcast Sound",
107 "",
108 "aica"
109 };
110
111 __inline static void aica_g2fifo_wait(void);
112 void aica_enable(struct aica_softc *);
113 void aica_disable(struct aica_softc *);
114 void aica_memwrite(struct aica_softc *, bus_size_t, u_int32_t *, int);
115 void aica_ch2p16write(struct aica_softc *, bus_size_t, u_int16_t *, int);
116 void aica_ch2p8write(struct aica_softc *, bus_size_t, u_int8_t *, int);
117 void aica_command(struct aica_softc *, u_int32_t);
118 void aica_sendparam(struct aica_softc *, u_int32_t, int, int);
119 void aica_play(struct aica_softc *, int, int, int, int);
120 void aica_fillbuffer(struct aica_softc *);
121
122 /* intr */
123 int aica_intr(void *);
124
125 /* for audio */
126 int aica_open(void *, int);
127 void aica_close(void *);
128 int aica_query_encoding(void *, struct audio_encoding *);
129 int aica_set_params(void *, int, int, struct audio_params *,
130 struct audio_params *);
131 int aica_round_blocksize(void *, int);
132 size_t aica_round_buffersize(void *, int, size_t);
133 int aica_trigger_output(void *, void *, void *, int, void (*)(void *), void *,
134 struct audio_params *);
135 int aica_trigger_input(void *, void *, void *, int, void (*)(void *), void *,
136 struct audio_params *);
137 int aica_halt_output(void *);
138 int aica_halt_input(void *);
139 int aica_getdev(void *, struct audio_device *);
140 int aica_set_port(void *, mixer_ctrl_t *);
141 int aica_get_port(void *, mixer_ctrl_t *);
142 int aica_query_devinfo(void *, mixer_devinfo_t *);
143 void aica_encode(int, int, int, int, u_char *, u_short **);
144 int aica_get_props(void *);
145
146 struct audio_hw_if aica_hw_if = {
147 aica_open,
148 aica_close,
149 NULL, /* aica_drain */
150 aica_query_encoding,
151 aica_set_params,
152 aica_round_blocksize,
153 NULL, /* aica_commit_setting */
154 NULL, /* aica_init_output */
155 NULL, /* aica_init_input */
156 NULL, /* aica_start_output */
157 NULL, /* aica_start_input */
158 aica_halt_output,
159 aica_halt_input,
160 NULL, /* aica_speaker_ctl */
161 aica_getdev,
162 NULL, /* aica_setfd */
163 aica_set_port,
164 aica_get_port,
165 aica_query_devinfo,
166 NULL, /* aica_allocm */
167 NULL, /* aica_freem */
168
169 aica_round_buffersize, /* aica_round_buffersize */
170
171 NULL, /* aica_mappage */
172 aica_get_props,
173 aica_trigger_output,
174 aica_trigger_input,
175 NULL, /* aica_dev_ioctl */
176 };
177
178 int
179 aica_match(struct device *parent, struct cfdata *cf, void *aux)
180 {
181 static int aica_matched = 0;
182
183 if (aica_matched)
184 return 0;
185
186 aica_matched = 1;
187 return 1;
188 }
189
190 void
191 aica_attach(struct device *parent, struct device *self, void *aux)
192 {
193 struct aica_softc *sc = (struct aica_softc *)self;
194 struct g2bus_attach_args *ga = aux;
195 int i;
196
197 sc->sc_memt = ga->ga_memt;
198
199 if (bus_space_map(sc->sc_memt, AICA_REG_ADDR, 0x3000, 0,
200 &sc->sc_aica_regh) != 0) {
201 printf(": can't map AICA register space\n");
202 return;
203 }
204
205 if (bus_space_map(sc->sc_memt, AICA_RAM_START, AICA_RAM_SIZE, 0,
206 &sc->sc_aica_memh) != 0) {
207 printf(": can't map AICA memory space\n");
208 return;
209 }
210
211 printf(": ARM7 Sound Processing Unit\n");
212
213 aica_disable(sc);
214
215 for (i = 0; i < AICA_NCHAN; i++)
216 bus_space_write_4(sc->sc_memt,sc->sc_aica_regh, i << 7,
217 ((bus_space_read_4(sc->sc_memt, sc->sc_aica_regh, i << 7)
218 & ~0x4000) | 0x8000));
219
220 /* load microcode, and clear memory */
221 bus_space_set_region_4(sc->sc_memt, sc->sc_aica_memh,
222 0, 0, AICA_RAM_SIZE);
223
224 aica_memwrite(sc, 0, aica_armcode, sizeof(aica_armcode));
225
226 aica_enable(sc);
227
228 printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname,
229 sysasic_intr_string(IPL_BIO));
230 sysasic_intr_establish(SYSASIC_EVENT_AICA, IPL_BIO, aica_intr, sc);
231
232 audio_attach_mi(&aica_hw_if, sc, &sc->sc_dev);
233
234 /* init parameters */
235 sc->sc_output_master = 255;
236 sc->sc_output_gain[AICA_VOLUME_LEFT] = 255;
237 sc->sc_output_gain[AICA_VOLUME_RIGHT] = 255;
238 }
239
240 void
241 aica_enable(struct aica_softc *sc)
242 {
243
244 bus_space_write_4(sc->sc_memt, sc->sc_aica_regh, 0x28a8, 24);
245 bus_space_write_4(sc->sc_memt, sc->sc_aica_regh, 0x2c00,
246 bus_space_read_4(sc->sc_memt, sc->sc_aica_regh, 0x2c00) & ~1);
247 }
248
249 void
250 aica_disable(struct aica_softc *sc)
251 {
252
253 bus_space_write_4(sc->sc_memt, sc->sc_aica_regh, 0x2c00,
254 bus_space_read_4(sc->sc_memt, sc->sc_aica_regh, 0x2c00) | 1);
255 }
256
257 inline static void
258 aica_g2fifo_wait()
259 {
260 int i;
261
262 i = AICA_TIMEOUT;
263 while (--i > 0)
264 if ((*(volatile u_int32_t *)0xa05f688c) & 0x11)
265 break;
266 }
267
268 void
269 aica_memwrite(struct aica_softc *sc, bus_size_t offset, u_int32_t *src, int len)
270 {
271 int n;
272
273 KASSERT((offset & 3) == 0);
274 n = (len + 3) / 4; /* u_int32_t * n (aligned) */
275
276 aica_g2fifo_wait();
277 bus_space_write_region_4(sc->sc_memt, sc->sc_aica_memh,
278 offset, src, n);
279 }
280
281 void
282 aica_ch2p16write(struct aica_softc *sc, bus_size_t offset, u_int16_t *src,
283 int len)
284 {
285 union {
286 u_int32_t w[8];
287 u_int16_t s[16];
288 } buf;
289 u_int16_t *p;
290 int i;
291
292 KASSERT((offset & 3) == 0);
293
294 while (len >= 32) {
295 p = buf.s;
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 *p++ = *src++; src++;
311 *p++ = *src++; src++;
312
313 aica_g2fifo_wait();
314 bus_space_write_region_4(sc->sc_memt, sc->sc_aica_memh,
315 offset, buf.w , 32 / 4);
316
317 offset += sizeof(u_int16_t) * 16;
318 len -= 32;
319 }
320
321 if (len / 2 > 0) {
322 p = buf.s;
323 for (i = 0; i < len / 2; i++) {
324 *p++ = *src++; src++;
325 }
326
327 aica_g2fifo_wait();
328 bus_space_write_region_4(sc->sc_memt, sc->sc_aica_memh,
329 offset, buf.w, len / 4);
330 }
331 }
332
333 void
334 aica_ch2p8write(struct aica_softc *sc, bus_size_t offset, u_int8_t *src,
335 int len)
336 {
337 u_int32_t buf[8];
338 u_int8_t *p;
339 int i;
340
341 KASSERT((offset & 3) == 0);
342 while (len >= 32) {
343 p = (u_int8_t *)buf;
344
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 *p++ = *src++; src++;
376 *p++ = *src++; src++;
377
378 aica_g2fifo_wait();
379 bus_space_write_region_4(sc->sc_memt, sc->sc_aica_memh,
380 offset, buf, 32 / 4);
381
382 offset += 32;
383 len -= 32;
384 }
385
386 if (len) {
387 p = (u_int8_t *)buf;
388 for (i = 0; i < len; i++)
389 *p++ = *src++; src++;
390
391 aica_g2fifo_wait();
392 bus_space_write_region_4(sc->sc_memt, sc->sc_aica_memh,
393 offset, buf, len / 4);
394 }
395 }
396
397 int
398 aica_open(void *addr, int flags)
399 {
400 struct aica_softc *sc = addr;
401
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 = addr;
415
416 sc->sc_open = 0;
417 sc->sc_intr = NULL;
418 }
419
420 int
421 aica_query_encoding(void *addr, struct audio_encoding *fp)
422 {
423 if (fp->index >= sizeof(aica_encodings) / sizeof(aica_encodings[0]))
424 return EINVAL;
425
426 strcpy(fp->name, aica_encodings[fp->index].name);
427 fp->encoding = aica_encodings[fp->index].encoding;
428 fp->precision = aica_encodings[fp->index].precision;
429 fp->flags = 0;
430
431 return 0;
432 }
433
434 int
435 aica_set_params(void *addr, int setmode, int usemode,
436 struct audio_params *play, struct audio_params *rec)
437 {
438 struct aica_softc *sc = addr;
439
440 if ((play->channels != 1) &&
441 (play->channels != 2))
442 return EINVAL;
443
444 if ((play->precision != 4) &&
445 (play->precision != 8) &&
446 (play->precision != 16))
447 return EINVAL;
448
449 play->factor = 1;
450 play->factor_denom = 1;
451
452 play->hw_precision = play->precision;
453 play->hw_channels = play->channels;
454 play->hw_sample_rate = play->sample_rate;
455 play->hw_encoding = AUDIO_ENCODING_SLINEAR_LE;
456
457 play->sw_code = NULL;
458
459 sc->sc_precision = play->hw_precision;
460 sc->sc_channels = play->hw_channels;
461 sc->sc_rate = play->hw_sample_rate;
462 sc->sc_encodings = play->hw_encoding;
463
464 #if 1
465 /* XXX: limit check */
466 if ((play->precision == 4) &&
467 (play->channels == 1) &&
468 (play->sample_rate >= 65536))
469 return EINVAL;
470
471 if ((play->precision == 8) &&
472 (play->channels == 1) &&
473 (play->sample_rate >= 65536))
474 return EINVAL;
475 #endif
476
477 switch (play->encoding) {
478 case AUDIO_ENCODING_ADPCM:
479 if (play->precision != 4)
480 return EINVAL;
481 if (play->channels != 1)
482 return EINVAL;
483
484 play->hw_encoding = AUDIO_ENCODING_ADPCM;
485 play->hw_precision = 8; /* 4? XXX */
486 sc->sc_precision = 4;
487 break;
488
489 case AUDIO_ENCODING_SLINEAR:
490 break;
491 case AUDIO_ENCODING_ULINEAR:
492 play->sw_code = change_sign8;
493 break;
494
495 case AUDIO_ENCODING_SLINEAR_BE:
496 if (play->precision == 16)
497 play->sw_code = swap_bytes;
498 break;
499 case AUDIO_ENCODING_SLINEAR_LE:
500 break;
501 case AUDIO_ENCODING_ULINEAR_BE:
502 if (play->precision == 16)
503 play->sw_code = swap_bytes_change_sign16_le;
504 break;
505 case AUDIO_ENCODING_ULINEAR_LE:
506 if (play->precision == 16)
507 play->sw_code = change_sign16_le;
508 break;
509
510 case AUDIO_ENCODING_ULAW:
511 play->sw_code = mulaw_to_slinear16_le;
512 play->hw_precision = 16;
513 sc->sc_precision = play->hw_precision;
514 break;
515 case AUDIO_ENCODING_ALAW:
516 play->sw_code = alaw_to_slinear16_le;
517 play->hw_precision = 16;
518 sc->sc_precision = play->hw_precision;
519 break;
520
521 default:
522 return EINVAL;
523 }
524
525 return 0;
526 }
527
528 int
529 aica_round_blocksize(void *addr, int blk)
530 {
531 struct aica_softc *sc = addr;
532
533 switch (sc->sc_precision) {
534 case 4:
535 if (sc->sc_channels == 1)
536 return AICA_DMABUF_SIZE / 4;
537 else
538 return AICA_DMABUF_SIZE / 2;
539 break;
540 case 8:
541 if (sc->sc_channels == 1)
542 return AICA_DMABUF_SIZE / 2;
543 else
544 return AICA_DMABUF_SIZE;
545 break;
546 case 16:
547 if (sc->sc_channels == 1)
548 return AICA_DMABUF_SIZE;
549 else
550 return AICA_DMABUF_SIZE * 2;
551 break;
552 default:
553 break;
554 }
555
556 return AICA_DMABUF_SIZE / 4;
557 }
558
559 size_t
560 aica_round_buffersize(void *addr, int dir, size_t bufsize)
561 {
562
563 if (dir == AUMODE_PLAY)
564 return 65536;
565
566 return 512; /* XXX: AUMINBUF */
567 }
568
569 void
570 aica_command(struct aica_softc *sc, u_int32_t command)
571 {
572
573 bus_space_write_4(sc->sc_memt, sc->sc_aica_memh,
574 AICA_ARM_CMD_COMMAND, command);
575 bus_space_write_4(sc->sc_memt,sc->sc_aica_memh, AICA_ARM_CMD_SERIAL,
576 bus_space_read_4(sc->sc_memt, sc->sc_aica_memh,
577 AICA_ARM_CMD_SERIAL) + 1);
578 }
579
580 void
581 aica_sendparam(struct aica_softc *sc, u_int32_t command,
582 int32_t lparam, int32_t rparam)
583 {
584
585 bus_space_write_4(sc->sc_memt,sc->sc_aica_memh,
586 AICA_ARM_CMD_LPARAM, lparam);
587 bus_space_write_4(sc->sc_memt,sc->sc_aica_memh,
588 AICA_ARM_CMD_RPARAM, rparam);
589
590 aica_command(sc, command);
591 }
592
593 void
594 aica_play(struct aica_softc *sc, int blksize, int channel, int rate, int prec)
595 {
596
597 bus_space_write_4(sc->sc_memt,sc->sc_aica_memh,
598 AICA_ARM_CMD_BLOCKSIZE, blksize);
599 bus_space_write_4(sc->sc_memt,sc->sc_aica_memh,
600 AICA_ARM_CMD_CHANNEL, channel);
601 bus_space_write_4(sc->sc_memt,sc->sc_aica_memh,
602 AICA_ARM_CMD_RATE, rate);
603 bus_space_write_4(sc->sc_memt,sc->sc_aica_memh,
604 AICA_ARM_CMD_PRECISION, prec);
605
606 aica_command(sc, AICA_COMMAND_PLAY);
607 }
608
609 void
610 aica_fillbuffer(struct aica_softc *sc)
611 {
612
613 if (sc->sc_channels == 2) {
614 if (sc->sc_precision == 16) {
615 aica_ch2p16write(sc,
616 AICA_DMABUF_LEFT + sc->sc_nextfill,
617 (u_int16_t *)sc->sc_buffer + 0, sc->sc_blksize / 2);
618 aica_ch2p16write(sc,
619 AICA_DMABUF_RIGHT + sc->sc_nextfill,
620 (u_int16_t *)sc->sc_buffer + 1, sc->sc_blksize / 2);
621 } else if (sc->sc_precision == 8) {
622 aica_ch2p8write(sc, AICA_DMABUF_LEFT + sc->sc_nextfill,
623 (u_int8_t *)sc->sc_buffer + 0, sc->sc_blksize / 2);
624 aica_ch2p8write(sc, AICA_DMABUF_RIGHT + sc->sc_nextfill,
625 (u_int8_t *)sc->sc_buffer + 1, sc->sc_blksize / 2);
626 }
627 } else {
628 aica_memwrite(sc, AICA_DMABUF_MONO + sc->sc_nextfill,
629 sc->sc_buffer, sc->sc_blksize);
630 }
631
632 (int8_t *)sc->sc_buffer += sc->sc_blksize;
633 if (sc->sc_buffer >= sc->sc_buffer_end)
634 sc->sc_buffer = sc->sc_buffer_start;
635
636 sc->sc_nextfill ^= sc->sc_blksize / sc->sc_channels;
637 }
638
639 int
640 aica_intr(void *arg)
641 {
642 struct aica_softc *sc = arg;
643
644 aica_fillbuffer(sc);
645
646 /* call audio interrupt handler (audio_pint()) */
647 if (sc->sc_open && sc->sc_intr != NULL) {
648 (*(sc->sc_intr))(sc->sc_intr_arg);
649 }
650
651 /* clear SPU interrupt */
652 bus_space_write_4(sc->sc_memt, sc->sc_aica_regh, 0x28bc, 0x20);
653 return 1;
654 }
655
656 int
657 aica_trigger_output(void *addr, void *start, void *end, int blksize,
658 void (*intr)(void *), void *arg, struct audio_params *param)
659 {
660 struct aica_softc *sc = addr;
661
662 aica_command(sc, AICA_COMMAND_INIT);
663 tsleep(aica_trigger_output, PWAIT, "aicawait", hz / 20);
664
665 sc->sc_buffer_start = sc->sc_buffer = start;
666 sc->sc_buffer_end = end;
667 sc->sc_blksize = blksize;
668 sc->sc_nextfill = 0;
669
670 sc->sc_intr = intr;
671 sc->sc_intr_arg = arg;
672
673 /* fill buffers in advance */
674 aica_intr(sc);
675 aica_intr(sc);
676
677 /* ...and start playing */
678 aica_play(sc, blksize / sc->sc_channels, sc->sc_channels, sc->sc_rate,
679 sc->sc_precision);
680
681 return 0;
682 }
683
684 int
685 aica_trigger_input(void *addr, void *start, void *end, int blksize,
686 void (*intr)(void *), void *arg, struct audio_params *param)
687 {
688
689 return ENODEV;
690 }
691
692 int
693 aica_halt_output(void *addr)
694 {
695 struct aica_softc *sc = addr;
696
697 aica_command(sc, AICA_COMMAND_STOP);
698
699 return 0;
700 }
701
702 int
703 aica_halt_input(void *addr)
704 {
705
706 return ENODEV;
707 }
708
709 int
710 aica_getdev(void *addr, struct audio_device *ret)
711 {
712
713 *ret = aica_device;
714 return 0;
715 }
716
717 int
718 aica_set_port(void *addr, mixer_ctrl_t *mc)
719 {
720 struct aica_softc *sc = addr;
721
722 switch (mc->dev) {
723 case AICA_MASTER_VOL:
724 sc->sc_output_master =
725 mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] & 0xff;
726 aica_sendparam(sc, AICA_COMMAND_MVOL,
727 sc->sc_output_master, sc->sc_output_master);
728 break;
729 case AICA_OUTPUT_GAIN:
730 sc->sc_output_gain[AICA_VOLUME_LEFT] =
731 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] & 0xff;
732 sc->sc_output_gain[AICA_VOLUME_RIGHT] =
733 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] & 0xff;
734 aica_sendparam(sc, AICA_COMMAND_VOL,
735 sc->sc_output_gain[AICA_VOLUME_LEFT],
736 sc->sc_output_gain[AICA_VOLUME_RIGHT]);
737 break;
738 default:
739 return EINVAL;
740 }
741
742 return 0;
743 }
744
745 int
746 aica_get_port(void *addr, mixer_ctrl_t *mc)
747 {
748 struct aica_softc *sc = addr;
749
750 switch (mc->dev) {
751 case AICA_MASTER_VOL:
752 if (mc->un.value.num_channels != 1)
753 return EINVAL;
754 mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
755 L16TO256(L256TO16(sc->sc_output_master));
756 break;
757 case AICA_OUTPUT_GAIN:
758 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
759 sc->sc_output_gain[AICA_VOLUME_LEFT];
760 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
761 sc->sc_output_gain[AICA_VOLUME_RIGHT];
762 break;
763 default:
764 return EINVAL;
765 }
766 return 0;
767 }
768
769 int
770 aica_query_devinfo(void *addr, mixer_devinfo_t *md)
771 {
772
773 switch (md->index) {
774 case AICA_MASTER_VOL:
775 md->type = AUDIO_MIXER_VALUE;
776 md->mixer_class = AICA_OUTPUT_CLASS;
777 md->prev = md->next = AUDIO_MIXER_LAST;
778 strcpy(md->label.name, AudioNmaster);
779 md->un.v.num_channels = 1;
780 strcpy(md->un.v.units.name, AudioNvolume);
781 return 0;
782 case AICA_OUTPUT_GAIN:
783 md->type = AUDIO_MIXER_VALUE;
784 md->mixer_class = AICA_OUTPUT_CLASS;
785 md->prev = md->next = AUDIO_MIXER_LAST;
786 strcpy(md->label.name, AudioNoutput);
787 md->un.v.num_channels = 2;
788 strcpy(md->label.name, AudioNvolume);
789 return 0;
790 case AICA_OUTPUT_CLASS:
791 md->type = AUDIO_MIXER_CLASS;
792 md->mixer_class = AICA_OUTPUT_CLASS;
793 md->next = md->prev = AUDIO_MIXER_LAST;
794 strcpy(md->label.name, AudioCoutputs);
795 return 0;
796 }
797
798 return ENXIO;
799 }
800
801 int
802 aica_get_props(void *addr)
803 {
804
805 return 0;
806 }
807