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