harmony.c revision 1.5.2.2 1 /* $NetBSD: harmony.c,v 1.5.2.2 2019/05/04 04:51:20 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_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 int rate;
445
446 sc = vsc;
447
448 /* *play and *rec are the identical because !AUDIO_PROP_INDEPENDENT. */
449 switch (play->encoding) {
450 case AUDIO_ENCODING_ULAW:
451 bits = CNTL_FORMAT_ULAW;
452 break;
453 case AUDIO_ENCODING_ALAW:
454 bits = CNTL_FORMAT_ALAW;
455 break;
456 case AUDIO_ENCODING_SLINEAR_BE:
457 bits = CNTL_FORMAT_SLINEAR16BE;
458 break;
459 default:
460 return EINVAL;
461 }
462
463 if (sc->sc_outputgain)
464 bits |= CNTL_OLB;
465
466 bits |= CNTL_CHANS_STEREO;
467
468 /* XXX modify harmony_speed_bits() not to rewrite rate */
469 rate = play->sample_rate;
470 sc->sc_cntlbits |= harmony_speed_bits(sc, &rate);
471 sc->sc_need_commit = 1;
472
473 return 0;
474 }
475
476 int
477 harmony_round_blocksize(void *vsc, int blk,
478 int mode, const audio_params_t *param)
479 {
480
481 return HARMONY_BUFSIZE;
482 }
483
484 int
485 harmony_control_wait(struct harmony_softc *sc)
486 {
487 uint32_t reg;
488 int j = 0;
489
490 while (j < 10) {
491 /* Wait for it to come out of control mode */
492 reg = READ_REG(sc, HARMONY_CNTL);
493 if ((reg & CNTL_C) == 0)
494 return 0;
495 DELAY(50000); /* wait 0.05 */
496 j++;
497 }
498
499 return 1;
500 }
501
502 int
503 harmony_commit_settings(void *vsc)
504 {
505 struct harmony_softc *sc;
506 uint32_t reg;
507 uint8_t quietchar;
508 int i;
509
510 sc = vsc;
511 if (sc->sc_need_commit == 0)
512 return 0;
513
514 harmony_intr_disable(sc);
515
516 for (;;) {
517 reg = READ_REG(sc, HARMONY_DSTATUS);
518 if ((reg & (DSTATUS_PC | DSTATUS_RC)) == 0)
519 break;
520 }
521
522 /* Setting some bits in gainctl requires a reset */
523 harmony_reset_codec(sc);
524
525 /* set the silence character based on the encoding type */
526 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
527 offsetof(struct harmony_empty, playback[0][0]),
528 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_POSTWRITE);
529 switch (sc->sc_cntlbits & CNTL_FORMAT_MASK) {
530 case CNTL_FORMAT_ULAW:
531 quietchar = 0x7f;
532 break;
533 case CNTL_FORMAT_ALAW:
534 quietchar = 0x55;
535 break;
536 case CNTL_FORMAT_SLINEAR16BE:
537 case CNTL_FORMAT_ULINEAR8:
538 default:
539 quietchar = 0;
540 break;
541 }
542 for (i = 0; i < PLAYBACK_EMPTYS; i++)
543 memset(&sc->sc_empty_kva->playback[i][0],
544 quietchar, HARMONY_BUFSIZE);
545 bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
546 offsetof(struct harmony_empty, playback[0][0]),
547 PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE);
548
549 harmony_control_wait(sc);
550
551 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_CNTL,
552 sc->sc_cntlbits | CNTL_C);
553
554 harmony_control_wait(sc);
555
556 sc->sc_need_commit = 0;
557
558 if (sc->sc_playing || sc->sc_capturing)
559 harmony_intr_enable(sc);
560
561 return 0;
562 }
563
564 static void
565 harmony_empty_output(struct harmony_softc *sc)
566 {
567
568 WRITE_REG(sc, HARMONY_PNXTADD,
569 sc->sc_playback_paddrs[sc->sc_playback_empty]);
570 SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE);
571
572 if (++sc->sc_playback_empty == PLAYBACK_EMPTYS)
573 sc->sc_playback_empty = 0;
574 }
575
576 int
577 harmony_halt_output(void *vsc)
578 {
579 struct harmony_softc *sc;
580
581 sc = vsc;
582 sc->sc_playing = 0;
583
584 harmony_empty_output(sc);
585 return 0;
586 }
587
588 static void
589 harmony_empty_input(struct harmony_softc *sc)
590 {
591
592 WRITE_REG(sc, HARMONY_RNXTADD,
593 sc->sc_capture_paddrs[sc->sc_capture_empty]);
594 SYNC_REG(sc, HARMONY_RNXTADD, BUS_SPACE_BARRIER_WRITE);
595
596 if (++sc->sc_capture_empty == CAPTURE_EMPTYS)
597 sc->sc_capture_empty = 0;
598 }
599
600 int
601 harmony_halt_input(void *vsc)
602 {
603 struct harmony_softc *sc;
604
605 sc = vsc;
606 sc->sc_capturing = 0;
607
608 harmony_empty_input(sc);
609 return 0;
610 }
611
612 int
613 harmony_getdev(void *vsc, struct audio_device *retp)
614 {
615 struct harmony_softc *sc;
616
617 sc = vsc;
618 *retp = sc->sc_audev;
619 return 0;
620 }
621
622 int
623 harmony_set_port(void *vsc, mixer_ctrl_t *cp)
624 {
625 struct harmony_softc *sc;
626 int err;
627
628 sc = vsc;
629 err = EINVAL;
630 switch (cp->dev) {
631 case HARMONY_PORT_INPUT_LVL:
632 if (cp->type != AUDIO_MIXER_VALUE)
633 break;
634 if (cp->un.value.num_channels == 1)
635 sc->sc_input_lvl.left = sc->sc_input_lvl.right =
636 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
637 else if (cp->un.value.num_channels == 2) {
638 sc->sc_input_lvl.left =
639 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
640 sc->sc_input_lvl.right =
641 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
642 } else
643 break;
644 sc->sc_need_commit = 1;
645 err = 0;
646 break;
647 case HARMONY_PORT_OUTPUT_LVL:
648 if (cp->type != AUDIO_MIXER_VALUE)
649 break;
650 if (cp->un.value.num_channels == 1)
651 sc->sc_output_lvl.left = sc->sc_output_lvl.right =
652 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
653 else if (cp->un.value.num_channels == 2) {
654 sc->sc_output_lvl.left =
655 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
656 sc->sc_output_lvl.right =
657 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
658 } else
659 break;
660 sc->sc_need_commit = 1;
661 err = 0;
662 break;
663 case HARMONY_PORT_OUTPUT_GAIN:
664 if (cp->type != AUDIO_MIXER_ENUM)
665 break;
666 sc->sc_outputgain = cp->un.ord ? 1 : 0;
667 err = 0;
668 break;
669 case HARMONY_PORT_MONITOR_LVL:
670 if (cp->type != AUDIO_MIXER_VALUE)
671 break;
672 if (cp->un.value.num_channels != 1)
673 break;
674 sc->sc_monitor_lvl.left = sc->sc_input_lvl.right =
675 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
676 sc->sc_need_commit = 1;
677 err = 0;
678 break;
679 case HARMONY_PORT_RECORD_SOURCE:
680 if (cp->type != AUDIO_MIXER_ENUM)
681 break;
682 if (cp->un.ord != HARMONY_IN_LINE &&
683 cp->un.ord != HARMONY_IN_MIC)
684 break;
685 sc->sc_in_port = cp->un.ord;
686 err = 0;
687 sc->sc_need_commit = 1;
688 break;
689 case HARMONY_PORT_OUTPUT_SOURCE:
690 if (cp->type != AUDIO_MIXER_ENUM)
691 break;
692 if (cp->un.ord != HARMONY_OUT_LINE &&
693 cp->un.ord != HARMONY_OUT_SPEAKER &&
694 cp->un.ord != HARMONY_OUT_HEADPHONE)
695 break;
696 sc->sc_out_port = cp->un.ord;
697 err = 0;
698 sc->sc_need_commit = 1;
699 break;
700 }
701
702 return err;
703 }
704
705 int
706 harmony_get_port(void *vsc, mixer_ctrl_t *cp)
707 {
708 struct harmony_softc *sc;
709 int err;
710
711 sc = vsc;
712 err = EINVAL;
713 switch (cp->dev) {
714 case HARMONY_PORT_INPUT_LVL:
715 if (cp->type != AUDIO_MIXER_VALUE)
716 break;
717 if (cp->un.value.num_channels == 1) {
718 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
719 sc->sc_input_lvl.left;
720 } else if (cp->un.value.num_channels == 2) {
721 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
722 sc->sc_input_lvl.left;
723 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
724 sc->sc_input_lvl.right;
725 } else
726 break;
727 err = 0;
728 break;
729 case HARMONY_PORT_INPUT_OV:
730 if (cp->type != AUDIO_MIXER_ENUM)
731 break;
732 cp->un.ord = sc->sc_ov ? 1 : 0;
733 err = 0;
734 break;
735 case HARMONY_PORT_OUTPUT_LVL:
736 if (cp->type != AUDIO_MIXER_VALUE)
737 break;
738 if (cp->un.value.num_channels == 1) {
739 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
740 sc->sc_output_lvl.left;
741 } else if (cp->un.value.num_channels == 2) {
742 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
743 sc->sc_output_lvl.left;
744 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
745 sc->sc_output_lvl.right;
746 } else
747 break;
748 err = 0;
749 break;
750 case HARMONY_PORT_OUTPUT_GAIN:
751 if (cp->type != AUDIO_MIXER_ENUM)
752 break;
753 cp->un.ord = sc->sc_outputgain ? 1 : 0;
754 err = 0;
755 break;
756 case HARMONY_PORT_MONITOR_LVL:
757 if (cp->type != AUDIO_MIXER_VALUE)
758 break;
759 if (cp->un.value.num_channels != 1)
760 break;
761 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
762 sc->sc_monitor_lvl.left;
763 err = 0;
764 break;
765 case HARMONY_PORT_RECORD_SOURCE:
766 if (cp->type != AUDIO_MIXER_ENUM)
767 break;
768 cp->un.ord = sc->sc_in_port;
769 err = 0;
770 break;
771 case HARMONY_PORT_OUTPUT_SOURCE:
772 if (cp->type != AUDIO_MIXER_ENUM)
773 break;
774 cp->un.ord = sc->sc_out_port;
775 err = 0;
776 break;
777 }
778 return err;
779 }
780
781 int
782 harmony_query_devinfo(void *vsc, mixer_devinfo_t *dip)
783 {
784 int err;
785
786 err = 0;
787 switch (dip->index) {
788 case HARMONY_PORT_INPUT_LVL:
789 dip->type = AUDIO_MIXER_VALUE;
790 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
791 dip->prev = dip->next = AUDIO_MIXER_LAST;
792 strlcpy(dip->label.name, AudioNinput, sizeof dip->label.name);
793 dip->un.v.num_channels = 2;
794 strlcpy(dip->un.v.units.name, AudioNvolume,
795 sizeof dip->un.v.units.name);
796 break;
797 case HARMONY_PORT_INPUT_OV:
798 dip->type = AUDIO_MIXER_ENUM;
799 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
800 dip->prev = dip->next = AUDIO_MIXER_LAST;
801 strlcpy(dip->label.name, "overrange", sizeof dip->label.name);
802 dip->un.e.num_mem = 2;
803 strlcpy(dip->un.e.member[0].label.name, AudioNoff,
804 sizeof dip->un.e.member[0].label.name);
805 dip->un.e.member[0].ord = 0;
806 strlcpy(dip->un.e.member[1].label.name, AudioNon,
807 sizeof dip->un.e.member[1].label.name);
808 dip->un.e.member[1].ord = 1;
809 break;
810 case HARMONY_PORT_OUTPUT_LVL:
811 dip->type = AUDIO_MIXER_VALUE;
812 dip->mixer_class = HARMONY_PORT_OUTPUT_CLASS;
813 dip->prev = dip->next = AUDIO_MIXER_LAST;
814 strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
815 dip->un.v.num_channels = 2;
816 strlcpy(dip->un.v.units.name, AudioNvolume,
817 sizeof dip->un.v.units.name);
818 break;
819 case HARMONY_PORT_OUTPUT_GAIN:
820 dip->type = AUDIO_MIXER_ENUM;
821 dip->mixer_class = HARMONY_PORT_OUTPUT_CLASS;
822 dip->prev = dip->next = AUDIO_MIXER_LAST;
823 strlcpy(dip->label.name, "gain", sizeof dip->label.name);
824 dip->un.e.num_mem = 2;
825 strlcpy(dip->un.e.member[0].label.name, AudioNoff,
826 sizeof dip->un.e.member[0].label.name);
827 dip->un.e.member[0].ord = 0;
828 strlcpy(dip->un.e.member[1].label.name, AudioNon,
829 sizeof dip->un.e.member[1].label.name);
830 dip->un.e.member[1].ord = 1;
831 break;
832 case HARMONY_PORT_MONITOR_LVL:
833 dip->type = AUDIO_MIXER_VALUE;
834 dip->mixer_class = HARMONY_PORT_MONITOR_CLASS;
835 dip->prev = dip->next = AUDIO_MIXER_LAST;
836 strlcpy(dip->label.name, AudioNmonitor, sizeof dip->label.name);
837 dip->un.v.num_channels = 1;
838 strlcpy(dip->un.v.units.name, AudioNvolume,
839 sizeof dip->un.v.units.name);
840 break;
841 case HARMONY_PORT_RECORD_SOURCE:
842 dip->type = AUDIO_MIXER_ENUM;
843 dip->mixer_class = HARMONY_PORT_RECORD_CLASS;
844 dip->prev = dip->next = AUDIO_MIXER_LAST;
845 strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
846 dip->un.e.num_mem = 2;
847 strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone,
848 sizeof dip->un.e.member[0].label.name);
849 dip->un.e.member[0].ord = HARMONY_IN_MIC;
850 strlcpy(dip->un.e.member[1].label.name, AudioNline,
851 sizeof dip->un.e.member[1].label.name);
852 dip->un.e.member[1].ord = HARMONY_IN_LINE;
853 break;
854 case HARMONY_PORT_OUTPUT_SOURCE:
855 dip->type = AUDIO_MIXER_ENUM;
856 dip->mixer_class = HARMONY_PORT_MONITOR_CLASS;
857 dip->prev = dip->next = AUDIO_MIXER_LAST;
858 strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
859 dip->un.e.num_mem = 3;
860 strlcpy(dip->un.e.member[0].label.name, AudioNline,
861 sizeof dip->un.e.member[0].label.name);
862 dip->un.e.member[0].ord = HARMONY_OUT_LINE;
863 strlcpy(dip->un.e.member[1].label.name, AudioNspeaker,
864 sizeof dip->un.e.member[1].label.name);
865 dip->un.e.member[1].ord = HARMONY_OUT_SPEAKER;
866 strlcpy(dip->un.e.member[2].label.name, AudioNheadphone,
867 sizeof dip->un.e.member[2].label.name);
868 dip->un.e.member[2].ord = HARMONY_OUT_HEADPHONE;
869 break;
870 case HARMONY_PORT_INPUT_CLASS:
871 dip->type = AUDIO_MIXER_CLASS;
872 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
873 dip->prev = dip->next = AUDIO_MIXER_LAST;
874 strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
875 break;
876 case HARMONY_PORT_OUTPUT_CLASS:
877 dip->type = AUDIO_MIXER_CLASS;
878 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
879 dip->prev = dip->next = AUDIO_MIXER_LAST;
880 strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
881 break;
882 case HARMONY_PORT_MONITOR_CLASS:
883 dip->type = AUDIO_MIXER_CLASS;
884 dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
885 dip->prev = dip->next = AUDIO_MIXER_LAST;
886 strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name);
887 break;
888 case HARMONY_PORT_RECORD_CLASS:
889 dip->type = AUDIO_MIXER_CLASS;
890 dip->mixer_class = HARMONY_PORT_RECORD_CLASS;
891 dip->prev = dip->next = AUDIO_MIXER_LAST;
892 strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
893 break;
894 default:
895 err = ENXIO;
896 break;
897 }
898
899 return err;
900 }
901
902 void *
903 harmony_allocm(void *vsc, int dir, size_t size)
904 {
905 struct harmony_softc *sc;
906 struct harmony_dma *d;
907 int rseg;
908
909 sc = vsc;
910 d = kmem_alloc(sizeof(*d), KM_SLEEP);
911
912 if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, BUS_DMA_WAITOK,
913 &d->d_map) != 0)
914 goto fail1;
915
916 if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &d->d_seg, 1,
917 &rseg, BUS_DMA_WAITOK) != 0)
918 goto fail2;
919
920 if (bus_dmamem_map(sc->sc_dmat, &d->d_seg, 1, size, &d->d_kva,
921 BUS_DMA_WAITOK) != 0)
922 goto fail3;
923
924 if (bus_dmamap_load(sc->sc_dmat, d->d_map, d->d_kva, size, NULL,
925 BUS_DMA_WAITOK) != 0)
926 goto fail4;
927
928 d->d_next = sc->sc_dmas;
929 sc->sc_dmas = d;
930 d->d_size = size;
931 return (d->d_kva);
932
933 fail4:
934 bus_dmamem_unmap(sc->sc_dmat, d->d_kva, size);
935 fail3:
936 bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1);
937 fail2:
938 bus_dmamap_destroy(sc->sc_dmat, d->d_map);
939 fail1:
940 kmem_free(d, sizeof(*d));
941 return (NULL);
942 }
943
944 void
945 harmony_freem(void *vsc, void *ptr, size_t size)
946 {
947 struct harmony_softc *sc;
948 struct harmony_dma *d, **dd;
949
950 sc = vsc;
951 for (dd = &sc->sc_dmas; (d = *dd) != NULL; dd = &(*dd)->d_next) {
952 if (d->d_kva != ptr)
953 continue;
954 bus_dmamap_unload(sc->sc_dmat, d->d_map);
955 bus_dmamem_unmap(sc->sc_dmat, d->d_kva, d->d_size);
956 bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1);
957 bus_dmamap_destroy(sc->sc_dmat, d->d_map);
958 kmem_free(d, sizeof(*d));
959 return;
960 }
961 printf("%s: free rogue pointer\n", device_xname(sc->sc_dv));
962 }
963
964 size_t
965 harmony_round_buffersize(void *vsc, int direction, size_t size)
966 {
967
968 return ((size + HARMONY_BUFSIZE - 1) & (size_t)(-HARMONY_BUFSIZE));
969 }
970
971 int
972 harmony_get_props(void *vsc)
973 {
974
975 return AUDIO_PROP_FULLDUPLEX;
976 }
977
978 void
979 harmony_get_locks(void *vsc, kmutex_t **intr, kmutex_t **thread)
980 {
981 struct harmony_softc *sc;
982
983 sc = vsc;
984 *intr = &sc->sc_intr_lock;
985 *thread = &sc->sc_lock;
986 }
987
988 int
989 harmony_trigger_output(void *vsc, void *start, void *end, int blksize,
990 void (*intr)(void *), void *intrarg, const audio_params_t *param)
991 {
992 struct harmony_softc *sc;
993 struct harmony_channel *c;
994 struct harmony_dma *d;
995
996 sc = vsc;
997 c = &sc->sc_playback;
998 for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next)
999 continue;
1000 if (d == NULL) {
1001 printf("%s: trigger_output: bad addr: %p\n",
1002 device_xname(sc->sc_dv), start);
1003 return EINVAL;
1004 }
1005
1006 mutex_spin_enter(&sc->sc_intr_lock);
1007
1008 c->c_intr = intr;
1009 c->c_intrarg = intrarg;
1010 c->c_blksz = blksize;
1011 c->c_current = d;
1012 c->c_segsz = (char *)end - (char *)start;
1013 c->c_cnt = 0;
1014 c->c_lastaddr = d->d_map->dm_segs[0].ds_addr;
1015
1016 sc->sc_playing = 1;
1017
1018 harmony_start_pp(sc, 1);
1019 harmony_start_cp(sc, 0);
1020 harmony_intr_enable(sc);
1021
1022 mutex_spin_exit(&sc->sc_intr_lock);
1023
1024 return 0;
1025 }
1026
1027 void
1028 harmony_start_cp(struct harmony_softc *sc, int start)
1029 {
1030 struct harmony_channel *c;
1031 struct harmony_dma *d;
1032 bus_addr_t nextaddr;
1033 bus_size_t togo;
1034
1035 KASSERT(mutex_owned(&sc->sc_intr_lock));
1036
1037 c = &sc->sc_capture;
1038 if (sc->sc_capturing == 0)
1039 harmony_empty_input(sc);
1040 else {
1041 d = c->c_current;
1042 togo = c->c_segsz - c->c_cnt;
1043 if (togo == 0) {
1044 nextaddr = d->d_map->dm_segs[0].ds_addr;
1045 c->c_cnt = togo = c->c_blksz;
1046 } else {
1047 nextaddr = c->c_lastaddr;
1048 if (togo > c->c_blksz)
1049 togo = c->c_blksz;
1050 c->c_cnt += togo;
1051 }
1052
1053 bus_dmamap_sync(sc->sc_dmat, d->d_map,
1054 nextaddr - d->d_map->dm_segs[0].ds_addr,
1055 c->c_blksz, BUS_DMASYNC_PREWRITE);
1056
1057 WRITE_REG(sc, HARMONY_RNXTADD, nextaddr);
1058 if (start)
1059 c->c_theaddr = nextaddr;
1060 SYNC_REG(sc, HARMONY_RNXTADD, BUS_SPACE_BARRIER_WRITE);
1061 c->c_lastaddr = nextaddr + togo;
1062
1063 harmony_try_more(sc, HARMONY_RCURADD,
1064 RCURADD_BUFMASK, &sc->sc_capture);
1065 }
1066
1067 callout_schedule(&sc->sc_acc_tmo, 1);
1068 }
1069
1070 void
1071 harmony_start_pp(struct harmony_softc *sc, int start)
1072 {
1073 struct harmony_channel *c;
1074 struct harmony_dma *d;
1075 bus_addr_t nextaddr;
1076 bus_size_t togo;
1077
1078 KASSERT(mutex_owned(&sc->sc_intr_lock));
1079
1080 c = &sc->sc_playback;
1081 if (sc->sc_playing == 0)
1082 harmony_empty_output(sc);
1083 else {
1084 d = c->c_current;
1085 togo = c->c_segsz - c->c_cnt;
1086 if (togo == 0) {
1087 nextaddr = d->d_map->dm_segs[0].ds_addr;
1088 c->c_cnt = togo = c->c_blksz;
1089 } else {
1090 nextaddr = c->c_lastaddr;
1091 if (togo > c->c_blksz)
1092 togo = c->c_blksz;
1093 c->c_cnt += togo;
1094 }
1095
1096 bus_dmamap_sync(sc->sc_dmat, d->d_map,
1097 nextaddr - d->d_map->dm_segs[0].ds_addr,
1098 c->c_blksz, BUS_DMASYNC_PREWRITE);
1099
1100 WRITE_REG(sc, HARMONY_PNXTADD, nextaddr);
1101 if (start)
1102 c->c_theaddr = nextaddr;
1103 SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE);
1104 c->c_lastaddr = nextaddr + togo;
1105
1106 harmony_try_more(sc, HARMONY_PCURADD,
1107 PCURADD_BUFMASK, &sc->sc_playback);
1108 }
1109 }
1110
1111 int
1112 harmony_trigger_input(void *vsc, void *start, void *end, int blksize,
1113 void (*intr)(void *), void *intrarg, const audio_params_t *param)
1114 {
1115 struct harmony_softc *sc = vsc;
1116 struct harmony_channel *c = &sc->sc_capture;
1117 struct harmony_dma *d;
1118
1119 KASSERT(mutex_owned(&sc->sc_intr_lock));
1120
1121 for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next)
1122 continue;
1123 if (d == NULL) {
1124 printf("%s: trigger_input: bad addr: %p\n",
1125 device_xname(sc->sc_dv), start);
1126 return EINVAL;
1127 }
1128
1129 c->c_intr = intr;
1130 c->c_intrarg = intrarg;
1131 c->c_blksz = blksize;
1132 c->c_current = d;
1133 c->c_segsz = (char *)end - (char *)start;
1134 c->c_cnt = 0;
1135 c->c_lastaddr = d->d_map->dm_segs[0].ds_addr;
1136
1137 sc->sc_capturing = 1;
1138
1139 harmony_start_cp(sc, 1);
1140 harmony_intr_enable(sc);
1141
1142 return 0;
1143 }
1144
1145 static const struct speed_struct {
1146 uint32_t speed;
1147 uint32_t bits;
1148 } harmony_speeds[] = {
1149 { 5125, CNTL_RATE_5125 },
1150 { 6615, CNTL_RATE_6615 },
1151 { 8000, CNTL_RATE_8000 },
1152 { 9600, CNTL_RATE_9600 },
1153 { 11025, CNTL_RATE_11025 },
1154 { 16000, CNTL_RATE_16000 },
1155 { 18900, CNTL_RATE_18900 },
1156 { 22050, CNTL_RATE_22050 },
1157 { 27428, CNTL_RATE_27428 },
1158 { 32000, CNTL_RATE_32000 },
1159 { 33075, CNTL_RATE_33075 },
1160 { 37800, CNTL_RATE_37800 },
1161 { 44100, CNTL_RATE_44100 },
1162 { 48000, CNTL_RATE_48000 },
1163 };
1164
1165 uint32_t
1166 harmony_speed_bits(struct harmony_softc *sc, u_int *speedp)
1167 {
1168 int i, n, selected;
1169
1170 selected = -1;
1171 n = sizeof(harmony_speeds) / sizeof(harmony_speeds[0]);
1172
1173 if ((*speedp) <= harmony_speeds[0].speed)
1174 selected = 0;
1175 else if ((*speedp) >= harmony_speeds[n - 1].speed)
1176 selected = n - 1;
1177 else {
1178 for (i = 1; selected == -1 && i < n; i++) {
1179 if ((*speedp) == harmony_speeds[i].speed)
1180 selected = i;
1181 else if ((*speedp) < harmony_speeds[i].speed) {
1182 int diff1, diff2;
1183
1184 diff1 = (*speedp) - harmony_speeds[i - 1].speed;
1185 diff2 = harmony_speeds[i].speed - (*speedp);
1186 if (diff1 < diff2)
1187 selected = i - 1;
1188 else
1189 selected = i;
1190 }
1191 }
1192 }
1193
1194 if (selected == -1)
1195 selected = 2;
1196
1197 *speedp = harmony_speeds[selected].speed;
1198 return harmony_speeds[selected].bits;
1199 }
1200
1201 int
1202 harmony_set_gainctl(struct harmony_softc *sc)
1203 {
1204 uint32_t bits, mask, val, old;
1205
1206 /* XXX leave these bits alone or the chip will not come out of CNTL */
1207 bits = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK;
1208
1209 /* input level */
1210 bits |= ((sc->sc_input_lvl.left >> (8 - GAINCTL_INPUT_BITS)) <<
1211 GAINCTL_INPUT_LEFT_S) & GAINCTL_INPUT_LEFT_M;
1212 bits |= ((sc->sc_input_lvl.right >> (8 - GAINCTL_INPUT_BITS)) <<
1213 GAINCTL_INPUT_RIGHT_S) & GAINCTL_INPUT_RIGHT_M;
1214
1215 /* output level (inverted) */
1216 mask = (1 << GAINCTL_OUTPUT_BITS) - 1;
1217 val = mask - (sc->sc_output_lvl.left >> (8 - GAINCTL_OUTPUT_BITS));
1218 bits |= (val << GAINCTL_OUTPUT_LEFT_S) & GAINCTL_OUTPUT_LEFT_M;
1219 val = mask - (sc->sc_output_lvl.right >> (8 - GAINCTL_OUTPUT_BITS));
1220 bits |= (val << GAINCTL_OUTPUT_RIGHT_S) & GAINCTL_OUTPUT_RIGHT_M;
1221
1222 /* monitor level (inverted) */
1223 mask = (1 << GAINCTL_MONITOR_BITS) - 1;
1224 val = mask - (sc->sc_monitor_lvl.left >> (8 - GAINCTL_MONITOR_BITS));
1225 bits |= (val << GAINCTL_MONITOR_S) & GAINCTL_MONITOR_M;
1226
1227 /* XXX messing with these causes CNTL_C to get stuck... grr. */
1228 bits &= ~GAINCTL_IS_MASK;
1229 if (sc->sc_in_port == HARMONY_IN_MIC)
1230 bits |= GAINCTL_IS_LINE;
1231 else
1232 bits |= GAINCTL_IS_MICROPHONE;
1233
1234 /* XXX messing with these causes CNTL_C to get stuck... grr. */
1235 bits &= ~(GAINCTL_LE | GAINCTL_HE | GAINCTL_SE);
1236 if (sc->sc_out_port == HARMONY_OUT_LINE)
1237 bits |= GAINCTL_LE;
1238 else if (sc->sc_out_port == HARMONY_OUT_SPEAKER)
1239 bits |= GAINCTL_SE;
1240 else
1241 bits |= GAINCTL_HE;
1242
1243 mask = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK;
1244 old = bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL);
1245 bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL, bits);
1246 if ((old & mask) != (bits & mask))
1247 return 1;
1248 return 0;
1249 }
1250
1251 void
1252 harmony_try_more(struct harmony_softc *sc, int curadd, int bufmask,
1253 struct harmony_channel *c)
1254 {
1255 struct harmony_dma *d;
1256 uint32_t cur;
1257 int i, nsegs;
1258
1259 d = c->c_current;
1260 cur = bus_space_read_4(sc->sc_bt, sc->sc_bh, curadd);
1261 cur &= bufmask;
1262 nsegs = 0;
1263
1264 #ifdef DIAGNOSTIC
1265 if (cur < d->d_map->dm_segs[0].ds_addr ||
1266 cur >= (d->d_map->dm_segs[0].ds_addr + c->c_segsz))
1267 panic("%s: bad current %x < %lx || %x > %lx",
1268 device_xname(sc->sc_dv), cur,
1269 d->d_map->dm_segs[0].ds_addr, cur,
1270 d->d_map->dm_segs[0].ds_addr + c->c_segsz);
1271 #endif /* DIAGNOSTIC */
1272
1273 if (cur > c->c_theaddr) {
1274 nsegs = (cur - c->c_theaddr) / HARMONY_BUFSIZE;
1275 } else if (cur < c->c_theaddr) {
1276 nsegs = (d->d_map->dm_segs[0].ds_addr + c->c_segsz -
1277 c->c_theaddr) / HARMONY_BUFSIZE;
1278 nsegs += (cur - d->d_map->dm_segs[0].ds_addr) /
1279 HARMONY_BUFSIZE;
1280 }
1281
1282 if (nsegs != 0 && c->c_intr != NULL) {
1283 for (i = 0; i < nsegs; i++)
1284 (*c->c_intr)(c->c_intrarg);
1285 c->c_theaddr = cur;
1286 }
1287 }
1288