xref: /openbsd-src/sys/arch/hppa/gsc/harmony.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: harmony.c,v 1.33 2016/09/19 06:46:43 ratchov Exp $	*/
2 
3 /*
4  * Copyright (c) 2003 Jason L. Wright (jason@thought.net)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * Harmony (CS4215/AD1849 LASI) audio interface.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/kernel.h>
35 #include <sys/systm.h>
36 #include <sys/errno.h>
37 #include <sys/ioctl.h>
38 #include <sys/device.h>
39 #include <sys/proc.h>
40 #include <sys/malloc.h>
41 
42 #include <sys/audioio.h>
43 #include <dev/audio_if.h>
44 #include <dev/rndvar.h>
45 
46 #include <machine/cpu.h>
47 #include <machine/intr.h>
48 #include <machine/iomod.h>
49 #include <machine/autoconf.h>
50 #include <machine/bus.h>
51 
52 #include <hppa/dev/cpudevs.h>
53 #include <hppa/gsc/gscbusvar.h>
54 #include <hppa/gsc/harmonyreg.h>
55 #include <hppa/gsc/harmonyvar.h>
56 
57 int     harmony_open(void *, int);
58 void    harmony_close(void *);
59 int     harmony_set_params(void *, int, int, struct audio_params *,
60     struct audio_params *);
61 int     harmony_round_blocksize(void *, int);
62 int     harmony_commit_settings(void *);
63 int     harmony_halt_output(void *);
64 int     harmony_halt_input(void *);
65 int     harmony_set_port(void *, mixer_ctrl_t *);
66 int     harmony_get_port(void *, mixer_ctrl_t *);
67 int     harmony_query_devinfo(void *addr, mixer_devinfo_t *);
68 void *  harmony_allocm(void *, int, size_t, int, int);
69 void    harmony_freem(void *, void *, int);
70 size_t  harmony_round_buffersize(void *, int, size_t);
71 int     harmony_get_props(void *);
72 int     harmony_trigger_output(void *, void *, void *, int,
73     void (*intr)(void *), void *, struct audio_params *);
74 int     harmony_trigger_input(void *, void *, void *, int,
75     void (*intr)(void *), void *, struct audio_params *);
76 
77 struct audio_hw_if harmony_sa_hw_if = {
78 	harmony_open,
79 	harmony_close,
80 	harmony_set_params,
81 	harmony_round_blocksize,
82 	harmony_commit_settings,
83 	NULL,
84 	NULL,
85 	NULL,
86 	NULL,
87 	harmony_halt_output,
88 	harmony_halt_input,
89 	NULL,
90 	NULL,
91 	harmony_set_port,
92 	harmony_get_port,
93 	harmony_query_devinfo,
94 	harmony_allocm,
95 	harmony_freem,
96 	harmony_round_buffersize,
97 	harmony_get_props,
98 	harmony_trigger_output,
99 	harmony_trigger_input
100 };
101 
102 int harmony_match(struct device *, void *, void *);
103 void harmony_attach(struct device *, struct device *, void *);
104 int harmony_intr(void *);
105 void harmony_intr_enable(struct harmony_softc *);
106 void harmony_intr_disable(struct harmony_softc *);
107 u_int32_t harmony_speed_bits(struct harmony_softc *, u_long *);
108 int harmony_set_gainctl(struct harmony_softc *);
109 void harmony_reset_codec(struct harmony_softc *);
110 void harmony_start_cp(struct harmony_softc *);
111 void harmony_tick_pb(void *);
112 void harmony_tick_cp(void *);
113 void harmony_try_more(struct harmony_softc *);
114 
115 void harmony_acc_tmo(void *);
116 #define	ADD_CLKALLICA(sc) do {						\
117 	(sc)->sc_acc <<= 1;						\
118 	(sc)->sc_acc |= READ_REG((sc), HARMONY_DIAG) & DIAG_CO;		\
119 	if ((sc)->sc_acc_cnt++ && !((sc)->sc_acc_cnt % 32))		\
120 		add_true_randomness((sc)->sc_acc_num ^= (sc)->sc_acc);	\
121 } while(0)
122 
123 int
124 harmony_match(parent, match, aux)
125 	struct device *parent;
126 	void *match, *aux;
127 {
128 	struct gsc_attach_args *ga = aux;
129 	bus_space_handle_t bh;
130 	u_int32_t cntl;
131 
132 	if (ga->ga_type.iodc_type == HPPA_TYPE_FIO) {
133 		if (ga->ga_type.iodc_sv_model == HPPA_FIO_A1 ||
134 		    ga->ga_type.iodc_sv_model == HPPA_FIO_A2NB ||
135 		    ga->ga_type.iodc_sv_model == HPPA_FIO_A1NB ||
136 		    ga->ga_type.iodc_sv_model == HPPA_FIO_A2) {
137 			if (bus_space_map(ga->ga_iot, ga->ga_hpa,
138 			    HARMONY_NREGS, 0, &bh) != 0)
139 				return (0);
140 			cntl = bus_space_read_4(ga->ga_iot, bh, HARMONY_ID) &
141 			    ID_REV_MASK;
142 			bus_space_unmap(ga->ga_iot, bh, HARMONY_NREGS);
143 			if (cntl == ID_REV_TS || cntl == ID_REV_NOTS)
144 				return (1);
145 		}
146 	}
147 	return (0);
148 }
149 
150 void
151 harmony_attach(parent, self, aux)
152 	struct device *parent, *self;
153 	void *aux;
154 {
155 	struct harmony_softc *sc = (struct harmony_softc *)self;
156 	struct gsc_attach_args *ga = aux;
157 	u_int8_t rev;
158 	u_int32_t cntl;
159 	int i;
160 
161 	sc->sc_bt = ga->ga_iot;
162 	sc->sc_dmat = ga->ga_dmatag;
163 
164 	if (bus_space_map(sc->sc_bt, ga->ga_hpa, HARMONY_NREGS, 0,
165 	    &sc->sc_bh) != 0) {
166 		printf(": couldn't map registers\n");
167 		return;
168 	}
169 
170 	cntl = READ_REG(sc, HARMONY_ID);
171 	sc->sc_teleshare = (cntl & ID_REV_MASK) == ID_REV_TS;
172 
173 	if (bus_dmamem_alloc(sc->sc_dmat, sizeof(struct harmony_empty),
174 	    PAGE_SIZE, 0, &sc->sc_empty_seg, 1, &sc->sc_empty_rseg,
175 	    BUS_DMA_NOWAIT) != 0) {
176 		printf(": couldn't alloc DMA memory\n");
177 		bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
178 		return;
179 	}
180 	if (bus_dmamem_map(sc->sc_dmat, &sc->sc_empty_seg, 1,
181 	    sizeof(struct harmony_empty), (caddr_t *)&sc->sc_empty_kva,
182 	    BUS_DMA_NOWAIT) != 0) {
183 		printf(": couldn't map DMA memory\n");
184 		bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg,
185 		    sc->sc_empty_rseg);
186 		bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
187 		return;
188 	}
189 	if (bus_dmamap_create(sc->sc_dmat, sizeof(struct harmony_empty), 1,
190 	    sizeof(struct harmony_empty), 0, BUS_DMA_NOWAIT,
191 	    &sc->sc_empty_map) != 0) {
192 		printf(": can't create DMA map\n");
193 		bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_empty_kva,
194 		    sizeof(struct harmony_empty));
195 		bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg,
196 		    sc->sc_empty_rseg);
197 		bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
198 		return;
199 	}
200 	if (bus_dmamap_load(sc->sc_dmat, sc->sc_empty_map, sc->sc_empty_kva,
201 	    sizeof(struct harmony_empty), NULL, BUS_DMA_NOWAIT) != 0) {
202 		printf(": can't load DMA map\n");
203 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_empty_map);
204 		bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_empty_kva,
205 		    sizeof(struct harmony_empty));
206 		bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg,
207 		    sc->sc_empty_rseg);
208 		bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
209 		return;
210 	}
211 
212 	sc->sc_playback_empty = 0;
213 	for (i = 0; i < PLAYBACK_EMPTYS; i++)
214 		sc->sc_playback_paddrs[i] =
215 		    sc->sc_empty_map->dm_segs[0].ds_addr +
216 		    offsetof(struct harmony_empty, playback[i][0]);
217 
218 	sc->sc_capture_empty = 0;
219 	for (i = 0; i < CAPTURE_EMPTYS; i++)
220 		sc->sc_capture_paddrs[i] =
221 		    sc->sc_empty_map->dm_segs[0].ds_addr +
222 		    offsetof(struct harmony_empty, playback[i][0]);
223 
224 	bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
225 	    offsetof(struct harmony_empty, playback[0][0]),
226 	    PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE);
227 
228 	(void)gsc_intr_establish((struct gsc_softc *)parent, ga->ga_irq,
229 	    IPL_AUDIO, harmony_intr, sc, sc->sc_dv.dv_xname);
230 
231 	/* set defaults */
232 	sc->sc_in_port = HARMONY_IN_LINE;
233 	sc->sc_out_port = HARMONY_OUT_SPEAKER;
234 	sc->sc_input_lvl.left = sc->sc_input_lvl.right = 240;
235 	sc->sc_output_lvl.left = sc->sc_output_lvl.right = 244;
236 	sc->sc_monitor_lvl.left = sc->sc_monitor_lvl.right = 208;
237 	sc->sc_outputgain = 0;
238 
239 	/* reset chip, and push default gain controls */
240 	harmony_reset_codec(sc);
241 
242 	cntl = READ_REG(sc, HARMONY_CNTL);
243 	rev = (cntl & CNTL_CODEC_REV_MASK) >> CNTL_CODEC_REV_SHIFT;
244 	printf(": rev %u", rev);
245 
246 	if (sc->sc_teleshare)
247 		printf(", teleshare");
248 	printf("\n");
249 
250 	if ((rev & CS4215_REV_VER) >= CS4215_REV_VER_E)
251 		sc->sc_hasulinear8 = 1;
252 
253 	audio_attach_mi(&harmony_sa_hw_if, sc, &sc->sc_dv);
254 
255 	timeout_set(&sc->sc_acc_tmo, harmony_acc_tmo, sc);
256 	sc->sc_acc_num = 0xa5a5a5a5;
257 }
258 
259 void
260 harmony_reset_codec(struct harmony_softc *sc)
261 {
262 	/* silence */
263 	WRITE_REG(sc, HARMONY_GAINCTL, GAINCTL_OUTPUT_LEFT_M |
264 	    GAINCTL_OUTPUT_RIGHT_M | GAINCTL_MONITOR_M);
265 
266 	/* start reset */
267 	WRITE_REG(sc, HARMONY_RESET, RESET_RST);
268 
269 	DELAY(100000);		/* wait at least 0.05 sec */
270 
271 	harmony_set_gainctl(sc);
272 	WRITE_REG(sc, HARMONY_RESET, 0);
273 }
274 
275 void
276 harmony_acc_tmo(void *v)
277 {
278 	struct harmony_softc *sc = v;
279 
280 	ADD_CLKALLICA(sc);
281 	timeout_add(&sc->sc_acc_tmo, 1);
282 }
283 
284 /*
285  * interrupt handler
286  */
287 int
288 harmony_intr(vsc)
289 	void *vsc;
290 {
291 	struct harmony_softc *sc = vsc;
292 	struct harmony_channel *c;
293 	u_int32_t dstatus;
294 	int r = 0;
295 
296 	mtx_enter(&audio_lock);
297 	ADD_CLKALLICA(sc);
298 
299 	harmony_intr_disable(sc);
300 
301 	dstatus = READ_REG(sc, HARMONY_DSTATUS);
302 
303 	if (dstatus & DSTATUS_PN) {
304 		struct harmony_dma *d;
305 		bus_addr_t nextaddr;
306 		bus_size_t togo;
307 
308 		r = 1;
309 		c = &sc->sc_playback;
310 		d = c->c_current;
311 		togo = c->c_segsz - c->c_cnt;
312 		if (togo == 0) {
313 			nextaddr = d->d_map->dm_segs[0].ds_addr;
314 			c->c_cnt = togo = c->c_blksz;
315 		} else {
316 			nextaddr = c->c_lastaddr;
317 			if (togo > c->c_blksz)
318 				togo = c->c_blksz;
319 			c->c_cnt += togo;
320 		}
321 
322 		bus_dmamap_sync(sc->sc_dmat, d->d_map,
323 		    nextaddr - d->d_map->dm_segs[0].ds_addr,
324 		    c->c_blksz, BUS_DMASYNC_PREWRITE);
325 
326 		WRITE_REG(sc, HARMONY_PNXTADD, nextaddr);
327 		SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE);
328 		c->c_lastaddr = nextaddr + togo;
329 		harmony_try_more(sc);
330 	}
331 
332 	dstatus = READ_REG(sc, HARMONY_DSTATUS);
333 
334 	if (dstatus & DSTATUS_RN) {
335 		c = &sc->sc_capture;
336 		r = 1;
337 		harmony_start_cp(sc);
338 		if (sc->sc_capturing && c->c_intr != NULL)
339 			(*c->c_intr)(c->c_intrarg);
340 	}
341 
342 	if (READ_REG(sc, HARMONY_OV) & OV_OV) {
343 		sc->sc_ov = 1;
344 		WRITE_REG(sc, HARMONY_OV, 0);
345 	} else
346 		sc->sc_ov = 0;
347 
348 	harmony_intr_enable(sc);
349 	mtx_leave(&audio_lock);
350 	return (r);
351 }
352 
353 void
354 harmony_intr_enable(struct harmony_softc *sc)
355 {
356 	WRITE_REG(sc, HARMONY_DSTATUS, DSTATUS_IE);
357 	SYNC_REG(sc, HARMONY_DSTATUS, BUS_SPACE_BARRIER_WRITE);
358 }
359 
360 void
361 harmony_intr_disable(struct harmony_softc *sc)
362 {
363 	WRITE_REG(sc, HARMONY_DSTATUS, 0);
364 	SYNC_REG(sc, HARMONY_DSTATUS, BUS_SPACE_BARRIER_WRITE);
365 }
366 
367 int
368 harmony_open(void *vsc, int flags)
369 {
370 	struct harmony_softc *sc = vsc;
371 
372 	if (sc->sc_open)
373 		return (EBUSY);
374 	sc->sc_open = 1;
375 	return (0);
376 }
377 
378 void
379 harmony_close(void *vsc)
380 {
381 	struct harmony_softc *sc = vsc;
382 
383 	/* XXX: not useful, halt_*() already called */
384 	harmony_halt_input(sc);
385 	harmony_halt_output(sc);
386 	harmony_intr_disable(sc);
387 	sc->sc_open = 0;
388 }
389 
390 int
391 harmony_set_params(void *vsc, int setmode, int usemode,
392     struct audio_params *p, struct audio_params *r)
393 {
394 	struct harmony_softc *sc = vsc;
395 	u_int32_t bits;
396 
397 	switch (p->encoding) {
398 	case AUDIO_ENCODING_ULAW:
399 		bits = CNTL_FORMAT_ULAW;
400 		p->precision = 8;
401 		break;
402 	case AUDIO_ENCODING_ALAW:
403 		bits = CNTL_FORMAT_ALAW;
404 		p->precision = 8;
405 		break;
406 	case AUDIO_ENCODING_SLINEAR_BE:
407 		if (p->precision == 16) {
408 			bits = CNTL_FORMAT_SLINEAR16BE;
409 			break;
410 		}
411 		return (EINVAL);
412 	case AUDIO_ENCODING_ULINEAR_LE:
413 	case AUDIO_ENCODING_ULINEAR_BE:
414 		if (p->precision == 8) {
415 			bits = CNTL_FORMAT_ULINEAR8;
416 			break;
417 		}
418 		return (EINVAL);
419 	default:
420 		return (EINVAL);
421 	}
422 
423 	if (sc->sc_outputgain)
424 		bits |= CNTL_OLB;
425 
426 	if (p->channels == 1)
427 		bits |= CNTL_CHANS_MONO;
428 	else if (p->channels == 2)
429 		bits |= CNTL_CHANS_STEREO;
430 	else
431 		return (EINVAL);
432 
433 	r->sample_rate = p->sample_rate;
434 	r->encoding = p->encoding;
435 	r->precision = p->precision;
436 	p->bps = AUDIO_BPS(p->precision);
437 	r->bps = AUDIO_BPS(r->precision);
438 	p->msb = r->msb = 1;
439 
440 	bits |= harmony_speed_bits(sc, &p->sample_rate);
441 	sc->sc_cntlbits = bits;
442 	sc->sc_need_commit = 1;
443 
444 	return (0);
445 }
446 
447 int
448 harmony_round_blocksize(void *vsc, int blk)
449 {
450 	return (HARMONY_BUFSIZE);
451 }
452 
453 int
454 harmony_commit_settings(void *vsc)
455 {
456 	struct harmony_softc *sc = vsc;
457 	u_int32_t reg;
458 	u_int8_t quietchar;
459 	int i;
460 
461 	if (sc->sc_need_commit == 0)
462 		return (0);
463 
464 	harmony_intr_disable(sc);
465 
466 	for (;;) {
467 		reg = READ_REG(sc, HARMONY_DSTATUS);
468 		if ((reg & (DSTATUS_PC | DSTATUS_RC)) == 0)
469 			break;
470 	}
471 
472 	/* Setting some bits in gainctl requires a reset */
473 	harmony_reset_codec(sc);
474 
475 	/* set the silence character based on the encoding type */
476 	bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
477 	    offsetof(struct harmony_empty, playback[0][0]),
478 	    PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_POSTWRITE);
479 	switch (sc->sc_cntlbits & CNTL_FORMAT_MASK) {
480 	case CNTL_FORMAT_ULAW:
481 		quietchar = 0x7f;
482 		break;
483 	case CNTL_FORMAT_ALAW:
484 		quietchar = 0x55;
485 		break;
486 	case CNTL_FORMAT_SLINEAR16BE:
487 	case CNTL_FORMAT_ULINEAR8:
488 	default:
489 		quietchar = 0;
490 		break;
491 	}
492 	for (i = 0; i < PLAYBACK_EMPTYS; i++)
493 		memset(&sc->sc_empty_kva->playback[i][0],
494 		    quietchar, HARMONY_BUFSIZE);
495 	bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
496 	    offsetof(struct harmony_empty, playback[0][0]),
497 	    PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE);
498 
499 	for (;;) {
500 		/* Wait for it to come out of control mode */
501 		reg = READ_REG(sc, HARMONY_CNTL);
502 		if ((reg & CNTL_C) == 0)
503 			break;
504 	}
505 
506 	bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_CNTL,
507 	    sc->sc_cntlbits | CNTL_C);
508 
509 	for (;;) {
510 		/* Wait for it to come out of control mode */
511 		reg = READ_REG(sc, HARMONY_CNTL);
512 		if ((reg & CNTL_C) == 0)
513 			break;
514 	}
515 
516 	sc->sc_need_commit = 0;
517 
518 	if (sc->sc_playing || sc->sc_capturing)
519 		harmony_intr_enable(sc);
520 
521 	return (0);
522 }
523 
524 int
525 harmony_halt_output(void *vsc)
526 {
527 	struct harmony_softc *sc = vsc;
528 
529 	/* XXX: disable interrupts */
530 	sc->sc_playing = 0;
531 	return (0);
532 }
533 
534 int
535 harmony_halt_input(void *vsc)
536 {
537 	struct harmony_softc *sc = vsc;
538 
539 	/* XXX: disable interrupts */
540 	sc->sc_capturing = 0;
541 	return (0);
542 }
543 
544 int
545 harmony_set_port(void *vsc, mixer_ctrl_t *cp)
546 {
547 	struct harmony_softc *sc = vsc;
548 	int err = EINVAL;
549 
550 	switch (cp->dev) {
551 	case HARMONY_PORT_INPUT_LVL:
552 		if (cp->type != AUDIO_MIXER_VALUE)
553 			break;
554 		if (cp->un.value.num_channels == 1)
555 			sc->sc_input_lvl.left = sc->sc_input_lvl.right =
556 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
557 		else if (cp->un.value.num_channels == 2) {
558 			sc->sc_input_lvl.left =
559 			    cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
560 			sc->sc_input_lvl.right =
561 			    cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
562 		} else
563 			break;
564 		sc->sc_need_commit = 1;
565 		err = 0;
566 		break;
567 	case HARMONY_PORT_OUTPUT_LVL:
568 		if (cp->type != AUDIO_MIXER_VALUE)
569 			break;
570 		if (cp->un.value.num_channels == 1)
571 			sc->sc_output_lvl.left = sc->sc_output_lvl.right =
572 			    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
573 		else if (cp->un.value.num_channels == 2) {
574 			sc->sc_output_lvl.left =
575 			    cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
576 			sc->sc_output_lvl.right =
577 			    cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
578 		} else
579 			break;
580 		sc->sc_need_commit = 1;
581 		err = 0;
582 		break;
583 	case HARMONY_PORT_OUTPUT_GAIN:
584 		if (cp->type != AUDIO_MIXER_ENUM)
585 			break;
586 		sc->sc_outputgain = cp->un.ord ? 1 : 0;
587 		err = 0;
588 		break;
589 	case HARMONY_PORT_MONITOR_LVL:
590 		if (cp->type != AUDIO_MIXER_VALUE)
591 			break;
592 		if (cp->un.value.num_channels != 1)
593 			break;
594 		sc->sc_monitor_lvl.left = sc->sc_input_lvl.right =
595 		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
596 		sc->sc_need_commit = 1;
597 		err = 0;
598 		break;
599 	case HARMONY_PORT_RECORD_SOURCE:
600 		if (cp->type != AUDIO_MIXER_ENUM)
601 			break;
602 		if (cp->un.ord != HARMONY_IN_LINE &&
603 		    cp->un.ord != HARMONY_IN_MIC)
604 			break;
605 		sc->sc_in_port = cp->un.ord;
606 		err = 0;
607 		sc->sc_need_commit = 1;
608 		break;
609 	case HARMONY_PORT_OUTPUT_SOURCE:
610 		if (cp->type != AUDIO_MIXER_ENUM)
611 			break;
612 		if (cp->un.ord != HARMONY_OUT_LINE &&
613 		    cp->un.ord != HARMONY_OUT_SPEAKER &&
614 		    cp->un.ord != HARMONY_OUT_HEADPHONE)
615 			break;
616 		sc->sc_out_port = cp->un.ord;
617 		err = 0;
618 		sc->sc_need_commit = 1;
619 		break;
620 	}
621 
622 	return (err);
623 }
624 
625 int
626 harmony_get_port(void *vsc, mixer_ctrl_t *cp)
627 {
628 	struct harmony_softc *sc = vsc;
629 	int err = EINVAL;
630 
631 	switch (cp->dev) {
632 	case HARMONY_PORT_INPUT_LVL:
633 		if (cp->type != AUDIO_MIXER_VALUE)
634 			break;
635 		if (cp->un.value.num_channels == 1) {
636 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
637 			    sc->sc_input_lvl.left;
638 		} else if (cp->un.value.num_channels == 2) {
639 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
640 			    sc->sc_input_lvl.left;
641 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
642 			    sc->sc_input_lvl.right;
643 		} else
644 			break;
645 		err = 0;
646 		break;
647 	case HARMONY_PORT_INPUT_OV:
648 		if (cp->type != AUDIO_MIXER_ENUM)
649 			break;
650 		cp->un.ord = sc->sc_ov ? 1 : 0;
651 		err = 0;
652 		break;
653 	case HARMONY_PORT_OUTPUT_LVL:
654 		if (cp->type != AUDIO_MIXER_VALUE)
655 			break;
656 		if (cp->un.value.num_channels == 1) {
657 			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
658 			    sc->sc_output_lvl.left;
659 		} else if (cp->un.value.num_channels == 2) {
660 			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
661 			    sc->sc_output_lvl.left;
662 			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
663 			    sc->sc_output_lvl.right;
664 		} else
665 			break;
666 		err = 0;
667 		break;
668 	case HARMONY_PORT_OUTPUT_GAIN:
669 		if (cp->type != AUDIO_MIXER_ENUM)
670 			break;
671 		cp->un.ord = sc->sc_outputgain ? 1 : 0;
672 		err = 0;
673 		break;
674 	case HARMONY_PORT_MONITOR_LVL:
675 		if (cp->type != AUDIO_MIXER_VALUE)
676 			break;
677 		if (cp->un.value.num_channels != 1)
678 			break;
679 		cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
680 		    sc->sc_monitor_lvl.left;
681 		err = 0;
682 		break;
683 	case HARMONY_PORT_RECORD_SOURCE:
684 		if (cp->type != AUDIO_MIXER_ENUM)
685 			break;
686 		cp->un.ord = sc->sc_in_port;
687 		err = 0;
688 		break;
689 	case HARMONY_PORT_OUTPUT_SOURCE:
690 		if (cp->type != AUDIO_MIXER_ENUM)
691 			break;
692 		cp->un.ord = sc->sc_out_port;
693 		err = 0;
694 		break;
695 	}
696 	return (0);
697 }
698 
699 int
700 harmony_query_devinfo(void *vsc, mixer_devinfo_t *dip)
701 {
702 	int err = 0;
703 
704 	switch (dip->index) {
705 	case HARMONY_PORT_INPUT_LVL:
706 		dip->type = AUDIO_MIXER_VALUE;
707 		dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
708 		dip->prev = dip->next = AUDIO_MIXER_LAST;
709 		strlcpy(dip->label.name, AudioNinput, sizeof dip->label.name);
710 		dip->un.v.num_channels = 2;
711 		strlcpy(dip->un.v.units.name, AudioNvolume,
712 		    sizeof dip->un.v.units.name);
713 		break;
714 	case HARMONY_PORT_INPUT_OV:
715 		dip->type = AUDIO_MIXER_ENUM;
716 		dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
717 		dip->prev = dip->next = AUDIO_MIXER_LAST;
718 		strlcpy(dip->label.name, "overrange", sizeof dip->label.name);
719 		dip->un.e.num_mem = 2;
720 		strlcpy(dip->un.e.member[0].label.name, AudioNoff,
721 		    sizeof dip->un.e.member[0].label.name);
722 		dip->un.e.member[0].ord = 0;
723 		strlcpy(dip->un.e.member[1].label.name, AudioNon,
724 		    sizeof dip->un.e.member[1].label.name);
725 		dip->un.e.member[1].ord = 1;
726 		break;
727 	case HARMONY_PORT_OUTPUT_LVL:
728 		dip->type = AUDIO_MIXER_VALUE;
729 		dip->mixer_class = HARMONY_PORT_OUTPUT_CLASS;
730 		dip->prev = dip->next = AUDIO_MIXER_LAST;
731 		strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
732 		dip->un.v.num_channels = 2;
733 		strlcpy(dip->un.v.units.name, AudioNvolume,
734 		    sizeof dip->un.v.units.name);
735 		break;
736 	case HARMONY_PORT_OUTPUT_GAIN:
737 		dip->type = AUDIO_MIXER_ENUM;
738 		dip->mixer_class = HARMONY_PORT_OUTPUT_CLASS;
739 		dip->prev = dip->next = AUDIO_MIXER_LAST;
740 		strlcpy(dip->label.name, "gain", sizeof dip->label.name);
741 		dip->un.e.num_mem = 2;
742 		strlcpy(dip->un.e.member[0].label.name, AudioNoff,
743 		    sizeof dip->un.e.member[0].label.name);
744 		dip->un.e.member[0].ord = 0;
745 		strlcpy(dip->un.e.member[1].label.name, AudioNon,
746 		    sizeof dip->un.e.member[1].label.name);
747 		dip->un.e.member[1].ord = 1;
748 		break;
749 	case HARMONY_PORT_MONITOR_LVL:
750 		dip->type = AUDIO_MIXER_VALUE;
751 		dip->mixer_class = HARMONY_PORT_MONITOR_CLASS;
752 		dip->prev = dip->next = AUDIO_MIXER_LAST;
753 		strlcpy(dip->label.name, AudioNmonitor, sizeof dip->label.name);
754 		dip->un.v.num_channels = 1;
755 		strlcpy(dip->un.v.units.name, AudioNvolume,
756 		    sizeof dip->un.v.units.name);
757 		break;
758 	case HARMONY_PORT_RECORD_SOURCE:
759 		dip->type = AUDIO_MIXER_ENUM;
760 		dip->mixer_class = HARMONY_PORT_RECORD_CLASS;
761 		dip->prev = dip->next = AUDIO_MIXER_LAST;
762 		strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
763 		dip->un.e.num_mem = 2;
764 		strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone,
765 		    sizeof dip->un.e.member[0].label.name);
766 		dip->un.e.member[0].ord = HARMONY_IN_MIC;
767 		strlcpy(dip->un.e.member[1].label.name, AudioNline,
768 		    sizeof dip->un.e.member[1].label.name);
769 		dip->un.e.member[1].ord = HARMONY_IN_LINE;
770 		break;
771 	case HARMONY_PORT_OUTPUT_SOURCE:
772 		dip->type = AUDIO_MIXER_ENUM;
773 		dip->mixer_class = HARMONY_PORT_MONITOR_CLASS;
774 		dip->prev = dip->next = AUDIO_MIXER_LAST;
775 		strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
776 		dip->un.e.num_mem = 3;
777 		strlcpy(dip->un.e.member[0].label.name, AudioNline,
778 		    sizeof dip->un.e.member[0].label.name);
779 		dip->un.e.member[0].ord = HARMONY_OUT_LINE;
780 		strlcpy(dip->un.e.member[1].label.name, AudioNspeaker,
781 		    sizeof dip->un.e.member[1].label.name);
782 		dip->un.e.member[1].ord = HARMONY_OUT_SPEAKER;
783 		strlcpy(dip->un.e.member[2].label.name, AudioNheadphone,
784 		    sizeof dip->un.e.member[2].label.name);
785 		dip->un.e.member[2].ord = HARMONY_OUT_HEADPHONE;
786 		break;
787 	case HARMONY_PORT_INPUT_CLASS:
788 		dip->type = AUDIO_MIXER_CLASS;
789 		dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
790 		dip->prev = dip->next = AUDIO_MIXER_LAST;
791 		strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
792 		break;
793 	case HARMONY_PORT_OUTPUT_CLASS:
794 		dip->type = AUDIO_MIXER_CLASS;
795 		dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
796 		dip->prev = dip->next = AUDIO_MIXER_LAST;
797 		strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
798 		break;
799 	case HARMONY_PORT_MONITOR_CLASS:
800 		dip->type = AUDIO_MIXER_CLASS;
801 		dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
802 		dip->prev = dip->next = AUDIO_MIXER_LAST;
803 		strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name);
804 		break;
805 	case HARMONY_PORT_RECORD_CLASS:
806 		dip->type = AUDIO_MIXER_CLASS;
807 		dip->mixer_class = HARMONY_PORT_RECORD_CLASS;
808 		dip->prev = dip->next = AUDIO_MIXER_LAST;
809 		strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
810 		break;
811 	default:
812 		err = ENXIO;
813 		break;
814 	}
815 
816 	return (err);
817 }
818 
819 void *
820 harmony_allocm(void *vsc, int dir, size_t size, int pool, int flags)
821 {
822 	struct harmony_softc *sc = vsc;
823 	struct harmony_dma *d;
824 	int rseg;
825 
826 	d = (struct harmony_dma *)malloc(sizeof(struct harmony_dma), pool, flags);
827 	if (d == NULL)
828 		goto fail;
829 
830 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, BUS_DMA_NOWAIT,
831 	    &d->d_map) != 0)
832 		goto fail1;
833 
834 	if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &d->d_seg, 1,
835 	    &rseg, BUS_DMA_NOWAIT) != 0)
836 		goto fail2;
837 
838 	if (bus_dmamem_map(sc->sc_dmat, &d->d_seg, 1, size, &d->d_kva,
839 	    BUS_DMA_NOWAIT) != 0)
840 		goto fail3;
841 
842 	if (bus_dmamap_load(sc->sc_dmat, d->d_map, d->d_kva, size, NULL,
843 	    BUS_DMA_NOWAIT) != 0)
844 		goto fail4;
845 
846 	d->d_next = sc->sc_dmas;
847 	sc->sc_dmas = d;
848 	d->d_size = size;
849 	return (d->d_kva);
850 
851 fail4:
852 	bus_dmamem_unmap(sc->sc_dmat, d->d_kva, size);
853 fail3:
854 	bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1);
855 fail2:
856 	bus_dmamap_destroy(sc->sc_dmat, d->d_map);
857 fail1:
858 	free(d, pool, sizeof *d);
859 fail:
860 	return (NULL);
861 }
862 
863 void
864 harmony_freem(void *vsc, void *ptr, int pool)
865 {
866 	struct harmony_softc *sc = vsc;
867 	struct harmony_dma *d, **dd;
868 
869 	for (dd = &sc->sc_dmas; (d = *dd) != NULL; dd = &(*dd)->d_next) {
870 		if (d->d_kva != ptr)
871 			continue;
872 		bus_dmamap_unload(sc->sc_dmat, d->d_map);
873 		bus_dmamem_unmap(sc->sc_dmat, d->d_kva, d->d_size);
874 		bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1);
875 		bus_dmamap_destroy(sc->sc_dmat, d->d_map);
876 		free(d, pool, sizeof *d);
877 		return;
878 	}
879 	printf("%s: free rogue pointer\n", sc->sc_dv.dv_xname);
880 }
881 
882 size_t
883 harmony_round_buffersize(void *vsc, int direction, size_t size)
884 {
885 	return ((size + HARMONY_BUFSIZE - 1) & (size_t)(-HARMONY_BUFSIZE));
886 }
887 
888 int
889 harmony_get_props(void *vsc)
890 {
891 	return (AUDIO_PROP_FULLDUPLEX);
892 }
893 
894 int
895 harmony_trigger_output(void *vsc, void *start, void *end, int blksize,
896     void (*intr)(void *), void *intrarg, struct audio_params *param)
897 {
898 	struct harmony_softc *sc = vsc;
899 	struct harmony_channel *c = &sc->sc_playback;
900 	struct harmony_dma *d;
901 	bus_addr_t nextaddr;
902 	bus_size_t togo;
903 
904 	for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next)
905 		/*EMPTY*/;
906 	if (d == NULL) {
907 		printf("%s: trigger_output: bad addr: %p\n",
908 		    sc->sc_dv.dv_xname, start);
909 		return (EINVAL);
910 	}
911 
912 	c->c_intr = intr;
913 	c->c_intrarg = intrarg;
914 	c->c_blksz = blksize;
915 	c->c_current = d;
916 	c->c_segsz = (caddr_t)end - (caddr_t)start;
917 	c->c_cnt = 0;
918 	c->c_lastaddr = d->d_map->dm_segs[0].ds_addr;
919 
920 	sc->sc_playing = 1;
921 
922 	togo = c->c_segsz - c->c_cnt;
923 	if (togo == 0) {
924 		nextaddr = d->d_map->dm_segs[0].ds_addr;
925 		c->c_cnt = togo = c->c_blksz;
926 	} else {
927 		nextaddr = c->c_lastaddr;
928 		if (togo > c->c_blksz)
929 			togo = c->c_blksz;
930 		c->c_cnt += togo;
931 	}
932 
933 	bus_dmamap_sync(sc->sc_dmat, d->d_map,
934 	    nextaddr - d->d_map->dm_segs[0].ds_addr,
935 	    c->c_blksz, BUS_DMASYNC_PREWRITE);
936 
937 	mtx_enter(&audio_lock);
938 	WRITE_REG(sc, HARMONY_PNXTADD, nextaddr);
939 	c->c_theaddr = nextaddr;
940 	SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE);
941 	c->c_lastaddr = nextaddr + togo;
942 
943 	harmony_start_cp(sc);
944 	harmony_intr_enable(sc);
945 	mtx_leave(&audio_lock);
946 	return (0);
947 }
948 
949 void
950 harmony_start_cp(struct harmony_softc *sc)
951 {
952 	struct harmony_channel *c = &sc->sc_capture;
953 	struct harmony_dma *d;
954 	bus_addr_t nextaddr;
955 	bus_size_t togo;
956 
957 	if (sc->sc_capturing == 0) {
958 		WRITE_REG(sc, HARMONY_RNXTADD,
959 		    sc->sc_capture_paddrs[sc->sc_capture_empty]);
960 		if (++sc->sc_capture_empty == CAPTURE_EMPTYS)
961 			sc->sc_capture_empty = 0;
962 	} else {
963 		d = c->c_current;
964 		togo = c->c_segsz - c->c_cnt;
965 		if (togo == 0) {
966 			nextaddr = d->d_map->dm_segs[0].ds_addr;
967 			c->c_cnt = togo = c->c_blksz;
968 		} else {
969 			nextaddr = c->c_lastaddr;
970 			if (togo > c->c_blksz)
971 				togo = c->c_blksz;
972 			c->c_cnt += togo;
973 		}
974 
975 		bus_dmamap_sync(sc->sc_dmat, d->d_map,
976 		    nextaddr - d->d_map->dm_segs[0].ds_addr,
977 		    c->c_blksz, BUS_DMASYNC_PREWRITE);
978 
979 		WRITE_REG(sc, HARMONY_RNXTADD, nextaddr);
980 		SYNC_REG(sc, HARMONY_RNXTADD, BUS_SPACE_BARRIER_WRITE);
981 		c->c_lastaddr = nextaddr + togo;
982 	}
983 
984 	timeout_add(&sc->sc_acc_tmo, 1);
985 }
986 
987 int
988 harmony_trigger_input(void *vsc, void *start, void *end, int blksize,
989     void (*intr)(void *), void *intrarg, struct audio_params *param)
990 {
991 	struct harmony_softc *sc = vsc;
992 	struct harmony_channel *c = &sc->sc_capture;
993 	struct harmony_dma *d;
994 
995 	for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next)
996 		/*EMPTY*/;
997 	if (d == NULL) {
998 		printf("%s: trigger_input: bad addr: %p\n",
999 		    sc->sc_dv.dv_xname, start);
1000 		return (EINVAL);
1001 	}
1002 
1003 	c->c_intr = intr;
1004 	c->c_intrarg = intrarg;
1005 	c->c_blksz = blksize;
1006 	c->c_current = d;
1007 	c->c_segsz = (caddr_t)end - (caddr_t)start;
1008 	c->c_cnt = 0;
1009 	c->c_lastaddr = d->d_map->dm_segs[0].ds_addr;
1010 	mtx_enter(&audio_lock);
1011 	sc->sc_capturing = 1;
1012 	harmony_start_cp(sc);
1013 	harmony_intr_enable(sc);
1014 	mtx_leave(&audio_lock);
1015 	return (0);
1016 }
1017 
1018 static const struct speed_struct {
1019 	u_int32_t speed;
1020 	u_int32_t bits;
1021 } harmony_speeds[] = {
1022 	{ 5125, CNTL_RATE_5125 },
1023 	{ 6615, CNTL_RATE_6615 },
1024 	{ 8000, CNTL_RATE_8000 },
1025 	{ 9600, CNTL_RATE_9600 },
1026 	{ 11025, CNTL_RATE_11025 },
1027 	{ 16000, CNTL_RATE_16000 },
1028 	{ 18900, CNTL_RATE_18900 },
1029 	{ 22050, CNTL_RATE_22050 },
1030 	{ 27428, CNTL_RATE_27428 },
1031 	{ 32000, CNTL_RATE_32000 },
1032 	{ 33075, CNTL_RATE_33075 },
1033 	{ 37800, CNTL_RATE_37800 },
1034 	{ 44100, CNTL_RATE_44100 },
1035 	{ 48000, CNTL_RATE_48000 },
1036 };
1037 
1038 u_int32_t
1039 harmony_speed_bits(struct harmony_softc *sc, u_long *speedp)
1040 {
1041 	int i, n, selected = -1;
1042 
1043 	n = sizeof(harmony_speeds) / sizeof(harmony_speeds[0]);
1044 
1045 	if ((*speedp) <= harmony_speeds[0].speed)
1046 		selected = 0;
1047 	else if ((*speedp) >= harmony_speeds[n - 1].speed)
1048 		selected = n - 1;
1049 	else {
1050 		for (i = 1; selected == -1 && i < n; i++) {
1051 			if ((*speedp) == harmony_speeds[i].speed)
1052 				selected = i;
1053 			else if ((*speedp) < harmony_speeds[i].speed) {
1054 				int diff1, diff2;
1055 
1056 				diff1 = (*speedp) - harmony_speeds[i - 1].speed;
1057 				diff2 = harmony_speeds[i].speed - (*speedp);
1058 				if (diff1 < diff2)
1059 					selected = i - 1;
1060 				else
1061 					selected = i;
1062 			}
1063 		}
1064 	}
1065 
1066 	if (selected == -1)
1067 		selected = 2;
1068 
1069 	*speedp = harmony_speeds[selected].speed;
1070 	return (harmony_speeds[selected].bits);
1071 }
1072 
1073 int
1074 harmony_set_gainctl(struct harmony_softc *sc)
1075 {
1076 	u_int32_t bits, mask, val, old;
1077 
1078 	/* XXX leave these bits alone or the chip will not come out of CNTL */
1079 	bits = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK;
1080 
1081 	/* input level */
1082 	bits |= ((sc->sc_input_lvl.left >> (8 - GAINCTL_INPUT_BITS)) <<
1083 	    GAINCTL_INPUT_LEFT_S) & GAINCTL_INPUT_LEFT_M;
1084 	bits |= ((sc->sc_input_lvl.right >> (8 - GAINCTL_INPUT_BITS)) <<
1085 	    GAINCTL_INPUT_RIGHT_S) & GAINCTL_INPUT_RIGHT_M;
1086 
1087 	/* output level (inverted) */
1088 	mask = (1 << GAINCTL_OUTPUT_BITS) - 1;
1089 	val = mask - (sc->sc_output_lvl.left >> (8 - GAINCTL_OUTPUT_BITS));
1090 	bits |= (val << GAINCTL_OUTPUT_LEFT_S) & GAINCTL_OUTPUT_LEFT_M;
1091 	val = mask - (sc->sc_output_lvl.right >> (8 - GAINCTL_OUTPUT_BITS));
1092 	bits |= (val << GAINCTL_OUTPUT_RIGHT_S) & GAINCTL_OUTPUT_RIGHT_M;
1093 
1094 	/* monitor level (inverted) */
1095 	mask = (1 << GAINCTL_MONITOR_BITS) - 1;
1096 	val = mask - (sc->sc_monitor_lvl.left >> (8 - GAINCTL_MONITOR_BITS));
1097 	bits |= (val << GAINCTL_MONITOR_S) & GAINCTL_MONITOR_M;
1098 
1099 	/* XXX messing with these causes CNTL_C to get stuck... grr. */
1100 	bits &= ~GAINCTL_IS_MASK;
1101 	if (sc->sc_in_port == HARMONY_IN_MIC)
1102 		bits |= GAINCTL_IS_LINE;
1103 	else
1104 		bits |= GAINCTL_IS_MICROPHONE;
1105 
1106 	/* XXX messing with these causes CNTL_C to get stuck... grr. */
1107 	bits &= ~(GAINCTL_LE | GAINCTL_HE | GAINCTL_SE);
1108 	if (sc->sc_out_port == HARMONY_OUT_LINE)
1109 		bits |= GAINCTL_LE;
1110 	else if (sc->sc_out_port == HARMONY_OUT_SPEAKER)
1111 		bits |= GAINCTL_SE;
1112 	else
1113 		bits |= GAINCTL_HE;
1114 
1115 	mask = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK;
1116 	old = bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL);
1117 	bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL, bits);
1118 	if ((old & mask) != (bits & mask))
1119 		return (1);
1120 	return (0);
1121 }
1122 
1123 void
1124 harmony_try_more(struct harmony_softc *sc)
1125 {
1126 	struct harmony_channel *c = &sc->sc_playback;
1127 	struct harmony_dma *d = c->c_current;
1128 	u_int32_t cur;
1129 	int i, nsegs;
1130 
1131 	cur = bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_PCURADD);
1132 	cur &= PCURADD_BUFMASK;
1133 	nsegs = 0;
1134 
1135 #ifdef DIAGNOSTIC
1136 	if (cur < d->d_map->dm_segs[0].ds_addr ||
1137 	    cur >= (d->d_map->dm_segs[0].ds_addr + c->c_segsz))
1138 		panic("%s: bad current %x < %lx || %x > %lx",
1139 		    sc->sc_dv.dv_xname, cur, d->d_map->dm_segs[0].ds_addr, cur,
1140 		    d->d_map->dm_segs[0].ds_addr + c->c_segsz);
1141 #endif /* DIAGNOSTIC */
1142 
1143 	if (cur > c->c_theaddr) {
1144 		nsegs = (cur - c->c_theaddr) / HARMONY_BUFSIZE;
1145 	} else if (cur < c->c_theaddr) {
1146 		nsegs = (d->d_map->dm_segs[0].ds_addr + c->c_segsz -
1147 		    c->c_theaddr) / HARMONY_BUFSIZE;
1148 		nsegs += (cur - d->d_map->dm_segs[0].ds_addr) /
1149 		    HARMONY_BUFSIZE;
1150 	}
1151 
1152 	if (nsegs != 0 && c->c_intr != NULL) {
1153 		for (i = 0; i < nsegs; i++)
1154 			(*c->c_intr)(c->c_intrarg);
1155 		c->c_theaddr = cur;
1156 	}
1157 }
1158 
1159 struct cfdriver harmony_cd = {
1160 	NULL, "harmony", DV_DULL
1161 };
1162 
1163 struct cfattach harmony_ca = {
1164 	sizeof(struct harmony_softc), harmony_match, harmony_attach
1165 };
1166