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