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