xref: /netbsd-src/sys/arch/amiga/dev/aucc.c (revision 3204498c4416bc85d0b6b17524f04bc22ae964e8)
1*3204498cSisaki /*	$NetBSD: aucc.c,v 1.48 2020/02/29 06:03:55 isaki Exp $ */
2e7029fc0Saugustss 
3b14e6082Sis /*
4946db35cSis  * Copyright (c) 1999 Bernardo Innocenti
5946db35cSis  * All rights reserved.
6946db35cSis  *
7b14e6082Sis  * Copyright (c) 1997 Stephan Thesing
8b14e6082Sis  * All rights reserved.
9b14e6082Sis  *
10b14e6082Sis  * Redistribution and use in source and binary forms, with or without
11b14e6082Sis  * modification, are permitted provided that the following conditions
12b14e6082Sis  * are met:
13b14e6082Sis  * 1. Redistributions of source code must retain the above copyright
14b14e6082Sis  *    notice, this list of conditions and the following disclaimer.
15b14e6082Sis  * 2. Redistributions in binary form must reproduce the above copyright
16b14e6082Sis  *    notice, this list of conditions and the following disclaimer in the
17b14e6082Sis  *    documentation and/or other materials provided with the distribution.
18b14e6082Sis  * 3. All advertising materials mentioning features or use of this software
19b14e6082Sis  *    must display the following acknowledgement:
20b14e6082Sis  *      This product includes software developed by Stephan Thesing.
21b14e6082Sis  * 4. The name of the author may not be used to endorse or promote products
22b14e6082Sis  *    derived from this software without specific prior written permission
23b14e6082Sis  *
24b14e6082Sis  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25b14e6082Sis  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26b14e6082Sis  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27b14e6082Sis  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28b14e6082Sis  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29b14e6082Sis  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30b14e6082Sis  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31b14e6082Sis  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32b14e6082Sis  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33b14e6082Sis  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34b14e6082Sis  */
35b14e6082Sis 
36946db35cSis /* TODO:
37946db35cSis  *
38946db35cSis  * - channel allocation is wrong for 14bit mono
39946db35cSis  * - perhaps use a calibration table for better 14bit output
40a1f606d3Slukem  * - set 31 kHz AGA video mode to allow 44.1 kHz even if grfcc is missing
41946db35cSis  *	in the kernel
42946db35cSis  * - 14bit output requires maximum volume
43946db35cSis  */
44946db35cSis 
45b14e6082Sis #include "aucc.h"
46b14e6082Sis #if NAUCC > 0
47b14e6082Sis 
481ea4df81Saymeric #include <sys/cdefs.h>
49*3204498cSisaki __KERNEL_RCSID(0, "$NetBSD: aucc.c,v 1.48 2020/02/29 06:03:55 isaki Exp $");
501ea4df81Saymeric 
51b14e6082Sis #include <sys/param.h>
52b14e6082Sis #include <sys/systm.h>
53b14e6082Sis #include <sys/errno.h>
54b14e6082Sis #include <sys/ioctl.h>
55b14e6082Sis #include <sys/device.h>
56b14e6082Sis #include <sys/proc.h>
57b14e6082Sis #include <machine/cpu.h>
58b14e6082Sis 
59b14e6082Sis #include <sys/audioio.h>
60e622eac4Sisaki #include <dev/audio/audio_if.h>
61e622eac4Sisaki #include <dev/audio/audiovar.h>	/* for AUDIO_MIN_FREQUENCY */
62e622eac4Sisaki 
63b14e6082Sis #include <amiga/amiga/cc.h>
64b14e6082Sis #include <amiga/amiga/custom.h>
65b14e6082Sis #include <amiga/amiga/device.h>
66b14e6082Sis #include <amiga/dev/auccvar.h>
67b14e6082Sis 
6809a3dd5fSis #include "opt_lev6_defer.h"
6909a3dd5fSis 
707fe30657Sis 
717fe30657Sis #ifdef LEV6_DEFER
727fe30657Sis #define AUCC_MAXINT 3
737fe30657Sis #define AUCC_ALLINTF (INTF_AUD0|INTF_AUD1|INTF_AUD2)
747fe30657Sis #else
757fe30657Sis #define AUCC_MAXINT 4
767fe30657Sis #define AUCC_ALLINTF (INTF_AUD0|INTF_AUD1|INTF_AUD2|INTF_AUD3)
777fe30657Sis #endif
787fe30657Sis /* this unconditionally; we may use AUD3 as slave channel with LEV6_DEFER */
797fe30657Sis #define AUCC_ALLDMAF (DMAF_AUD0|DMAF_AUD1|DMAF_AUD2|DMAF_AUD3)
807fe30657Sis 
81b14e6082Sis #ifdef AUDIO_DEBUG
829382c873Saymeric /*extern printf(const char *,...);*/
83b14e6082Sis int     auccdebug = 1;
84b14e6082Sis #define DPRINTF(x)      if (auccdebug) printf x
85b14e6082Sis #else
86b14e6082Sis #define DPRINTF(x)
87b14e6082Sis #endif
88b14e6082Sis 
89b14e6082Sis /* clock frequency.. */
90b14e6082Sis extern int eclockfreq;
91b14e6082Sis 
92b14e6082Sis 
93b14e6082Sis /* hw audio ch */
94b14e6082Sis extern struct audio_channel channel[4];
95b14e6082Sis 
96b14e6082Sis 
97b14e6082Sis /*
98b14e6082Sis  * Software state.
99b14e6082Sis  */
100b14e6082Sis struct aucc_softc {
101b14e6082Sis 	aucc_data_t sc_channel[4];	/* per channel freq, ... */
102b14e6082Sis 	u_int	sc_encoding;		/* encoding AUDIO_ENCODING_.*/
103b14e6082Sis 	int	sc_channels;		/* # of channels used */
104946db35cSis 	int	sc_precision;		/* 8 or 16 bits */
105946db35cSis 	int	sc_14bit;		/* 14bit output enabled */
106b14e6082Sis 
107b14e6082Sis 	int	sc_intrcnt;		/* interrupt count */
108b14e6082Sis 	int	sc_channelmask;		/* which channels are used ? */
1099382c873Saymeric 	void (*sc_decodefunc)(u_char **, u_char *, int);
110946db35cSis 				/* pointer to format conversion routine */
1118a962f23Sjmcneill 
1128a962f23Sjmcneill 	kmutex_t sc_lock;
1138a962f23Sjmcneill 	kmutex_t sc_intr_lock;
114b14e6082Sis };
115b14e6082Sis 
116b14e6082Sis /* interrupt interfaces */
1179382c873Saymeric void aucc_inthdl(int);
118b14e6082Sis 
119b14e6082Sis /* forward declarations */
1209382c873Saymeric static int init_aucc(struct aucc_softc *);
1219382c873Saymeric static u_int freqtoper(u_int);
1229382c873Saymeric static u_int pertofreq(u_int);
123b14e6082Sis 
124b14e6082Sis /* autoconfiguration driver */
125cbab9cadSchs void	auccattach(device_t, device_t, void *);
126cbab9cadSchs int	auccmatch(device_t, cfdata_t, void *);
127b14e6082Sis 
128cbab9cadSchs CFATTACH_DECL_NEW(aucc, sizeof(struct aucc_softc),
129c5e91d44Sthorpej     auccmatch, auccattach, NULL, NULL);
130b14e6082Sis 
131b14e6082Sis struct audio_device aucc_device = {
132b14e6082Sis 	"Amiga-audio",
133946db35cSis 	"2.0",
134b14e6082Sis 	"aucc"
135b14e6082Sis };
136b14e6082Sis 
137b14e6082Sis 
138b14e6082Sis struct aucc_softc *aucc = NULL;
139b14e6082Sis 
140b14e6082Sis 
141b14e6082Sis /*
142b14e6082Sis  * Define our interface to the higher level audio driver.
143b14e6082Sis  */
1449382c873Saymeric int	aucc_open(void *, int);
1459382c873Saymeric void	aucc_close(void *);
14623b5d914Skent int	aucc_set_out_sr(void *, u_int);
147e622eac4Sisaki int	aucc_query_format(void *, audio_format_query_t *);
14823b5d914Skent int	aucc_round_blocksize(void *, int, int, const audio_params_t *);
1499382c873Saymeric int	aucc_commit_settings(void *);
1509382c873Saymeric int	aucc_start_output(void *, void *, int, void (*)(void *), void *);
1519382c873Saymeric int	aucc_start_input(void *, void *, int, void (*)(void *), void *);
1529382c873Saymeric int	aucc_halt_output(void *);
1539382c873Saymeric int	aucc_halt_input(void *);
1549382c873Saymeric int	aucc_getdev(void *, struct audio_device *);
1559382c873Saymeric int	aucc_set_port(void *, mixer_ctrl_t *);
1569382c873Saymeric int	aucc_get_port(void *, mixer_ctrl_t *);
1579382c873Saymeric int	aucc_query_devinfo(void *, mixer_devinfo_t *);
1589382c873Saymeric void	aucc_encode(int, int, int, int, u_char *, u_short **);
159e622eac4Sisaki int	aucc_set_format(void *, int,
160e622eac4Sisaki 			const audio_params_t *, const audio_params_t *,
161e622eac4Sisaki 			audio_filter_reg_t *, audio_filter_reg_t *);
1629382c873Saymeric int	aucc_get_props(void *);
1638a962f23Sjmcneill void	aucc_get_locks(void *, kmutex_t **, kmutex_t **);
164b14e6082Sis 
165946db35cSis 
1669382c873Saymeric static void aucc_decode_slinear16_1ch(u_char **, u_char *, int);
1679382c873Saymeric static void aucc_decode_slinear16_2ch(u_char **, u_char *, int);
1689382c873Saymeric static void aucc_decode_slinear16_3ch(u_char **, u_char *, int);
1699382c873Saymeric static void aucc_decode_slinear16_4ch(u_char **, u_char *, int);
170946db35cSis 
171946db35cSis 
17218f717bbSyamt const struct audio_hw_if sa_hw_if = {
1736291b134Sisaki 	.open			= aucc_open,
1746291b134Sisaki 	.close			= aucc_close,
175e622eac4Sisaki 	.query_format		= aucc_query_format,
176e622eac4Sisaki 	.set_format		= aucc_set_format,
1776291b134Sisaki 	.round_blocksize	= aucc_round_blocksize,
1786291b134Sisaki 	.commit_settings	= aucc_commit_settings,
1796291b134Sisaki 	.start_output		= aucc_start_output,
1806291b134Sisaki 	.start_input		= aucc_start_input,
1816291b134Sisaki 	.halt_output		= aucc_halt_output,
1826291b134Sisaki 	.halt_input		= aucc_halt_input,
1836291b134Sisaki 	.getdev			= aucc_getdev,
1846291b134Sisaki 	.set_port		= aucc_set_port,
1856291b134Sisaki 	.get_port		= aucc_get_port,
1866291b134Sisaki 	.query_devinfo		= aucc_query_devinfo,
1876291b134Sisaki 	.get_props		= aucc_get_props,
1886291b134Sisaki 	.get_locks		= aucc_get_locks,
189b14e6082Sis };
190b14e6082Sis 
191e622eac4Sisaki /*
192e622eac4Sisaki  * XXX *1 How lower limit of frequency should be?  same as audio(4)?
193e622eac4Sisaki  * XXX *2 Should avoid a magic number at the upper limit of frequency.
194e622eac4Sisaki  * XXX *3 In fact, there is a number in this range that have minimal errors.
195e622eac4Sisaki  *        It would be better if there is a mechanism which such frequency
196e622eac4Sisaki  *        is prioritized.
197e622eac4Sisaki  * XXX *4 3/4ch modes use 8bits, 1/2ch modes use 14bits,
198e622eac4Sisaki  *        so I imagined that 1/2ch modes are better.
199e622eac4Sisaki  */
200e622eac4Sisaki #define AUCC_FORMAT(prio, ch, chmask) \
201e622eac4Sisaki 	{ \
202e622eac4Sisaki 		.mode		= AUMODE_PLAY, \
203e622eac4Sisaki 		.priority	= (prio), \
204e622eac4Sisaki 		.encoding	= AUDIO_ENCODING_SLINEAR_BE, \
205e622eac4Sisaki 		.validbits	= 16, \
206e622eac4Sisaki 		.precision	= 16, \
207e622eac4Sisaki 		.channels	= (ch), \
208e622eac4Sisaki 		.channel_mask	= (chmask), \
209e622eac4Sisaki 		.frequency_type	= 0, \
210e622eac4Sisaki 		.frequency	= { AUDIO_MIN_FREQUENCY, 28867 }, \
211e622eac4Sisaki 	}
212e622eac4Sisaki static const struct audio_format aucc_formats[] = {
213e622eac4Sisaki 	AUCC_FORMAT(1, 1, AUFMT_MONAURAL),
214e622eac4Sisaki 	AUCC_FORMAT(1, 2, AUFMT_STEREO),
215e622eac4Sisaki 	AUCC_FORMAT(0, 3, AUFMT_UNKNOWN_POSITION),
216e622eac4Sisaki 	AUCC_FORMAT(0, 4, AUFMT_UNKNOWN_POSITION),
217e622eac4Sisaki };
218e622eac4Sisaki #define AUCC_NFORMATS __arraycount(aucc_formats)
219e622eac4Sisaki 
220b14e6082Sis /* autoconfig routines */
221b14e6082Sis 
222b14e6082Sis int
auccmatch(device_t parent,cfdata_t cf,void * aux)223cbab9cadSchs auccmatch(device_t parent, cfdata_t cf, void *aux)
224b14e6082Sis {
2258bc084e1Skleink 	static int aucc_matched = 0;
226b14e6082Sis 
2278bc084e1Skleink 	if (!matchname((char *)aux, "aucc") ||
2288bc084e1Skleink #ifdef DRACO
2298bc084e1Skleink 	    is_draco() ||
2308bc084e1Skleink #endif
2318bc084e1Skleink 	    aucc_matched)
232b14e6082Sis 		return 0;
2338bc084e1Skleink 
2348bc084e1Skleink 	aucc_matched = 1;
2358bc084e1Skleink 	return 1;
236b14e6082Sis }
237b14e6082Sis 
238b14e6082Sis /*
239b14e6082Sis  * Audio chip found.
240b14e6082Sis  */
241b14e6082Sis void
auccattach(device_t parent,device_t self,void * args)242cbab9cadSchs auccattach(device_t parent, device_t self, void *args)
243b14e6082Sis {
24493293b9eSkent 	struct aucc_softc *sc;
24593293b9eSkent 	int i;
246b14e6082Sis 
247cbab9cadSchs 	sc = device_private(self);
248b14e6082Sis 	printf("\n");
249b14e6082Sis 
250b14e6082Sis 	if ((i=init_aucc(sc))) {
251b14e6082Sis 		printf("audio: no chipmem\n");
252b14e6082Sis 		return;
253b14e6082Sis 	}
254b14e6082Sis 
255cbab9cadSchs 	audio_attach_mi(&sa_hw_if, sc, self);
256b14e6082Sis }
257b14e6082Sis 
258b14e6082Sis 
259b14e6082Sis static int
init_aucc(struct aucc_softc * sc)2609382c873Saymeric init_aucc(struct aucc_softc *sc)
261b14e6082Sis {
26293293b9eSkent 	int i, err;
263b14e6082Sis 
26493293b9eSkent 	err = 0;
265b14e6082Sis 	/* init values per channel */
266b14e6082Sis 	for (i = 0; i < 4; i++) {
267b14e6082Sis 		sc->sc_channel[i].nd_freq = 8000;
268b14e6082Sis 		sc->sc_channel[i].nd_per = freqtoper(8000);
269b14e6082Sis 		sc->sc_channel[i].nd_busy = 0;
270b14e6082Sis 		sc->sc_channel[i].nd_dma = alloc_chipmem(AUDIO_BUF_SIZE*2);
271b14e6082Sis 		if (sc->sc_channel[i].nd_dma == NULL)
272b14e6082Sis 			err = 1;
273b14e6082Sis 		sc->sc_channel[i].nd_dmalength = 0;
274b14e6082Sis 		sc->sc_channel[i].nd_volume = 64;
275b14e6082Sis 		sc->sc_channel[i].nd_intr = NULL;
276b14e6082Sis 		sc->sc_channel[i].nd_intrdata = NULL;
2775171612dSis 		sc->sc_channel[i].nd_doublebuf = 0;
2781ffa7b76Swiz 		DPRINTF(("DMA buffer for channel %d is %p\n", i,
279b14e6082Sis 		    sc->sc_channel[i].nd_dma));
280b14e6082Sis 	}
281b14e6082Sis 
282b14e6082Sis 	if (err) {
283b14e6082Sis 		for (i = 0; i < 4; i++)
284b14e6082Sis 			if (sc->sc_channel[i].nd_dma)
285b14e6082Sis 				free_chipmem(sc->sc_channel[i].nd_dma);
286b14e6082Sis 	}
287b14e6082Sis 
2885171612dSis 	sc->sc_channels = 1;
289b14e6082Sis 	sc->sc_channelmask = 0xf;
290e622eac4Sisaki 	sc->sc_precision = 16;
291e622eac4Sisaki 	sc->sc_14bit = 1;
292e622eac4Sisaki 	sc->sc_encoding = AUDIO_ENCODING_SLINEAR_BE;
293e622eac4Sisaki 	sc->sc_decodefunc = aucc_decode_slinear16_2ch;
294b14e6082Sis 
2951ffa7b76Swiz 	/* clear interrupts and DMA: */
2967fe30657Sis 	custom.intena = AUCC_ALLINTF;
297946db35cSis 	custom.dmacon = AUCC_ALLDMAF;
298b14e6082Sis 
2998a962f23Sjmcneill 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
3008a962f23Sjmcneill 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
3018a962f23Sjmcneill 
302b14e6082Sis 	return err;
303b14e6082Sis }
304b14e6082Sis 
305b14e6082Sis int
aucc_open(void * addr,int flags)3069382c873Saymeric aucc_open(void *addr, int flags)
307b14e6082Sis {
30893293b9eSkent 	struct aucc_softc *sc;
309658656bbSaugustss 	int i;
310b14e6082Sis 
31193293b9eSkent 	sc = addr;
312658656bbSaugustss 	DPRINTF(("sa_open: unit %p\n",sc));
313b14e6082Sis 
3147fe30657Sis 	for (i = 0; i < AUCC_MAXINT; i++) {
315b14e6082Sis 		sc->sc_channel[i].nd_intr = NULL;
316b14e6082Sis 		sc->sc_channel[i].nd_intrdata = NULL;
317b14e6082Sis 	}
318b14e6082Sis 	aucc = sc;
319b14e6082Sis 	sc->sc_channelmask = 0xf;
320b14e6082Sis 
3217cdea212Schristos 	DPRINTF(("saopen: ok -> sc=%p\n",sc));
322b14e6082Sis 
32393293b9eSkent 	return 0;
324b14e6082Sis }
325b14e6082Sis 
326b14e6082Sis void
aucc_close(void * addr)3279382c873Saymeric aucc_close(void *addr)
328b14e6082Sis {
329b14e6082Sis 
330b14e6082Sis 	DPRINTF(("sa_close: closed.\n"));
331b14e6082Sis }
332b14e6082Sis 
333b14e6082Sis int
aucc_set_out_sr(void * addr,u_int sr)33423b5d914Skent aucc_set_out_sr(void *addr, u_int sr)
335b14e6082Sis {
33693293b9eSkent 	struct aucc_softc *sc;
337b14e6082Sis 	u_long per;
33893293b9eSkent 	int i;
339b14e6082Sis 
34093293b9eSkent 	sc = addr;
341b14e6082Sis 	per = freqtoper(sr);
342b14e6082Sis 	if (per > 0xffff)
343b14e6082Sis 		return EINVAL;
344b14e6082Sis 	sr = pertofreq(per);
345b14e6082Sis 
346b14e6082Sis 	for (i = 0; i < 4; i++) {
347b14e6082Sis 		sc->sc_channel[i].nd_freq = sr;
348b14e6082Sis 		sc->sc_channel[i].nd_per = per;
349b14e6082Sis 	}
350b14e6082Sis 
35193293b9eSkent 	return 0;
352b14e6082Sis }
353b14e6082Sis 
354b14e6082Sis int
aucc_query_format(void * addr,audio_format_query_t * afp)355e622eac4Sisaki aucc_query_format(void *addr, audio_format_query_t *afp)
356b14e6082Sis {
35793293b9eSkent 
358e622eac4Sisaki 	return audio_query_format(aucc_formats, AUCC_NFORMATS, afp);
359b14e6082Sis }
360b14e6082Sis 
361b14e6082Sis int
aucc_set_format(void * addr,int setmode,const audio_params_t * p,const audio_params_t * r,audio_filter_reg_t * pfil,audio_filter_reg_t * rfil)362e622eac4Sisaki aucc_set_format(void *addr, int setmode,
363e622eac4Sisaki 	const audio_params_t *p, const audio_params_t *r,
364e622eac4Sisaki 	audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
365b14e6082Sis {
36693293b9eSkent 	struct aucc_softc *sc;
3675171612dSis 
36893293b9eSkent 	sc = addr;
369e622eac4Sisaki 	KASSERT((setmode & AUMODE_RECORD) == 0);
3705171612dSis 
371e7609638Sis #ifdef AUCCDEBUG
372e622eac4Sisaki 	printf("%s(setmode 0x%x,"
373e622eac4Sisaki 	    "enc %u bits %u, chn %u, sr %u)\n", setmode,
374946db35cSis 	    p->encoding, p->precision, p->channels, p->sample_rate);
375e7609638Sis #endif
3764b718644Sis 
377946db35cSis 	switch (p->channels) {
378946db35cSis 	case 1:
379946db35cSis 		sc->sc_decodefunc = aucc_decode_slinear16_1ch;
380946db35cSis 		break;
381946db35cSis 	case 2:
382946db35cSis 		sc->sc_decodefunc = aucc_decode_slinear16_2ch;
383946db35cSis 		break;
384946db35cSis 	case 3:
385946db35cSis 		sc->sc_decodefunc = aucc_decode_slinear16_3ch;
386946db35cSis 		break;
387946db35cSis 	case 4:
388946db35cSis 		sc->sc_decodefunc = aucc_decode_slinear16_4ch;
389946db35cSis 		break;
390946db35cSis 	default:
391946db35cSis 		return EINVAL;
392946db35cSis 	}
393b14e6082Sis 
3945171612dSis 	sc->sc_encoding = p->encoding;
395946db35cSis 	sc->sc_precision = p->precision;
396946db35cSis 	sc->sc_14bit = ((p->precision == 16) && (p->channels <= 2));
397946db35cSis 	sc->sc_channels = sc->sc_14bit ? (p->channels * 2) : p->channels;
3985171612dSis 
3995171612dSis 	return aucc_set_out_sr(addr, p->sample_rate);
400b14e6082Sis }
401b14e6082Sis 
402b14e6082Sis int
aucc_round_blocksize(void * addr,int blk,int mode,const audio_params_t * param)40323b5d914Skent aucc_round_blocksize(void *addr, int blk,
40423b5d914Skent 		     int mode, const audio_params_t *param)
405b14e6082Sis {
40693293b9eSkent 
407*3204498cSisaki 	if (blk > AUDIO_BUF_SIZE)
408*3204498cSisaki 		blk = AUDIO_BUF_SIZE;
409*3204498cSisaki 
410*3204498cSisaki 	blk = rounddown(blk, param->channels * param->precision / NBBY);
411*3204498cSisaki 	return blk;
412b14e6082Sis }
413b14e6082Sis 
414b14e6082Sis int
aucc_commit_settings(void * addr)4159382c873Saymeric aucc_commit_settings(void *addr)
416b14e6082Sis {
41793293b9eSkent 	struct aucc_softc *sc;
41893293b9eSkent 	int i;
419b14e6082Sis 
420b14e6082Sis 	DPRINTF(("sa_commit.\n"));
421b14e6082Sis 
42293293b9eSkent 	sc = addr;
423b14e6082Sis 	for (i = 0; i < 4; i++) {
424b14e6082Sis 		custom.aud[i].vol = sc->sc_channel[i].nd_volume;
425b14e6082Sis 		custom.aud[i].per = sc->sc_channel[i].nd_per;
426b14e6082Sis 	}
427b14e6082Sis 
428b14e6082Sis 	DPRINTF(("commit done\n"));
429b14e6082Sis 
43093293b9eSkent 	return 0;
431b14e6082Sis }
432b14e6082Sis 
433b14e6082Sis static int masks[4] = {1,3,7,15}; /* masks for n first channels */
434b14e6082Sis static int masks2[4] = {1,2,4,8};
435b14e6082Sis 
436b14e6082Sis int
aucc_start_output(void * addr,void * p,int cc,void (* intr)(void *),void * arg)4379382c873Saymeric aucc_start_output(void *addr, void *p, int cc, void (*intr)(void *), void *arg)
438b14e6082Sis {
4395171612dSis 	struct aucc_softc *sc;
4405171612dSis 	int mask;
441946db35cSis 	int i, j, k, len;
442946db35cSis 	u_char *dmap[4];
443b14e6082Sis 
444b14e6082Sis 
4455171612dSis 	sc = addr;
4465171612dSis 	mask = sc->sc_channelmask;
4475171612dSis 
4485171612dSis 	dmap[0] = dmap[1] = dmap[2] = dmap[3] = NULL;
449b14e6082Sis 
450b14e6082Sis 	DPRINTF(("sa_start_output: cc=%d %p (%p)\n", cc, intr, arg));
451b14e6082Sis 
452c7e3ab13Sis 	if (sc->sc_channels > 1)
453c7e3ab13Sis 		mask &= masks[sc->sc_channels - 1];
454c7e3ab13Sis 		/* we use first sc_channels channels */
455b14e6082Sis 	if (mask == 0) /* active and used channels are disjoint */
456b14e6082Sis 		return EINVAL;
457b14e6082Sis 
458946db35cSis 	for (i = 0; i < 4; i++) {
459946db35cSis 		/* channels available ? */
460b14e6082Sis 		if ((masks2[i] & mask) && (sc->sc_channel[i].nd_busy))
461b14e6082Sis 			return EBUSY; /* channel is busy */
462b14e6082Sis 		if (channel[i].isaudio == -1)
463b14e6082Sis 			return EBUSY; /* system uses them */
464b14e6082Sis 	}
465b14e6082Sis 
466b14e6082Sis 	/* enable interrupt on 1st channel */
4675171612dSis 	for (i = j = 0; i < AUCC_MAXINT; i++) {
468b14e6082Sis 		if (masks2[i] & mask) {
469b14e6082Sis 			DPRINTF(("first channel is %d\n",i));
470b14e6082Sis 			j = i;
471b14e6082Sis 			sc->sc_channel[i].nd_intr = intr;
472b14e6082Sis 			sc->sc_channel[i].nd_intrdata = arg;
473b14e6082Sis 			break;
474b14e6082Sis 		}
475b14e6082Sis 	}
476b14e6082Sis 
4775171612dSis 	DPRINTF(("dmap is %p %p %p %p, mask=0x%x\n", dmap[0], dmap[1],
4785171612dSis 		 dmap[2], dmap[3], mask));
4795171612dSis 
4801ffa7b76Swiz 	/* disable ints, DMA for channels, until all parameters set */
4815171612dSis 	/* XXX dont disable DMA! custom.dmacon=mask;*/
4825171612dSis 	custom.intreq = mask << INTB_AUD0;
4835171612dSis 	custom.intena = mask << INTB_AUD0;
484b14e6082Sis 
4851ffa7b76Swiz 	/* copy data to DMA buffer */
486b14e6082Sis 
4875171612dSis 	if (sc->sc_channels == 1) {
4885171612dSis 		dmap[0] =
4895171612dSis 		dmap[1] =
4905171612dSis 		dmap[2] =
491946db35cSis 		dmap[3] = (u_char *)sc->sc_channel[j].nd_dma;
49293293b9eSkent 	} else {
4935171612dSis 		for (k = 0; k < 4; k++) {
4945171612dSis 			if (masks2[k+j] & mask)
495946db35cSis 				dmap[k] = (u_char *)sc->sc_channel[k+j].nd_dma;
4965171612dSis 		}
4975171612dSis 	}
498b14e6082Sis 
4995171612dSis 	sc->sc_channel[j].nd_doublebuf ^= 1;
5005171612dSis 	if (sc->sc_channel[j].nd_doublebuf) {
501946db35cSis 		dmap[0] += AUDIO_BUF_SIZE;
502946db35cSis 		dmap[1] += AUDIO_BUF_SIZE;
503946db35cSis 		dmap[2] += AUDIO_BUF_SIZE;
504946db35cSis 		dmap[3] += AUDIO_BUF_SIZE;
5055171612dSis 	}
506b14e6082Sis 
50793293b9eSkent 	/*
50893293b9eSkent 	 * compute output length in bytes per channel.
509946db35cSis 	 * divide by two only for 16bit->8bit conversion.
510946db35cSis 	 */
511946db35cSis 	len = cc / sc->sc_channels;
512946db35cSis 	if (!sc->sc_14bit && (sc->sc_precision == 16))
513946db35cSis 		len /= 2;
514b14e6082Sis 
515946db35cSis 	/* call audio decoding routine */
516946db35cSis 	sc->sc_decodefunc (dmap, (u_char *)p, len);
517946db35cSis 
5181ffa7b76Swiz 	/* DMA buffers: we use same buffer 4 all channels
5191ffa7b76Swiz 	 * write DMA location and length
520946db35cSis 	 */
5215171612dSis 	for (i = k = 0; i < 4; i++) {
522b14e6082Sis 		if (masks2[i] & mask) {
523b14e6082Sis 			DPRINTF(("turning channel %d on\n",i));
524b14e6082Sis 			/* sc->sc_channel[i].nd_busy=1; */
525b14e6082Sis 			channel[i].isaudio = 1;
526b14e6082Sis 			channel[i].play_count = 1;
527b14e6082Sis 			channel[i].handler = NULL;
528b14e6082Sis 			custom.aud[i].per = sc->sc_channel[i].nd_per;
529946db35cSis 			if (sc->sc_14bit && (i > 1))
530946db35cSis 				custom.aud[i].vol = 1;
531946db35cSis 			else
532b14e6082Sis 				custom.aud[i].vol = sc->sc_channel[i].nd_volume;
5335171612dSis 			custom.aud[i].lc = PREP_DMA_MEM(dmap[k++]);
534946db35cSis 			custom.aud[i].len = len / 2;
535b14e6082Sis 			sc->sc_channel[i].nd_mask = mask;
536b14e6082Sis 			DPRINTF(("per is %d, vol is %d, len is %d\n",\
5375171612dSis 			    sc->sc_channel[i].nd_per,
538946db35cSis 			    sc->sc_channel[i].nd_volume, len));
539b14e6082Sis 		}
540b14e6082Sis 	}
541b14e6082Sis 
542b14e6082Sis 	channel[j].handler = aucc_inthdl;
543b14e6082Sis 
544b14e6082Sis 	/* enable ints */
5457fe30657Sis 	custom.intena = INTF_SETCLR | INTF_INTEN | (masks2[j] << INTB_AUD0);
546b14e6082Sis 
5477fe30657Sis 	DPRINTF(("enabled ints: 0x%x\n", (masks2[j] << INTB_AUD0)));
548b14e6082Sis 
5491ffa7b76Swiz 	/* enable DMA */
550b14e6082Sis 	custom.dmacon = DMAF_SETCLR | DMAF_MASTER | mask;
551b14e6082Sis 
5521ffa7b76Swiz 	DPRINTF(("enabled DMA, mask=0x%x\n",mask));
553b14e6082Sis 
55493293b9eSkent 	return 0;
555b14e6082Sis }
556b14e6082Sis 
557b14e6082Sis /* ARGSUSED */
558b14e6082Sis int
aucc_start_input(void * addr,void * p,int cc,void (* intr)(void *),void * arg)5599382c873Saymeric aucc_start_input(void *addr, void *p, int cc, void (*intr)(void *), void *arg)
560b14e6082Sis {
561b14e6082Sis 
562b14e6082Sis 	return ENXIO; /* no input */
563b14e6082Sis }
564b14e6082Sis 
565b14e6082Sis int
aucc_halt_output(void * addr)5669382c873Saymeric aucc_halt_output(void *addr)
567b14e6082Sis {
56893293b9eSkent 	struct aucc_softc *sc;
56993293b9eSkent 	int i;
570b14e6082Sis 
571b14e6082Sis 	/* XXX only halt, if input is also halted ?? */
57293293b9eSkent 	sc = addr;
5731ffa7b76Swiz 	/* stop DMA, etc */
5747fe30657Sis 	custom.intena = AUCC_ALLINTF;
5757fe30657Sis 	custom.dmacon = AUCC_ALLDMAF;
576b14e6082Sis 	/* mark every busy unit idle */
577b14e6082Sis 	for (i = 0; i < 4; i++) {
578b14e6082Sis 		sc->sc_channel[i].nd_busy = sc->sc_channel[i].nd_mask = 0;
579b14e6082Sis 		channel[i].isaudio = 0;
580b14e6082Sis 		channel[i].play_count = 0;
581b14e6082Sis 	}
582b14e6082Sis 
58393293b9eSkent 	return 0;
584b14e6082Sis }
585b14e6082Sis 
586b14e6082Sis int
aucc_halt_input(void * addr)5879382c873Saymeric aucc_halt_input(void *addr)
588b14e6082Sis {
589b14e6082Sis 
59093293b9eSkent 	/* no input */
591b14e6082Sis 	return ENXIO;
592b14e6082Sis }
593b14e6082Sis 
594b14e6082Sis int
aucc_getdev(void * addr,struct audio_device * retp)5959382c873Saymeric aucc_getdev(void *addr, struct audio_device *retp)
596b14e6082Sis {
59793293b9eSkent 
598b14e6082Sis 	*retp = aucc_device;
599b14e6082Sis 	return 0;
600b14e6082Sis }
601b14e6082Sis 
602b14e6082Sis int
aucc_set_port(void * addr,mixer_ctrl_t * cp)6039382c873Saymeric aucc_set_port(void *addr, mixer_ctrl_t *cp)
604b14e6082Sis {
60593293b9eSkent 	struct aucc_softc *sc;
60693293b9eSkent 	int i,j;
607b14e6082Sis 
608b14e6082Sis 	DPRINTF(("aucc_set_port: port=%d", cp->dev));
60993293b9eSkent 	sc = addr;
610b14e6082Sis 	switch (cp->type) {
611b14e6082Sis 	case AUDIO_MIXER_SET:
612b14e6082Sis 		if (cp->dev != AUCC_CHANNELS)
613b14e6082Sis 			return EINVAL;
614b14e6082Sis 		i = cp->un.mask;
615b14e6082Sis 		if ((i < 1) || (i > 15))
616b14e6082Sis 			return EINVAL;
617946db35cSis 
618b14e6082Sis 		sc->sc_channelmask = i;
619b14e6082Sis 		break;
620b14e6082Sis 
621b14e6082Sis 	case AUDIO_MIXER_VALUE:
622b14e6082Sis 		i = cp->un.value.num_channels;
623b14e6082Sis 		if ((i < 1) || (i > 4))
624b14e6082Sis 			return EINVAL;
625b14e6082Sis 
626c7e3ab13Sis #ifdef __XXXwhatsthat
627b14e6082Sis 		if (cp->dev != AUCC_VOLUME)
628b14e6082Sis 			return EINVAL;
629c7e3ab13Sis #endif
630b14e6082Sis 
631b14e6082Sis 		/* set volume for channel 0..i-1 */
632a90ace97Sis 
633a90ace97Sis 		/* evil workaround for xanim bug, IMO */
634a90ace97Sis 		if ((sc->sc_channels == 1) && (i == 2)) {
635a90ace97Sis 			sc->sc_channel[0].nd_volume =
636a90ace97Sis 			    sc->sc_channel[3].nd_volume =
637a90ace97Sis 			    cp->un.value.level[0] >> 2;
638a90ace97Sis 			sc->sc_channel[1].nd_volume =
639a90ace97Sis 			    sc->sc_channel[2].nd_volume =
640a90ace97Sis 			    cp->un.value.level[1] >> 2;
641a90ace97Sis 		} else if (i > 1) {
642b14e6082Sis 			for (j = 0; j < i; j++)
643c7e3ab13Sis 				sc->sc_channel[j].nd_volume =
644c7e3ab13Sis 				    cp->un.value.level[j] >> 2;
645a90ace97Sis 		} else if (sc->sc_channels > 1)
646c7e3ab13Sis 			for (j = 0; j < sc->sc_channels; j++)
647c7e3ab13Sis 				sc->sc_channel[j].nd_volume =
648c7e3ab13Sis 				    cp->un.value.level[0] >> 2;
649c7e3ab13Sis 		else
650c7e3ab13Sis 			for (j = 0; j < 4; j++)
651c7e3ab13Sis 				sc->sc_channel[j].nd_volume =
652c7e3ab13Sis 				    cp->un.value.level[0] >> 2;
653b14e6082Sis 		break;
654b14e6082Sis 
655b14e6082Sis 	default:
656b14e6082Sis 		return EINVAL;
657b14e6082Sis 		break;
658b14e6082Sis 	}
659b14e6082Sis 	return 0;
660b14e6082Sis }
661b14e6082Sis 
662b14e6082Sis 
663b14e6082Sis int
aucc_get_port(void * addr,mixer_ctrl_t * cp)6649382c873Saymeric aucc_get_port(void *addr, mixer_ctrl_t *cp)
665b14e6082Sis {
66693293b9eSkent 	struct aucc_softc *sc;
66793293b9eSkent 	int i,j;
668b14e6082Sis 
669b14e6082Sis 	DPRINTF(("aucc_get_port: port=%d", cp->dev));
67093293b9eSkent 	sc = addr;
671b14e6082Sis 	switch (cp->type) {
672b14e6082Sis 	case AUDIO_MIXER_SET:
673b14e6082Sis 		if (cp->dev != AUCC_CHANNELS)
674b14e6082Sis 			return EINVAL;
675b14e6082Sis 		cp->un.mask = sc->sc_channelmask;
676b14e6082Sis 		break;
677b14e6082Sis 
678b14e6082Sis 	case AUDIO_MIXER_VALUE:
679b14e6082Sis 		i = cp->un.value.num_channels;
680b14e6082Sis 		if ((i < 1) || (i > 4))
681b14e6082Sis 			return EINVAL;
682b14e6082Sis 
683b14e6082Sis 		for (j = 0; j < i; j++)
684c7e3ab13Sis 			cp->un.value.level[j] =
685c7e3ab13Sis 			    (sc->sc_channel[j].nd_volume << 2) +
686c7e3ab13Sis 			    (sc->sc_channel[j].nd_volume >> 4);
687b14e6082Sis 		break;
688b14e6082Sis 
689b14e6082Sis 	default:
690b14e6082Sis 		return EINVAL;
691b14e6082Sis 	}
692b14e6082Sis 	return 0;
693b14e6082Sis }
694b14e6082Sis 
695b14e6082Sis 
696b14e6082Sis int
aucc_get_props(void * addr)6979382c873Saymeric aucc_get_props(void *addr)
698658656bbSaugustss {
699ede47d01Sisaki 
7007abe87f1Srin 	return AUDIO_PROP_PLAYBACK;
701658656bbSaugustss }
702658656bbSaugustss 
7038a962f23Sjmcneill 
7048a962f23Sjmcneill void
aucc_get_locks(void * opaque,kmutex_t ** intr,kmutex_t ** thread)7058a962f23Sjmcneill aucc_get_locks(void *opaque, kmutex_t **intr, kmutex_t **thread)
7068a962f23Sjmcneill {
7078a962f23Sjmcneill 	struct aucc_softc *sc = opaque;
7088a962f23Sjmcneill 
7098a962f23Sjmcneill 	*intr = &sc->sc_intr_lock;
7108a962f23Sjmcneill 	*thread = &sc->sc_lock;
7118a962f23Sjmcneill }
7128a962f23Sjmcneill 
713658656bbSaugustss int
aucc_query_devinfo(void * addr,register mixer_devinfo_t * dip)7149382c873Saymeric aucc_query_devinfo(void *addr, register mixer_devinfo_t *dip)
715b14e6082Sis {
71693293b9eSkent 	int i;
717b14e6082Sis 
718b14e6082Sis 	switch(dip->index) {
719b14e6082Sis 	case AUCC_CHANNELS:
720b14e6082Sis 		dip->type = AUDIO_MIXER_SET;
721b14e6082Sis 		dip->mixer_class = AUCC_OUTPUT_CLASS;
722b14e6082Sis 		dip->prev = dip->next = AUDIO_MIXER_LAST;
723889cc98cSchristos #define setname(a) strlcpy(dip->label.name, (a), sizeof(dip->label.name))
724889cc98cSchristos 		setname(AudioNspeaker);
725b14e6082Sis 		for (i = 0; i < 16; i++) {
726889cc98cSchristos 			snprintf(dip->un.s.member[i].label.name,
727889cc98cSchristos 			    sizeof(dip->un.s.member[i].label.name),
728b14e6082Sis 			    "channelmask%d", i);
729b14e6082Sis 			dip->un.s.member[i].mask = i;
730b14e6082Sis 		}
731b14e6082Sis 		dip->un.s.num_mem = 16;
732b14e6082Sis 		break;
733b14e6082Sis 
734b14e6082Sis 	case AUCC_VOLUME:
735b14e6082Sis 		dip->type = AUDIO_MIXER_VALUE;
736b14e6082Sis 		dip->mixer_class = AUCC_OUTPUT_CLASS;
737b14e6082Sis 		dip->prev = dip->next = AUDIO_MIXER_LAST;
738889cc98cSchristos 		setname(AudioNmaster);
739b14e6082Sis 		dip->un.v.num_channels = 4;
740b14e6082Sis 		strcpy(dip->un.v.units.name, AudioNvolume);
741b14e6082Sis 		break;
742b14e6082Sis 
743b14e6082Sis 	case AUCC_OUTPUT_CLASS:
744b14e6082Sis 		dip->type = AUDIO_MIXER_CLASS;
745b14e6082Sis 		dip->mixer_class = AUCC_OUTPUT_CLASS;
746b14e6082Sis 		dip->next = dip->prev = AUDIO_MIXER_LAST;
747889cc98cSchristos 		setname(AudioCoutputs);
748b14e6082Sis 		break;
749e7029fc0Saugustss 
750b14e6082Sis 	default:
751b14e6082Sis 		return ENXIO;
752b14e6082Sis 	}
753b14e6082Sis 
754b14e6082Sis 	DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
755b14e6082Sis 
75693293b9eSkent 	return 0;
757b14e6082Sis }
758b14e6082Sis 
759b14e6082Sis /* audio int handler */
760b14e6082Sis void
aucc_inthdl(int ch)761b14e6082Sis aucc_inthdl(int ch)
762b14e6082Sis {
76393293b9eSkent 	int i;
76493293b9eSkent 	int mask;
765b14e6082Sis 
7668a962f23Sjmcneill 	mutex_spin_enter(&aucc->sc_intr_lock);
76793293b9eSkent 	mask = aucc->sc_channel[ch].nd_mask;
76893293b9eSkent 	/*
76993293b9eSkent 	 * for all channels in this maskgroup:
77093293b9eSkent 	 * disable DMA, int
77193293b9eSkent 	 * mark idle
77293293b9eSkent 	 */
773b14e6082Sis 	DPRINTF(("inthandler called, channel %d, mask 0x%x\n", ch, mask));
774b14e6082Sis 
7757fe30657Sis 	custom.intreq = mask << INTB_AUD0; /* clear request */
776946db35cSis 	/*
777946db35cSis 	 * XXX: maybe we can leave ints and/or DMA on,
778946db35cSis 	 * if another sample has to be played?
779946db35cSis 	 */
7807fe30657Sis 	custom.intena = mask << INTB_AUD0;
781b14e6082Sis 	/*
782b14e6082Sis 	 * XXX custom.dmacon=mask; NO!!!
783b14e6082Sis 	 */
784b14e6082Sis 	for (i = 0; i < 4; i++) {
785b14e6082Sis 		if (masks2[i] && mask) {
786b14e6082Sis 			DPRINTF(("marking channel %d idle\n",i));
787b14e6082Sis 			aucc->sc_channel[i].nd_busy = 0;
788b14e6082Sis 			aucc->sc_channel[i].nd_mask = 0;
789b14e6082Sis 			channel[i].isaudio = channel[i].play_count = 0;
790b14e6082Sis 		}
791b14e6082Sis 	}
792b14e6082Sis 
793b14e6082Sis 	/* call handler */
794b14e6082Sis 	if (aucc->sc_channel[ch].nd_intr) {
795b14e6082Sis 		DPRINTF(("calling %p\n",aucc->sc_channel[ch].nd_intr));
796946db35cSis 		(*(aucc->sc_channel[ch].nd_intr))
797946db35cSis 		    (aucc->sc_channel[ch].nd_intrdata);
79893293b9eSkent 	} else
799946db35cSis 		DPRINTF(("zero int handler\n"));
8008a962f23Sjmcneill 	mutex_spin_exit(&aucc->sc_intr_lock);
801b14e6082Sis 	DPRINTF(("ints done\n"));
802b14e6082Sis }
803b14e6082Sis 
804b14e6082Sis /* transform frequency to period, adjust bounds */
805b14e6082Sis static u_int
freqtoper(u_int freq)8069382c873Saymeric freqtoper(u_int freq)
8079382c873Saymeric {
80893293b9eSkent 	u_int per;
809b14e6082Sis 
81093293b9eSkent 	per = eclockfreq * 5 / freq;
811b14e6082Sis 	if (per < 124)
812b14e6082Sis 		per = 124;   /* must have at least 124 ticks between samples */
813b14e6082Sis 
814b14e6082Sis 	return per;
815b14e6082Sis }
816b14e6082Sis 
817b14e6082Sis /* transform period to frequency */
818b14e6082Sis static u_int
pertofreq(u_int per)8199382c873Saymeric pertofreq(u_int per)
8209382c873Saymeric {
821b14e6082Sis 
82293293b9eSkent 	return eclockfreq * 5 / per;
823b14e6082Sis }
824b14e6082Sis 
825946db35cSis 
826946db35cSis /* 14bit output */
827946db35cSis static void
aucc_decode_slinear16_1ch(u_char ** dmap,u_char * p,int i)8289382c873Saymeric aucc_decode_slinear16_1ch(u_char **dmap, u_char *p, int i)
829946db35cSis {
83093293b9eSkent 	u_char *ch0;
83193293b9eSkent 	u_char *ch3;
832946db35cSis 
83393293b9eSkent 	ch0 = dmap[0];
83493293b9eSkent 	ch3 = dmap[1];		/* XXX should be 3 */
835946db35cSis 	while (i--) {
836946db35cSis 		*ch0++ = *p++;
837946db35cSis 		*ch3++ = *p++ >> 2;
838946db35cSis 	}
839946db35cSis }
840946db35cSis 
841946db35cSis /* 14bit stereo output */
842946db35cSis static void
aucc_decode_slinear16_2ch(u_char ** dmap,u_char * p,int i)8439382c873Saymeric aucc_decode_slinear16_2ch(u_char **dmap, u_char *p, int i)
844946db35cSis {
84593293b9eSkent 	u_char *ch0;
84693293b9eSkent 	u_char *ch1;
84793293b9eSkent 	u_char *ch2;
84893293b9eSkent 	u_char *ch3;
849946db35cSis 
85093293b9eSkent 	ch0 = dmap[0];
85193293b9eSkent 	ch1 = dmap[1];
85293293b9eSkent 	ch2 = dmap[2];
85393293b9eSkent 	ch3 = dmap[3];
854946db35cSis 	while (i--) {
855946db35cSis 		*ch0++ = *p++;
856946db35cSis 		*ch3++ = *p++ >> 2;
857946db35cSis 		*ch1++ = *p++;
858946db35cSis 		*ch2++ = *p++ >> 2;
859946db35cSis 	}
860946db35cSis }
861946db35cSis 
862946db35cSis static void
aucc_decode_slinear16_3ch(u_char ** dmap,u_char * p,int i)8639382c873Saymeric aucc_decode_slinear16_3ch(u_char **dmap, u_char *p, int i)
864946db35cSis {
86593293b9eSkent 	u_char *ch0;
86693293b9eSkent 	u_char *ch1;
86793293b9eSkent 	u_char *ch2;
868946db35cSis 
86993293b9eSkent 	ch0 = dmap[0];
87093293b9eSkent 	ch1 = dmap[1];
87193293b9eSkent 	ch2 = dmap[2];
872946db35cSis 	while (i--) {
873946db35cSis 		*ch0++ = *p++; p++;
874946db35cSis 		*ch1++ = *p++; p++;
875946db35cSis 		*ch2++ = *p++; p++;
876946db35cSis 	}
877946db35cSis }
878946db35cSis 
879946db35cSis static void
aucc_decode_slinear16_4ch(u_char ** dmap,u_char * p,int i)8809382c873Saymeric aucc_decode_slinear16_4ch(u_char **dmap, u_char *p, int i)
881946db35cSis {
88293293b9eSkent 	u_char *ch0;
88393293b9eSkent 	u_char *ch1;
88493293b9eSkent 	u_char *ch2;
88593293b9eSkent 	u_char *ch3;
886946db35cSis 
88793293b9eSkent 	ch0 = dmap[0];
88893293b9eSkent 	ch1 = dmap[1];
88993293b9eSkent 	ch2 = dmap[2];
89093293b9eSkent 	ch3 = dmap[3];
891946db35cSis 	while (i--) {
892946db35cSis 		*ch0++ = *p++; p++;
893946db35cSis 		*ch1++ = *p++; p++;
894946db35cSis 		*ch2++ = *p++; p++;
895946db35cSis 		*ch3++ = *p++; p++;
896946db35cSis 	}
897946db35cSis }
898946db35cSis 
899b14e6082Sis #endif /* NAUCC > 0 */
900