1 /* $NetBSD: harmony.c,v 1.16 2009/05/07 15:34:49 skrll Exp $ */
3 /* $OpenBSD: harmony.c,v 1.23 2004/02/13 21:28:19 mickey Exp $ */
6 * Copyright (c) 2009 The NetBSD Foundation, Inc.
9 * This code is derived from software contributed to The NetBSD Foundation
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
35 * Copyright (c) 2003 Jason L. Wright (jason@thought.net)
36 * All rights reserved.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
48 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
49 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
50 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
51 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
52 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
53 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
55 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
56 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
57 * POSSIBILITY OF SUCH DAMAGE.
61 * Harmony (CS4215/AD1849 LASI) audio interface.
66 #include <sys/param.h>
67 #include <sys/kernel.h>
68 #include <sys/systm.h>
69 #include <sys/errno.h>
70 #include <sys/ioctl.h>
71 #include <sys/device.h>
73 #include <sys/malloc.h>
74 #include <uvm/uvm_extern.h>
80 #include <sys/audioio.h>
81 #include <dev/audio_if.h>
82 #include <dev/auconv.h>
84 #include <machine/cpu.h>
85 #include <machine/intr.h>
86 #include <machine/iomod.h>
87 #include <machine/autoconf.h>
88 #include <machine/bus.h>
90 #include <hp700/dev/cpudevs.h>
91 #include <hp700/gsc/gscbusvar.h>
92 #include <hp700/gsc/harmonyreg.h>
93 #include <hp700/gsc/harmonyvar.h>
95 int harmony_open(void *, int);
96 void harmony_close(void *);
97 int harmony_query_encoding(void *, struct audio_encoding
*);
98 int harmony_set_params(void *, int, int, audio_params_t
*,
99 audio_params_t
*, stream_filter_list_t
*, stream_filter_list_t
*);
100 int harmony_round_blocksize(void *, int, int, const audio_params_t
*);
101 int harmony_commit_settings(void *);
102 int harmony_halt_output(void *);
103 int harmony_halt_input(void *);
104 int harmony_getdev(void *, struct audio_device
*);
105 int harmony_set_port(void *, mixer_ctrl_t
*);
106 int harmony_get_port(void *, mixer_ctrl_t
*);
107 int harmony_query_devinfo(void *, mixer_devinfo_t
*);
108 void * harmony_allocm(void *, int, size_t, struct malloc_type
*, int);
109 void harmony_freem(void *, void *, struct malloc_type
*);
110 size_t harmony_round_buffersize(void *, int, size_t);
111 int harmony_get_props(void *);
112 int harmony_trigger_output(void *, void *, void *, int,
113 void (*)(void *), void *, const audio_params_t
*);
114 int harmony_trigger_input(void *, void *, void *, int,
115 void (*)(void *), void *, const audio_params_t
*);
117 const struct audio_hw_if harmony_sa_hw_if
= {
121 harmony_query_encoding
,
123 harmony_round_blocksize
,
124 harmony_commit_settings
,
136 harmony_query_devinfo
,
139 harmony_round_buffersize
,
142 harmony_trigger_output
,
143 harmony_trigger_input
,
146 int harmony_match(device_t
, struct cfdata
*, void *);
147 void harmony_attach(device_t
, device_t
, void *);
150 CFATTACH_DECL_NEW(harmony
, sizeof(struct harmony_softc
),
151 harmony_match
, harmony_attach
, NULL
, NULL
);
153 int harmony_intr(void *);
154 void harmony_intr_enable(struct harmony_softc
*);
155 void harmony_intr_disable(struct harmony_softc
*);
156 uint32_t harmony_speed_bits(struct harmony_softc
*, u_int
*);
157 int harmony_set_gainctl(struct harmony_softc
*);
158 void harmony_reset_codec(struct harmony_softc
*);
159 void harmony_start_cp(struct harmony_softc
*, int);
160 void harmony_start_pp(struct harmony_softc
*, int);
161 void harmony_tick_pb(void *);
162 void harmony_tick_cp(void *);
163 void harmony_try_more(struct harmony_softc
*, int, int,
164 struct harmony_channel
*);
165 static void harmony_empty_input(struct harmony_softc
*);
166 static void harmony_empty_output(struct harmony_softc
*);
169 void harmony_acc_tmo(void *);
170 #define ADD_CLKALLICA(sc) do { \
171 (sc)->sc_acc <<= 1; \
172 (sc)->sc_acc |= READ_REG((sc), HARMONY_DIAG) & DIAG_CO; \
173 if ((sc)->sc_acc_cnt++ && !((sc)->sc_acc_cnt % 32)) \
174 rnd_add_uint32(&(sc)->sc_rnd_source, \
175 (sc)->sc_acc_num ^= (sc)->sc_acc); \
180 harmony_match(device_t parent
, struct cfdata
*match
, void *aux
)
182 struct gsc_attach_args
*ga
;
185 if (ga
->ga_type
.iodc_type
== HPPA_TYPE_FIO
) {
186 if (ga
->ga_type
.iodc_sv_model
== HPPA_FIO_A1
||
187 ga
->ga_type
.iodc_sv_model
== HPPA_FIO_A2NB
||
188 ga
->ga_type
.iodc_sv_model
== HPPA_FIO_A1NB
||
189 ga
->ga_type
.iodc_sv_model
== HPPA_FIO_A2
)
196 harmony_attach(device_t parent
, device_t self
, void *aux
)
198 struct harmony_softc
*sc
= device_private(self
);
199 struct gsc_attach_args
*ga
;
206 sc
->sc_bt
= ga
->ga_iot
;
207 sc
->sc_dmat
= ga
->ga_dmatag
;
209 if (bus_space_map(sc
->sc_bt
, ga
->ga_hpa
, HARMONY_NREGS
, 0,
211 aprint_error(": couldn't map registers\n");
215 cntl
= READ_REG(sc
, HARMONY_ID
);
216 switch ((cntl
& ID_REV_MASK
)) {
218 sc
->sc_teleshare
= 1;
222 aprint_error(": unknown id == 0x%02x\n",
223 (cntl
& ID_REV_MASK
) >> ID_REV_SHIFT
);
224 bus_space_unmap(sc
->sc_bt
, sc
->sc_bh
, HARMONY_NREGS
);
228 if (bus_dmamem_alloc(sc
->sc_dmat
, sizeof(struct harmony_empty
),
229 PAGE_SIZE
, 0, &sc
->sc_empty_seg
, 1, &sc
->sc_empty_rseg
,
230 BUS_DMA_NOWAIT
) != 0) {
231 aprint_error(": could not alloc DMA memory\n");
232 bus_space_unmap(sc
->sc_bt
, sc
->sc_bh
, HARMONY_NREGS
);
235 if (bus_dmamem_map(sc
->sc_dmat
, &sc
->sc_empty_seg
, 1,
236 sizeof(struct harmony_empty
), (void **)&sc
->sc_empty_kva
,
237 BUS_DMA_NOWAIT
) != 0) {
238 aprint_error(": couldn't map DMA memory\n");
239 bus_dmamem_free(sc
->sc_dmat
, &sc
->sc_empty_seg
,
241 bus_space_unmap(sc
->sc_bt
, sc
->sc_bh
, HARMONY_NREGS
);
244 if (bus_dmamap_create(sc
->sc_dmat
, sizeof(struct harmony_empty
), 1,
245 sizeof(struct harmony_empty
), 0, BUS_DMA_NOWAIT
,
246 &sc
->sc_empty_map
) != 0) {
247 aprint_error(": can't create DMA map\n");
248 bus_dmamem_unmap(sc
->sc_dmat
, (void *)sc
->sc_empty_kva
,
249 sizeof(struct harmony_empty
));
250 bus_dmamem_free(sc
->sc_dmat
, &sc
->sc_empty_seg
,
252 bus_space_unmap(sc
->sc_bt
, sc
->sc_bh
, HARMONY_NREGS
);
255 if (bus_dmamap_load(sc
->sc_dmat
, sc
->sc_empty_map
, sc
->sc_empty_kva
,
256 sizeof(struct harmony_empty
), NULL
, BUS_DMA_NOWAIT
) != 0) {
257 aprint_error(": can't load DMA map\n");
258 bus_dmamap_destroy(sc
->sc_dmat
, sc
->sc_empty_map
);
259 bus_dmamem_unmap(sc
->sc_dmat
, (void *)sc
->sc_empty_kva
,
260 sizeof(struct harmony_empty
));
261 bus_dmamem_free(sc
->sc_dmat
, &sc
->sc_empty_seg
,
263 bus_space_unmap(sc
->sc_bt
, sc
->sc_bh
, HARMONY_NREGS
);
267 sc
->sc_playback_empty
= 0;
268 for (i
= 0; i
< PLAYBACK_EMPTYS
; i
++)
269 sc
->sc_playback_paddrs
[i
] =
270 sc
->sc_empty_map
->dm_segs
[0].ds_addr
+
271 offsetof(struct harmony_empty
, playback
[i
][0]);
273 sc
->sc_capture_empty
= 0;
274 for (i
= 0; i
< CAPTURE_EMPTYS
; i
++)
275 sc
->sc_capture_paddrs
[i
] =
276 sc
->sc_empty_map
->dm_segs
[0].ds_addr
+
277 offsetof(struct harmony_empty
, capture
[i
][0]);
279 bus_dmamap_sync(sc
->sc_dmat
, sc
->sc_empty_map
,
280 offsetof(struct harmony_empty
, playback
[0][0]),
281 PLAYBACK_EMPTYS
* HARMONY_BUFSIZE
, BUS_DMASYNC_PREWRITE
);
283 (void) hp700_intr_establish(sc
->sc_dv
, IPL_AUDIO
,
284 harmony_intr
, sc
, ga
->ga_int_reg
, ga
->ga_irq
);
287 sc
->sc_in_port
= HARMONY_IN_LINE
;
288 sc
->sc_out_port
= HARMONY_OUT_SPEAKER
;
289 sc
->sc_input_lvl
.left
= sc
->sc_input_lvl
.right
= 240;
290 sc
->sc_output_lvl
.left
= sc
->sc_output_lvl
.right
= 244;
291 sc
->sc_monitor_lvl
.left
= sc
->sc_monitor_lvl
.right
= 208;
292 sc
->sc_outputgain
= 0;
294 /* reset chip, and push default gain controls */
295 harmony_reset_codec(sc
);
297 cntl
= READ_REG(sc
, HARMONY_CNTL
);
298 rev
= (cntl
& CNTL_CODEC_REV_MASK
) >> CNTL_CODEC_REV_SHIFT
;
299 aprint_normal(": rev %u", rev
);
301 if (sc
->sc_teleshare
)
302 printf(", teleshare");
305 if ((rev
& CS4215_REV_VER
) >= CS4215_REV_VER_E
)
306 sc
->sc_hasulinear8
= 1;
308 strlcpy(sc
->sc_audev
.name
, ga
->ga_name
, sizeof(sc
->sc_audev
.name
));
309 snprintf(sc
->sc_audev
.version
, sizeof sc
->sc_audev
.version
,
310 "%u.%u;%u", ga
->ga_type
.iodc_sv_rev
,
311 ga
->ga_type
.iodc_model
, ga
->ga_type
.iodc_revision
);
312 strlcpy(sc
->sc_audev
.config
, device_xname(sc
->sc_dv
),
313 sizeof(sc
->sc_audev
.config
));
315 audio_attach_mi(&harmony_sa_hw_if
, sc
, sc
->sc_dv
);
318 rnd_attach_source(&sc
->sc_rnd_source
, device_xname(sc
->sc_dv
),
319 RND_TYPE_UNKNOWN
, 0);
321 callout_init(&sc
->sc_acc_tmo
, 0);
322 callout_setfunc(&sc
->sc_acc_tmo
, harmony_acc_tmo
, sc
);
323 sc
->sc_acc_num
= 0xa5a5a5a5;
328 harmony_reset_codec(struct harmony_softc
*sc
)
332 WRITE_REG(sc
, HARMONY_GAINCTL
, GAINCTL_OUTPUT_LEFT_M
|
333 GAINCTL_OUTPUT_RIGHT_M
| GAINCTL_MONITOR_M
);
336 WRITE_REG(sc
, HARMONY_RESET
, RESET_RST
);
338 DELAY(100000); /* wait at least 0.05 sec */
340 harmony_set_gainctl(sc
);
341 WRITE_REG(sc
, HARMONY_RESET
, 0);
346 harmony_acc_tmo(void *v
)
348 struct harmony_softc
*sc
;
352 callout_schedule(&sc
->sc_acc_tmo
, 1);
360 harmony_intr(void *vsc
)
362 struct harmony_softc
*sc
;
372 harmony_intr_disable(sc
);
374 dstatus
= READ_REG(sc
, HARMONY_DSTATUS
);
376 if (dstatus
& DSTATUS_PN
) {
378 harmony_start_pp(sc
, 0);
381 if (dstatus
& DSTATUS_RN
) {
383 harmony_start_cp(sc
, 0);
386 if (READ_REG(sc
, HARMONY_OV
) & OV_OV
) {
388 WRITE_REG(sc
, HARMONY_OV
, 0);
392 harmony_intr_enable(sc
);
398 harmony_intr_enable(struct harmony_softc
*sc
)
401 WRITE_REG(sc
, HARMONY_DSTATUS
, DSTATUS_IE
);
402 SYNC_REG(sc
, HARMONY_DSTATUS
, BUS_SPACE_BARRIER_WRITE
);
406 harmony_intr_disable(struct harmony_softc
*sc
)
409 WRITE_REG(sc
, HARMONY_DSTATUS
, 0);
410 SYNC_REG(sc
, HARMONY_DSTATUS
, BUS_SPACE_BARRIER_WRITE
);
414 harmony_open(void *vsc
, int flags
)
416 struct harmony_softc
*sc
;
426 harmony_close(void *vsc
)
428 struct harmony_softc
*sc
;
431 harmony_halt_input(sc
);
432 harmony_halt_output(sc
);
433 harmony_intr_disable(sc
);
438 harmony_query_encoding(void *vsc
, struct audio_encoding
*fp
)
440 struct harmony_softc
*sc
;
447 strlcpy(fp
->name
, AudioEmulaw
, sizeof fp
->name
);
448 fp
->encoding
= AUDIO_ENCODING_ULAW
;
453 strlcpy(fp
->name
, AudioEalaw
, sizeof fp
->name
);
454 fp
->encoding
= AUDIO_ENCODING_ALAW
;
459 strlcpy(fp
->name
, AudioEslinear_be
, sizeof fp
->name
);
460 fp
->encoding
= AUDIO_ENCODING_SLINEAR_BE
;
465 strlcpy(fp
->name
, AudioEslinear_le
, sizeof fp
->name
);
466 fp
->encoding
= AUDIO_ENCODING_SLINEAR_LE
;
468 fp
->flags
= AUDIO_ENCODINGFLAG_EMULATED
;
471 strlcpy(fp
->name
, AudioEulinear_be
, sizeof fp
->name
);
472 fp
->encoding
= AUDIO_ENCODING_ULINEAR_BE
;
474 fp
->flags
= AUDIO_ENCODINGFLAG_EMULATED
;
477 strlcpy(fp
->name
, AudioEulinear_le
, sizeof fp
->name
);
478 fp
->encoding
= AUDIO_ENCODING_ULINEAR_LE
;
480 fp
->flags
= AUDIO_ENCODINGFLAG_EMULATED
;
483 if (sc
->sc_hasulinear8
) {
484 strlcpy(fp
->name
, AudioEulinear
, sizeof fp
->name
);
485 fp
->encoding
= AUDIO_ENCODING_ULINEAR
;
492 if (sc
->sc_hasulinear8
) {
493 strlcpy(fp
->name
, AudioEslinear
, sizeof fp
->name
);
494 fp
->encoding
= AUDIO_ENCODING_SLINEAR
;
496 fp
->flags
= AUDIO_ENCODINGFLAG_EMULATED
;
507 harmony_set_params(void *vsc
, int setmode
, int usemode
,
508 audio_params_t
*p
, audio_params_t
*r
,
509 stream_filter_list_t
*pfil
, stream_filter_list_t
*rfil
)
512 struct harmony_softc
*sc
;
514 stream_filter_factory_t
*pswcode
= NULL
;
515 stream_filter_factory_t
*rswcode
= NULL
;
518 /* assume p.equals(r) */
520 switch (p
->encoding
) {
521 case AUDIO_ENCODING_ULAW
:
522 if (p
->precision
!= 8)
524 bits
= CNTL_FORMAT_ULAW
;
526 case AUDIO_ENCODING_ALAW
:
527 if (p
->precision
!= 8)
529 bits
= CNTL_FORMAT_ALAW
;
531 case AUDIO_ENCODING_SLINEAR_BE
:
532 if (p
->precision
== 8) {
533 bits
= CNTL_FORMAT_ULINEAR8
;
534 hw
.encoding
= AUDIO_ENCODING_ULINEAR_LE
;
535 rswcode
= pswcode
= change_sign8
;
538 if (p
->precision
== 16) {
539 bits
= CNTL_FORMAT_SLINEAR16BE
;
543 case AUDIO_ENCODING_ULINEAR
:
544 if (p
->precision
!= 8)
546 bits
= CNTL_FORMAT_ULINEAR8
;
548 case AUDIO_ENCODING_SLINEAR
:
549 if (p
->precision
!= 8)
551 bits
= CNTL_FORMAT_ULINEAR8
;
552 hw
.encoding
= AUDIO_ENCODING_ULINEAR_LE
;
553 rswcode
= pswcode
= change_sign8
;
555 case AUDIO_ENCODING_SLINEAR_LE
:
556 if (p
->precision
== 8) {
557 bits
= CNTL_FORMAT_ULINEAR8
;
558 hw
.encoding
= AUDIO_ENCODING_ULINEAR_LE
;
559 rswcode
= pswcode
= change_sign8
;
562 if (p
->precision
== 16) {
563 bits
= CNTL_FORMAT_SLINEAR16BE
;
564 hw
.encoding
= AUDIO_ENCODING_SLINEAR_BE
;
565 rswcode
= pswcode
= swap_bytes
;
569 case AUDIO_ENCODING_ULINEAR_BE
:
570 if (p
->precision
== 8) {
571 bits
= CNTL_FORMAT_ULINEAR8
;
574 if (p
->precision
== 16) {
575 bits
= CNTL_FORMAT_SLINEAR16BE
;
576 rswcode
= pswcode
= change_sign16
;
580 case AUDIO_ENCODING_ULINEAR_LE
:
581 if (p
->precision
== 8) {
582 bits
= CNTL_FORMAT_ULINEAR8
;
585 if (p
->precision
== 16) {
586 bits
= CNTL_FORMAT_SLINEAR16BE
;
587 hw
.encoding
= AUDIO_ENCODING_SLINEAR_BE
;
588 rswcode
= pswcode
= swap_bytes_change_sign16
;
596 if (sc
->sc_outputgain
)
599 if (p
->channels
== 1)
600 bits
|= CNTL_CHANS_MONO
;
601 else if (p
->channels
== 2)
602 bits
|= CNTL_CHANS_STEREO
;
606 bits
|= harmony_speed_bits(sc
, &p
->sample_rate
);
608 pfil
->append(pfil
, pswcode
, &hw
);
610 rfil
->append(rfil
, rswcode
, &hw
);
611 sc
->sc_cntlbits
= bits
;
612 sc
->sc_need_commit
= 1;
618 harmony_round_blocksize(void *vsc
, int blk
,
619 int mode
, const audio_params_t
*param
)
622 return HARMONY_BUFSIZE
;
626 harmony_commit_settings(void *vsc
)
628 struct harmony_softc
*sc
;
634 if (sc
->sc_need_commit
== 0)
637 harmony_intr_disable(sc
);
640 reg
= READ_REG(sc
, HARMONY_DSTATUS
);
641 if ((reg
& (DSTATUS_PC
| DSTATUS_RC
)) == 0)
645 /* Setting some bits in gainctl requires a reset */
646 harmony_reset_codec(sc
);
648 /* set the silence character based on the encoding type */
649 bus_dmamap_sync(sc
->sc_dmat
, sc
->sc_empty_map
,
650 offsetof(struct harmony_empty
, playback
[0][0]),
651 PLAYBACK_EMPTYS
* HARMONY_BUFSIZE
, BUS_DMASYNC_POSTWRITE
);
652 switch (sc
->sc_cntlbits
& CNTL_FORMAT_MASK
) {
653 case CNTL_FORMAT_ULAW
:
656 case CNTL_FORMAT_ALAW
:
659 case CNTL_FORMAT_SLINEAR16BE
:
660 case CNTL_FORMAT_ULINEAR8
:
665 for (i
= 0; i
< PLAYBACK_EMPTYS
; i
++)
666 memset(&sc
->sc_empty_kva
->playback
[i
][0],
667 quietchar
, HARMONY_BUFSIZE
);
668 bus_dmamap_sync(sc
->sc_dmat
, sc
->sc_empty_map
,
669 offsetof(struct harmony_empty
, playback
[0][0]),
670 PLAYBACK_EMPTYS
* HARMONY_BUFSIZE
, BUS_DMASYNC_PREWRITE
);
673 /* Wait for it to come out of control mode */
674 reg
= READ_REG(sc
, HARMONY_CNTL
);
675 if ((reg
& CNTL_C
) == 0)
679 bus_space_write_4(sc
->sc_bt
, sc
->sc_bh
, HARMONY_CNTL
,
680 sc
->sc_cntlbits
| CNTL_C
);
683 /* Wait for it to come out of control mode */
684 reg
= READ_REG(sc
, HARMONY_CNTL
);
685 if ((reg
& CNTL_C
) == 0)
689 sc
->sc_need_commit
= 0;
691 if (sc
->sc_playing
|| sc
->sc_capturing
)
692 harmony_intr_enable(sc
);
698 harmony_empty_output(struct harmony_softc
*sc
)
701 WRITE_REG(sc
, HARMONY_PNXTADD
,
702 sc
->sc_playback_paddrs
[sc
->sc_playback_empty
]);
703 SYNC_REG(sc
, HARMONY_PNXTADD
, BUS_SPACE_BARRIER_WRITE
);
705 if (++sc
->sc_playback_empty
== PLAYBACK_EMPTYS
)
706 sc
->sc_playback_empty
= 0;
710 harmony_halt_output(void *vsc
)
712 struct harmony_softc
*sc
;
717 harmony_empty_output(sc
);
722 harmony_empty_input(struct harmony_softc
*sc
)
725 WRITE_REG(sc
, HARMONY_RNXTADD
,
726 sc
->sc_capture_paddrs
[sc
->sc_capture_empty
]);
727 SYNC_REG(sc
, HARMONY_RNXTADD
, BUS_SPACE_BARRIER_WRITE
);
729 if (++sc
->sc_capture_empty
== CAPTURE_EMPTYS
)
730 sc
->sc_capture_empty
= 0;
734 harmony_halt_input(void *vsc
)
736 struct harmony_softc
*sc
;
739 sc
->sc_capturing
= 0;
741 harmony_empty_input(sc
);
746 harmony_getdev(void *vsc
, struct audio_device
*retp
)
748 struct harmony_softc
*sc
;
751 *retp
= sc
->sc_audev
;
756 harmony_set_port(void *vsc
, mixer_ctrl_t
*cp
)
758 struct harmony_softc
*sc
;
764 case HARMONY_PORT_INPUT_LVL
:
765 if (cp
->type
!= AUDIO_MIXER_VALUE
)
767 if (cp
->un
.value
.num_channels
== 1)
768 sc
->sc_input_lvl
.left
= sc
->sc_input_lvl
.right
=
769 cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_MONO
];
770 else if (cp
->un
.value
.num_channels
== 2) {
771 sc
->sc_input_lvl
.left
=
772 cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_LEFT
];
773 sc
->sc_input_lvl
.right
=
774 cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_RIGHT
];
777 sc
->sc_need_commit
= 1;
780 case HARMONY_PORT_OUTPUT_LVL
:
781 if (cp
->type
!= AUDIO_MIXER_VALUE
)
783 if (cp
->un
.value
.num_channels
== 1)
784 sc
->sc_output_lvl
.left
= sc
->sc_output_lvl
.right
=
785 cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_MONO
];
786 else if (cp
->un
.value
.num_channels
== 2) {
787 sc
->sc_output_lvl
.left
=
788 cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_LEFT
];
789 sc
->sc_output_lvl
.right
=
790 cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_RIGHT
];
793 sc
->sc_need_commit
= 1;
796 case HARMONY_PORT_OUTPUT_GAIN
:
797 if (cp
->type
!= AUDIO_MIXER_ENUM
)
799 sc
->sc_outputgain
= cp
->un
.ord
? 1 : 0;
802 case HARMONY_PORT_MONITOR_LVL
:
803 if (cp
->type
!= AUDIO_MIXER_VALUE
)
805 if (cp
->un
.value
.num_channels
!= 1)
807 sc
->sc_monitor_lvl
.left
= sc
->sc_input_lvl
.right
=
808 cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_MONO
];
809 sc
->sc_need_commit
= 1;
812 case HARMONY_PORT_RECORD_SOURCE
:
813 if (cp
->type
!= AUDIO_MIXER_ENUM
)
815 if (cp
->un
.ord
!= HARMONY_IN_LINE
&&
816 cp
->un
.ord
!= HARMONY_IN_MIC
)
818 sc
->sc_in_port
= cp
->un
.ord
;
820 sc
->sc_need_commit
= 1;
822 case HARMONY_PORT_OUTPUT_SOURCE
:
823 if (cp
->type
!= AUDIO_MIXER_ENUM
)
825 if (cp
->un
.ord
!= HARMONY_OUT_LINE
&&
826 cp
->un
.ord
!= HARMONY_OUT_SPEAKER
&&
827 cp
->un
.ord
!= HARMONY_OUT_HEADPHONE
)
829 sc
->sc_out_port
= cp
->un
.ord
;
831 sc
->sc_need_commit
= 1;
839 harmony_get_port(void *vsc
, mixer_ctrl_t
*cp
)
841 struct harmony_softc
*sc
;
847 case HARMONY_PORT_INPUT_LVL
:
848 if (cp
->type
!= AUDIO_MIXER_VALUE
)
850 if (cp
->un
.value
.num_channels
== 1) {
851 cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_MONO
] =
852 sc
->sc_input_lvl
.left
;
853 } else if (cp
->un
.value
.num_channels
== 2) {
854 cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_LEFT
] =
855 sc
->sc_input_lvl
.left
;
856 cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_RIGHT
] =
857 sc
->sc_input_lvl
.right
;
862 case HARMONY_PORT_INPUT_OV
:
863 if (cp
->type
!= AUDIO_MIXER_ENUM
)
865 cp
->un
.ord
= sc
->sc_ov
? 1 : 0;
868 case HARMONY_PORT_OUTPUT_LVL
:
869 if (cp
->type
!= AUDIO_MIXER_VALUE
)
871 if (cp
->un
.value
.num_channels
== 1) {
872 cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_MONO
] =
873 sc
->sc_output_lvl
.left
;
874 } else if (cp
->un
.value
.num_channels
== 2) {
875 cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_LEFT
] =
876 sc
->sc_output_lvl
.left
;
877 cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_RIGHT
] =
878 sc
->sc_output_lvl
.right
;
883 case HARMONY_PORT_OUTPUT_GAIN
:
884 if (cp
->type
!= AUDIO_MIXER_ENUM
)
886 cp
->un
.ord
= sc
->sc_outputgain
? 1 : 0;
889 case HARMONY_PORT_MONITOR_LVL
:
890 if (cp
->type
!= AUDIO_MIXER_VALUE
)
892 if (cp
->un
.value
.num_channels
!= 1)
894 cp
->un
.value
.level
[AUDIO_MIXER_LEVEL_MONO
] =
895 sc
->sc_monitor_lvl
.left
;
898 case HARMONY_PORT_RECORD_SOURCE
:
899 if (cp
->type
!= AUDIO_MIXER_ENUM
)
901 cp
->un
.ord
= sc
->sc_in_port
;
904 case HARMONY_PORT_OUTPUT_SOURCE
:
905 if (cp
->type
!= AUDIO_MIXER_ENUM
)
907 cp
->un
.ord
= sc
->sc_out_port
;
915 harmony_query_devinfo(void *vsc
, mixer_devinfo_t
*dip
)
920 switch (dip
->index
) {
921 case HARMONY_PORT_INPUT_LVL
:
922 dip
->type
= AUDIO_MIXER_VALUE
;
923 dip
->mixer_class
= HARMONY_PORT_INPUT_CLASS
;
924 dip
->prev
= dip
->next
= AUDIO_MIXER_LAST
;
925 strlcpy(dip
->label
.name
, AudioNinput
, sizeof dip
->label
.name
);
926 dip
->un
.v
.num_channels
= 2;
927 strlcpy(dip
->un
.v
.units
.name
, AudioNvolume
,
928 sizeof dip
->un
.v
.units
.name
);
930 case HARMONY_PORT_INPUT_OV
:
931 dip
->type
= AUDIO_MIXER_ENUM
;
932 dip
->mixer_class
= HARMONY_PORT_INPUT_CLASS
;
933 dip
->prev
= dip
->next
= AUDIO_MIXER_LAST
;
934 strlcpy(dip
->label
.name
, "overrange", sizeof dip
->label
.name
);
935 dip
->un
.e
.num_mem
= 2;
936 strlcpy(dip
->un
.e
.member
[0].label
.name
, AudioNoff
,
937 sizeof dip
->un
.e
.member
[0].label
.name
);
938 dip
->un
.e
.member
[0].ord
= 0;
939 strlcpy(dip
->un
.e
.member
[1].label
.name
, AudioNon
,
940 sizeof dip
->un
.e
.member
[1].label
.name
);
941 dip
->un
.e
.member
[1].ord
= 1;
943 case HARMONY_PORT_OUTPUT_LVL
:
944 dip
->type
= AUDIO_MIXER_VALUE
;
945 dip
->mixer_class
= HARMONY_PORT_OUTPUT_CLASS
;
946 dip
->prev
= dip
->next
= AUDIO_MIXER_LAST
;
947 strlcpy(dip
->label
.name
, AudioNoutput
, sizeof dip
->label
.name
);
948 dip
->un
.v
.num_channels
= 2;
949 strlcpy(dip
->un
.v
.units
.name
, AudioNvolume
,
950 sizeof dip
->un
.v
.units
.name
);
952 case HARMONY_PORT_OUTPUT_GAIN
:
953 dip
->type
= AUDIO_MIXER_ENUM
;
954 dip
->mixer_class
= HARMONY_PORT_OUTPUT_CLASS
;
955 dip
->prev
= dip
->next
= AUDIO_MIXER_LAST
;
956 strlcpy(dip
->label
.name
, "gain", sizeof dip
->label
.name
);
957 dip
->un
.e
.num_mem
= 2;
958 strlcpy(dip
->un
.e
.member
[0].label
.name
, AudioNoff
,
959 sizeof dip
->un
.e
.member
[0].label
.name
);
960 dip
->un
.e
.member
[0].ord
= 0;
961 strlcpy(dip
->un
.e
.member
[1].label
.name
, AudioNon
,
962 sizeof dip
->un
.e
.member
[1].label
.name
);
963 dip
->un
.e
.member
[1].ord
= 1;
965 case HARMONY_PORT_MONITOR_LVL
:
966 dip
->type
= AUDIO_MIXER_VALUE
;
967 dip
->mixer_class
= HARMONY_PORT_MONITOR_CLASS
;
968 dip
->prev
= dip
->next
= AUDIO_MIXER_LAST
;
969 strlcpy(dip
->label
.name
, AudioNmonitor
, sizeof dip
->label
.name
);
970 dip
->un
.v
.num_channels
= 1;
971 strlcpy(dip
->un
.v
.units
.name
, AudioNvolume
,
972 sizeof dip
->un
.v
.units
.name
);
974 case HARMONY_PORT_RECORD_SOURCE
:
975 dip
->type
= AUDIO_MIXER_ENUM
;
976 dip
->mixer_class
= HARMONY_PORT_RECORD_CLASS
;
977 dip
->prev
= dip
->next
= AUDIO_MIXER_LAST
;
978 strlcpy(dip
->label
.name
, AudioNsource
, sizeof dip
->label
.name
);
979 dip
->un
.e
.num_mem
= 2;
980 strlcpy(dip
->un
.e
.member
[0].label
.name
, AudioNmicrophone
,
981 sizeof dip
->un
.e
.member
[0].label
.name
);
982 dip
->un
.e
.member
[0].ord
= HARMONY_IN_MIC
;
983 strlcpy(dip
->un
.e
.member
[1].label
.name
, AudioNline
,
984 sizeof dip
->un
.e
.member
[1].label
.name
);
985 dip
->un
.e
.member
[1].ord
= HARMONY_IN_LINE
;
987 case HARMONY_PORT_OUTPUT_SOURCE
:
988 dip
->type
= AUDIO_MIXER_ENUM
;
989 dip
->mixer_class
= HARMONY_PORT_MONITOR_CLASS
;
990 dip
->prev
= dip
->next
= AUDIO_MIXER_LAST
;
991 strlcpy(dip
->label
.name
, AudioNoutput
, sizeof dip
->label
.name
);
992 dip
->un
.e
.num_mem
= 3;
993 strlcpy(dip
->un
.e
.member
[0].label
.name
, AudioNline
,
994 sizeof dip
->un
.e
.member
[0].label
.name
);
995 dip
->un
.e
.member
[0].ord
= HARMONY_OUT_LINE
;
996 strlcpy(dip
->un
.e
.member
[1].label
.name
, AudioNspeaker
,
997 sizeof dip
->un
.e
.member
[1].label
.name
);
998 dip
->un
.e
.member
[1].ord
= HARMONY_OUT_SPEAKER
;
999 strlcpy(dip
->un
.e
.member
[2].label
.name
, AudioNheadphone
,
1000 sizeof dip
->un
.e
.member
[2].label
.name
);
1001 dip
->un
.e
.member
[2].ord
= HARMONY_OUT_HEADPHONE
;
1003 case HARMONY_PORT_INPUT_CLASS
:
1004 dip
->type
= AUDIO_MIXER_CLASS
;
1005 dip
->mixer_class
= HARMONY_PORT_INPUT_CLASS
;
1006 dip
->prev
= dip
->next
= AUDIO_MIXER_LAST
;
1007 strlcpy(dip
->label
.name
, AudioCinputs
, sizeof dip
->label
.name
);
1009 case HARMONY_PORT_OUTPUT_CLASS
:
1010 dip
->type
= AUDIO_MIXER_CLASS
;
1011 dip
->mixer_class
= HARMONY_PORT_INPUT_CLASS
;
1012 dip
->prev
= dip
->next
= AUDIO_MIXER_LAST
;
1013 strlcpy(dip
->label
.name
, AudioCoutputs
, sizeof dip
->label
.name
);
1015 case HARMONY_PORT_MONITOR_CLASS
:
1016 dip
->type
= AUDIO_MIXER_CLASS
;
1017 dip
->mixer_class
= HARMONY_PORT_INPUT_CLASS
;
1018 dip
->prev
= dip
->next
= AUDIO_MIXER_LAST
;
1019 strlcpy(dip
->label
.name
, AudioCmonitor
, sizeof dip
->label
.name
);
1021 case HARMONY_PORT_RECORD_CLASS
:
1022 dip
->type
= AUDIO_MIXER_CLASS
;
1023 dip
->mixer_class
= HARMONY_PORT_RECORD_CLASS
;
1024 dip
->prev
= dip
->next
= AUDIO_MIXER_LAST
;
1025 strlcpy(dip
->label
.name
, AudioCrecord
, sizeof dip
->label
.name
);
1036 harmony_allocm(void *vsc
, int dir
, size_t size
, struct malloc_type
*pool
,
1039 struct harmony_softc
*sc
;
1040 struct harmony_dma
*d
;
1044 d
= malloc(sizeof(struct harmony_dma
), pool
, flags
);
1048 if (bus_dmamap_create(sc
->sc_dmat
, size
, 1, size
, 0, BUS_DMA_NOWAIT
,
1052 if (bus_dmamem_alloc(sc
->sc_dmat
, size
, PAGE_SIZE
, 0, &d
->d_seg
, 1,
1053 &rseg
, BUS_DMA_NOWAIT
) != 0)
1056 if (bus_dmamem_map(sc
->sc_dmat
, &d
->d_seg
, 1, size
, &d
->d_kva
,
1057 BUS_DMA_NOWAIT
) != 0)
1060 if (bus_dmamap_load(sc
->sc_dmat
, d
->d_map
, d
->d_kva
, size
, NULL
,
1061 BUS_DMA_NOWAIT
) != 0)
1064 d
->d_next
= sc
->sc_dmas
;
1070 bus_dmamem_unmap(sc
->sc_dmat
, d
->d_kva
, size
);
1072 bus_dmamem_free(sc
->sc_dmat
, &d
->d_seg
, 1);
1074 bus_dmamap_destroy(sc
->sc_dmat
, d
->d_map
);
1082 harmony_freem(void *vsc
, void *ptr
, struct malloc_type
*pool
)
1084 struct harmony_softc
*sc
;
1085 struct harmony_dma
*d
, **dd
;
1088 for (dd
= &sc
->sc_dmas
; (d
= *dd
) != NULL
; dd
= &(*dd
)->d_next
) {
1089 if (d
->d_kva
!= ptr
)
1091 bus_dmamap_unload(sc
->sc_dmat
, d
->d_map
);
1092 bus_dmamem_unmap(sc
->sc_dmat
, d
->d_kva
, d
->d_size
);
1093 bus_dmamem_free(sc
->sc_dmat
, &d
->d_seg
, 1);
1094 bus_dmamap_destroy(sc
->sc_dmat
, d
->d_map
);
1098 printf("%s: free rogue pointer\n", device_xname(sc
->sc_dv
));
1102 harmony_round_buffersize(void *vsc
, int direction
, size_t size
)
1105 return ((size
+ HARMONY_BUFSIZE
- 1) & (size_t)(-HARMONY_BUFSIZE
));
1109 harmony_get_props(void *vsc
)
1112 return AUDIO_PROP_FULLDUPLEX
;
1116 harmony_trigger_output(void *vsc
, void *start
, void *end
, int blksize
,
1117 void (*intr
)(void *), void *intrarg
, const audio_params_t
*param
)
1119 struct harmony_softc
*sc
;
1120 struct harmony_channel
*c
;
1121 struct harmony_dma
*d
;
1124 c
= &sc
->sc_playback
;
1125 for (d
= sc
->sc_dmas
; d
->d_kva
!= start
; d
= d
->d_next
)
1128 printf("%s: trigger_output: bad addr: %p\n",
1129 device_xname(sc
->sc_dv
), start
);
1134 c
->c_intrarg
= intrarg
;
1135 c
->c_blksz
= blksize
;
1137 c
->c_segsz
= (char *)end
- (char *)start
;
1139 c
->c_lastaddr
= d
->d_map
->dm_segs
[0].ds_addr
;
1143 harmony_start_pp(sc
, 1);
1144 harmony_start_cp(sc
, 0);
1145 harmony_intr_enable(sc
);
1151 harmony_start_cp(struct harmony_softc
*sc
, int start
)
1153 struct harmony_channel
*c
;
1154 struct harmony_dma
*d
;
1155 bus_addr_t nextaddr
;
1158 c
= &sc
->sc_capture
;
1159 if (sc
->sc_capturing
== 0)
1160 harmony_empty_input(sc
);
1163 togo
= c
->c_segsz
- c
->c_cnt
;
1165 nextaddr
= d
->d_map
->dm_segs
[0].ds_addr
;
1166 c
->c_cnt
= togo
= c
->c_blksz
;
1168 nextaddr
= c
->c_lastaddr
;
1169 if (togo
> c
->c_blksz
)
1174 bus_dmamap_sync(sc
->sc_dmat
, d
->d_map
,
1175 nextaddr
- d
->d_map
->dm_segs
[0].ds_addr
,
1176 c
->c_blksz
, BUS_DMASYNC_PREWRITE
);
1178 WRITE_REG(sc
, HARMONY_RNXTADD
, nextaddr
);
1180 c
->c_theaddr
= nextaddr
;
1181 SYNC_REG(sc
, HARMONY_RNXTADD
, BUS_SPACE_BARRIER_WRITE
);
1182 c
->c_lastaddr
= nextaddr
+ togo
;
1184 harmony_try_more(sc
, HARMONY_RCURADD
,
1185 RCURADD_BUFMASK
, &sc
->sc_capture
);
1189 callout_schedule(&sc
->sc_acc_tmo
, 1);
1194 harmony_start_pp(struct harmony_softc
*sc
, int start
)
1196 struct harmony_channel
*c
;
1197 struct harmony_dma
*d
;
1198 bus_addr_t nextaddr
;
1201 c
= &sc
->sc_playback
;
1202 if (sc
->sc_playing
== 0)
1203 harmony_empty_output(sc
);
1206 togo
= c
->c_segsz
- c
->c_cnt
;
1208 nextaddr
= d
->d_map
->dm_segs
[0].ds_addr
;
1209 c
->c_cnt
= togo
= c
->c_blksz
;
1211 nextaddr
= c
->c_lastaddr
;
1212 if (togo
> c
->c_blksz
)
1217 bus_dmamap_sync(sc
->sc_dmat
, d
->d_map
,
1218 nextaddr
- d
->d_map
->dm_segs
[0].ds_addr
,
1219 c
->c_blksz
, BUS_DMASYNC_PREWRITE
);
1221 WRITE_REG(sc
, HARMONY_PNXTADD
, nextaddr
);
1223 c
->c_theaddr
= nextaddr
;
1224 SYNC_REG(sc
, HARMONY_PNXTADD
, BUS_SPACE_BARRIER_WRITE
);
1225 c
->c_lastaddr
= nextaddr
+ togo
;
1227 harmony_try_more(sc
, HARMONY_PCURADD
,
1228 PCURADD_BUFMASK
, &sc
->sc_playback
);
1233 harmony_trigger_input(void *vsc
, void *start
, void *end
, int blksize
,
1234 void (*intr
)(void *), void *intrarg
, const audio_params_t
*param
)
1236 struct harmony_softc
*sc
;
1237 struct harmony_channel
*c
;
1238 struct harmony_dma
*d
;
1241 c
= &sc
->sc_capture
;
1242 for (d
= sc
->sc_dmas
; d
->d_kva
!= start
; d
= d
->d_next
)
1245 printf("%s: trigger_input: bad addr: %p\n",
1246 device_xname(sc
->sc_dv
), start
);
1251 c
->c_intrarg
= intrarg
;
1252 c
->c_blksz
= blksize
;
1254 c
->c_segsz
= (char *)end
- (char *)start
;
1256 c
->c_lastaddr
= d
->d_map
->dm_segs
[0].ds_addr
;
1258 sc
->sc_capturing
= 1;
1260 harmony_start_pp(sc
, 0);
1261 harmony_start_cp(sc
, 1);
1262 harmony_intr_enable(sc
);
1267 static const struct speed_struct
{
1270 } harmony_speeds
[] = {
1271 { 5125, CNTL_RATE_5125
},
1272 { 6615, CNTL_RATE_6615
},
1273 { 8000, CNTL_RATE_8000
},
1274 { 9600, CNTL_RATE_9600
},
1275 { 11025, CNTL_RATE_11025
},
1276 { 16000, CNTL_RATE_16000
},
1277 { 18900, CNTL_RATE_18900
},
1278 { 22050, CNTL_RATE_22050
},
1279 { 27428, CNTL_RATE_27428
},
1280 { 32000, CNTL_RATE_32000
},
1281 { 33075, CNTL_RATE_33075
},
1282 { 37800, CNTL_RATE_37800
},
1283 { 44100, CNTL_RATE_44100
},
1284 { 48000, CNTL_RATE_48000
},
1288 harmony_speed_bits(struct harmony_softc
*sc
, u_int
*speedp
)
1293 n
= sizeof(harmony_speeds
) / sizeof(harmony_speeds
[0]);
1295 if ((*speedp
) <= harmony_speeds
[0].speed
)
1297 else if ((*speedp
) >= harmony_speeds
[n
- 1].speed
)
1300 for (i
= 1; selected
== -1 && i
< n
; i
++) {
1301 if ((*speedp
) == harmony_speeds
[i
].speed
)
1303 else if ((*speedp
) < harmony_speeds
[i
].speed
) {
1306 diff1
= (*speedp
) - harmony_speeds
[i
- 1].speed
;
1307 diff2
= harmony_speeds
[i
].speed
- (*speedp
);
1319 *speedp
= harmony_speeds
[selected
].speed
;
1320 return harmony_speeds
[selected
].bits
;
1324 harmony_set_gainctl(struct harmony_softc
*sc
)
1326 uint32_t bits
, mask
, val
, old
;
1328 /* XXX leave these bits alone or the chip will not come out of CNTL */
1329 bits
= GAINCTL_LE
| GAINCTL_HE
| GAINCTL_SE
| GAINCTL_IS_MASK
;
1332 bits
|= ((sc
->sc_input_lvl
.left
>> (8 - GAINCTL_INPUT_BITS
)) <<
1333 GAINCTL_INPUT_LEFT_S
) & GAINCTL_INPUT_LEFT_M
;
1334 bits
|= ((sc
->sc_input_lvl
.right
>> (8 - GAINCTL_INPUT_BITS
)) <<
1335 GAINCTL_INPUT_RIGHT_S
) & GAINCTL_INPUT_RIGHT_M
;
1337 /* output level (inverted) */
1338 mask
= (1 << GAINCTL_OUTPUT_BITS
) - 1;
1339 val
= mask
- (sc
->sc_output_lvl
.left
>> (8 - GAINCTL_OUTPUT_BITS
));
1340 bits
|= (val
<< GAINCTL_OUTPUT_LEFT_S
) & GAINCTL_OUTPUT_LEFT_M
;
1341 val
= mask
- (sc
->sc_output_lvl
.right
>> (8 - GAINCTL_OUTPUT_BITS
));
1342 bits
|= (val
<< GAINCTL_OUTPUT_RIGHT_S
) & GAINCTL_OUTPUT_RIGHT_M
;
1344 /* monitor level (inverted) */
1345 mask
= (1 << GAINCTL_MONITOR_BITS
) - 1;
1346 val
= mask
- (sc
->sc_monitor_lvl
.left
>> (8 - GAINCTL_MONITOR_BITS
));
1347 bits
|= (val
<< GAINCTL_MONITOR_S
) & GAINCTL_MONITOR_M
;
1349 /* XXX messing with these causes CNTL_C to get stuck... grr. */
1350 bits
&= ~GAINCTL_IS_MASK
;
1351 if (sc
->sc_in_port
== HARMONY_IN_MIC
)
1352 bits
|= GAINCTL_IS_LINE
;
1354 bits
|= GAINCTL_IS_MICROPHONE
;
1356 /* XXX messing with these causes CNTL_C to get stuck... grr. */
1357 bits
&= ~(GAINCTL_LE
| GAINCTL_HE
| GAINCTL_SE
);
1358 if (sc
->sc_out_port
== HARMONY_OUT_LINE
)
1360 else if (sc
->sc_out_port
== HARMONY_OUT_SPEAKER
)
1365 mask
= GAINCTL_LE
| GAINCTL_HE
| GAINCTL_SE
| GAINCTL_IS_MASK
;
1366 old
= bus_space_read_4(sc
->sc_bt
, sc
->sc_bh
, HARMONY_GAINCTL
);
1367 bus_space_write_4(sc
->sc_bt
, sc
->sc_bh
, HARMONY_GAINCTL
, bits
);
1368 if ((old
& mask
) != (bits
& mask
))
1374 harmony_try_more(struct harmony_softc
*sc
, int curadd
, int bufmask
,
1375 struct harmony_channel
*c
)
1377 struct harmony_dma
*d
;
1382 cur
= bus_space_read_4(sc
->sc_bt
, sc
->sc_bh
, curadd
);
1387 if (cur
< d
->d_map
->dm_segs
[0].ds_addr
||
1388 cur
>= (d
->d_map
->dm_segs
[0].ds_addr
+ c
->c_segsz
))
1389 panic("%s: bad current %x < %lx || %x > %lx",
1390 device_xname(sc
->sc_dv
), cur
,
1391 d
->d_map
->dm_segs
[0].ds_addr
, cur
,
1392 d
->d_map
->dm_segs
[0].ds_addr
+ c
->c_segsz
);
1393 #endif /* DIAGNOSTIC */
1395 if (cur
> c
->c_theaddr
) {
1396 nsegs
= (cur
- c
->c_theaddr
) / HARMONY_BUFSIZE
;
1397 } else if (cur
< c
->c_theaddr
) {
1398 nsegs
= (d
->d_map
->dm_segs
[0].ds_addr
+ c
->c_segsz
-
1399 c
->c_theaddr
) / HARMONY_BUFSIZE
;
1400 nsegs
+= (cur
- d
->d_map
->dm_segs
[0].ds_addr
) /
1404 if (nsegs
!= 0 && c
->c_intr
!= NULL
) {
1405 for (i
= 0; i
< nsegs
; i
++)
1406 (*c
->c_intr
)(c
->c_intrarg
);