1 /* $NetBSD: awacs.c,v 1.35 2008/08/27 14:31:46 jmcneill Exp $ */
4 * Copyright (c) 2000 Tsubai Masanari. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: awacs.c,v 1.35 2008/08/27 14:31:46 jmcneill Exp $");
32 #include <sys/param.h>
33 #include <sys/audioio.h>
34 #include <sys/device.h>
35 #include <sys/malloc.h>
36 #include <sys/systm.h>
37 #include <sys/kthread.h>
38 #include <sys/kernel.h>
40 #include <dev/auconv.h>
41 #include <dev/audio_if.h>
42 #include <dev/mulaw.h>
44 #include <uvm/uvm_extern.h>
46 #include <machine/autoconf.h>
47 #include <machine/pio.h>
49 #include <dev/ofw/openfirm.h>
50 #include <macppc/dev/dbdma.h>
52 #include <dev/i2c/sgsmixvar.h>
54 #include "opt_awacs.h"
57 # define DPRINTF printf
59 # define DPRINTF while (0) printf
63 #define AWACS_CAP_BSWAP 0x0001
69 void (*sc_ointr
)(void *); /* DMA completion intr handler */
70 void *sc_oarg
; /* arg for sc_ointr() */
71 int sc_opages
; /* # of output pages */
73 void (*sc_iintr
)(void *); /* DMA completion intr handler */
74 void *sc_iarg
; /* arg for sc_iintr() */
76 uint32_t sc_record_source
; /* recording source mask */
77 uint32_t sc_output_mask
; /* output mask */
78 uint32_t sc_headphones_mask
; /* which reading of the gpio means */
79 uint32_t sc_headphones_in
; /* headphones are present */
84 int sc_bass
, sc_treble
;
88 int sc_need_parallel_output
;
103 struct dbdma_regmap
*sc_odma
;
104 struct dbdma_regmap
*sc_idma
;
105 struct dbdma_command
*sc_odmacmd
;
106 struct dbdma_command
*sc_idmacmd
;
108 #define AWACS_NFORMATS 2
109 struct audio_format sc_formats
[AWACS_NFORMATS
];
112 static int awacs_match(device_t
, struct cfdata
*, void *);
113 static void awacs_attach(device_t
, device_t
, void *);
114 static int awacs_intr(void *);
115 static int awacs_status_intr(void *);
117 static void awacs_close(void *);
118 static int awacs_query_encoding(void *, struct audio_encoding
*);
119 static int awacs_set_params(void *, int, int, audio_params_t
*, audio_params_t
*,
120 stream_filter_list_t
*, stream_filter_list_t
*);
122 static int awacs_round_blocksize(void *, int, int, const audio_params_t
*);
123 static int awacs_trigger_output(void *, void *, void *, int, void (*)(void *),
124 void *, const audio_params_t
*);
125 static int awacs_trigger_input(void *, void *, void *, int, void (*)(void *),
126 void *, const audio_params_t
*);
127 static int awacs_halt_output(void *);
128 static int awacs_halt_input(void *);
129 static int awacs_getdev(void *, struct audio_device
*);
130 static int awacs_set_port(void *, mixer_ctrl_t
*);
131 static int awacs_get_port(void *, mixer_ctrl_t
*);
132 static int awacs_query_devinfo(void *, mixer_devinfo_t
*);
133 static size_t awacs_round_buffersize(void *, int, size_t);
134 static paddr_t
awacs_mappage(void *, void *, off_t
, int);
135 static int awacs_get_props(void *);
137 static inline u_int
awacs_read_reg(struct awacs_softc
*, int);
138 static inline void awacs_write_reg(struct awacs_softc
*, int, int);
139 static void awacs_write_codec(struct awacs_softc
*, int);
141 void awacs_set_volume(struct awacs_softc
*, int, int);
142 static void awacs_set_speaker_volume(struct awacs_softc
*, int, int);
143 static void awacs_set_ext_volume(struct awacs_softc
*, int, int);
144 static void awacs_set_loopthrough_volume(struct awacs_softc
*, int, int);
145 static int awacs_set_rate(struct awacs_softc
*, const audio_params_t
*);
146 static void awacs_select_output(struct awacs_softc
*, int);
147 static int awacs_check_headphones(struct awacs_softc
*);
148 static void awacs_thread(void *);
151 static void awacs_set_bass(struct awacs_softc
*, int);
152 static void awacs_set_treble(struct awacs_softc
*, int);
154 static int awacs_setup_sgsmix(device_t
);
156 CFATTACH_DECL_NEW(awacs
, sizeof(struct awacs_softc
),
157 awacs_match
, awacs_attach
, NULL
, NULL
);
159 const struct audio_hw_if awacs_hw_if
= {
163 awacs_query_encoding
,
165 awacs_round_blocksize
,
181 awacs_round_buffersize
,
184 awacs_trigger_output
,
189 struct audio_device awacs_device
= {
195 #define AWACS_NFORMATS 2
196 #define AWACS_FORMATS_LE 0
197 static const struct audio_format awacs_formats
[AWACS_NFORMATS
] = {
198 {NULL
, AUMODE_PLAY
| AUMODE_RECORD
, AUDIO_ENCODING_SLINEAR_LE
, 16, 16,
200 {7350, 8820, 11025, 14700, 17640, 22050, 29400, 44100}},
201 {NULL
, AUMODE_PLAY
| AUMODE_RECORD
, AUDIO_ENCODING_SLINEAR_BE
, 16, 16,
203 {7350, 8820, 11025, 14700, 17640, 22050, 29400, 44100}},
206 /* register offset */
207 #define AWACS_SOUND_CTRL 0x00
208 #define AWACS_CODEC_CTRL 0x10
209 #define AWACS_CODEC_STATUS 0x20
210 #define AWACS_CLIP_COUNT 0x30
211 #define AWACS_BYTE_SWAP 0x40
214 #define AWACS_INPUT_SUBFRAME0 0x00000001
215 #define AWACS_INPUT_SUBFRAME1 0x00000002
216 #define AWACS_INPUT_SUBFRAME2 0x00000004
217 #define AWACS_INPUT_SUBFRAME3 0x00000008
219 #define AWACS_OUTPUT_SUBFRAME0 0x00000010
220 #define AWACS_OUTPUT_SUBFRAME1 0x00000020
221 #define AWACS_OUTPUT_SUBFRAME2 0x00000040
222 #define AWACS_OUTPUT_SUBFRAME3 0x00000080
224 #define AWACS_RATE_44100 0x00000000
225 #define AWACS_RATE_29400 0x00000100
226 #define AWACS_RATE_22050 0x00000200
227 #define AWACS_RATE_17640 0x00000300
228 #define AWACS_RATE_14700 0x00000400
229 #define AWACS_RATE_11025 0x00000500
230 #define AWACS_RATE_8820 0x00000600
231 #define AWACS_RATE_7350 0x00000700
232 #define AWACS_RATE_MASK 0x00000700
234 #define AWACS_ERROR 0x00000800
235 #define AWACS_PORTCHG 0x00001000
236 #define AWACS_INTR_ERROR 0x00002000 /* interrupt on error */
237 #define AWACS_INTR_PORTCHG 0x00004000 /* interrupt on port change */
239 #define AWACS_STATUS_SUBFRAME 0x00018000 /* mask */
242 #define AWACS_CODEC_ADDR0 0x00000000
243 #define AWACS_CODEC_ADDR1 0x00001000
244 #define AWACS_CODEC_ADDR2 0x00002000
245 #define AWACS_CODEC_ADDR4 0x00004000
246 #define AWACS_CODEC_ADDR5 0x00005000
247 #define AWACS_CODEC_ADDR6 0x00006000
248 #define AWACS_CODEC_ADDR7 0x00007000
249 #define AWACS_CODEC_EMSEL0 0x00000000
250 #define AWACS_CODEC_EMSEL1 0x00400000
251 #define AWACS_CODEC_EMSEL2 0x00800000
252 #define AWACS_CODEC_EMSEL4 0x00c00000
253 #define AWACS_CODEC_BUSY 0x01000000
256 #define AWACS_DEFAULT_CD_GAIN 0x000000bb
257 #define AWACS_INPUT_CD 0x00000200
258 #define AWACS_INPUT_LINE 0x00000400
259 #define AWACS_INPUT_MICROPHONE 0x00000800
260 #define AWACS_INPUT_MASK 0x00000e00
263 #define AWACS_LOOP_THROUGH 0x00000040
264 #define AWACS_MUTE_SPEAKER 0x00000080
265 #define AWACS_MUTE_HEADPHONE 0x00000200
266 #define AWACS_PARALLEL_OUTPUT 0x00000c00
269 #define OUTPUT_SPEAKER 1
270 #define OUTPUT_HEADPHONES 2
274 static const char *screamer
[] = {"screamer", NULL
};
277 * list machines that have the headphone detect GPIO reversed here.
278 * so far the only known case is the PowerBook 3400c and similar machines
280 static const char *detect_reversed
[] = {"AAPL,3400/2400",
284 static const char *use_gpio4
[] = { "PowerMac3,3",
288 * list of machines that do not require AWACS_PARALLEL_OUTPUT
290 static const char *no_parallel_output
[] = { "PowerBook3,1",
294 awacs_match(device_t parent
, struct cfdata
*match
, void *aux
)
300 if (strcmp(ca
->ca_name
, "awacs") == 0 ||
301 strcmp(ca
->ca_name
, "davbus") == 0)
304 if (ca
->ca_nreg
< 24 || ca
->ca_nintr
< 12)
307 if (strcmp(ca
->ca_name
, "i2s") == 0)
314 awacs_attach(device_t parent
, device_t self
, void *aux
)
316 struct awacs_softc
*sc
;
318 int cirq
, oirq
, iirq
, cirq_type
, oirq_type
, iirq_type
;
323 sc
= device_private(self
);
327 sc
->sc_reg
= mapiodev(ca
->ca_baseaddr
+ ca
->ca_reg
[0], ca
->ca_reg
[1]);
330 sc
->sc_odma
= mapiodev(ca
->ca_baseaddr
+ ca
->ca_reg
[2], ca
->ca_reg
[3]);
331 sc
->sc_odmacmd
= dbdma_alloc(20 * sizeof(struct dbdma_command
));
333 sc
->sc_idma
= mapiodev(ca
->ca_baseaddr
+ ca
->ca_reg
[4], ca
->ca_reg
[5]);
334 sc
->sc_idmacmd
= dbdma_alloc(20 * sizeof(struct dbdma_command
));
336 if (strcmp(ca
->ca_name
, "i2s") == 0) {
339 node
= OF_child(ca
->ca_node
);
341 printf("no i2s-a child\n");
344 if (OF_getprop(node
, "interrupts", intr
, sizeof(intr
)) == -1) {
345 printf("no interrupt property\n");
352 cirq_type
= intr
[1] ? IST_LEVEL
: IST_EDGE
;
353 oirq_type
= intr
[3] ? IST_LEVEL
: IST_EDGE
;
354 iirq_type
= intr
[5] ? IST_LEVEL
: IST_EDGE
;
355 } else if (ca
->ca_nintr
== 24) {
356 cirq
= ca
->ca_intr
[0];
357 oirq
= ca
->ca_intr
[2];
358 iirq
= ca
->ca_intr
[4];
359 cirq_type
= ca
->ca_intr
[1] ? IST_LEVEL
: IST_EDGE
;
360 oirq_type
= ca
->ca_intr
[3] ? IST_LEVEL
: IST_EDGE
;
361 iirq_type
= ca
->ca_intr
[5] ? IST_LEVEL
: IST_EDGE
;
363 cirq
= ca
->ca_intr
[0];
364 oirq
= ca
->ca_intr
[1];
365 iirq
= ca
->ca_intr
[2];
366 cirq_type
= oirq_type
= iirq_type
= IST_EDGE
;
369 intr_establish(cirq
, cirq_type
, IPL_BIO
, awacs_status_intr
, sc
);
370 intr_establish(oirq
, oirq_type
, IPL_AUDIO
, awacs_intr
, sc
);
371 intr_establish(iirq
, iirq_type
, IPL_AUDIO
, awacs_intr
, sc
);
373 /* check if the chip is a screamer */
374 sc
->sc_screamer
= (of_compatible(ca
->ca_node
, screamer
) != -1);
375 if (!sc
->sc_screamer
) {
376 /* look for 'sound' child node */
379 sound_node
= OF_child(ca
->ca_node
);
380 while ((sound_node
!= 0) && (!sc
->sc_screamer
)) {
383 (of_compatible(sound_node
, screamer
) != -1);
384 sound_node
= OF_peer(sound_node
);
388 if (sc
->sc_screamer
) {
392 printf(": irq %d,%d,%d\n", cirq
, oirq
, iirq
);
397 memcpy(&sc
->sc_formats
, awacs_formats
, sizeof(awacs_formats
));
399 /* XXX Uni-North based models don't have byteswap capability. */
400 if (OF_finddevice("/uni-n") == -1) {
402 sc
->sc_flags
|= AWACS_CAP_BSWAP
;
405 AUFMT_INVALIDATE(&sc
->sc_formats
[AWACS_FORMATS_LE
]);
408 sc
->sc_soundctl
= AWACS_INPUT_SUBFRAME0
| AWACS_OUTPUT_SUBFRAME0
|
409 AWACS_RATE_44100
| AWACS_INTR_PORTCHG
;
410 awacs_write_reg(sc
, AWACS_SOUND_CTRL
, sc
->sc_soundctl
);
412 sc
->sc_codecctl0
= AWACS_CODEC_ADDR0
| AWACS_CODEC_EMSEL0
;
413 sc
->sc_codecctl1
= AWACS_CODEC_ADDR1
| AWACS_CODEC_EMSEL0
;
414 sc
->sc_codecctl2
= AWACS_CODEC_ADDR2
| AWACS_CODEC_EMSEL0
;
415 sc
->sc_codecctl4
= AWACS_CODEC_ADDR4
| AWACS_CODEC_EMSEL0
;
416 sc
->sc_codecctl5
= AWACS_CODEC_ADDR5
| AWACS_CODEC_EMSEL0
;
417 sc
->sc_codecctl6
= AWACS_CODEC_ADDR6
| AWACS_CODEC_EMSEL0
;
418 sc
->sc_codecctl7
= AWACS_CODEC_ADDR7
| AWACS_CODEC_EMSEL0
;
420 sc
->sc_codecctl0
|= AWACS_INPUT_CD
| AWACS_DEFAULT_CD_GAIN
;
421 awacs_write_codec(sc
, sc
->sc_codecctl0
);
423 /* Set loopthrough for external mixer on beige G3 */
424 sc
->sc_codecctl1
|= AWACS_LOOP_THROUGH
;
426 printf("%s: ", device_xname(sc
->sc_dev
));
429 * all(?) awacs have GPIOs to detect if there's something plugged into
430 * the headphone jack. The other GPIOs are either used for other jacks
431 * ( the PB3400c's microphone jack for instance ) or unused.
432 * The problem is that there are at least three different ways how
433 * those GPIOs are wired to the actual jacks.
434 * For now we bother only with headphone detection
436 perch
= OF_finddevice("/perch");
437 root_node
= OF_finddevice("/");
438 if (of_compatible(root_node
, detect_reversed
) != -1) {
440 /* 0x02 is for the microphone jack, high active */
442 * for some reason the gpio for the headphones jack is low
443 * active on the PB3400 and similar machines
445 sc
->sc_headphones_mask
= 0x8;
446 sc
->sc_headphones_in
= 0x0;
447 } else if ((perch
!= -1) ||
448 (of_compatible(root_node
, use_gpio4
) != -1)) {
450 * this is for the beige G3's 'personality card' which uses
451 * yet another wiring of the headphone detect GPIOs
452 * some G4s use it as well
454 sc
->sc_headphones_mask
= 0x04;
455 sc
->sc_headphones_in
= 0x04;
457 /* while on most machines it's high active as well */
458 sc
->sc_headphones_mask
= 0x8;
459 sc
->sc_headphones_in
= 0x8;
462 if (of_compatible(root_node
, no_parallel_output
) != -1)
463 sc
->sc_need_parallel_output
= 0;
465 sc
->sc_need_parallel_output
= 1;
466 sc
->sc_codecctl1
|= AWACS_PARALLEL_OUTPUT
;
469 if (awacs_check_headphones(sc
)) {
471 /* default output to headphones */
472 printf("headphones\n");
473 sc
->sc_output_mask
= OUTPUT_HEADPHONES
;
476 /* default output to speakers */
478 sc
->sc_output_mask
= OUTPUT_SPEAKER
;
480 sc
->sc_output_wanted
= sc
->sc_output_mask
;
481 awacs_select_output(sc
, sc
->sc_output_mask
);
484 if (sc
->sc_screamer
) {
485 awacs_write_codec(sc
, sc
->sc_codecctl6
);
486 awacs_write_codec(sc
, sc
->sc_codecctl5
);
488 awacs_write_codec(sc
, sc
->sc_codecctl1
);
489 awacs_write_codec(sc
, sc
->sc_codecctl7
);
492 /* default input from CD */
493 sc
->sc_record_source
= 1 << 0;
494 sc
->sc_codecctl0
&= ~AWACS_INPUT_MASK
;
495 sc
->sc_codecctl0
|= AWACS_INPUT_CD
;
496 awacs_write_codec(sc
, sc
->sc_codecctl0
);
498 /* Enable interrupts and looping mode. */
501 sc
->sc_codecctl1
|= AWACS_LOOP_THROUGH
;
502 if (sc
->sc_need_parallel_output
)
503 sc
->sc_codecctl1
|= AWACS_PARALLEL_OUTPUT
;
504 awacs_write_codec(sc
, sc
->sc_codecctl1
);
507 sc
->sc_sgsmix
= NULL
;
509 sc
->sc_have_perch
= 0;
512 len
= OF_getprop(perch
, "compatible", compat
, 255);
514 printf("%s: found '%s' personality card\n",
515 device_xname(sc
->sc_dev
), compat
);
516 sc
->sc_have_perch
= 1;
517 config_finalize_register(sc
->sc_dev
,
522 /* Set initial volume[s] */
523 awacs_set_volume(sc
, 144, 144);
524 awacs_set_loopthrough_volume(sc
, 0, 0);
526 audio_attach_mi(&awacs_hw_if
, sc
, sc
->sc_dev
);
528 if (kthread_create(PRI_NONE
, 0, NULL
, awacs_thread
, sc
,
529 &sc
->sc_thread
, "%s", "awacs") != 0) {
530 printf("awacs: unable to create event kthread");
535 awacs_setup_sgsmix(device_t cookie
)
537 struct awacs_softc
*sc
= device_private(cookie
);
543 if (!sc
->sc_have_perch
)
546 /* look for sgsmix */
547 for (dv
= deviter_first(&di
, DEVITER_F_ROOT_FIRST
);
549 dv
= deviter_next(&di
)) {
550 if (device_is_a(dv
, "sgsmix")) {
555 deviter_release(&di
);
556 if (sc
->sc_sgsmix
== NULL
)
559 printf("%s: using %s\n", device_xname(sc
->sc_dev
),
560 device_xname(sc
->sc_sgsmix
));
562 awacs_select_output(sc
, sc
->sc_output_mask
);
563 awacs_set_volume(sc
, sc
->vol_l
, sc
->vol_r
);
564 awacs_set_bass(sc
, 128);
565 awacs_set_treble(sc
, 128);
566 wakeup(&sc
->sc_event
);
573 awacs_read_reg(struct awacs_softc
*sc
, int reg
)
578 return in32rb(addr
+ reg
);
582 awacs_write_reg(struct awacs_softc
*sc
, int reg
, int val
)
587 out32rb(addr
+ reg
, val
);
591 awacs_write_codec(struct awacs_softc
*sc
, int value
)
596 } while (awacs_read_reg(sc
, AWACS_CODEC_CTRL
) & AWACS_CODEC_BUSY
);
598 awacs_write_reg(sc
, AWACS_CODEC_CTRL
, value
);
602 } while (awacs_read_reg(sc
, AWACS_CODEC_CTRL
) & AWACS_CODEC_BUSY
);
608 struct awacs_softc
*sc
;
609 struct dbdma_command
*cmd
;
614 cmd
= sc
->sc_odmacmd
;
615 count
= sc
->sc_opages
;
616 /* Fill used buffer(s). */
617 while (count
-- > 0) {
618 /* if DBDMA_INT_ALWAYS */
619 if (in16rb(&cmd
->d_command
) & 0x30) { /* XXX */
620 status
= in16rb(&cmd
->d_status
);
622 if (status
) /* status == 0x8400 */
624 (*sc
->sc_ointr
)(sc
->sc_oarg
);
633 * Close function is called at splaudio().
638 struct awacs_softc
*sc
;
641 awacs_halt_output(sc
);
642 awacs_halt_input(sc
);
649 awacs_query_encoding(void *h
, struct audio_encoding
*ae
)
651 struct awacs_softc
*sc
;
654 ae
->flags
= AUDIO_ENCODINGFLAG_EMULATED
;
658 strcpy(ae
->name
, AudioEslinear
);
659 ae
->encoding
= AUDIO_ENCODING_SLINEAR
;
664 strcpy(ae
->name
, AudioEslinear_be
);
665 ae
->encoding
= AUDIO_ENCODING_SLINEAR_BE
;
670 strcpy(ae
->name
, AudioEslinear_le
);
671 ae
->encoding
= AUDIO_ENCODING_SLINEAR_LE
;
673 if (sc
->sc_flags
& AWACS_CAP_BSWAP
)
677 strcpy(ae
->name
, AudioEulinear_be
);
678 ae
->encoding
= AUDIO_ENCODING_ULINEAR_BE
;
682 strcpy(ae
->name
, AudioEulinear_le
);
683 ae
->encoding
= AUDIO_ENCODING_ULINEAR_LE
;
687 strcpy(ae
->name
, AudioEmulaw
);
688 ae
->encoding
= AUDIO_ENCODING_ULAW
;
692 strcpy(ae
->name
, AudioEalaw
);
693 ae
->encoding
= AUDIO_ENCODING_ALAW
;
702 awacs_set_params(void *h
, int setmode
, int usemode
,
703 audio_params_t
*play
, audio_params_t
*rec
,
704 stream_filter_list_t
*pfil
, stream_filter_list_t
*rfil
)
706 struct awacs_softc
*sc
;
708 stream_filter_list_t
*fil
;
714 * This device only has one clock, so make the sample rates match.
716 if (play
->sample_rate
!= rec
->sample_rate
&&
717 usemode
== (AUMODE_PLAY
| AUMODE_RECORD
)) {
718 if (setmode
== AUMODE_PLAY
) {
719 rec
->sample_rate
= play
->sample_rate
;
720 setmode
|= AUMODE_RECORD
;
721 } else if (setmode
== AUMODE_RECORD
) {
722 play
->sample_rate
= rec
->sample_rate
;
723 setmode
|= AUMODE_PLAY
;
728 for (mode
= AUMODE_RECORD
; mode
!= -1;
729 mode
= mode
== AUMODE_RECORD
? AUMODE_PLAY
: -1) {
730 if ((setmode
& mode
) == 0)
733 p
= mode
== AUMODE_PLAY
? play
: rec
;
734 fil
= mode
== AUMODE_PLAY
? pfil
: rfil
;
735 switch (p
->sample_rate
) {
736 case 48000: /* aurateconv */
744 case 8000: /* aurateconv */
750 awacs_write_reg(sc
, AWACS_BYTE_SWAP
, 0);
751 i
= auconv_set_converter(sc
->sc_formats
, AWACS_NFORMATS
,
755 if (i
== AWACS_FORMATS_LE
)
756 awacs_write_reg(sc
, AWACS_BYTE_SWAP
, 1);
757 if (fil
->req_size
> 0)
758 p
= &fil
->filters
[0].param
;
759 if (awacs_set_rate(sc
, p
))
766 awacs_round_blocksize(void *h
, int size
, int mode
, const audio_params_t
*param
)
769 if (size
< PAGE_SIZE
)
771 return size
& ~PGOFSET
;
775 awacs_halt_output(void *h
)
777 struct awacs_softc
*sc
;
780 dbdma_stop(sc
->sc_odma
);
781 dbdma_reset(sc
->sc_odma
);
786 awacs_halt_input(void *h
)
788 struct awacs_softc
*sc
;
791 dbdma_stop(sc
->sc_idma
);
792 dbdma_reset(sc
->sc_idma
);
797 awacs_getdev(void *h
, struct audio_device
*retp
)
800 *retp
= awacs_device
;
819 awacs_set_port(void *h
, mixer_ctrl_t
*mc
)
821 struct awacs_softc
*sc
;
824 DPRINTF("awacs_set_port dev = %d, type = %d\n", mc
->dev
, mc
->type
);
826 l
= mc
->un
.value
.level
[AUDIO_MIXER_LEVEL_LEFT
];
827 r
= mc
->un
.value
.level
[AUDIO_MIXER_LEVEL_RIGHT
];
830 case AWACS_OUTPUT_SELECT
:
831 /* No change necessary? */
832 if (mc
->un
.mask
== sc
->sc_output_mask
)
834 awacs_select_output(sc
, mc
->un
.mask
);
837 case AWACS_VOL_MASTER
:
838 awacs_set_volume(sc
, l
, r
);
841 case AWACS_INPUT_SELECT
:
842 /* no change necessary? */
843 if (mc
->un
.mask
== sc
->sc_record_source
)
845 switch (mc
->un
.mask
) {
846 case 1 << 0: /* CD */
847 sc
->sc_codecctl0
&= ~AWACS_INPUT_MASK
;
848 sc
->sc_codecctl0
|= AWACS_INPUT_CD
;
849 awacs_write_codec(sc
, sc
->sc_codecctl0
);
851 case 1 << 1: /* microphone */
852 sc
->sc_codecctl0
&= ~AWACS_INPUT_MASK
;
853 sc
->sc_codecctl0
|= AWACS_INPUT_MICROPHONE
;
854 awacs_write_codec(sc
, sc
->sc_codecctl0
);
856 case 1 << 2: /* line in */
857 sc
->sc_codecctl0
&= ~AWACS_INPUT_MASK
;
858 sc
->sc_codecctl0
|= AWACS_INPUT_LINE
;
859 awacs_write_codec(sc
, sc
->sc_codecctl0
);
861 default: /* invalid argument */
864 sc
->sc_record_source
= mc
->un
.mask
;
867 case AWACS_VOL_INPUT
:
868 sc
->sc_codecctl0
&= ~0xff;
869 sc
->sc_codecctl0
|= (l
& 0xf0) | (r
>> 4);
870 awacs_write_codec(sc
, sc
->sc_codecctl0
);
873 case AWACS_VOL_MONITOR
:
874 awacs_set_loopthrough_volume(sc
, l
, r
);
879 awacs_set_bass(sc
, l
);
883 awacs_set_treble(sc
, l
);
892 awacs_get_port(void *h
, mixer_ctrl_t
*mc
)
894 struct awacs_softc
*sc
;
899 case AWACS_OUTPUT_SELECT
:
900 mc
->un
.mask
= sc
->sc_output_mask
;
903 case AWACS_VOL_MASTER
:
904 mc
->un
.value
.level
[AUDIO_MIXER_LEVEL_LEFT
] = sc
->vol_l
;
905 mc
->un
.value
.level
[AUDIO_MIXER_LEVEL_RIGHT
] = sc
->vol_r
;
908 case AWACS_INPUT_SELECT
:
909 mc
->un
.mask
= sc
->sc_record_source
;
912 case AWACS_VOL_INPUT
:
913 vol
= sc
->sc_codecctl0
& 0xff;
915 r
= (vol
& 0x0f) << 4;
916 mc
->un
.value
.level
[AUDIO_MIXER_LEVEL_LEFT
] = l
;
917 mc
->un
.value
.level
[AUDIO_MIXER_LEVEL_RIGHT
] = r
;
920 case AWACS_VOL_MONITOR
:
921 vol
= sc
->sc_codecctl5
& 0x3cf;
922 l
= (vol
& 0x3c0) >> 6;
924 mc
->un
.value
.level
[AUDIO_MIXER_LEVEL_LEFT
] = (15 - l
) << 4;
925 mc
->un
.value
.level
[AUDIO_MIXER_LEVEL_RIGHT
] = (15 - r
) << 4;
930 mc
->un
.value
.level
[AUDIO_MIXER_LEVEL_MONO
] = sc
->sc_bass
;
934 mc
->un
.value
.level
[AUDIO_MIXER_LEVEL_MONO
] = sc
->sc_treble
;
946 awacs_query_devinfo(void *h
, mixer_devinfo_t
*dip
)
949 struct awacs_softc
*sc
= h
;
952 switch (dip
->index
) {
954 case AWACS_OUTPUT_SELECT
:
955 dip
->mixer_class
= AWACS_MONITOR_CLASS
;
956 strcpy(dip
->label
.name
, AudioNoutput
);
957 dip
->type
= AUDIO_MIXER_SET
;
958 dip
->prev
= dip
->next
= AUDIO_MIXER_LAST
;
959 dip
->un
.s
.num_mem
= 2;
960 strcpy(dip
->un
.s
.member
[0].label
.name
, AudioNspeaker
);
961 dip
->un
.s
.member
[0].mask
= 1 << 0;
962 strcpy(dip
->un
.s
.member
[1].label
.name
, AudioNheadphone
);
963 dip
->un
.s
.member
[1].mask
= 1 << 1;
966 case AWACS_VOL_MASTER
:
967 dip
->mixer_class
= AWACS_MONITOR_CLASS
;
968 strcpy(dip
->label
.name
, AudioNmaster
);
969 dip
->type
= AUDIO_MIXER_VALUE
;
970 dip
->prev
= dip
->next
= AUDIO_MIXER_LAST
;
971 dip
->un
.v
.num_channels
= 2;
972 strcpy(dip
->un
.v
.units
.name
, AudioNvolume
);
975 case AWACS_VOL_MONITOR
:
976 dip
->mixer_class
= AWACS_MONITOR_CLASS
;
977 strcpy(dip
->label
.name
, AudioNmonitor
);
978 dip
->type
= AUDIO_MIXER_VALUE
;
979 dip
->prev
= dip
->next
= AUDIO_MIXER_LAST
;
980 dip
->un
.v
.num_channels
= 2;
981 strcpy(dip
->un
.v
.units
.name
, AudioNvolume
);
986 if (sc
->sc_sgsmix
== NULL
)
988 dip
->mixer_class
= AWACS_MONITOR_CLASS
;
989 strcpy(dip
->label
.name
, AudioNbass
);
990 dip
->type
= AUDIO_MIXER_VALUE
;
991 dip
->prev
= dip
->next
= AUDIO_MIXER_LAST
;
992 dip
->un
.v
.num_channels
= 1;
993 strcpy(dip
->un
.v
.units
.name
, AudioNbass
);
997 if (sc
->sc_sgsmix
== NULL
)
999 dip
->mixer_class
= AWACS_MONITOR_CLASS
;
1000 strcpy(dip
->label
.name
, AudioNtreble
);
1001 dip
->type
= AUDIO_MIXER_VALUE
;
1002 dip
->prev
= dip
->next
= AUDIO_MIXER_LAST
;
1003 dip
->un
.v
.num_channels
= 1;
1004 strcpy(dip
->un
.v
.units
.name
, AudioNtreble
);
1008 case AWACS_INPUT_SELECT
:
1009 dip
->mixer_class
= AWACS_RECORD_CLASS
;
1010 strcpy(dip
->label
.name
, AudioNsource
);
1011 dip
->type
= AUDIO_MIXER_SET
;
1012 dip
->prev
= dip
->next
= AUDIO_MIXER_LAST
;
1013 dip
->un
.s
.num_mem
= 3;
1014 strcpy(dip
->un
.s
.member
[0].label
.name
, AudioNcd
);
1015 dip
->un
.s
.member
[0].mask
= 1 << 0;
1016 strcpy(dip
->un
.s
.member
[1].label
.name
, AudioNmicrophone
);
1017 dip
->un
.s
.member
[1].mask
= 1 << 1;
1018 strcpy(dip
->un
.s
.member
[2].label
.name
, AudioNline
);
1019 dip
->un
.s
.member
[2].mask
= 1 << 2;
1022 case AWACS_VOL_INPUT
:
1023 dip
->mixer_class
= AWACS_RECORD_CLASS
;
1024 strcpy(dip
->label
.name
, AudioNrecord
);
1025 dip
->type
= AUDIO_MIXER_VALUE
;
1026 dip
->prev
= dip
->next
= AUDIO_MIXER_LAST
;
1027 dip
->un
.v
.num_channels
= 2;
1028 strcpy(dip
->un
.v
.units
.name
, AudioNvolume
);
1031 case AWACS_MONITOR_CLASS
:
1032 dip
->mixer_class
= AWACS_MONITOR_CLASS
;
1033 strcpy(dip
->label
.name
, AudioCmonitor
);
1034 dip
->type
= AUDIO_MIXER_CLASS
;
1035 dip
->next
= dip
->prev
= AUDIO_MIXER_LAST
;
1038 case AWACS_OUTPUT_CLASS
:
1039 dip
->mixer_class
= AWACS_OUTPUT_CLASS
;
1040 strcpy(dip
->label
.name
, AudioCoutputs
);
1041 dip
->type
= AUDIO_MIXER_CLASS
;
1042 dip
->next
= dip
->prev
= AUDIO_MIXER_LAST
;
1045 case AWACS_RECORD_CLASS
:
1046 dip
->mixer_class
= AWACS_RECORD_CLASS
;
1047 strcpy(dip
->label
.name
, AudioCrecord
);
1048 dip
->type
= AUDIO_MIXER_CLASS
;
1049 dip
->next
= dip
->prev
= AUDIO_MIXER_LAST
;
1057 awacs_round_buffersize(void *h
, int dir
, size_t size
)
1066 awacs_mappage(void *h
, void *mem
, off_t off
, int prot
)
1071 return -1; /* XXX */
1075 awacs_get_props(void *h
)
1077 return AUDIO_PROP_FULLDUPLEX
/* | AUDIO_PROP_MMAP */;
1081 awacs_trigger_output(void *h
, void *start
, void *end
, int bsize
,
1082 void (*intr
)(void *), void *arg
,
1083 const audio_params_t
*param
)
1085 struct awacs_softc
*sc
;
1086 struct dbdma_command
*cmd
;
1088 int i
, len
, intmode
;
1090 DPRINTF("trigger_output %p %p 0x%x\n", start
, end
, bsize
);
1092 cmd
= sc
->sc_odmacmd
;
1093 sc
->sc_ointr
= intr
;
1095 sc
->sc_opages
= ((char *)end
- (char *)start
) / PAGE_SIZE
;
1098 if (sc
->sc_opages
> 16)
1099 panic("awacs_trigger_output");
1102 va
= (vaddr_t
)start
;
1104 for (i
= sc
->sc_opages
; i
> 0; i
--) {
1107 intmode
= DBDMA_INT_NEVER
;
1110 intmode
= DBDMA_INT_ALWAYS
;
1113 DBDMA_BUILD(cmd
, DBDMA_CMD_OUT_MORE
, 0, PAGE_SIZE
, vtophys(va
),
1114 intmode
, DBDMA_WAIT_NEVER
, DBDMA_BRANCH_NEVER
);
1119 DBDMA_BUILD(cmd
, DBDMA_CMD_NOP
, 0, 0, 0,
1120 DBDMA_INT_NEVER
, DBDMA_WAIT_NEVER
, DBDMA_BRANCH_ALWAYS
);
1121 out32rb(&cmd
->d_cmddep
, vtophys((vaddr_t
)sc
->sc_odmacmd
));
1123 dbdma_start(sc
->sc_odma
, sc
->sc_odmacmd
);
1129 awacs_trigger_input(void *h
, void *start
, void *end
, int bsize
,
1130 void (*intr
)(void *), void *arg
,
1131 const audio_params_t
*param
)
1134 DPRINTF("awacs_trigger_input called\n");
1139 awacs_select_output(struct awacs_softc
*sc
, int mask
)
1143 if (sc
->sc_sgsmix
) {
1144 if (mask
& OUTPUT_HEADPHONES
) {
1146 sgsmix_set_speaker_vol(sc
->sc_sgsmix
, 0, 0);
1147 sgsmix_set_headphone_vol(sc
->sc_sgsmix
,
1148 sc
->vol_l
, sc
->vol_r
);
1150 if (mask
& OUTPUT_SPEAKER
) {
1151 /* mute headphones */
1152 sgsmix_set_speaker_vol(sc
->sc_sgsmix
,
1153 sc
->vol_l
, sc
->vol_r
);
1154 sgsmix_set_headphone_vol(sc
->sc_sgsmix
, 0, 0);
1158 sc
->sc_codecctl1
|= AWACS_MUTE_SPEAKER
| AWACS_MUTE_HEADPHONE
;
1159 if ((sc
->vol_l
> 0) || (sc
->vol_r
> 0)) {
1160 if (mask
& OUTPUT_SPEAKER
)
1161 sc
->sc_codecctl1
&= ~AWACS_MUTE_SPEAKER
;
1162 if (mask
& OUTPUT_HEADPHONES
)
1163 sc
->sc_codecctl1
&= ~AWACS_MUTE_HEADPHONE
;
1165 awacs_write_codec(sc
, sc
->sc_codecctl1
);
1169 sc
->sc_output_mask
= mask
;
1173 awacs_set_speaker_volume(struct awacs_softc
*sc
, int left
, int right
)
1177 if (sc
->sc_sgsmix
) {
1178 if (sc
->sc_output_mask
& OUTPUT_SPEAKER
)
1179 sgsmix_set_speaker_vol(sc
->sc_sgsmix
, left
, right
);
1185 uint32_t codecctl
= sc
->sc_codecctl1
;
1187 lval
= 15 - ((left
& 0xf0) >> 4);
1188 rval
= 15 - ((right
& 0xf0) >> 4);
1189 DPRINTF("speaker_volume %d %d\n", lval
, rval
);
1191 sc
->sc_codecctl4
&= ~0x3cf;
1192 sc
->sc_codecctl4
|= (lval
<< 6) | rval
;
1193 awacs_write_codec(sc
, sc
->sc_codecctl4
);
1194 if ((left
== 0) && (right
== 0)) {
1196 * max. attenuation doesn't mean silence so we need to
1197 * mute the output channel here
1199 codecctl
|= AWACS_MUTE_SPEAKER
;
1200 } else if (sc
->sc_output_mask
& OUTPUT_SPEAKER
) {
1201 codecctl
&= ~AWACS_MUTE_SPEAKER
;
1204 if (codecctl
!= sc
->sc_codecctl1
) {
1206 sc
->sc_codecctl1
= codecctl
;
1207 awacs_write_codec(sc
, sc
->sc_codecctl1
);
1213 awacs_set_ext_volume(struct awacs_softc
*sc
, int left
, int right
)
1217 if (sc
->sc_sgsmix
) {
1218 if (sc
->sc_output_mask
& OUTPUT_HEADPHONES
)
1219 sgsmix_set_headphone_vol(sc
->sc_sgsmix
, left
, right
);
1225 uint32_t codecctl
= sc
->sc_codecctl1
;
1227 lval
= 15 - ((left
& 0xf0) >> 4);
1228 rval
= 15 - ((right
& 0xf0) >> 4);
1229 DPRINTF("ext_volume %d %d\n", lval
, rval
);
1231 sc
->sc_codecctl2
&= ~0x3cf;
1232 sc
->sc_codecctl2
|= (lval
<< 6) | rval
;
1233 awacs_write_codec(sc
, sc
->sc_codecctl2
);
1235 if ((left
== 0) && (right
== 0)) {
1237 * max. attenuation doesn't mean silence so we need to
1238 * mute the output channel here
1240 codecctl
|= AWACS_MUTE_HEADPHONE
;
1241 } else if (sc
->sc_output_mask
& OUTPUT_HEADPHONES
) {
1243 codecctl
&= ~AWACS_MUTE_HEADPHONE
;
1246 if (codecctl
!= sc
->sc_codecctl1
) {
1248 sc
->sc_codecctl1
= codecctl
;
1249 awacs_write_codec(sc
, sc
->sc_codecctl1
);
1255 awacs_set_volume(struct awacs_softc
*sc
, int left
, int right
)
1258 awacs_set_ext_volume(sc
, left
, right
);
1259 awacs_set_speaker_volume(sc
, left
, right
);
1267 awacs_set_bass(struct awacs_softc
*sc
, int bass
)
1270 if (sc
->sc_bass
== bass
)
1275 sgsmix_set_bass_treble(sc
->sc_sgsmix
, sc
->sc_bass
,
1280 awacs_set_treble(struct awacs_softc
*sc
, int treble
)
1283 if (sc
->sc_treble
== treble
)
1286 sc
->sc_treble
= treble
;
1288 sgsmix_set_bass_treble(sc
->sc_sgsmix
, sc
->sc_bass
,
1294 awacs_set_loopthrough_volume(struct awacs_softc
*sc
, int left
, int right
)
1299 lval
= 15 - ((left
& 0xff) >> 4);
1300 rval
= 15 - ((right
& 0xff) >> 4);
1301 DPRINTF("loopthrough_volume %d %d\n", lval
, rval
);
1303 sc
->sc_codecctl5
&= ~0x3cf;
1304 sc
->sc_codecctl5
|= (lval
<< 6) | rval
;
1305 awacs_write_codec(sc
, sc
->sc_codecctl5
);
1309 awacs_set_rate(struct awacs_softc
*sc
, const audio_params_t
*p
)
1313 switch (p
->sample_rate
) {
1315 c
= AWACS_RATE_44100
;
1318 c
= AWACS_RATE_29400
;
1321 c
= AWACS_RATE_22050
;
1324 c
= AWACS_RATE_17640
;
1327 c
= AWACS_RATE_14700
;
1330 c
= AWACS_RATE_11025
;
1333 c
= AWACS_RATE_8820
;
1336 c
= AWACS_RATE_7350
;
1342 sc
->sc_soundctl
&= ~AWACS_RATE_MASK
;
1343 sc
->sc_soundctl
|= c
;
1344 awacs_write_reg(sc
, AWACS_SOUND_CTRL
, sc
->sc_soundctl
);
1350 awacs_check_headphones(struct awacs_softc
*sc
)
1353 reg
= awacs_read_reg(sc
, AWACS_CODEC_STATUS
);
1354 DPRINTF("%s: codec status reg %08x\n", device_xname(sc
->sc_dev
), reg
);
1355 return ((reg
& sc
->sc_headphones_mask
) == sc
->sc_headphones_in
);
1359 awacs_status_intr(void *cookie
)
1361 struct awacs_softc
*sc
= cookie
;
1364 mask
= awacs_check_headphones(sc
) ? OUTPUT_HEADPHONES
: OUTPUT_SPEAKER
;
1365 if (mask
!= sc
->sc_output_mask
) {
1367 sc
->sc_output_wanted
= mask
;
1368 wakeup(&sc
->sc_event
);
1370 /* clear the interrupt */
1371 awacs_write_reg(sc
, AWACS_SOUND_CTRL
, sc
->sc_soundctl
| AWACS_PORTCHG
);
1376 awacs_thread(void *cookie
)
1378 struct awacs_softc
*sc
= cookie
;
1381 tsleep(&sc
->sc_event
, PWAIT
, "awacs_wait", hz
);
1382 if (sc
->sc_output_wanted
== sc
->sc_output_mask
)
1385 awacs_select_output(sc
, sc
->sc_output_wanted
);
1386 DPRINTF("%s: switching to %s\n", device_xname(sc
->sc_dev
),
1387 (sc
->sc_output_wanted
& OUTPUT_SPEAKER
) ?
1388 "speaker" : "headphones");