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