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