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