xref: /netbsd-src/sys/arch/hppa/gsc/harmony.c (revision fbc88947f9dd4e88fcf0fe3d57e0423d6245eac8)
1 /*	$NetBSD: harmony.c,v 1.11 2022/05/15 00:25:15 gutteridge 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@thought.net)
36  * All rights reserved.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
48  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
49  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
50  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
51  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
52  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
53  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
55  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
56  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
57  * POSSIBILITY OF SUCH DAMAGE.
58  */
59 
60 /*
61  * Harmony (CS4215/AD1849 LASI) audio interface.
62  */
63 
64 
65 
66 #include <sys/param.h>
67 #include <sys/kernel.h>
68 #include <sys/systm.h>
69 #include <sys/errno.h>
70 #include <sys/ioctl.h>
71 #include <sys/device.h>
72 #include <sys/proc.h>
73 #include <sys/kmem.h>
74 #include <uvm/uvm_extern.h>
75 
76 #include <sys/rndsource.h>
77 
78 #include <sys/audioio.h>
79 #include <dev/audio/audio_if.h>
80 
81 #include <machine/cpu.h>
82 #include <machine/intr.h>
83 #include <machine/iomod.h>
84 #include <machine/autoconf.h>
85 #include <sys/bus.h>
86 
87 #include <hppa/dev/cpudevs.h>
88 #include <hppa/gsc/gscbusvar.h>
89 #include <hppa/gsc/harmonyreg.h>
90 #include <hppa/gsc/harmonyvar.h>
91 
92 void	harmony_close(void *);
93 int	harmony_query_format(void *, audio_format_query_t *);
94 int	harmony_set_format(void *, int,
95     const audio_params_t *, const audio_params_t *,
96     audio_filter_reg_t *, audio_filter_reg_t *);
97 int	harmony_round_blocksize(void *, int, int, const audio_params_t *);
98 
99 int	harmony_control_wait(struct harmony_softc *);
100 int	harmony_commit_settings(void *);
101 
102 int	harmony_halt_output(void *);
103 int	harmony_halt_input(void *);
104 int	harmony_getdev(void *, struct audio_device *);
105 int	harmony_set_port(void *, mixer_ctrl_t *);
106 int	harmony_get_port(void *, mixer_ctrl_t *);
107 int	harmony_query_devinfo(void *, mixer_devinfo_t *);
108 void *	harmony_allocm(void *, int, size_t);
109 void	harmony_freem(void *, void *, size_t);
110 size_t	harmony_round_buffersize(void *, int, size_t);
111 int	harmony_get_props(void *);
112 int	harmony_trigger_output(void *, void *, void *, int,
113     void (*)(void *), void *, const audio_params_t *);
114 int	harmony_trigger_input(void *, void *, void *, int,
115     void (*)(void *), void *, const audio_params_t *);
116 void	harmony_get_locks(void *, kmutex_t **, kmutex_t **);
117 
118 const struct audio_hw_if harmony_sa_hw_if = {
119 	.close			= harmony_close,
120 	.query_format		= harmony_query_format,
121 	.set_format		= harmony_set_format,
122 	.round_blocksize	= harmony_round_blocksize,
123 	.commit_settings	= harmony_commit_settings,
124 	.halt_output		= harmony_halt_output,
125 	.halt_input		= harmony_halt_input,
126 	.getdev			= harmony_getdev,
127 	.set_port		= harmony_set_port,
128 	.get_port		= harmony_get_port,
129 	.query_devinfo		= harmony_query_devinfo,
130 	.allocm			= harmony_allocm,
131 	.freem			= harmony_freem,
132 	.round_buffersize	= harmony_round_buffersize,
133 	.get_props		= harmony_get_props,
134 	.trigger_output		= harmony_trigger_output,
135 	.trigger_input		= harmony_trigger_input,
136 	.get_locks		= harmony_get_locks,
137 };
138 
139 /*
140  * The HW actually supports more frequencies, but these are the standard ones.
141  * For the full list, see the definition of harmony_speeds below.
142  */
143 #define HARMONY_FORMAT(enc, prec) \
144 	{ \
145 		.mode		= AUMODE_PLAY | AUMODE_RECORD, \
146 		.encoding	= (enc), \
147 		.validbits	= (prec), \
148 		.precision	= (prec), \
149 		.channels	= 2, \
150 		.channel_mask	= AUFMT_STEREO, \
151 		.frequency_type = 4, \
152 		.frequency	= { 16000, 32000, 44100, 48000 }, \
153 	}
154 static struct audio_format harmony_formats[] = {
155 	HARMONY_FORMAT(AUDIO_ENCODING_ULAW,        8),
156 	HARMONY_FORMAT(AUDIO_ENCODING_ALAW,        8),
157 	HARMONY_FORMAT(AUDIO_ENCODING_SLINEAR_BE, 16),
158 };
159 #define HARMONY_NFORMATS __arraycount(harmony_formats)
160 
161 int harmony_match(device_t, struct cfdata *, void *);
162 void harmony_attach(device_t, device_t, void *);
163 
164 
165 CFATTACH_DECL_NEW(harmony, sizeof(struct harmony_softc),
166     harmony_match, harmony_attach, NULL, NULL);
167 
168 int harmony_intr(void *);
169 void harmony_intr_enable(struct harmony_softc *);
170 void harmony_intr_disable(struct harmony_softc *);
171 uint32_t harmony_speed_bits(struct harmony_softc *, u_int);
172 int harmony_set_gainctl(struct harmony_softc *);
173 void harmony_reset_codec(struct harmony_softc *);
174 void harmony_start_cp(struct harmony_softc *, int);
175 void harmony_start_pp(struct harmony_softc *, int);
176 void harmony_tick_pb(void *);
177 void harmony_tick_cp(void *);
178 void harmony_try_more(struct harmony_softc *, int, int,
179 	struct harmony_channel *);
180 static void harmony_empty_input(struct harmony_softc *);
181 static void harmony_empty_output(struct harmony_softc *);
182 
183 void harmony_acc_tmo(void *);
184 #define	ADD_CLKALLICA(sc) do {						\
185 	(sc)->sc_acc <<= 1;						\
186 	(sc)->sc_acc |= READ_REG((sc), HARMONY_DIAG) & DIAG_CO;		\
187 	if ((sc)->sc_acc_cnt++ && !((sc)->sc_acc_cnt % 32))		\
188 		rnd_add_uint32(&(sc)->sc_rnd_source,			\
189 			       (sc)->sc_acc_num ^= (sc)->sc_acc);	\
190 } while(0)
191 
192 int
harmony_match(device_t parent,struct cfdata * match,void * aux)193 harmony_match(device_t parent, struct cfdata *match, void *aux)
194 {
195 	struct gsc_attach_args *ga;
196 
197 	ga = aux;
198 	if (ga->ga_type.iodc_type == HPPA_TYPE_FIO) {
199 		if (ga->ga_type.iodc_sv_model == HPPA_FIO_A1 ||
200 		    ga->ga_type.iodc_sv_model == HPPA_FIO_A2NB ||
201 		    ga->ga_type.iodc_sv_model == HPPA_FIO_A1NB ||
202 		    ga->ga_type.iodc_sv_model == HPPA_FIO_A2)
203 			return 1;
204 	}
205 	return 0;
206 }
207 
208 void
harmony_attach(device_t parent,device_t self,void * aux)209 harmony_attach(device_t parent, device_t self, void *aux)
210 {
211 	struct harmony_softc *sc = device_private(self);
212 	struct gsc_attach_args *ga;
213 	uint8_t rev;
214 	uint32_t cntl;
215 	int i;
216 
217 	sc->sc_dv = self;
218 	ga = aux;
219 	sc->sc_bt = ga->ga_iot;
220 	sc->sc_dmat = ga->ga_dmatag;
221 
222 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
223 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO);
224 
225 	if (bus_space_map(sc->sc_bt, ga->ga_hpa, HARMONY_NREGS, 0,
226 	    &sc->sc_bh) != 0) {
227 		aprint_error(": couldn't map registers\n");
228 		return;
229 	}
230 
231 	cntl = READ_REG(sc, HARMONY_ID);
232 	switch ((cntl & ID_REV_MASK)) {
233 	case ID_REV_TS:
234 		sc->sc_teleshare = 1;
235 	case ID_REV_NOTS:
236 		break;
237 	default:
238 		aprint_error(": unknown id == 0x%02x\n",
239 		    (cntl & ID_REV_MASK) >> ID_REV_SHIFT);
240 		bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
241 		return;
242 	}
243 
244 	if (bus_dmamem_alloc(sc->sc_dmat, sizeof(struct harmony_empty),
245 	    PAGE_SIZE, 0, &sc->sc_empty_seg, 1, &sc->sc_empty_rseg,
246 	    BUS_DMA_WAITOK) != 0) {
247 		aprint_error(": could not alloc DMA memory\n");
248 		bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
249 		return;
250 	}
251 	if (bus_dmamem_map(sc->sc_dmat, &sc->sc_empty_seg, 1,
252 	    sizeof(struct harmony_empty), (void **)&sc->sc_empty_kva,
253 	    BUS_DMA_WAITOK) != 0) {
254 		aprint_error(": couldn't map DMA memory\n");
255 		bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg,
256 		    sc->sc_empty_rseg);
257 		bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
258 		return;
259 	}
260 	if (bus_dmamap_create(sc->sc_dmat, sizeof(struct harmony_empty), 1,
261 	    sizeof(struct harmony_empty), 0, BUS_DMA_WAITOK,
262 	    &sc->sc_empty_map) != 0) {
263 		aprint_error(": can't create DMA map\n");
264 		bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_empty_kva,
265 		    sizeof(struct harmony_empty));
266 		bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg,
267 		    sc->sc_empty_rseg);
268 		bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
269 		return;
270 	}
271 	if (bus_dmamap_load(sc->sc_dmat, sc->sc_empty_map, sc->sc_empty_kva,
272 	    sizeof(struct harmony_empty), NULL, BUS_DMA_WAITOK) != 0) {
273 		aprint_error(": can't load DMA map\n");
274 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_empty_map);
275 		bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_empty_kva,
276 		    sizeof(struct harmony_empty));
277 		bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg,
278 		    sc->sc_empty_rseg);
279 		bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
280 		return;
281 	}
282 
283 	sc->sc_playback_empty = 0;
284 	for (i = 0; i < PLAYBACK_EMPTYS; i++)
285 		sc->sc_playback_paddrs[i] =
286 		    sc->sc_empty_map->dm_segs[0].ds_addr +
287 		    offsetof(struct harmony_empty, playback[i][0]);
288 
289 	sc->sc_capture_empty = 0;
290 	for (i = 0; i < CAPTURE_EMPTYS; i++)
291 		sc->sc_capture_paddrs[i] =
292 		    sc->sc_empty_map->dm_segs[0].ds_addr +
293 		    offsetof(struct harmony_empty, capture[i][0]);
294 
295 	bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
296 	    offsetof(struct harmony_empty, playback[0][0]),
297 	    PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE);
298 
299 	(void) hppa_intr_establish(IPL_AUDIO, harmony_intr, sc, ga->ga_ir,
300 	     ga->ga_irq);
301 
302 	/* set defaults */
303 	sc->sc_in_port = HARMONY_IN_LINE;
304 	sc->sc_out_port = HARMONY_OUT_SPEAKER;
305 	sc->sc_input_lvl.left = sc->sc_input_lvl.right = 240;
306 	sc->sc_output_lvl.left = sc->sc_output_lvl.right = 244;
307 	sc->sc_monitor_lvl.left = sc->sc_monitor_lvl.right = 208;
308 	sc->sc_outputgain = 0;
309 
310 	/* reset chip, and push default gain controls */
311 	harmony_reset_codec(sc);
312 
313 	cntl = READ_REG(sc, HARMONY_CNTL);
314 	rev = (cntl & CNTL_CODEC_REV_MASK) >> CNTL_CODEC_REV_SHIFT;
315 	aprint_normal(": rev %u", rev);
316 
317 	if (sc->sc_teleshare)
318 		printf(", teleshare");
319 	aprint_normal("\n");
320 
321 	strlcpy(sc->sc_audev.name, ga->ga_name, sizeof(sc->sc_audev.name));
322 	snprintf(sc->sc_audev.version, sizeof sc->sc_audev.version,
323 	    "%u.%u;%u", ga->ga_type.iodc_sv_rev,
324 	    ga->ga_type.iodc_model, ga->ga_type.iodc_revision);
325 	strlcpy(sc->sc_audev.config, device_xname(sc->sc_dv),
326 	    sizeof(sc->sc_audev.config));
327 
328 	audio_attach_mi(&harmony_sa_hw_if, sc, sc->sc_dv);
329 
330 	rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dv),
331 	    RND_TYPE_UNKNOWN, RND_FLAG_DEFAULT);
332 
333 	callout_init(&sc->sc_acc_tmo, 0);
334 	callout_setfunc(&sc->sc_acc_tmo, harmony_acc_tmo, sc);
335 	sc->sc_acc_num = 0xa5a5a5a5;
336 }
337 
338 void
harmony_reset_codec(struct harmony_softc * sc)339 harmony_reset_codec(struct harmony_softc *sc)
340 {
341 
342 	/* silence */
343 	WRITE_REG(sc, HARMONY_GAINCTL, GAINCTL_OUTPUT_LEFT_M |
344 	    GAINCTL_OUTPUT_RIGHT_M | GAINCTL_MONITOR_M);
345 
346 	/* start reset */
347 	WRITE_REG(sc, HARMONY_RESET, RESET_RST);
348 
349 	DELAY(100000);		/* wait at least 0.1 sec */
350 
351 	harmony_set_gainctl(sc);
352 	WRITE_REG(sc, HARMONY_RESET, 0);
353 }
354 
355 void
harmony_acc_tmo(void * v)356 harmony_acc_tmo(void *v)
357 {
358 	struct harmony_softc *sc;
359 
360 	sc = v;
361 	ADD_CLKALLICA(sc);
362 	callout_schedule(&sc->sc_acc_tmo, 1);
363 }
364 
365 /*
366  * interrupt handler
367  */
368 int
harmony_intr(void * vsc)369 harmony_intr(void *vsc)
370 {
371 	struct harmony_softc *sc;
372 	uint32_t dstatus;
373 	int r;
374 
375 	sc = vsc;
376 	r = 0;
377 	ADD_CLKALLICA(sc);
378 
379 	mutex_spin_enter(&sc->sc_intr_lock);
380 
381 	harmony_intr_disable(sc);
382 
383 	dstatus = READ_REG(sc, HARMONY_DSTATUS);
384 
385 	if (dstatus & DSTATUS_PN) {
386 		r = 1;
387 		harmony_start_pp(sc, 0);
388 	}
389 
390 	if (dstatus & DSTATUS_RN) {
391 		r = 1;
392 		harmony_start_cp(sc, 0);
393 	}
394 
395 	if (READ_REG(sc, HARMONY_OV) & OV_OV) {
396 		sc->sc_ov = 1;
397 		WRITE_REG(sc, HARMONY_OV, 0);
398 	} else
399 		sc->sc_ov = 0;
400 
401 	harmony_intr_enable(sc);
402 
403 	mutex_spin_exit(&sc->sc_intr_lock);
404 
405 	return r;
406 }
407 
408 void
harmony_intr_enable(struct harmony_softc * sc)409 harmony_intr_enable(struct harmony_softc *sc)
410 {
411 
412 	WRITE_REG(sc, HARMONY_DSTATUS, DSTATUS_IE);
413 	SYNC_REG(sc, HARMONY_DSTATUS, BUS_SPACE_BARRIER_WRITE);
414 }
415 
416 void
harmony_intr_disable(struct harmony_softc * sc)417 harmony_intr_disable(struct harmony_softc *sc)
418 {
419 
420 	WRITE_REG(sc, HARMONY_DSTATUS, 0);
421 	SYNC_REG(sc, HARMONY_DSTATUS, BUS_SPACE_BARRIER_WRITE);
422 }
423 
424 void
harmony_close(void * vsc)425 harmony_close(void *vsc)
426 {
427 	struct harmony_softc *sc;
428 
429 	sc = vsc;
430 	harmony_intr_disable(sc);
431 }
432 
433 int
harmony_query_format(void * vsc,audio_format_query_t * afp)434 harmony_query_format(void *vsc, audio_format_query_t *afp)
435 {
436 
437 	return audio_query_format(harmony_formats, HARMONY_NFORMATS, afp);
438 }
439 
440 int
harmony_set_format(void * vsc,int setmode,const audio_params_t * play,const audio_params_t * rec,audio_filter_reg_t * pfil,audio_filter_reg_t * rfil)441 harmony_set_format(void *vsc, int setmode,
442     const audio_params_t *play, const audio_params_t *rec,
443     audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
444 {
445 	struct harmony_softc *sc;
446 	uint32_t bits;
447 
448 	sc = vsc;
449 
450 	/* *play and *rec are the identical because !AUDIO_PROP_INDEPENDENT. */
451 	switch (play->encoding) {
452 	case AUDIO_ENCODING_ULAW:
453 		bits = CNTL_FORMAT_ULAW;
454 		break;
455 	case AUDIO_ENCODING_ALAW:
456 		bits = CNTL_FORMAT_ALAW;
457 		break;
458 	case AUDIO_ENCODING_SLINEAR_BE:
459 		bits = CNTL_FORMAT_SLINEAR16BE;
460 		break;
461 	default:
462 		return EINVAL;
463 	}
464 
465 	if (sc->sc_outputgain)
466 		bits |= CNTL_OLB;
467 
468 	bits |= CNTL_CHANS_STEREO;
469 	bits |= harmony_speed_bits(sc, play->sample_rate);
470 	sc->sc_cntlbits = bits;
471 	sc->sc_need_commit = 1;
472 
473 	return 0;
474 }
475 
476 int
harmony_round_blocksize(void * vsc,int blk,int mode,const audio_params_t * param)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
harmony_control_wait(struct harmony_softc * sc)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
harmony_commit_settings(void * vsc)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
harmony_empty_output(struct harmony_softc * sc)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
harmony_halt_output(void * vsc)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
harmony_empty_input(struct harmony_softc * sc)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
harmony_halt_input(void * vsc)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
harmony_getdev(void * vsc,struct audio_device * retp)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
harmony_set_port(void * vsc,mixer_ctrl_t * cp)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
harmony_get_port(void * vsc,mixer_ctrl_t * cp)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
harmony_query_devinfo(void * vsc,mixer_devinfo_t * dip)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 *
harmony_allocm(void * vsc,int dir,size_t size)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
harmony_freem(void * vsc,void * ptr,size_t size)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
harmony_round_buffersize(void * vsc,int direction,size_t size)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
harmony_get_props(void * vsc)972 harmony_get_props(void *vsc)
973 {
974 
975 	return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE |
976 	    AUDIO_PROP_FULLDUPLEX;
977 }
978 
979 void
harmony_get_locks(void * vsc,kmutex_t ** intr,kmutex_t ** thread)980 harmony_get_locks(void *vsc, kmutex_t **intr, kmutex_t **thread)
981 {
982 	struct harmony_softc *sc;
983 
984 	sc = vsc;
985 	*intr = &sc->sc_intr_lock;
986 	*thread = &sc->sc_lock;
987 }
988 
989 int
harmony_trigger_output(void * vsc,void * start,void * end,int blksize,void (* intr)(void *),void * intrarg,const audio_params_t * param)990 harmony_trigger_output(void *vsc, void *start, void *end, int blksize,
991     void (*intr)(void *), void *intrarg, const audio_params_t *param)
992 {
993 	struct harmony_softc *sc;
994 	struct harmony_channel *c;
995 	struct harmony_dma *d;
996 
997 	sc = vsc;
998 	c = &sc->sc_playback;
999 	for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next)
1000 		continue;
1001 	if (d == NULL) {
1002 		printf("%s: trigger_output: bad addr: %p\n",
1003 		    device_xname(sc->sc_dv), start);
1004 		return EINVAL;
1005 	}
1006 
1007 	c->c_intr = intr;
1008 	c->c_intrarg = intrarg;
1009 	c->c_blksz = blksize;
1010 	c->c_current = d;
1011 	c->c_segsz = (char *)end - (char *)start;
1012 	c->c_cnt = 0;
1013 	c->c_lastaddr = d->d_map->dm_segs[0].ds_addr;
1014 
1015 	sc->sc_playing = 1;
1016 
1017 	harmony_start_pp(sc, 1);
1018 	harmony_start_cp(sc, 0);
1019 	harmony_intr_enable(sc);
1020 
1021 	return 0;
1022 }
1023 
1024 void
harmony_start_cp(struct harmony_softc * sc,int start)1025 harmony_start_cp(struct harmony_softc *sc, int start)
1026 {
1027 	struct harmony_channel *c;
1028 	struct harmony_dma *d;
1029 	bus_addr_t nextaddr;
1030 	bus_size_t togo;
1031 
1032 	KASSERT(mutex_owned(&sc->sc_intr_lock));
1033 
1034 	c = &sc->sc_capture;
1035 	if (sc->sc_capturing == 0)
1036 		harmony_empty_input(sc);
1037 	else {
1038 		d = c->c_current;
1039 		togo = c->c_segsz - c->c_cnt;
1040 		if (togo == 0) {
1041 			nextaddr = d->d_map->dm_segs[0].ds_addr;
1042 			c->c_cnt = togo = c->c_blksz;
1043 		} else {
1044 			nextaddr = c->c_lastaddr;
1045 			if (togo > c->c_blksz)
1046 				togo = c->c_blksz;
1047 			c->c_cnt += togo;
1048 		}
1049 
1050 		bus_dmamap_sync(sc->sc_dmat, d->d_map,
1051 		    nextaddr - d->d_map->dm_segs[0].ds_addr,
1052 		    c->c_blksz, BUS_DMASYNC_PREWRITE);
1053 
1054 		WRITE_REG(sc, HARMONY_RNXTADD, nextaddr);
1055 		if (start)
1056 			c->c_theaddr = nextaddr;
1057 		SYNC_REG(sc, HARMONY_RNXTADD, BUS_SPACE_BARRIER_WRITE);
1058 		c->c_lastaddr = nextaddr + togo;
1059 
1060 		harmony_try_more(sc, HARMONY_RCURADD,
1061 		    RCURADD_BUFMASK, &sc->sc_capture);
1062 	}
1063 
1064 	callout_schedule(&sc->sc_acc_tmo, 1);
1065 }
1066 
1067 void
harmony_start_pp(struct harmony_softc * sc,int start)1068 harmony_start_pp(struct harmony_softc *sc, int start)
1069 {
1070 	struct harmony_channel *c;
1071 	struct harmony_dma *d;
1072 	bus_addr_t nextaddr;
1073 	bus_size_t togo;
1074 
1075 	KASSERT(mutex_owned(&sc->sc_intr_lock));
1076 
1077 	c = &sc->sc_playback;
1078 	if (sc->sc_playing == 0)
1079 		harmony_empty_output(sc);
1080 	else {
1081 		d = c->c_current;
1082 		togo = c->c_segsz - c->c_cnt;
1083 		if (togo == 0) {
1084 			nextaddr = d->d_map->dm_segs[0].ds_addr;
1085 			c->c_cnt = togo = c->c_blksz;
1086 		} else {
1087 			nextaddr = c->c_lastaddr;
1088 			if (togo > c->c_blksz)
1089 				togo = c->c_blksz;
1090 			c->c_cnt += togo;
1091 		}
1092 
1093 		bus_dmamap_sync(sc->sc_dmat, d->d_map,
1094 		    nextaddr - d->d_map->dm_segs[0].ds_addr,
1095 		    c->c_blksz, BUS_DMASYNC_PREWRITE);
1096 
1097 		WRITE_REG(sc, HARMONY_PNXTADD, nextaddr);
1098 		if (start)
1099 			c->c_theaddr = nextaddr;
1100 		SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE);
1101 		c->c_lastaddr = nextaddr + togo;
1102 
1103 		harmony_try_more(sc, HARMONY_PCURADD,
1104 		    PCURADD_BUFMASK, &sc->sc_playback);
1105 	}
1106 }
1107 
1108 int
harmony_trigger_input(void * vsc,void * start,void * end,int blksize,void (* intr)(void *),void * intrarg,const audio_params_t * param)1109 harmony_trigger_input(void *vsc, void *start, void *end, int blksize,
1110     void (*intr)(void *), void *intrarg, const audio_params_t *param)
1111 {
1112 	struct harmony_softc *sc = vsc;
1113 	struct harmony_channel *c = &sc->sc_capture;
1114 	struct harmony_dma *d;
1115 
1116 	KASSERT(mutex_owned(&sc->sc_intr_lock));
1117 
1118 	for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next)
1119 		continue;
1120 	if (d == NULL) {
1121 		printf("%s: trigger_input: bad addr: %p\n",
1122 		    device_xname(sc->sc_dv), start);
1123 		return EINVAL;
1124 	}
1125 
1126 	c->c_intr = intr;
1127 	c->c_intrarg = intrarg;
1128 	c->c_blksz = blksize;
1129 	c->c_current = d;
1130 	c->c_segsz = (char *)end - (char *)start;
1131 	c->c_cnt = 0;
1132 	c->c_lastaddr = d->d_map->dm_segs[0].ds_addr;
1133 
1134 	sc->sc_capturing = 1;
1135 
1136 	harmony_start_cp(sc, 1);
1137 	harmony_intr_enable(sc);
1138 
1139 	return 0;
1140 }
1141 
1142 static const struct speed_struct {
1143 	uint32_t speed;
1144 	uint32_t bits;
1145 } harmony_speeds[] = {
1146 	{ 5125, CNTL_RATE_5125 },
1147 	{ 6615, CNTL_RATE_6615 },
1148 	{ 8000, CNTL_RATE_8000 },
1149 	{ 9600, CNTL_RATE_9600 },
1150 	{ 11025, CNTL_RATE_11025 },
1151 	{ 16000, CNTL_RATE_16000 },
1152 	{ 18900, CNTL_RATE_18900 },
1153 	{ 22050, CNTL_RATE_22050 },
1154 	{ 27428, CNTL_RATE_27428 },
1155 	{ 32000, CNTL_RATE_32000 },
1156 	{ 33075, CNTL_RATE_33075 },
1157 	{ 37800, CNTL_RATE_37800 },
1158 	{ 44100, CNTL_RATE_44100 },
1159 	{ 48000, CNTL_RATE_48000 },
1160 };
1161 
1162 uint32_t
harmony_speed_bits(struct harmony_softc * sc,u_int speed)1163 harmony_speed_bits(struct harmony_softc *sc, u_int speed)
1164 {
1165 	int i;
1166 
1167 	for (i = 0; i < __arraycount(harmony_speeds); i++) {
1168 		if (speed == harmony_speeds[i].speed) {
1169 			return harmony_speeds[i].bits;
1170 		}
1171 	}
1172 	/* If this happens, harmony_formats[] is wrong */
1173 	panic("speed %u not supported", speed);
1174 }
1175 
1176 int
harmony_set_gainctl(struct harmony_softc * sc)1177 harmony_set_gainctl(struct harmony_softc *sc)
1178 {
1179 	uint32_t bits, mask, val, old;
1180 
1181 	/* XXX leave these bits alone or the chip will not come out of CNTL */
1182 	bits = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK;
1183 
1184 	/* input level */
1185 	bits |= ((sc->sc_input_lvl.left >> (8 - GAINCTL_INPUT_BITS)) <<
1186 	    GAINCTL_INPUT_LEFT_S) & GAINCTL_INPUT_LEFT_M;
1187 	bits |= ((sc->sc_input_lvl.right >> (8 - GAINCTL_INPUT_BITS)) <<
1188 	    GAINCTL_INPUT_RIGHT_S) & GAINCTL_INPUT_RIGHT_M;
1189 
1190 	/* output level (inverted) */
1191 	mask = (1 << GAINCTL_OUTPUT_BITS) - 1;
1192 	val = mask - (sc->sc_output_lvl.left >> (8 - GAINCTL_OUTPUT_BITS));
1193 	bits |= (val << GAINCTL_OUTPUT_LEFT_S) & GAINCTL_OUTPUT_LEFT_M;
1194 	val = mask - (sc->sc_output_lvl.right >> (8 - GAINCTL_OUTPUT_BITS));
1195 	bits |= (val << GAINCTL_OUTPUT_RIGHT_S) & GAINCTL_OUTPUT_RIGHT_M;
1196 
1197 	/* monitor level (inverted) */
1198 	mask = (1 << GAINCTL_MONITOR_BITS) - 1;
1199 	val = mask - (sc->sc_monitor_lvl.left >> (8 - GAINCTL_MONITOR_BITS));
1200 	bits |= (val << GAINCTL_MONITOR_S) & GAINCTL_MONITOR_M;
1201 
1202 	/* XXX messing with these causes CNTL_C to get stuck... grr. */
1203 	bits &= ~GAINCTL_IS_MASK;
1204 	if (sc->sc_in_port == HARMONY_IN_MIC)
1205 		bits |= GAINCTL_IS_LINE;
1206 	else
1207 		bits |= GAINCTL_IS_MICROPHONE;
1208 
1209 	/* XXX messing with these causes CNTL_C to get stuck... grr. */
1210 	bits &= ~(GAINCTL_LE | GAINCTL_HE | GAINCTL_SE);
1211 	if (sc->sc_out_port == HARMONY_OUT_LINE)
1212 		bits |= GAINCTL_LE;
1213 	else if (sc->sc_out_port == HARMONY_OUT_SPEAKER)
1214 		bits |= GAINCTL_SE;
1215 	else
1216 		bits |= GAINCTL_HE;
1217 
1218 	mask = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK;
1219 	old = bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL);
1220 	bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL, bits);
1221 	if ((old & mask) != (bits & mask))
1222 		return 1;
1223 	return 0;
1224 }
1225 
1226 void
harmony_try_more(struct harmony_softc * sc,int curadd,int bufmask,struct harmony_channel * c)1227 harmony_try_more(struct harmony_softc *sc, int curadd, int bufmask,
1228 	struct harmony_channel *c)
1229 {
1230 	struct harmony_dma *d;
1231 	uint32_t cur;
1232 	int i, nsegs;
1233 
1234 	d = c->c_current;
1235 	cur = bus_space_read_4(sc->sc_bt, sc->sc_bh, curadd);
1236 	cur &= bufmask;
1237 	nsegs = 0;
1238 
1239 #ifdef DIAGNOSTIC
1240 	if (cur < d->d_map->dm_segs[0].ds_addr ||
1241 	    cur >= (d->d_map->dm_segs[0].ds_addr + c->c_segsz))
1242 		panic("%s: bad current %x < %lx || %x > %lx",
1243 		    device_xname(sc->sc_dv), cur,
1244 		    d->d_map->dm_segs[0].ds_addr, cur,
1245 		    d->d_map->dm_segs[0].ds_addr + c->c_segsz);
1246 #endif /* DIAGNOSTIC */
1247 
1248 	if (cur > c->c_theaddr) {
1249 		nsegs = (cur - c->c_theaddr) / HARMONY_BUFSIZE;
1250 	} else if (cur < c->c_theaddr) {
1251 		nsegs = (d->d_map->dm_segs[0].ds_addr + c->c_segsz -
1252 		    c->c_theaddr) / HARMONY_BUFSIZE;
1253 		nsegs += (cur - d->d_map->dm_segs[0].ds_addr) /
1254 		    HARMONY_BUFSIZE;
1255 	}
1256 
1257 	if (nsegs != 0 && c->c_intr != NULL) {
1258 		for (i = 0; i < nsegs; i++)
1259 			(*c->c_intr)(c->c_intrarg);
1260 		c->c_theaddr = cur;
1261 	}
1262 }
1263