No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / hpcmips / vr / vraiu.c
blob4010ff1bfd32fdfbb0e5b73166aef921d8766847
1 /* $NetBSD: vraiu.c,v 1.11 2005/12/11 12:17:34 christos Exp $ */
3 /*
4 * Copyright (c) 2001 HAMAJIMA Katsuomi. All rights reserved.
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.
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.
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: vraiu.c,v 1.11 2005/12/11 12:17:34 christos Exp $");
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>
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>
44 #include <sys/audioio.h>
45 #include <dev/audio_if.h>
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>
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
60 #define AUDIO_BUF_SIZE 2048
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 */
86 int vraiu_match(struct device *, struct cfdata *, void *);
87 void vraiu_attach(struct device *, struct device *, void *);
88 int vraiu_intr(void *);
90 CFATTACH_DECL(vraiu, sizeof(struct vraiu_softc),
91 vraiu_match, vraiu_attach, NULL, NULL);
93 struct audio_device aiu_device = {
94 "VR4121 AIU",
95 "0.1",
96 "aiu"
100 * Define our interface to the higher level audio driver.
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 *);
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,
148 * convert to 1ch 10bit unsigned PCM data.
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);
161 * software volume control
163 static void vraiu_volume(struct vraiu_softc *, u_short *, void *, int);
166 vraiu_match(struct device *parent, struct cfdata *cf, void *aux)
168 return 1;
171 void
172 vraiu_attach(struct device *parent, struct device *self, void *aux)
174 struct vrip_attach_args *va;
175 struct vraiu_softc *sc;
176 bus_dma_segment_t segs;
177 int rsegs;
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;
191 if (!sc->sc_cc) {
192 printf(" not configured: cmu not found\n");
193 return;
195 if (!sc->sc_dc) {
196 printf(" not configured: dcu not found\n");
197 return;
199 if (!sc->sc_ac) {
200 printf(" not configured: dmaau not found\n");
201 return;
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;
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;
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);
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;
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;
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;
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;
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;
261 printf("\n");
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);
276 vraiu_open(void *self, int flags)
278 struct vraiu_softc *sc;
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;
286 sc->sc_status = EBUSY;
287 return 0;
290 void
291 vraiu_close(void *self)
293 struct vraiu_softc *sc;
295 DPRINTFN(1, ("vraiu_close\n"));
296 sc = self;
297 vraiu_halt_output(self);
298 sc->sc_status = 0;
302 vraiu_query_encoding(void *self, struct audio_encoding *ae)
304 DPRINTFN(3, ("vraiu_query_encoding\n"));
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;
366 return 0;
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)
374 struct vraiu_softc *sc;
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;
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;
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;
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;
447 break;
448 default:
449 DPRINTFN(0, ("vraiu_set_params: encoding error"
450 " (%d)\n", play->encoding));
451 return EINVAL;
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;
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;
505 break;
506 default:
507 DPRINTFN(0, ("vraiu_set_params: encoding error"
508 " (%d)\n", play->encoding));
509 return EINVAL;
511 break;
512 default:
513 DPRINTFN(0, ("vraiu_set_params: precision error (%d)\n",
514 play->precision));
515 return EINVAL;
518 sc->sc_encoding = play->encoding;
519 sc->sc_precision = play->precision;
520 sc->sc_channels = play->channels;
521 return 0;
525 vraiu_round_blocksize(void *self, int bs, int mode, const audio_params_t *param)
527 struct vraiu_softc *sc;
528 int n;
530 sc = self;
531 n = AUDIO_BUF_SIZE;
532 if (sc->sc_precision == 8)
533 n /= 2;
534 n *= sc->sc_channels;
536 DPRINTFN(1, ("vraiu_round_blocksize: upper %d, lower %d\n",
537 bs, n));
539 return n;
543 vraiu_commit_settings(void *self)
545 struct vraiu_softc *sc;
546 int err;
548 DPRINTFN(1, ("vraiu_commit_settings\n"));
549 sc = self;
550 if (sc->sc_status != EBUSY)
551 return sc->sc_status;
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;
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;
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;
573 vraiu_init_output(void *self, void *buffer, int size)
575 struct vraiu_softc *sc;
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;
589 vraiu_start_output(void *self, void *block, int bsize,
590 void (*intr)(void *), void *intrarg)
592 struct vraiu_softc *sc;
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;
612 vraiu_start_input(void *self, void *block, int bsize,
613 void (*intr)(void *), void *intrarg)
616 DPRINTFN(3, ("vraiu_start_input\n"));
617 /* no input */
618 return ENXIO;
622 vraiu_intr(void* self)
624 struct vraiu_softc *sc;
625 uint32_t reg;
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);
639 bus_space_write_2(sc->sc_iot, sc->sc_ioh, INT_REG_W, SENDINTR);
641 DPRINTFN(2, ("\n"));
642 return 0;
646 vraiu_halt_output(void *self)
648 struct vraiu_softc *sc;
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;
670 vraiu_halt_input(void *self)
673 DPRINTFN(3, ("vraiu_halt_input\n"));
674 /* no input */
675 return ENXIO;
680 vraiu_getdev(void *self, struct audio_device *ret)
683 DPRINTFN(3, ("vraiu_getdev\n"));
684 *ret = aiu_device;
685 return 0;
689 vraiu_set_port(void *self, mixer_ctrl_t *mc)
691 struct vraiu_softc *sc;
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;
705 return EINVAL;
709 vraiu_get_port(void *self, mixer_ctrl_t *mc)
711 struct vraiu_softc *sc;
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;
723 return EINVAL;
727 vraiu_query_devinfo(void *self, mixer_devinfo_t *di)
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;
749 return ENXIO;
753 vraiu_get_props(void *self)
755 DPRINTFN(3, ("vraiu_get_props\n"));
757 return 0;
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,
795 static void
796 vraiu_slinear8_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
798 char *q;
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;
808 #endif
809 while (n--) {
810 short i = *q++;
811 *dmap++ = (i << 2) + 0x200;
815 static void
816 vraiu_slinear8_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
818 char *q;
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;
828 #endif
829 n /= 2;
830 while (n--) {
831 short i = *q++;
832 short j = *q++;
833 *dmap++ = ((i + j) << 1) + 0x200;
837 static void
838 vraiu_ulinear8_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
840 u_char *q;
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;
850 #endif
851 while (n--) {
852 short i = *q++;
853 *dmap++ = i << 2;
857 static void
858 vraiu_ulinear8_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
860 u_char *q;
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;
870 #endif
871 n /= 2;
872 while (n--) {
873 short i = *q++;
874 short j = *q++;
875 *dmap++ = (i + j) << 1;
879 static void
880 vraiu_mulaw_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
882 u_char *q;
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;
892 #endif
893 while (n--) {
894 short i = mulaw_to_lin[*q++];
895 *dmap++ = i << 2;
899 static void
900 vraiu_mulaw_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
902 u_char *q;
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;
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;
921 static void
922 vraiu_slinear16_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
924 short *q;
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;
934 #endif
935 n /= 2;
936 while (n--) {
937 short i = *q++;
938 *dmap++ = (i >> 6) + 0x200;
942 static void
943 vraiu_slinear16_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
945 short *q;
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;
955 #endif
956 n /= 4;
957 while (n--) {
958 short i = *q++;
959 short j = *q++;
960 *dmap++ = (i >> 7) + (j >> 7) + 0x200;
964 static void
965 vraiu_slinear16sw_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
967 short *q;
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;
977 #endif
978 n /= 2;
979 while (n--) {
980 short i = bswap16(*q++);
981 *dmap++ = (i >> 6) + 0x200;
985 static void
986 vraiu_slinear16sw_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
988 short *q;
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;
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;
1007 static void
1008 vraiu_volume(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
1010 int16_t *x;
1011 int i;
1012 short j;
1013 int vol;
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;
1022 return;