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