Home | History | Annotate | Line # | Download | only in vr
vraiu.c revision 1.7
      1 /*	$NetBSD: vraiu.c,v 1.7 2004/02/04 06:43:47 jmcneill 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.7 2004/02/04 06:43:47 jmcneill 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);
    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, struct audio_params *,
    117 		     struct audio_params *);
    118 int vraiu_get_props(void *);
    119 
    120 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 		 struct audio_params *play, struct audio_params *rec)
    371 {
    372 	struct vraiu_softc *sc = (void*)self;
    373 
    374 	DPRINTFN(1, ("vraiu_set_params: %dbit, %dch, %ldHz, encoding %d\n",
    375 		     play->precision, play->channels, play->sample_rate,
    376 		     play->encoding));
    377 
    378 	switch (play->sample_rate) {
    379 	case 8000:
    380 		sc->sc_rate = SPS8000;
    381 		break;
    382 	case 11025:
    383 		sc->sc_rate = SPS11025;
    384 		break;
    385 	case 22050:
    386 		sc->sc_rate = SPS22050;
    387 		break;
    388 	case 44100:
    389 		sc->sc_rate = SPS44100;
    390 		break;
    391 	default:
    392 		DPRINTFN(0, ("vraiu_set_params: rate error (%ld)\n",
    393 			     play->sample_rate));
    394 		return EINVAL;
    395 	}
    396 
    397 	switch (play->precision) {
    398 	case 8:
    399 		switch (play->encoding) {
    400 		case AUDIO_ENCODING_ULAW:
    401 			switch (play->channels) {
    402 			case 1:
    403 				sc->sc_decodefunc = vraiu_mulaw_1;
    404 				break;
    405 			case 2:
    406 				sc->sc_decodefunc = vraiu_mulaw_2;
    407 				break;
    408 			default:
    409 				DPRINTFN(0, ("vraiu_set_params: channel error"
    410 					     " (%d)\n", play->channels));
    411 				return EINVAL;
    412 			}
    413 			break;
    414 		case AUDIO_ENCODING_SLINEAR:
    415 		case AUDIO_ENCODING_SLINEAR_BE:
    416 		case AUDIO_ENCODING_SLINEAR_LE:
    417 			switch (play->channels) {
    418 			case 1:
    419 				sc->sc_decodefunc = vraiu_slinear8_1;
    420 				break;
    421 			case 2:
    422 				sc->sc_decodefunc = vraiu_slinear8_2;
    423 				break;
    424 			default:
    425 				DPRINTFN(0, ("vraiu_set_params: channel error"
    426 					     " (%d)\n", play->channels));
    427 				return EINVAL;
    428 			}
    429 			break;
    430 		case AUDIO_ENCODING_ULINEAR:
    431 		case AUDIO_ENCODING_ULINEAR_BE:
    432 		case AUDIO_ENCODING_ULINEAR_LE:
    433 			switch (play->channels) {
    434 			case 1:
    435 				sc->sc_decodefunc = vraiu_ulinear8_1;
    436 				break;
    437 			case 2:
    438 				sc->sc_decodefunc = vraiu_ulinear8_2;
    439 				break;
    440 			default:
    441 				DPRINTFN(0, ("vraiu_set_params: channel error"
    442 					     " (%d)\n", play->channels));
    443 				return EINVAL;
    444 			}
    445 			break;
    446 		default:
    447 			DPRINTFN(0, ("vraiu_set_params: encoding error"
    448 				     " (%d)\n", play->encoding));
    449 			return EINVAL;
    450 		}
    451 		break;
    452 	case 16:
    453 		switch (play->encoding) {
    454 #if BYTE_ORDER == BIG_ENDIAN
    455 		case AUDIO_ENCODING_SLINEAR:
    456 #endif
    457 		case AUDIO_ENCODING_SLINEAR_BE:
    458 			switch (play->channels) {
    459 			case 1:
    460 #if BYTE_ORDER == BIG_ENDIAN
    461 				sc->sc_decodefunc = vraiu_slinear16_1;
    462 #else
    463 				sc->sc_decodefunc = vraiu_slinear16sw_1;
    464 #endif
    465 				break;
    466 			case 2:
    467 #if BYTE_ORDER == BIG_ENDIAN
    468 				sc->sc_decodefunc = vraiu_slinear16_2;
    469 #else
    470 				sc->sc_decodefunc = vraiu_slinear16sw_2;
    471 #endif
    472 				break;
    473 			default:
    474 				DPRINTFN(0, ("vraiu_set_params: channel error"
    475 					     " (%d)\n", play->channels));
    476 				return EINVAL;
    477 			}
    478 			break;
    479 #if BYTE_ORDER == LITTLE_ENDIAN
    480 		case AUDIO_ENCODING_SLINEAR:
    481 #endif
    482 		case AUDIO_ENCODING_SLINEAR_LE:
    483 			switch (play->channels) {
    484 			case 1:
    485 #if BYTE_ORDER == LITTLE_ENDIAN
    486 				sc->sc_decodefunc = vraiu_slinear16_1;
    487 #else
    488 				sc->sc_decodefunc = vraiu_slinear16sw_1;
    489 #endif
    490 				break;
    491 			case 2:
    492 #if BYTE_ORDER == LITTLE_ENDIAN
    493 				sc->sc_decodefunc = vraiu_slinear16_2;
    494 #else
    495 				sc->sc_decodefunc = vraiu_slinear16sw_2;
    496 #endif
    497 				break;
    498 			default:
    499 				DPRINTFN(0, ("vraiu_set_params: channel error"
    500 					     " (%d)\n", play->channels));
    501 				return EINVAL;
    502 			}
    503 			break;
    504 		default:
    505 			DPRINTFN(0, ("vraiu_set_params: encoding error"
    506 				     " (%d)\n", play->encoding));
    507 			return EINVAL;
    508 		}
    509 		break;
    510 	default:
    511 		DPRINTFN(0, ("vraiu_set_params: precision error (%d)\n",
    512 			     play->precision));
    513 		return EINVAL;
    514 	}
    515 
    516 	sc->sc_encoding = play->encoding;
    517 	sc->sc_precision = play->precision;
    518 	sc->sc_channels = play->channels;
    519 	return 0;
    520 }
    521 
    522 int
    523 vraiu_round_blocksize(void *self, int bs)
    524 {
    525 	struct vraiu_softc *sc = (void*)self;
    526 	int n = AUDIO_BUF_SIZE;
    527 
    528 	if (sc->sc_precision == 8)
    529 		n /= 2;
    530 	n *= sc->sc_channels;
    531 
    532 	DPRINTFN(1, ("vraiu_round_blocksize: upper %d, lower %d\n",
    533 		     bs, n));
    534 
    535 	return n;
    536 }
    537 
    538 int
    539 vraiu_commit_settings(void *self)
    540 {
    541 	struct vraiu_softc *sc = (void*)self;
    542 	int err;
    543 
    544 	DPRINTFN(1, ("vraiu_commit_settings\n"));
    545 
    546 	if (sc->sc_status != EBUSY)
    547 		return sc->sc_status;
    548 
    549 	DPRINTFN(1, ("vraiu_commit_settings: set conversion rate %d\n",
    550 		     sc->sc_rate))
    551 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNVR_REG_W, sc->sc_rate);
    552 	DPRINTFN(1, ("vraiu_commit_settings: clock supply start\n"))
    553 	if ((err = sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 1))) {
    554 		DPRINTFN(0, ("vraiu_commit_settings: clock supply error\n"));
    555 		return err;
    556 	}
    557 	DPRINTFN(1, ("vraiu_commit_settings: enable DMA\n"))
    558 	if ((err = sc->sc_dc->dc_enable_aiuout(sc->sc_dc))) {
    559 		sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 0);
    560 		DPRINTFN(0, ("vraiu_commit_settings: enable DMA error\n"));
    561 		return err;
    562 	}
    563 	DPRINTFN(1, ("vraiu_commit_settings: Vref on\n"))
    564 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNT_REG_W, DAENAIU);
    565 	return 0;
    566 }
    567 
    568 int
    569 vraiu_init_output(void *self, void *buffer, int size)
    570 {
    571 	struct vraiu_softc *sc = (void*)self;
    572 
    573 	DPRINTFN(1, ("vraiu_init_output: buffer %p, size %d\n", buffer, size));
    574 
    575 	sc->sc_intr = NULL;
    576 	DPRINTFN(1, ("vraiu_init_output: speaker power on\n"))
    577 	config_hook_call(CONFIG_HOOK_POWERCONTROL,
    578 			 CONFIG_HOOK_POWERCONTROL_SPEAKER, (void*)1);
    579 	DPRINTFN(1, ("vraiu_init_output: start output\n"))
    580 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, AIUSEN);
    581 	return 0;
    582 }
    583 
    584 int
    585 vraiu_start_output(void *self, void *block, int bsize,
    586 		   void (*intr)(void *), void *intrarg)
    587 {
    588 	struct vraiu_softc *sc = (void*)self;
    589 
    590 	DPRINTFN(2, ("vraiu_start_output: block %p, bsize %d\n",
    591 		     block, bsize));
    592 	sc->sc_decodefunc(sc, sc->sc_buf, block, bsize);
    593 	vraiu_volume(sc, sc->sc_buf, block, bsize);
    594 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, AUDIO_BUF_SIZE,
    595 			BUS_DMASYNC_PREWRITE);
    596 	sc->sc_intr = intr;
    597 	sc->sc_intrdata = intrarg;
    598 	/* clear interrupt status */
    599 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, INT_REG_W,
    600 			  SENDINTR | SINTR | SIDLEINTR);
    601 	/* enable interrupt */
    602 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 1);
    603 	return 0;
    604 }
    605 
    606 int
    607 vraiu_start_input(void *self, void *block, int bsize,
    608 		  void (*intr)(void *), void *intrarg)
    609 {
    610 	DPRINTFN(3, ("vraiu_start_input\n"));
    611 
    612 	/* no input */
    613 	return ENXIO;
    614 }
    615 
    616 int
    617 vraiu_intr(void* self)
    618 {
    619 	struct vraiu_softc *sc = (void*)self;
    620 	u_int32_t reg;
    621 
    622 	DPRINTFN(2, ("vraiu_intr"));
    623 
    624 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 0);
    625 	vrip_intr_getstatus2(sc->sc_vrip, sc->sc_handler, &reg);
    626 	if (reg & AIUINT_INTSEND) {
    627 		DPRINTFN(2, (": AIUINT_INTSEND"));
    628 		if (sc->sc_intr) {
    629 			void (*intr)(void *) = sc->sc_intr;
    630 			sc->sc_intr = NULL;
    631 			(*(intr))(sc->sc_intrdata);
    632 		}
    633 		bus_space_write_2(sc->sc_iot, sc->sc_ioh, INT_REG_W, SENDINTR);
    634 	}
    635 	DPRINTFN(2, ("\n"));
    636 	return 0;
    637 }
    638 
    639 int
    640 vraiu_halt_output(void *self)
    641 {
    642 	struct vraiu_softc *sc = (void*)self;
    643 
    644 	DPRINTFN(1, ("vraiu_halt_output\n"));
    645 
    646 	DPRINTFN(1, ("vraiu_halt_output: disable interrupt\n"))
    647 	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 0);
    648 	DPRINTFN(1, ("vraiu_halt_output: stop output\n"))
    649 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, 0);
    650 	DPRINTFN(1, ("vraiu_halt_output: speaker power off\n"))
    651 	config_hook_call(CONFIG_HOOK_POWERCONTROL,
    652 			 CONFIG_HOOK_POWERCONTROL_SPEAKER, (void*)0);
    653 	DPRINTFN(1, ("vraiu_halt_output: Vref off\n"))
    654 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNT_REG_W, 0);
    655 	DPRINTFN(1, ("vraiu_halt_output: disable DMA\n"))
    656 	sc->sc_dc->dc_disable(sc->sc_dc);
    657 	DPRINTFN(1, ("vraiu_halt_output: clock supply stop\n"))
    658 	sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 0);
    659 	sc->sc_intr = NULL;
    660 	return 0;
    661 }
    662 
    663 int
    664 vraiu_halt_input(void *self)
    665 {
    666 	DPRINTFN(3, ("vraiu_halt_input\n"));
    667 
    668 	/* no input */
    669 	return ENXIO;
    670 }
    671 
    672 
    673 int
    674 vraiu_getdev(void *self, struct audio_device *ret)
    675 {
    676 	DPRINTFN(3, ("vraiu_getdev\n"));
    677 
    678 	*ret = aiu_device;
    679 	return 0;
    680 }
    681 
    682 int
    683 vraiu_set_port(void *self, mixer_ctrl_t *mc)
    684 {
    685 	struct vraiu_softc *sc = (struct vraiu_softc *)self;
    686 	DPRINTFN(3, ("vraiu_set_port\n"));
    687 
    688 	/* software mixer, 1ch */
    689 	if (mc->dev == 0) {
    690 		if (mc->type != AUDIO_MIXER_VALUE)
    691 			return EINVAL;
    692 		if (mc->un.value.num_channels != 1)
    693 			return EINVAL;
    694 		sc->sc_volume = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
    695 		return 0;
    696 	}
    697 
    698 	return EINVAL;
    699 }
    700 
    701 int
    702 vraiu_get_port(void *self, mixer_ctrl_t *mc)
    703 {
    704 	struct vraiu_softc *sc = (struct vraiu_softc *)self;
    705 	DPRINTFN(3, ("vraiu_get_port\n"));
    706 
    707 	/* software mixer, 1ch */
    708 	if (mc->dev == 0) {
    709 		if (mc->un.value.num_channels != 1)
    710 			return EINVAL;
    711 		mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_volume;
    712 		return 0;
    713 	}
    714 
    715 	return EINVAL;
    716 }
    717 
    718 int
    719 vraiu_query_devinfo(void *self, mixer_devinfo_t *di)
    720 {
    721 	DPRINTFN(3, ("vraiu_query_devinfo\n"));
    722 
    723 	/* software mixer, 1ch */
    724 	switch (di->index) {
    725 	case 0: /* inputs.dac mixer value */
    726 		di->mixer_class = 1;
    727 		di->next = di->prev = AUDIO_MIXER_LAST;
    728 		strcpy(di->label.name, AudioNdac);
    729 		di->type = AUDIO_MIXER_VALUE;
    730 		di->un.v.num_channels = 1;
    731 		strcpy(di->un.v.units.name, AudioNvolume);
    732 		return 0;
    733 	case 1: /* outputs class */
    734 		di->mixer_class = 1;
    735 		di->next = di->prev = AUDIO_MIXER_LAST;
    736 		strcpy(di->label.name, AudioCinputs);
    737 		di->type = AUDIO_MIXER_CLASS;
    738 		return 0;
    739 	}
    740 
    741 	return ENXIO;
    742 }
    743 
    744 int
    745 vraiu_get_props(void *self)
    746 {
    747 	DPRINTFN(3, ("vraiu_get_props\n"));
    748 
    749 	return 0;
    750 }
    751 
    752 unsigned char mulaw_to_lin[] = {
    753 	0x02, 0x06, 0x0a, 0x0e, 0x12, 0x16, 0x1a, 0x1e,
    754 	0x22, 0x26, 0x2a, 0x2e, 0x32, 0x36, 0x3a, 0x3e,
    755 	0x41, 0x43, 0x45, 0x47, 0x49, 0x4b, 0x4d, 0x4f,
    756 	0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f,
    757 	0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
    758 	0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
    759 	0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x74,
    760 	0x74, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x78,
    761 	0x78, 0x78, 0x79, 0x79, 0x79, 0x79, 0x7a, 0x7a,
    762 	0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c,
    763 	0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d,
    764 	0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e,
    765 	0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e,
    766 	0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
    767 	0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
    768 	0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80,
    769 	0xfd, 0xf9, 0xf5, 0xf1, 0xed, 0xe9, 0xe5, 0xe1,
    770 	0xdd, 0xd9, 0xd5, 0xd1, 0xcd, 0xc9, 0xc5, 0xc1,
    771 	0xbe, 0xbc, 0xba, 0xb8, 0xb6, 0xb4, 0xb2, 0xb0,
    772 	0xae, 0xac, 0xaa, 0xa8, 0xa6, 0xa4, 0xa2, 0xa0,
    773 	0x9e, 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97,
    774 	0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f,
    775 	0x8f, 0x8e, 0x8e, 0x8d, 0x8d, 0x8c, 0x8c, 0x8b,
    776 	0x8b, 0x8a, 0x8a, 0x89, 0x89, 0x88, 0x88, 0x87,
    777 	0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x85, 0x85,
    778 	0x85, 0x85, 0x84, 0x84, 0x84, 0x84, 0x83, 0x83,
    779 	0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82,
    780 	0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x81,
    781 	0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
    782 	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    783 	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    784 	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    785 };
    786 
    787 static void
    788 vraiu_slinear8_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
    789 {
    790 	char *q = (char*)p;
    791 
    792 	DPRINTFN(3, ("vraiu_slinear8_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) + 0x200;
    804 	}
    805 }
    806 
    807 static void
    808 vraiu_slinear8_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
    809 {
    810 	char *q = (char*)p;
    811 
    812 	DPRINTFN(3, ("vraiu_slinear8_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) + 0x200;
    826 	}
    827 }
    828 
    829 static void
    830 vraiu_ulinear8_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_ulinear8_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 = *q++;
    845 		*dmap++ = i << 2;
    846 	}
    847 }
    848 
    849 static void
    850 vraiu_ulinear8_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_ulinear8_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 = *q++;
    866 		short j = *q++;
    867 		*dmap++ = (i + j) << 1;
    868 	}
    869 }
    870 
    871 static void
    872 vraiu_mulaw_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
    873 {
    874 	u_char *q = (u_char*)p;
    875 
    876 	DPRINTFN(3, ("vraiu_mulaw_1\n"));
    877 
    878 #ifdef DIAGNOSTIC
    879 	if (n > AUDIO_BUF_SIZE/2) {
    880 		printf("%s: output data too large (%d > %d)\n",
    881 		       sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE/2);
    882 		n = AUDIO_BUF_SIZE/2;
    883 	}
    884 #endif
    885 	while (n--) {
    886 		short i = mulaw_to_lin[*q++];
    887 		*dmap++ = i << 2;
    888 	}
    889 }
    890 
    891 static void
    892 vraiu_mulaw_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
    893 {
    894 	u_char *q = (u_char*)p;
    895 
    896 	DPRINTFN(3, ("vraiu_mulaw_2\n"));
    897 
    898 #ifdef DIAGNOSTIC
    899 	if (n > AUDIO_BUF_SIZE) {
    900 		printf("%s: output data too large (%d > %d)\n",
    901 		       sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE);
    902 		n = AUDIO_BUF_SIZE;
    903 	}
    904 #endif
    905 	n /= 2;
    906 	while (n--) {
    907 		short i = mulaw_to_lin[*q++];
    908 		short j = mulaw_to_lin[*q++];
    909 		*dmap++ = (i + j) << 1;
    910 	}
    911 }
    912 
    913 static void
    914 vraiu_slinear16_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
    915 {
    916 	short *q = (short*)p;
    917 
    918 	DPRINTFN(3, ("vraiu_slinear16_1\n"));
    919 
    920 #ifdef DIAGNOSTIC
    921 	if (n > AUDIO_BUF_SIZE) {
    922 		printf("%s: output data too large (%d > %d)\n",
    923 		       sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE);
    924 		n = AUDIO_BUF_SIZE;
    925 	}
    926 #endif
    927 	n /= 2;
    928 	while (n--) {
    929 		short i = *q++;
    930 		*dmap++ = (i >> 6) + 0x200;
    931 	}
    932 }
    933 
    934 static void
    935 vraiu_slinear16_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
    936 {
    937 	short *q = (short*)p;
    938 
    939 	DPRINTFN(3, ("vraiu_slinear16_2\n"));
    940 
    941 #ifdef DIAGNOSTIC
    942 	if (n > AUDIO_BUF_SIZE*2) {
    943 		printf("%s: output data too large (%d > %d)\n",
    944 		       sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE*2);
    945 		n = AUDIO_BUF_SIZE*2;
    946 	}
    947 #endif
    948 	n /= 4;
    949 	while (n--) {
    950 		short i = *q++;
    951 		short j = *q++;
    952 		*dmap++ = (i >> 7) + (j >> 7) + 0x200;
    953 	}
    954 }
    955 
    956 static void
    957 vraiu_slinear16sw_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
    958 {
    959 	short *q = (short*)p;
    960 
    961 	DPRINTFN(3, ("vraiu_slinear16sw_1\n"));
    962 
    963 #ifdef DIAGNOSTIC
    964 	if (n > AUDIO_BUF_SIZE) {
    965 		printf("%s: output data too large (%d > %d)\n",
    966 		       sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE);
    967 		n = AUDIO_BUF_SIZE;
    968 	}
    969 #endif
    970 	n /= 2;
    971 	while (n--) {
    972 		short i = bswap16(*q++);
    973 		*dmap++ = (i >> 6) + 0x200;
    974 	}
    975 }
    976 
    977 static void
    978 vraiu_slinear16sw_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
    979 {
    980 	short *q = (short*)p;
    981 
    982 	DPRINTFN(3, ("vraiu_slinear16sw_2\n"));
    983 
    984 #ifdef DIAGNOSTIC
    985 	if (n > AUDIO_BUF_SIZE*2) {
    986 		printf("%s: output data too large (%d > %d)\n",
    987 		       sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE*2);
    988 		n = AUDIO_BUF_SIZE*2;
    989 	}
    990 #endif
    991 	n /= 4;
    992 	while (n--) {
    993 		short i = bswap16(*q++);
    994 		short j = bswap16(*q++);
    995 		*dmap++ = (i >> 7) + (j >> 7) + 0x200;
    996 	}
    997 }
    998 
    999 static void
   1000 vraiu_volume(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
   1001 {
   1002 	int16_t *x = (int16_t *)dmap;
   1003 	int i;
   1004 	short j;
   1005 	int vol = sc->sc_volume;
   1006 
   1007 	for (i = 0; i < n / 2; i++) {
   1008 		j = x[i] - 512;
   1009 		x[i] = ((j * vol) / 255) + 512;
   1010 	}
   1011 
   1012 	return;
   1013 }
   1014