vraiu.c revision 1.6 1 /* $NetBSD: vraiu.c,v 1.6 2003/07/15 02:29:35 lukem 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.6 2003/07/15 02:29:35 lukem 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 void (*sc_decodefunc)(struct vraiu_softc *, u_short *, void *, int);
81 void (*sc_intr)(void *); /* interrupt routine */
82 void *sc_intrdata; /* interrupt data */
83 };
84
85 int vraiu_match(struct device *, struct cfdata *, void *);
86 void vraiu_attach(struct device *, struct device *, void *);
87 int vraiu_intr(void *);
88
89 CFATTACH_DECL(vraiu, sizeof(struct vraiu_softc),
90 vraiu_match, vraiu_attach, NULL, NULL);
91
92 struct audio_device aiu_device = {
93 "VR4121 AIU",
94 "0.1",
95 "aiu"
96 };
97
98 /*
99 * Define our interface to the higher level audio driver.
100 */
101 int vraiu_open(void *, int);
102 void vraiu_close(void *);
103 int vraiu_query_encoding(void *, struct audio_encoding *);
104 int vraiu_round_blocksize(void *, int);
105 int vraiu_commit_settings(void *);
106 int vraiu_init_output(void *, void*, int);
107 int vraiu_start_output(void *, void *, int, void (*)(void *), void *);
108 int vraiu_start_input(void *, void *, int, void (*)(void *), void *);
109 int vraiu_halt_output(void *);
110 int vraiu_halt_input(void *);
111 int vraiu_getdev(void *, struct audio_device *);
112 int vraiu_set_port(void *, mixer_ctrl_t *);
113 int vraiu_get_port(void *, mixer_ctrl_t *);
114 int vraiu_query_devinfo(void *, mixer_devinfo_t *);
115 int vraiu_set_params(void *, int, int, struct audio_params *,
116 struct audio_params *);
117 int vraiu_get_props(void *);
118
119 struct audio_hw_if vraiu_hw_if = {
120 vraiu_open,
121 vraiu_close,
122 NULL,
123 vraiu_query_encoding,
124 vraiu_set_params,
125 vraiu_round_blocksize,
126 vraiu_commit_settings,
127 vraiu_init_output,
128 NULL,
129 vraiu_start_output,
130 vraiu_start_input,
131 vraiu_halt_output,
132 vraiu_halt_input,
133 NULL,
134 vraiu_getdev,
135 NULL,
136 vraiu_set_port,
137 vraiu_get_port,
138 vraiu_query_devinfo,
139 NULL,
140 NULL,
141 NULL,
142 NULL,
143 vraiu_get_props,
144 };
145
146 /*
147 * convert to 1ch 10bit unsigned PCM data.
148 */
149 static void vraiu_slinear8_1(struct vraiu_softc *, u_short *, void *, int);
150 static void vraiu_slinear8_2(struct vraiu_softc *, u_short *, void *, int);
151 static void vraiu_ulinear8_1(struct vraiu_softc *, u_short *, void *, int);
152 static void vraiu_ulinear8_2(struct vraiu_softc *, u_short *, void *, int);
153 static void vraiu_mulaw_1(struct vraiu_softc *, u_short *, void *, int);
154 static void vraiu_mulaw_2(struct vraiu_softc *, u_short *, void *, int);
155 static void vraiu_slinear16_1(struct vraiu_softc *, u_short *, void *, int);
156 static void vraiu_slinear16_2(struct vraiu_softc *, u_short *, void *, int);
157 static void vraiu_slinear16sw_1(struct vraiu_softc *, u_short *, void *, int);
158 static void vraiu_slinear16sw_2(struct vraiu_softc *, u_short *, void *, int);
159
160 int
161 vraiu_match(struct device *parent, struct cfdata *cf, void *aux)
162 {
163 return 1;
164 }
165
166 void
167 vraiu_attach(struct device *parent, struct device *self, void *aux)
168 {
169 struct vrip_attach_args *va = aux;
170 struct vraiu_softc *sc = (void*)self;
171 bus_dma_segment_t segs;
172 int rsegs;
173
174 sc->sc_status = ENXIO;
175 sc->sc_intr = NULL;
176 sc->sc_iot = va->va_iot;
177 sc->sc_vrip = va->va_vc;
178 sc->sc_cc = va->va_cc;
179 sc->sc_dc = va->va_dc;
180 sc->sc_ac = va->va_ac;
181 sc->sc_dmat = &vrdcu_bus_dma_tag;
182
183 if (!sc->sc_cc) {
184 printf(" not configured: cmu not found\n");
185 return;
186 }
187 if (!sc->sc_dc) {
188 printf(" not configured: dcu not found\n");
189 return;
190 }
191 if (!sc->sc_ac) {
192 printf(" not configured: dmaau not found\n");
193 return;
194 }
195 if (bus_space_map(sc->sc_iot, va->va_addr, va->va_size,
196 0 /* no flags */, &sc->sc_ioh)) {
197 printf(": can't map i/o space\n");
198 return;
199 }
200
201 /* install interrupt handler and enable interrupt */
202 if (!(sc->sc_handler = vrip_intr_establish(va->va_vc, va->va_unit,
203 0, IPL_AUDIO,
204 vraiu_intr, sc))) {
205 printf(": can't map interrupt line.\n");
206 return;
207 }
208 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, (AIUINT_INTMEND | \
209 AIUINT_INTM | \
210 AIUINT_INTMIDLE | \
211 AIUINT_INTMST | \
212 AIUINT_INTSEND | \
213 AIUINT_INTS | \
214 AIUINT_INTSIDLE), 0);
215
216 if (bus_dmamem_alloc(sc->sc_dmat, AUDIO_BUF_SIZE, 0, 0, &segs, 1,
217 &rsegs, BUS_DMA_NOWAIT)) {
218 printf(": can't allocate memory.\n");
219 return;
220 }
221 if (bus_dmamem_map(sc->sc_dmat, &segs, rsegs, AUDIO_BUF_SIZE,
222 (caddr_t *)&sc->sc_buf,
223 BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) {
224 printf(": can't map memory.\n");
225 bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
226 return;
227 }
228 if (bus_dmamap_create(sc->sc_dmat, AUDIO_BUF_SIZE, 1, AUDIO_BUF_SIZE,
229 0, BUS_DMA_NOWAIT, &sc->sc_dmap)) {
230 printf(": can't create DMA map.\n");
231 bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_buf,
232 AUDIO_BUF_SIZE);
233 bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
234 return;
235 }
236 if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmap, sc->sc_buf,
237 AUDIO_BUF_SIZE, NULL, BUS_DMA_NOWAIT)) {
238 printf(": can't load DMA map.\n");
239 bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmap);
240 bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_buf,
241 AUDIO_BUF_SIZE);
242 bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
243 return;
244 }
245 if (sc->sc_ac->ac_set_aiuout(sc->sc_ac, sc->sc_buf)) {
246 printf(": can't set DMA address.\n");
247 bus_dmamap_unload(sc->sc_dmat, sc->sc_dmap);
248 bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmap);
249 bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_buf,
250 AUDIO_BUF_SIZE);
251 bus_dmamem_free(sc->sc_dmat, &segs, rsegs);
252 return;
253 }
254 printf("\n");
255
256 sc->sc_status = 0;
257 sc->sc_rate = SPS8000;
258 sc->sc_channels = 1;
259 sc->sc_precision = 8;
260 sc->sc_encoding = AUDIO_ENCODING_ULAW;
261 sc->sc_decodefunc = vraiu_mulaw_1;
262 DPRINTFN(1, ("vraiu_attach: reset AIU\n"))
263 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, AIURST);
264 /* attach audio subsystem */
265 audio_attach_mi(&vraiu_hw_if, sc, &sc->sc_dev);
266 }
267
268 int
269 vraiu_open(void *self, int flags)
270 {
271 struct vraiu_softc *sc = (void*)self;
272
273 DPRINTFN(1, ("vraiu_open\n"));
274
275 if (sc->sc_status) {
276 DPRINTFN(0, ("vraiu_open: device error\n"));
277 return sc->sc_status;
278 }
279 sc->sc_status = EBUSY;
280 return 0;
281 }
282
283 void
284 vraiu_close(void *self)
285 {
286 struct vraiu_softc *sc = (void*)self;
287
288 DPRINTFN(1, ("vraiu_close\n"));
289
290 vraiu_halt_output(self);
291 sc->sc_status = 0;
292 }
293
294 int
295 vraiu_query_encoding(void *self, struct audio_encoding *ae)
296 {
297 DPRINTFN(3, ("vraiu_query_encoding\n"));
298
299 switch (ae->index) {
300 case 0:
301 strcpy(ae->name, AudioEslinear);
302 ae->encoding = AUDIO_ENCODING_SLINEAR;
303 ae->precision = 8;
304 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
305 break;
306 case 1:
307 strcpy(ae->name, AudioEmulaw);
308 ae->encoding = AUDIO_ENCODING_ULAW;
309 ae->precision = 8;
310 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
311 break;
312 case 2:
313 strcpy(ae->name, AudioEulinear);
314 ae->encoding = AUDIO_ENCODING_ULINEAR;
315 ae->precision = 8;
316 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
317 break;
318 case 3:
319 strcpy(ae->name, AudioEslinear);
320 ae->encoding = AUDIO_ENCODING_SLINEAR;
321 ae->precision = 16;
322 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
323 break;
324 case 4:
325 strcpy(ae->name, AudioEslinear_be);
326 ae->encoding = AUDIO_ENCODING_SLINEAR_BE;
327 ae->precision = 16;
328 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
329 break;
330 case 5:
331 strcpy(ae->name, AudioEslinear_le);
332 ae->encoding = AUDIO_ENCODING_SLINEAR_LE;
333 ae->precision = 16;
334 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
335 break;
336 case 6:
337 strcpy(ae->name, AudioEslinear);
338 ae->encoding = AUDIO_ENCODING_ULINEAR;
339 ae->precision = 16;
340 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
341 break;
342 case 7:
343 strcpy(ae->name, AudioEslinear_be);
344 ae->encoding = AUDIO_ENCODING_ULINEAR_BE;
345 ae->precision = 16;
346 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
347 break;
348 case 8:
349 strcpy(ae->name, AudioEslinear_le);
350 ae->encoding = AUDIO_ENCODING_ULINEAR_LE;
351 ae->precision = 16;
352 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
353 break;
354 default:
355 DPRINTFN(0, ("vraiu_query_encoding: param error"
356 " (%d)\n", ae->index));
357 return EINVAL;
358 }
359 return 0;
360 }
361
362 int
363 vraiu_set_params(void *self, int setmode, int usemode,
364 struct audio_params *play, struct audio_params *rec)
365 {
366 struct vraiu_softc *sc = (void*)self;
367
368 DPRINTFN(1, ("vraiu_set_params: %dbit, %dch, %ldHz, encoding %d\n",
369 play->precision, play->channels, play->sample_rate,
370 play->encoding));
371
372 switch (play->sample_rate) {
373 case 8000:
374 sc->sc_rate = SPS8000;
375 break;
376 case 11025:
377 sc->sc_rate = SPS11025;
378 break;
379 case 22050:
380 sc->sc_rate = SPS22050;
381 break;
382 case 44100:
383 sc->sc_rate = SPS44100;
384 break;
385 default:
386 DPRINTFN(0, ("vraiu_set_params: rate error (%ld)\n",
387 play->sample_rate));
388 return EINVAL;
389 }
390
391 switch (play->precision) {
392 case 8:
393 switch (play->encoding) {
394 case AUDIO_ENCODING_ULAW:
395 switch (play->channels) {
396 case 1:
397 sc->sc_decodefunc = vraiu_mulaw_1;
398 break;
399 case 2:
400 sc->sc_decodefunc = vraiu_mulaw_2;
401 break;
402 default:
403 DPRINTFN(0, ("vraiu_set_params: channel error"
404 " (%d)\n", play->channels));
405 return EINVAL;
406 }
407 break;
408 case AUDIO_ENCODING_SLINEAR:
409 case AUDIO_ENCODING_SLINEAR_BE:
410 case AUDIO_ENCODING_SLINEAR_LE:
411 switch (play->channels) {
412 case 1:
413 sc->sc_decodefunc = vraiu_slinear8_1;
414 break;
415 case 2:
416 sc->sc_decodefunc = vraiu_slinear8_2;
417 break;
418 default:
419 DPRINTFN(0, ("vraiu_set_params: channel error"
420 " (%d)\n", play->channels));
421 return EINVAL;
422 }
423 break;
424 case AUDIO_ENCODING_ULINEAR:
425 case AUDIO_ENCODING_ULINEAR_BE:
426 case AUDIO_ENCODING_ULINEAR_LE:
427 switch (play->channels) {
428 case 1:
429 sc->sc_decodefunc = vraiu_ulinear8_1;
430 break;
431 case 2:
432 sc->sc_decodefunc = vraiu_ulinear8_2;
433 break;
434 default:
435 DPRINTFN(0, ("vraiu_set_params: channel error"
436 " (%d)\n", play->channels));
437 return EINVAL;
438 }
439 break;
440 default:
441 DPRINTFN(0, ("vraiu_set_params: encoding error"
442 " (%d)\n", play->encoding));
443 return EINVAL;
444 }
445 break;
446 case 16:
447 switch (play->encoding) {
448 #if BYTE_ORDER == BIG_ENDIAN
449 case AUDIO_ENCODING_SLINEAR:
450 #endif
451 case AUDIO_ENCODING_SLINEAR_BE:
452 switch (play->channels) {
453 case 1:
454 #if BYTE_ORDER == BIG_ENDIAN
455 sc->sc_decodefunc = vraiu_slinear16_1;
456 #else
457 sc->sc_decodefunc = vraiu_slinear16sw_1;
458 #endif
459 break;
460 case 2:
461 #if BYTE_ORDER == BIG_ENDIAN
462 sc->sc_decodefunc = vraiu_slinear16_2;
463 #else
464 sc->sc_decodefunc = vraiu_slinear16sw_2;
465 #endif
466 break;
467 default:
468 DPRINTFN(0, ("vraiu_set_params: channel error"
469 " (%d)\n", play->channels));
470 return EINVAL;
471 }
472 break;
473 #if BYTE_ORDER == LITTLE_ENDIAN
474 case AUDIO_ENCODING_SLINEAR:
475 #endif
476 case AUDIO_ENCODING_SLINEAR_LE:
477 switch (play->channels) {
478 case 1:
479 #if BYTE_ORDER == LITTLE_ENDIAN
480 sc->sc_decodefunc = vraiu_slinear16_1;
481 #else
482 sc->sc_decodefunc = vraiu_slinear16sw_1;
483 #endif
484 break;
485 case 2:
486 #if BYTE_ORDER == LITTLE_ENDIAN
487 sc->sc_decodefunc = vraiu_slinear16_2;
488 #else
489 sc->sc_decodefunc = vraiu_slinear16sw_2;
490 #endif
491 break;
492 default:
493 DPRINTFN(0, ("vraiu_set_params: channel error"
494 " (%d)\n", play->channels));
495 return EINVAL;
496 }
497 break;
498 default:
499 DPRINTFN(0, ("vraiu_set_params: encoding error"
500 " (%d)\n", play->encoding));
501 return EINVAL;
502 }
503 break;
504 default:
505 DPRINTFN(0, ("vraiu_set_params: precision error (%d)\n",
506 play->precision));
507 return EINVAL;
508 }
509
510 sc->sc_encoding = play->encoding;
511 sc->sc_precision = play->precision;
512 sc->sc_channels = play->channels;
513 return 0;
514 }
515
516 int
517 vraiu_round_blocksize(void *self, int bs)
518 {
519 struct vraiu_softc *sc = (void*)self;
520 int n = AUDIO_BUF_SIZE;
521
522 if (sc->sc_precision == 8)
523 n /= 2;
524 n *= sc->sc_channels;
525
526 DPRINTFN(1, ("vraiu_round_blocksize: upper %d, lower %d\n",
527 bs, n));
528
529 return n;
530 }
531
532 int
533 vraiu_commit_settings(void *self)
534 {
535 struct vraiu_softc *sc = (void*)self;
536 int err;
537
538 DPRINTFN(1, ("vraiu_commit_settings\n"));
539
540 if (sc->sc_status != EBUSY)
541 return sc->sc_status;
542
543 DPRINTFN(1, ("vraiu_commit_settings: set conversion rate %d\n",
544 sc->sc_rate))
545 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNVR_REG_W, sc->sc_rate);
546 DPRINTFN(1, ("vraiu_commit_settings: clock supply start\n"))
547 if ((err = sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 1))) {
548 DPRINTFN(0, ("vraiu_commit_settings: clock supply error\n"));
549 return err;
550 }
551 DPRINTFN(1, ("vraiu_commit_settings: enable DMA\n"))
552 if ((err = sc->sc_dc->dc_enable_aiuout(sc->sc_dc))) {
553 sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 0);
554 DPRINTFN(0, ("vraiu_commit_settings: enable DMA error\n"));
555 return err;
556 }
557 DPRINTFN(1, ("vraiu_commit_settings: Vref on\n"))
558 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNT_REG_W, DAENAIU);
559 return 0;
560 }
561
562 int
563 vraiu_init_output(void *self, void *buffer, int size)
564 {
565 struct vraiu_softc *sc = (void*)self;
566
567 DPRINTFN(1, ("vraiu_init_output: buffer %p, size %d\n", buffer, size));
568
569 sc->sc_intr = NULL;
570 DPRINTFN(1, ("vraiu_init_output: speaker power on\n"))
571 config_hook_call(CONFIG_HOOK_POWERCONTROL,
572 CONFIG_HOOK_POWERCONTROL_SPEAKER, (void*)1);
573 DPRINTFN(1, ("vraiu_init_output: start output\n"))
574 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, AIUSEN);
575 return 0;
576 }
577
578 int
579 vraiu_start_output(void *self, void *block, int bsize,
580 void (*intr)(void *), void *intrarg)
581 {
582 struct vraiu_softc *sc = (void*)self;
583
584 DPRINTFN(2, ("vraiu_start_output: block %p, bsize %d\n",
585 block, bsize));
586 sc->sc_decodefunc(sc, sc->sc_buf, block, bsize);
587 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, AUDIO_BUF_SIZE,
588 BUS_DMASYNC_PREWRITE);
589 sc->sc_intr = intr;
590 sc->sc_intrdata = intrarg;
591 /* clear interrupt status */
592 bus_space_write_2(sc->sc_iot, sc->sc_ioh, INT_REG_W,
593 SENDINTR | SINTR | SIDLEINTR);
594 /* enable interrupt */
595 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 1);
596 return 0;
597 }
598
599 int
600 vraiu_start_input(void *self, void *block, int bsize,
601 void (*intr)(void *), void *intrarg)
602 {
603 DPRINTFN(3, ("vraiu_start_input\n"));
604
605 /* no input */
606 return ENXIO;
607 }
608
609 int
610 vraiu_intr(void* self)
611 {
612 struct vraiu_softc *sc = (void*)self;
613 u_int32_t reg;
614
615 DPRINTFN(2, ("vraiu_intr"));
616
617 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 0);
618 vrip_intr_getstatus2(sc->sc_vrip, sc->sc_handler, ®);
619 if (reg & AIUINT_INTSEND) {
620 DPRINTFN(2, (": AIUINT_INTSEND"));
621 if (sc->sc_intr) {
622 void (*intr)(void *) = sc->sc_intr;
623 sc->sc_intr = NULL;
624 (*(intr))(sc->sc_intrdata);
625 }
626 bus_space_write_2(sc->sc_iot, sc->sc_ioh, INT_REG_W, SENDINTR);
627 }
628 DPRINTFN(2, ("\n"));
629 return 0;
630 }
631
632 int
633 vraiu_halt_output(void *self)
634 {
635 struct vraiu_softc *sc = (void*)self;
636
637 DPRINTFN(1, ("vraiu_halt_output\n"));
638
639 DPRINTFN(1, ("vraiu_halt_output: disable interrupt\n"))
640 vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, AIUINT_INTSEND, 0);
641 DPRINTFN(1, ("vraiu_halt_output: stop output\n"))
642 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SEQ_REG_W, 0);
643 DPRINTFN(1, ("vraiu_halt_output: speaker power off\n"))
644 config_hook_call(CONFIG_HOOK_POWERCONTROL,
645 CONFIG_HOOK_POWERCONTROL_SPEAKER, (void*)0);
646 DPRINTFN(1, ("vraiu_halt_output: Vref off\n"))
647 bus_space_write_2(sc->sc_iot, sc->sc_ioh, SCNT_REG_W, 0);
648 DPRINTFN(1, ("vraiu_halt_output: disable DMA\n"))
649 sc->sc_dc->dc_disable(sc->sc_dc);
650 DPRINTFN(1, ("vraiu_halt_output: clock supply stop\n"))
651 sc->sc_cc->cc_clock(sc->sc_cc, VR4102_CMUMSKAIU, 0);
652 sc->sc_intr = NULL;
653 return 0;
654 }
655
656 int
657 vraiu_halt_input(void *self)
658 {
659 DPRINTFN(3, ("vraiu_halt_input\n"));
660
661 /* no input */
662 return ENXIO;
663 }
664
665
666 int
667 vraiu_getdev(void *self, struct audio_device *ret)
668 {
669 DPRINTFN(3, ("vraiu_getdev\n"));
670
671 *ret = aiu_device;
672 return 0;
673 }
674
675 int
676 vraiu_set_port(void *self, mixer_ctrl_t *mc)
677 {
678 DPRINTFN(3, ("vraiu_set_port\n"));
679
680 /* no mixer */
681 return EINVAL;
682 }
683
684 int
685 vraiu_get_port(void *self, mixer_ctrl_t *mc)
686 {
687 DPRINTFN(3, ("vraiu_get_port\n"));
688
689 /* no mixer */
690 return EINVAL;
691 }
692
693 int
694 vraiu_query_devinfo(void *self, mixer_devinfo_t *di)
695 {
696 DPRINTFN(3, ("vraiu_query_devinfo\n"));
697
698 /* no mixer */
699 return ENXIO;
700 }
701
702 int
703 vraiu_get_props(void *self)
704 {
705 DPRINTFN(3, ("vraiu_get_props\n"));
706
707 return 0;
708 }
709
710 unsigned char mulaw_to_lin[] = {
711 0x02, 0x06, 0x0a, 0x0e, 0x12, 0x16, 0x1a, 0x1e,
712 0x22, 0x26, 0x2a, 0x2e, 0x32, 0x36, 0x3a, 0x3e,
713 0x41, 0x43, 0x45, 0x47, 0x49, 0x4b, 0x4d, 0x4f,
714 0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f,
715 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
716 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
717 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x74,
718 0x74, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x78,
719 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, 0x7a, 0x7a,
720 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c,
721 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d,
722 0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e,
723 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e,
724 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
725 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
726 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80,
727 0xfd, 0xf9, 0xf5, 0xf1, 0xed, 0xe9, 0xe5, 0xe1,
728 0xdd, 0xd9, 0xd5, 0xd1, 0xcd, 0xc9, 0xc5, 0xc1,
729 0xbe, 0xbc, 0xba, 0xb8, 0xb6, 0xb4, 0xb2, 0xb0,
730 0xae, 0xac, 0xaa, 0xa8, 0xa6, 0xa4, 0xa2, 0xa0,
731 0x9e, 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97,
732 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f,
733 0x8f, 0x8e, 0x8e, 0x8d, 0x8d, 0x8c, 0x8c, 0x8b,
734 0x8b, 0x8a, 0x8a, 0x89, 0x89, 0x88, 0x88, 0x87,
735 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x85, 0x85,
736 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, 0x83, 0x83,
737 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82,
738 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x81,
739 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
740 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
741 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
742 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
743 };
744
745 static void
746 vraiu_slinear8_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
747 {
748 char *q = (char*)p;
749
750 DPRINTFN(3, ("vraiu_slinear8_1\n"));
751
752 #ifdef DIAGNOSTIC
753 if (n > AUDIO_BUF_SIZE/2) {
754 printf("%s: output data too large (%d > %d)\n",
755 sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE/2);
756 n = AUDIO_BUF_SIZE/2;
757 }
758 #endif
759 while (n--) {
760 short i = *q++;
761 *dmap++ = (i << 2) + 0x200;
762 }
763 }
764
765 static void
766 vraiu_slinear8_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
767 {
768 char *q = (char*)p;
769
770 DPRINTFN(3, ("vraiu_slinear8_2\n"));
771
772 #ifdef DIAGNOSTIC
773 if (n > AUDIO_BUF_SIZE) {
774 printf("%s: output data too large (%d > %d)\n",
775 sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE);
776 n = AUDIO_BUF_SIZE;
777 }
778 #endif
779 n /= 2;
780 while (n--) {
781 short i = *q++;
782 short j = *q++;
783 *dmap++ = ((i + j) << 1) + 0x200;
784 }
785 }
786
787 static void
788 vraiu_ulinear8_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
789 {
790 u_char *q = (u_char*)p;
791
792 DPRINTFN(3, ("vraiu_ulinear8_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;
804 }
805 }
806
807 static void
808 vraiu_ulinear8_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
809 {
810 u_char *q = (u_char*)p;
811
812 DPRINTFN(3, ("vraiu_ulinear8_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;
826 }
827 }
828
829 static void
830 vraiu_mulaw_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_mulaw_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 = mulaw_to_lin[*q++];
845 *dmap++ = i << 2;
846 }
847 }
848
849 static void
850 vraiu_mulaw_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_mulaw_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 = mulaw_to_lin[*q++];
866 short j = mulaw_to_lin[*q++];
867 *dmap++ = (i + j) << 1;
868 }
869 }
870
871 static void
872 vraiu_slinear16_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
873 {
874 short *q = (short*)p;
875
876 DPRINTFN(3, ("vraiu_slinear16_1\n"));
877
878 #ifdef DIAGNOSTIC
879 if (n > AUDIO_BUF_SIZE) {
880 printf("%s: output data too large (%d > %d)\n",
881 sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE);
882 n = AUDIO_BUF_SIZE;
883 }
884 #endif
885 n /= 2;
886 while (n--) {
887 short i = *q++;
888 *dmap++ = (i >> 6) + 0x200;
889 }
890 }
891
892 static void
893 vraiu_slinear16_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
894 {
895 short *q = (short*)p;
896
897 DPRINTFN(3, ("vraiu_slinear16_2\n"));
898
899 #ifdef DIAGNOSTIC
900 if (n > AUDIO_BUF_SIZE*2) {
901 printf("%s: output data too large (%d > %d)\n",
902 sc->sc_dev.dv_xname, n, AUDIO_BUF_SIZE*2);
903 n = AUDIO_BUF_SIZE*2;
904 }
905 #endif
906 n /= 4;
907 while (n--) {
908 short i = *q++;
909 short j = *q++;
910 *dmap++ = (i >> 7) + (j >> 7) + 0x200;
911 }
912 }
913
914 static void
915 vraiu_slinear16sw_1(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
916 {
917 short *q = (short*)p;
918
919 DPRINTFN(3, ("vraiu_slinear16sw_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 = bswap16(*q++);
931 *dmap++ = (i >> 6) + 0x200;
932 }
933 }
934
935 static void
936 vraiu_slinear16sw_2(struct vraiu_softc *sc, u_short *dmap, void *p, int n)
937 {
938 short *q = (short*)p;
939
940 DPRINTFN(3, ("vraiu_slinear16sw_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 = bswap16(*q++);
952 short j = bswap16(*q++);
953 *dmap++ = (i >> 7) + (j >> 7) + 0x200;
954 }
955 }
956