xref: /netbsd-src/sys/arch/amiga/dev/aucc.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: aucc.c,v 1.40 2006/03/08 23:46:22 lukem 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  * - mu-law -> 14bit conversion
39  * - channel allocation is wrong for 14bit mono
40  * - convert the... err... conversion routines to 68k asm for best performance
41  * 	XXX: NO. aucc audio is limited by chipmem speed, anyway. You dont
42  *	want to make life difficult for amigappc work.
43  *		-is
44  *
45  * - rely on auconv.c routines for mu-law/A-law conversions
46  * - perhaps use a calibration table for better 14bit output
47  * - set 31 kHz AGA video mode to allow 44.1 kHz even if grfcc is missing
48  *	in the kernel
49  * - 14bit output requires maximum volume
50  */
51 
52 #include "aucc.h"
53 #if NAUCC > 0
54 
55 #include <sys/cdefs.h>
56 __KERNEL_RCSID(0, "$NetBSD: aucc.c,v 1.40 2006/03/08 23:46:22 lukem Exp $");
57 
58 #include <sys/param.h>
59 #include <sys/systm.h>
60 #include <sys/errno.h>
61 #include <sys/ioctl.h>
62 #include <sys/device.h>
63 #include <sys/proc.h>
64 #include <machine/cpu.h>
65 
66 #include <sys/audioio.h>
67 #include <dev/audio_if.h>
68 #include <amiga/amiga/cc.h>
69 #include <amiga/amiga/custom.h>
70 #include <amiga/amiga/device.h>
71 #include <amiga/dev/auccvar.h>
72 
73 #include "opt_lev6_defer.h"
74 
75 
76 #ifdef LEV6_DEFER
77 #define AUCC_MAXINT 3
78 #define AUCC_ALLINTF (INTF_AUD0|INTF_AUD1|INTF_AUD2)
79 #else
80 #define AUCC_MAXINT 4
81 #define AUCC_ALLINTF (INTF_AUD0|INTF_AUD1|INTF_AUD2|INTF_AUD3)
82 #endif
83 /* this unconditionally; we may use AUD3 as slave channel with LEV6_DEFER */
84 #define AUCC_ALLDMAF (DMAF_AUD0|DMAF_AUD1|DMAF_AUD2|DMAF_AUD3)
85 
86 #ifdef AUDIO_DEBUG
87 /*extern printf(const char *,...);*/
88 int     auccdebug = 1;
89 #define DPRINTF(x)      if (auccdebug) printf x
90 #else
91 #define DPRINTF(x)
92 #endif
93 
94 #ifdef splaudio
95 #undef splaudio
96 #endif
97 
98 #define splaudio() spl4();
99 
100 /* clock frequency.. */
101 extern int eclockfreq;
102 
103 
104 /* hw audio ch */
105 extern struct audio_channel channel[4];
106 
107 
108 /*
109  * Software state.
110  */
111 struct aucc_softc {
112 	struct	device sc_dev;		/* base device */
113 
114 	int	sc_open;		/* single use device */
115 	aucc_data_t sc_channel[4];	/* per channel freq, ... */
116 	u_int	sc_encoding;		/* encoding AUDIO_ENCODING_.*/
117 	int	sc_channels;		/* # of channels used */
118 	int	sc_precision;		/* 8 or 16 bits */
119 	int	sc_14bit;		/* 14bit output enabled */
120 
121 	int	sc_intrcnt;		/* interrupt count */
122 	int	sc_channelmask;		/* which channels are used ? */
123 	void (*sc_decodefunc)(u_char **, u_char *, int);
124 				/* pointer to format conversion routine */
125 };
126 
127 /* interrupt interfaces */
128 void aucc_inthdl(int);
129 
130 /* forward declarations */
131 static int init_aucc(struct aucc_softc *);
132 static u_int freqtoper(u_int);
133 static u_int pertofreq(u_int);
134 
135 /* autoconfiguration driver */
136 void	auccattach(struct device *, struct device *, void *);
137 int	auccmatch(struct device *, struct cfdata *, void *);
138 
139 CFATTACH_DECL(aucc, sizeof(struct aucc_softc),
140     auccmatch, auccattach, NULL, NULL);
141 
142 struct audio_device aucc_device = {
143 	"Amiga-audio",
144 	"2.0",
145 	"aucc"
146 };
147 
148 
149 struct aucc_softc *aucc = NULL;
150 
151 
152 unsigned char mulaw_to_lin[] = {
153 	0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
154 	0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
155 	0xc1, 0xc3, 0xc5, 0xc7, 0xc9, 0xcb, 0xcd, 0xcf,
156 	0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf,
157 	0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
158 	0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0,
159 	0xf0, 0xf1, 0xf1, 0xf2, 0xf2, 0xf3, 0xf3, 0xf4,
160 	0xf4, 0xf5, 0xf5, 0xf6, 0xf6, 0xf7, 0xf7, 0xf8,
161 	0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa,
162 	0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc,
163 	0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd,
164 	0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe,
165 	0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
166 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
167 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
168 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
169 	0x7d, 0x79, 0x75, 0x71, 0x6d, 0x69, 0x65, 0x61,
170 	0x5d, 0x59, 0x55, 0x51, 0x4d, 0x49, 0x45, 0x41,
171 	0x3e, 0x3c, 0x3a, 0x38, 0x36, 0x34, 0x32, 0x30,
172 	0x2e, 0x2c, 0x2a, 0x28, 0x26, 0x24, 0x22, 0x20,
173 	0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17,
174 	0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f,
175 	0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b,
176 	0x0b, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x07,
177 	0x07, 0x07, 0x06, 0x06, 0x06, 0x06, 0x05, 0x05,
178 	0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
179 	0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02,
180 	0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
181 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
182 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
183 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
184 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
185 };
186 
187 /*
188  * Define our interface to the higher level audio driver.
189  */
190 int	aucc_open(void *, int);
191 void	aucc_close(void *);
192 int	aucc_set_out_sr(void *, u_int);
193 int	aucc_query_encoding(void *, struct audio_encoding *);
194 int	aucc_round_blocksize(void *, int, int, const audio_params_t *);
195 int	aucc_commit_settings(void *);
196 int	aucc_start_output(void *, void *, int, void (*)(void *), void *);
197 int	aucc_start_input(void *, void *, int, void (*)(void *), void *);
198 int	aucc_halt_output(void *);
199 int	aucc_halt_input(void *);
200 int	aucc_getdev(void *, struct audio_device *);
201 int	aucc_set_port(void *, mixer_ctrl_t *);
202 int	aucc_get_port(void *, mixer_ctrl_t *);
203 int	aucc_query_devinfo(void *, mixer_devinfo_t *);
204 void	aucc_encode(int, int, int, int, u_char *, u_short **);
205 int	aucc_set_params(void *, int, int, audio_params_t *, audio_params_t *,
206 			stream_filter_list_t *, stream_filter_list_t *);
207 int	aucc_get_props(void *);
208 
209 
210 static void aucc_decode_slinear8_1ch(u_char **, u_char *, int);
211 static void aucc_decode_slinear8_2ch(u_char **, u_char *, int);
212 static void aucc_decode_slinear8_3ch(u_char **, u_char *, int);
213 static void aucc_decode_slinear8_4ch(u_char **, u_char *, int);
214 
215 static void aucc_decode_ulinear8_1ch(u_char **, u_char *, int);
216 static void aucc_decode_ulinear8_2ch(u_char **, u_char *, int);
217 static void aucc_decode_ulinear8_3ch(u_char **, u_char *, int);
218 static void aucc_decode_ulinear8_4ch(u_char **, u_char *, int);
219 
220 static void aucc_decode_mulaw_1ch(u_char **, u_char *, int);
221 static void aucc_decode_mulaw_2ch(u_char **, u_char *, int);
222 static void aucc_decode_mulaw_3ch(u_char **, u_char *, int);
223 static void aucc_decode_mulaw_4ch(u_char **, u_char *, int);
224 
225 static void aucc_decode_slinear16_1ch(u_char **, u_char *, int);
226 static void aucc_decode_slinear16_2ch(u_char **, u_char *, int);
227 static void aucc_decode_slinear16_3ch(u_char **, u_char *, int);
228 static void aucc_decode_slinear16_4ch(u_char **, u_char *, int);
229 
230 static void aucc_decode_slinear16sw_1ch(u_char **, u_char *, int);
231 static void aucc_decode_slinear16sw_2ch(u_char **, u_char *, int);
232 static void aucc_decode_slinear16sw_3ch(u_char **, u_char *, int);
233 static void aucc_decode_slinear16sw_4ch(u_char **, u_char *, int);
234 
235 
236 
237 const struct audio_hw_if sa_hw_if = {
238 	aucc_open,
239 	aucc_close,
240 	NULL,
241 	aucc_query_encoding,
242 	aucc_set_params,
243 	aucc_round_blocksize,
244 	aucc_commit_settings,
245 	NULL,
246 	NULL,
247 	aucc_start_output,
248 	aucc_start_input,
249 	aucc_halt_output,
250 	aucc_halt_input,
251 	NULL,
252 	aucc_getdev,
253 	NULL,
254 	aucc_set_port,
255 	aucc_get_port,
256 	aucc_query_devinfo,
257 	NULL,
258 	NULL,
259 	NULL,
260 	NULL,
261 	aucc_get_props,
262 	NULL,
263 	NULL,
264 	NULL,
265 };
266 
267 /* autoconfig routines */
268 
269 int
270 auccmatch(struct device *pdp, struct cfdata *cfp, void *aux)
271 {
272 	static int aucc_matched = 0;
273 
274 	if (!matchname((char *)aux, "aucc") ||
275 #ifdef DRACO
276 	    is_draco() ||
277 #endif
278 	    aucc_matched)
279 		return 0;
280 
281 	aucc_matched = 1;
282 	return 1;
283 }
284 
285 /*
286  * Audio chip found.
287  */
288 void
289 auccattach(struct device *parent, struct device *self, void *args)
290 {
291 	struct aucc_softc *sc;
292 	int i;
293 
294 	sc = (struct aucc_softc *)self;
295 	printf("\n");
296 
297 	if ((i=init_aucc(sc))) {
298 		printf("audio: no chipmem\n");
299 		return;
300 	}
301 
302 	audio_attach_mi(&sa_hw_if, sc, &sc->sc_dev);
303 }
304 
305 
306 static int
307 init_aucc(struct aucc_softc *sc)
308 {
309 	int i, err;
310 
311 	err = 0;
312 	/* init values per channel */
313 	for (i = 0; i < 4; i++) {
314 		sc->sc_channel[i].nd_freq = 8000;
315 		sc->sc_channel[i].nd_per = freqtoper(8000);
316 		sc->sc_channel[i].nd_busy = 0;
317 		sc->sc_channel[i].nd_dma = alloc_chipmem(AUDIO_BUF_SIZE*2);
318 		if (sc->sc_channel[i].nd_dma == NULL)
319 			err = 1;
320 		sc->sc_channel[i].nd_dmalength = 0;
321 		sc->sc_channel[i].nd_volume = 64;
322 		sc->sc_channel[i].nd_intr = NULL;
323 		sc->sc_channel[i].nd_intrdata = NULL;
324 		sc->sc_channel[i].nd_doublebuf = 0;
325 		DPRINTF(("DMA buffer for channel %d is %p\n", i,
326 		    sc->sc_channel[i].nd_dma));
327 	}
328 
329 	if (err) {
330 		for (i = 0; i < 4; i++)
331 			if (sc->sc_channel[i].nd_dma)
332 				free_chipmem(sc->sc_channel[i].nd_dma);
333 	}
334 
335 	sc->sc_channels = 1;
336 	sc->sc_channelmask = 0xf;
337 	sc->sc_precision = 8;
338 	sc->sc_14bit = 0;
339 	sc->sc_encoding = AUDIO_ENCODING_ULAW;
340 	sc->sc_decodefunc = aucc_decode_mulaw_1ch;
341 
342 	/* clear interrupts and DMA: */
343 	custom.intena = AUCC_ALLINTF;
344 	custom.dmacon = AUCC_ALLDMAF;
345 
346 	return err;
347 }
348 
349 int
350 aucc_open(void *addr, int flags)
351 {
352 	struct aucc_softc *sc;
353 	int i;
354 
355 	sc = addr;
356 	DPRINTF(("sa_open: unit %p\n",sc));
357 
358 	if (sc->sc_open)
359 		return EBUSY;
360 	sc->sc_open = 1;
361 	for (i = 0; i < AUCC_MAXINT; i++) {
362 		sc->sc_channel[i].nd_intr = NULL;
363 		sc->sc_channel[i].nd_intrdata = NULL;
364 	}
365 	aucc = sc;
366 	sc->sc_channelmask = 0xf;
367 
368 	DPRINTF(("saopen: ok -> sc=%p\n",sc));
369 
370 	return 0;
371 }
372 
373 void
374 aucc_close(void *addr)
375 {
376 	struct aucc_softc *sc;
377 
378 	sc = addr;
379 	DPRINTF(("sa_close: sc=%p\n", sc));
380 	/*
381 	 * halt i/o, clear open flag, and done.
382 	 */
383 	aucc_halt_output(sc);
384 	sc->sc_open = 0;
385 
386 	DPRINTF(("sa_close: closed.\n"));
387 }
388 
389 int
390 aucc_set_out_sr(void *addr, u_int sr)
391 {
392 	struct aucc_softc *sc;
393 	u_long per;
394 	int i;
395 
396 	sc = addr;
397 	per = freqtoper(sr);
398 	if (per > 0xffff)
399 		return EINVAL;
400 	sr = pertofreq(per);
401 
402 	for (i = 0; i < 4; i++) {
403 		sc->sc_channel[i].nd_freq = sr;
404 		sc->sc_channel[i].nd_per = per;
405 	}
406 
407 	return 0;
408 }
409 
410 int
411 aucc_query_encoding(void *addr, struct audio_encoding *fp)
412 {
413 
414 	switch (fp->index) {
415 	case 0:
416 		strcpy(fp->name, AudioEslinear);
417 		fp->encoding = AUDIO_ENCODING_SLINEAR;
418 		fp->precision = 8;
419 		fp->flags = 0;
420 		break;
421 	case 1:
422 		strcpy(fp->name, AudioEmulaw);
423 		fp->encoding = AUDIO_ENCODING_ULAW;
424 		fp->precision = 8;
425 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
426 		break;
427 
428 	case 2:
429 		strcpy(fp->name, AudioEulinear);
430 		fp->encoding = AUDIO_ENCODING_ULINEAR;
431 		fp->precision = 8;
432 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
433 		break;
434 
435 	case 3:
436 		strcpy(fp->name, AudioEslinear);
437 		fp->encoding = AUDIO_ENCODING_SLINEAR;
438 		fp->precision = 16;
439 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
440 		break;
441 
442 	case 4:
443 		strcpy(fp->name, AudioEslinear_be);
444 		fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
445 		fp->precision = 16;
446 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
447 		break;
448 
449 	case 5:
450 		strcpy(fp->name, AudioEslinear_le);
451 		fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
452 		fp->precision = 16;
453 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
454 		break;
455 
456 	default:
457 		return EINVAL;
458 		/*NOTREACHED*/
459 	}
460 	return 0;
461 }
462 
463 int
464 aucc_set_params(void *addr, int setmode, int usemode,
465 		audio_params_t *p, audio_params_t *r,
466 		stream_filter_list_t *pfil, stream_filter_list_t *rfil)
467 {
468 	struct aucc_softc *sc;
469 
470 	sc = addr;
471 	/* if (setmode & AUMODE_RECORD)
472 		return 0 ENXIO*/;
473 
474 #ifdef AUCCDEBUG
475 	printf("aucc_set_params(setmode 0x%x, usemode 0x%x, "
476 	       "enc %u, bits %u, chn %u, sr %u)\n", setmode, usemode,
477 	       p->encoding, p->precision, p->channels, p->sample_rate);
478 #endif
479 
480 	switch (p->precision) {
481 	case 8:
482 		switch (p->encoding) {
483 		case AUDIO_ENCODING_ULAW:
484 			switch (p->channels) {
485 			case 1:
486 				sc->sc_decodefunc = aucc_decode_mulaw_1ch;
487 				break;
488 			case 2:
489 				sc->sc_decodefunc = aucc_decode_mulaw_2ch;
490 				break;
491 			case 3:
492 				sc->sc_decodefunc = aucc_decode_mulaw_3ch;
493 				break;
494 			case 4:
495 				sc->sc_decodefunc = aucc_decode_mulaw_4ch;
496 				break;
497 			default:
498 				return EINVAL;
499 			}
500 			break;
501 
502 		case AUDIO_ENCODING_SLINEAR:
503 		case AUDIO_ENCODING_SLINEAR_BE:
504 		case AUDIO_ENCODING_SLINEAR_LE:
505 			switch (p->channels) {
506 			case 1:
507 				sc->sc_decodefunc = aucc_decode_slinear8_1ch;
508 				break;
509 			case 2:
510 				sc->sc_decodefunc = aucc_decode_slinear8_2ch;
511 				break;
512 			case 3:
513 				sc->sc_decodefunc = aucc_decode_slinear8_3ch;
514 				break;
515 			case 4:
516 				sc->sc_decodefunc = aucc_decode_slinear8_4ch;
517 				break;
518 			default:
519 				return EINVAL;
520 			}
521 			break;
522 
523 		case AUDIO_ENCODING_ULINEAR:
524 		case AUDIO_ENCODING_ULINEAR_BE:
525 		case AUDIO_ENCODING_ULINEAR_LE:
526 			switch (p->channels) {
527 			case 1:
528 				sc->sc_decodefunc = aucc_decode_ulinear8_1ch;
529 				break;
530 			case 2:
531 				sc->sc_decodefunc = aucc_decode_ulinear8_2ch;
532 				break;
533 			case 3:
534 				sc->sc_decodefunc = aucc_decode_ulinear8_3ch;
535 				break;
536 			case 4:
537 				sc->sc_decodefunc = aucc_decode_ulinear8_4ch;
538 				break;
539 			default:
540 				return EINVAL;
541 			}
542 			break;
543 
544 		default:
545 			return EINVAL;
546 		}
547 		break;
548 
549 	case 16:
550 		switch (p->encoding) {
551 #if BYTE_ORDER == BIG_ENDIAN
552 		case AUDIO_ENCODING_SLINEAR:
553 #endif
554 		case AUDIO_ENCODING_SLINEAR_BE:
555 			switch (p->channels) {
556 			case 1:
557 				sc->sc_decodefunc = aucc_decode_slinear16_1ch;
558 				break;
559 
560 			case 2:
561 				sc->sc_decodefunc = aucc_decode_slinear16_2ch;
562 				break;
563 			case 3:
564 				sc->sc_decodefunc = aucc_decode_slinear16_3ch;
565 				break;
566 			case 4:
567 				sc->sc_decodefunc = aucc_decode_slinear16_4ch;
568 				break;
569 			default:
570 				return EINVAL;
571 			}
572 			break;
573 
574 #if BYTE_ORDER == LITTLE_ENDIAN
575 		case AUDIO_ENCODING_SLINEAR:
576 #endif
577 		case AUDIO_ENCODING_SLINEAR_LE:
578 			switch (p->channels) {
579 			case 1:
580 				sc->sc_decodefunc = aucc_decode_slinear16sw_1ch;
581 				break;
582 			case 2:
583 				sc->sc_decodefunc = aucc_decode_slinear16sw_2ch;
584 				break;
585 			case 3:
586 				sc->sc_decodefunc = aucc_decode_slinear16sw_3ch;
587 				break;
588 			case 4:
589 				sc->sc_decodefunc = aucc_decode_slinear16sw_4ch;
590 				break;
591 			default:
592 				return EINVAL;
593 			}
594 			break;
595 
596 		default:
597 			return EINVAL;
598 		}
599 		break;
600 
601 	default:
602 		return EINVAL;
603 	}
604 
605 	sc->sc_encoding = p->encoding;
606 	sc->sc_precision = p->precision;
607 	sc->sc_14bit = ((p->precision == 16) && (p->channels <= 2));
608 	sc->sc_channels = sc->sc_14bit ? (p->channels * 2) : p->channels;
609 
610 	return aucc_set_out_sr(addr, p->sample_rate);
611 }
612 
613 int
614 aucc_round_blocksize(void *addr, int blk,
615 		     int mode, const audio_params_t *param)
616 {
617 
618 	/* round up to even size */
619 	return blk > AUDIO_BUF_SIZE ? AUDIO_BUF_SIZE : blk;
620 }
621 
622 int
623 aucc_commit_settings(void *addr)
624 {
625 	struct aucc_softc *sc;
626 	int i;
627 
628 	DPRINTF(("sa_commit.\n"));
629 
630 	sc = addr;
631 	for (i = 0; i < 4; i++) {
632 		custom.aud[i].vol = sc->sc_channel[i].nd_volume;
633 		custom.aud[i].per = sc->sc_channel[i].nd_per;
634 	}
635 
636 	DPRINTF(("commit done\n"));
637 
638 	return 0;
639 }
640 
641 static int masks[4] = {1,3,7,15}; /* masks for n first channels */
642 static int masks2[4] = {1,2,4,8};
643 
644 int
645 aucc_start_output(void *addr, void *p, int cc, void (*intr)(void *), void *arg)
646 {
647 	struct aucc_softc *sc;
648 	int mask;
649 	int i, j, k, len;
650 	u_char *dmap[4];
651 
652 
653 	sc = addr;
654 	mask = sc->sc_channelmask;
655 
656 	dmap[0] = dmap[1] = dmap[2] = dmap[3] = NULL;
657 
658 	DPRINTF(("sa_start_output: cc=%d %p (%p)\n", cc, intr, arg));
659 
660 	if (sc->sc_channels > 1)
661 		mask &= masks[sc->sc_channels - 1];
662 		/* we use first sc_channels channels */
663 	if (mask == 0) /* active and used channels are disjoint */
664 		return EINVAL;
665 
666 	for (i = 0; i < 4; i++) {
667 		/* channels available ? */
668 		if ((masks2[i] & mask) && (sc->sc_channel[i].nd_busy))
669 			return EBUSY; /* channel is busy */
670 		if (channel[i].isaudio == -1)
671 			return EBUSY; /* system uses them */
672 	}
673 
674 	/* enable interrupt on 1st channel */
675 	for (i = j = 0; i < AUCC_MAXINT; i++) {
676 		if (masks2[i] & mask) {
677 			DPRINTF(("first channel is %d\n",i));
678 			j = i;
679 			sc->sc_channel[i].nd_intr = intr;
680 			sc->sc_channel[i].nd_intrdata = arg;
681 			break;
682 		}
683 	}
684 
685 	DPRINTF(("dmap is %p %p %p %p, mask=0x%x\n", dmap[0], dmap[1],
686 		 dmap[2], dmap[3], mask));
687 
688 	/* disable ints, DMA for channels, until all parameters set */
689 	/* XXX dont disable DMA! custom.dmacon=mask;*/
690 	custom.intreq = mask << INTB_AUD0;
691 	custom.intena = mask << INTB_AUD0;
692 
693 	/* copy data to DMA buffer */
694 
695 	if (sc->sc_channels == 1) {
696 		dmap[0] =
697 		dmap[1] =
698 		dmap[2] =
699 		dmap[3] = (u_char *)sc->sc_channel[j].nd_dma;
700 	} else {
701 		for (k = 0; k < 4; k++) {
702 			if (masks2[k+j] & mask)
703 				dmap[k] = (u_char *)sc->sc_channel[k+j].nd_dma;
704 		}
705 	}
706 
707 	sc->sc_channel[j].nd_doublebuf ^= 1;
708 	if (sc->sc_channel[j].nd_doublebuf) {
709 		dmap[0] += AUDIO_BUF_SIZE;
710 		dmap[1] += AUDIO_BUF_SIZE;
711 		dmap[2] += AUDIO_BUF_SIZE;
712 		dmap[3] += AUDIO_BUF_SIZE;
713 	}
714 
715 	/*
716 	 * compute output length in bytes per channel.
717 	 * divide by two only for 16bit->8bit conversion.
718 	 */
719 	len = cc / sc->sc_channels;
720 	if (!sc->sc_14bit && (sc->sc_precision == 16))
721 		len /= 2;
722 
723 	/* call audio decoding routine */
724 	sc->sc_decodefunc (dmap, (u_char *)p, len);
725 
726 	/* DMA buffers: we use same buffer 4 all channels
727 	 * write DMA location and length
728 	 */
729 	for (i = k = 0; i < 4; i++) {
730 		if (masks2[i] & mask) {
731 			DPRINTF(("turning channel %d on\n",i));
732 			/* sc->sc_channel[i].nd_busy=1; */
733 			channel[i].isaudio = 1;
734 			channel[i].play_count = 1;
735 			channel[i].handler = NULL;
736 			custom.aud[i].per = sc->sc_channel[i].nd_per;
737 			if (sc->sc_14bit && (i > 1))
738 				custom.aud[i].vol = 1;
739 			else
740 				custom.aud[i].vol = sc->sc_channel[i].nd_volume;
741 			custom.aud[i].lc = PREP_DMA_MEM(dmap[k++]);
742 			custom.aud[i].len = len / 2;
743 			sc->sc_channel[i].nd_mask = mask;
744 			DPRINTF(("per is %d, vol is %d, len is %d\n",\
745 			    sc->sc_channel[i].nd_per,
746 			    sc->sc_channel[i].nd_volume, len));
747 		}
748 	}
749 
750 	channel[j].handler = aucc_inthdl;
751 
752 	/* enable ints */
753 	custom.intena = INTF_SETCLR | INTF_INTEN | (masks2[j] << INTB_AUD0);
754 
755 	DPRINTF(("enabled ints: 0x%x\n", (masks2[j] << INTB_AUD0)));
756 
757 	/* enable DMA */
758 	custom.dmacon = DMAF_SETCLR | DMAF_MASTER | mask;
759 
760 	DPRINTF(("enabled DMA, mask=0x%x\n",mask));
761 
762 	return 0;
763 }
764 
765 /* ARGSUSED */
766 int
767 aucc_start_input(void *addr, void *p, int cc, void (*intr)(void *), void *arg)
768 {
769 
770 	return ENXIO; /* no input */
771 }
772 
773 int
774 aucc_halt_output(void *addr)
775 {
776 	struct aucc_softc *sc;
777 	int i;
778 
779 	/* XXX only halt, if input is also halted ?? */
780 	sc = addr;
781 	/* stop DMA, etc */
782 	custom.intena = AUCC_ALLINTF;
783 	custom.dmacon = AUCC_ALLDMAF;
784 	/* mark every busy unit idle */
785 	for (i = 0; i < 4; i++) {
786 		sc->sc_channel[i].nd_busy = sc->sc_channel[i].nd_mask = 0;
787 		channel[i].isaudio = 0;
788 		channel[i].play_count = 0;
789 	}
790 
791 	return 0;
792 }
793 
794 int
795 aucc_halt_input(void *addr)
796 {
797 
798 	/* no input */
799 	return ENXIO;
800 }
801 
802 int
803 aucc_getdev(void *addr, struct audio_device *retp)
804 {
805 
806 	*retp = aucc_device;
807 	return 0;
808 }
809 
810 int
811 aucc_set_port(void *addr, mixer_ctrl_t *cp)
812 {
813 	struct aucc_softc *sc;
814 	int i,j;
815 
816 	DPRINTF(("aucc_set_port: port=%d", cp->dev));
817 	sc = addr;
818 	switch (cp->type) {
819 	case AUDIO_MIXER_SET:
820 		if (cp->dev != AUCC_CHANNELS)
821 			return EINVAL;
822 		i = cp->un.mask;
823 		if ((i < 1) || (i > 15))
824 			return EINVAL;
825 
826 		sc->sc_channelmask = i;
827 		break;
828 
829 	case AUDIO_MIXER_VALUE:
830 		i = cp->un.value.num_channels;
831 		if ((i < 1) || (i > 4))
832 			return EINVAL;
833 
834 #ifdef __XXXwhatsthat
835 		if (cp->dev != AUCC_VOLUME)
836 			return EINVAL;
837 #endif
838 
839 		/* set volume for channel 0..i-1 */
840 
841 		/* evil workaround for xanim bug, IMO */
842 		if ((sc->sc_channels == 1) && (i == 2)) {
843 			sc->sc_channel[0].nd_volume =
844 			    sc->sc_channel[3].nd_volume =
845 			    cp->un.value.level[0] >> 2;
846 			sc->sc_channel[1].nd_volume =
847 			    sc->sc_channel[2].nd_volume =
848 			    cp->un.value.level[1] >> 2;
849 		} else if (i > 1) {
850 			for (j = 0; j < i; j++)
851 				sc->sc_channel[j].nd_volume =
852 				    cp->un.value.level[j] >> 2;
853 		} else if (sc->sc_channels > 1)
854 			for (j = 0; j < sc->sc_channels; j++)
855 				sc->sc_channel[j].nd_volume =
856 				    cp->un.value.level[0] >> 2;
857 		else
858 			for (j = 0; j < 4; j++)
859 				sc->sc_channel[j].nd_volume =
860 				    cp->un.value.level[0] >> 2;
861 		break;
862 
863 	default:
864 		return EINVAL;
865 		break;
866 	}
867 	return 0;
868 }
869 
870 
871 int
872 aucc_get_port(void *addr, mixer_ctrl_t *cp)
873 {
874 	struct aucc_softc *sc;
875 	int i,j;
876 
877 	DPRINTF(("aucc_get_port: port=%d", cp->dev));
878 	sc = addr;
879 	switch (cp->type) {
880 	case AUDIO_MIXER_SET:
881 		if (cp->dev != AUCC_CHANNELS)
882 			return EINVAL;
883 		cp->un.mask = sc->sc_channelmask;
884 		break;
885 
886 	case AUDIO_MIXER_VALUE:
887 		i = cp->un.value.num_channels;
888 		if ((i < 1) || (i > 4))
889 			return EINVAL;
890 
891 		for (j = 0; j < i; j++)
892 			cp->un.value.level[j] =
893 			    (sc->sc_channel[j].nd_volume << 2) +
894 			    (sc->sc_channel[j].nd_volume >> 4);
895 		break;
896 
897 	default:
898 		return EINVAL;
899 	}
900 	return 0;
901 }
902 
903 
904 int
905 aucc_get_props(void *addr)
906 {
907 	return 0;
908 }
909 
910 int
911 aucc_query_devinfo(void *addr, register mixer_devinfo_t *dip)
912 {
913 	int i;
914 
915 	switch(dip->index) {
916 	case AUCC_CHANNELS:
917 		dip->type = AUDIO_MIXER_SET;
918 		dip->mixer_class = AUCC_OUTPUT_CLASS;
919 		dip->prev = dip->next = AUDIO_MIXER_LAST;
920 		strcpy(dip->label.name, AudioNspeaker);
921 		for (i = 0; i < 16; i++) {
922 			sprintf(dip->un.s.member[i].label.name,
923 			    "channelmask%d", i);
924 			dip->un.s.member[i].mask = i;
925 		}
926 		dip->un.s.num_mem = 16;
927 		break;
928 
929 	case AUCC_VOLUME:
930 		dip->type = AUDIO_MIXER_VALUE;
931 		dip->mixer_class = AUCC_OUTPUT_CLASS;
932 		dip->prev = dip->next = AUDIO_MIXER_LAST;
933 		strcpy(dip->label.name, AudioNmaster);
934 		dip->un.v.num_channels = 4;
935 		strcpy(dip->un.v.units.name, AudioNvolume);
936 		break;
937 
938 	case AUCC_OUTPUT_CLASS:
939 		dip->type = AUDIO_MIXER_CLASS;
940 		dip->mixer_class = AUCC_OUTPUT_CLASS;
941 		dip->next = dip->prev = AUDIO_MIXER_LAST;
942 		strcpy(dip->label.name, AudioCoutputs);
943 		break;
944 
945 	default:
946 		return ENXIO;
947 	}
948 
949 	DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
950 
951 	return 0;
952 }
953 
954 /* audio int handler */
955 void
956 aucc_inthdl(int ch)
957 {
958 	int i;
959 	int mask;
960 
961 	mask = aucc->sc_channel[ch].nd_mask;
962 	/*
963 	 * for all channels in this maskgroup:
964 	 * disable DMA, int
965 	 * mark idle
966 	 */
967 	DPRINTF(("inthandler called, channel %d, mask 0x%x\n", ch, mask));
968 
969 	custom.intreq = mask << INTB_AUD0; /* clear request */
970 	/*
971 	 * XXX: maybe we can leave ints and/or DMA on,
972 	 * if another sample has to be played?
973 	 */
974 	custom.intena = mask << INTB_AUD0;
975 	/*
976 	 * XXX custom.dmacon=mask; NO!!!
977 	 */
978 	for (i = 0; i < 4; i++) {
979 		if (masks2[i] && mask) {
980 			DPRINTF(("marking channel %d idle\n",i));
981 			aucc->sc_channel[i].nd_busy = 0;
982 			aucc->sc_channel[i].nd_mask = 0;
983 			channel[i].isaudio = channel[i].play_count = 0;
984 		}
985 	}
986 
987 	/* call handler */
988 	if (aucc->sc_channel[ch].nd_intr) {
989 		DPRINTF(("calling %p\n",aucc->sc_channel[ch].nd_intr));
990 		(*(aucc->sc_channel[ch].nd_intr))
991 		    (aucc->sc_channel[ch].nd_intrdata);
992 	} else
993 		DPRINTF(("zero int handler\n"));
994 	DPRINTF(("ints done\n"));
995 }
996 
997 /* transform frequency to period, adjust bounds */
998 static u_int
999 freqtoper(u_int freq)
1000 {
1001 	u_int per;
1002 
1003 	per = eclockfreq * 5 / freq;
1004 	if (per < 124)
1005 		per = 124;   /* must have at least 124 ticks between samples */
1006 
1007 	return per;
1008 }
1009 
1010 /* transform period to frequency */
1011 static u_int
1012 pertofreq(u_int per)
1013 {
1014 
1015 	return eclockfreq * 5 / per;
1016 }
1017 
1018 static void
1019 aucc_decode_slinear8_1ch(u_char **dmap, u_char *p, int i)
1020 {
1021 	memcpy(dmap[0], p, i);
1022 }
1023 
1024 static void
1025 aucc_decode_slinear8_2ch(u_char **dmap, u_char *p, int i)
1026 {
1027 	u_char *ch0;
1028 	u_char *ch1;
1029 
1030 	ch0 = dmap[0];
1031 	ch1 = dmap[1];
1032 	while (i--) {
1033 		*ch0++ = *p++;
1034 		*ch1++ = *p++;
1035 	}
1036 }
1037 
1038 static void
1039 aucc_decode_slinear8_3ch(u_char **dmap, u_char *p, int i)
1040 {
1041 	u_char *ch0;
1042 	u_char *ch1;
1043 	u_char *ch2;
1044 
1045 	ch0 = dmap[0];
1046 	ch1 = dmap[1];
1047 	ch2 = dmap[2];
1048 	while (i--) {
1049 		*ch0++ = *p++;
1050 		*ch1++ = *p++;
1051 		*ch2++ = *p++;
1052 	}
1053 }
1054 
1055 static void
1056 aucc_decode_slinear8_4ch(u_char **dmap, u_char *p, int i)
1057 {
1058 	u_char *ch0;
1059 	u_char *ch1;
1060 	u_char *ch2;
1061 	u_char *ch3;
1062 
1063 	ch0 = dmap[0];
1064 	ch1 = dmap[1];
1065 	ch2 = dmap[2];
1066 	ch3 = dmap[3];
1067 	while (i--) {
1068 		*ch0++ = *p++;
1069 		*ch1++ = *p++;
1070 		*ch2++ = *p++;
1071 		*ch3++ = *p++;
1072 	}
1073 }
1074 
1075 static void
1076 aucc_decode_ulinear8_1ch(u_char **dmap, u_char *p, int i)
1077 {
1078 	u_char *ch0;
1079 
1080 	ch0 = dmap[0];
1081 	while (i--)
1082 		*ch0++ = *p++ - 128;
1083 }
1084 
1085 static void
1086 aucc_decode_ulinear8_2ch(u_char **dmap, u_char *p, int i)
1087 {
1088 	u_char *ch0;
1089 	u_char *ch1;
1090 
1091 	ch0 = dmap[0];
1092 	ch1 = dmap[1];
1093 	while (i--) {
1094 		*ch0++ = *p++ - 128;
1095 		*ch1++ = *p++ - 128;
1096 	}
1097 }
1098 
1099 static void
1100 aucc_decode_ulinear8_3ch(u_char **dmap, u_char *p, int i)
1101 {
1102 	u_char *ch0;
1103 	u_char *ch1;
1104 	u_char *ch2;
1105 
1106 	ch0 = dmap[0];
1107 	ch1 = dmap[1];
1108 	ch2 = dmap[2];
1109 	while (i--) {
1110 		*ch0++ = *p++ - 128;
1111 		*ch1++ = *p++ - 128;
1112 		*ch2++ = *p++ - 128;
1113 	}
1114 }
1115 
1116 static void
1117 aucc_decode_ulinear8_4ch(u_char **dmap, u_char *p, int i)
1118 {
1119 	u_char *ch0;
1120 	u_char *ch1;
1121 	u_char *ch2;
1122 	u_char *ch3;
1123 
1124 	ch0 = dmap[0];
1125 	ch1 = dmap[1];
1126 	ch2 = dmap[2];
1127 	ch3 = dmap[3];
1128 	while (i--) {
1129 		*ch0++ = *p++ - 128;
1130 		*ch1++ = *p++ - 128;
1131 		*ch2++ = *p++ - 128;
1132 		*ch3++ = *p++ - 128;
1133 	}
1134 }
1135 
1136 
1137 static void
1138 aucc_decode_mulaw_1ch(u_char **dmap, u_char *p, int i)
1139 {
1140 	u_char *ch0;
1141 
1142 	ch0 = dmap[0];
1143 	while (i--)
1144 		*ch0++ = mulaw_to_lin[*p++];
1145 }
1146 
1147 static void
1148 aucc_decode_mulaw_2ch(u_char **dmap, u_char *p, int i)
1149 {
1150 	u_char *ch0;
1151 	u_char *ch1;
1152 
1153 	ch0 = dmap[0];
1154 	ch1 = dmap[1];
1155 	while (i--) {
1156 		*ch0++ = mulaw_to_lin[*p++];
1157 		*ch1++ = mulaw_to_lin[*p++];
1158 	}
1159 }
1160 
1161 static void
1162 aucc_decode_mulaw_3ch(u_char **dmap, u_char *p, int i)
1163 {
1164 	u_char *ch0;
1165 	u_char *ch1;
1166 	u_char *ch2;
1167 
1168 	ch0 = dmap[0];
1169 	ch1 = dmap[1];
1170 	ch2 = dmap[2];
1171 	while (i--) {
1172 		*ch0++ = mulaw_to_lin[*p++];
1173 		*ch1++ = mulaw_to_lin[*p++];
1174 		*ch2++ = mulaw_to_lin[*p++];
1175 	}
1176 }
1177 
1178 static void
1179 aucc_decode_mulaw_4ch(u_char **dmap, u_char *p, int i)
1180 {
1181 	u_char *ch0;
1182 	u_char *ch1;
1183 	u_char *ch2;
1184 	u_char *ch3;
1185 
1186 	ch0 = dmap[0];
1187 	ch1 = dmap[1];
1188 	ch2 = dmap[2];
1189 	ch3 = dmap[3];
1190 	while (i--) {
1191 		*ch0++ = mulaw_to_lin[*p++];
1192 		*ch1++ = mulaw_to_lin[*p++];
1193 		*ch2++ = mulaw_to_lin[*p++];
1194 		*ch3++ = mulaw_to_lin[*p++];
1195 	}
1196 }
1197 
1198 
1199 /* 14bit output */
1200 static void
1201 aucc_decode_slinear16_1ch(u_char **dmap, u_char *p, int i)
1202 {
1203 	u_char *ch0;
1204 	u_char *ch3;
1205 
1206 	ch0 = dmap[0];
1207 	ch3 = dmap[1];		/* XXX should be 3 */
1208 	while (i--) {
1209 		*ch0++ = *p++;
1210 		*ch3++ = *p++ >> 2;
1211 	}
1212 }
1213 
1214 /* 14bit stereo output */
1215 static void
1216 aucc_decode_slinear16_2ch(u_char **dmap, u_char *p, int i)
1217 {
1218 	u_char *ch0;
1219 	u_char *ch1;
1220 	u_char *ch2;
1221 	u_char *ch3;
1222 
1223 	ch0 = dmap[0];
1224 	ch1 = dmap[1];
1225 	ch2 = dmap[2];
1226 	ch3 = dmap[3];
1227 	while (i--) {
1228 		*ch0++ = *p++;
1229 		*ch3++ = *p++ >> 2;
1230 		*ch1++ = *p++;
1231 		*ch2++ = *p++ >> 2;
1232 	}
1233 }
1234 
1235 static void
1236 aucc_decode_slinear16_3ch(u_char **dmap, u_char *p, int i)
1237 {
1238 	u_char *ch0;
1239 	u_char *ch1;
1240 	u_char *ch2;
1241 
1242 	ch0 = dmap[0];
1243 	ch1 = dmap[1];
1244 	ch2 = dmap[2];
1245 	while (i--) {
1246 		*ch0++ = *p++; p++;
1247 		*ch1++ = *p++; p++;
1248 		*ch2++ = *p++; p++;
1249 	}
1250 }
1251 
1252 static void
1253 aucc_decode_slinear16_4ch(u_char **dmap, u_char *p, int i)
1254 {
1255 	u_char *ch0;
1256 	u_char *ch1;
1257 	u_char *ch2;
1258 	u_char *ch3;
1259 
1260 	ch0 = dmap[0];
1261 	ch1 = dmap[1];
1262 	ch2 = dmap[2];
1263 	ch3 = dmap[3];
1264 	while (i--) {
1265 		*ch0++ = *p++; p++;
1266 		*ch1++ = *p++; p++;
1267 		*ch2++ = *p++; p++;
1268 		*ch3++ = *p++; p++;
1269 	}
1270 }
1271 
1272 /* 14bit output, swap bytes */
1273 static void
1274 aucc_decode_slinear16sw_1ch(u_char **dmap, u_char *p, int i)
1275 {
1276 	u_char *ch0;
1277 	u_char *ch3;
1278 
1279 	ch0 = dmap[0];
1280 	ch3 = dmap[1];		/* XXX should be 3 */
1281 	while (i--) {
1282 		*ch3++ = *p++ >> 2;
1283 		*ch0++ = *p++;
1284 	}
1285 }
1286 
1287 static void
1288 aucc_decode_slinear16sw_2ch(u_char **dmap, u_char *p, int i)
1289 {
1290 	u_char *ch0;
1291 	u_char *ch1;
1292 	u_char *ch2;
1293 	u_char *ch3;
1294 
1295 	ch0 = dmap[0];
1296 	ch1 = dmap[1];
1297 	ch2 = dmap[2];
1298 	ch3 = dmap[3];
1299 	while (i--) {
1300 		*ch3++ = *p++ >> 2;
1301 		*ch0++ = *p++;
1302 		*ch2++ = *p++ >> 2;
1303 		*ch1++ = *p++;
1304 	}
1305 }
1306 
1307 static void
1308 aucc_decode_slinear16sw_3ch(u_char **dmap, u_char *p, int i)
1309 {
1310 	u_char *ch0;
1311 	u_char *ch1;
1312 	u_char *ch2;
1313 
1314 	ch0 = dmap[0];
1315 	ch1 = dmap[1];
1316 	ch2 = dmap[2];
1317 	while (i--) {
1318 		p++; *ch0++ = *p++;
1319 		p++; *ch1++ = *p++;
1320 		p++; *ch2++ = *p++;
1321 	}
1322 }
1323 
1324 static void
1325 aucc_decode_slinear16sw_4ch(u_char **dmap, u_char *p, int i)
1326 {
1327 	u_char *ch0;
1328 	u_char *ch1;
1329 	u_char *ch2;
1330 	u_char *ch3;
1331 
1332 	ch0 = dmap[0];
1333 	ch1 = dmap[1];
1334 	ch2 = dmap[2];
1335 	ch3 = dmap[3];
1336 	while (i--) {
1337 		p++; *ch0++ = *p++;
1338 		p++; *ch1++ = *p++;
1339 		p++; *ch2++ = *p++;
1340 		p++; *ch3++ = *p++;
1341 	}
1342 }
1343 
1344 
1345 #endif /* NAUCC > 0 */
1346