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