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