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