Home | History | Annotate | Line # | Download | only in vr
vraiu.c revision 1.16.2.1
      1 /*	$NetBSD: vraiu.c,v 1.16.2.1 2019/04/21 09:54:00 isaki Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2001 HAMAJIMA Katsuomi. 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  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 #include <sys/cdefs.h>
     29 __KERNEL_RCSID(0, "$NetBSD: vraiu.c,v 1.16.2.1 2019/04/21 09:54:00 isaki Exp $");
     30 
     31 #include <sys/param.h>
     32 #include <sys/systm.h>
     33 #include <sys/device.h>
     34 #include <sys/bswap.h>
     35 
     36 #include <machine/cpu.h>
     37 #include <machine/intr.h>
     38 #include <machine/bus.h>
     39 #include <machine/platid.h>
     40 #include <machine/platid_mask.h>
     41 #include <machine/config_hook.h>
     42 
     43 #include <sys/audioio.h>
     44 #include <dev/audio_if.h>
     45 
     46 #include <hpcmips/vr/vr.h>
     47 #include <hpcmips/vr/vripif.h>
     48 #include <hpcmips/vr/icureg.h>
     49 #include <hpcmips/vr/cmureg.h>
     50 #include <hpcmips/vr/vraiureg.h>
     51 
     52 #ifdef VRAIU_DEBUG
     53 int vraiu_debug = VRAIU_DEBUG;
     54 #define DPRINTFN(n,x) if (vraiu_debug>(n)) printf x;
     55 #else
     56 #define DPRINTFN(n,x)
     57 #endif
     58 
     59 #define AUDIO_BUF_SIZE 2048
     60 
     61 struct vraiu_softc {
     62 	device_t		sc_dev;
     63 	kmutex_t		sc_lock;
     64 	kmutex_t		sc_intr_lock;
     65 	bus_space_tag_t		sc_iot;
     66 	bus_space_handle_t	sc_ioh;
     67 	bus_dma_tag_t		sc_dmat;
     68 	bus_dmamap_t		sc_dmap;
     69 	vrip_chipset_tag_t	sc_vrip;
     70 	vrdcu_chipset_tag_t	sc_dc;
     71 	vrdmaau_chipset_tag_t	sc_ac;
     72 	vrcmu_chipset_tag_t	sc_cc;
     73 	void			*sc_handler;
     74 	u_short	*sc_buf;	/* DMA buffer pointer */
     75 	int	sc_status;	/* status */
     76 	u_int	sc_rate;	/* sampling rate */
     77 	u_char	sc_volume;	/* volume */
     78 	void	(*sc_intr)(void *);	/* interrupt routine */
     79 	void	*sc_intrdata;		/* interrupt data */
     80 };
     81 
     82 int vraiu_match(device_t, cfdata_t, void *);
     83 void vraiu_attach(device_t, device_t, void *);
     84 int vraiu_intr(void *);
     85 
     86 CFATTACH_DECL_NEW(vraiu, sizeof(struct vraiu_softc),
     87     vraiu_match, vraiu_attach, NULL, NULL);
     88 
     89 struct audio_device aiu_device = {
     90 	"VR4121 AIU",
     91 	"0.1",
     92 	"aiu"
     93 };
     94 
     95 const struct audio_format vraiu_formats = {
     96 	.mode		= AUMODE_PLAY,
     97 	.encoding	= AUDIO_ENCODING_SLINEAR_NE,
     98 	.validbits	= 10,
     99 	.precision	= 16,
    100 	.channels	= 1,
    101 	.channel_mask	= AUFMT_MONAURAL,
    102 	.frequency_type	= 4,
    103 	.frequency	= { 8000, 11025, 22050, 44100 },
    104 };
    105 
    106 /*
    107  * Define our interface to the higher level audio driver.
    108  */
    109 int vraiu_open(void *, int);
    110 void vraiu_close(void *);
    111 int vraiu_query_format(void *, audio_format_query_t *);
    112 int vraiu_round_blocksize(void *, int, int, const audio_params_t *);
    113 int vraiu_commit_settings(void *);
    114 int vraiu_init_output(void *, void*, int);
    115 int vraiu_start_output(void *, void *, int, void (*)(void *), void *);
    116 int vraiu_start_input(void *, void *, int, void (*)(void *), void *);
    117 int vraiu_halt_output(void *);
    118 int vraiu_halt_input(void *);
    119 int vraiu_getdev(void *, struct audio_device *);
    120 int vraiu_set_port(void *, mixer_ctrl_t *);
    121 int vraiu_get_port(void *, mixer_ctrl_t *);
    122 int vraiu_query_devinfo(void *, mixer_devinfo_t *);
    123 int vraiu_set_format(void *, int,
    124     const audio_params_t *, const audio_params_t *,
    125     audio_filter_reg_t *, audio_filter_reg_t *);
    126 int vraiu_get_props(void *);
    127 void vraiu_get_locks(void *, kmutex_t **, kmutex_t **);
    128 
    129 const struct audio_hw_if vraiu_hw_if = {
    130 	.open			= vraiu_open,
    131 	.close			= vraiu_close,
    132 	.query_format		= vraiu_query_format,
    133 	.set_format		= vraiu_set_format,
    134 	.round_blocksize	= vraiu_round_blocksize,
    135 	.commit_settings	= vraiu_commit_settings,
    136 	.init_output		= vraiu_init_output,
    137 	.init_input		= NULL,
    138 	.start_output		= vraiu_start_output,
    139 	.start_input		= vraiu_start_input,
    140 	.halt_output		= vraiu_halt_output,
    141 	.halt_input		= vraiu_halt_input,
    142 	.getdev			= vraiu_getdev,
    143 	.set_port		= vraiu_set_port,
    144 	.get_port		= vraiu_get_port,
    145 	.query_devinfo		= vraiu_query_devinfo,
    146 	.get_props		= vraiu_get_props,
    147 	.get_locks		= vraiu_get_locks,
    148 };
    149 
    150 /*
    151  * convert to 1ch 10bit unsigned PCM data.
    152  */
    153 static void vraiu_slinear16_1(struct vraiu_softc *, u_short *, void *, int);
    154 
    155 int
    156 vraiu_match(device_t parent, cfdata_t cf, void *aux)
    157 {
    158 	return 1;
    159 }
    160 
    161 void
    162 vraiu_attach(device_t parent, device_t self, void *aux)
    163 {
    164 	struct vrip_attach_args *va;
    165 	struct vraiu_softc *sc;
    166 	bus_dma_segment_t segs;
    167 	int rsegs;
    168 
    169 	va = aux;
    170 	sc = device_private(self);
    171 	sc->sc_dev = self;
    172 	sc->sc_status = ENXIO;
    173 	sc->sc_intr = NULL;
    174 	sc->sc_iot = va->va_iot;
    175 	sc->sc_vrip = va->va_vc;
    176 	sc->sc_cc = va->va_cc;
    177 	sc->sc_dc = va->va_dc;
    178 	sc->sc_ac = va->va_ac;
    179 	sc->sc_dmat = &vrdcu_bus_dma_tag;
    180 	sc->sc_volume = 127;
    181 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
    182 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO);
    183 
    184 	if (!sc->sc_cc) {
    185 		printf(" not configured: cmu not found\n");
    186 		return;
    187 	}
    188 	if (!sc->sc_dc) {
    189 		printf(" not configured: dcu not found\n");
    190 		return;
    191 	}
    192 	if (!sc->sc_ac) {
    193 		printf(" not configured: dmaau not found\n");
    194 		return;
    195 	}
    196 	if (bus_space_map(sc->sc_iot, va->va_addr, va->va_size,
    197 			  0 /* no flags */, &sc->sc_ioh)) {
    198 		printf(": can't map i/o space\n");
    199 		return;
    200 	}
    201 
    202 	/* install interrupt handler and enable interrupt */
    203 	if (!(sc->sc_handler = vrip_intr_establish(va->va_vc, va->va_unit,
    204 	    0, IPL_AUDIO, vraiu_intr, sc))) {
    205 		printf(": can't map interrupt line.\n");
    206 		return;
    207 	}
    208 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, (AIUINT_INTMEND | \
    209 							 AIUINT_INTM | \
    210 							 AIUINT_INTMIDLE | \
    211 							 AIUINT_INTMST | \
    212 							 AIUINT_INTSEND | \
    213 							 AIUINT_INTS | \
    214 							 AIUINT_INTSIDLE), 0);
    215 
    216 	if (bus_dmamem_alloc(sc->sc_dmat, AUDIO_BUF_SIZE, 0, 0, &segs, 1,
    217 			     &rsegs, BUS_DMA_WAITOK)) {
    218 		printf(": can't allocate memory.\n");
    219 		return;
    220 	}
    221 	if (bus_dmamem_map(sc->sc_dmat, &segs, rsegs, AUDIO_BUF_SIZE,
    222 			   (void **)&sc->sc_buf,
    223 			   BUS_DMA_WAITOK | BUS_DMA_COHERENT)) {
    224 		printf(": can't map memory.\n");
    225 		bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
    226 		return;
    227 	}
    228 	if (bus_dmamap_create(sc->sc_dmat, AUDIO_BUF_SIZE, 1, AUDIO_BUF_SIZE,
    229 			      0, BUS_DMA_WAITOK, &sc->sc_dmap)) {
    230 		printf(": can't create DMA map.\n");
    231 		bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_buf,
    232 				 AUDIO_BUF_SIZE);
    233 		bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
    234 		return;
    235 	}
    236 	if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmap, sc->sc_buf,
    237 				   AUDIO_BUF_SIZE, NULL, BUS_DMA_WAITOK)) {
    238 		printf(": can't load DMA map.\n");
    239 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmap);
    240 		bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_buf,
    241 				 AUDIO_BUF_SIZE);
    242 		bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
    243 		return;
    244 	}
    245 	if (sc->sc_ac->ac_set_aiuout(sc->sc_ac, sc->sc_buf)) {
    246 		printf(": can't set DMA address.\n");
    247 		bus_dmamap_unload(sc->sc_dmat, sc->sc_dmap);
    248 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmap);
    249 		bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_buf,
    250 				 AUDIO_BUF_SIZE);
    251 		bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
    252 		return;
    253 	}
    254 	printf("\n");
    255 
    256 	sc->sc_status = 0;
    257 	sc->sc_rate = SPS8000;
    258 	DPRINTFN(1, ("vraiu_attach: reset AIU\n"))
    259 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, AIURST);
    260 	/* attach audio subsystem */
    261 	audio_attach_mi(&vraiu_hw_if, sc, self);
    262 }
    263 
    264 int
    265 vraiu_open(void *self, int flags)
    266 {
    267 	struct vraiu_softc *sc;
    268 
    269 	DPRINTFN(1, ("vraiu_open\n"));
    270 	sc = self;
    271 	if (sc->sc_status) {
    272 		DPRINTFN(0, ("vraiu_open: device error\n"));
    273 		return sc->sc_status;
    274 	}
    275 	sc->sc_status = EBUSY;
    276 	return 0;
    277 }
    278 
    279 void
    280 vraiu_close(void *self)
    281 {
    282 	struct vraiu_softc *sc;
    283 
    284 	DPRINTFN(1, ("vraiu_close\n"));
    285 	sc = self;
    286 	sc->sc_status = 0;
    287 }
    288 
    289 int
    290 vraiu_query_format(void *self, audio_format_query_t *afp)
    291 {
    292 
    293 	return audio_query_format(&vraiu_formats, 1, afp);
    294 }
    295 
    296 int
    297 vraiu_set_format(void *self, int setmode,
    298 		 const audio_params_t *play, const audio_params_t *rec,
    299 		 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
    300 {
    301 	struct vraiu_softc *sc;
    302 
    303 	DPRINTFN(1, ("%s: %ubit, %uch, %uHz, encoding %u\n", __func__,
    304 		     play->precision, play->channels, play->sample_rate,
    305 		     play->encoding));
    306 	sc = self;
    307 
    308 	switch (play->sample_rate) {
    309 	case 8000:
    310 		sc->sc_rate = SPS8000;
    311 		break;
    312 	case 11025:
    313 		sc->sc_rate = SPS11025;
    314 		break;
    315 	case 22050:
    316 		sc->sc_rate = SPS22050;
    317 		break;
    318 	case 44100:
    319 		sc->sc_rate = SPS44100;
    320 		break;
    321 	default:
    322 		/* NOTREACHED */
    323 		panic("%s: rate error (%d)\n", __func__, play->sample_rate);
    324 	}
    325 
    326 	return 0;
    327 }
    328 
    329 int
    330 vraiu_round_blocksize(void *self, int bs, int mode, const audio_params_t *param)
    331 {
    332 	return AUDIO_BUF_SIZE;
    333 }
    334 
    335 int
    336 vraiu_commit_settings(void *self)
    337 {
    338 	struct vraiu_softc *sc;
    339 	int err;
    340 
    341 	DPRINTFN(1, ("vraiu_commit_settings\n"));
    342 	sc = self;
    343 	if (sc->sc_status != EBUSY)
    344 		return sc->sc_status;
    345 
    346 	DPRINTFN(1, ("vraiu_commit_settings: set conversion rate %d\n",
    347 		     sc->sc_rate))
    348 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNVR_REG_W, sc->sc_rate);
    349 	DPRINTFN(1, ("vraiu_commit_settings: clock supply start\n"))
    350 	if ((err = sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 1))) {
    351 		DPRINTFN(0, ("vraiu_commit_settings: clock supply error\n"));
    352 		return err;
    353 	}
    354 	DPRINTFN(1, ("vraiu_commit_settings: enable DMA\n"))
    355 	if ((err = sc->sc_dc->dc_enable_aiuout(sc->sc_dc))) {
    356 		sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 0);
    357 		DPRINTFN(0, ("vraiu_commit_settings: enable DMA error\n"));
    358 		return err;
    359 	}
    360 	DPRINTFN(1, ("vraiu_commit_settings: Vref on\n"))
    361 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNT_REG_W, DAENAIU);
    362 	return 0;
    363 }
    364 
    365 int
    366 vraiu_init_output(void *self, void *buffer, int size)
    367 {
    368 	struct vraiu_softc *sc;
    369 
    370 	DPRINTFN(1, ("vraiu_init_output: buffer %p, size %d\n", buffer, size));
    371 	sc = self;
    372 	sc->sc_intr = NULL;
    373 	DPRINTFN(1, ("vraiu_init_output: speaker power on\n"))
    374 	config_hook_call(CONFIG_HOOK_POWERCONTROL,
    375 			 CONFIG_HOOK_POWERCONTROL_SPEAKER, (void*)1);
    376 	DPRINTFN(1, ("vraiu_init_output: start output\n"))
    377 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, AIUSEN);
    378 	return 0;
    379 }
    380 
    381 int
    382 vraiu_start_output(void *self, void *block, int bsize,
    383 		   void (*intr)(void *), void *intrarg)
    384 {
    385 	struct vraiu_softc *sc;
    386 
    387 	DPRINTFN(2, ("vraiu_start_output: block %p, bsize %d\n",
    388 		     block, bsize));
    389 	sc = self;
    390 	vraiu_slinear16_1(sc, sc->sc_buf, block, bsize);
    391 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, AUDIO_BUF_SIZE,
    392 			BUS_DMASYNC_PREWRITE);
    393 	sc->sc_intr = intr;
    394 	sc->sc_intrdata = intrarg;
    395 	/* clear interrupt status */
    396 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, INT_REG_W,
    397 			  SENDINTR | SINTR | SIDLEINTR);
    398 	/* enable interrupt */
    399 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 1);
    400 	return 0;
    401 }
    402 
    403 int
    404 vraiu_start_input(void *self, void *block, int bsize,
    405 		  void (*intr)(void *), void *intrarg)
    406 {
    407 
    408 	DPRINTFN(3, ("vraiu_start_input\n"));
    409 	/* no input */
    410 	return ENXIO;
    411 }
    412 
    413 int
    414 vraiu_intr(void* self)
    415 {
    416 	struct vraiu_softc *sc;
    417 	uint32_t reg;
    418 
    419 	DPRINTFN(2, ("vraiu_intr"));
    420 	sc = self;
    421 
    422 	mutex_spin_enter(&sc->sc_intr_lock);
    423 
    424 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 0);
    425 	vrip_intr_getstatus2(sc->sc_vrip, sc->sc_handler, &reg);
    426 	if (reg & AIUINT_INTSEND) {
    427 		DPRINTFN(2, (": AIUINT_INTSEND"));
    428 		if (sc->sc_intr) {
    429 			void (*intr)(void *);
    430 			intr = sc->sc_intr;
    431 			sc->sc_intr = NULL;
    432 			(*(intr))(sc->sc_intrdata);
    433 		}
    434 		bus_space_write_2(sc->sc_iot, sc->sc_ioh, INT_REG_W, SENDINTR);
    435 	}
    436 	DPRINTFN(2, ("\n"));
    437 
    438 	mutex_spin_exit(&sc->sc_intr_lock);
    439 
    440 	return 0;
    441 }
    442 
    443 int
    444 vraiu_halt_output(void *self)
    445 {
    446 	struct vraiu_softc *sc;
    447 
    448 	DPRINTFN(1, ("vraiu_halt_output\n"));
    449 	sc =self;
    450 	DPRINTFN(1, ("vraiu_halt_output: disable interrupt\n"))
    451 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 0);
    452 	DPRINTFN(1, ("vraiu_halt_output: stop output\n"))
    453 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, 0);
    454 	DPRINTFN(1, ("vraiu_halt_output: speaker power off\n"))
    455 	config_hook_call(CONFIG_HOOK_POWERCONTROL,
    456 			 CONFIG_HOOK_POWERCONTROL_SPEAKER, (void*)0);
    457 	DPRINTFN(1, ("vraiu_halt_output: Vref off\n"))
    458 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNT_REG_W, 0);
    459 	DPRINTFN(1, ("vraiu_halt_output: disable DMA\n"))
    460 	sc->sc_dc->dc_disable(sc->sc_dc);
    461 	DPRINTFN(1, ("vraiu_halt_output: clock supply stop\n"))
    462 	sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 0);
    463 	sc->sc_intr = NULL;
    464 	return 0;
    465 }
    466 
    467 int
    468 vraiu_halt_input(void *self)
    469 {
    470 
    471 	DPRINTFN(3, ("vraiu_halt_input\n"));
    472 	/* no input */
    473 	return ENXIO;
    474 }
    475 
    476 
    477 int
    478 vraiu_getdev(void *self, struct audio_device *ret)
    479 {
    480 
    481 	DPRINTFN(3, ("vraiu_getdev\n"));
    482 	*ret = aiu_device;
    483 	return 0;
    484 }
    485 
    486 int
    487 vraiu_set_port(void *self, mixer_ctrl_t *mc)
    488 {
    489 	struct vraiu_softc *sc;
    490 
    491 	DPRINTFN(3, ("vraiu_set_port\n"));
    492 	sc = self;
    493 	/* software mixer, 1ch */
    494 	if (mc->dev == 0) {
    495 		if (mc->type != AUDIO_MIXER_VALUE)
    496 			return EINVAL;
    497 		if (mc->un.value.num_channels != 1)
    498 			return EINVAL;
    499 		sc->sc_volume = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    500 		return 0;
    501 	}
    502 
    503 	return EINVAL;
    504 }
    505 
    506 int
    507 vraiu_get_port(void *self, mixer_ctrl_t *mc)
    508 {
    509 	struct vraiu_softc *sc;
    510 
    511 	DPRINTFN(3, ("vraiu_get_port\n"));
    512 	sc = self;
    513 	/* software mixer, 1ch */
    514 	if (mc->dev == 0) {
    515 		if (mc->un.value.num_channels != 1)
    516 			return EINVAL;
    517 		mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_volume;
    518 		return 0;
    519 	}
    520 
    521 	return EINVAL;
    522 }
    523 
    524 int
    525 vraiu_query_devinfo(void *self, mixer_devinfo_t *di)
    526 {
    527 
    528 	DPRINTFN(3, ("vraiu_query_devinfo\n"));
    529 	/* software mixer, 1ch */
    530 	switch (di->index) {
    531 	case 0: /* inputs.dac mixer value */
    532 		di->mixer_class = 1;
    533 		di->next = di->prev = AUDIO_MIXER_LAST;
    534 		strcpy(di->label.name, AudioNdac);
    535 		di->type = AUDIO_MIXER_VALUE;
    536 		di->un.v.num_channels = 1;
    537 		strcpy(di->un.v.units.name, AudioNvolume);
    538 		return 0;
    539 	case 1: /* outputs class */
    540 		di->mixer_class = 1;
    541 		di->next = di->prev = AUDIO_MIXER_LAST;
    542 		strcpy(di->label.name, AudioCinputs);
    543 		di->type = AUDIO_MIXER_CLASS;
    544 		return 0;
    545 	}
    546 
    547 	return ENXIO;
    548 }
    549 
    550 int
    551 vraiu_get_props(void *self)
    552 {
    553 	DPRINTFN(3, ("vraiu_get_props\n"));
    554 
    555 	return 0;
    556 }
    557 
    558 void
    559 vraiu_get_locks(void *self, kmutex_t **intr, kmutex_t **thread)
    560 {
    561 	struct vraiu_softc *sc;
    562 
    563 	DPRINTFN(3, ("vraiu_get_locks\n"));
    564 	sc = self;
    565 
    566 	*intr = &sc->sc_intr_lock;
    567 	*thread = &sc->sc_lock;
    568 }
    569 
    570 /* slinear16/mono -> ulinear10/mono with volume */
    571 static void
    572 vraiu_slinear16_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
    573 {
    574 	short *q;
    575 
    576 	DPRINTFN(3, ("vraiu_slinear16_1\n"));
    577 	q = p;
    578 #ifdef DIAGNOSTIC
    579 	if (n > AUDIO_BUF_SIZE) {
    580 		printf("%s: output data too large (%d > %d)\n",
    581 		       device_xname(sc->sc_dev), n, AUDIO_BUF_SIZE);
    582 		n = AUDIO_BUF_SIZE;
    583 	}
    584 #endif
    585 	n /= 2;
    586 	while (n--) {
    587 		int i = *q++;
    588 		i = i * sc->sc_volume / 255;
    589 		*dmap++ = (i >> 6) + 0x200;
    590 	}
    591 }
    592