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