harmony.c revision 1.3
1/*	$OpenBSD: harmony.c,v 1.3 2003/01/26 21:25:39 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#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/errno.h>
37#include <sys/ioctl.h>
38#include <sys/device.h>
39#include <sys/proc.h>
40#include <sys/malloc.h>
41
42#include <sys/audioio.h>
43#include <dev/audio_if.h>
44#include <dev/auconv.h>
45
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
55#define	HARMONY_NREGS	0x40
56
57#define	HARMONY_ID		0x00
58#define	HARMONY_RESET		0x04
59#define	HARMONY_CNTL		0x08
60#define	HARMONY_GAINCTL		0x0c		/* gain control */
61#define	HARMONY_PLAYNXT		0x10		/* play next address */
62#define	HARMONY_PLAYCUR		0x14		/* play current address */
63#define	HARMONY_CAPTNXT		0x18		/* capture next address */
64#define	HARMONY_CAPTCUR		0x1c		/* capture current address */
65#define	HARMONY_DSTATUS		0x20		/* device status */
66#define	HARMONY_OV		0x24
67#define	HARMONY_PIO		0x28
68#define	HARMONY_DIAG		0x3c
69
70#define	CNTL_INCNTL		0x80000000
71#define	CNTL_FORMAT_MASK	0x000000c0
72#define	CNTL_FORMAT_SLINEAR16BE	0x00000000
73#define	CNTL_FORMAT_ULAW	0x00000040
74#define	CNTL_FORMAT_ALAW	0x00000080
75#define	CNTL_CHANS_MASK		0x00000020
76#define	CNTL_CHANS_MONO		0x00000000
77#define	CNTL_CHANS_STEREO	0x00000020
78#define	CNTL_RATE_MASK		0x0000001f
79#define	CNTL_RATE_5125		0x00000010
80#define	CNTL_RATE_6615		0x00000017
81#define	CNTL_RATE_8000		0x00000008
82#define	CNTL_RATE_9600		0x0000000f
83#define	CNTL_RATE_11025		0x00000011
84#define	CNTL_RATE_16000		0x00000009
85#define	CNTL_RATE_18900		0x00000012
86#define	CNTL_RATE_22050		0x00000013
87#define	CNTL_RATE_27428		0x0000000a
88#define	CNTL_RATE_32000		0x0000000b
89#define	CNTL_RATE_33075		0x00000016
90#define	CNTL_RATE_37800		0x00000014
91#define	CNTL_RATE_44100		0x00000015
92#define	CNTL_RATE_48000		0x0000000e
93
94#define	GAINCTL_INPUT_LEFT_M	0x0000f000
95#define	GAINCTL_INPUT_LEFT_S	12
96#define	GAINCTL_INPUT_RIGHT_M	0x000f0000
97#define	GAINCTL_INPUT_RIGHT_S	16
98#define	GAINCTL_MONITOR_M	0x00f00000
99#define	GAINCTL_MONITOR_S	20
100#define	GAINCTL_OUTPUT_LEFT_M	0x00000fc0
101#define	GAINCTL_OUTPUT_LEFT_S	6
102#define	GAINCTL_OUTPUT_RIGHT_M	0x0000003f
103#define	GAINCTL_OUTPUT_RIGHT_S	0
104
105#define	DSTATUS_INTRENA		0x80000000
106#define	DSTATUS_PLAYNXT		0x00000200
107#define	DSTATUS_CAPTNXT		0x00000002
108
109#define HARMONY_PORT_INPUT_LVL		0
110#define	HARMONY_PORT_OUTPUT_LVL		1
111#define	HARMONY_PORT_MONITOR_LVL	2
112#define	HARMONY_PORT_INPUT_CLASS	3
113#define	HARMONY_PORT_OUTPUT_CLASS	4
114#define	HARMONY_PORT_MONITOR_CLASS	5
115
116#define	PLAYBACK_EMPTYS			3	/* playback empty buffers */
117#define	CAPTURE_EMPTYS			3	/* capture empty buffers */
118#define	HARMONY_BUFSIZE			4096
119
120struct harmony_empty {
121	u_int8_t	playback[PLAYBACK_EMPTYS][HARMONY_BUFSIZE];
122	u_int8_t	capture[CAPTURE_EMPTYS][HARMONY_BUFSIZE];
123};
124
125struct harmony_dma {
126	struct harmony_dma *d_next;
127	bus_dmamap_t d_map;
128	bus_dma_segment_t d_seg;
129	caddr_t d_kva;
130	size_t d_size;
131};
132
133struct harmony_channel {
134	struct harmony_dma *c_current;
135	bus_size_t c_segsz;
136	bus_size_t c_cnt;
137	bus_size_t c_blksz;
138	bus_addr_t c_lastaddr;
139	void (*c_intr)(void *);
140	void *c_intrarg;
141};
142
143struct harmony_softc {
144	struct device sc_dv;
145	bus_dma_tag_t sc_dmat;
146	bus_space_tag_t sc_bt;
147	bus_space_handle_t sc_bh;
148	int sc_open;
149	u_int32_t sc_gainctl;
150	u_int32_t sc_cntlbits;
151	int sc_need_commit;
152	int sc_playback_empty;
153	bus_addr_t sc_playback_paddrs[PLAYBACK_EMPTYS];
154	int sc_capture_empty;
155	bus_addr_t sc_capture_paddrs[CAPTURE_EMPTYS];
156	bus_dmamap_t sc_empty_map;
157	bus_dma_segment_t sc_empty_seg;
158	int sc_empty_rseg;
159	struct harmony_empty *sc_empty_kva;
160	struct harmony_dma *sc_dmas;
161	int sc_playing, sc_capturing, sc_intr_enable;
162	struct harmony_channel sc_playback;
163};
164
165int     harmony_open(void *, int);
166void    harmony_close(void *);
167int     harmony_query_encoding(void *, struct audio_encoding *);
168int     harmony_set_params(void *, int, int, struct audio_params *,
169    struct audio_params *);
170int     harmony_round_blocksize(void *, int);
171int     harmony_commit_settings(void *);
172int     harmony_halt_output(void *);
173int     harmony_halt_input(void *);
174int     harmony_getdev(void *, struct audio_device *);
175int     harmony_set_port(void *, mixer_ctrl_t *);
176int     harmony_get_port(void *, mixer_ctrl_t *);
177int     harmony_query_devinfo(void *addr, mixer_devinfo_t *);
178void *  harmony_allocm(void *, int, size_t, int, int);
179void    harmony_freem(void *, void *, int);
180size_t  harmony_round_buffersize(void *, int, size_t);
181int     harmony_get_props(void *);
182int     harmony_trigger_output(void *, void *, void *, int,
183    void (*intr)(void *), void *arg, struct audio_params *);
184int     harmony_trigger_input(void *, void *, void *, int,
185    void (*intr)(void *), void *arg, struct audio_params *);
186
187struct audio_hw_if harmony_sa_hw_if = {
188	harmony_open,
189	harmony_close,
190	NULL,
191	harmony_query_encoding,
192	harmony_set_params,
193	harmony_round_blocksize,
194	harmony_commit_settings,
195	NULL,
196	NULL,
197	NULL,
198	NULL,
199	harmony_halt_output,
200	harmony_halt_input,
201	NULL,
202	harmony_getdev,
203	NULL,
204	harmony_set_port,
205	harmony_get_port,
206	harmony_query_devinfo,
207	harmony_allocm,
208	harmony_freem,
209	harmony_round_buffersize,
210	NULL,
211	harmony_get_props,
212	harmony_trigger_output,
213	harmony_trigger_input,
214};
215
216struct audio_device harmony_device = {
217	"harmony",
218	"gsc",
219	"lasi",
220};
221
222int harmony_match(struct device *, void *, void *);
223void harmony_attach(struct device *, struct device *, void *);
224int harmony_intr(void *);
225void harmony_intr_enable(struct harmony_softc *);
226void harmony_intr_disable(struct harmony_softc *);
227void harmony_wait(struct harmony_softc *);
228void harmony_set_gainctl(struct harmony_softc *, u_int32_t);
229u_int32_t harmony_speed_bits(struct harmony_softc *, u_long *);
230
231int
232harmony_match(parent, match, aux)
233	struct device *parent;
234	void *match, *aux;
235{
236	struct gsc_attach_args *ga = aux;
237
238	if (ga->ga_type.iodc_type == HPPA_TYPE_FIO) {
239		if (ga->ga_type.iodc_sv_model == HPPA_FIO_A1 ||
240		    ga->ga_type.iodc_sv_model == HPPA_FIO_A2NB ||
241		    ga->ga_type.iodc_sv_model == HPPA_FIO_A1NB ||
242		    ga->ga_type.iodc_sv_model == HPPA_FIO_A2)
243			return (1);
244	}
245	return (0);
246}
247
248void
249harmony_attach(parent, self, aux)
250	struct device *parent, *self;
251	void *aux;
252{
253	struct harmony_softc *sc = (struct harmony_softc *)self;
254	struct gsc_attach_args *ga = aux;
255	int i;
256
257	sc->sc_bt = ga->ga_iot;
258	sc->sc_dmat = ga->ga_dmatag;
259
260	if (bus_space_map(sc->sc_bt, ga->ga_hpa, HARMONY_NREGS, 0,
261	    &sc->sc_bh) != 0) {
262		printf(": couldn't map registers\n");
263		return;
264	}
265
266	if (bus_dmamem_alloc(sc->sc_dmat, sizeof(struct harmony_empty),
267	    PAGE_SIZE, 0, &sc->sc_empty_seg, 1, &sc->sc_empty_rseg,
268	    BUS_DMA_NOWAIT) != 0) {
269		printf(": couldn't alloc empty memory\n");
270		return;
271	}
272	if (bus_dmamem_map(sc->sc_dmat, &sc->sc_empty_seg, 1,
273	    sizeof(struct harmony_empty), (caddr_t *)&sc->sc_empty_kva,
274	    BUS_DMA_NOWAIT) != 0) {
275		printf(": couldn't map empty memory\n");
276		bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg,
277		    sc->sc_empty_rseg);
278		return;
279	}
280	if (bus_dmamap_create(sc->sc_dmat, sizeof(struct harmony_empty), 1,
281	    sizeof(struct harmony_empty), 0, BUS_DMA_NOWAIT,
282	    &sc->sc_empty_map) != 0) {
283		printf(": can't create empty dmamap\n");
284		bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_empty_kva,
285		    sizeof(struct harmony_empty));
286		bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg,
287		    sc->sc_empty_rseg);
288		return;
289	}
290	if (bus_dmamap_load(sc->sc_dmat, sc->sc_empty_map, sc->sc_empty_kva,
291	    sizeof(struct harmony_empty), NULL, BUS_DMA_NOWAIT) != 0) {
292		printf(": can't load empty dmamap\n");
293		bus_dmamap_destroy(sc->sc_dmat, sc->sc_empty_map);
294		bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_empty_kva,
295		    sizeof(struct harmony_empty));
296		bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg,
297		    sc->sc_empty_rseg);
298		return;
299	}
300
301	sc->sc_playback_empty = 0;
302	for (i = 0; i < PLAYBACK_EMPTYS; i++)
303		sc->sc_playback_paddrs[i] =
304		    sc->sc_empty_map->dm_segs[0].ds_addr +
305		    offsetof(struct harmony_empty, playback[i][0]);
306
307	sc->sc_capture_empty = 0;
308	for (i = 0; i < CAPTURE_EMPTYS; i++)
309		sc->sc_capture_paddrs[i] =
310		    sc->sc_empty_map->dm_segs[0].ds_addr +
311		    offsetof(struct harmony_empty, playback[i][0]);
312
313	bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
314	    offsetof(struct harmony_empty, playback[0][0]),
315	    PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE);
316
317	(void)gsc_intr_establish((struct gsc_softc *)parent,
318	    IPL_AUDIO, ga->ga_irq, harmony_intr, sc, &sc->sc_dv);
319
320	/* set default gains */
321	sc->sc_gainctl =
322	    ((0x2 << GAINCTL_OUTPUT_LEFT_S) & GAINCTL_OUTPUT_LEFT_M) |
323	    ((0x2 << GAINCTL_OUTPUT_RIGHT_S) & GAINCTL_OUTPUT_RIGHT_M) |
324	    ((0xf << GAINCTL_INPUT_LEFT_S) & GAINCTL_INPUT_LEFT_M) |
325	    ((0xf << GAINCTL_INPUT_RIGHT_S) & GAINCTL_INPUT_RIGHT_M) |
326	    ((0x2 << GAINCTL_MONITOR_S) & GAINCTL_MONITOR_M) |
327	    0x0f000000;
328
329	printf("\n");
330
331	audio_attach_mi(&harmony_sa_hw_if, sc, &sc->sc_dv);
332}
333
334/*
335 * interrupt handler
336 */
337int
338harmony_intr(vsc)
339	void *vsc;
340{
341	struct harmony_softc *sc = vsc;
342	u_int32_t dstatus;
343	int r = 0;
344
345	if (sc->sc_intr_enable == 0)
346		return (0);
347
348	harmony_intr_disable(sc);
349	harmony_wait(sc);
350
351	dstatus = bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_DSTATUS) &
352	    (DSTATUS_PLAYNXT | DSTATUS_CAPTNXT);
353
354	if (dstatus & DSTATUS_PLAYNXT) {
355		r = 1;
356		if (sc->sc_playing == 0) {
357			bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_PLAYNXT,
358			    sc->sc_playback_paddrs[sc->sc_playback_empty]);
359			if (++sc->sc_playback_empty == PLAYBACK_EMPTYS)
360				sc->sc_playback_empty = 0;
361		} else {
362			struct harmony_channel *c = &sc->sc_playback;
363			struct harmony_dma *d;
364			bus_addr_t nextaddr;
365			bus_size_t togo;
366
367			d = c->c_current;
368			togo = c->c_segsz - c->c_cnt;
369			if (togo == 0) {
370				nextaddr = d->d_map->dm_segs[0].ds_addr;
371				c->c_cnt = togo = c->c_blksz;
372			} else {
373				nextaddr = c->c_lastaddr;
374				if (togo > c->c_blksz)
375					togo = c->c_blksz;
376				c->c_cnt += togo;
377			}
378
379			bus_dmamap_sync(sc->sc_dmat, d->d_map,
380			    nextaddr - d->d_map->dm_segs[0].ds_addr,
381			    c->c_blksz, BUS_DMASYNC_PREWRITE);
382
383			bus_space_write_4(sc->sc_bt, sc->sc_bh,
384			    HARMONY_PLAYNXT, nextaddr);
385			c->c_lastaddr = nextaddr + togo;
386
387			if (c->c_intr != NULL)
388				(*c->c_intr)(c->c_intrarg);
389		}
390	}
391
392	if (dstatus & DSTATUS_CAPTNXT) {
393		r = 1;
394		bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_CAPTNXT,
395		    sc->sc_capture_paddrs[sc->sc_capture_empty]);
396		if (++sc->sc_capture_empty == CAPTURE_EMPTYS)
397			sc->sc_capture_empty = 0;
398	}
399
400	harmony_intr_enable(sc);
401
402	return (r);
403}
404
405void
406harmony_intr_enable(struct harmony_softc *sc)
407{
408	harmony_wait(sc);
409	sc->sc_intr_enable = 1;
410	bus_space_write_4(sc->sc_bt, sc->sc_bh,
411	    HARMONY_DSTATUS, DSTATUS_INTRENA);
412}
413
414void
415harmony_intr_disable(struct harmony_softc *sc)
416{
417	harmony_wait(sc);
418	bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_DSTATUS, 0);
419	sc->sc_intr_enable = 0;
420}
421
422void
423harmony_wait(struct harmony_softc *sc)
424{
425	int i = 5000;
426
427	for (i = 5000; i > 0; i++)
428		if (((bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_CNTL)
429		    & CNTL_INCNTL)) == 0)
430			return;
431	printf("%s: wait timeout\n", sc->sc_dv.dv_xname);
432}
433
434void
435harmony_set_gainctl(struct harmony_softc *sc, u_int32_t gain)
436{
437	harmony_wait(sc);
438	bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL, gain);
439}
440
441int
442harmony_open(void *vsc, int flags)
443{
444	struct harmony_softc *sc = vsc;
445
446	if (sc->sc_open)
447		return (EBUSY);
448	sc->sc_open = 1;
449
450	/* silence */
451	harmony_set_gainctl(sc, GAINCTL_OUTPUT_LEFT_M |
452	    GAINCTL_OUTPUT_RIGHT_M | GAINCTL_MONITOR_M);
453
454	/* reset codec */
455	harmony_wait(sc);
456	bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_RESET, 1);
457	DELAY(50000);
458	bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_RESET, 0);
459
460	harmony_set_gainctl(sc, sc->sc_gainctl);
461
462	return (0);
463}
464
465void
466harmony_close(void *vsc)
467{
468	struct harmony_softc *sc = vsc;
469
470	harmony_halt_input(sc);
471	harmony_halt_output(sc);
472	sc->sc_open = 0;
473}
474
475int
476harmony_query_encoding(void *vsc, struct audio_encoding *fp)
477{
478	int err = 0;
479
480	switch (fp->index) {
481	case 0:
482		strcpy(fp->name, AudioEmulaw);
483		fp->encoding = AUDIO_ENCODING_ULAW;
484		fp->precision = 8;
485		fp->flags = 0;
486		break;
487	case 1:
488		strcpy(fp->name, AudioEalaw);
489		fp->encoding = AUDIO_ENCODING_ALAW;
490		fp->precision = 8;
491		fp->flags = 0;
492		break;
493	case 2:
494		strcpy(fp->name, AudioEslinear_be);
495		fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
496		fp->precision = 16;
497		fp->flags = 0;
498		break;
499	case 3:
500		strcpy(fp->name, AudioEslinear_le);
501		fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
502		fp->precision = 16;
503		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
504		break;
505	case 4:
506		strcpy(fp->name, AudioEulinear_be);
507		fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
508		fp->precision = 16;
509		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
510		break;
511	default:
512		err = EINVAL;
513	}
514	return (err);
515}
516
517int
518harmony_set_params(void *vsc, int setmode, int usemode,
519    struct audio_params *p, struct audio_params *r)
520{
521	struct harmony_softc *sc = vsc;
522	u_int32_t bits;
523	void (*pswcode)(void *, u_char *, int cnt) = NULL;
524	void (*rswcode)(void *, u_char *, int cnt) = NULL;
525
526	switch (p->encoding) {
527	case AUDIO_ENCODING_ULAW:
528		if (p->precision != 8)
529			return (EINVAL);
530		bits = CNTL_FORMAT_ULAW;
531		break;
532	case AUDIO_ENCODING_ALAW:
533		if (p->precision != 8)
534			return (EINVAL);
535		bits = CNTL_FORMAT_ALAW;
536		break;
537	case AUDIO_ENCODING_SLINEAR_BE:
538		if (p->precision != 16)
539			return (EINVAL);
540		bits = CNTL_FORMAT_SLINEAR16BE;
541		break;
542
543	/* emulated formats */
544	case AUDIO_ENCODING_SLINEAR_LE:
545		if (p->precision != 16)
546			return (EINVAL);
547		bits = CNTL_FORMAT_SLINEAR16BE;
548		rswcode = pswcode = swap_bytes;
549		break;
550	case AUDIO_ENCODING_ULINEAR_BE:
551		if (p->precision != 16)
552			return (EINVAL);
553		bits = CNTL_FORMAT_SLINEAR16BE;
554		rswcode = pswcode = change_sign16_be;
555		break;
556	default:
557		return (EINVAL);
558	}
559
560	if (p->channels == 1)
561		bits |= CNTL_CHANS_MONO;
562	else if (p->channels == 2)
563		bits |= CNTL_CHANS_STEREO;
564	else
565		return (EINVAL);
566
567	bits |= harmony_speed_bits(sc, &p->sample_rate);
568	p->sw_code = pswcode;
569	r->sw_code = rswcode;
570	sc->sc_cntlbits = bits;
571	sc->sc_need_commit = 1;
572
573	return (0);
574}
575
576int
577harmony_round_blocksize(void *vsc, int blk)
578{
579	return (HARMONY_BUFSIZE);
580}
581
582int
583harmony_commit_settings(void *vsc)
584{
585	struct harmony_softc *sc = vsc;
586	u_int8_t quietchar;
587	int i;
588
589	if (sc->sc_need_commit == 0)
590		return (0);
591
592	harmony_wait(sc);
593	bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_CNTL, sc->sc_cntlbits);
594
595	/* set the silence character based on the encoding type */
596	bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
597	    offsetof(struct harmony_empty, playback[0][0]),
598	    PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_POSTWRITE);
599	switch (sc->sc_cntlbits & CNTL_FORMAT_MASK) {
600	case CNTL_FORMAT_ULAW:
601		quietchar = 0x7f;
602		break;
603	case CNTL_FORMAT_ALAW:
604		quietchar = 0x55;
605		break;
606	case CNTL_FORMAT_SLINEAR16BE:
607	default:
608		quietchar = 0;
609		break;
610	}
611	for (i = 0; i < PLAYBACK_EMPTYS; i++)
612		memset(&sc->sc_empty_kva->playback[i][0],
613		    quietchar, HARMONY_BUFSIZE);
614	bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
615	    offsetof(struct harmony_empty, playback[0][0]),
616	    PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE);
617	sc->sc_need_commit = 0;
618
619	return (0);
620}
621
622int
623harmony_halt_output(void *vsc)
624{
625	struct harmony_softc *sc = vsc;
626
627	harmony_intr_disable(sc);
628	sc->sc_playing = 0;
629	return (0);
630}
631
632int
633harmony_halt_input(void *vsc)
634{
635	struct harmony_softc *sc = vsc;
636
637	harmony_intr_disable(sc);
638	sc->sc_capturing = 0;
639	return (0);
640}
641
642int
643harmony_getdev(void *vsc, struct audio_device *retp)
644{
645	*retp = harmony_device;
646	return (0);
647}
648
649int
650harmony_set_port(void *vsc, mixer_ctrl_t *cp)
651{
652	struct harmony_softc *sc = vsc;
653	int err = EINVAL;
654
655	switch (cp->dev) {
656	case HARMONY_PORT_INPUT_LVL:
657		if (cp->type != AUDIO_MIXER_VALUE)
658			break;
659		if (cp->un.value.num_channels == 1) {
660			sc->sc_gainctl &=
661			    ~(GAINCTL_INPUT_LEFT_M | GAINCTL_INPUT_RIGHT_M);
662			sc->sc_gainctl |=
663			    (cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] <<
664			    GAINCTL_INPUT_LEFT_S) & GAINCTL_INPUT_LEFT_M;
665			sc->sc_gainctl |=
666			    (cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] <<
667			    GAINCTL_INPUT_RIGHT_S) & GAINCTL_INPUT_RIGHT_M;
668		} else if (cp->un.value.num_channels == 2) {
669			sc->sc_gainctl &=
670			    ~(GAINCTL_INPUT_LEFT_M | GAINCTL_INPUT_RIGHT_M);
671			sc->sc_gainctl |=
672			    (cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] <<
673			    GAINCTL_INPUT_RIGHT_S) & GAINCTL_INPUT_RIGHT_M;
674			sc->sc_gainctl |=
675			    (cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] <<
676			    GAINCTL_INPUT_RIGHT_S) & GAINCTL_INPUT_RIGHT_M;
677		} else
678			break;
679		harmony_set_gainctl(sc, sc->sc_gainctl);
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_gainctl &=
687			    ~(GAINCTL_OUTPUT_LEFT_M | GAINCTL_OUTPUT_RIGHT_M);
688			sc->sc_gainctl |=
689			    (cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] <<
690			    GAINCTL_OUTPUT_LEFT_S) & GAINCTL_OUTPUT_LEFT_M;
691			sc->sc_gainctl |=
692			    (cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] <<
693			    GAINCTL_OUTPUT_RIGHT_S) & GAINCTL_OUTPUT_RIGHT_M;
694		} else if (cp->un.value.num_channels == 2) {
695			sc->sc_gainctl &=
696			    ~(GAINCTL_OUTPUT_LEFT_M | GAINCTL_OUTPUT_RIGHT_M);
697			sc->sc_gainctl |=
698			    (cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] <<
699			    GAINCTL_OUTPUT_RIGHT_S) & GAINCTL_OUTPUT_RIGHT_M;
700			sc->sc_gainctl |=
701			    (cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] <<
702			    GAINCTL_OUTPUT_RIGHT_S) & GAINCTL_OUTPUT_RIGHT_M;
703		} else
704			break;
705		harmony_set_gainctl(sc, sc->sc_gainctl);
706		err = 0;
707		break;
708	case HARMONY_PORT_MONITOR_LVL:
709		if (cp->type != AUDIO_MIXER_VALUE)
710			break;
711		if (cp->un.value.num_channels != 1)
712			break;
713		sc->sc_gainctl &= ~GAINCTL_MONITOR_M;
714		sc->sc_gainctl |=
715		    (cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] <<
716		    GAINCTL_MONITOR_S) & GAINCTL_MONITOR_M;
717		harmony_set_gainctl(sc, sc->sc_gainctl);
718		err = 0;
719		break;
720	}
721
722	return (err);
723}
724
725int
726harmony_get_port(void *vsc, mixer_ctrl_t *cp)
727{
728	struct harmony_softc *sc = vsc;
729	int err = EINVAL;
730
731	switch (cp->dev) {
732	case HARMONY_PORT_INPUT_LVL:
733		if (cp->type != AUDIO_MIXER_VALUE)
734			break;
735		if (cp->un.value.num_channels == 1) {
736			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
737			    (sc->sc_gainctl & GAINCTL_INPUT_LEFT_M) >>
738			    GAINCTL_INPUT_LEFT_S;
739		} else if (cp->un.value.num_channels == 2) {
740			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
741			    (sc->sc_gainctl & GAINCTL_INPUT_LEFT_M) >>
742			    GAINCTL_INPUT_LEFT_S;
743			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
744			    (sc->sc_gainctl & GAINCTL_INPUT_RIGHT_M) >>
745			    GAINCTL_INPUT_RIGHT_S;
746		} else
747			break;
748		err = 0;
749		break;
750	case HARMONY_PORT_OUTPUT_LVL:
751		if (cp->type != AUDIO_MIXER_VALUE)
752			break;
753		if (cp->un.value.num_channels == 1) {
754			cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
755			    (sc->sc_gainctl & GAINCTL_OUTPUT_LEFT_M) >>
756			    GAINCTL_OUTPUT_LEFT_S;
757		} else if (cp->un.value.num_channels == 2) {
758			cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
759			    (sc->sc_gainctl & GAINCTL_OUTPUT_LEFT_M) >>
760			    GAINCTL_OUTPUT_LEFT_S;
761			cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
762			    (sc->sc_gainctl & GAINCTL_OUTPUT_RIGHT_M) >>
763			    GAINCTL_OUTPUT_RIGHT_S;
764		} else
765			break;
766		err = 0;
767		break;
768	case HARMONY_PORT_MONITOR_LVL:
769		if (cp->type != AUDIO_MIXER_VALUE)
770			break;
771		if (cp->un.value.num_channels != 1)
772			break;
773		cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
774		    (sc->sc_gainctl & GAINCTL_MONITOR_M) >>
775		    GAINCTL_MONITOR_S;
776		err = 0;
777		break;
778	}
779	return (0);
780}
781
782int
783harmony_query_devinfo(void *vsc, mixer_devinfo_t *dip)
784{
785	int err = 0;
786
787	switch (dip->index) {
788	case HARMONY_PORT_INPUT_LVL:
789		dip->type = AUDIO_MIXER_VALUE;
790		dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
791		dip->prev = dip->next = AUDIO_MIXER_LAST;
792		strcpy(dip->label.name, AudioNinput);
793		dip->un.v.num_channels = 2;
794		strcpy(dip->un.v.units.name, AudioNvolume);
795		break;
796	case HARMONY_PORT_OUTPUT_LVL:
797		dip->type = AUDIO_MIXER_VALUE;
798		dip->mixer_class = HARMONY_PORT_OUTPUT_CLASS;
799		dip->prev = dip->next = AUDIO_MIXER_LAST;
800		strcpy(dip->label.name, AudioNoutput);
801		dip->un.v.num_channels = 2;
802		strcpy(dip->un.v.units.name, AudioNvolume);
803		break;
804	case HARMONY_PORT_MONITOR_LVL:
805		dip->type = AUDIO_MIXER_VALUE;
806		dip->mixer_class = HARMONY_PORT_MONITOR_CLASS;
807		dip->prev = dip->next = AUDIO_MIXER_LAST;
808		strcpy(dip->label.name, AudioNoutput);
809		dip->un.v.num_channels = 1;
810		strcpy(dip->un.v.units.name, AudioNvolume);
811		break;
812	case HARMONY_PORT_INPUT_CLASS:
813		dip->type = AUDIO_MIXER_CLASS;
814		dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
815		dip->prev = dip->next = AUDIO_MIXER_LAST;
816		strcpy(dip->label.name, AudioCinputs);
817		break;
818	case HARMONY_PORT_OUTPUT_CLASS:
819		dip->type = AUDIO_MIXER_CLASS;
820		dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
821		dip->prev = dip->next = AUDIO_MIXER_LAST;
822		strcpy(dip->label.name, AudioCoutputs);
823		break;
824	case HARMONY_PORT_MONITOR_CLASS:
825		dip->type = AUDIO_MIXER_CLASS;
826		dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
827		dip->prev = dip->next = AUDIO_MIXER_LAST;
828		strcpy(dip->label.name, AudioCmonitor);
829		break;
830	default:
831		err = ENXIO;
832		break;
833	}
834
835	return (err);
836}
837
838void *
839harmony_allocm(void *vsc, int dir, size_t size, int pool, int flags)
840{
841	struct harmony_softc *sc = vsc;
842	struct harmony_dma *d;
843	int rseg;
844
845	d = (struct harmony_dma *)malloc(sizeof(struct harmony_dma), pool, flags);
846	if (d == NULL)
847		goto fail;
848
849	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, BUS_DMA_NOWAIT,
850	    &d->d_map) != 0)
851		goto fail1;
852
853	if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &d->d_seg, 1,
854	    &rseg, BUS_DMA_NOWAIT) != 0)
855		goto fail2;
856
857	if (bus_dmamem_map(sc->sc_dmat, &d->d_seg, 1, size, &d->d_kva,
858	    BUS_DMA_NOWAIT) != 0)
859		goto fail3;
860
861	if (bus_dmamap_load(sc->sc_dmat, d->d_map, d->d_kva, size, NULL,
862	    BUS_DMA_NOWAIT) != 0)
863		goto fail4;
864
865	d->d_next = sc->sc_dmas;
866	sc->sc_dmas = d;
867	d->d_size = size;
868	return (d->d_kva);
869
870fail4:
871	bus_dmamem_unmap(sc->sc_dmat, d->d_kva, size);
872fail3:
873	bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1);
874fail2:
875	bus_dmamap_destroy(sc->sc_dmat, d->d_map);
876fail1:
877	free(d, pool);
878fail:
879	return (NULL);
880}
881
882void
883harmony_freem(void *vsc, void *ptr, int pool)
884{
885	struct harmony_softc *sc = vsc;
886	struct harmony_dma *d, **dd;
887
888	for (dd = &sc->sc_dmas; (d = *dd) != NULL; dd = &(*dd)->d_next) {
889		if (d->d_kva != ptr)
890			continue;
891		bus_dmamap_unload(sc->sc_dmat, d->d_map);
892		bus_dmamem_unmap(sc->sc_dmat, d->d_kva, d->d_size);
893		bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1);
894		bus_dmamap_destroy(sc->sc_dmat, d->d_map);
895		free(d, pool);
896		return;
897	}
898	printf("%s: free rogue pointer\n", sc->sc_dv.dv_xname);
899}
900
901size_t
902harmony_round_buffersize(void *vsc, int direction, size_t size)
903{
904	return (size & (size_t)(-HARMONY_BUFSIZE));
905}
906
907int
908harmony_get_props(void *vsc)
909{
910	return (AUDIO_PROP_FULLDUPLEX);
911}
912
913int
914harmony_trigger_output(void *vsc, void *start, void *end, int blksize,
915    void (*intr)(void *), void *intrarg, struct audio_params *param)
916{
917	struct harmony_softc *sc = vsc;
918	struct harmony_channel *c = &sc->sc_playback;
919	struct harmony_dma *d;
920	bus_size_t n;
921
922	for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next)
923		/*EMPTY*/;
924	if (d == NULL) {
925		printf("%s: trigger_output: bad addr: %p\n",
926		    sc->sc_dv.dv_xname, start);
927		return (EINVAL);
928	}
929
930	c->c_intr = intr;
931	c->c_intrarg = intrarg;
932
933	n = (caddr_t)end - (caddr_t)start;
934
935	c->c_blksz = blksize;
936	c->c_current = d;
937	c->c_segsz = n;
938
939	if (n > c->c_blksz)
940		n = c->c_blksz;
941	c->c_cnt = n;
942
943	bus_dmamap_sync(sc->sc_dmat, d->d_map, 0, c->c_blksz,
944	    BUS_DMASYNC_PREWRITE);
945	bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_PLAYNXT,
946	    d->d_map->dm_segs[0].ds_addr);
947	c->c_lastaddr = d->d_map->dm_segs[0].ds_addr + n;
948
949	sc->sc_playing = 1;
950	harmony_intr_enable(sc);
951	return (0);
952}
953
954int
955harmony_trigger_input(void *vsc, void *start, void *end, int blksize,
956    void (*intr)(void *), void *arg, struct audio_params *param)
957{
958	struct harmony_softc *sc = vsc;
959
960	bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_CAPTNXT,
961	    sc->sc_capture_paddrs[sc->sc_capture_empty]);
962	if (++sc->sc_capture_empty == CAPTURE_EMPTYS)
963		sc->sc_capture_empty = 0;
964	sc->sc_capturing = 1;
965	harmony_intr_enable(sc);
966	return (0);
967}
968
969static const struct speed_struct {
970	u_int32_t speed;
971	u_int32_t bits;
972} harmony_speeds[] = {
973	{ 5125, CNTL_RATE_5125 },
974	{ 6615, CNTL_RATE_6615 },
975	{ 8000, CNTL_RATE_8000 },
976	{ 9600, CNTL_RATE_9600 },
977	{ 11025, CNTL_RATE_11025 },
978	{ 16000, CNTL_RATE_16000 },
979	{ 18900, CNTL_RATE_18900 },
980	{ 22050, CNTL_RATE_22050 },
981	{ 27428, CNTL_RATE_27428 },
982	{ 32000, CNTL_RATE_32000 },
983	{ 33075, CNTL_RATE_33075 },
984	{ 37800, CNTL_RATE_37800 },
985	{ 44100, CNTL_RATE_44100 },
986	{ 48000, CNTL_RATE_48000 },
987};
988
989u_int32_t
990harmony_speed_bits(struct harmony_softc *sc, u_long *speedp)
991{
992	int i, n, selected = -1;
993
994	n = sizeof(harmony_speeds) / sizeof(harmony_speeds[0]);
995
996	if ((*speedp) <= harmony_speeds[0].speed)
997		selected = 0;
998	else if ((*speedp) >= harmony_speeds[n - 1].speed)
999		selected = n - 1;
1000	else {
1001		for (i = 1; selected == -1 && i < n; i++) {
1002			if ((*speedp) == harmony_speeds[i].speed)
1003				selected = i;
1004			else if ((*speedp) < harmony_speeds[i].speed) {
1005				int diff1, diff2;
1006
1007				diff1 = (*speedp) - harmony_speeds[i - 1].speed;
1008				diff2 = harmony_speeds[i].speed - (*speedp);
1009				if (diff1 < diff2)
1010					selected = i - 1;
1011				else
1012					selected = i;
1013			}
1014		}
1015	}
1016
1017	if (selected == -1)
1018		selected = 2;
1019
1020	*speedp = harmony_speeds[selected].speed;
1021	return (harmony_speeds[selected].bits);
1022}
1023
1024struct cfdriver harmony_cd = {
1025	NULL, "harmony", DV_DULL
1026};
1027
1028struct cfattach harmony_ca = {
1029	sizeof(struct harmony_softc), harmony_match, harmony_attach
1030};
1031