awacs.c revision 1.3.2.4 1 /* $NetBSD: awacs.c,v 1.3.2.4 2001/03/22 02:32:01 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, AudioEulinear_be);
377 ae->encoding = AUDIO_ENCODING_ULINEAR_BE;
378 ae->precision = 16;
379 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
380 return 0;
381 case 4:
382 strcpy(ae->name, AudioEulinear_le);
383 ae->encoding = AUDIO_ENCODING_ULINEAR_LE;
384 ae->precision = 16;
385 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
386 return 0;
387 case 5:
388 strcpy(ae->name, AudioEmulaw);
389 ae->encoding = AUDIO_ENCODING_ULAW;
390 ae->precision = 8;
391 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
392 return 0;
393 case 6:
394 strcpy(ae->name, AudioEalaw);
395 ae->encoding = AUDIO_ENCODING_ALAW;
396 ae->precision = 8;
397 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
398 return 0;
399 default:
400 return EINVAL;
401 }
402 }
403
404 static void
405 mono16_to_stereo16(v, p, cc)
406 void *v;
407 u_char *p;
408 int cc;
409 {
410 int x;
411 int16_t *src, *dst;
412
413 src = (void *)(p + cc);
414 dst = (void *)(p + cc * 2);
415 while (cc > 0) {
416 x = *--src;
417 *--dst = x;
418 *--dst = x;
419 cc -= 2;
420 }
421 }
422
423 int
424 awacs_set_params(h, setmode, usemode, play, rec)
425 void *h;
426 int setmode, usemode;
427 struct audio_params *play, *rec;
428 {
429 struct awacs_softc *sc = h;
430 struct audio_params *p;
431 int mode, rate;
432
433 /*
434 * This device only has one clock, so make the sample rates match.
435 */
436 if (play->sample_rate != rec->sample_rate &&
437 usemode == (AUMODE_PLAY | AUMODE_RECORD)) {
438 if (setmode == AUMODE_PLAY) {
439 rec->sample_rate = play->sample_rate;
440 setmode |= AUMODE_RECORD;
441 } else if (setmode == AUMODE_RECORD) {
442 play->sample_rate = rec->sample_rate;
443 setmode |= AUMODE_PLAY;
444 } else
445 return EINVAL;
446 }
447
448 for (mode = AUMODE_RECORD; mode != -1;
449 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
450 if ((setmode & mode) == 0)
451 continue;
452
453 p = mode == AUMODE_PLAY ? play : rec;
454
455 if (p->sample_rate < 4000 || p->sample_rate > 50000 ||
456 (p->precision != 8 && p->precision != 16) ||
457 (p->channels != 1 && p->channels != 2))
458 return EINVAL;
459
460 p->factor = 1;
461 p->sw_code = 0;
462 awacs_write_reg(sc, AWACS_BYTE_SWAP, 0);
463
464 switch (p->encoding) {
465
466 case AUDIO_ENCODING_SLINEAR_LE:
467 awacs_write_reg(sc, AWACS_BYTE_SWAP, 1);
468 case AUDIO_ENCODING_SLINEAR_BE:
469 if (p->channels == 1) {
470 p->factor = 2;
471 p->sw_code = mono16_to_stereo16;
472 break;
473 }
474 if (p->precision != 16)
475 return EINVAL;
476 /* p->sw_code = change_sign8; */
477 break;
478
479 case AUDIO_ENCODING_ULINEAR_LE:
480 awacs_write_reg(sc, AWACS_BYTE_SWAP, 1);
481 if (p->channels == 2 && p->precision == 16)
482 p->sw_code = change_sign16_le;
483 else
484 return EINVAL;
485 break;
486
487 case AUDIO_ENCODING_ULINEAR_BE:
488 if (p->channels == 2 && p->precision == 16)
489 p->sw_code = change_sign16_be;
490 else
491 return EINVAL;
492 break;
493
494 case AUDIO_ENCODING_ULAW:
495 if (mode == AUMODE_PLAY) {
496 p->factor = 2;
497 p->sw_code = mulaw_to_slinear16_be;
498 } else
499 p->sw_code = ulinear8_to_mulaw;
500 break;
501
502 case AUDIO_ENCODING_ALAW:
503 if (mode == AUMODE_PLAY) {
504 p->factor = 2;
505 p->sw_code = alaw_to_slinear16_be;
506 } else
507 p->sw_code = ulinear8_to_alaw;
508 break;
509
510 default:
511 return EINVAL;
512 }
513 }
514
515 /* Set the speed */
516 rate = p->sample_rate;
517
518 if (awacs_set_rate(sc, rate))
519 return EINVAL;
520
521 return 0;
522 }
523
524 int
525 awacs_round_blocksize(h, size)
526 void *h;
527 int size;
528 {
529 if (size < NBPG)
530 size = NBPG;
531 return size & ~PGOFSET;
532 }
533
534 int
535 awacs_halt_output(h)
536 void *h;
537 {
538 struct awacs_softc *sc = h;
539
540 dbdma_stop(sc->sc_odma);
541 dbdma_reset(sc->sc_odma);
542 return 0;
543 }
544
545 int
546 awacs_halt_input(h)
547 void *h;
548 {
549 struct awacs_softc *sc = h;
550
551 dbdma_stop(sc->sc_idma);
552 dbdma_reset(sc->sc_idma);
553 return 0;
554 }
555
556 int
557 awacs_getdev(h, retp)
558 void *h;
559 struct audio_device *retp;
560 {
561 *retp = awacs_device;
562 return 0;
563 }
564
565 enum {
566 AWACS_OUTPUT_SELECT,
567 AWACS_VOL_SPEAKER,
568 AWACS_VOL_HEADPHONE,
569 AWACS_OUTPUT_CLASS,
570 AWACS_MONITOR_CLASS,
571 AWACS_ENUM_LAST
572 };
573
574 int
575 awacs_set_port(h, mc)
576 void *h;
577 mixer_ctrl_t *mc;
578 {
579 struct awacs_softc *sc = h;
580 int l, r;
581
582 DPRINTF("awacs_set_port dev = %d, type = %d\n", mc->dev, mc->type);
583
584 l = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
585 r = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
586
587 switch (mc->dev) {
588 case AWACS_OUTPUT_SELECT:
589 printf("output_select mask = 0x%x\n", mc->un.mask);
590 sc->sc_output_mask = mc->un.mask;
591 return 0;
592
593 case AWACS_VOL_SPEAKER:
594 awacs_set_speaker_volume(sc, l, r);
595 return 0;
596
597 case AWACS_VOL_HEADPHONE:
598 awacs_set_ext_volume(sc, l, r);
599 return 0;
600 }
601
602 return ENXIO;
603 }
604
605 int
606 awacs_get_port(h, mc)
607 void *h;
608 mixer_ctrl_t *mc;
609 {
610 struct awacs_softc *sc = h;
611 int vol, l, r;
612
613 DPRINTF("awacs_get_port dev = %d, type = %d\n", mc->dev, mc->type);
614
615 switch (mc->dev) {
616 case AWACS_OUTPUT_SELECT:
617 mc->un.mask = sc->sc_output_mask;
618 return 0;
619
620 case AWACS_VOL_SPEAKER:
621 vol = sc->sc_codecctl4;
622 l = (15 - ((vol & 0x3c0) >> 6)) * 16;
623 r = (15 - (vol & 0x0f)) * 16;
624 mc->un.mask = 1 << 0;
625 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
626 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
627 return 0;
628
629 case AWACS_VOL_HEADPHONE:
630 vol = sc->sc_codecctl2;
631 l = (15 - ((vol & 0x3c0) >> 6)) * 16;
632 r = (15 - (vol & 0x0f)) * 16;
633 mc->un.mask = 1 << 1;
634 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
635 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
636 return 0;
637
638 default:
639 return ENXIO;
640 }
641
642 return 0;
643 }
644
645 int
646 awacs_query_devinfo(h, dip)
647 void *h;
648 mixer_devinfo_t *dip;
649 {
650
651 DPRINTF("query_devinfo %d\n", dip->index);
652
653 switch (dip->index) {
654
655 case AWACS_OUTPUT_SELECT:
656 dip->mixer_class = AWACS_MONITOR_CLASS;
657 strcpy(dip->label.name, AudioNoutput);
658 dip->type = AUDIO_MIXER_SET;
659 dip->prev = dip->next = AUDIO_MIXER_LAST;
660 dip->un.s.num_mem = 2;
661 strcpy(dip->un.s.member[0].label.name, AudioNspeaker);
662 dip->un.s.member[0].mask = 1 << 0;
663 strcpy(dip->un.s.member[1].label.name, AudioNheadphone);
664 dip->un.s.member[1].mask = 1 << 1;
665 return 0;
666
667 case AWACS_VOL_SPEAKER:
668 dip->mixer_class = AWACS_OUTPUT_CLASS;
669 strcpy(dip->label.name, AudioNspeaker);
670 dip->type = AUDIO_MIXER_VALUE;
671 dip->prev = dip->next = AUDIO_MIXER_LAST;
672 dip->un.v.num_channels = 2;
673 strcpy(dip->un.v.units.name, AudioNvolume);
674 return 0;
675
676 case AWACS_VOL_HEADPHONE:
677 dip->mixer_class = AWACS_OUTPUT_CLASS;
678 strcpy(dip->label.name, AudioNheadphone);
679 dip->type = AUDIO_MIXER_VALUE;
680 dip->prev = dip->next = AUDIO_MIXER_LAST;
681 dip->un.v.num_channels = 2;
682 strcpy(dip->un.v.units.name, AudioNvolume);
683 return 0;
684
685 case AWACS_MONITOR_CLASS:
686 dip->mixer_class = AWACS_MONITOR_CLASS;
687 strcpy(dip->label.name, AudioCmonitor);
688 dip->type = AUDIO_MIXER_CLASS;
689 dip->next = dip->prev = AUDIO_MIXER_LAST;
690 return 0;
691
692 case AWACS_OUTPUT_CLASS:
693 dip->mixer_class = AWACS_OUTPUT_CLASS;
694 strcpy(dip->label.name, AudioCoutputs);
695 dip->type = AUDIO_MIXER_CLASS;
696 dip->next = dip->prev = AUDIO_MIXER_LAST;
697 return 0;
698 }
699
700 return ENXIO;
701 }
702
703 size_t
704 awacs_round_buffersize(h, dir, size)
705 void *h;
706 int dir;
707 size_t size;
708 {
709 if (size > 65536)
710 size = 65536;
711 return size;
712 }
713
714 paddr_t
715 awacs_mappage(h, mem, off, prot)
716 void *h;
717 void *mem;
718 off_t off;
719 int prot;
720 {
721 if (off < 0)
722 return -1;
723 return -1; /* XXX */
724 }
725
726 int
727 awacs_get_props(h)
728 void *h;
729 {
730 return AUDIO_PROP_FULLDUPLEX /* | AUDIO_PROP_MMAP */;
731 }
732
733 int
734 awacs_trigger_output(h, start, end, bsize, intr, arg, param)
735 void *h;
736 void *start, *end;
737 int bsize;
738 void (*intr)(void *);
739 void *arg;
740 struct audio_params *param;
741 {
742 struct awacs_softc *sc = h;
743 struct dbdma_command *cmd = sc->sc_odmacmd;
744 vaddr_t va;
745 int i, len, intmode;
746
747 DPRINTF("trigger_output %p %p 0x%x\n", start, end, bsize);
748
749 sc->sc_ointr = intr;
750 sc->sc_oarg = arg;
751 sc->sc_opages = ((char *)end - (char *)start) / NBPG;
752
753 #ifdef DIAGNOSTIC
754 if (sc->sc_opages > 16)
755 panic("awacs_trigger_output");
756 #endif
757
758 va = (vaddr_t)start;
759 len = 0;
760 for (i = sc->sc_opages; i > 0; i--) {
761 len += NBPG;
762 if (len < bsize)
763 intmode = DBDMA_INT_NEVER;
764 else {
765 len = 0;
766 intmode = DBDMA_INT_ALWAYS;
767 }
768
769 DBDMA_BUILD(cmd, DBDMA_CMD_OUT_MORE, 0, NBPG, vtophys(va),
770 intmode, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
771 va += NBPG;
772 cmd++;
773 }
774
775 DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0,
776 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS);
777 dbdma_st32(&cmd->d_cmddep, vtophys((vaddr_t)sc->sc_odmacmd));
778
779 dbdma_start(sc->sc_odma, sc->sc_odmacmd);
780
781 return 0;
782 }
783
784 int
785 awacs_trigger_input(h, start, end, bsize, intr, arg, param)
786 void *h;
787 void *start, *end;
788 int bsize;
789 void (*intr)(void *);
790 void *arg;
791 struct audio_params *param;
792 {
793 printf("awacs_trigger_input called\n");
794
795 return 1;
796 }
797
798 void
799 awacs_set_speaker_volume(sc, left, right)
800 struct awacs_softc *sc;
801 int left, right;
802 {
803 int lval = 15 - (left & 0xff) / 16;
804 int rval = 15 - (right & 0xff) / 16;
805
806 DPRINTF("speaker_volume %d %d\n", lval, rval);
807
808 sc->sc_codecctl4 &= ~0x3cf;
809 sc->sc_codecctl4 |= (lval << 6) | rval;
810 awacs_write_codec(sc, sc->sc_codecctl4);
811 }
812
813 void
814 awacs_set_ext_volume(sc, left, right)
815 struct awacs_softc *sc;
816 int left, right;
817 {
818 int lval = 15 - (left & 0xff) / 16;
819 int rval = 15 - (right & 0xff) / 16;
820
821 DPRINTF("ext_volume %d %d\n", lval, rval);
822
823 sc->sc_codecctl2 &= ~0x3cf;
824 sc->sc_codecctl2 |= (lval << 6) | rval;
825 awacs_write_codec(sc, sc->sc_codecctl2);
826 }
827
828 int
829 awacs_set_rate(sc, rate)
830 struct awacs_softc *sc;
831 int rate;
832 {
833 int c;
834
835 switch (rate) {
836
837 case 44100:
838 c = AWACS_RATE_44100;
839 break;
840 case 29400:
841 c = AWACS_RATE_29400;
842 break;
843 case 22050:
844 c = AWACS_RATE_22050;
845 break;
846 case 17640:
847 c = AWACS_RATE_17640;
848 break;
849 case 14700:
850 c = AWACS_RATE_14700;
851 break;
852 case 11025:
853 c = AWACS_RATE_11025;
854 break;
855 case 8820:
856 c = AWACS_RATE_8820;
857 break;
858 case 8000: /* XXX */
859 case 7350:
860 c = AWACS_RATE_7350;
861 break;
862 default:
863 return -1;
864 }
865
866 sc->sc_soundctl &= ~AWACS_RATE_MASK;
867 sc->sc_soundctl |= c;
868 awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl);
869
870 return 0;
871 }
872