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