Home | History | Annotate | Line # | Download | only in g2
aica.c revision 1.28
      1 /*	$NetBSD: aica.c,v 1.28 2020/02/23 04:02:45 isaki 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.28 2020/02/23 04:02:45 isaki 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_halt_output(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 void aica_get_locks(void *, kmutex_t **, kmutex_t **);
    146 
    147 const struct audio_hw_if aica_hw_if = {
    148 	.open			= aica_open,
    149 	.close			= aica_close,
    150 	.query_format		= aica_query_format,
    151 	.set_format		= aica_set_format,
    152 	.round_blocksize	= aica_round_blocksize,
    153 	.halt_output		= aica_halt_output,
    154 	.getdev			= aica_getdev,
    155 	.set_port		= aica_set_port,
    156 	.get_port		= aica_get_port,
    157 	.query_devinfo		= aica_query_devinfo,
    158 	.round_buffersize	= aica_round_buffersize,
    159 	.get_props		= aica_get_props,
    160 	.trigger_output		= aica_trigger_output,
    161 	.get_locks		= aica_get_locks,
    162 };
    163 
    164 int
    165 aica_match(device_t parent, cfdata_t cf, void *aux)
    166 {
    167 	static int aica_matched = 0;
    168 
    169 	if (aica_matched)
    170 		return 0;
    171 
    172 	aica_matched = 1;
    173 	return 1;
    174 }
    175 
    176 void
    177 aica_attach(device_t parent, device_t self, void *aux)
    178 {
    179 	struct aica_softc *sc;
    180 	struct g2bus_attach_args *ga;
    181 	int i;
    182 
    183 	sc = device_private(self);
    184 	ga = aux;
    185 	sc->sc_dev = self;
    186 	sc->sc_memt = ga->ga_memt;
    187 
    188 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
    189 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
    190 
    191 	if (bus_space_map(sc->sc_memt, AICA_REG_ADDR, 0x3000, 0,
    192 	    &sc->sc_aica_regh) != 0) {
    193 		aprint_error(": can't map AICA register space\n");
    194 		return;
    195 	}
    196 
    197 	if (bus_space_map(sc->sc_memt, AICA_RAM_START, AICA_RAM_SIZE, 0,
    198 	    &sc->sc_aica_memh) != 0) {
    199 		aprint_error(": can't map AICA memory space\n");
    200 		return;
    201 	}
    202 
    203 	aprint_normal(": ARM7 Sound Processing Unit\n");
    204 
    205 	aica_disable(sc);
    206 
    207 	for (i = 0; i < AICA_NCHAN; i++)
    208 		bus_space_write_4(sc->sc_memt,sc->sc_aica_regh, i << 7,
    209 		    ((bus_space_read_4(sc->sc_memt, sc->sc_aica_regh, i << 7)
    210 		    & ~0x4000) | 0x8000));
    211 
    212 	/* load microcode, and clear memory */
    213 	bus_space_set_region_4(sc->sc_memt, sc->sc_aica_memh,
    214 	    0, 0, AICA_RAM_SIZE / 4);
    215 
    216 	aica_memwrite(sc, 0, aica_armcode, sizeof(aica_armcode));
    217 
    218 	aica_enable(sc);
    219 
    220 	aprint_normal_dev(self, "interrupting at %s\n",
    221 	    sysasic_intr_string(SYSASIC_IRL9));
    222 	sysasic_intr_establish(SYSASIC_EVENT_AICA, IPL_BIO, SYSASIC_IRL9,
    223 	    aica_intr, sc);
    224 
    225 	audio_attach_mi(&aica_hw_if, sc, self);
    226 
    227 	/* init parameters */
    228 	sc->sc_output_master = 255;
    229 	sc->sc_output_gain[AICA_VOLUME_LEFT]  = 255;
    230 	sc->sc_output_gain[AICA_VOLUME_RIGHT] = 255;
    231 }
    232 
    233 void
    234 aica_enable(struct aica_softc *sc)
    235 {
    236 
    237 	bus_space_write_4(sc->sc_memt, sc->sc_aica_regh, 0x28a8, 24);
    238 	bus_space_write_4(sc->sc_memt, sc->sc_aica_regh, 0x2c00,
    239 	    bus_space_read_4(sc->sc_memt, sc->sc_aica_regh, 0x2c00) & ~1);
    240 }
    241 
    242 void
    243 aica_disable(struct aica_softc *sc)
    244 {
    245 
    246 	bus_space_write_4(sc->sc_memt, sc->sc_aica_regh, 0x2c00,
    247 	    bus_space_read_4(sc->sc_memt, sc->sc_aica_regh, 0x2c00) | 1);
    248 }
    249 
    250 inline static void
    251 aica_g2fifo_wait(void)
    252 {
    253 	int i;
    254 
    255 	i = AICA_TIMEOUT;
    256 	while (--i > 0)
    257 		if ((*(volatile uint32_t *)0xa05f688c) & 0x11)
    258 			break;
    259 }
    260 
    261 void
    262 aica_memwrite(struct aica_softc *sc, bus_size_t offset, uint32_t *src, int len)
    263 {
    264 	int n;
    265 
    266 	KASSERT((offset & 3) == 0);
    267 	n = (len + 3) / 4;	/* uint32_t * n (aligned) */
    268 
    269 	aica_g2fifo_wait();
    270 	bus_space_write_region_4(sc->sc_memt, sc->sc_aica_memh,
    271 	    offset, src, n);
    272 }
    273 
    274 void
    275 aica_ch2p16write(struct aica_softc *sc, bus_size_t offset, uint16_t *src,
    276     int len)
    277 {
    278 	union {
    279 		uint32_t w[8];
    280 		uint16_t s[16];
    281 	} buf;
    282 	uint16_t *p;
    283 	int i;
    284 
    285 	KASSERT((offset & 3) == 0);
    286 
    287 	while (len >= 32) {
    288 		p = buf.s;
    289 		*p++ = *src++; src++;
    290 		*p++ = *src++; src++;
    291 		*p++ = *src++; src++;
    292 		*p++ = *src++; src++;
    293 		*p++ = *src++; src++;
    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 
    306 		aica_g2fifo_wait();
    307 		bus_space_write_region_4(sc->sc_memt, sc->sc_aica_memh,
    308 		    offset, buf.w , 32 / 4);
    309 
    310 		offset += sizeof(uint16_t) * 16;
    311 		len -= 32;
    312 	}
    313 
    314 	if (len / 2 > 0) {
    315 		p = buf.s;
    316 		for (i = 0; i < len / 2; i++) {
    317 			*p++ = *src++; src++;
    318 		}
    319 
    320 		aica_g2fifo_wait();
    321 		bus_space_write_region_4(sc->sc_memt, sc->sc_aica_memh,
    322 		    offset, buf.w, len / 4);
    323 	}
    324 }
    325 
    326 void
    327 aica_ch2p8write(struct aica_softc *sc, bus_size_t offset, uint8_t *src,
    328     int len)
    329 {
    330 	uint32_t buf[8];
    331 	uint8_t *p;
    332 	int i;
    333 
    334 	KASSERT((offset & 3) == 0);
    335 	while (len >= 32) {
    336 		p = (uint8_t *)buf;
    337 
    338 		*p++ = *src++; src++;
    339 		*p++ = *src++; src++;
    340 		*p++ = *src++; src++;
    341 		*p++ = *src++; src++;
    342 		*p++ = *src++; src++;
    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 
    371 		aica_g2fifo_wait();
    372 		bus_space_write_region_4(sc->sc_memt, sc->sc_aica_memh,
    373 		    offset, buf, 32 / 4);
    374 
    375 		offset += 32;
    376 		len -= 32;
    377 	}
    378 
    379 	if (len) {
    380 		p = (uint8_t *)buf;
    381 		for (i = 0; i < len; i++) {
    382 			*p++ = *src++; src++;
    383 		}
    384 
    385 		aica_g2fifo_wait();
    386 		bus_space_write_region_4(sc->sc_memt, sc->sc_aica_memh,
    387 		    offset, buf, len / 4);
    388 	}
    389 }
    390 
    391 int
    392 aica_open(void *addr, int flags)
    393 {
    394 	struct aica_softc *sc;
    395 
    396 	sc = addr;
    397 	if (sc->sc_open)
    398 		return EBUSY;
    399 
    400 	sc->sc_intr = NULL;
    401 	sc->sc_open = 1;
    402 
    403 	return 0;
    404 }
    405 
    406 void
    407 aica_close(void *addr)
    408 {
    409 	struct aica_softc *sc;
    410 
    411 	sc = addr;
    412 	sc->sc_open = 0;
    413 	sc->sc_intr = NULL;
    414 }
    415 
    416 int
    417 aica_query_format(void *addr, audio_format_query_t *afp)
    418 {
    419 
    420 	return audio_query_format(aica_formats, AICA_NFORMATS, afp);
    421 }
    422 
    423 int
    424 aica_set_format(void *addr, int setmode,
    425     const audio_params_t *play, const audio_params_t *rec,
    426     audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
    427 {
    428 	struct aica_softc *sc;
    429 
    430 	sc = addr;
    431 	sc->sc_precision = play->precision;
    432 	sc->sc_channels = play->channels;
    433 	sc->sc_rate = play->sample_rate;
    434 	return 0;
    435 }
    436 
    437 int
    438 aica_round_blocksize(void *addr, int blk, int mode, const audio_params_t *param)
    439 {
    440 #if 0	/* XXX this has not worked since kent-audio1 merge? */
    441 	struct aica_softc *sc;
    442 
    443 	sc = addr;
    444 	switch (sc->sc_precision) {
    445 	case 4:
    446 		if (sc->sc_channels == 1)
    447 			return AICA_DMABUF_SIZE / 4;
    448 		else
    449 			return AICA_DMABUF_SIZE / 2;
    450 		break;
    451 	case 8:
    452 		if (sc->sc_channels == 1)
    453 			return AICA_DMABUF_SIZE / 2;
    454 		else
    455 			return AICA_DMABUF_SIZE;
    456 		break;
    457 	case 16:
    458 		if (sc->sc_channels == 1)
    459 			return AICA_DMABUF_SIZE;
    460 		else
    461 			return AICA_DMABUF_SIZE * 2;
    462 		break;
    463 	default:
    464 		break;
    465 	}
    466 
    467 #endif
    468 	return AICA_DMABUF_SIZE / 4;
    469 }
    470 
    471 size_t
    472 aica_round_buffersize(void *addr, int dir, size_t bufsize)
    473 {
    474 	struct aica_softc *sc;
    475 
    476 	sc = addr;
    477 	if (bufsize > 65536 * sc->sc_channels)
    478 		return 65536 * sc->sc_channels;
    479 	return bufsize;
    480 }
    481 
    482 void
    483 aica_command(struct aica_softc *sc, uint32_t command)
    484 {
    485 
    486 	bus_space_write_4(sc->sc_memt, sc->sc_aica_memh,
    487 	    AICA_ARM_CMD_COMMAND, command);
    488 	bus_space_write_4(sc->sc_memt,sc->sc_aica_memh, AICA_ARM_CMD_SERIAL,
    489 	    bus_space_read_4(sc->sc_memt, sc->sc_aica_memh,
    490 	    AICA_ARM_CMD_SERIAL) + 1);
    491 }
    492 
    493 void
    494 aica_sendparam(struct aica_softc *sc, uint32_t command,
    495     int32_t lparam, int32_t rparam)
    496 {
    497 
    498 	bus_space_write_4(sc->sc_memt,sc->sc_aica_memh,
    499 	    AICA_ARM_CMD_LPARAM, lparam);
    500 	bus_space_write_4(sc->sc_memt,sc->sc_aica_memh,
    501 	    AICA_ARM_CMD_RPARAM, rparam);
    502 
    503 	aica_command(sc, command);
    504 }
    505 
    506 void
    507 aica_play(struct aica_softc *sc, int blksize, int channel, int rate, int prec)
    508 {
    509 
    510 	bus_space_write_4(sc->sc_memt,sc->sc_aica_memh,
    511 	    AICA_ARM_CMD_BLOCKSIZE, blksize);
    512 	bus_space_write_4(sc->sc_memt,sc->sc_aica_memh,
    513 	    AICA_ARM_CMD_CHANNEL, channel);
    514 	bus_space_write_4(sc->sc_memt,sc->sc_aica_memh,
    515 	    AICA_ARM_CMD_RATE, rate);
    516 	bus_space_write_4(sc->sc_memt,sc->sc_aica_memh,
    517 	    AICA_ARM_CMD_PRECISION, prec);
    518 
    519 	aica_command(sc, AICA_COMMAND_PLAY);
    520 }
    521 
    522 void
    523 aica_fillbuffer(struct aica_softc *sc)
    524 {
    525 
    526 	if (sc->sc_channels == 2) {
    527 		if (sc->sc_precision == 16) {
    528 			aica_ch2p16write(sc,
    529 			    AICA_DMABUF_LEFT + sc->sc_nextfill,
    530 			    (uint16_t *)sc->sc_buffer + 0, sc->sc_blksize / 2);
    531 			aica_ch2p16write(sc,
    532 			    AICA_DMABUF_RIGHT + sc->sc_nextfill,
    533 			    (uint16_t *)sc->sc_buffer + 1, sc->sc_blksize / 2);
    534 		} else if (sc->sc_precision == 8) {
    535 			aica_ch2p8write(sc, AICA_DMABUF_LEFT + sc->sc_nextfill,
    536 			    (uint8_t *)sc->sc_buffer + 0, sc->sc_blksize / 2);
    537 			aica_ch2p8write(sc, AICA_DMABUF_RIGHT + sc->sc_nextfill,
    538 			    (uint8_t *)sc->sc_buffer + 1, sc->sc_blksize / 2);
    539 		}
    540 	} else {
    541 		aica_memwrite(sc, AICA_DMABUF_MONO + sc->sc_nextfill,
    542 		    sc->sc_buffer, sc->sc_blksize);
    543 	}
    544 
    545 	sc->sc_buffer = (int8_t *)sc->sc_buffer + sc->sc_blksize;
    546 	if (sc->sc_buffer >= sc->sc_buffer_end)
    547 		sc->sc_buffer = sc->sc_buffer_start;
    548 
    549 	sc->sc_nextfill ^= sc->sc_blksize / sc->sc_channels;
    550 }
    551 
    552 int
    553 aica_intr(void *arg)
    554 {
    555 	struct aica_softc *sc;
    556 
    557 	sc = arg;
    558 
    559 	mutex_spin_enter(&sc->sc_intr_lock);
    560 
    561 	aica_fillbuffer(sc);
    562 
    563 	/* call audio interrupt handler (audio_pint()) */
    564 	if (sc->sc_open && sc->sc_intr != NULL) {
    565 		(*(sc->sc_intr))(sc->sc_intr_arg);
    566 	}
    567 
    568 	/* clear SPU interrupt */
    569 	bus_space_write_4(sc->sc_memt, sc->sc_aica_regh, 0x28bc, 0x20);
    570 
    571 	mutex_spin_exit(&sc->sc_intr_lock);
    572 
    573 	return 1;
    574 }
    575 
    576 int
    577 aica_trigger_output(void *addr, void *start, void *end, int blksize,
    578     void (*intr)(void *), void *arg, const audio_params_t *param)
    579 {
    580 	struct aica_softc *sc;
    581 
    582 	sc = addr;
    583 
    584 	sc->sc_buffer_start = sc->sc_buffer = start;
    585 	sc->sc_buffer_end = end;
    586 	sc->sc_blksize = blksize;
    587 	sc->sc_nextfill = 0;
    588 
    589 	sc->sc_intr = intr;
    590 	sc->sc_intr_arg = arg;
    591 
    592 	/*
    593 	 * The aica arm side driver uses a double buffer to play sounds.
    594 	 * we need to fill two buffers before playing.
    595 	 */
    596 	aica_fillbuffer(sc);
    597 	aica_fillbuffer(sc);
    598 
    599 	/* ...and start playing */
    600 	aica_play(sc, blksize / sc->sc_channels, sc->sc_channels, sc->sc_rate,
    601 	    sc->sc_precision);
    602 
    603 	return 0;
    604 }
    605 
    606 int
    607 aica_halt_output(void *addr)
    608 {
    609 	struct aica_softc *sc;
    610 
    611 	sc = addr;
    612 	aica_command(sc, AICA_COMMAND_STOP);
    613 	return 0;
    614 }
    615 
    616 int
    617 aica_getdev(void *addr, struct audio_device *ret)
    618 {
    619 
    620 	*ret = aica_device;
    621 	return 0;
    622 }
    623 
    624 int
    625 aica_set_port(void *addr, mixer_ctrl_t *mc)
    626 {
    627 	struct aica_softc *sc;
    628 
    629 	sc = addr;
    630 	switch (mc->dev) {
    631 	case AICA_MASTER_VOL:
    632 		sc->sc_output_master =
    633 		    mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] & 0xff;
    634 		aica_sendparam(sc, AICA_COMMAND_MVOL,
    635 		    sc->sc_output_master, sc->sc_output_master);
    636 		break;
    637 	case AICA_OUTPUT_GAIN:
    638 		sc->sc_output_gain[AICA_VOLUME_LEFT] =
    639 		    mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]  & 0xff;
    640 		sc->sc_output_gain[AICA_VOLUME_RIGHT] =
    641 		    mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] & 0xff;
    642 		aica_sendparam(sc, AICA_COMMAND_VOL,
    643 		    sc->sc_output_gain[AICA_VOLUME_LEFT],
    644 		    sc->sc_output_gain[AICA_VOLUME_RIGHT]);
    645 		break;
    646 	default:
    647 		return EINVAL;
    648 	}
    649 
    650 	return 0;
    651 }
    652 
    653 int
    654 aica_get_port(void *addr, mixer_ctrl_t *mc)
    655 {
    656 	struct aica_softc *sc;
    657 
    658 	sc = addr;
    659 	switch (mc->dev) {
    660 	case AICA_MASTER_VOL:
    661 		if (mc->un.value.num_channels != 1)
    662 			return EINVAL;
    663 		mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
    664 		    L16TO256(L256TO16(sc->sc_output_master));
    665 		break;
    666 	case AICA_OUTPUT_GAIN:
    667 		mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
    668 		    sc->sc_output_gain[AICA_VOLUME_LEFT];
    669 		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
    670 		    sc->sc_output_gain[AICA_VOLUME_RIGHT];
    671 		break;
    672 	default:
    673 		return EINVAL;
    674 	}
    675 	return 0;
    676 }
    677 
    678 int
    679 aica_query_devinfo(void *addr, mixer_devinfo_t *md)
    680 {
    681 
    682 	switch (md->index) {
    683 	case AICA_MASTER_VOL:
    684 		md->type = AUDIO_MIXER_VALUE;
    685 		md->mixer_class = AICA_OUTPUT_CLASS;
    686 		md->prev = md->next = AUDIO_MIXER_LAST;
    687 		strcpy(md->label.name, AudioNmaster);
    688 		md->un.v.num_channels = 1;
    689 		strcpy(md->un.v.units.name, AudioNvolume);
    690 		return 0;
    691 	case AICA_OUTPUT_GAIN:
    692 		md->type = AUDIO_MIXER_VALUE;
    693 		md->mixer_class = AICA_OUTPUT_CLASS;
    694 		md->prev = md->next = AUDIO_MIXER_LAST;
    695 		strcpy(md->label.name, AudioNoutput);
    696 		md->un.v.num_channels = 2;
    697 		strcpy(md->label.name, AudioNvolume);
    698 		return 0;
    699 	case AICA_OUTPUT_CLASS:
    700 		md->type = AUDIO_MIXER_CLASS;
    701 		md->mixer_class = AICA_OUTPUT_CLASS;
    702 		md->next = md->prev = AUDIO_MIXER_LAST;
    703 		strcpy(md->label.name, AudioCoutputs);
    704 		return 0;
    705 	}
    706 
    707 	return ENXIO;
    708 }
    709 
    710 int
    711 aica_get_props(void *addr)
    712 {
    713 
    714 	return AUDIO_PROP_PLAYBACK;
    715 }
    716 
    717 void
    718 aica_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
    719 {
    720 	struct aica_softc *sc;
    721 
    722 	sc = addr;
    723 	*intr = &sc->sc_intr_lock;
    724 	*thread = &sc->sc_lock;
    725 }
    726