harmony.c revision 1.10 1 /* $NetBSD: harmony.c,v 1.10 2021/02/04 15:08:44 isaki Exp $ */
2
3 /* $OpenBSD: harmony.c,v 1.23 2004/02/13 21:28:19 mickey Exp $ */
4
5 /*-
6 * Copyright (c) 2009 The NetBSD Foundation, Inc.
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by Matt Fleming.
11 *
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.
20 *
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.
32 */
33
34 /*
35 * Copyright (c) 2003 Jason L. Wright (jason (at) thought.net)
36 * All rights reserved.
37 *
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.
46 *
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.
58 */
59
60 /*
61 * Harmony (CS4215/AD1849 LASI) audio interface.
62 */
63
64
65
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/kmem.h>
74 #include <uvm/uvm_extern.h>
75
76 #include <sys/rndsource.h>
77
78 #include <sys/audioio.h>
79 #include <dev/audio/audio_if.h>
80
81 #include <machine/cpu.h>
82 #include <machine/intr.h>
83 #include <machine/iomod.h>
84 #include <machine/autoconf.h>
85 #include <sys/bus.h>
86
87 #include <hppa/dev/cpudevs.h>
88 #include <hppa/gsc/gscbusvar.h>
89 #include <hppa/gsc/harmonyreg.h>
90 #include <hppa/gsc/harmonyvar.h>
91
92 void harmony_close(void *);
93 int harmony_query_format(void *, audio_format_query_t *);
94 int harmony_set_format(void *, int,
95 const audio_params_t *, const audio_params_t *,
96 audio_filter_reg_t *, audio_filter_reg_t *);
97 int harmony_round_blocksize(void *, int, int, const audio_params_t *);
98
99 int harmony_control_wait(struct harmony_softc *);
100 int harmony_commit_settings(void *);
101
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);
109 void harmony_freem(void *, void *, size_t);
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 *);
116 void harmony_get_locks(void *, kmutex_t **, kmutex_t **);
117
118 const struct audio_hw_if harmony_sa_hw_if = {
119 .close = harmony_close,
120 .query_format = harmony_query_format,
121 .set_format = harmony_set_format,
122 .round_blocksize = harmony_round_blocksize,
123 .commit_settings = harmony_commit_settings,
124 .halt_output = harmony_halt_output,
125 .halt_input = harmony_halt_input,
126 .getdev = harmony_getdev,
127 .set_port = harmony_set_port,
128 .get_port = harmony_get_port,
129 .query_devinfo = harmony_query_devinfo,
130 .allocm = harmony_allocm,
131 .freem = harmony_freem,
132 .round_buffersize = harmony_round_buffersize,
133 .get_props = harmony_get_props,
134 .trigger_output = harmony_trigger_output,
135 .trigger_input = harmony_trigger_input,
136 .get_locks = harmony_get_locks,
137 };
138
139 /* The HW actually supports more frequencies, but these looks enough. */
140 #define HARMONY_FORMAT(enc, prec) \
141 { \
142 .mode = AUMODE_PLAY | AUMODE_RECORD, \
143 .encoding = (enc), \
144 .validbits = (prec), \
145 .precision = (prec), \
146 .channels = 2, \
147 .channel_mask = AUFMT_STEREO, \
148 .frequency_type = 4, \
149 .frequency = { 16000, 32000, 44100, 48000 }, \
150 }
151 static struct audio_format harmony_formats[] = {
152 HARMONY_FORMAT(AUDIO_ENCODING_ULAW, 8),
153 HARMONY_FORMAT(AUDIO_ENCODING_ALAW, 8),
154 HARMONY_FORMAT(AUDIO_ENCODING_SLINEAR_BE, 16),
155 };
156 #define HARMONY_NFORMATS __arraycount(harmony_formats)
157
158 int harmony_match(device_t, struct cfdata *, void *);
159 void harmony_attach(device_t, device_t, void *);
160
161
162 CFATTACH_DECL_NEW(harmony, sizeof(struct harmony_softc),
163 harmony_match, harmony_attach, NULL, NULL);
164
165 int harmony_intr(void *);
166 void harmony_intr_enable(struct harmony_softc *);
167 void harmony_intr_disable(struct harmony_softc *);
168 uint32_t harmony_speed_bits(struct harmony_softc *, u_int);
169 int harmony_set_gainctl(struct harmony_softc *);
170 void harmony_reset_codec(struct harmony_softc *);
171 void harmony_start_cp(struct harmony_softc *, int);
172 void harmony_start_pp(struct harmony_softc *, int);
173 void harmony_tick_pb(void *);
174 void harmony_tick_cp(void *);
175 void harmony_try_more(struct harmony_softc *, int, int,
176 struct harmony_channel *);
177 static void harmony_empty_input(struct harmony_softc *);
178 static void harmony_empty_output(struct harmony_softc *);
179
180 void harmony_acc_tmo(void *);
181 #define ADD_CLKALLICA(sc) do { \
182 (sc)->sc_acc <<= 1; \
183 (sc)->sc_acc |= READ_REG((sc), HARMONY_DIAG) & DIAG_CO; \
184 if ((sc)->sc_acc_cnt++ && !((sc)->sc_acc_cnt % 32)) \
185 rnd_add_uint32(&(sc)->sc_rnd_source, \
186 (sc)->sc_acc_num ^= (sc)->sc_acc); \
187 } while(0)
188
189 int
190 harmony_match(device_t parent, struct cfdata *match, void *aux)
191 {
192 struct gsc_attach_args *ga;
193
194 ga = aux;
195 if (ga->ga_type.iodc_type == HPPA_TYPE_FIO) {
196 if (ga->ga_type.iodc_sv_model == HPPA_FIO_A1 ||
197 ga->ga_type.iodc_sv_model == HPPA_FIO_A2NB ||
198 ga->ga_type.iodc_sv_model == HPPA_FIO_A1NB ||
199 ga->ga_type.iodc_sv_model == HPPA_FIO_A2)
200 return 1;
201 }
202 return 0;
203 }
204
205 void
206 harmony_attach(device_t parent, device_t self, void *aux)
207 {
208 struct harmony_softc *sc = device_private(self);
209 struct gsc_attach_args *ga;
210 uint8_t rev;
211 uint32_t cntl;
212 int i;
213
214 sc->sc_dv = self;
215 ga = aux;
216 sc->sc_bt = ga->ga_iot;
217 sc->sc_dmat = ga->ga_dmatag;
218
219 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
220 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO);
221
222 if (bus_space_map(sc->sc_bt, ga->ga_hpa, HARMONY_NREGS, 0,
223 &sc->sc_bh) != 0) {
224 aprint_error(": couldn't map registers\n");
225 return;
226 }
227
228 cntl = READ_REG(sc, HARMONY_ID);
229 switch ((cntl & ID_REV_MASK)) {
230 case ID_REV_TS:
231 sc->sc_teleshare = 1;
232 case ID_REV_NOTS:
233 break;
234 default:
235 aprint_error(": unknown id == 0x%02x\n",
236 (cntl & ID_REV_MASK) >> ID_REV_SHIFT);
237 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
238 return;
239 }
240
241 if (bus_dmamem_alloc(sc->sc_dmat, sizeof(struct harmony_empty),
242 PAGE_SIZE, 0, &sc->sc_empty_seg, 1, &sc->sc_empty_rseg,
243 BUS_DMA_WAITOK) != 0) {
244 aprint_error(": could not alloc DMA memory\n");
245 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
246 return;
247 }
248 if (bus_dmamem_map(sc->sc_dmat, &sc->sc_empty_seg, 1,
249 sizeof(struct harmony_empty), (void **)&sc->sc_empty_kva,
250 BUS_DMA_WAITOK) != 0) {
251 aprint_error(": couldn't map DMA memory\n");
252 bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg,
253 sc->sc_empty_rseg);
254 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
255 return;
256 }
257 if (bus_dmamap_create(sc->sc_dmat, sizeof(struct harmony_empty), 1,
258 sizeof(struct harmony_empty), 0, BUS_DMA_WAITOK,
259 &sc->sc_empty_map) != 0) {
260 aprint_error(": can't create DMA map\n");
261 bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_empty_kva,
262 sizeof(struct harmony_empty));
263 bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg,
264 sc->sc_empty_rseg);
265 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
266 return;
267 }
268 if (bus_dmamap_load(sc->sc_dmat, sc->sc_empty_map, sc->sc_empty_kva,
269 sizeof(struct harmony_empty), NULL, BUS_DMA_WAITOK) != 0) {
270 aprint_error(": can't load DMA map\n");
271 bus_dmamap_destroy(sc->sc_dmat, sc->sc_empty_map);
272 bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_empty_kva,
273 sizeof(struct harmony_empty));
274 bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg,
275 sc->sc_empty_rseg);
276 bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
277 return;
278 }
279
280 sc->sc_playback_empty = 0;
281 for (i = 0; i < PLAYBACK_EMPTYS; i++)
282 sc->sc_playback_paddrs[i] =
283 sc->sc_empty_map->dm_segs[0].ds_addr +
284 offsetof(struct harmony_empty, playback[i][0]);
285
286 sc->sc_capture_empty = 0;
287 for (i = 0; i < CAPTURE_EMPTYS; i++)
288 sc->sc_capture_paddrs[i] =
289 sc->sc_empty_map->dm_segs[0].ds_addr +
290 offsetof(struct harmony_empty, capture[i][0]);
291
292 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
293 offsetof(struct harmony_empty, playback[0][0]),
294 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE);
295
296 (void) hppa_intr_establish(IPL_AUDIO, harmony_intr, sc, ga->ga_ir,
297 ga->ga_irq);
298
299 /* set defaults */
300 sc->sc_in_port = HARMONY_IN_LINE;
301 sc->sc_out_port = HARMONY_OUT_SPEAKER;
302 sc->sc_input_lvl.left = sc->sc_input_lvl.right = 240;
303 sc->sc_output_lvl.left = sc->sc_output_lvl.right = 244;
304 sc->sc_monitor_lvl.left = sc->sc_monitor_lvl.right = 208;
305 sc->sc_outputgain = 0;
306
307 /* reset chip, and push default gain controls */
308 harmony_reset_codec(sc);
309
310 cntl = READ_REG(sc, HARMONY_CNTL);
311 rev = (cntl & CNTL_CODEC_REV_MASK) >> CNTL_CODEC_REV_SHIFT;
312 aprint_normal(": rev %u", rev);
313
314 if (sc->sc_teleshare)
315 printf(", teleshare");
316 aprint_normal("\n");
317
318 strlcpy(sc->sc_audev.name, ga->ga_name, sizeof(sc->sc_audev.name));
319 snprintf(sc->sc_audev.version, sizeof sc->sc_audev.version,
320 "%u.%u;%u", ga->ga_type.iodc_sv_rev,
321 ga->ga_type.iodc_model, ga->ga_type.iodc_revision);
322 strlcpy(sc->sc_audev.config, device_xname(sc->sc_dv),
323 sizeof(sc->sc_audev.config));
324
325 audio_attach_mi(&harmony_sa_hw_if, sc, sc->sc_dv);
326
327 rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dv),
328 RND_TYPE_UNKNOWN, RND_FLAG_DEFAULT);
329
330 callout_init(&sc->sc_acc_tmo, 0);
331 callout_setfunc(&sc->sc_acc_tmo, harmony_acc_tmo, sc);
332 sc->sc_acc_num = 0xa5a5a5a5;
333 }
334
335 void
336 harmony_reset_codec(struct harmony_softc *sc)
337 {
338
339 /* silence */
340 WRITE_REG(sc, HARMONY_GAINCTL, GAINCTL_OUTPUT_LEFT_M |
341 GAINCTL_OUTPUT_RIGHT_M | GAINCTL_MONITOR_M);
342
343 /* start reset */
344 WRITE_REG(sc, HARMONY_RESET, RESET_RST);
345
346 DELAY(100000); /* wait at least 0.05 sec */
347
348 harmony_set_gainctl(sc);
349 WRITE_REG(sc, HARMONY_RESET, 0);
350 }
351
352 void
353 harmony_acc_tmo(void *v)
354 {
355 struct harmony_softc *sc;
356
357 sc = v;
358 ADD_CLKALLICA(sc);
359 callout_schedule(&sc->sc_acc_tmo, 1);
360 }
361
362 /*
363 * interrupt handler
364 */
365 int
366 harmony_intr(void *vsc)
367 {
368 struct harmony_softc *sc;
369 uint32_t dstatus;
370 int r;
371
372 sc = vsc;
373 r = 0;
374 ADD_CLKALLICA(sc);
375
376 mutex_spin_enter(&sc->sc_intr_lock);
377
378 harmony_intr_disable(sc);
379
380 dstatus = READ_REG(sc, HARMONY_DSTATUS);
381
382 if (dstatus & DSTATUS_PN) {
383 r = 1;
384 harmony_start_pp(sc, 0);
385 }
386
387 if (dstatus & DSTATUS_RN) {
388 r = 1;
389 harmony_start_cp(sc, 0);
390 }
391
392 if (READ_REG(sc, HARMONY_OV) & OV_OV) {
393 sc->sc_ov = 1;
394 WRITE_REG(sc, HARMONY_OV, 0);
395 } else
396 sc->sc_ov = 0;
397
398 harmony_intr_enable(sc);
399
400 mutex_spin_exit(&sc->sc_intr_lock);
401
402 return r;
403 }
404
405 void
406 harmony_intr_enable(struct harmony_softc *sc)
407 {
408
409 WRITE_REG(sc, HARMONY_DSTATUS, DSTATUS_IE);
410 SYNC_REG(sc, HARMONY_DSTATUS, BUS_SPACE_BARRIER_WRITE);
411 }
412
413 void
414 harmony_intr_disable(struct harmony_softc *sc)
415 {
416
417 WRITE_REG(sc, HARMONY_DSTATUS, 0);
418 SYNC_REG(sc, HARMONY_DSTATUS, BUS_SPACE_BARRIER_WRITE);
419 }
420
421 void
422 harmony_close(void *vsc)
423 {
424 struct harmony_softc *sc;
425
426 sc = vsc;
427 harmony_intr_disable(sc);
428 }
429
430 int
431 harmony_query_format(void *vsc, audio_format_query_t *afp)
432 {
433
434 return audio_query_format(harmony_formats, HARMONY_NFORMATS, afp);
435 }
436
437 int
438 harmony_set_format(void *vsc, int setmode,
439 const audio_params_t *play, const audio_params_t *rec,
440 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
441 {
442 struct harmony_softc *sc;
443 uint32_t bits;
444
445 sc = vsc;
446
447 /* *play and *rec are the identical because !AUDIO_PROP_INDEPENDENT. */
448 switch (play->encoding) {
449 case AUDIO_ENCODING_ULAW:
450 bits = CNTL_FORMAT_ULAW;
451 break;
452 case AUDIO_ENCODING_ALAW:
453 bits = CNTL_FORMAT_ALAW;
454 break;
455 case AUDIO_ENCODING_SLINEAR_BE:
456 bits = CNTL_FORMAT_SLINEAR16BE;
457 break;
458 default:
459 return EINVAL;
460 }
461
462 if (sc->sc_outputgain)
463 bits |= CNTL_OLB;
464
465 bits |= CNTL_CHANS_STEREO;
466 bits |= harmony_speed_bits(sc, play->sample_rate);
467 sc->sc_cntlbits = bits;
468 sc->sc_need_commit = 1;
469
470 return 0;
471 }
472
473 int
474 harmony_round_blocksize(void *vsc, int blk,
475 int mode, const audio_params_t *param)
476 {
477
478 return HARMONY_BUFSIZE;
479 }
480
481 int
482 harmony_control_wait(struct harmony_softc *sc)
483 {
484 uint32_t reg;
485 int j = 0;
486
487 while (j < 10) {
488 /* Wait for it to come out of control mode */
489 reg = READ_REG(sc, HARMONY_CNTL);
490 if ((reg & CNTL_C) == 0)
491 return 0;
492 DELAY(50000); /* wait 0.05 */
493 j++;
494 }
495
496 return 1;
497 }
498
499 int
500 harmony_commit_settings(void *vsc)
501 {
502 struct harmony_softc *sc;
503 uint32_t reg;
504 uint8_t quietchar;
505 int i;
506
507 sc = vsc;
508 if (sc->sc_need_commit == 0)
509 return 0;
510
511 harmony_intr_disable(sc);
512
513 for (;;) {
514 reg = READ_REG(sc, HARMONY_DSTATUS);
515 if ((reg & (DSTATUS_PC | DSTATUS_RC)) == 0)
516 break;
517 }
518
519 /* Setting some bits in gainctl requires a reset */
520 harmony_reset_codec(sc);
521
522 /* set the silence character based on the encoding type */
523 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
524 offsetof(struct harmony_empty, playback[0][0]),
525 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_POSTWRITE);
526 switch (sc->sc_cntlbits & CNTL_FORMAT_MASK) {
527 case CNTL_FORMAT_ULAW:
528 quietchar = 0x7f;
529 break;
530 case CNTL_FORMAT_ALAW:
531 quietchar = 0x55;
532 break;
533 case CNTL_FORMAT_SLINEAR16BE:
534 case CNTL_FORMAT_ULINEAR8:
535 default:
536 quietchar = 0;
537 break;
538 }
539 for (i = 0; i < PLAYBACK_EMPTYS; i++)
540 memset(&sc->sc_empty_kva->playback[i][0],
541 quietchar, HARMONY_BUFSIZE);
542 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
543 offsetof(struct harmony_empty, playback[0][0]),
544 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE);
545
546 harmony_control_wait(sc);
547
548 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_CNTL,
549 sc->sc_cntlbits | CNTL_C);
550
551 harmony_control_wait(sc);
552
553 sc->sc_need_commit = 0;
554
555 if (sc->sc_playing || sc->sc_capturing)
556 harmony_intr_enable(sc);
557
558 return 0;
559 }
560
561 static void
562 harmony_empty_output(struct harmony_softc *sc)
563 {
564
565 WRITE_REG(sc, HARMONY_PNXTADD,
566 sc->sc_playback_paddrs[sc->sc_playback_empty]);
567 SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE);
568
569 if (++sc->sc_playback_empty == PLAYBACK_EMPTYS)
570 sc->sc_playback_empty = 0;
571 }
572
573 int
574 harmony_halt_output(void *vsc)
575 {
576 struct harmony_softc *sc;
577
578 sc = vsc;
579 sc->sc_playing = 0;
580
581 harmony_empty_output(sc);
582 return 0;
583 }
584
585 static void
586 harmony_empty_input(struct harmony_softc *sc)
587 {
588
589 WRITE_REG(sc, HARMONY_RNXTADD,
590 sc->sc_capture_paddrs[sc->sc_capture_empty]);
591 SYNC_REG(sc, HARMONY_RNXTADD, BUS_SPACE_BARRIER_WRITE);
592
593 if (++sc->sc_capture_empty == CAPTURE_EMPTYS)
594 sc->sc_capture_empty = 0;
595 }
596
597 int
598 harmony_halt_input(void *vsc)
599 {
600 struct harmony_softc *sc;
601
602 sc = vsc;
603 sc->sc_capturing = 0;
604
605 harmony_empty_input(sc);
606 return 0;
607 }
608
609 int
610 harmony_getdev(void *vsc, struct audio_device *retp)
611 {
612 struct harmony_softc *sc;
613
614 sc = vsc;
615 *retp = sc->sc_audev;
616 return 0;
617 }
618
619 int
620 harmony_set_port(void *vsc, mixer_ctrl_t *cp)
621 {
622 struct harmony_softc *sc;
623 int err;
624
625 sc = vsc;
626 err = EINVAL;
627 switch (cp->dev) {
628 case HARMONY_PORT_INPUT_LVL:
629 if (cp->type != AUDIO_MIXER_VALUE)
630 break;
631 if (cp->un.value.num_channels == 1)
632 sc->sc_input_lvl.left = sc->sc_input_lvl.right =
633 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
634 else if (cp->un.value.num_channels == 2) {
635 sc->sc_input_lvl.left =
636 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
637 sc->sc_input_lvl.right =
638 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
639 } else
640 break;
641 sc->sc_need_commit = 1;
642 err = 0;
643 break;
644 case HARMONY_PORT_OUTPUT_LVL:
645 if (cp->type != AUDIO_MIXER_VALUE)
646 break;
647 if (cp->un.value.num_channels == 1)
648 sc->sc_output_lvl.left = sc->sc_output_lvl.right =
649 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
650 else if (cp->un.value.num_channels == 2) {
651 sc->sc_output_lvl.left =
652 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
653 sc->sc_output_lvl.right =
654 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
655 } else
656 break;
657 sc->sc_need_commit = 1;
658 err = 0;
659 break;
660 case HARMONY_PORT_OUTPUT_GAIN:
661 if (cp->type != AUDIO_MIXER_ENUM)
662 break;
663 sc->sc_outputgain = cp->un.ord ? 1 : 0;
664 err = 0;
665 break;
666 case HARMONY_PORT_MONITOR_LVL:
667 if (cp->type != AUDIO_MIXER_VALUE)
668 break;
669 if (cp->un.value.num_channels != 1)
670 break;
671 sc->sc_monitor_lvl.left = sc->sc_input_lvl.right =
672 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
673 sc->sc_need_commit = 1;
674 err = 0;
675 break;
676 case HARMONY_PORT_RECORD_SOURCE:
677 if (cp->type != AUDIO_MIXER_ENUM)
678 break;
679 if (cp->un.ord != HARMONY_IN_LINE &&
680 cp->un.ord != HARMONY_IN_MIC)
681 break;
682 sc->sc_in_port = cp->un.ord;
683 err = 0;
684 sc->sc_need_commit = 1;
685 break;
686 case HARMONY_PORT_OUTPUT_SOURCE:
687 if (cp->type != AUDIO_MIXER_ENUM)
688 break;
689 if (cp->un.ord != HARMONY_OUT_LINE &&
690 cp->un.ord != HARMONY_OUT_SPEAKER &&
691 cp->un.ord != HARMONY_OUT_HEADPHONE)
692 break;
693 sc->sc_out_port = cp->un.ord;
694 err = 0;
695 sc->sc_need_commit = 1;
696 break;
697 }
698
699 return err;
700 }
701
702 int
703 harmony_get_port(void *vsc, mixer_ctrl_t *cp)
704 {
705 struct harmony_softc *sc;
706 int err;
707
708 sc = vsc;
709 err = EINVAL;
710 switch (cp->dev) {
711 case HARMONY_PORT_INPUT_LVL:
712 if (cp->type != AUDIO_MIXER_VALUE)
713 break;
714 if (cp->un.value.num_channels == 1) {
715 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
716 sc->sc_input_lvl.left;
717 } else if (cp->un.value.num_channels == 2) {
718 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
719 sc->sc_input_lvl.left;
720 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
721 sc->sc_input_lvl.right;
722 } else
723 break;
724 err = 0;
725 break;
726 case HARMONY_PORT_INPUT_OV:
727 if (cp->type != AUDIO_MIXER_ENUM)
728 break;
729 cp->un.ord = sc->sc_ov ? 1 : 0;
730 err = 0;
731 break;
732 case HARMONY_PORT_OUTPUT_LVL:
733 if (cp->type != AUDIO_MIXER_VALUE)
734 break;
735 if (cp->un.value.num_channels == 1) {
736 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
737 sc->sc_output_lvl.left;
738 } else if (cp->un.value.num_channels == 2) {
739 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
740 sc->sc_output_lvl.left;
741 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
742 sc->sc_output_lvl.right;
743 } else
744 break;
745 err = 0;
746 break;
747 case HARMONY_PORT_OUTPUT_GAIN:
748 if (cp->type != AUDIO_MIXER_ENUM)
749 break;
750 cp->un.ord = sc->sc_outputgain ? 1 : 0;
751 err = 0;
752 break;
753 case HARMONY_PORT_MONITOR_LVL:
754 if (cp->type != AUDIO_MIXER_VALUE)
755 break;
756 if (cp->un.value.num_channels != 1)
757 break;
758 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
759 sc->sc_monitor_lvl.left;
760 err = 0;
761 break;
762 case HARMONY_PORT_RECORD_SOURCE:
763 if (cp->type != AUDIO_MIXER_ENUM)
764 break;
765 cp->un.ord = sc->sc_in_port;
766 err = 0;
767 break;
768 case HARMONY_PORT_OUTPUT_SOURCE:
769 if (cp->type != AUDIO_MIXER_ENUM)
770 break;
771 cp->un.ord = sc->sc_out_port;
772 err = 0;
773 break;
774 }
775 return err;
776 }
777
778 int
779 harmony_query_devinfo(void *vsc, mixer_devinfo_t *dip)
780 {
781 int err;
782
783 err = 0;
784 switch (dip->index) {
785 case HARMONY_PORT_INPUT_LVL:
786 dip->type = AUDIO_MIXER_VALUE;
787 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
788 dip->prev = dip->next = AUDIO_MIXER_LAST;
789 strlcpy(dip->label.name, AudioNinput, sizeof dip->label.name);
790 dip->un.v.num_channels = 2;
791 strlcpy(dip->un.v.units.name, AudioNvolume,
792 sizeof dip->un.v.units.name);
793 break;
794 case HARMONY_PORT_INPUT_OV:
795 dip->type = AUDIO_MIXER_ENUM;
796 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
797 dip->prev = dip->next = AUDIO_MIXER_LAST;
798 strlcpy(dip->label.name, "overrange", sizeof dip->label.name);
799 dip->un.e.num_mem = 2;
800 strlcpy(dip->un.e.member[0].label.name, AudioNoff,
801 sizeof dip->un.e.member[0].label.name);
802 dip->un.e.member[0].ord = 0;
803 strlcpy(dip->un.e.member[1].label.name, AudioNon,
804 sizeof dip->un.e.member[1].label.name);
805 dip->un.e.member[1].ord = 1;
806 break;
807 case HARMONY_PORT_OUTPUT_LVL:
808 dip->type = AUDIO_MIXER_VALUE;
809 dip->mixer_class = HARMONY_PORT_OUTPUT_CLASS;
810 dip->prev = dip->next = AUDIO_MIXER_LAST;
811 strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
812 dip->un.v.num_channels = 2;
813 strlcpy(dip->un.v.units.name, AudioNvolume,
814 sizeof dip->un.v.units.name);
815 break;
816 case HARMONY_PORT_OUTPUT_GAIN:
817 dip->type = AUDIO_MIXER_ENUM;
818 dip->mixer_class = HARMONY_PORT_OUTPUT_CLASS;
819 dip->prev = dip->next = AUDIO_MIXER_LAST;
820 strlcpy(dip->label.name, "gain", sizeof dip->label.name);
821 dip->un.e.num_mem = 2;
822 strlcpy(dip->un.e.member[0].label.name, AudioNoff,
823 sizeof dip->un.e.member[0].label.name);
824 dip->un.e.member[0].ord = 0;
825 strlcpy(dip->un.e.member[1].label.name, AudioNon,
826 sizeof dip->un.e.member[1].label.name);
827 dip->un.e.member[1].ord = 1;
828 break;
829 case HARMONY_PORT_MONITOR_LVL:
830 dip->type = AUDIO_MIXER_VALUE;
831 dip->mixer_class = HARMONY_PORT_MONITOR_CLASS;
832 dip->prev = dip->next = AUDIO_MIXER_LAST;
833 strlcpy(dip->label.name, AudioNmonitor, sizeof dip->label.name);
834 dip->un.v.num_channels = 1;
835 strlcpy(dip->un.v.units.name, AudioNvolume,
836 sizeof dip->un.v.units.name);
837 break;
838 case HARMONY_PORT_RECORD_SOURCE:
839 dip->type = AUDIO_MIXER_ENUM;
840 dip->mixer_class = HARMONY_PORT_RECORD_CLASS;
841 dip->prev = dip->next = AUDIO_MIXER_LAST;
842 strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
843 dip->un.e.num_mem = 2;
844 strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone,
845 sizeof dip->un.e.member[0].label.name);
846 dip->un.e.member[0].ord = HARMONY_IN_MIC;
847 strlcpy(dip->un.e.member[1].label.name, AudioNline,
848 sizeof dip->un.e.member[1].label.name);
849 dip->un.e.member[1].ord = HARMONY_IN_LINE;
850 break;
851 case HARMONY_PORT_OUTPUT_SOURCE:
852 dip->type = AUDIO_MIXER_ENUM;
853 dip->mixer_class = HARMONY_PORT_MONITOR_CLASS;
854 dip->prev = dip->next = AUDIO_MIXER_LAST;
855 strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
856 dip->un.e.num_mem = 3;
857 strlcpy(dip->un.e.member[0].label.name, AudioNline,
858 sizeof dip->un.e.member[0].label.name);
859 dip->un.e.member[0].ord = HARMONY_OUT_LINE;
860 strlcpy(dip->un.e.member[1].label.name, AudioNspeaker,
861 sizeof dip->un.e.member[1].label.name);
862 dip->un.e.member[1].ord = HARMONY_OUT_SPEAKER;
863 strlcpy(dip->un.e.member[2].label.name, AudioNheadphone,
864 sizeof dip->un.e.member[2].label.name);
865 dip->un.e.member[2].ord = HARMONY_OUT_HEADPHONE;
866 break;
867 case HARMONY_PORT_INPUT_CLASS:
868 dip->type = AUDIO_MIXER_CLASS;
869 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
870 dip->prev = dip->next = AUDIO_MIXER_LAST;
871 strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
872 break;
873 case HARMONY_PORT_OUTPUT_CLASS:
874 dip->type = AUDIO_MIXER_CLASS;
875 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
876 dip->prev = dip->next = AUDIO_MIXER_LAST;
877 strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
878 break;
879 case HARMONY_PORT_MONITOR_CLASS:
880 dip->type = AUDIO_MIXER_CLASS;
881 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
882 dip->prev = dip->next = AUDIO_MIXER_LAST;
883 strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name);
884 break;
885 case HARMONY_PORT_RECORD_CLASS:
886 dip->type = AUDIO_MIXER_CLASS;
887 dip->mixer_class = HARMONY_PORT_RECORD_CLASS;
888 dip->prev = dip->next = AUDIO_MIXER_LAST;
889 strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
890 break;
891 default:
892 err = ENXIO;
893 break;
894 }
895
896 return err;
897 }
898
899 void *
900 harmony_allocm(void *vsc, int dir, size_t size)
901 {
902 struct harmony_softc *sc;
903 struct harmony_dma *d;
904 int rseg;
905
906 sc = vsc;
907 d = kmem_alloc(sizeof(*d), KM_SLEEP);
908
909 if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, BUS_DMA_WAITOK,
910 &d->d_map) != 0)
911 goto fail1;
912
913 if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &d->d_seg, 1,
914 &rseg, BUS_DMA_WAITOK) != 0)
915 goto fail2;
916
917 if (bus_dmamem_map(sc->sc_dmat, &d->d_seg, 1, size, &d->d_kva,
918 BUS_DMA_WAITOK) != 0)
919 goto fail3;
920
921 if (bus_dmamap_load(sc->sc_dmat, d->d_map, d->d_kva, size, NULL,
922 BUS_DMA_WAITOK) != 0)
923 goto fail4;
924
925 d->d_next = sc->sc_dmas;
926 sc->sc_dmas = d;
927 d->d_size = size;
928 return (d->d_kva);
929
930 fail4:
931 bus_dmamem_unmap(sc->sc_dmat, d->d_kva, size);
932 fail3:
933 bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1);
934 fail2:
935 bus_dmamap_destroy(sc->sc_dmat, d->d_map);
936 fail1:
937 kmem_free(d, sizeof(*d));
938 return (NULL);
939 }
940
941 void
942 harmony_freem(void *vsc, void *ptr, size_t size)
943 {
944 struct harmony_softc *sc;
945 struct harmony_dma *d, **dd;
946
947 sc = vsc;
948 for (dd = &sc->sc_dmas; (d = *dd) != NULL; dd = &(*dd)->d_next) {
949 if (d->d_kva != ptr)
950 continue;
951 bus_dmamap_unload(sc->sc_dmat, d->d_map);
952 bus_dmamem_unmap(sc->sc_dmat, d->d_kva, d->d_size);
953 bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1);
954 bus_dmamap_destroy(sc->sc_dmat, d->d_map);
955 kmem_free(d, sizeof(*d));
956 return;
957 }
958 printf("%s: free rogue pointer\n", device_xname(sc->sc_dv));
959 }
960
961 size_t
962 harmony_round_buffersize(void *vsc, int direction, size_t size)
963 {
964
965 return ((size + HARMONY_BUFSIZE - 1) & (size_t)(-HARMONY_BUFSIZE));
966 }
967
968 int
969 harmony_get_props(void *vsc)
970 {
971
972 return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE |
973 AUDIO_PROP_FULLDUPLEX;
974 }
975
976 void
977 harmony_get_locks(void *vsc, kmutex_t **intr, kmutex_t **thread)
978 {
979 struct harmony_softc *sc;
980
981 sc = vsc;
982 *intr = &sc->sc_intr_lock;
983 *thread = &sc->sc_lock;
984 }
985
986 int
987 harmony_trigger_output(void *vsc, void *start, void *end, int blksize,
988 void (*intr)(void *), void *intrarg, const audio_params_t *param)
989 {
990 struct harmony_softc *sc;
991 struct harmony_channel *c;
992 struct harmony_dma *d;
993
994 sc = vsc;
995 c = &sc->sc_playback;
996 for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next)
997 continue;
998 if (d == NULL) {
999 printf("%s: trigger_output: bad addr: %p\n",
1000 device_xname(sc->sc_dv), start);
1001 return EINVAL;
1002 }
1003
1004 c->c_intr = intr;
1005 c->c_intrarg = intrarg;
1006 c->c_blksz = blksize;
1007 c->c_current = d;
1008 c->c_segsz = (char *)end - (char *)start;
1009 c->c_cnt = 0;
1010 c->c_lastaddr = d->d_map->dm_segs[0].ds_addr;
1011
1012 sc->sc_playing = 1;
1013
1014 harmony_start_pp(sc, 1);
1015 harmony_start_cp(sc, 0);
1016 harmony_intr_enable(sc);
1017
1018 return 0;
1019 }
1020
1021 void
1022 harmony_start_cp(struct harmony_softc *sc, int start)
1023 {
1024 struct harmony_channel *c;
1025 struct harmony_dma *d;
1026 bus_addr_t nextaddr;
1027 bus_size_t togo;
1028
1029 KASSERT(mutex_owned(&sc->sc_intr_lock));
1030
1031 c = &sc->sc_capture;
1032 if (sc->sc_capturing == 0)
1033 harmony_empty_input(sc);
1034 else {
1035 d = c->c_current;
1036 togo = c->c_segsz - c->c_cnt;
1037 if (togo == 0) {
1038 nextaddr = d->d_map->dm_segs[0].ds_addr;
1039 c->c_cnt = togo = c->c_blksz;
1040 } else {
1041 nextaddr = c->c_lastaddr;
1042 if (togo > c->c_blksz)
1043 togo = c->c_blksz;
1044 c->c_cnt += togo;
1045 }
1046
1047 bus_dmamap_sync(sc->sc_dmat, d->d_map,
1048 nextaddr - d->d_map->dm_segs[0].ds_addr,
1049 c->c_blksz, BUS_DMASYNC_PREWRITE);
1050
1051 WRITE_REG(sc, HARMONY_RNXTADD, nextaddr);
1052 if (start)
1053 c->c_theaddr = nextaddr;
1054 SYNC_REG(sc, HARMONY_RNXTADD, BUS_SPACE_BARRIER_WRITE);
1055 c->c_lastaddr = nextaddr + togo;
1056
1057 harmony_try_more(sc, HARMONY_RCURADD,
1058 RCURADD_BUFMASK, &sc->sc_capture);
1059 }
1060
1061 callout_schedule(&sc->sc_acc_tmo, 1);
1062 }
1063
1064 void
1065 harmony_start_pp(struct harmony_softc *sc, int start)
1066 {
1067 struct harmony_channel *c;
1068 struct harmony_dma *d;
1069 bus_addr_t nextaddr;
1070 bus_size_t togo;
1071
1072 KASSERT(mutex_owned(&sc->sc_intr_lock));
1073
1074 c = &sc->sc_playback;
1075 if (sc->sc_playing == 0)
1076 harmony_empty_output(sc);
1077 else {
1078 d = c->c_current;
1079 togo = c->c_segsz - c->c_cnt;
1080 if (togo == 0) {
1081 nextaddr = d->d_map->dm_segs[0].ds_addr;
1082 c->c_cnt = togo = c->c_blksz;
1083 } else {
1084 nextaddr = c->c_lastaddr;
1085 if (togo > c->c_blksz)
1086 togo = c->c_blksz;
1087 c->c_cnt += togo;
1088 }
1089
1090 bus_dmamap_sync(sc->sc_dmat, d->d_map,
1091 nextaddr - d->d_map->dm_segs[0].ds_addr,
1092 c->c_blksz, BUS_DMASYNC_PREWRITE);
1093
1094 WRITE_REG(sc, HARMONY_PNXTADD, nextaddr);
1095 if (start)
1096 c->c_theaddr = nextaddr;
1097 SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE);
1098 c->c_lastaddr = nextaddr + togo;
1099
1100 harmony_try_more(sc, HARMONY_PCURADD,
1101 PCURADD_BUFMASK, &sc->sc_playback);
1102 }
1103 }
1104
1105 int
1106 harmony_trigger_input(void *vsc, void *start, void *end, int blksize,
1107 void (*intr)(void *), void *intrarg, const audio_params_t *param)
1108 {
1109 struct harmony_softc *sc = vsc;
1110 struct harmony_channel *c = &sc->sc_capture;
1111 struct harmony_dma *d;
1112
1113 KASSERT(mutex_owned(&sc->sc_intr_lock));
1114
1115 for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next)
1116 continue;
1117 if (d == NULL) {
1118 printf("%s: trigger_input: bad addr: %p\n",
1119 device_xname(sc->sc_dv), start);
1120 return EINVAL;
1121 }
1122
1123 c->c_intr = intr;
1124 c->c_intrarg = intrarg;
1125 c->c_blksz = blksize;
1126 c->c_current = d;
1127 c->c_segsz = (char *)end - (char *)start;
1128 c->c_cnt = 0;
1129 c->c_lastaddr = d->d_map->dm_segs[0].ds_addr;
1130
1131 sc->sc_capturing = 1;
1132
1133 harmony_start_cp(sc, 1);
1134 harmony_intr_enable(sc);
1135
1136 return 0;
1137 }
1138
1139 static const struct speed_struct {
1140 uint32_t speed;
1141 uint32_t bits;
1142 } harmony_speeds[] = {
1143 { 5125, CNTL_RATE_5125 },
1144 { 6615, CNTL_RATE_6615 },
1145 { 8000, CNTL_RATE_8000 },
1146 { 9600, CNTL_RATE_9600 },
1147 { 11025, CNTL_RATE_11025 },
1148 { 16000, CNTL_RATE_16000 },
1149 { 18900, CNTL_RATE_18900 },
1150 { 22050, CNTL_RATE_22050 },
1151 { 27428, CNTL_RATE_27428 },
1152 { 32000, CNTL_RATE_32000 },
1153 { 33075, CNTL_RATE_33075 },
1154 { 37800, CNTL_RATE_37800 },
1155 { 44100, CNTL_RATE_44100 },
1156 { 48000, CNTL_RATE_48000 },
1157 };
1158
1159 uint32_t
1160 harmony_speed_bits(struct harmony_softc *sc, u_int speed)
1161 {
1162 int i;
1163
1164 for (i = 0; i < __arraycount(harmony_speeds); i++) {
1165 if (speed == harmony_speeds[i].speed) {
1166 return harmony_speeds[i].bits;
1167 }
1168 }
1169 /* If this happens, harmony_formats[] is wrong */
1170 panic("speed %u not supported", speed);
1171 }
1172
1173 int
1174 harmony_set_gainctl(struct harmony_softc *sc)
1175 {
1176 uint32_t bits, mask, val, old;
1177
1178 /* XXX leave these bits alone or the chip will not come out of CNTL */
1179 bits = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK;
1180
1181 /* input level */
1182 bits |= ((sc->sc_input_lvl.left >> (8 - GAINCTL_INPUT_BITS)) <<
1183 GAINCTL_INPUT_LEFT_S) & GAINCTL_INPUT_LEFT_M;
1184 bits |= ((sc->sc_input_lvl.right >> (8 - GAINCTL_INPUT_BITS)) <<
1185 GAINCTL_INPUT_RIGHT_S) & GAINCTL_INPUT_RIGHT_M;
1186
1187 /* output level (inverted) */
1188 mask = (1 << GAINCTL_OUTPUT_BITS) - 1;
1189 val = mask - (sc->sc_output_lvl.left >> (8 - GAINCTL_OUTPUT_BITS));
1190 bits |= (val << GAINCTL_OUTPUT_LEFT_S) & GAINCTL_OUTPUT_LEFT_M;
1191 val = mask - (sc->sc_output_lvl.right >> (8 - GAINCTL_OUTPUT_BITS));
1192 bits |= (val << GAINCTL_OUTPUT_RIGHT_S) & GAINCTL_OUTPUT_RIGHT_M;
1193
1194 /* monitor level (inverted) */
1195 mask = (1 << GAINCTL_MONITOR_BITS) - 1;
1196 val = mask - (sc->sc_monitor_lvl.left >> (8 - GAINCTL_MONITOR_BITS));
1197 bits |= (val << GAINCTL_MONITOR_S) & GAINCTL_MONITOR_M;
1198
1199 /* XXX messing with these causes CNTL_C to get stuck... grr. */
1200 bits &= ~GAINCTL_IS_MASK;
1201 if (sc->sc_in_port == HARMONY_IN_MIC)
1202 bits |= GAINCTL_IS_LINE;
1203 else
1204 bits |= GAINCTL_IS_MICROPHONE;
1205
1206 /* XXX messing with these causes CNTL_C to get stuck... grr. */
1207 bits &= ~(GAINCTL_LE | GAINCTL_HE | GAINCTL_SE);
1208 if (sc->sc_out_port == HARMONY_OUT_LINE)
1209 bits |= GAINCTL_LE;
1210 else if (sc->sc_out_port == HARMONY_OUT_SPEAKER)
1211 bits |= GAINCTL_SE;
1212 else
1213 bits |= GAINCTL_HE;
1214
1215 mask = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK;
1216 old = bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL);
1217 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL, bits);
1218 if ((old & mask) != (bits & mask))
1219 return 1;
1220 return 0;
1221 }
1222
1223 void
1224 harmony_try_more(struct harmony_softc *sc, int curadd, int bufmask,
1225 struct harmony_channel *c)
1226 {
1227 struct harmony_dma *d;
1228 uint32_t cur;
1229 int i, nsegs;
1230
1231 d = c->c_current;
1232 cur = bus_space_read_4(sc->sc_bt, sc->sc_bh, curadd);
1233 cur &= bufmask;
1234 nsegs = 0;
1235
1236 #ifdef DIAGNOSTIC
1237 if (cur < d->d_map->dm_segs[0].ds_addr ||
1238 cur >= (d->d_map->dm_segs[0].ds_addr + c->c_segsz))
1239 panic("%s: bad current %x < %lx || %x > %lx",
1240 device_xname(sc->sc_dv), cur,
1241 d->d_map->dm_segs[0].ds_addr, cur,
1242 d->d_map->dm_segs[0].ds_addr + c->c_segsz);
1243 #endif /* DIAGNOSTIC */
1244
1245 if (cur > c->c_theaddr) {
1246 nsegs = (cur - c->c_theaddr) / HARMONY_BUFSIZE;
1247 } else if (cur < c->c_theaddr) {
1248 nsegs = (d->d_map->dm_segs[0].ds_addr + c->c_segsz -
1249 c->c_theaddr) / HARMONY_BUFSIZE;
1250 nsegs += (cur - d->d_map->dm_segs[0].ds_addr) /
1251 HARMONY_BUFSIZE;
1252 }
1253
1254 if (nsegs != 0 && c->c_intr != NULL) {
1255 for (i = 0; i < nsegs; i++)
1256 (*c->c_intr)(c->c_intrarg);
1257 c->c_theaddr = cur;
1258 }
1259 }
1260