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