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