awacs.c revision 1.3.2.3 1 /* $NetBSD: awacs.c,v 1.3.2.3 2001/02/26 22:33:15 he Exp $ */
2
3 /*-
4 * Copyright (c) 2000 Tsubai Masanari. 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 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/param.h>
30 #include <sys/audioio.h>
31 #include <sys/device.h>
32 #include <sys/malloc.h>
33 #include <sys/systm.h>
34
35 #include <dev/auconv.h>
36 #include <dev/audio_if.h>
37 #include <dev/mulaw.h>
38
39 #include <vm/vm.h>
40 #include <uvm/uvm_extern.h>
41
42 #include <machine/autoconf.h>
43 #include <machine/pio.h>
44 #include <macppc/dev/dbdma.h>
45
46 #ifdef AWACS_DEBUG
47 # define DPRINTF printf
48 #else
49 # define DPRINTF while (0) printf
50 #endif
51
52 struct awacs_softc {
53 struct device sc_dev;
54
55 void (*sc_ointr)(void *); /* dma completion intr handler */
56 void *sc_oarg; /* arg for sc_ointr() */
57 int sc_opages; /* # of output pages */
58
59 void (*sc_iintr)(void *); /* dma completion intr handler */
60 void *sc_iarg; /* arg for sc_iintr() */
61
62 u_int sc_record_source; /* recording source mask */
63 u_int sc_output_mask; /* output source mask */
64
65 char *sc_reg;
66 u_int sc_codecctl0;
67 u_int sc_codecctl1;
68 u_int sc_codecctl2;
69 u_int sc_codecctl4;
70 u_int sc_soundctl;
71
72 struct dbdma_regmap *sc_odma;
73 struct dbdma_regmap *sc_idma;
74 struct dbdma_command *sc_odmacmd;
75 struct dbdma_command *sc_idmacmd;
76 };
77
78 int awacs_match(struct device *, struct cfdata *, void *);
79 void awacs_attach(struct device *, struct device *, void *);
80 int awacs_intr(void *);
81
82 int awacs_open(void *, int);
83 void awacs_close(void *);
84 int awacs_query_encoding(void *, struct audio_encoding *);
85 int awacs_set_params(void *, int, int, struct audio_params *,
86 struct audio_params *);
87 int awacs_round_blocksize(void *, int);
88 int awacs_trigger_output(void *, void *, void *, int, void (*)(void *),
89 void *, struct audio_params *);
90 int awacs_trigger_input(void *, void *, void *, int, void (*)(void *),
91 void *, struct audio_params *);
92 int awacs_halt_output(void *);
93 int awacs_halt_input(void *);
94 int awacs_getdev(void *, struct audio_device *);
95 int awacs_set_port(void *, mixer_ctrl_t *);
96 int awacs_get_port(void *, mixer_ctrl_t *);
97 int awacs_query_devinfo(void *, mixer_devinfo_t *);
98 size_t awacs_round_buffersize(void *, int, size_t);
99 paddr_t awacs_mappage(void *, void *, off_t, int);
100 int awacs_get_props(void *);
101
102 static inline u_int awacs_read_reg(struct awacs_softc *, int);
103 static inline void awacs_write_reg(struct awacs_softc *, int, int);
104 void awacs_write_codec(struct awacs_softc *, int);
105 void awacs_set_speaker_volume(struct awacs_softc *, int, int);
106 void awacs_set_ext_volume(struct awacs_softc *, int, int);
107 int awacs_set_rate(struct awacs_softc *, int);
108
109 struct cfattach awacs_ca = {
110 sizeof(struct awacs_softc), awacs_match, awacs_attach
111 };
112
113 struct audio_hw_if awacs_hw_if = {
114 awacs_open,
115 awacs_close,
116 NULL,
117 awacs_query_encoding,
118 awacs_set_params,
119 awacs_round_blocksize,
120 NULL,
121 NULL,
122 NULL,
123 NULL,
124 NULL,
125 awacs_halt_output,
126 awacs_halt_input,
127 NULL,
128 awacs_getdev,
129 NULL,
130 awacs_set_port,
131 awacs_get_port,
132 awacs_query_devinfo,
133 NULL,
134 NULL,
135 awacs_round_buffersize,
136 awacs_mappage,
137 awacs_get_props,
138 awacs_trigger_output,
139 awacs_trigger_input,
140 };
141
142 struct audio_device awacs_device = {
143 "AWACS",
144 "",
145 "awacs"
146 };
147
148 /* register offset */
149 #define AWACS_SOUND_CTRL 0x00
150 #define AWACS_CODEC_CTRL 0x10
151 #define AWACS_CODEC_STATUS 0x20
152 #define AWACS_CLIP_COUNT 0x30
153 #define AWACS_BYTE_SWAP 0x40
154
155 /* sound control */
156 #define AWACS_INPUT_SUBFRAME0 0x00000001
157 #define AWACS_INPUT_SUBFRAME1 0x00000002
158 #define AWACS_INPUT_SUBFRAME2 0x00000004
159 #define AWACS_INPUT_SUBFRAME3 0x00000008
160
161 #define AWACS_OUTPUT_SUBFRAME0 0x00000010
162 #define AWACS_OUTPUT_SUBFRAME1 0x00000020
163 #define AWACS_OUTPUT_SUBFRAME2 0x00000040
164 #define AWACS_OUTPUT_SUBFRAME3 0x00000080
165
166 #define AWACS_RATE_44100 0x00000000
167 #define AWACS_RATE_29400 0x00000100
168 #define AWACS_RATE_22050 0x00000200
169 #define AWACS_RATE_17640 0x00000300
170 #define AWACS_RATE_14700 0x00000400
171 #define AWACS_RATE_11025 0x00000500
172 #define AWACS_RATE_8820 0x00000600
173 #define AWACS_RATE_7350 0x00000700
174 #define AWACS_RATE_MASK 0x00000700
175
176 /* codec control */
177 #define AWACS_CODEC_ADDR0 0x00000000
178 #define AWACS_CODEC_ADDR1 0x00001000
179 #define AWACS_CODEC_ADDR2 0x00002000
180 #define AWACS_CODEC_ADDR4 0x00004000
181 #define AWACS_CODEC_EMSEL0 0x00000000
182 #define AWACS_CODEC_EMSEL1 0x00400000
183 #define AWACS_CODEC_EMSEL2 0x00800000
184 #define AWACS_CODEC_EMSEL4 0x00c00000
185 #define AWACS_CODEC_BUSY 0x01000000
186
187 /* cc0 */
188 #define AWACS_DEFAULT_CD_GAIN 0x000000bb
189 #define AWACS_INPUT_CD 0x00000200
190 #define AWACS_INPUT_MIC 0x00000400
191 #define AWACS_INPUT_MASK 0x00000e00
192
193 /* cc1 */
194 #define AWACS_MUTE_SPEAKER 0x00000080
195 #define AWACS_MUTE_HEADPHONE 0x00000200
196
197 int
198 awacs_match(parent, match, aux)
199 struct device *parent;
200 struct cfdata *match;
201 void *aux;
202 {
203 struct confargs *ca = aux;
204
205 if (strcmp(ca->ca_name, "awacs") != 0 &&
206 strcmp(ca->ca_name, "davbus") != 0)
207 return 0;
208
209 if (ca->ca_nreg < 24 || ca->ca_nintr < 12)
210 return 0;
211
212 return 1;
213 }
214
215 void
216 awacs_attach(parent, self, aux)
217 struct device *parent;
218 struct device *self;
219 void *aux;
220 {
221 struct awacs_softc *sc = (struct awacs_softc *)self;
222 struct confargs *ca = aux;
223
224 ca->ca_reg[0] += ca->ca_baseaddr;
225 ca->ca_reg[2] += ca->ca_baseaddr;
226 ca->ca_reg[4] += ca->ca_baseaddr;
227
228 sc->sc_reg = mapiodev(ca->ca_reg[0], ca->ca_reg[1]);
229
230 sc->sc_odma = mapiodev(ca->ca_reg[2], ca->ca_reg[3]); /* out */
231 sc->sc_idma = mapiodev(ca->ca_reg[4], ca->ca_reg[5]); /* in */
232 sc->sc_odmacmd = dbdma_alloc(20 * sizeof(struct dbdma_command));
233 sc->sc_idmacmd = dbdma_alloc(20 * sizeof(struct dbdma_command));
234
235 intr_establish(ca->ca_intr[0], IST_LEVEL, IPL_AUDIO, awacs_intr, sc);
236 intr_establish(ca->ca_intr[1], IST_LEVEL, IPL_AUDIO, awacs_intr, sc);
237 intr_establish(ca->ca_intr[2], IST_LEVEL, IPL_AUDIO, awacs_intr, sc);
238
239 printf(": irq %d,%d,%d\n",
240 ca->ca_intr[0], ca->ca_intr[1], ca->ca_intr[2]);
241
242 sc->sc_soundctl = AWACS_INPUT_SUBFRAME0 | AWACS_OUTPUT_SUBFRAME0 |
243 AWACS_RATE_44100;
244 awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl);
245
246 sc->sc_codecctl0 = AWACS_CODEC_ADDR0 | AWACS_CODEC_EMSEL0;
247 sc->sc_codecctl1 = AWACS_CODEC_ADDR1 | AWACS_CODEC_EMSEL0;
248 sc->sc_codecctl2 = AWACS_CODEC_ADDR2 | AWACS_CODEC_EMSEL0;
249 sc->sc_codecctl4 = AWACS_CODEC_ADDR4 | AWACS_CODEC_EMSEL0;
250
251 sc->sc_codecctl0 |= AWACS_INPUT_CD | AWACS_DEFAULT_CD_GAIN;
252 awacs_write_codec(sc, sc->sc_codecctl0);
253
254 /* Set initial volume[s] */
255 awacs_set_speaker_volume(sc, 80, 80);
256
257 /* Set loopback (for CD?) */
258 sc->sc_codecctl1 |= 0x440;
259 awacs_write_codec(sc, sc->sc_codecctl1);
260
261 sc->sc_output_mask = 1 << 0;
262
263 sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER;
264 sc->sc_codecctl1 |= AWACS_MUTE_HEADPHONE;
265 awacs_write_codec(sc, sc->sc_codecctl1);
266
267 /* Enable interrupts and looping mode. */
268 /* XXX ... */
269
270 audio_attach_mi(&awacs_hw_if, sc, &sc->sc_dev);
271 }
272
273 u_int
274 awacs_read_reg(sc, reg)
275 struct awacs_softc *sc;
276 int reg;
277 {
278 char *addr = sc->sc_reg;
279
280 return in32rb(addr + reg);
281 }
282
283 void
284 awacs_write_reg(sc, reg, val)
285 struct awacs_softc *sc;
286 int reg, val;
287 {
288 char *addr = sc->sc_reg;
289
290 out32rb(addr + reg, val);
291 }
292
293 void
294 awacs_write_codec(sc, value)
295 struct awacs_softc *sc;
296 int value;
297 {
298 awacs_write_reg(sc, AWACS_CODEC_CTRL, value);
299 while (awacs_read_reg(sc, AWACS_CODEC_CTRL) & AWACS_CODEC_BUSY);
300 }
301
302 int
303 awacs_intr(v)
304 void *v;
305 {
306 struct awacs_softc *sc = v;
307 struct dbdma_command *cmd = sc->sc_odmacmd;
308 int count = sc->sc_opages;
309 int status;
310
311 /* Fill used buffer(s). */
312 while (count-- > 0) {
313 /* if DBDMA_INT_ALWAYS */
314 if (in16rb(&cmd->d_command) & 0x30) { /* XXX */
315 status = in16rb(&cmd->d_status);
316 cmd->d_status = 0;
317 if (status) /* status == 0x8400 */
318 if (sc->sc_ointr)
319 (*sc->sc_ointr)(sc->sc_oarg);
320 }
321 cmd++;
322 }
323
324 return 1;
325 }
326
327 int
328 awacs_open(h, flags)
329 void *h;
330 int flags;
331 {
332 return 0;
333 }
334
335 /*
336 * Close function is called at splaudio().
337 */
338 void
339 awacs_close(h)
340 void *h;
341 {
342 struct awacs_softc *sc = h;
343
344 awacs_halt_output(sc);
345 awacs_halt_input(sc);
346
347 sc->sc_ointr = 0;
348 sc->sc_iintr = 0;
349 }
350
351 int
352 awacs_query_encoding(h, ae)
353 void *h;
354 struct audio_encoding *ae;
355 {
356 switch (ae->index) {
357 case 0:
358 strcpy(ae->name, AudioEslinear);
359 ae->encoding = AUDIO_ENCODING_SLINEAR;
360 ae->precision = 16;
361 ae->flags = 0;
362 return 0;
363 case 1:
364 strcpy(ae->name, AudioEslinear_be);
365 ae->encoding = AUDIO_ENCODING_SLINEAR_BE;
366 ae->precision = 16;
367 ae->flags = 0;
368 return 0;
369 case 2:
370 strcpy(ae->name, AudioEslinear_le);
371 ae->encoding = AUDIO_ENCODING_SLINEAR_LE;
372 ae->precision = 16;
373 ae->flags = 0;
374 return 0;
375 case 3:
376 strcpy(ae->name, AudioEmulaw);
377 ae->encoding = AUDIO_ENCODING_ULAW;
378 ae->precision = 8;
379 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
380 return 0;
381 case 4:
382 strcpy(ae->name, AudioEalaw);
383 ae->encoding = AUDIO_ENCODING_ALAW;
384 ae->precision = 8;
385 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
386 return 0;
387 default:
388 return EINVAL;
389 }
390 }
391
392 static void
393 mono16_to_stereo16(v, p, cc)
394 void *v;
395 u_char *p;
396 int cc;
397 {
398 int x;
399 int16_t *src, *dst;
400
401 src = (void *)(p + cc);
402 dst = (void *)(p + cc * 2);
403 while (cc > 0) {
404 x = *--src;
405 *--dst = x;
406 *--dst = x;
407 cc -= 2;
408 }
409 }
410
411 int
412 awacs_set_params(h, setmode, usemode, play, rec)
413 void *h;
414 int setmode, usemode;
415 struct audio_params *play, *rec;
416 {
417 struct awacs_softc *sc = h;
418 struct audio_params *p;
419 int mode, rate;
420
421 /*
422 * This device only has one clock, so make the sample rates match.
423 */
424 if (play->sample_rate != rec->sample_rate &&
425 usemode == (AUMODE_PLAY | AUMODE_RECORD)) {
426 if (setmode == AUMODE_PLAY) {
427 rec->sample_rate = play->sample_rate;
428 setmode |= AUMODE_RECORD;
429 } else if (setmode == AUMODE_RECORD) {
430 play->sample_rate = rec->sample_rate;
431 setmode |= AUMODE_PLAY;
432 } else
433 return EINVAL;
434 }
435
436 for (mode = AUMODE_RECORD; mode != -1;
437 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
438 if ((setmode & mode) == 0)
439 continue;
440
441 p = mode == AUMODE_PLAY ? play : rec;
442
443 if (p->sample_rate < 4000 || p->sample_rate > 50000 ||
444 (p->precision != 8 && p->precision != 16) ||
445 (p->channels != 1 && p->channels != 2))
446 return EINVAL;
447
448 p->factor = 1;
449 p->sw_code = 0;
450 awacs_write_reg(sc, AWACS_BYTE_SWAP, 0);
451
452 switch (p->encoding) {
453
454 case AUDIO_ENCODING_SLINEAR_LE:
455 awacs_write_reg(sc, AWACS_BYTE_SWAP, 1);
456 case AUDIO_ENCODING_SLINEAR_BE:
457 if (p->channels == 1) {
458 p->factor = 2;
459 p->sw_code = mono16_to_stereo16;
460 break;
461 }
462 if (p->precision != 16)
463 return EINVAL;
464 /* p->sw_code = change_sign8; */
465 break;
466
467 case AUDIO_ENCODING_ULINEAR_LE:
468 awacs_write_reg(sc, AWACS_BYTE_SWAP, 1);
469 case AUDIO_ENCODING_ULINEAR_BE:
470 if (p->precision == 16)
471 p->sw_code = change_sign16_be;
472 else
473 return EINVAL;
474 break;
475
476 case AUDIO_ENCODING_ULAW:
477 if (mode == AUMODE_PLAY) {
478 p->factor = 2;
479 p->sw_code = mulaw_to_slinear16_be;
480 } else
481 p->sw_code = ulinear8_to_mulaw;
482 break;
483
484 case AUDIO_ENCODING_ALAW:
485 if (mode == AUMODE_PLAY) {
486 p->factor = 2;
487 p->sw_code = alaw_to_slinear16_be;
488 } else
489 p->sw_code = ulinear8_to_alaw;
490 break;
491
492 default:
493 return EINVAL;
494 }
495 }
496
497 /* Set the speed */
498 rate = p->sample_rate;
499
500 awacs_set_rate(sc, rate);
501
502 return 0;
503 }
504
505 int
506 awacs_round_blocksize(h, size)
507 void *h;
508 int size;
509 {
510 return size & ~PGOFSET;
511 }
512
513 int
514 awacs_halt_output(h)
515 void *h;
516 {
517 struct awacs_softc *sc = h;
518
519 dbdma_stop(sc->sc_odma);
520 dbdma_reset(sc->sc_odma);
521 return 0;
522 }
523
524 int
525 awacs_halt_input(h)
526 void *h;
527 {
528 struct awacs_softc *sc = h;
529
530 dbdma_stop(sc->sc_idma);
531 dbdma_reset(sc->sc_idma);
532 return 0;
533 }
534
535 int
536 awacs_getdev(h, retp)
537 void *h;
538 struct audio_device *retp;
539 {
540 *retp = awacs_device;
541 return 0;
542 }
543
544 enum {
545 AWACS_OUTPUT_SELECT,
546 AWACS_VOL_SPEAKER,
547 AWACS_VOL_HEADPHONE,
548 AWACS_OUTPUT_CLASS,
549 AWACS_MONITOR_CLASS,
550 AWACS_ENUM_LAST
551 };
552
553 int
554 awacs_set_port(h, mc)
555 void *h;
556 mixer_ctrl_t *mc;
557 {
558 struct awacs_softc *sc = h;
559 int l, r;
560
561 DPRINTF("awacs_set_port dev = %d, type = %d\n", mc->dev, mc->type);
562
563 l = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
564 r = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
565
566 switch (mc->dev) {
567 case AWACS_OUTPUT_SELECT:
568 printf("output_select mask = 0x%x\n", mc->un.mask);
569 sc->sc_output_mask = mc->un.mask;
570 return 0;
571
572 case AWACS_VOL_SPEAKER:
573 awacs_set_speaker_volume(sc, l, r);
574 return 0;
575
576 case AWACS_VOL_HEADPHONE:
577 awacs_set_ext_volume(sc, l, r);
578 return 0;
579 }
580
581 return ENXIO;
582 }
583
584 int
585 awacs_get_port(h, mc)
586 void *h;
587 mixer_ctrl_t *mc;
588 {
589 struct awacs_softc *sc = h;
590 int vol, l, r;
591
592 DPRINTF("awacs_get_port dev = %d, type = %d\n", mc->dev, mc->type);
593
594 switch (mc->dev) {
595 case AWACS_OUTPUT_SELECT:
596 mc->un.mask = sc->sc_output_mask;
597 return 0;
598
599 case AWACS_VOL_SPEAKER:
600 vol = sc->sc_codecctl4;
601 l = (15 - ((vol & 0x3c0) >> 6)) * 16;
602 r = (15 - (vol & 0x0f)) * 16;
603 mc->un.mask = 1 << 0;
604 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
605 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
606 return 0;
607
608 case AWACS_VOL_HEADPHONE:
609 vol = sc->sc_codecctl2;
610 l = (15 - ((vol & 0x3c0) >> 6)) * 16;
611 r = (15 - (vol & 0x0f)) * 16;
612 mc->un.mask = 1 << 1;
613 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
614 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
615 return 0;
616
617 default:
618 return ENXIO;
619 }
620
621 return 0;
622 }
623
624 int
625 awacs_query_devinfo(h, dip)
626 void *h;
627 mixer_devinfo_t *dip;
628 {
629
630 DPRINTF("query_devinfo %d\n", dip->index);
631
632 switch (dip->index) {
633
634 case AWACS_OUTPUT_SELECT:
635 dip->mixer_class = AWACS_MONITOR_CLASS;
636 strcpy(dip->label.name, AudioNoutput);
637 dip->type = AUDIO_MIXER_SET;
638 dip->prev = dip->next = AUDIO_MIXER_LAST;
639 dip->un.s.num_mem = 2;
640 strcpy(dip->un.s.member[0].label.name, AudioNspeaker);
641 dip->un.s.member[0].mask = 1 << 0;
642 strcpy(dip->un.s.member[1].label.name, AudioNheadphone);
643 dip->un.s.member[1].mask = 1 << 1;
644 return 0;
645
646 case AWACS_VOL_SPEAKER:
647 dip->mixer_class = AWACS_OUTPUT_CLASS;
648 strcpy(dip->label.name, AudioNspeaker);
649 dip->type = AUDIO_MIXER_VALUE;
650 dip->prev = dip->next = AUDIO_MIXER_LAST;
651 dip->un.v.num_channels = 2;
652 strcpy(dip->un.v.units.name, AudioNvolume);
653 return 0;
654
655 case AWACS_VOL_HEADPHONE:
656 dip->mixer_class = AWACS_OUTPUT_CLASS;
657 strcpy(dip->label.name, AudioNheadphone);
658 dip->type = AUDIO_MIXER_VALUE;
659 dip->prev = dip->next = AUDIO_MIXER_LAST;
660 dip->un.v.num_channels = 2;
661 strcpy(dip->un.v.units.name, AudioNvolume);
662 return 0;
663
664 case AWACS_MONITOR_CLASS:
665 dip->mixer_class = AWACS_MONITOR_CLASS;
666 strcpy(dip->label.name, AudioCmonitor);
667 dip->type = AUDIO_MIXER_CLASS;
668 dip->next = dip->prev = AUDIO_MIXER_LAST;
669 return 0;
670
671 case AWACS_OUTPUT_CLASS:
672 dip->mixer_class = AWACS_OUTPUT_CLASS;
673 strcpy(dip->label.name, AudioCoutputs);
674 dip->type = AUDIO_MIXER_CLASS;
675 dip->next = dip->prev = AUDIO_MIXER_LAST;
676 return 0;
677 }
678
679 return ENXIO;
680 }
681
682 size_t
683 awacs_round_buffersize(h, dir, size)
684 void *h;
685 int dir;
686 size_t size;
687 {
688 if (size > 65536)
689 size = 65536;
690 return size;
691 }
692
693 paddr_t
694 awacs_mappage(h, mem, off, prot)
695 void *h;
696 void *mem;
697 off_t off;
698 int prot;
699 {
700 if (off < 0)
701 return -1;
702 return -1; /* XXX */
703 }
704
705 int
706 awacs_get_props(h)
707 void *h;
708 {
709 return AUDIO_PROP_FULLDUPLEX /* | AUDIO_PROP_MMAP */;
710 }
711
712 int
713 awacs_trigger_output(h, start, end, bsize, intr, arg, param)
714 void *h;
715 void *start, *end;
716 int bsize;
717 void (*intr)(void *);
718 void *arg;
719 struct audio_params *param;
720 {
721 struct awacs_softc *sc = h;
722 struct dbdma_command *cmd = sc->sc_odmacmd;
723 vaddr_t va;
724 int i, len, intmode;
725
726 DPRINTF("trigger_output %p %p 0x%x\n", start, end, bsize);
727
728 sc->sc_ointr = intr;
729 sc->sc_oarg = arg;
730 sc->sc_opages = ((char *)end - (char *)start) / NBPG;
731
732 #ifdef DIAGNOSTIC
733 if (sc->sc_opages > 16)
734 panic("awacs_trigger_output");
735 #endif
736
737 va = (vaddr_t)start;
738 len = 0;
739 for (i = sc->sc_opages; i > 0; i--) {
740 len += NBPG;
741 if (len < bsize)
742 intmode = DBDMA_INT_NEVER;
743 else {
744 len = 0;
745 intmode = DBDMA_INT_ALWAYS;
746 }
747
748 DBDMA_BUILD(cmd, DBDMA_CMD_OUT_MORE, 0, NBPG, vtophys(va),
749 intmode, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
750 va += NBPG;
751 cmd++;
752 }
753
754 DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0,
755 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS);
756 dbdma_st32(&cmd->d_cmddep, vtophys((vaddr_t)sc->sc_odmacmd));
757
758 dbdma_start(sc->sc_odma, sc->sc_odmacmd);
759
760 return 0;
761 }
762
763 int
764 awacs_trigger_input(h, start, end, bsize, intr, arg, param)
765 void *h;
766 void *start, *end;
767 int bsize;
768 void (*intr)(void *);
769 void *arg;
770 struct audio_params *param;
771 {
772 printf("awacs_trigger_input called\n");
773
774 return 1;
775 }
776
777 void
778 awacs_set_speaker_volume(sc, left, right)
779 struct awacs_softc *sc;
780 int left, right;
781 {
782 int lval = 15 - (left & 0xff) / 16;
783 int rval = 15 - (right & 0xff) / 16;
784
785 DPRINTF("speaker_volume %d %d\n", lval, rval);
786
787 sc->sc_codecctl4 &= ~0x3cf;
788 sc->sc_codecctl4 |= (lval << 6) | rval;
789 awacs_write_codec(sc, sc->sc_codecctl4);
790 }
791
792 void
793 awacs_set_ext_volume(sc, left, right)
794 struct awacs_softc *sc;
795 int left, right;
796 {
797 int lval = 15 - (left & 0xff) / 16;
798 int rval = 15 - (right & 0xff) / 16;
799
800 DPRINTF("ext_volume %d %d\n", lval, rval);
801
802 sc->sc_codecctl2 &= ~0x3cf;
803 sc->sc_codecctl2 |= (lval << 6) | rval;
804 awacs_write_codec(sc, sc->sc_codecctl2);
805 }
806
807 int
808 awacs_set_rate(sc, rate)
809 struct awacs_softc *sc;
810 int rate;
811 {
812 int c;
813
814 switch (rate) {
815
816 case 44100:
817 c = AWACS_RATE_44100;
818 break;
819 case 29400:
820 c = AWACS_RATE_29400;
821 break;
822 case 22050:
823 c = AWACS_RATE_22050;
824 break;
825 case 17640:
826 c = AWACS_RATE_17640;
827 break;
828 case 14700:
829 c = AWACS_RATE_14700;
830 break;
831 case 11025:
832 c = AWACS_RATE_11025;
833 break;
834 case 8820:
835 c = AWACS_RATE_8820;
836 break;
837 case 7350:
838 c = AWACS_RATE_7350;
839 break;
840 default:
841 return -1;
842 }
843
844 sc->sc_soundctl &= ~AWACS_RATE_MASK;
845 sc->sc_soundctl |= c;
846 awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl);
847
848 return 0;
849 }
850