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