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