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