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