vraiu.c revision 1.7 1 /* $NetBSD: vraiu.c,v 1.7 2004/02/04 06:43:47 jmcneill 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.7 2004/02/04 06:43:47 jmcneill 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);
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, struct audio_params *,
117 struct audio_params *);
118 int vraiu_get_props(void *);
119
120 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 struct audio_params *play, struct audio_params *rec)
371 {
372 struct vraiu_softc *sc = (void*)self;
373
374 DPRINTFN(1, ("vraiu_set_params: %dbit, %dch, %ldHz, encoding %d\n",
375 play->precision, play->channels, play->sample_rate,
376 play->encoding));
377
378 switch (play->sample_rate) {
379 case 8000:
380 sc->sc_rate = SPS8000;
381 break;
382 case 11025:
383 sc->sc_rate = SPS11025;
384 break;
385 case 22050:
386 sc->sc_rate = SPS22050;
387 break;
388 case 44100:
389 sc->sc_rate = SPS44100;
390 break;
391 default:
392 DPRINTFN(0, ("vraiu_set_params: rate error (%ld)\n",
393 play->sample_rate));
394 return EINVAL;
395 }
396
397 switch (play->precision) {
398 case 8:
399 switch (play->encoding) {
400 case AUDIO_ENCODING_ULAW:
401 switch (play->channels) {
402 case 1:
403 sc->sc_decodefunc = vraiu_mulaw_1;
404 break;
405 case 2:
406 sc->sc_decodefunc = vraiu_mulaw_2;
407 break;
408 default:
409 DPRINTFN(0, ("vraiu_set_params: channel error"
410 " (%d)\n", play->channels));
411 return EINVAL;
412 }
413 break;
414 case AUDIO_ENCODING_SLINEAR:
415 case AUDIO_ENCODING_SLINEAR_BE:
416 case AUDIO_ENCODING_SLINEAR_LE:
417 switch (play->channels) {
418 case 1:
419 sc->sc_decodefunc = vraiu_slinear8_1;
420 break;
421 case 2:
422 sc->sc_decodefunc = vraiu_slinear8_2;
423 break;
424 default:
425 DPRINTFN(0, ("vraiu_set_params: channel error"
426 " (%d)\n", play->channels));
427 return EINVAL;
428 }
429 break;
430 case AUDIO_ENCODING_ULINEAR:
431 case AUDIO_ENCODING_ULINEAR_BE:
432 case AUDIO_ENCODING_ULINEAR_LE:
433 switch (play->channels) {
434 case 1:
435 sc->sc_decodefunc = vraiu_ulinear8_1;
436 break;
437 case 2:
438 sc->sc_decodefunc = vraiu_ulinear8_2;
439 break;
440 default:
441 DPRINTFN(0, ("vraiu_set_params: channel error"
442 " (%d)\n", play->channels));
443 return EINVAL;
444 }
445 break;
446 default:
447 DPRINTFN(0, ("vraiu_set_params: encoding error"
448 " (%d)\n", play->encoding));
449 return EINVAL;
450 }
451 break;
452 case 16:
453 switch (play->encoding) {
454 #if BYTE_ORDER == BIG_ENDIAN
455 case AUDIO_ENCODING_SLINEAR:
456 #endif
457 case AUDIO_ENCODING_SLINEAR_BE:
458 switch (play->channels) {
459 case 1:
460 #if BYTE_ORDER == BIG_ENDIAN
461 sc->sc_decodefunc = vraiu_slinear16_1;
462 #else
463 sc->sc_decodefunc = vraiu_slinear16sw_1;
464 #endif
465 break;
466 case 2:
467 #if BYTE_ORDER == BIG_ENDIAN
468 sc->sc_decodefunc = vraiu_slinear16_2;
469 #else
470 sc->sc_decodefunc = vraiu_slinear16sw_2;
471 #endif
472 break;
473 default:
474 DPRINTFN(0, ("vraiu_set_params: channel error"
475 " (%d)\n", play->channels));
476 return EINVAL;
477 }
478 break;
479 #if BYTE_ORDER == LITTLE_ENDIAN
480 case AUDIO_ENCODING_SLINEAR:
481 #endif
482 case AUDIO_ENCODING_SLINEAR_LE:
483 switch (play->channels) {
484 case 1:
485 #if BYTE_ORDER == LITTLE_ENDIAN
486 sc->sc_decodefunc = vraiu_slinear16_1;
487 #else
488 sc->sc_decodefunc = vraiu_slinear16sw_1;
489 #endif
490 break;
491 case 2:
492 #if BYTE_ORDER == LITTLE_ENDIAN
493 sc->sc_decodefunc = vraiu_slinear16_2;
494 #else
495 sc->sc_decodefunc = vraiu_slinear16sw_2;
496 #endif
497 break;
498 default:
499 DPRINTFN(0, ("vraiu_set_params: channel error"
500 " (%d)\n", play->channels));
501 return EINVAL;
502 }
503 break;
504 default:
505 DPRINTFN(0, ("vraiu_set_params: encoding error"
506 " (%d)\n", play->encoding));
507 return EINVAL;
508 }
509 break;
510 default:
511 DPRINTFN(0, ("vraiu_set_params: precision error (%d)\n",
512 play->precision));
513 return EINVAL;
514 }
515
516 sc->sc_encoding = play->encoding;
517 sc->sc_precision = play->precision;
518 sc->sc_channels = play->channels;
519 return 0;
520 }
521
522 int
523 vraiu_round_blocksize(void *self, int bs)
524 {
525 struct vraiu_softc *sc = (void*)self;
526 int n = AUDIO_BUF_SIZE;
527
528 if (sc->sc_precision == 8)
529 n /= 2;
530 n *= sc->sc_channels;
531
532 DPRINTFN(1, ("vraiu_round_blocksize: upper %d, lower %d\n",
533 bs, n));
534
535 return n;
536 }
537
538 int
539 vraiu_commit_settings(void *self)
540 {
541 struct vraiu_softc *sc = (void*)self;
542 int err;
543
544 DPRINTFN(1, ("vraiu_commit_settings\n"));
545
546 if (sc->sc_status != EBUSY)
547 return sc->sc_status;
548
549 DPRINTFN(1, ("vraiu_commit_settings: set conversion rate %d\n",
550 sc->sc_rate))
551 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNVR_REG_W, sc->sc_rate);
552 DPRINTFN(1, ("vraiu_commit_settings: clock supply start\n"))
553 if ((err = sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 1))) {
554 DPRINTFN(0, ("vraiu_commit_settings: clock supply error\n"));
555 return err;
556 }
557 DPRINTFN(1, ("vraiu_commit_settings: enable DMA\n"))
558 if ((err = sc->sc_dc->dc_enable_aiuout(sc->sc_dc))) {
559 sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 0);
560 DPRINTFN(0, ("vraiu_commit_settings: enable DMA error\n"));
561 return err;
562 }
563 DPRINTFN(1, ("vraiu_commit_settings: Vref on\n"))
564 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNT_REG_W, DAENAIU);
565 return 0;
566 }
567
568 int
569 vraiu_init_output(void *self, void *buffer, int size)
570 {
571 struct vraiu_softc *sc = (void*)self;
572
573 DPRINTFN(1, ("vraiu_init_output: buffer %p, size %d\n", buffer, size));
574
575 sc->sc_intr = NULL;
576 DPRINTFN(1, ("vraiu_init_output: speaker power on\n"))
577 config_hook_call(CONFIG_HOOK_POWERCONTROL,
578 CONFIG_HOOK_POWERCONTROL_SPEAKER, (void*)1);
579 DPRINTFN(1, ("vraiu_init_output: start output\n"))
580 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, AIUSEN);
581 return 0;
582 }
583
584 int
585 vraiu_start_output(void *self, void *block, int bsize,
586 void (*intr)(void *), void *intrarg)
587 {
588 struct vraiu_softc *sc = (void*)self;
589
590 DPRINTFN(2, ("vraiu_start_output: block %p, bsize %d\n",
591 block, bsize));
592 sc->sc_decodefunc(sc, sc->sc_buf, block, bsize);
593 vraiu_volume(sc, sc->sc_buf, block, bsize);
594 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, AUDIO_BUF_SIZE,
595 BUS_DMASYNC_PREWRITE);
596 sc->sc_intr = intr;
597 sc->sc_intrdata = intrarg;
598 /* clear interrupt status */
599 bus_space_write_2(sc->sc_iot, sc->sc_ioh, INT_REG_W,
600 SENDINTR | SINTR | SIDLEINTR);
601 /* enable interrupt */
602 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 1);
603 return 0;
604 }
605
606 int
607 vraiu_start_input(void *self, void *block, int bsize,
608 void (*intr)(void *), void *intrarg)
609 {
610 DPRINTFN(3, ("vraiu_start_input\n"));
611
612 /* no input */
613 return ENXIO;
614 }
615
616 int
617 vraiu_intr(void* self)
618 {
619 struct vraiu_softc *sc = (void*)self;
620 u_int32_t reg;
621
622 DPRINTFN(2, ("vraiu_intr"));
623
624 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 0);
625 vrip_intr_getstatus2(sc->sc_vrip, sc->sc_handler, ®);
626 if (reg & AIUINT_INTSEND) {
627 DPRINTFN(2, (": AIUINT_INTSEND"));
628 if (sc->sc_intr) {
629 void (*intr)(void *) = sc->sc_intr;
630 sc->sc_intr = NULL;
631 (*(intr))(sc->sc_intrdata);
632 }
633 bus_space_write_2(sc->sc_iot, sc->sc_ioh, INT_REG_W, SENDINTR);
634 }
635 DPRINTFN(2, ("\n"));
636 return 0;
637 }
638
639 int
640 vraiu_halt_output(void *self)
641 {
642 struct vraiu_softc *sc = (void*)self;
643
644 DPRINTFN(1, ("vraiu_halt_output\n"));
645
646 DPRINTFN(1, ("vraiu_halt_output: disable interrupt\n"))
647 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 0);
648 DPRINTFN(1, ("vraiu_halt_output: stop output\n"))
649 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, 0);
650 DPRINTFN(1, ("vraiu_halt_output: speaker power off\n"))
651 config_hook_call(CONFIG_HOOK_POWERCONTROL,
652 CONFIG_HOOK_POWERCONTROL_SPEAKER, (void*)0);
653 DPRINTFN(1, ("vraiu_halt_output: Vref off\n"))
654 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNT_REG_W, 0);
655 DPRINTFN(1, ("vraiu_halt_output: disable DMA\n"))
656 sc->sc_dc->dc_disable(sc->sc_dc);
657 DPRINTFN(1, ("vraiu_halt_output: clock supply stop\n"))
658 sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 0);
659 sc->sc_intr = NULL;
660 return 0;
661 }
662
663 int
664 vraiu_halt_input(void *self)
665 {
666 DPRINTFN(3, ("vraiu_halt_input\n"));
667
668 /* no input */
669 return ENXIO;
670 }
671
672
673 int
674 vraiu_getdev(void *self, struct audio_device *ret)
675 {
676 DPRINTFN(3, ("vraiu_getdev\n"));
677
678 *ret = aiu_device;
679 return 0;
680 }
681
682 int
683 vraiu_set_port(void *self, mixer_ctrl_t *mc)
684 {
685 struct vraiu_softc *sc = (struct vraiu_softc *)self;
686 DPRINTFN(3, ("vraiu_set_port\n"));
687
688 /* software mixer, 1ch */
689 if (mc->dev == 0) {
690 if (mc->type != AUDIO_MIXER_VALUE)
691 return EINVAL;
692 if (mc->un.value.num_channels != 1)
693 return EINVAL;
694 sc->sc_volume = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
695 return 0;
696 }
697
698 return EINVAL;
699 }
700
701 int
702 vraiu_get_port(void *self, mixer_ctrl_t *mc)
703 {
704 struct vraiu_softc *sc = (struct vraiu_softc *)self;
705 DPRINTFN(3, ("vraiu_get_port\n"));
706
707 /* software mixer, 1ch */
708 if (mc->dev == 0) {
709 if (mc->un.value.num_channels != 1)
710 return EINVAL;
711 mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_volume;
712 return 0;
713 }
714
715 return EINVAL;
716 }
717
718 int
719 vraiu_query_devinfo(void *self, mixer_devinfo_t *di)
720 {
721 DPRINTFN(3, ("vraiu_query_devinfo\n"));
722
723 /* software mixer, 1ch */
724 switch (di->index) {
725 case 0: /* inputs.dac mixer value */
726 di->mixer_class = 1;
727 di->next = di->prev = AUDIO_MIXER_LAST;
728 strcpy(di->label.name, AudioNdac);
729 di->type = AUDIO_MIXER_VALUE;
730 di->un.v.num_channels = 1;
731 strcpy(di->un.v.units.name, AudioNvolume);
732 return 0;
733 case 1: /* outputs class */
734 di->mixer_class = 1;
735 di->next = di->prev = AUDIO_MIXER_LAST;
736 strcpy(di->label.name, AudioCinputs);
737 di->type = AUDIO_MIXER_CLASS;
738 return 0;
739 }
740
741 return ENXIO;
742 }
743
744 int
745 vraiu_get_props(void *self)
746 {
747 DPRINTFN(3, ("vraiu_get_props\n"));
748
749 return 0;
750 }
751
752 unsigned char mulaw_to_lin[] = {
753 0x02, 0x06, 0x0a, 0x0e, 0x12, 0x16, 0x1a, 0x1e,
754 0x22, 0x26, 0x2a, 0x2e, 0x32, 0x36, 0x3a, 0x3e,
755 0x41, 0x43, 0x45, 0x47, 0x49, 0x4b, 0x4d, 0x4f,
756 0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f,
757 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
758 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
759 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x74,
760 0x74, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x78,
761 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, 0x7a, 0x7a,
762 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c,
763 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d,
764 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e,
765 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e,
766 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
767 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
768 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80,
769 0xfd, 0xf9, 0xf5, 0xf1, 0xed, 0xe9, 0xe5, 0xe1,
770 0xdd, 0xd9, 0xd5, 0xd1, 0xcd, 0xc9, 0xc5, 0xc1,
771 0xbe, 0xbc, 0xba, 0xb8, 0xb6, 0xb4, 0xb2, 0xb0,
772 0xae, 0xac, 0xaa, 0xa8, 0xa6, 0xa4, 0xa2, 0xa0,
773 0x9e, 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97,
774 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f,
775 0x8f, 0x8e, 0x8e, 0x8d, 0x8d, 0x8c, 0x8c, 0x8b,
776 0x8b, 0x8a, 0x8a, 0x89, 0x89, 0x88, 0x88, 0x87,
777 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x85, 0x85,
778 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, 0x83, 0x83,
779 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82,
780 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x81,
781 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
782 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
783 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
784 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
785 };
786
787 static void
788 vraiu_slinear8_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
789 {
790 char *q = (char*)p;
791
792 DPRINTFN(3, ("vraiu_slinear8_1\n"));
793
794 #ifdef DIAGNOSTIC
795 if (n > AUDIO_BUF_SIZE/2) {
796 printf("%s: output data too large (%d > %d)\n",
797 sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE/2);
798 n = AUDIO_BUF_SIZE/2;
799 }
800 #endif
801 while (n--) {
802 short i = *q++;
803 *dmap++ = (i << 2) + 0x200;
804 }
805 }
806
807 static void
808 vraiu_slinear8_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
809 {
810 char *q = (char*)p;
811
812 DPRINTFN(3, ("vraiu_slinear8_2\n"));
813
814 #ifdef DIAGNOSTIC
815 if (n > AUDIO_BUF_SIZE) {
816 printf("%s: output data too large (%d > %d)\n",
817 sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE);
818 n = AUDIO_BUF_SIZE;
819 }
820 #endif
821 n /= 2;
822 while (n--) {
823 short i = *q++;
824 short j = *q++;
825 *dmap++ = ((i + j) << 1) + 0x200;
826 }
827 }
828
829 static void
830 vraiu_ulinear8_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
831 {
832 u_char *q = (u_char*)p;
833
834 DPRINTFN(3, ("vraiu_ulinear8_1\n"));
835
836 #ifdef DIAGNOSTIC
837 if (n > AUDIO_BUF_SIZE/2) {
838 printf("%s: output data too large (%d > %d)\n",
839 sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE/2);
840 n = AUDIO_BUF_SIZE/2;
841 }
842 #endif
843 while (n--) {
844 short i = *q++;
845 *dmap++ = i << 2;
846 }
847 }
848
849 static void
850 vraiu_ulinear8_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
851 {
852 u_char *q = (u_char*)p;
853
854 DPRINTFN(3, ("vraiu_ulinear8_2\n"));
855
856 #ifdef DIAGNOSTIC
857 if (n > AUDIO_BUF_SIZE) {
858 printf("%s: output data too large (%d > %d)\n",
859 sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE);
860 n = AUDIO_BUF_SIZE;
861 }
862 #endif
863 n /= 2;
864 while (n--) {
865 short i = *q++;
866 short j = *q++;
867 *dmap++ = (i + j) << 1;
868 }
869 }
870
871 static void
872 vraiu_mulaw_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
873 {
874 u_char *q = (u_char*)p;
875
876 DPRINTFN(3, ("vraiu_mulaw_1\n"));
877
878 #ifdef DIAGNOSTIC
879 if (n > AUDIO_BUF_SIZE/2) {
880 printf("%s: output data too large (%d > %d)\n",
881 sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE/2);
882 n = AUDIO_BUF_SIZE/2;
883 }
884 #endif
885 while (n--) {
886 short i = mulaw_to_lin[*q++];
887 *dmap++ = i << 2;
888 }
889 }
890
891 static void
892 vraiu_mulaw_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
893 {
894 u_char *q = (u_char*)p;
895
896 DPRINTFN(3, ("vraiu_mulaw_2\n"));
897
898 #ifdef DIAGNOSTIC
899 if (n > AUDIO_BUF_SIZE) {
900 printf("%s: output data too large (%d > %d)\n",
901 sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE);
902 n = AUDIO_BUF_SIZE;
903 }
904 #endif
905 n /= 2;
906 while (n--) {
907 short i = mulaw_to_lin[*q++];
908 short j = mulaw_to_lin[*q++];
909 *dmap++ = (i + j) << 1;
910 }
911 }
912
913 static void
914 vraiu_slinear16_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
915 {
916 short *q = (short*)p;
917
918 DPRINTFN(3, ("vraiu_slinear16_1\n"));
919
920 #ifdef DIAGNOSTIC
921 if (n > AUDIO_BUF_SIZE) {
922 printf("%s: output data too large (%d > %d)\n",
923 sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE);
924 n = AUDIO_BUF_SIZE;
925 }
926 #endif
927 n /= 2;
928 while (n--) {
929 short i = *q++;
930 *dmap++ = (i >> 6) + 0x200;
931 }
932 }
933
934 static void
935 vraiu_slinear16_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
936 {
937 short *q = (short*)p;
938
939 DPRINTFN(3, ("vraiu_slinear16_2\n"));
940
941 #ifdef DIAGNOSTIC
942 if (n > AUDIO_BUF_SIZE*2) {
943 printf("%s: output data too large (%d > %d)\n",
944 sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE*2);
945 n = AUDIO_BUF_SIZE*2;
946 }
947 #endif
948 n /= 4;
949 while (n--) {
950 short i = *q++;
951 short j = *q++;
952 *dmap++ = (i >> 7) + (j >> 7) + 0x200;
953 }
954 }
955
956 static void
957 vraiu_slinear16sw_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
958 {
959 short *q = (short*)p;
960
961 DPRINTFN(3, ("vraiu_slinear16sw_1\n"));
962
963 #ifdef DIAGNOSTIC
964 if (n > AUDIO_BUF_SIZE) {
965 printf("%s: output data too large (%d > %d)\n",
966 sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE);
967 n = AUDIO_BUF_SIZE;
968 }
969 #endif
970 n /= 2;
971 while (n--) {
972 short i = bswap16(*q++);
973 *dmap++ = (i >> 6) + 0x200;
974 }
975 }
976
977 static void
978 vraiu_slinear16sw_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
979 {
980 short *q = (short*)p;
981
982 DPRINTFN(3, ("vraiu_slinear16sw_2\n"));
983
984 #ifdef DIAGNOSTIC
985 if (n > AUDIO_BUF_SIZE*2) {
986 printf("%s: output data too large (%d > %d)\n",
987 sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE*2);
988 n = AUDIO_BUF_SIZE*2;
989 }
990 #endif
991 n /= 4;
992 while (n--) {
993 short i = bswap16(*q++);
994 short j = bswap16(*q++);
995 *dmap++ = (i >> 7) + (j >> 7) + 0x200;
996 }
997 }
998
999 static void
1000 vraiu_volume(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
1001 {
1002 int16_t *x = (int16_t *)dmap;
1003 int i;
1004 short j;
1005 int vol = sc->sc_volume;
1006
1007 for (i = 0; i < n / 2; i++) {
1008 j = x[i] - 512;
1009 x[i] = ((j * vol) / 255) + 512;
1010 }
1011
1012 return;
1013 }
1014