xref: /netbsd-src/sys/arch/amiga/dev/aucc.c (revision f3cfa6f6ce31685c6c4a758bc430e69eb99f50a4)
1 /*	$NetBSD: aucc.c,v 1.45 2019/05/08 13:40:14 isaki Exp $ */
2 
3 /*
4  * Copyright (c) 1999 Bernardo Innocenti
5  * All rights reserved.
6  *
7  * Copyright (c) 1997 Stephan Thesing
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by Stephan Thesing.
21  * 4. The name of the author may not be used to endorse or promote products
22  *    derived from this software without specific prior written permission
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 /* TODO:
37  *
38  * - channel allocation is wrong for 14bit mono
39  * - perhaps use a calibration table for better 14bit output
40  * - set 31 kHz AGA video mode to allow 44.1 kHz even if grfcc is missing
41  *	in the kernel
42  * - 14bit output requires maximum volume
43  */
44 
45 #include "aucc.h"
46 #if NAUCC > 0
47 
48 #include <sys/cdefs.h>
49 __KERNEL_RCSID(0, "$NetBSD: aucc.c,v 1.45 2019/05/08 13:40:14 isaki Exp $");
50 
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/errno.h>
54 #include <sys/ioctl.h>
55 #include <sys/device.h>
56 #include <sys/proc.h>
57 #include <machine/cpu.h>
58 
59 #include <sys/audioio.h>
60 #include <dev/audio/audio_if.h>
61 #include <dev/audio/audiovar.h>	/* for AUDIO_MIN_FREQUENCY */
62 
63 #include <amiga/amiga/cc.h>
64 #include <amiga/amiga/custom.h>
65 #include <amiga/amiga/device.h>
66 #include <amiga/dev/auccvar.h>
67 
68 #include "opt_lev6_defer.h"
69 
70 
71 #ifdef LEV6_DEFER
72 #define AUCC_MAXINT 3
73 #define AUCC_ALLINTF (INTF_AUD0|INTF_AUD1|INTF_AUD2)
74 #else
75 #define AUCC_MAXINT 4
76 #define AUCC_ALLINTF (INTF_AUD0|INTF_AUD1|INTF_AUD2|INTF_AUD3)
77 #endif
78 /* this unconditionally; we may use AUD3 as slave channel with LEV6_DEFER */
79 #define AUCC_ALLDMAF (DMAF_AUD0|DMAF_AUD1|DMAF_AUD2|DMAF_AUD3)
80 
81 #ifdef AUDIO_DEBUG
82 /*extern printf(const char *,...);*/
83 int     auccdebug = 1;
84 #define DPRINTF(x)      if (auccdebug) printf x
85 #else
86 #define DPRINTF(x)
87 #endif
88 
89 /* clock frequency.. */
90 extern int eclockfreq;
91 
92 
93 /* hw audio ch */
94 extern struct audio_channel channel[4];
95 
96 
97 /*
98  * Software state.
99  */
100 struct aucc_softc {
101 	aucc_data_t sc_channel[4];	/* per channel freq, ... */
102 	u_int	sc_encoding;		/* encoding AUDIO_ENCODING_.*/
103 	int	sc_channels;		/* # of channels used */
104 	int	sc_precision;		/* 8 or 16 bits */
105 	int	sc_14bit;		/* 14bit output enabled */
106 
107 	int	sc_intrcnt;		/* interrupt count */
108 	int	sc_channelmask;		/* which channels are used ? */
109 	void (*sc_decodefunc)(u_char **, u_char *, int);
110 				/* pointer to format conversion routine */
111 
112 	kmutex_t sc_lock;
113 	kmutex_t sc_intr_lock;
114 };
115 
116 /* interrupt interfaces */
117 void aucc_inthdl(int);
118 
119 /* forward declarations */
120 static int init_aucc(struct aucc_softc *);
121 static u_int freqtoper(u_int);
122 static u_int pertofreq(u_int);
123 
124 /* autoconfiguration driver */
125 void	auccattach(device_t, device_t, void *);
126 int	auccmatch(device_t, cfdata_t, void *);
127 
128 CFATTACH_DECL_NEW(aucc, sizeof(struct aucc_softc),
129     auccmatch, auccattach, NULL, NULL);
130 
131 struct audio_device aucc_device = {
132 	"Amiga-audio",
133 	"2.0",
134 	"aucc"
135 };
136 
137 
138 struct aucc_softc *aucc = NULL;
139 
140 
141 /*
142  * Define our interface to the higher level audio driver.
143  */
144 int	aucc_open(void *, int);
145 void	aucc_close(void *);
146 int	aucc_set_out_sr(void *, u_int);
147 int	aucc_query_format(void *, audio_format_query_t *);
148 int	aucc_round_blocksize(void *, int, int, const audio_params_t *);
149 int	aucc_commit_settings(void *);
150 int	aucc_start_output(void *, void *, int, void (*)(void *), void *);
151 int	aucc_start_input(void *, void *, int, void (*)(void *), void *);
152 int	aucc_halt_output(void *);
153 int	aucc_halt_input(void *);
154 int	aucc_getdev(void *, struct audio_device *);
155 int	aucc_set_port(void *, mixer_ctrl_t *);
156 int	aucc_get_port(void *, mixer_ctrl_t *);
157 int	aucc_query_devinfo(void *, mixer_devinfo_t *);
158 void	aucc_encode(int, int, int, int, u_char *, u_short **);
159 int	aucc_set_format(void *, int,
160 			const audio_params_t *, const audio_params_t *,
161 			audio_filter_reg_t *, audio_filter_reg_t *);
162 int	aucc_get_props(void *);
163 void	aucc_get_locks(void *, kmutex_t **, kmutex_t **);
164 
165 
166 static void aucc_decode_slinear16_1ch(u_char **, u_char *, int);
167 static void aucc_decode_slinear16_2ch(u_char **, u_char *, int);
168 static void aucc_decode_slinear16_3ch(u_char **, u_char *, int);
169 static void aucc_decode_slinear16_4ch(u_char **, u_char *, int);
170 
171 
172 const struct audio_hw_if sa_hw_if = {
173 	.open			= aucc_open,
174 	.close			= aucc_close,
175 	.query_format		= aucc_query_format,
176 	.set_format		= aucc_set_format,
177 	.round_blocksize	= aucc_round_blocksize,
178 	.commit_settings	= aucc_commit_settings,
179 	.start_output		= aucc_start_output,
180 	.start_input		= aucc_start_input,
181 	.halt_output		= aucc_halt_output,
182 	.halt_input		= aucc_halt_input,
183 	.getdev			= aucc_getdev,
184 	.set_port		= aucc_set_port,
185 	.get_port		= aucc_get_port,
186 	.query_devinfo		= aucc_query_devinfo,
187 	.get_props		= aucc_get_props,
188 	.get_locks		= aucc_get_locks,
189 };
190 
191 /*
192  * XXX *1 How lower limit of frequency should be?  same as audio(4)?
193  * XXX *2 Should avoid a magic number at the upper limit of frequency.
194  * XXX *3 In fact, there is a number in this range that have minimal errors.
195  *        It would be better if there is a mechanism which such frequency
196  *        is prioritized.
197  * XXX *4 3/4ch modes use 8bits, 1/2ch modes use 14bits,
198  *        so I imagined that 1/2ch modes are better.
199  */
200 #define AUCC_FORMAT(prio, ch, chmask) \
201 	{ \
202 		.mode		= AUMODE_PLAY, \
203 		.priority	= (prio), \
204 		.encoding	= AUDIO_ENCODING_SLINEAR_BE, \
205 		.validbits	= 16, \
206 		.precision	= 16, \
207 		.channels	= (ch), \
208 		.channel_mask	= (chmask), \
209 		.frequency_type	= 0, \
210 		.frequency	= { AUDIO_MIN_FREQUENCY, 28867 }, \
211 	}
212 static const struct audio_format aucc_formats[] = {
213 	AUCC_FORMAT(1, 1, AUFMT_MONAURAL),
214 	AUCC_FORMAT(1, 2, AUFMT_STEREO),
215 	AUCC_FORMAT(0, 3, AUFMT_UNKNOWN_POSITION),
216 	AUCC_FORMAT(0, 4, AUFMT_UNKNOWN_POSITION),
217 };
218 #define AUCC_NFORMATS __arraycount(aucc_formats)
219 
220 /* autoconfig routines */
221 
222 int
223 auccmatch(device_t parent, cfdata_t cf, void *aux)
224 {
225 	static int aucc_matched = 0;
226 
227 	if (!matchname((char *)aux, "aucc") ||
228 #ifdef DRACO
229 	    is_draco() ||
230 #endif
231 	    aucc_matched)
232 		return 0;
233 
234 	aucc_matched = 1;
235 	return 1;
236 }
237 
238 /*
239  * Audio chip found.
240  */
241 void
242 auccattach(device_t parent, device_t self, void *args)
243 {
244 	struct aucc_softc *sc;
245 	int i;
246 
247 	sc = device_private(self);
248 	printf("\n");
249 
250 	if ((i=init_aucc(sc))) {
251 		printf("audio: no chipmem\n");
252 		return;
253 	}
254 
255 	audio_attach_mi(&sa_hw_if, sc, self);
256 }
257 
258 
259 static int
260 init_aucc(struct aucc_softc *sc)
261 {
262 	int i, err;
263 
264 	err = 0;
265 	/* init values per channel */
266 	for (i = 0; i < 4; i++) {
267 		sc->sc_channel[i].nd_freq = 8000;
268 		sc->sc_channel[i].nd_per = freqtoper(8000);
269 		sc->sc_channel[i].nd_busy = 0;
270 		sc->sc_channel[i].nd_dma = alloc_chipmem(AUDIO_BUF_SIZE*2);
271 		if (sc->sc_channel[i].nd_dma == NULL)
272 			err = 1;
273 		sc->sc_channel[i].nd_dmalength = 0;
274 		sc->sc_channel[i].nd_volume = 64;
275 		sc->sc_channel[i].nd_intr = NULL;
276 		sc->sc_channel[i].nd_intrdata = NULL;
277 		sc->sc_channel[i].nd_doublebuf = 0;
278 		DPRINTF(("DMA buffer for channel %d is %p\n", i,
279 		    sc->sc_channel[i].nd_dma));
280 	}
281 
282 	if (err) {
283 		for (i = 0; i < 4; i++)
284 			if (sc->sc_channel[i].nd_dma)
285 				free_chipmem(sc->sc_channel[i].nd_dma);
286 	}
287 
288 	sc->sc_channels = 1;
289 	sc->sc_channelmask = 0xf;
290 	sc->sc_precision = 16;
291 	sc->sc_14bit = 1;
292 	sc->sc_encoding = AUDIO_ENCODING_SLINEAR_BE;
293 	sc->sc_decodefunc = aucc_decode_slinear16_2ch;
294 
295 	/* clear interrupts and DMA: */
296 	custom.intena = AUCC_ALLINTF;
297 	custom.dmacon = AUCC_ALLDMAF;
298 
299 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
300 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
301 
302 	return err;
303 }
304 
305 int
306 aucc_open(void *addr, int flags)
307 {
308 	struct aucc_softc *sc;
309 	int i;
310 
311 	sc = addr;
312 	DPRINTF(("sa_open: unit %p\n",sc));
313 
314 	for (i = 0; i < AUCC_MAXINT; i++) {
315 		sc->sc_channel[i].nd_intr = NULL;
316 		sc->sc_channel[i].nd_intrdata = NULL;
317 	}
318 	aucc = sc;
319 	sc->sc_channelmask = 0xf;
320 
321 	DPRINTF(("saopen: ok -> sc=%p\n",sc));
322 
323 	return 0;
324 }
325 
326 void
327 aucc_close(void *addr)
328 {
329 
330 	DPRINTF(("sa_close: closed.\n"));
331 }
332 
333 int
334 aucc_set_out_sr(void *addr, u_int sr)
335 {
336 	struct aucc_softc *sc;
337 	u_long per;
338 	int i;
339 
340 	sc = addr;
341 	per = freqtoper(sr);
342 	if (per > 0xffff)
343 		return EINVAL;
344 	sr = pertofreq(per);
345 
346 	for (i = 0; i < 4; i++) {
347 		sc->sc_channel[i].nd_freq = sr;
348 		sc->sc_channel[i].nd_per = per;
349 	}
350 
351 	return 0;
352 }
353 
354 int
355 aucc_query_format(void *addr, audio_format_query_t *afp)
356 {
357 
358 	return audio_query_format(aucc_formats, AUCC_NFORMATS, afp);
359 }
360 
361 int
362 aucc_set_format(void *addr, int setmode,
363 	const audio_params_t *p, const audio_params_t *r,
364 	audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
365 {
366 	struct aucc_softc *sc;
367 
368 	sc = addr;
369 	KASSERT((setmode & AUMODE_RECORD) == 0);
370 
371 #ifdef AUCCDEBUG
372 	printf("%s(setmode 0x%x,"
373 	    "enc %u bits %u, chn %u, sr %u)\n", setmode,
374 	    p->encoding, p->precision, p->channels, p->sample_rate);
375 #endif
376 
377 	switch (p->channels) {
378 	case 1:
379 		sc->sc_decodefunc = aucc_decode_slinear16_1ch;
380 		break;
381 	case 2:
382 		sc->sc_decodefunc = aucc_decode_slinear16_2ch;
383 		break;
384 	case 3:
385 		sc->sc_decodefunc = aucc_decode_slinear16_3ch;
386 		break;
387 	case 4:
388 		sc->sc_decodefunc = aucc_decode_slinear16_4ch;
389 		break;
390 	default:
391 		return EINVAL;
392 	}
393 
394 	sc->sc_encoding = p->encoding;
395 	sc->sc_precision = p->precision;
396 	sc->sc_14bit = ((p->precision == 16) && (p->channels <= 2));
397 	sc->sc_channels = sc->sc_14bit ? (p->channels * 2) : p->channels;
398 
399 	return aucc_set_out_sr(addr, p->sample_rate);
400 }
401 
402 int
403 aucc_round_blocksize(void *addr, int blk,
404 		     int mode, const audio_params_t *param)
405 {
406 
407 	/* round up to even size */
408 	return blk > AUDIO_BUF_SIZE ? AUDIO_BUF_SIZE : blk;
409 }
410 
411 int
412 aucc_commit_settings(void *addr)
413 {
414 	struct aucc_softc *sc;
415 	int i;
416 
417 	DPRINTF(("sa_commit.\n"));
418 
419 	sc = addr;
420 	for (i = 0; i < 4; i++) {
421 		custom.aud[i].vol = sc->sc_channel[i].nd_volume;
422 		custom.aud[i].per = sc->sc_channel[i].nd_per;
423 	}
424 
425 	DPRINTF(("commit done\n"));
426 
427 	return 0;
428 }
429 
430 static int masks[4] = {1,3,7,15}; /* masks for n first channels */
431 static int masks2[4] = {1,2,4,8};
432 
433 int
434 aucc_start_output(void *addr, void *p, int cc, void (*intr)(void *), void *arg)
435 {
436 	struct aucc_softc *sc;
437 	int mask;
438 	int i, j, k, len;
439 	u_char *dmap[4];
440 
441 
442 	sc = addr;
443 	mask = sc->sc_channelmask;
444 
445 	dmap[0] = dmap[1] = dmap[2] = dmap[3] = NULL;
446 
447 	DPRINTF(("sa_start_output: cc=%d %p (%p)\n", cc, intr, arg));
448 
449 	if (sc->sc_channels > 1)
450 		mask &= masks[sc->sc_channels - 1];
451 		/* we use first sc_channels channels */
452 	if (mask == 0) /* active and used channels are disjoint */
453 		return EINVAL;
454 
455 	for (i = 0; i < 4; i++) {
456 		/* channels available ? */
457 		if ((masks2[i] & mask) && (sc->sc_channel[i].nd_busy))
458 			return EBUSY; /* channel is busy */
459 		if (channel[i].isaudio == -1)
460 			return EBUSY; /* system uses them */
461 	}
462 
463 	/* enable interrupt on 1st channel */
464 	for (i = j = 0; i < AUCC_MAXINT; i++) {
465 		if (masks2[i] & mask) {
466 			DPRINTF(("first channel is %d\n",i));
467 			j = i;
468 			sc->sc_channel[i].nd_intr = intr;
469 			sc->sc_channel[i].nd_intrdata = arg;
470 			break;
471 		}
472 	}
473 
474 	DPRINTF(("dmap is %p %p %p %p, mask=0x%x\n", dmap[0], dmap[1],
475 		 dmap[2], dmap[3], mask));
476 
477 	/* disable ints, DMA for channels, until all parameters set */
478 	/* XXX dont disable DMA! custom.dmacon=mask;*/
479 	custom.intreq = mask << INTB_AUD0;
480 	custom.intena = mask << INTB_AUD0;
481 
482 	/* copy data to DMA buffer */
483 
484 	if (sc->sc_channels == 1) {
485 		dmap[0] =
486 		dmap[1] =
487 		dmap[2] =
488 		dmap[3] = (u_char *)sc->sc_channel[j].nd_dma;
489 	} else {
490 		for (k = 0; k < 4; k++) {
491 			if (masks2[k+j] & mask)
492 				dmap[k] = (u_char *)sc->sc_channel[k+j].nd_dma;
493 		}
494 	}
495 
496 	sc->sc_channel[j].nd_doublebuf ^= 1;
497 	if (sc->sc_channel[j].nd_doublebuf) {
498 		dmap[0] += AUDIO_BUF_SIZE;
499 		dmap[1] += AUDIO_BUF_SIZE;
500 		dmap[2] += AUDIO_BUF_SIZE;
501 		dmap[3] += AUDIO_BUF_SIZE;
502 	}
503 
504 	/*
505 	 * compute output length in bytes per channel.
506 	 * divide by two only for 16bit->8bit conversion.
507 	 */
508 	len = cc / sc->sc_channels;
509 	if (!sc->sc_14bit && (sc->sc_precision == 16))
510 		len /= 2;
511 
512 	/* call audio decoding routine */
513 	sc->sc_decodefunc (dmap, (u_char *)p, len);
514 
515 	/* DMA buffers: we use same buffer 4 all channels
516 	 * write DMA location and length
517 	 */
518 	for (i = k = 0; i < 4; i++) {
519 		if (masks2[i] & mask) {
520 			DPRINTF(("turning channel %d on\n",i));
521 			/* sc->sc_channel[i].nd_busy=1; */
522 			channel[i].isaudio = 1;
523 			channel[i].play_count = 1;
524 			channel[i].handler = NULL;
525 			custom.aud[i].per = sc->sc_channel[i].nd_per;
526 			if (sc->sc_14bit && (i > 1))
527 				custom.aud[i].vol = 1;
528 			else
529 				custom.aud[i].vol = sc->sc_channel[i].nd_volume;
530 			custom.aud[i].lc = PREP_DMA_MEM(dmap[k++]);
531 			custom.aud[i].len = len / 2;
532 			sc->sc_channel[i].nd_mask = mask;
533 			DPRINTF(("per is %d, vol is %d, len is %d\n",\
534 			    sc->sc_channel[i].nd_per,
535 			    sc->sc_channel[i].nd_volume, len));
536 		}
537 	}
538 
539 	channel[j].handler = aucc_inthdl;
540 
541 	/* enable ints */
542 	custom.intena = INTF_SETCLR | INTF_INTEN | (masks2[j] << INTB_AUD0);
543 
544 	DPRINTF(("enabled ints: 0x%x\n", (masks2[j] << INTB_AUD0)));
545 
546 	/* enable DMA */
547 	custom.dmacon = DMAF_SETCLR | DMAF_MASTER | mask;
548 
549 	DPRINTF(("enabled DMA, mask=0x%x\n",mask));
550 
551 	return 0;
552 }
553 
554 /* ARGSUSED */
555 int
556 aucc_start_input(void *addr, void *p, int cc, void (*intr)(void *), void *arg)
557 {
558 
559 	return ENXIO; /* no input */
560 }
561 
562 int
563 aucc_halt_output(void *addr)
564 {
565 	struct aucc_softc *sc;
566 	int i;
567 
568 	/* XXX only halt, if input is also halted ?? */
569 	sc = addr;
570 	/* stop DMA, etc */
571 	custom.intena = AUCC_ALLINTF;
572 	custom.dmacon = AUCC_ALLDMAF;
573 	/* mark every busy unit idle */
574 	for (i = 0; i < 4; i++) {
575 		sc->sc_channel[i].nd_busy = sc->sc_channel[i].nd_mask = 0;
576 		channel[i].isaudio = 0;
577 		channel[i].play_count = 0;
578 	}
579 
580 	return 0;
581 }
582 
583 int
584 aucc_halt_input(void *addr)
585 {
586 
587 	/* no input */
588 	return ENXIO;
589 }
590 
591 int
592 aucc_getdev(void *addr, struct audio_device *retp)
593 {
594 
595 	*retp = aucc_device;
596 	return 0;
597 }
598 
599 int
600 aucc_set_port(void *addr, mixer_ctrl_t *cp)
601 {
602 	struct aucc_softc *sc;
603 	int i,j;
604 
605 	DPRINTF(("aucc_set_port: port=%d", cp->dev));
606 	sc = addr;
607 	switch (cp->type) {
608 	case AUDIO_MIXER_SET:
609 		if (cp->dev != AUCC_CHANNELS)
610 			return EINVAL;
611 		i = cp->un.mask;
612 		if ((i < 1) || (i > 15))
613 			return EINVAL;
614 
615 		sc->sc_channelmask = i;
616 		break;
617 
618 	case AUDIO_MIXER_VALUE:
619 		i = cp->un.value.num_channels;
620 		if ((i < 1) || (i > 4))
621 			return EINVAL;
622 
623 #ifdef __XXXwhatsthat
624 		if (cp->dev != AUCC_VOLUME)
625 			return EINVAL;
626 #endif
627 
628 		/* set volume for channel 0..i-1 */
629 
630 		/* evil workaround for xanim bug, IMO */
631 		if ((sc->sc_channels == 1) && (i == 2)) {
632 			sc->sc_channel[0].nd_volume =
633 			    sc->sc_channel[3].nd_volume =
634 			    cp->un.value.level[0] >> 2;
635 			sc->sc_channel[1].nd_volume =
636 			    sc->sc_channel[2].nd_volume =
637 			    cp->un.value.level[1] >> 2;
638 		} else if (i > 1) {
639 			for (j = 0; j < i; j++)
640 				sc->sc_channel[j].nd_volume =
641 				    cp->un.value.level[j] >> 2;
642 		} else if (sc->sc_channels > 1)
643 			for (j = 0; j < sc->sc_channels; j++)
644 				sc->sc_channel[j].nd_volume =
645 				    cp->un.value.level[0] >> 2;
646 		else
647 			for (j = 0; j < 4; j++)
648 				sc->sc_channel[j].nd_volume =
649 				    cp->un.value.level[0] >> 2;
650 		break;
651 
652 	default:
653 		return EINVAL;
654 		break;
655 	}
656 	return 0;
657 }
658 
659 
660 int
661 aucc_get_port(void *addr, mixer_ctrl_t *cp)
662 {
663 	struct aucc_softc *sc;
664 	int i,j;
665 
666 	DPRINTF(("aucc_get_port: port=%d", cp->dev));
667 	sc = addr;
668 	switch (cp->type) {
669 	case AUDIO_MIXER_SET:
670 		if (cp->dev != AUCC_CHANNELS)
671 			return EINVAL;
672 		cp->un.mask = sc->sc_channelmask;
673 		break;
674 
675 	case AUDIO_MIXER_VALUE:
676 		i = cp->un.value.num_channels;
677 		if ((i < 1) || (i > 4))
678 			return EINVAL;
679 
680 		for (j = 0; j < i; j++)
681 			cp->un.value.level[j] =
682 			    (sc->sc_channel[j].nd_volume << 2) +
683 			    (sc->sc_channel[j].nd_volume >> 4);
684 		break;
685 
686 	default:
687 		return EINVAL;
688 	}
689 	return 0;
690 }
691 
692 
693 int
694 aucc_get_props(void *addr)
695 {
696 	return 0;
697 }
698 
699 
700 void
701 aucc_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread)
702 {
703 	struct aucc_softc *sc = opaque;
704 
705 	*intr = &sc->sc_intr_lock;
706 	*thread = &sc->sc_lock;
707 }
708 
709 int
710 aucc_query_devinfo(void *addr, register mixer_devinfo_t *dip)
711 {
712 	int i;
713 
714 	switch(dip->index) {
715 	case AUCC_CHANNELS:
716 		dip->type = AUDIO_MIXER_SET;
717 		dip->mixer_class = AUCC_OUTPUT_CLASS;
718 		dip->prev = dip->next = AUDIO_MIXER_LAST;
719 #define setname(a) strlcpy(dip->label.name, (a), sizeof(dip->label.name))
720 		setname(AudioNspeaker);
721 		for (i = 0; i < 16; i++) {
722 			snprintf(dip->un.s.member[i].label.name,
723 			    sizeof(dip->un.s.member[i].label.name),
724 			    "channelmask%d", i);
725 			dip->un.s.member[i].mask = i;
726 		}
727 		dip->un.s.num_mem = 16;
728 		break;
729 
730 	case AUCC_VOLUME:
731 		dip->type = AUDIO_MIXER_VALUE;
732 		dip->mixer_class = AUCC_OUTPUT_CLASS;
733 		dip->prev = dip->next = AUDIO_MIXER_LAST;
734 		setname(AudioNmaster);
735 		dip->un.v.num_channels = 4;
736 		strcpy(dip->un.v.units.name, AudioNvolume);
737 		break;
738 
739 	case AUCC_OUTPUT_CLASS:
740 		dip->type = AUDIO_MIXER_CLASS;
741 		dip->mixer_class = AUCC_OUTPUT_CLASS;
742 		dip->next = dip->prev = AUDIO_MIXER_LAST;
743 		setname(AudioCoutputs);
744 		break;
745 
746 	default:
747 		return ENXIO;
748 	}
749 
750 	DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
751 
752 	return 0;
753 }
754 
755 /* audio int handler */
756 void
757 aucc_inthdl(int ch)
758 {
759 	int i;
760 	int mask;
761 
762 	mutex_spin_enter(&aucc->sc_intr_lock);
763 	mask = aucc->sc_channel[ch].nd_mask;
764 	/*
765 	 * for all channels in this maskgroup:
766 	 * disable DMA, int
767 	 * mark idle
768 	 */
769 	DPRINTF(("inthandler called, channel %d, mask 0x%x\n", ch, mask));
770 
771 	custom.intreq = mask << INTB_AUD0; /* clear request */
772 	/*
773 	 * XXX: maybe we can leave ints and/or DMA on,
774 	 * if another sample has to be played?
775 	 */
776 	custom.intena = mask << INTB_AUD0;
777 	/*
778 	 * XXX custom.dmacon=mask; NO!!!
779 	 */
780 	for (i = 0; i < 4; i++) {
781 		if (masks2[i] && mask) {
782 			DPRINTF(("marking channel %d idle\n",i));
783 			aucc->sc_channel[i].nd_busy = 0;
784 			aucc->sc_channel[i].nd_mask = 0;
785 			channel[i].isaudio = channel[i].play_count = 0;
786 		}
787 	}
788 
789 	/* call handler */
790 	if (aucc->sc_channel[ch].nd_intr) {
791 		DPRINTF(("calling %p\n",aucc->sc_channel[ch].nd_intr));
792 		(*(aucc->sc_channel[ch].nd_intr))
793 		    (aucc->sc_channel[ch].nd_intrdata);
794 	} else
795 		DPRINTF(("zero int handler\n"));
796 	mutex_spin_exit(&aucc->sc_intr_lock);
797 	DPRINTF(("ints done\n"));
798 }
799 
800 /* transform frequency to period, adjust bounds */
801 static u_int
802 freqtoper(u_int freq)
803 {
804 	u_int per;
805 
806 	per = eclockfreq * 5 / freq;
807 	if (per < 124)
808 		per = 124;   /* must have at least 124 ticks between samples */
809 
810 	return per;
811 }
812 
813 /* transform period to frequency */
814 static u_int
815 pertofreq(u_int per)
816 {
817 
818 	return eclockfreq * 5 / per;
819 }
820 
821 
822 /* 14bit output */
823 static void
824 aucc_decode_slinear16_1ch(u_char **dmap, u_char *p, int i)
825 {
826 	u_char *ch0;
827 	u_char *ch3;
828 
829 	ch0 = dmap[0];
830 	ch3 = dmap[1];		/* XXX should be 3 */
831 	while (i--) {
832 		*ch0++ = *p++;
833 		*ch3++ = *p++ >> 2;
834 	}
835 }
836 
837 /* 14bit stereo output */
838 static void
839 aucc_decode_slinear16_2ch(u_char **dmap, u_char *p, int i)
840 {
841 	u_char *ch0;
842 	u_char *ch1;
843 	u_char *ch2;
844 	u_char *ch3;
845 
846 	ch0 = dmap[0];
847 	ch1 = dmap[1];
848 	ch2 = dmap[2];
849 	ch3 = dmap[3];
850 	while (i--) {
851 		*ch0++ = *p++;
852 		*ch3++ = *p++ >> 2;
853 		*ch1++ = *p++;
854 		*ch2++ = *p++ >> 2;
855 	}
856 }
857 
858 static void
859 aucc_decode_slinear16_3ch(u_char **dmap, u_char *p, int i)
860 {
861 	u_char *ch0;
862 	u_char *ch1;
863 	u_char *ch2;
864 
865 	ch0 = dmap[0];
866 	ch1 = dmap[1];
867 	ch2 = dmap[2];
868 	while (i--) {
869 		*ch0++ = *p++; p++;
870 		*ch1++ = *p++; p++;
871 		*ch2++ = *p++; p++;
872 	}
873 }
874 
875 static void
876 aucc_decode_slinear16_4ch(u_char **dmap, u_char *p, int i)
877 {
878 	u_char *ch0;
879 	u_char *ch1;
880 	u_char *ch2;
881 	u_char *ch3;
882 
883 	ch0 = dmap[0];
884 	ch1 = dmap[1];
885 	ch2 = dmap[2];
886 	ch3 = dmap[3];
887 	while (i--) {
888 		*ch0++ = *p++; p++;
889 		*ch1++ = *p++; p++;
890 		*ch2++ = *p++; p++;
891 		*ch3++ = *p++; p++;
892 	}
893 }
894 
895 #endif /* NAUCC > 0 */
896