aucc.c revision 1.21 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