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