aucc.c revision 1.7 1 /* $NetBSD: aucc.c,v 1.7 1997/06/23 23:46:25 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
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((dev_t, 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_set_encoding __P((void *, u_int));
174 int aucc_get_encoding __P((void *));
175 int aucc_set_precision __P((void *, u_int));
176 int aucc_get_precision __P((void *));
177 int aucc_set_channels __P((void *, int));
178 int aucc_get_channels __P((void *));
179 int aucc_round_blocksize __P((void *, int));
180 int aucc_set_out_port __P((void *, int));
181 int aucc_get_out_port __P((void *));
182 int aucc_set_in_port __P((void *, int));
183 int aucc_get_in_port __P((void *));
184 int aucc_commit_settings __P((void *));
185 int aucc_start_output __P((void *, void *, int, void (*)(void *),
186 void *));
187 int aucc_start_input __P((void *, void *, int, void (*)(void *),
188 void *));
189 int aucc_halt_output __P((void *));
190 int aucc_halt_input __P((void *));
191 int aucc_cont_output __P((void *));
192 int aucc_cont_input __P((void *));
193 int aucc_getdev __P((void *, struct audio_device *));
194 int aucc_setfd __P((void *, int));
195 int aucc_set_port __P((void *, mixer_ctrl_t *));
196 int aucc_get_port __P((void *, mixer_ctrl_t *));
197 int aucc_query_devinfo __P((void *, mixer_devinfo_t *));
198 void aucc_encode __P((int, u_char *, char *, int));
199 int aucc_set_params __P((void *, int, struct audio_params *,
200 struct audio_params *));
201
202 struct audio_hw_if sa_hw_if = {
203 aucc_open,
204 aucc_close,
205 NULL,
206 aucc_query_encoding,
207 aucc_set_params,
208 aucc_round_blocksize,
209 aucc_set_out_port,
210 aucc_get_out_port,
211 aucc_set_in_port,
212 aucc_get_in_port,
213 aucc_commit_settings,
214 aucc_start_output,
215 aucc_start_input,
216 aucc_halt_output,
217 aucc_halt_input,
218 aucc_cont_output,
219 aucc_cont_input,
220 NULL,
221 aucc_getdev,
222 aucc_setfd,
223 aucc_set_port,
224 aucc_get_port,
225 aucc_query_devinfo,
226 0,
227 0
228 };
229
230 /* autoconfig routines */
231
232 int
233 auccmatch(pdp, cfp, aux)
234 struct device *pdp;
235 struct cfdata *cfp;
236 void *aux;
237 {
238 if (matchname((char *)aux, "aucc") &&
239 #ifdef DRACO
240 !is_draco() &&
241 #endif
242 (cfp->cf_unit == 0))
243 return 1;
244
245 return 0;
246 }
247
248 /*
249 * Audio chip found.
250 */
251 void
252 auccattach(parent, self, args)
253 struct device *parent, *self;
254 void *args;
255 {
256 register struct aucc_softc *sc = (struct aucc_softc *)self;
257 register int i;
258
259 printf("\n");
260
261 if((i=init_aucc(sc))) {
262 printf("audio: no chipmem\n");
263 return;
264 }
265
266 if (audio_hardware_attach(&sa_hw_if, sc) != 0)
267 printf("audio: could not attach to audio pseudo-device driver\n");
268 /* XXX: no way to return error, if init fails */
269 }
270
271
272 static int
273 init_aucc(sc)
274 struct aucc_softc *sc;
275 {
276 register int i, err=0;
277
278 /* init values per channel */
279 for (i=0;i<4;i++) {
280 sc->sc_channel[i].nd_freq=8000;
281 sc->sc_channel[i].nd_per=freqtoper(8000);
282 sc->sc_channel[i].nd_busy=0;
283 sc->sc_channel[i].nd_dma=alloc_chipmem(AUDIO_BUF_SIZE*2);
284 if (sc->sc_channel[i].nd_dma==NULL)
285 err=1;
286 sc->sc_channel[i].nd_dmalength=0;
287 sc->sc_channel[i].nd_volume=64;
288 sc->sc_channel[i].nd_intr=NULL;
289 sc->sc_channel[i].nd_intrdata=NULL;
290 DPRINTF(("dma buffer for channel %d is %p\n", i,
291 sc->sc_channel[i].nd_dma));
292
293 }
294
295 if (err) {
296 for(i=0;i<4;i++)
297 if (sc->sc_channel[i].nd_dma)
298 free_chipmem(sc->sc_channel[i].nd_dma);
299 }
300
301 sc->sc_channels=4;
302 sc->sc_channelmask=0xf;
303
304 /* clear interrupts and dma: */
305 custom.intena = AUCC_ALLINTF;
306 custom.dmacon = AUCC_ALLDMAF;;
307
308 sc->sc_encoding=AUDIO_ENCODING_ULAW;
309
310 return err;
311
312 }
313
314 int
315 aucc_open(dev, flags)
316 dev_t dev;
317 int flags;
318 {
319 register struct aucc_softc *sc;
320 int unit = AUDIOUNIT(dev);
321 register int i;
322
323 DPRINTF(("sa_open: unit %d\n",unit));
324
325 if (unit >= aucc_cd.cd_ndevs)
326 return (ENODEV);
327 if ((sc = aucc_cd.cd_devs[unit]) == NULL)
328 return (ENXIO);
329 if (sc->sc_open)
330 return (EBUSY);
331 sc->sc_open = 1;
332 for (i=0;i<AUCC_MAXINT;i++) {
333 sc->sc_channel[i].nd_intr=NULL;
334 sc->sc_channel[i].nd_intrdata=NULL;
335 }
336 aucc=sc;
337
338 sc->sc_channels=4;
339 sc->sc_channelmask=0xf;
340
341 DPRINTF(("saopen: ok -> sc=0x%p\n",sc));
342
343 return (0);
344 }
345
346 void
347 aucc_close(addr)
348 void *addr;
349 {
350 register struct aucc_softc *sc = addr;
351
352 DPRINTF(("sa_close: sc=0x%p\n", sc));
353 /*
354 * halt i/o, clear open flag, and done.
355 */
356 aucc_halt_output(sc);
357 sc->sc_open = 0;
358
359 DPRINTF(("sa_close: closed.\n"));
360 }
361
362 int
363 aucc_set_out_sr(addr, sr)
364 void *addr;
365 u_long sr;
366 {
367 struct aucc_softc *sc=addr;
368 u_long per;
369 register int i;
370
371 per=freqtoper(sr);
372 if (per>0xffff)
373 return EINVAL;
374 sr=pertofreq(per);
375
376 for (i=0;i<4;i++) {
377 sc->sc_channel[i].nd_freq=sr;
378 sc->sc_channel[i].nd_per=per;
379 }
380
381 return(0);
382 }
383
384 int
385 aucc_query_encoding(addr, fp)
386 void *addr;
387 struct audio_encoding *fp;
388 {
389 switch (fp->index) {
390 case 0:
391 strcpy(fp->name, AudioElinear);
392 fp->encoding = AUDIO_ENCODING_LINEAR;
393 fp->precision = 8;
394 fp->flags = 0;
395 break;
396 case 1:
397 strcpy(fp->name, AudioEmulaw);
398 fp->encoding = AUDIO_ENCODING_ULAW;
399 fp->precision = 8;
400 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
401 break;
402
403 case 2:
404 strcpy(fp->name, AudioEulinear);
405 fp->encoding = AUDIO_ENCODING_ULINEAR;
406 fp->precision = 8;
407 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
408 break;
409
410 default:
411 return(EINVAL);
412 /*NOTREACHED*/
413 }
414 return(0);
415 }
416
417 int
418 aucc_set_params(addr, mode, p, q)
419 void *addr;
420 int mode;
421 struct audio_params *p, *q;
422 {
423 if (mode == AUMODE_RECORD)
424 return 0 /*ENXIO*/;
425
426 switch (p->encoding) {
427 case AUDIO_ENCODING_ULAW:
428 case AUDIO_ENCODING_LINEAR:
429 case AUDIO_ENCODING_ULINEAR:
430 break;
431 default:
432 return EINVAL;
433 /* NOTREADCHED */
434 }
435
436 if (p->precision != 8)
437 return EINVAL;
438
439 if ((p->channels<1) || (p->channels>4))
440 return(EINVAL);
441
442 q->encoding = p->encoding;
443 q->precision = p->precision;
444 q->channels = p->channels;
445
446 aucc_set_out_sr(addr, p->sample_rate);
447 return 0;
448 }
449
450 int
451 aucc_get_encoding(addr)
452 void *addr;
453 {
454 return ((struct aucc_softc *)addr)->sc_encoding;
455 }
456
457 int
458 aucc_get_precision(addr)
459 void *addr;
460 {
461 return(8);
462 }
463
464 int
465 aucc_get_channels(addr)
466 void *addr;
467 {
468 return ((struct aucc_softc *)addr)->sc_channels;
469 }
470
471 int
472 aucc_round_blocksize(addr, blk)
473 void *addr;
474 int blk;
475 {
476
477
478 return blk>AUDIO_BUF_SIZE?AUDIO_BUF_SIZE:blk; /* round up to even size */
479 }
480
481 int
482 aucc_set_out_port(addr, port) /* can set channels */
483 void *addr;
484 int port;
485 {
486 register struct aucc_softc *sc = addr;
487
488 /* port is mask for channels 0..3 */
489 if ((port<0)||(port>15))
490 return EINVAL;
491
492 sc->sc_channelmask=port;
493
494 return(0);
495 }
496
497 int
498 aucc_get_out_port(addr)
499 void *addr;
500 {
501 register struct aucc_softc *sc = addr;
502
503 return sc->sc_channelmask;
504 }
505
506 int
507 aucc_set_in_port(addr, port)
508 void *addr;
509 int port;
510 {
511 return(EINVAL); /* no input possible */
512
513 }
514
515 int
516 aucc_get_in_port(addr)
517 void *addr;
518 {
519 return(0);
520 }
521
522 int
523 aucc_commit_settings(addr)
524 void *addr;
525 {
526 register struct aucc_softc *sc = addr;
527 register int i;
528
529 DPRINTF(("sa_commit.\n"));
530
531 for (i=0;i<4;i++) {
532 custom.aud[i].vol=sc->sc_channel[i].nd_volume;
533 custom.aud[i].per=sc->sc_channel[i].nd_per;
534 }
535
536 DPRINTF(("commit done\n"));
537
538 return(0);
539 }
540
541 static int masks[4] = {1,3,7,15}; /* masks for n first channels */
542 static int masks2[4] = {1,2,4,8};
543
544 int
545 aucc_start_output(addr, p, cc, intr, arg)
546 void *addr;
547 void *p;
548 int cc;
549 void (*intr) __P((void *));
550 void *arg;
551 {
552 register struct aucc_softc *sc = addr;
553 register int mask=sc->sc_channelmask;
554 register int i,j=0;
555 register u_short *dmap;
556 register u_char *pp, *to;
557
558
559 dmap=NULL;
560
561 DPRINTF(("sa_start_output: cc=%d %p (%p)\n", cc, intr, arg));
562
563 mask &=masks[sc->sc_channels-1]; /* we use first sc_channels channels */
564 if (mask==0) /* active and used channels are disjoint */
565 return EINVAL;
566
567 for (i=0;i<4;i++) { /* channels available ? */
568 if ((masks2[i]&mask)&&(sc->sc_channel[i].nd_busy))
569 return EBUSY; /* channel is busy */
570 if (channel[i].isaudio==-1)
571 return EBUSY; /* system uses them */
572 }
573
574 /* enable interrupt on 1st channel */
575 for (i=0;i<AUCC_MAXINT;i++) {
576 if (masks2[i]&mask) {
577 DPRINTF(("first channel is %d\n",i));
578 j=i;
579 sc->sc_channel[i].nd_intr=intr;
580 sc->sc_channel[i].nd_intrdata=arg;
581 dmap=sc->sc_channel[i].nd_dma;
582 break;
583 }
584 }
585
586 DPRINTF(("dmap is %p, mask=0x%x\n",dmap,mask));
587
588 /* copy data to dma buffer */
589
590
591 to=(u_char *)dmap;
592 pp=(u_char *)p;
593 aucc_encode(sc->sc_encoding, pp, to, cc);
594
595
596 /* disable ints, dma for channels, until all parameters set */
597 /* XXX custom.dmacon=mask;*/
598 custom.intreq=mask<<INTB_AUD0;
599 custom.intena=mask<<INTB_AUD0;
600
601
602 /* dma buffers: we use same buffer 4 all channels */
603 /* write dma location and length */
604 for (i=0;i<4;i++) {
605 if (masks2[i]&mask) {
606 DPRINTF(("turning channel %d on\n",i));
607 /* sc->sc_channel[i].nd_busy=1;*/
608 channel[i].isaudio=1;
609 channel[i].play_count=1;
610 channel[i].handler=NULL;
611 custom.aud[i].per=sc->sc_channel[i].nd_per;
612 custom.aud[i].vol=sc->sc_channel[i].nd_volume;
613 if (custom.aud[i].lc==PREP_DMA_MEM(dmap))
614 custom.aud[i].lc =
615 PREP_DMA_MEM(dmap+AUDIO_BUF_SIZE);
616 else
617 custom.aud[i].lc = PREP_DMA_MEM(dmap);
618
619 custom.aud[i].len=cc>>1;
620 sc->sc_channel[i].nd_mask=mask;
621 DPRINTF(("per is %d, vol is %d, len is %d\n",\
622 sc->sc_channel[i].nd_per, sc->sc_channel[i].nd_volume, cc>>1));
623
624 }
625 }
626
627 channel[j].handler=aucc_inthdl;
628
629 /* enable ints */
630 custom.intena=INTF_SETCLR|INTF_INTEN| (masks2[j]<<INTB_AUD0);
631
632 DPRINTF(("enabled ints: 0x%x\n",(masks2[j]<<INTB_AUD0)));
633
634 /* enable dma */
635 custom.dmacon=DMAF_SETCLR|DMAF_MASTER|mask;
636
637 DPRINTF(("enabled dma, mask=0x%x\n",mask));
638
639 return(0);
640 }
641
642 /* ARGSUSED */
643 int
644 aucc_start_input(addr, p, cc, intr, arg)
645 void *addr;
646 void *p;
647 int cc;
648 void (*intr) __P((void *));
649 void *arg;
650 {
651
652 return ENXIO; /* no input */
653 }
654
655 int
656 aucc_halt_output(addr)
657 void *addr;
658 {
659 register struct aucc_softc *sc = addr;
660 register int i;
661
662 /* XXX only halt, if input is also halted ?? */
663 /* stop dma, etc */
664 custom.intena = AUCC_ALLINTF;
665 custom.dmacon = AUCC_ALLDMAF;
666 /* mark every busy unit idle */
667 for (i=0;i<4;i++) {
668 sc->sc_channel[i].nd_busy=sc->sc_channel[i].nd_mask=0;
669 channel[i].isaudio=0;
670 channel[i].play_count=0;
671 }
672
673 return(0);
674 }
675
676 int
677 aucc_halt_input(addr)
678 void *addr;
679 {
680 /* no input */
681
682 return ENXIO;
683 }
684
685 int
686 aucc_cont_output(addr)
687 void *addr;
688 {
689 DPRINTF(("aucc_cont_output: never called, what should it do?!\n"));
690 /* reenable DMA XXX */
691 return ENXIO;
692 }
693
694 int
695 aucc_cont_input(addr)
696 void *addr;
697 {
698 DPRINTF(("aucc_cont_input: never called, what should it do?!\n"));
699 return(0);
700 }
701
702 int
703 aucc_getdev(addr, retp)
704 void *addr;
705 struct audio_device *retp;
706 {
707 *retp = aucc_device;
708 return 0;
709 }
710
711 int
712 aucc_setfd(addr, flag)
713 void *addr;
714 int flag;
715 {
716 return flag?EINVAL:0; /* Always half-duplex */
717 }
718
719 int
720 aucc_set_port(addr, cp)
721 void *addr;
722 mixer_ctrl_t *cp;
723 {
724 register struct aucc_softc *sc = addr;
725 register int i,j;
726
727 DPRINTF(("aucc_set_port: port=%d", cp->dev));
728
729 switch (cp->type) {
730 case AUDIO_MIXER_SET:
731 if (cp->dev!=AUCC_CHANNELS)
732 return EINVAL;
733 i=cp->un.mask;
734 if ((i<1)||(i>15))
735 return EINVAL;
736 sc->sc_channelmask=i;
737 break;
738
739 case AUDIO_MIXER_VALUE:
740 i=cp->un.value.num_channels;
741 if ((i<1)||(i>4))
742 return EINVAL;
743
744 if (cp->dev!=AUCC_VOLUME)
745 return EINVAL;
746
747 /* set volume for channel 0..i-1 */
748 for (j=0;j<i;j++)
749 sc->sc_channel[j].nd_volume=cp->un.value.level[j]>>2;
750 break;
751
752 default:
753 return EINVAL;
754 break;
755 }
756 return 0;
757 }
758
759
760 int
761 aucc_get_port(addr, cp)
762 void *addr;
763 mixer_ctrl_t *cp;
764 {
765 register struct aucc_softc *sc = addr;
766 register int i,j;
767
768 DPRINTF(("aucc_get_port: port=%d", cp->dev));
769
770 switch (cp->type) {
771 case AUDIO_MIXER_SET:
772 if (cp->dev!=AUCC_CHANNELS)
773 return EINVAL;
774 cp->un.mask=sc->sc_channelmask;
775 break;
776
777 case AUDIO_MIXER_VALUE:
778 i = cp->un.value.num_channels;
779 if ((i<1)||(i>4))
780 return EINVAL;
781
782 for (j=0;j<i;j++)
783 cp->un.value.level[j]=sc->sc_channel[j].nd_volume<<2;
784 break;
785
786 default:
787 return EINVAL;
788 }
789 return 0;
790 }
791
792
793 int
794 aucc_query_devinfo(addr, dip)
795 void *addr;
796 register mixer_devinfo_t *dip;
797 {
798 register int i;
799
800 switch(dip->index) {
801 case AUCC_CHANNELS:
802 dip->type = AUDIO_MIXER_SET;
803 dip->mixer_class = AUCC_OUTPUT_CLASS;
804 dip->prev = dip->next = AUDIO_MIXER_LAST;
805 strcpy(dip->label.name, AudioNspeaker);
806 for (i=0;i<16;i++) {
807 sprintf(dip->un.s.member[i].label.name,
808 "channelmask%d", i);
809 dip->un.s.member[i].mask = i;
810 }
811 dip->un.s.num_mem = 16;
812 break;
813
814 case AUCC_VOLUME:
815 dip->type = AUDIO_MIXER_VALUE;
816 dip->mixer_class = AUCC_OUTPUT_CLASS;
817 dip->prev = dip->next = AUDIO_MIXER_LAST;
818 strcpy(dip->label.name, AudioNspeaker);
819 dip->un.v.num_channels = 4;
820 strcpy(dip->un.v.units.name, AudioNvolume);
821 break;
822
823 case AUCC_OUTPUT_CLASS:
824 dip->type = AUDIO_MIXER_CLASS;
825 dip->mixer_class = AUCC_OUTPUT_CLASS;
826 dip->next = dip->prev = AUDIO_MIXER_LAST;
827 strcpy(dip->label.name, AudioCOutputs);
828 break;
829 default:
830 return ENXIO;
831 /*NOTREACHED*/
832 }
833
834 DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
835
836 return(0);
837 }
838
839
840 /* audio int handler */
841 void
842 aucc_inthdl(int ch)
843 {
844 register int i;
845 register int mask=aucc->sc_channel[ch].nd_mask;
846
847 /* for all channels in this maskgroup:
848 disable dma, int
849 mark idle */
850 DPRINTF(("inthandler called, channel %d, mask 0x%x\n",ch,mask));
851
852 custom.intreq=mask<<INTB_AUD0; /* clear request */
853 /* XXX: maybe we can leave ints and/or DMA on, if another sample has to be played?*/
854 custom.intena=mask<<INTB_AUD0;
855 /*
856 * XXX custom.dmacon=mask; NO!!!
857 */
858 for (i=0;i<4;i++) {
859 if (masks2[i]&&mask) {
860 DPRINTF(("marking channel %d idle\n",i));
861 aucc->sc_channel[i].nd_busy=0;
862 aucc->sc_channel[i].nd_mask=0;
863 channel[i].isaudio=channel[i].play_count=0;
864 }
865 }
866
867 /* call handler */
868 if (aucc->sc_channel[ch].nd_intr) {
869 DPRINTF(("calling %p\n",aucc->sc_channel[ch].nd_intr));
870 (*(aucc->sc_channel[ch].nd_intr))(aucc->sc_channel[ch].nd_intrdata);
871 }
872 else DPRINTF(("zero int handler\n"));
873 DPRINTF(("ints done\n"));
874 }
875
876
877
878
879 /* transform frequency to period, adjust bounds */
880 static u_int
881 freqtoper(u_int freq)
882 {
883 u_int per=eclockfreq*5/freq;
884
885 if (per<124)
886 per=124; /* must have at least 124 ticks between samples */
887
888 return per;
889 }
890
891 /* transform period to frequency */
892 static u_int
893 pertofreq(u_int per)
894 {
895 u_int freq=eclockfreq*5/per;
896
897
898 return freq;
899 }
900
901
902
903 void
904 aucc_encode(enc, p, q, i)
905 int enc;
906 u_char *p;
907 char *q;
908 int i;
909 {
910 int off=0;
911 u_char *tab=NULL;
912
913
914
915 switch (enc) {
916 case AUDIO_ENCODING_ULAW:
917 tab=ulaw_to_lin;
918 break;
919 case AUDIO_ENCODING_ULINEAR:
920 off=-128;
921 /* FALLTHROUGH */
922 case AUDIO_ENCODING_LINEAR:
923 break;
924 default:
925 return;
926 }
927
928 if (tab)
929 while (i--)
930 *q++ = tab[*p++];
931 else
932 while (i--)
933 *q++ = *p++ + off;
934
935 }
936
937 #endif /* NAUCC > 0 */
938