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