Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / hp700 / gsc / harmony.c
blob713100f81dba4ad80bf1c1314b459de0a89fbf4f
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 $ */
5 /*-
6 * Copyright (c) 2009 The NetBSD Foundation, Inc.
7 * All rights reserved.
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by Matt Fleming.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
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
40 * are met:
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.
64 #include "rnd.h"
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>
72 #include <sys/proc.h>
73 #include <sys/malloc.h>
74 #include <uvm/uvm_extern.h>
76 #if NRND > 0
77 #include <sys/rnd.h>
78 #endif
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 = {
118 harmony_open,
119 harmony_close,
120 NULL,
121 harmony_query_encoding,
122 harmony_set_params,
123 harmony_round_blocksize,
124 harmony_commit_settings,
125 NULL,
126 NULL,
127 NULL,
128 NULL,
129 harmony_halt_output,
130 harmony_halt_input,
131 NULL,
132 harmony_getdev,
133 NULL,
134 harmony_set_port,
135 harmony_get_port,
136 harmony_query_devinfo,
137 harmony_allocm,
138 harmony_freem,
139 harmony_round_buffersize,
140 NULL,
141 harmony_get_props,
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 *);
168 #if NRND > 0
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); \
176 } while(0)
177 #endif
180 harmony_match(device_t parent, struct cfdata *match, void *aux)
182 struct gsc_attach_args *ga;
184 ga = aux;
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)
190 return 1;
192 return 0;
195 void
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;
200 uint8_t rev;
201 uint32_t cntl;
202 int i;
204 sc->sc_dv = self;
205 ga = aux;
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,
210 &sc->sc_bh) != 0) {
211 aprint_error(": couldn't map registers\n");
212 return;
215 cntl = READ_REG(sc, HARMONY_ID);
216 switch ((cntl & ID_REV_MASK)) {
217 case ID_REV_TS:
218 sc->sc_teleshare = 1;
219 case ID_REV_NOTS:
220 break;
221 default:
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);
225 return;
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);
233 return;
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,
240 sc->sc_empty_rseg);
241 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
242 return;
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,
251 sc->sc_empty_rseg);
252 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
253 return;
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,
262 sc->sc_empty_rseg);
263 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
264 return;
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);
286 /* set defaults */
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");
303 aprint_normal("\n");
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);
317 #if NRND > 0
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;
324 #endif
327 void
328 harmony_reset_codec(struct harmony_softc *sc)
331 /* silence */
332 WRITE_REG(sc, HARMONY_GAINCTL, GAINCTL_OUTPUT_LEFT_M |
333 GAINCTL_OUTPUT_RIGHT_M | GAINCTL_MONITOR_M);
335 /* start reset */
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);
344 #if NRND > 0
345 void
346 harmony_acc_tmo(void *v)
348 struct harmony_softc *sc;
350 sc = v;
351 ADD_CLKALLICA(sc);
352 callout_schedule(&sc->sc_acc_tmo, 1);
354 #endif
357 * interrupt handler
360 harmony_intr(void *vsc)
362 struct harmony_softc *sc;
363 uint32_t dstatus;
364 int r;
366 sc = vsc;
367 r = 0;
368 #if NRND > 0
369 ADD_CLKALLICA(sc);
370 #endif
372 harmony_intr_disable(sc);
374 dstatus = READ_REG(sc, HARMONY_DSTATUS);
376 if (dstatus & DSTATUS_PN) {
377 r = 1;
378 harmony_start_pp(sc, 0);
381 if (dstatus & DSTATUS_RN) {
382 r = 1;
383 harmony_start_cp(sc, 0);
386 if (READ_REG(sc, HARMONY_OV) & OV_OV) {
387 sc->sc_ov = 1;
388 WRITE_REG(sc, HARMONY_OV, 0);
389 } else
390 sc->sc_ov = 0;
392 harmony_intr_enable(sc);
394 return r;
397 void
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);
405 void
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;
418 sc = vsc;
419 if (sc->sc_open)
420 return EBUSY;
421 sc->sc_open = 1;
422 return 0;
425 void
426 harmony_close(void *vsc)
428 struct harmony_softc *sc;
430 sc = vsc;
431 harmony_halt_input(sc);
432 harmony_halt_output(sc);
433 harmony_intr_disable(sc);
434 sc->sc_open = 0;
438 harmony_query_encoding(void *vsc, struct audio_encoding *fp)
440 struct harmony_softc *sc;
441 int err;
443 sc = vsc;
444 err = 0;
445 switch (fp->index) {
446 case 0:
447 strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
448 fp->encoding = AUDIO_ENCODING_ULAW;
449 fp->precision = 8;
450 fp->flags = 0;
451 break;
452 case 1:
453 strlcpy(fp->name, AudioEalaw, sizeof fp->name);
454 fp->encoding = AUDIO_ENCODING_ALAW;
455 fp->precision = 8;
456 fp->flags = 0;
457 break;
458 case 2:
459 strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
460 fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
461 fp->precision = 16;
462 fp->flags = 0;
463 break;
464 case 3:
465 strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
466 fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
467 fp->precision = 16;
468 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
469 break;
470 case 4:
471 strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
472 fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
473 fp->precision = 16;
474 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
475 break;
476 case 5:
477 strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
478 fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
479 fp->precision = 16;
480 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
481 break;
482 case 6:
483 if (sc->sc_hasulinear8) {
484 strlcpy(fp->name, AudioEulinear, sizeof fp->name);
485 fp->encoding = AUDIO_ENCODING_ULINEAR;
486 fp->precision = 8;
487 fp->flags = 0;
488 break;
490 /*FALLTHROUGH*/
491 case 7:
492 if (sc->sc_hasulinear8) {
493 strlcpy(fp->name, AudioEslinear, sizeof fp->name);
494 fp->encoding = AUDIO_ENCODING_SLINEAR;
495 fp->precision = 8;
496 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
497 break;
499 /*FALLTHROUGH*/
500 default:
501 err = EINVAL;
503 return err;
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)
511 audio_params_t hw;
512 struct harmony_softc *sc;
513 uint32_t bits;
514 stream_filter_factory_t *pswcode = NULL;
515 stream_filter_factory_t *rswcode = NULL;
517 sc = vsc;
518 /* assume p.equals(r) */
519 hw = *p;
520 switch (p->encoding) {
521 case AUDIO_ENCODING_ULAW:
522 if (p->precision != 8)
523 return EINVAL;
524 bits = CNTL_FORMAT_ULAW;
525 break;
526 case AUDIO_ENCODING_ALAW:
527 if (p->precision != 8)
528 return EINVAL;
529 bits = CNTL_FORMAT_ALAW;
530 break;
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;
536 break;
538 if (p->precision == 16) {
539 bits = CNTL_FORMAT_SLINEAR16BE;
540 break;
542 return EINVAL;
543 case AUDIO_ENCODING_ULINEAR:
544 if (p->precision != 8)
545 return EINVAL;
546 bits = CNTL_FORMAT_ULINEAR8;
547 break;
548 case AUDIO_ENCODING_SLINEAR:
549 if (p->precision != 8)
550 return EINVAL;
551 bits = CNTL_FORMAT_ULINEAR8;
552 hw.encoding = AUDIO_ENCODING_ULINEAR_LE;
553 rswcode = pswcode = change_sign8;
554 break;
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;
560 break;
562 if (p->precision == 16) {
563 bits = CNTL_FORMAT_SLINEAR16BE;
564 hw.encoding = AUDIO_ENCODING_SLINEAR_BE;
565 rswcode = pswcode = swap_bytes;
566 break;
568 return EINVAL;
569 case AUDIO_ENCODING_ULINEAR_BE:
570 if (p->precision == 8) {
571 bits = CNTL_FORMAT_ULINEAR8;
572 break;
574 if (p->precision == 16) {
575 bits = CNTL_FORMAT_SLINEAR16BE;
576 rswcode = pswcode = change_sign16;
577 break;
579 return EINVAL;
580 case AUDIO_ENCODING_ULINEAR_LE:
581 if (p->precision == 8) {
582 bits = CNTL_FORMAT_ULINEAR8;
583 break;
585 if (p->precision == 16) {
586 bits = CNTL_FORMAT_SLINEAR16BE;
587 hw.encoding = AUDIO_ENCODING_SLINEAR_BE;
588 rswcode = pswcode = swap_bytes_change_sign16;
589 break;
591 return EINVAL;
592 default:
593 return EINVAL;
596 if (sc->sc_outputgain)
597 bits |= CNTL_OLB;
599 if (p->channels == 1)
600 bits |= CNTL_CHANS_MONO;
601 else if (p->channels == 2)
602 bits |= CNTL_CHANS_STEREO;
603 else
604 return EINVAL;
606 bits |= harmony_speed_bits(sc, &p->sample_rate);
607 if (pswcode != NULL)
608 pfil->append(pfil, pswcode, &hw);
609 if (rswcode != NULL)
610 rfil->append(rfil, rswcode, &hw);
611 sc->sc_cntlbits = bits;
612 sc->sc_need_commit = 1;
614 return 0;
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;
629 uint32_t reg;
630 uint8_t quietchar;
631 int i;
633 sc = vsc;
634 if (sc->sc_need_commit == 0)
635 return 0;
637 harmony_intr_disable(sc);
639 for (;;) {
640 reg = READ_REG(sc, HARMONY_DSTATUS);
641 if ((reg & (DSTATUS_PC | DSTATUS_RC)) == 0)
642 break;
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:
654 quietchar = 0x7f;
655 break;
656 case CNTL_FORMAT_ALAW:
657 quietchar = 0x55;
658 break;
659 case CNTL_FORMAT_SLINEAR16BE:
660 case CNTL_FORMAT_ULINEAR8:
661 default:
662 quietchar = 0;
663 break;
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);
672 for (;;) {
673 /* Wait for it to come out of control mode */
674 reg = READ_REG(sc, HARMONY_CNTL);
675 if ((reg & CNTL_C) == 0)
676 break;
679 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_CNTL,
680 sc->sc_cntlbits | CNTL_C);
682 for (;;) {
683 /* Wait for it to come out of control mode */
684 reg = READ_REG(sc, HARMONY_CNTL);
685 if ((reg & CNTL_C) == 0)
686 break;
689 sc->sc_need_commit = 0;
691 if (sc->sc_playing || sc->sc_capturing)
692 harmony_intr_enable(sc);
694 return 0;
697 static void
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;
714 sc = vsc;
715 sc->sc_playing = 0;
717 harmony_empty_output(sc);
718 return 0;
721 static void
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;
738 sc = vsc;
739 sc->sc_capturing = 0;
741 harmony_empty_input(sc);
742 return 0;
746 harmony_getdev(void *vsc, struct audio_device *retp)
748 struct harmony_softc *sc;
750 sc = vsc;
751 *retp = sc->sc_audev;
752 return 0;
756 harmony_set_port(void *vsc, mixer_ctrl_t *cp)
758 struct harmony_softc *sc;
759 int err;
761 sc = vsc;
762 err = EINVAL;
763 switch (cp->dev) {
764 case HARMONY_PORT_INPUT_LVL:
765 if (cp->type != AUDIO_MIXER_VALUE)
766 break;
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];
775 } else
776 break;
777 sc->sc_need_commit = 1;
778 err = 0;
779 break;
780 case HARMONY_PORT_OUTPUT_LVL:
781 if (cp->type != AUDIO_MIXER_VALUE)
782 break;
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];
791 } else
792 break;
793 sc->sc_need_commit = 1;
794 err = 0;
795 break;
796 case HARMONY_PORT_OUTPUT_GAIN:
797 if (cp->type != AUDIO_MIXER_ENUM)
798 break;
799 sc->sc_outputgain = cp->un.ord ? 1 : 0;
800 err = 0;
801 break;
802 case HARMONY_PORT_MONITOR_LVL:
803 if (cp->type != AUDIO_MIXER_VALUE)
804 break;
805 if (cp->un.value.num_channels != 1)
806 break;
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;
810 err = 0;
811 break;
812 case HARMONY_PORT_RECORD_SOURCE:
813 if (cp->type != AUDIO_MIXER_ENUM)
814 break;
815 if (cp->un.ord != HARMONY_IN_LINE &&
816 cp->un.ord != HARMONY_IN_MIC)
817 break;
818 sc->sc_in_port = cp->un.ord;
819 err = 0;
820 sc->sc_need_commit = 1;
821 break;
822 case HARMONY_PORT_OUTPUT_SOURCE:
823 if (cp->type != AUDIO_MIXER_ENUM)
824 break;
825 if (cp->un.ord != HARMONY_OUT_LINE &&
826 cp->un.ord != HARMONY_OUT_SPEAKER &&
827 cp->un.ord != HARMONY_OUT_HEADPHONE)
828 break;
829 sc->sc_out_port = cp->un.ord;
830 err = 0;
831 sc->sc_need_commit = 1;
832 break;
835 return err;
839 harmony_get_port(void *vsc, mixer_ctrl_t *cp)
841 struct harmony_softc *sc;
842 int err;
844 sc = vsc;
845 err = EINVAL;
846 switch (cp->dev) {
847 case HARMONY_PORT_INPUT_LVL:
848 if (cp->type != AUDIO_MIXER_VALUE)
849 break;
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;
858 } else
859 break;
860 err = 0;
861 break;
862 case HARMONY_PORT_INPUT_OV:
863 if (cp->type != AUDIO_MIXER_ENUM)
864 break;
865 cp->un.ord = sc->sc_ov ? 1 : 0;
866 err = 0;
867 break;
868 case HARMONY_PORT_OUTPUT_LVL:
869 if (cp->type != AUDIO_MIXER_VALUE)
870 break;
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;
879 } else
880 break;
881 err = 0;
882 break;
883 case HARMONY_PORT_OUTPUT_GAIN:
884 if (cp->type != AUDIO_MIXER_ENUM)
885 break;
886 cp->un.ord = sc->sc_outputgain ? 1 : 0;
887 err = 0;
888 break;
889 case HARMONY_PORT_MONITOR_LVL:
890 if (cp->type != AUDIO_MIXER_VALUE)
891 break;
892 if (cp->un.value.num_channels != 1)
893 break;
894 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
895 sc->sc_monitor_lvl.left;
896 err = 0;
897 break;
898 case HARMONY_PORT_RECORD_SOURCE:
899 if (cp->type != AUDIO_MIXER_ENUM)
900 break;
901 cp->un.ord = sc->sc_in_port;
902 err = 0;
903 break;
904 case HARMONY_PORT_OUTPUT_SOURCE:
905 if (cp->type != AUDIO_MIXER_ENUM)
906 break;
907 cp->un.ord = sc->sc_out_port;
908 err = 0;
909 break;
911 return 0;
915 harmony_query_devinfo(void *vsc, mixer_devinfo_t *dip)
917 int err;
919 err = 0;
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);
929 break;
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;
942 break;
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);
951 break;
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;
964 break;
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);
973 break;
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;
986 break;
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;
1002 break;
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);
1008 break;
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);
1014 break;
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);
1020 break;
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);
1026 break;
1027 default:
1028 err = ENXIO;
1029 break;
1032 return err;
1035 void *
1036 harmony_allocm(void *vsc, int dir, size_t size, struct malloc_type *pool,
1037 int flags)
1039 struct harmony_softc *sc;
1040 struct harmony_dma *d;
1041 int rseg;
1043 sc = vsc;
1044 d = malloc(sizeof(struct harmony_dma), pool, flags);
1045 if (d == NULL)
1046 goto fail;
1048 if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, BUS_DMA_NOWAIT,
1049 &d->d_map) != 0)
1050 goto fail1;
1052 if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &d->d_seg, 1,
1053 &rseg, BUS_DMA_NOWAIT) != 0)
1054 goto fail2;
1056 if (bus_dmamem_map(sc->sc_dmat, &d->d_seg, 1, size, &d->d_kva,
1057 BUS_DMA_NOWAIT) != 0)
1058 goto fail3;
1060 if (bus_dmamap_load(sc->sc_dmat, d->d_map, d->d_kva, size, NULL,
1061 BUS_DMA_NOWAIT) != 0)
1062 goto fail4;
1064 d->d_next = sc->sc_dmas;
1065 sc->sc_dmas = d;
1066 d->d_size = size;
1067 return (d->d_kva);
1069 fail4:
1070 bus_dmamem_unmap(sc->sc_dmat, d->d_kva, size);
1071 fail3:
1072 bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1);
1073 fail2:
1074 bus_dmamap_destroy(sc->sc_dmat, d->d_map);
1075 fail1:
1076 free(d, pool);
1077 fail:
1078 return (NULL);
1081 void
1082 harmony_freem(void *vsc, void *ptr, struct malloc_type *pool)
1084 struct harmony_softc *sc;
1085 struct harmony_dma *d, **dd;
1087 sc = vsc;
1088 for (dd = &sc->sc_dmas; (d = *dd) != NULL; dd = &(*dd)->d_next) {
1089 if (d->d_kva != ptr)
1090 continue;
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);
1095 free(d, pool);
1096 return;
1098 printf("%s: free rogue pointer\n", device_xname(sc->sc_dv));
1101 size_t
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;
1123 sc = vsc;
1124 c = &sc->sc_playback;
1125 for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next)
1126 continue;
1127 if (d == NULL) {
1128 printf("%s: trigger_output: bad addr: %p\n",
1129 device_xname(sc->sc_dv), start);
1130 return EINVAL;
1133 c->c_intr = intr;
1134 c->c_intrarg = intrarg;
1135 c->c_blksz = blksize;
1136 c->c_current = d;
1137 c->c_segsz = (char *)end - (char *)start;
1138 c->c_cnt = 0;
1139 c->c_lastaddr = d->d_map->dm_segs[0].ds_addr;
1141 sc->sc_playing = 1;
1143 harmony_start_pp(sc, 1);
1144 harmony_start_cp(sc, 0);
1145 harmony_intr_enable(sc);
1147 return 0;
1150 void
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;
1156 bus_size_t togo;
1158 c = &sc->sc_capture;
1159 if (sc->sc_capturing == 0)
1160 harmony_empty_input(sc);
1161 else {
1162 d = c->c_current;
1163 togo = c->c_segsz - c->c_cnt;
1164 if (togo == 0) {
1165 nextaddr = d->d_map->dm_segs[0].ds_addr;
1166 c->c_cnt = togo = c->c_blksz;
1167 } else {
1168 nextaddr = c->c_lastaddr;
1169 if (togo > c->c_blksz)
1170 togo = c->c_blksz;
1171 c->c_cnt += togo;
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);
1179 if (start)
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);
1188 #if NRND > 0
1189 callout_schedule(&sc->sc_acc_tmo, 1);
1190 #endif
1193 void
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;
1199 bus_size_t togo;
1201 c = &sc->sc_playback;
1202 if (sc->sc_playing == 0)
1203 harmony_empty_output(sc);
1204 else {
1205 d = c->c_current;
1206 togo = c->c_segsz - c->c_cnt;
1207 if (togo == 0) {
1208 nextaddr = d->d_map->dm_segs[0].ds_addr;
1209 c->c_cnt = togo = c->c_blksz;
1210 } else {
1211 nextaddr = c->c_lastaddr;
1212 if (togo > c->c_blksz)
1213 togo = c->c_blksz;
1214 c->c_cnt += togo;
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);
1222 if (start)
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;
1240 sc = vsc;
1241 c = &sc->sc_capture;
1242 for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next)
1243 continue;
1244 if (d == NULL) {
1245 printf("%s: trigger_input: bad addr: %p\n",
1246 device_xname(sc->sc_dv), start);
1247 return EINVAL;
1250 c->c_intr = intr;
1251 c->c_intrarg = intrarg;
1252 c->c_blksz = blksize;
1253 c->c_current = d;
1254 c->c_segsz = (char *)end - (char *)start;
1255 c->c_cnt = 0;
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);
1264 return 0;
1267 static const struct speed_struct {
1268 uint32_t speed;
1269 uint32_t bits;
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 },
1287 uint32_t
1288 harmony_speed_bits(struct harmony_softc *sc, u_int *speedp)
1290 int i, n, selected;
1292 selected = -1;
1293 n = sizeof(harmony_speeds) / sizeof(harmony_speeds[0]);
1295 if ((*speedp) <= harmony_speeds[0].speed)
1296 selected = 0;
1297 else if ((*speedp) >= harmony_speeds[n - 1].speed)
1298 selected = n - 1;
1299 else {
1300 for (i = 1; selected == -1 && i < n; i++) {
1301 if ((*speedp) == harmony_speeds[i].speed)
1302 selected = i;
1303 else if ((*speedp) < harmony_speeds[i].speed) {
1304 int diff1, diff2;
1306 diff1 = (*speedp) - harmony_speeds[i - 1].speed;
1307 diff2 = harmony_speeds[i].speed - (*speedp);
1308 if (diff1 < diff2)
1309 selected = i - 1;
1310 else
1311 selected = i;
1316 if (selected == -1)
1317 selected = 2;
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;
1331 /* input level */
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;
1353 else
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)
1359 bits |= GAINCTL_LE;
1360 else if (sc->sc_out_port == HARMONY_OUT_SPEAKER)
1361 bits |= GAINCTL_SE;
1362 else
1363 bits |= GAINCTL_HE;
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))
1369 return 1;
1370 return 0;
1373 void
1374 harmony_try_more(struct harmony_softc *sc, int curadd, int bufmask,
1375 struct harmony_channel *c)
1377 struct harmony_dma *d;
1378 uint32_t cur;
1379 int i, nsegs;
1381 d = c->c_current;
1382 cur = bus_space_read_4(sc->sc_bt, sc->sc_bh, curadd);
1383 cur &= bufmask;
1384 nsegs = 0;
1386 #ifdef DIAGNOSTIC
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) /
1401 HARMONY_BUFSIZE;
1404 if (nsegs != 0 && c->c_intr != NULL) {
1405 for (i = 0; i < nsegs; i++)
1406 (*c->c_intr)(c->c_intrarg);
1407 c->c_theaddr = cur;