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