Home | History | Annotate | Line # | Download | only in vr
vraiu.c revision 1.9
      1 /*	$NetBSD: vraiu.c,v 1.9 2005/01/10 22:01:36 kent 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.9 2005/01/10 22:01:36 kent Exp $");
     30 
     31 #include <sys/param.h>
     32 #include <sys/systm.h>
     33 #include <sys/device.h>
     34 #include <sys/malloc.h>
     35 #include <sys/bswap.h>
     36 
     37 #include <machine/cpu.h>
     38 #include <machine/intr.h>
     39 #include <machine/bus.h>
     40 #include <machine/platid.h>
     41 #include <machine/platid_mask.h>
     42 #include <machine/config_hook.h>
     43 
     44 #include <sys/audioio.h>
     45 #include <dev/audio_if.h>
     46 
     47 #include <hpcmips/vr/vr.h>
     48 #include <hpcmips/vr/vripif.h>
     49 #include <hpcmips/vr/icureg.h>
     50 #include <hpcmips/vr/cmureg.h>
     51 #include <hpcmips/vr/vraiureg.h>
     52 
     53 #ifdef VRAIU_DEBUG
     54 int vraiu_debug = VRAIU_DEBUG;
     55 #define DPRINTFN(n,x) if (vraiu_debug>(n)) printf x;
     56 #else
     57 #define DPRINTFN(n,x)
     58 #endif
     59 
     60 #define AUDIO_BUF_SIZE 2048
     61 
     62 struct vraiu_softc {
     63 	struct device		sc_dev;
     64 	bus_space_tag_t		sc_iot;
     65 	bus_space_handle_t	sc_ioh;
     66 	bus_dma_tag_t		sc_dmat;
     67 	bus_dmamap_t		sc_dmap;
     68 	vrip_chipset_tag_t	sc_vrip;
     69 	vrdcu_chipset_tag_t	sc_dc;
     70 	vrdmaau_chipset_tag_t	sc_ac;
     71 	vrcmu_chipset_tag_t	sc_cc;
     72 	void			*sc_handler;
     73 	u_short	*sc_buf;	/* DMA buffer pointer */
     74 	int	sc_status;	/* status */
     75 	u_int	sc_rate;	/* sampling rate */
     76 	u_int	sc_channels;	/* # of channels used */
     77 	u_int	sc_encoding;	/* encoding type */
     78 	int	sc_precision;	/* 8 or 16 bits */
     79 				/* pointer to format conversion routine */
     80 	u_char	sc_volume;	/* volume */
     81 	void	(*sc_decodefunc)(struct vraiu_softc *, u_short *, void *, int);
     82 	void	(*sc_intr)(void *);	/* interrupt routine */
     83 	void	*sc_intrdata;		/* interrupt data */
     84 };
     85 
     86 int vraiu_match(struct device *, struct cfdata *, void *);
     87 void vraiu_attach(struct device *, struct device *, void *);
     88 int vraiu_intr(void *);
     89 
     90 CFATTACH_DECL(vraiu, sizeof(struct vraiu_softc),
     91     vraiu_match, vraiu_attach, NULL, NULL);
     92 
     93 struct audio_device aiu_device = {
     94 	"VR4121 AIU",
     95 	"0.1",
     96 	"aiu"
     97 };
     98 
     99 /*
    100  * Define our interface to the higher level audio driver.
    101  */
    102 int vraiu_open(void *, int);
    103 void vraiu_close(void *);
    104 int vraiu_query_encoding(void *, struct audio_encoding *);
    105 int vraiu_round_blocksize(void *, int, int, const audio_params_t *);
    106 int vraiu_commit_settings(void *);
    107 int vraiu_init_output(void *, void*, int);
    108 int vraiu_start_output(void *, void *, int, void (*)(void *), void *);
    109 int vraiu_start_input(void *, void *, int, void (*)(void *), void *);
    110 int vraiu_halt_output(void *);
    111 int vraiu_halt_input(void *);
    112 int vraiu_getdev(void *, struct audio_device *);
    113 int vraiu_set_port(void *, mixer_ctrl_t *);
    114 int vraiu_get_port(void *, mixer_ctrl_t *);
    115 int vraiu_query_devinfo(void *, mixer_devinfo_t *);
    116 int vraiu_set_params(void *, int, int, audio_params_t *, audio_params_t *,
    117 		     stream_filter_list_t *, stream_filter_list_t *);
    118 int vraiu_get_props(void *);
    119 
    120 const struct audio_hw_if vraiu_hw_if = {
    121 	vraiu_open,
    122 	vraiu_close,
    123 	NULL,
    124 	vraiu_query_encoding,
    125 	vraiu_set_params,
    126 	vraiu_round_blocksize,
    127 	vraiu_commit_settings,
    128 	vraiu_init_output,
    129 	NULL,
    130 	vraiu_start_output,
    131 	vraiu_start_input,
    132 	vraiu_halt_output,
    133 	vraiu_halt_input,
    134 	NULL,
    135 	vraiu_getdev,
    136 	NULL,
    137 	vraiu_set_port,
    138 	vraiu_get_port,
    139 	vraiu_query_devinfo,
    140 	NULL,
    141 	NULL,
    142 	NULL,
    143 	NULL,
    144 	vraiu_get_props,
    145 };
    146 
    147 /*
    148  * convert to 1ch 10bit unsigned PCM data.
    149  */
    150 static void vraiu_slinear8_1(struct vraiu_softc *, u_short *, void *, int);
    151 static void vraiu_slinear8_2(struct vraiu_softc *, u_short *, void *, int);
    152 static void vraiu_ulinear8_1(struct vraiu_softc *, u_short *, void *, int);
    153 static void vraiu_ulinear8_2(struct vraiu_softc *, u_short *, void *, int);
    154 static void vraiu_mulaw_1(struct vraiu_softc *, u_short *, void *, int);
    155 static void vraiu_mulaw_2(struct vraiu_softc *, u_short *, void *, int);
    156 static void vraiu_slinear16_1(struct vraiu_softc *, u_short *, void *, int);
    157 static void vraiu_slinear16_2(struct vraiu_softc *, u_short *, void *, int);
    158 static void vraiu_slinear16sw_1(struct vraiu_softc *, u_short *, void *, int);
    159 static void vraiu_slinear16sw_2(struct vraiu_softc *, u_short *, void *, int);
    160 /*
    161  * software volume control
    162  */
    163 static void vraiu_volume(struct vraiu_softc *, u_short *, void *, int);
    164 
    165 int
    166 vraiu_match(struct device *parent, struct cfdata *cf, void *aux)
    167 {
    168 	return 1;
    169 }
    170 
    171 void
    172 vraiu_attach(struct device *parent, struct device *self, void *aux)
    173 {
    174 	struct vrip_attach_args *va = aux;
    175 	struct vraiu_softc *sc = (void*)self;
    176 	bus_dma_segment_t segs;
    177 	int rsegs;
    178 
    179 	sc->sc_status = ENXIO;
    180 	sc->sc_intr = NULL;
    181 	sc->sc_iot = va->va_iot;
    182 	sc->sc_vrip = va->va_vc;
    183 	sc->sc_cc = va->va_cc;
    184 	sc->sc_dc = va->va_dc;
    185 	sc->sc_ac = va->va_ac;
    186 	sc->sc_dmat = &vrdcu_bus_dma_tag;
    187 	sc->sc_volume = 127;
    188 
    189 	if (!sc->sc_cc) {
    190 		printf(" not configured: cmu not found\n");
    191 		return;
    192 	}
    193 	if (!sc->sc_dc) {
    194 		printf(" not configured: dcu not found\n");
    195 		return;
    196 	}
    197 	if (!sc->sc_ac) {
    198 		printf(" not configured: dmaau not found\n");
    199 		return;
    200 	}
    201 	if (bus_space_map(sc->sc_iot, va->va_addr, va->va_size,
    202 			  0 /* no flags */, &sc->sc_ioh)) {
    203 		printf(": can't map i/o space\n");
    204 		return;
    205 	}
    206 
    207 	/* install interrupt handler and enable interrupt */
    208 	if (!(sc->sc_handler = vrip_intr_establish(va->va_vc, va->va_unit,
    209 						   0, IPL_AUDIO,
    210 						   vraiu_intr, sc))) {
    211 		printf(": can't map interrupt line.\n");
    212 		return;
    213 	}
    214 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, (AIUINT_INTMEND | \
    215 							 AIUINT_INTM | \
    216 							 AIUINT_INTMIDLE | \
    217 							 AIUINT_INTMST | \
    218 							 AIUINT_INTSEND | \
    219 							 AIUINT_INTS | \
    220 							 AIUINT_INTSIDLE), 0);
    221 
    222 	if (bus_dmamem_alloc(sc->sc_dmat, AUDIO_BUF_SIZE, 0, 0, &segs, 1,
    223 			     &rsegs, BUS_DMA_NOWAIT)) {
    224 		printf(": can't allocate memory.\n");
    225 		return;
    226 	}
    227 	if (bus_dmamem_map(sc->sc_dmat, &segs, rsegs, AUDIO_BUF_SIZE,
    228 			   (caddr_t *)&sc->sc_buf,
    229 			   BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) {
    230 		printf(": can't map memory.\n");
    231 		bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
    232 		return;
    233 	}
    234 	if (bus_dmamap_create(sc->sc_dmat, AUDIO_BUF_SIZE, 1, AUDIO_BUF_SIZE,
    235 			      0, BUS_DMA_NOWAIT, &sc->sc_dmap)) {
    236 		printf(": can't create DMA map.\n");
    237 		bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_buf,
    238 				 AUDIO_BUF_SIZE);
    239 		bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
    240 		return;
    241 	}
    242 	if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmap, sc->sc_buf,
    243 				   AUDIO_BUF_SIZE, NULL, BUS_DMA_NOWAIT)) {
    244 		printf(": can't load DMA map.\n");
    245 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmap);
    246 		bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_buf,
    247 				 AUDIO_BUF_SIZE);
    248 		bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
    249 		return;
    250 	}
    251 	if (sc->sc_ac->ac_set_aiuout(sc->sc_ac, sc->sc_buf)) {
    252 		printf(": can't set DMA address.\n");
    253 		bus_dmamap_unload(sc->sc_dmat, sc->sc_dmap);
    254 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmap);
    255 		bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_buf,
    256 				 AUDIO_BUF_SIZE);
    257 		bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
    258 		return;
    259 	}
    260 	printf("\n");
    261 
    262 	sc->sc_status = 0;
    263 	sc->sc_rate = SPS8000;
    264 	sc->sc_channels = 1;
    265 	sc->sc_precision = 8;
    266 	sc->sc_encoding = AUDIO_ENCODING_ULAW;
    267 	sc->sc_decodefunc = vraiu_mulaw_1;
    268 	DPRINTFN(1, ("vraiu_attach: reset AIU\n"))
    269 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, AIURST);
    270 	/* attach audio subsystem */
    271 	audio_attach_mi(&vraiu_hw_if, sc, &sc->sc_dev);
    272 }
    273 
    274 int
    275 vraiu_open(void *self, int flags)
    276 {
    277 	struct vraiu_softc *sc = (void*)self;
    278 
    279 	DPRINTFN(1, ("vraiu_open\n"));
    280 
    281 	if (sc->sc_status) {
    282 		DPRINTFN(0, ("vraiu_open: device error\n"));
    283 		return sc->sc_status;
    284 	}
    285 	sc->sc_status = EBUSY;
    286 	return 0;
    287 }
    288 
    289 void
    290 vraiu_close(void *self)
    291 {
    292 	struct vraiu_softc *sc = (void*)self;
    293 
    294 	DPRINTFN(1, ("vraiu_close\n"));
    295 
    296 	vraiu_halt_output(self);
    297 	sc->sc_status = 0;
    298 }
    299 
    300 int
    301 vraiu_query_encoding(void *self, struct audio_encoding *ae)
    302 {
    303 	DPRINTFN(3, ("vraiu_query_encoding\n"));
    304 
    305 	switch (ae->index) {
    306 		case 0:
    307 			strcpy(ae->name, AudioEslinear);
    308 			ae->encoding = AUDIO_ENCODING_SLINEAR;
    309 			ae->precision = 8;
    310 			ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
    311 			break;
    312 		case 1:
    313 			strcpy(ae->name, AudioEmulaw);
    314 			ae->encoding = AUDIO_ENCODING_ULAW;
    315 			ae->precision = 8;
    316 			ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
    317 			break;
    318 		case 2:
    319 			strcpy(ae->name, AudioEulinear);
    320 			ae->encoding = AUDIO_ENCODING_ULINEAR;
    321 			ae->precision = 8;
    322 			ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
    323 			break;
    324 		case 3:
    325 			strcpy(ae->name, AudioEslinear);
    326 			ae->encoding = AUDIO_ENCODING_SLINEAR;
    327 			ae->precision = 16;
    328 			ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
    329 			break;
    330 		case 4:
    331 			strcpy(ae->name, AudioEslinear_be);
    332 			ae->encoding = AUDIO_ENCODING_SLINEAR_BE;
    333 			ae->precision = 16;
    334 			ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
    335 			break;
    336 		case 5:
    337 			strcpy(ae->name, AudioEslinear_le);
    338 			ae->encoding = AUDIO_ENCODING_SLINEAR_LE;
    339 			ae->precision = 16;
    340 			ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
    341 			break;
    342 		case 6:
    343 			strcpy(ae->name, AudioEslinear);
    344 			ae->encoding = AUDIO_ENCODING_ULINEAR;
    345 			ae->precision = 16;
    346 			ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
    347 			break;
    348 		case 7:
    349 			strcpy(ae->name, AudioEslinear_be);
    350 			ae->encoding = AUDIO_ENCODING_ULINEAR_BE;
    351 			ae->precision = 16;
    352 			ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
    353 			break;
    354 		case 8:
    355 			strcpy(ae->name, AudioEslinear_le);
    356 			ae->encoding = AUDIO_ENCODING_ULINEAR_LE;
    357 			ae->precision = 16;
    358 			ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
    359 			break;
    360 		default:
    361 			DPRINTFN(0, ("vraiu_query_encoding: param error"
    362 				     " (%d)\n", ae->index));
    363 			return EINVAL;
    364 	}
    365 	return 0;
    366 }
    367 
    368 int
    369 vraiu_set_params(void *self, int setmode, int usemode,
    370 		 audio_params_t *play, audio_params_t *rec,
    371 		 stream_filter_list_t *pfil, stream_filter_list_t *rfil)
    372 {
    373 	struct vraiu_softc *sc = (void*)self;
    374 
    375 	DPRINTFN(1, ("vraiu_set_params: %ubit, %uch, %uHz, encoding %u\n",
    376 		     play->precision, play->channels, play->sample_rate,
    377 		     play->encoding));
    378 
    379 	switch (play->sample_rate) {
    380 	case 8000:
    381 		sc->sc_rate = SPS8000;
    382 		break;
    383 	case 11025:
    384 		sc->sc_rate = SPS11025;
    385 		break;
    386 	case 22050:
    387 		sc->sc_rate = SPS22050;
    388 		break;
    389 	case 44100:
    390 		sc->sc_rate = SPS44100;
    391 		break;
    392 	default:
    393 		DPRINTFN(0, ("vraiu_set_params: rate error (%ld)\n",
    394 			     play->sample_rate));
    395 		return EINVAL;
    396 	}
    397 
    398 	switch (play->precision) {
    399 	case 8:
    400 		switch (play->encoding) {
    401 		case AUDIO_ENCODING_ULAW:
    402 			switch (play->channels) {
    403 			case 1:
    404 				sc->sc_decodefunc = vraiu_mulaw_1;
    405 				break;
    406 			case 2:
    407 				sc->sc_decodefunc = vraiu_mulaw_2;
    408 				break;
    409 			default:
    410 				DPRINTFN(0, ("vraiu_set_params: channel error"
    411 					     " (%d)\n", play->channels));
    412 				return EINVAL;
    413 			}
    414 			break;
    415 		case AUDIO_ENCODING_SLINEAR:
    416 		case AUDIO_ENCODING_SLINEAR_BE:
    417 		case AUDIO_ENCODING_SLINEAR_LE:
    418 			switch (play->channels) {
    419 			case 1:
    420 				sc->sc_decodefunc = vraiu_slinear8_1;
    421 				break;
    422 			case 2:
    423 				sc->sc_decodefunc = vraiu_slinear8_2;
    424 				break;
    425 			default:
    426 				DPRINTFN(0, ("vraiu_set_params: channel error"
    427 					     " (%d)\n", play->channels));
    428 				return EINVAL;
    429 			}
    430 			break;
    431 		case AUDIO_ENCODING_ULINEAR:
    432 		case AUDIO_ENCODING_ULINEAR_BE:
    433 		case AUDIO_ENCODING_ULINEAR_LE:
    434 			switch (play->channels) {
    435 			case 1:
    436 				sc->sc_decodefunc = vraiu_ulinear8_1;
    437 				break;
    438 			case 2:
    439 				sc->sc_decodefunc = vraiu_ulinear8_2;
    440 				break;
    441 			default:
    442 				DPRINTFN(0, ("vraiu_set_params: channel error"
    443 					     " (%d)\n", play->channels));
    444 				return EINVAL;
    445 			}
    446 			break;
    447 		default:
    448 			DPRINTFN(0, ("vraiu_set_params: encoding error"
    449 				     " (%d)\n", play->encoding));
    450 			return EINVAL;
    451 		}
    452 		break;
    453 	case 16:
    454 		switch (play->encoding) {
    455 #if BYTE_ORDER == BIG_ENDIAN
    456 		case AUDIO_ENCODING_SLINEAR:
    457 #endif
    458 		case AUDIO_ENCODING_SLINEAR_BE:
    459 			switch (play->channels) {
    460 			case 1:
    461 #if BYTE_ORDER == BIG_ENDIAN
    462 				sc->sc_decodefunc = vraiu_slinear16_1;
    463 #else
    464 				sc->sc_decodefunc = vraiu_slinear16sw_1;
    465 #endif
    466 				break;
    467 			case 2:
    468 #if BYTE_ORDER == BIG_ENDIAN
    469 				sc->sc_decodefunc = vraiu_slinear16_2;
    470 #else
    471 				sc->sc_decodefunc = vraiu_slinear16sw_2;
    472 #endif
    473 				break;
    474 			default:
    475 				DPRINTFN(0, ("vraiu_set_params: channel error"
    476 					     " (%d)\n", play->channels));
    477 				return EINVAL;
    478 			}
    479 			break;
    480 #if BYTE_ORDER == LITTLE_ENDIAN
    481 		case AUDIO_ENCODING_SLINEAR:
    482 #endif
    483 		case AUDIO_ENCODING_SLINEAR_LE:
    484 			switch (play->channels) {
    485 			case 1:
    486 #if BYTE_ORDER == LITTLE_ENDIAN
    487 				sc->sc_decodefunc = vraiu_slinear16_1;
    488 #else
    489 				sc->sc_decodefunc = vraiu_slinear16sw_1;
    490 #endif
    491 				break;
    492 			case 2:
    493 #if BYTE_ORDER == LITTLE_ENDIAN
    494 				sc->sc_decodefunc = vraiu_slinear16_2;
    495 #else
    496 				sc->sc_decodefunc = vraiu_slinear16sw_2;
    497 #endif
    498 				break;
    499 			default:
    500 				DPRINTFN(0, ("vraiu_set_params: channel error"
    501 					     " (%d)\n", play->channels));
    502 				return EINVAL;
    503 			}
    504 			break;
    505 		default:
    506 			DPRINTFN(0, ("vraiu_set_params: encoding error"
    507 				     " (%d)\n", play->encoding));
    508 			return EINVAL;
    509 		}
    510 		break;
    511 	default:
    512 		DPRINTFN(0, ("vraiu_set_params: precision error (%d)\n",
    513 			     play->precision));
    514 		return EINVAL;
    515 	}
    516 
    517 	sc->sc_encoding = play->encoding;
    518 	sc->sc_precision = play->precision;
    519 	sc->sc_channels = play->channels;
    520 	return 0;
    521 }
    522 
    523 int
    524 vraiu_round_blocksize(void *self, int bs, int mode, const audio_params_t *param)
    525 {
    526 	struct vraiu_softc *sc = (void*)self;
    527 	int n = AUDIO_BUF_SIZE;
    528 
    529 	if (sc->sc_precision == 8)
    530 		n /= 2;
    531 	n *= sc->sc_channels;
    532 
    533 	DPRINTFN(1, ("vraiu_round_blocksize: upper %d, lower %d\n",
    534 		     bs, n));
    535 
    536 	return n;
    537 }
    538 
    539 int
    540 vraiu_commit_settings(void *self)
    541 {
    542 	struct vraiu_softc *sc = (void*)self;
    543 	int err;
    544 
    545 	DPRINTFN(1, ("vraiu_commit_settings\n"));
    546 
    547 	if (sc->sc_status != EBUSY)
    548 		return sc->sc_status;
    549 
    550 	DPRINTFN(1, ("vraiu_commit_settings: set conversion rate %d\n",
    551 		     sc->sc_rate))
    552 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNVR_REG_W, sc->sc_rate);
    553 	DPRINTFN(1, ("vraiu_commit_settings: clock supply start\n"))
    554 	if ((err = sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 1))) {
    555 		DPRINTFN(0, ("vraiu_commit_settings: clock supply error\n"));
    556 		return err;
    557 	}
    558 	DPRINTFN(1, ("vraiu_commit_settings: enable DMA\n"))
    559 	if ((err = sc->sc_dc->dc_enable_aiuout(sc->sc_dc))) {
    560 		sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 0);
    561 		DPRINTFN(0, ("vraiu_commit_settings: enable DMA error\n"));
    562 		return err;
    563 	}
    564 	DPRINTFN(1, ("vraiu_commit_settings: Vref on\n"))
    565 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNT_REG_W, DAENAIU);
    566 	return 0;
    567 }
    568 
    569 int
    570 vraiu_init_output(void *self, void *buffer, int size)
    571 {
    572 	struct vraiu_softc *sc = (void*)self;
    573 
    574 	DPRINTFN(1, ("vraiu_init_output: buffer %p, size %d\n", buffer, size));
    575 
    576 	sc->sc_intr = NULL;
    577 	DPRINTFN(1, ("vraiu_init_output: speaker power on\n"))
    578 	config_hook_call(CONFIG_HOOK_POWERCONTROL,
    579 			 CONFIG_HOOK_POWERCONTROL_SPEAKER, (void*)1);
    580 	DPRINTFN(1, ("vraiu_init_output: start output\n"))
    581 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, AIUSEN);
    582 	return 0;
    583 }
    584 
    585 int
    586 vraiu_start_output(void *self, void *block, int bsize,
    587 		   void (*intr)(void *), void *intrarg)
    588 {
    589 	struct vraiu_softc *sc = (void*)self;
    590 
    591 	DPRINTFN(2, ("vraiu_start_output: block %p, bsize %d\n",
    592 		     block, bsize));
    593 	sc->sc_decodefunc(sc, sc->sc_buf, block, bsize);
    594 	vraiu_volume(sc, sc->sc_buf, block, bsize);
    595 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, AUDIO_BUF_SIZE,
    596 			BUS_DMASYNC_PREWRITE);
    597 	sc->sc_intr = intr;
    598 	sc->sc_intrdata = intrarg;
    599 	/* clear interrupt status */
    600 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, INT_REG_W,
    601 			  SENDINTR | SINTR | SIDLEINTR);
    602 	/* enable interrupt */
    603 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 1);
    604 	return 0;
    605 }
    606 
    607 int
    608 vraiu_start_input(void *self, void *block, int bsize,
    609 		  void (*intr)(void *), void *intrarg)
    610 {
    611 	DPRINTFN(3, ("vraiu_start_input\n"));
    612 
    613 	/* no input */
    614 	return ENXIO;
    615 }
    616 
    617 int
    618 vraiu_intr(void* self)
    619 {
    620 	struct vraiu_softc *sc = (void*)self;
    621 	u_int32_t reg;
    622 
    623 	DPRINTFN(2, ("vraiu_intr"));
    624 
    625 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 0);
    626 	vrip_intr_getstatus2(sc->sc_vrip, sc->sc_handler, &reg);
    627 	if (reg & AIUINT_INTSEND) {
    628 		DPRINTFN(2, (": AIUINT_INTSEND"));
    629 		if (sc->sc_intr) {
    630 			void (*intr)(void *) = sc->sc_intr;
    631 			sc->sc_intr = NULL;
    632 			(*(intr))(sc->sc_intrdata);
    633 		}
    634 		bus_space_write_2(sc->sc_iot, sc->sc_ioh, INT_REG_W, SENDINTR);
    635 	}
    636 	DPRINTFN(2, ("\n"));
    637 	return 0;
    638 }
    639 
    640 int
    641 vraiu_halt_output(void *self)
    642 {
    643 	struct vraiu_softc *sc = (void*)self;
    644 
    645 	DPRINTFN(1, ("vraiu_halt_output\n"));
    646 
    647 	DPRINTFN(1, ("vraiu_halt_output: disable interrupt\n"))
    648 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 0);
    649 	DPRINTFN(1, ("vraiu_halt_output: stop output\n"))
    650 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, 0);
    651 	DPRINTFN(1, ("vraiu_halt_output: speaker power off\n"))
    652 	config_hook_call(CONFIG_HOOK_POWERCONTROL,
    653 			 CONFIG_HOOK_POWERCONTROL_SPEAKER, (void*)0);
    654 	DPRINTFN(1, ("vraiu_halt_output: Vref off\n"))
    655 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNT_REG_W, 0);
    656 	DPRINTFN(1, ("vraiu_halt_output: disable DMA\n"))
    657 	sc->sc_dc->dc_disable(sc->sc_dc);
    658 	DPRINTFN(1, ("vraiu_halt_output: clock supply stop\n"))
    659 	sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 0);
    660 	sc->sc_intr = NULL;
    661 	return 0;
    662 }
    663 
    664 int
    665 vraiu_halt_input(void *self)
    666 {
    667 	DPRINTFN(3, ("vraiu_halt_input\n"));
    668 
    669 	/* no input */
    670 	return ENXIO;
    671 }
    672 
    673 
    674 int
    675 vraiu_getdev(void *self, struct audio_device *ret)
    676 {
    677 	DPRINTFN(3, ("vraiu_getdev\n"));
    678 
    679 	*ret = aiu_device;
    680 	return 0;
    681 }
    682 
    683 int
    684 vraiu_set_port(void *self, mixer_ctrl_t *mc)
    685 {
    686 	struct vraiu_softc *sc = (struct vraiu_softc *)self;
    687 	DPRINTFN(3, ("vraiu_set_port\n"));
    688 
    689 	/* software mixer, 1ch */
    690 	if (mc->dev == 0) {
    691 		if (mc->type != AUDIO_MIXER_VALUE)
    692 			return EINVAL;
    693 		if (mc->un.value.num_channels != 1)
    694 			return EINVAL;
    695 		sc->sc_volume = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    696 		return 0;
    697 	}
    698 
    699 	return EINVAL;
    700 }
    701 
    702 int
    703 vraiu_get_port(void *self, mixer_ctrl_t *mc)
    704 {
    705 	struct vraiu_softc *sc = (struct vraiu_softc *)self;
    706 	DPRINTFN(3, ("vraiu_get_port\n"));
    707 
    708 	/* software mixer, 1ch */
    709 	if (mc->dev == 0) {
    710 		if (mc->un.value.num_channels != 1)
    711 			return EINVAL;
    712 		mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_volume;
    713 		return 0;
    714 	}
    715 
    716 	return EINVAL;
    717 }
    718 
    719 int
    720 vraiu_query_devinfo(void *self, mixer_devinfo_t *di)
    721 {
    722 	DPRINTFN(3, ("vraiu_query_devinfo\n"));
    723 
    724 	/* software mixer, 1ch */
    725 	switch (di->index) {
    726 	case 0: /* inputs.dac mixer value */
    727 		di->mixer_class = 1;
    728 		di->next = di->prev = AUDIO_MIXER_LAST;
    729 		strcpy(di->label.name, AudioNdac);
    730 		di->type = AUDIO_MIXER_VALUE;
    731 		di->un.v.num_channels = 1;
    732 		strcpy(di->un.v.units.name, AudioNvolume);
    733 		return 0;
    734 	case 1: /* outputs class */
    735 		di->mixer_class = 1;
    736 		di->next = di->prev = AUDIO_MIXER_LAST;
    737 		strcpy(di->label.name, AudioCinputs);
    738 		di->type = AUDIO_MIXER_CLASS;
    739 		return 0;
    740 	}
    741 
    742 	return ENXIO;
    743 }
    744 
    745 int
    746 vraiu_get_props(void *self)
    747 {
    748 	DPRINTFN(3, ("vraiu_get_props\n"));
    749 
    750 	return 0;
    751 }
    752 
    753 unsigned char mulaw_to_lin[] = {
    754 	0x02, 0x06, 0x0a, 0x0e, 0x12, 0x16, 0x1a, 0x1e,
    755 	0x22, 0x26, 0x2a, 0x2e, 0x32, 0x36, 0x3a, 0x3e,
    756 	0x41, 0x43, 0x45, 0x47, 0x49, 0x4b, 0x4d, 0x4f,
    757 	0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f,
    758 	0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
    759 	0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
    760 	0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x74,
    761 	0x74, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x78,
    762 	0x78, 0x78, 0x79, 0x79, 0x79, 0x79, 0x7a, 0x7a,
    763 	0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c,
    764 	0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d,
    765 	0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e,
    766 	0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e,
    767 	0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
    768 	0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
    769 	0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80,
    770 	0xfd, 0xf9, 0xf5, 0xf1, 0xed, 0xe9, 0xe5, 0xe1,
    771 	0xdd, 0xd9, 0xd5, 0xd1, 0xcd, 0xc9, 0xc5, 0xc1,
    772 	0xbe, 0xbc, 0xba, 0xb8, 0xb6, 0xb4, 0xb2, 0xb0,
    773 	0xae, 0xac, 0xaa, 0xa8, 0xa6, 0xa4, 0xa2, 0xa0,
    774 	0x9e, 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97,
    775 	0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f,
    776 	0x8f, 0x8e, 0x8e, 0x8d, 0x8d, 0x8c, 0x8c, 0x8b,
    777 	0x8b, 0x8a, 0x8a, 0x89, 0x89, 0x88, 0x88, 0x87,
    778 	0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x85, 0x85,
    779 	0x85, 0x85, 0x84, 0x84, 0x84, 0x84, 0x83, 0x83,
    780 	0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82,
    781 	0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x81,
    782 	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
    783 	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    784 	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    785 	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    786 };
    787 
    788 static void
    789 vraiu_slinear8_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
    790 {
    791 	char *q = (char*)p;
    792 
    793 	DPRINTFN(3, ("vraiu_slinear8_1\n"));
    794 
    795 #ifdef DIAGNOSTIC
    796 	if (n > AUDIO_BUF_SIZE/2) {
    797 		printf("%s: output data too large (%d > %d)\n",
    798 		       sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE/2);
    799 		n = AUDIO_BUF_SIZE/2;
    800 	}
    801 #endif
    802 	while (n--) {
    803 		short i = *q++;
    804 		*dmap++ = (i << 2) + 0x200;
    805 	}
    806 }
    807 
    808 static void
    809 vraiu_slinear8_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
    810 {
    811 	char *q = (char*)p;
    812 
    813 	DPRINTFN(3, ("vraiu_slinear8_2\n"));
    814 
    815 #ifdef DIAGNOSTIC
    816 	if (n > AUDIO_BUF_SIZE) {
    817 		printf("%s: output data too large (%d > %d)\n",
    818 		       sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE);
    819 		n = AUDIO_BUF_SIZE;
    820 	}
    821 #endif
    822 	n /= 2;
    823 	while (n--) {
    824 		short i = *q++;
    825 		short j = *q++;
    826 		*dmap++ = ((i + j) << 1) + 0x200;
    827 	}
    828 }
    829 
    830 static void
    831 vraiu_ulinear8_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
    832 {
    833 	u_char *q = (u_char*)p;
    834 
    835 	DPRINTFN(3, ("vraiu_ulinear8_1\n"));
    836 
    837 #ifdef DIAGNOSTIC
    838 	if (n > AUDIO_BUF_SIZE/2) {
    839 		printf("%s: output data too large (%d > %d)\n",
    840 		       sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE/2);
    841 		n = AUDIO_BUF_SIZE/2;
    842 	}
    843 #endif
    844 	while (n--) {
    845 		short i = *q++;
    846 		*dmap++ = i << 2;
    847 	}
    848 }
    849 
    850 static void
    851 vraiu_ulinear8_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
    852 {
    853 	u_char *q = (u_char*)p;
    854 
    855 	DPRINTFN(3, ("vraiu_ulinear8_2\n"));
    856 
    857 #ifdef DIAGNOSTIC
    858 	if (n > AUDIO_BUF_SIZE) {
    859 		printf("%s: output data too large (%d > %d)\n",
    860 		       sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE);
    861 		n = AUDIO_BUF_SIZE;
    862 	}
    863 #endif
    864 	n /= 2;
    865 	while (n--) {
    866 		short i = *q++;
    867 		short j = *q++;
    868 		*dmap++ = (i + j) << 1;
    869 	}
    870 }
    871 
    872 static void
    873 vraiu_mulaw_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
    874 {
    875 	u_char *q = (u_char*)p;
    876 
    877 	DPRINTFN(3, ("vraiu_mulaw_1\n"));
    878 
    879 #ifdef DIAGNOSTIC
    880 	if (n > AUDIO_BUF_SIZE/2) {
    881 		printf("%s: output data too large (%d > %d)\n",
    882 		       sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE/2);
    883 		n = AUDIO_BUF_SIZE/2;
    884 	}
    885 #endif
    886 	while (n--) {
    887 		short i = mulaw_to_lin[*q++];
    888 		*dmap++ = i << 2;
    889 	}
    890 }
    891 
    892 static void
    893 vraiu_mulaw_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
    894 {
    895 	u_char *q = (u_char*)p;
    896 
    897 	DPRINTFN(3, ("vraiu_mulaw_2\n"));
    898 
    899 #ifdef DIAGNOSTIC
    900 	if (n > AUDIO_BUF_SIZE) {
    901 		printf("%s: output data too large (%d > %d)\n",
    902 		       sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE);
    903 		n = AUDIO_BUF_SIZE;
    904 	}
    905 #endif
    906 	n /= 2;
    907 	while (n--) {
    908 		short i = mulaw_to_lin[*q++];
    909 		short j = mulaw_to_lin[*q++];
    910 		*dmap++ = (i + j) << 1;
    911 	}
    912 }
    913 
    914 static void
    915 vraiu_slinear16_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
    916 {
    917 	short *q = (short*)p;
    918 
    919 	DPRINTFN(3, ("vraiu_slinear16_1\n"));
    920 
    921 #ifdef DIAGNOSTIC
    922 	if (n > AUDIO_BUF_SIZE) {
    923 		printf("%s: output data too large (%d > %d)\n",
    924 		       sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE);
    925 		n = AUDIO_BUF_SIZE;
    926 	}
    927 #endif
    928 	n /= 2;
    929 	while (n--) {
    930 		short i = *q++;
    931 		*dmap++ = (i >> 6) + 0x200;
    932 	}
    933 }
    934 
    935 static void
    936 vraiu_slinear16_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
    937 {
    938 	short *q = (short*)p;
    939 
    940 	DPRINTFN(3, ("vraiu_slinear16_2\n"));
    941 
    942 #ifdef DIAGNOSTIC
    943 	if (n > AUDIO_BUF_SIZE*2) {
    944 		printf("%s: output data too large (%d > %d)\n",
    945 		       sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE*2);
    946 		n = AUDIO_BUF_SIZE*2;
    947 	}
    948 #endif
    949 	n /= 4;
    950 	while (n--) {
    951 		short i = *q++;
    952 		short j = *q++;
    953 		*dmap++ = (i >> 7) + (j >> 7) + 0x200;
    954 	}
    955 }
    956 
    957 static void
    958 vraiu_slinear16sw_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
    959 {
    960 	short *q = (short*)p;
    961 
    962 	DPRINTFN(3, ("vraiu_slinear16sw_1\n"));
    963 
    964 #ifdef DIAGNOSTIC
    965 	if (n > AUDIO_BUF_SIZE) {
    966 		printf("%s: output data too large (%d > %d)\n",
    967 		       sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE);
    968 		n = AUDIO_BUF_SIZE;
    969 	}
    970 #endif
    971 	n /= 2;
    972 	while (n--) {
    973 		short i = bswap16(*q++);
    974 		*dmap++ = (i >> 6) + 0x200;
    975 	}
    976 }
    977 
    978 static void
    979 vraiu_slinear16sw_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
    980 {
    981 	short *q = (short*)p;
    982 
    983 	DPRINTFN(3, ("vraiu_slinear16sw_2\n"));
    984 
    985 #ifdef DIAGNOSTIC
    986 	if (n > AUDIO_BUF_SIZE*2) {
    987 		printf("%s: output data too large (%d > %d)\n",
    988 		       sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE*2);
    989 		n = AUDIO_BUF_SIZE*2;
    990 	}
    991 #endif
    992 	n /= 4;
    993 	while (n--) {
    994 		short i = bswap16(*q++);
    995 		short j = bswap16(*q++);
    996 		*dmap++ = (i >> 7) + (j >> 7) + 0x200;
    997 	}
    998 }
    999 
   1000 static void
   1001 vraiu_volume(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
   1002 {
   1003 	int16_t *x = (int16_t *)dmap;
   1004 	int i;
   1005 	short j;
   1006 	int vol = sc->sc_volume;
   1007 
   1008 	for (i = 0; i < n / 2; i++) {
   1009 		j = x[i] - 512;
   1010 		x[i] = ((j * vol) / 255) + 512;
   1011 	}
   1012 
   1013 	return;
   1014 }
   1015