summaryrefslogtreecommitdiff
path: root/sys/arch/amiga/dev/aucc.c
diff options
context:
space:
mode:
authorNiklas Hallqvist <niklas@cvs.openbsd.org>1997-09-18 13:40:05 +0000
committerNiklas Hallqvist <niklas@cvs.openbsd.org>1997-09-18 13:40:05 +0000
commit2157b0ba8b467d175588a39d0235e3f42cfa0167 (patch)
treeab27e576639f38402b47a6af61ab8711d85d7ce7 /sys/arch/amiga/dev/aucc.c
parent9557efb948677ebfd961c6f49a7b69e3c722c206 (diff)
Merge of NetBSD changes upto last week or so, with the exception of stand/
Diffstat (limited to 'sys/arch/amiga/dev/aucc.c')
-rw-r--r--sys/arch/amiga/dev/aucc.c978
1 files changed, 978 insertions, 0 deletions
diff --git a/sys/arch/amiga/dev/aucc.c b/sys/arch/amiga/dev/aucc.c
new file mode 100644
index 00000000000..ba60c5b9ba8
--- /dev/null
+++ b/sys/arch/amiga/dev/aucc.c
@@ -0,0 +1,978 @@
+/* $OpenBSD: aucc.c,v 1.1 1997/09/18 13:39:42 niklas Exp $ */
+/* $NetBSD: aucc.c,v 1.18 1997/08/24 22:31:23 augustss Exp $ */
+#undef AUDIO_DEBUG
+/*
+ * Copyright (c) 1997 Stephan Thesing
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Stephan Thesing.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "aucc.h"
+#if NAUCC > 0
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <machine/cpu.h>
+
+#include <sys/audioio.h>
+#include <dev/audio_if.h>
+#include <amiga/amiga/cc.h>
+#include <amiga/amiga/custom.h>
+#include <amiga/amiga/device.h>
+#include <amiga/dev/auccvar.h>
+
+#ifdef LEV6_DEFER
+#define AUCC_MAXINT 3
+#define AUCC_ALLINTF (INTF_AUD0|INTF_AUD1|INTF_AUD2)
+#else
+#define AUCC_MAXINT 4
+#define AUCC_ALLINTF (INTF_AUD0|INTF_AUD1|INTF_AUD2|INTF_AUD3)
+#endif
+/* this unconditionally; we may use AUD3 as slave channel with LEV6_DEFER */
+#define AUCC_ALLDMAF (DMAF_AUD0|DMAF_AUD1|DMAF_AUD2|DMAF_AUD3)
+
+#ifdef AUDIO_DEBUG
+/*extern printf __P((const char *,...));*/
+int auccdebug = 1;
+#define DPRINTF(x) if (auccdebug) printf x
+#else
+#define DPRINTF(x)
+#endif
+
+#ifdef splaudio
+#undef splaudio
+#endif
+
+#define splaudio() spl4();
+
+/* clock frequency.. */
+extern int eclockfreq;
+
+/* hw audio ch */
+extern struct audio_channel channel[4];
+
+/*
+ * Software state.
+ */
+struct aucc_softc {
+ struct device sc_dev; /* base device */
+
+ int sc_open; /* single use device */
+ aucc_data_t sc_channel[4]; /* per channel freq, ... */
+ u_int sc_encoding; /* encoding AUDIO_ENCODING_.*/
+ int sc_channels; /* # of channels used */
+
+ int sc_intrcnt; /* interrupt count */
+ int sc_channelmask; /* which channels are used ? */
+};
+
+/* interrupt interfaces */
+void aucc_inthdl __P((int));
+
+/* forward declarations */
+int init_aucc __P((struct aucc_softc *));
+u_int freqtoper __P((u_int));
+u_int pertofreq __P((u_int));
+
+/* autoconfiguration driver */
+void auccattach __P((struct device *, struct device *, void *));
+int auccmatch __P((struct device *, void *, void *));
+
+struct cfattach aucc_ca = {
+ sizeof(struct aucc_softc),
+ auccmatch,
+ auccattach
+};
+
+struct cfdriver aucc_cd = {
+ NULL, "aucc", DV_DULL, NULL, 0
+};
+
+struct audio_device aucc_device = {
+ "Amiga-audio",
+ "x",
+ "aucc"
+};
+
+struct aucc_softc *aucc = NULL;
+
+unsigned char ulaw_to_lin[] = {
+ 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
+ 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
+ 0xc1, 0xc3, 0xc5, 0xc7, 0xc9, 0xcb, 0xcd, 0xcf,
+ 0xd1, 0xd3, 0xd5, 0xd7, 0xd9, 0xdb, 0xdd, 0xdf,
+ 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
+ 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0,
+ 0xf0, 0xf1, 0xf1, 0xf2, 0xf2, 0xf3, 0xf3, 0xf4,
+ 0xf4, 0xf5, 0xf5, 0xf6, 0xf6, 0xf7, 0xf7, 0xf8,
+ 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa,
+ 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc,
+ 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd,
+ 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe,
+ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x7d, 0x79, 0x75, 0x71, 0x6d, 0x69, 0x65, 0x61,
+ 0x5d, 0x59, 0x55, 0x51, 0x4d, 0x49, 0x45, 0x41,
+ 0x3e, 0x3c, 0x3a, 0x38, 0x36, 0x34, 0x32, 0x30,
+ 0x2e, 0x2c, 0x2a, 0x28, 0x26, 0x24, 0x22, 0x20,
+ 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17,
+ 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f,
+ 0x0f, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b,
+ 0x0b, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x07,
+ 0x07, 0x07, 0x06, 0x06, 0x06, 0x06, 0x05, 0x05,
+ 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+/*
+ * Define our interface to the higher level audio driver.
+ */
+int aucc_open __P((void *, int));
+void aucc_close __P((void *));
+int aucc_set_out_sr __P((void *, u_long));
+int aucc_query_encoding __P((void *, struct audio_encoding *));
+int aucc_round_blocksize __P((void *, int));
+int aucc_set_out_port __P((void *, int));
+int aucc_get_out_port __P((void *));
+int aucc_set_in_port __P((void *, int));
+int aucc_get_in_port __P((void *));
+int aucc_commit_settings __P((void *));
+int aucc_start_output __P((void *, void *, int, void (*)(void *),
+ void *));
+int aucc_start_input __P((void *, void *, int, void (*)(void *),
+ void *));
+int aucc_halt_output __P((void *));
+int aucc_halt_input __P((void *));
+int aucc_cont_output __P((void *));
+int aucc_cont_input __P((void *));
+int aucc_getdev __P((void *, struct audio_device *));
+int aucc_set_port __P((void *, mixer_ctrl_t *));
+int aucc_get_port __P((void *, mixer_ctrl_t *));
+int aucc_query_devinfo __P((void *, mixer_devinfo_t *));
+void aucc_encode __P((int, int, int, u_char *, u_short **));
+int aucc_set_params __P((void *, int, int,
+ struct audio_params *, struct audio_params *));
+int aucc_get_props __P((void *));
+
+struct audio_hw_if sa_hw_if = {
+ aucc_open,
+ aucc_close,
+ NULL,
+ aucc_query_encoding,
+ aucc_set_params,
+ aucc_round_blocksize,
+ aucc_set_out_port,
+ aucc_get_out_port,
+ aucc_set_in_port,
+ aucc_get_in_port,
+ aucc_commit_settings,
+ NULL,
+ NULL,
+ aucc_start_output,
+ aucc_start_input,
+ aucc_halt_output,
+ aucc_halt_input,
+ aucc_cont_output,
+ aucc_cont_input,
+ NULL,
+ aucc_getdev,
+ NULL,
+ aucc_set_port,
+ aucc_get_port,
+ aucc_query_devinfo,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ aucc_get_props,
+};
+
+/* autoconfig routines */
+
+int
+auccmatch(pdp, match, aux)
+ struct device *pdp;
+ void *match;
+ void *aux;
+{
+ struct cfdata *cfp = match;
+
+ if (matchname((char *)aux, "aucc") &&
+#ifdef DRACO
+ !is_draco() &&
+#endif
+ (cfp->cf_unit == 0))
+ return (1);
+
+ return (0);
+}
+
+/*
+ * Audio chip found.
+ */
+void
+auccattach(parent, self, args)
+ struct device *parent, *self;
+ void *args;
+{
+ struct aucc_softc *sc = (struct aucc_softc *)self;
+ int i;
+
+ printf("\n");
+
+ if((i = init_aucc(sc)) != 0) {
+ printf("audio: no chipmem\n");
+ return;
+ }
+
+ audio_attach_mi(&sa_hw_if, 0, sc, &sc->sc_dev);
+}
+
+int
+init_aucc(sc)
+ struct aucc_softc *sc;
+{
+ int i, err=0;
+
+ /* init values per channel */
+ for (i = 0; i < 4; i++) {
+ sc->sc_channel[i].nd_freq = 8000;
+ sc->sc_channel[i].nd_per = freqtoper(8000);
+ sc->sc_channel[i].nd_busy = 0;
+ sc->sc_channel[i].nd_dma = alloc_chipmem(AUDIO_BUF_SIZE * 2);
+ if (sc->sc_channel[i].nd_dma == NULL)
+ err = 1;
+ sc->sc_channel[i].nd_dmalength = 0;
+ sc->sc_channel[i].nd_volume = 64;
+ sc->sc_channel[i].nd_intr = NULL;
+ sc->sc_channel[i].nd_intrdata = NULL;
+ sc->sc_channel[i].nd_doublebuf = 0;
+ DPRINTF(("dma buffer for channel %d is %p\n", i,
+ sc->sc_channel[i].nd_dma));
+
+ }
+
+ if (err) {
+ for(i = 0; i < 4; i++)
+ if (sc->sc_channel[i].nd_dma)
+ free_chipmem(sc->sc_channel[i].nd_dma);
+ }
+
+ sc->sc_channels = 1;
+ sc->sc_channelmask = 0xf;
+
+ /* clear interrupts and dma: */
+ custom.intena = AUCC_ALLINTF;
+ custom.dmacon = AUCC_ALLDMAF;
+
+ sc->sc_encoding = AUDIO_ENCODING_ULAW;
+
+ return (err);
+
+}
+
+int
+aucc_open(addr, flags)
+ void *addr;
+ int flags;
+{
+ struct aucc_softc *sc = addr;
+ int i;
+
+ DPRINTF(("sa_open: unit %p\n",sc));
+
+ if (sc->sc_open)
+ return (EBUSY);
+ sc->sc_open = 1;
+ for (i = 0; i < AUCC_MAXINT; i++) {
+ sc->sc_channel[i].nd_intr = NULL;
+ sc->sc_channel[i].nd_intrdata = NULL;
+ }
+ aucc = sc;
+ sc->sc_channelmask = 0xf;
+
+ DPRINTF(("saopen: ok -> sc=0x%p\n",sc));
+
+ return (0);
+}
+
+void
+aucc_close(addr)
+ void *addr;
+{
+ struct aucc_softc *sc = addr;
+
+ DPRINTF(("sa_close: sc=0x%p\n", sc));
+ /*
+ * halt i/o, clear open flag, and done.
+ */
+ aucc_halt_output(sc);
+ sc->sc_open = 0;
+
+ DPRINTF(("sa_close: closed.\n"));
+}
+
+int
+aucc_set_out_sr(addr, sr)
+ void *addr;
+ u_long sr;
+{
+ struct aucc_softc *sc = addr;
+ u_long per;
+ int i;
+
+ per = freqtoper(sr);
+ if (per > 0xffff)
+ return (EINVAL);
+ sr = pertofreq(per);
+
+ for (i = 0; i < 4; i++) {
+ sc->sc_channel[i].nd_freq = sr;
+ sc->sc_channel[i].nd_per = per;
+ }
+
+ return (0);
+}
+
+int
+aucc_query_encoding(addr, fp)
+ void *addr;
+ struct audio_encoding *fp;
+{
+ switch (fp->index) {
+ case 0:
+ strcpy(fp->name, AudioElinear);
+ fp->encoding = AUDIO_ENCODING_SLINEAR;
+ fp->precision = 8;
+ fp->flags = 0;
+ break;
+ case 1:
+ strcpy(fp->name, AudioEmulaw);
+ fp->encoding = AUDIO_ENCODING_ULAW;
+ fp->precision = 8;
+ fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ break;
+
+ case 2:
+ strcpy(fp->name, AudioEulinear);
+ fp->encoding = AUDIO_ENCODING_ULINEAR;
+ fp->precision = 8;
+ fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
+ break;
+
+ default:
+ return (EINVAL);
+ /*NOTREACHED*/
+ }
+ return (0);
+}
+
+int
+aucc_set_params(addr, setmode, usemode, p, r)
+ void *addr;
+ int setmode, usemode;
+ struct audio_params *p, *r;
+{
+ struct aucc_softc *sc = addr;
+
+#if 0
+ if (setmode & AUMODE_RECORD)
+ return (ENXIO);
+#endif
+
+#ifdef AUCCDEBUG
+ printf("aucc_set_params(setmode 0x%x, usemode 0x%x, enc %d, bits %d,"
+ "chn %d, sr %ld)\n",
+ setmode, usemode, p->encoding, p->precision, p->channels,
+ p->sample_rate);
+#endif
+
+ switch (p->encoding) {
+ case AUDIO_ENCODING_ULAW:
+ case AUDIO_ENCODING_SLINEAR:
+ case AUDIO_ENCODING_SLINEAR_BE:
+ case AUDIO_ENCODING_SLINEAR_LE:
+ case AUDIO_ENCODING_ULINEAR_BE:
+ case AUDIO_ENCODING_ULINEAR_LE:
+ break;
+
+ default:
+ return EINVAL;
+ /* NOTREADCHED */
+ }
+
+ if (p->precision != 8)
+ return (EINVAL);
+
+ if ((p->channels < 1) || (p->channels > 4))
+ return (EINVAL);
+
+ sc->sc_channels = p->channels;
+ sc->sc_encoding = p->encoding;
+
+ return (aucc_set_out_sr(addr, p->sample_rate));
+}
+
+int
+aucc_round_blocksize(addr, blk)
+ void *addr;
+ int blk;
+{
+ /* round up to even size */
+ return (blk > AUDIO_BUF_SIZE ? AUDIO_BUF_SIZE : blk);
+}
+
+int
+aucc_set_out_port(addr, port) /* can set channels */
+ void *addr;
+ int port;
+{
+ struct aucc_softc *sc = addr;
+
+ /* port is mask for channels 0..3 */
+ if ((port < 0) || (port > 15))
+ return (EINVAL);
+
+ sc->sc_channelmask = port;
+
+ return (0);
+}
+
+int
+aucc_get_out_port(addr)
+ void *addr;
+{
+ struct aucc_softc *sc = addr;
+
+ return (sc->sc_channelmask);
+}
+
+int
+aucc_set_in_port(addr, port)
+ void *addr;
+ int port;
+{
+ return (EINVAL); /* no input possible */
+}
+
+int
+aucc_get_in_port(addr)
+ void *addr;
+{
+ return (0);
+}
+
+int
+aucc_commit_settings(addr)
+ void *addr;
+{
+ struct aucc_softc *sc = addr;
+ int i;
+
+ DPRINTF(("sa_commit.\n"));
+
+ for (i = 0; i < 4; i++) {
+ custom.aud[i].vol = sc->sc_channel[i].nd_volume;
+ custom.aud[i].per = sc->sc_channel[i].nd_per;
+ }
+
+ DPRINTF(("commit done\n"));
+
+ return (0);
+}
+
+static int masks[4] = {1, 3, 7, 15}; /* masks for n first channels */
+static int masks2[4] = {1, 2, 4, 8};
+
+int
+aucc_start_output(addr, p, cc, intr, arg)
+ void *addr;
+ void *p;
+ int cc;
+ void (*intr) __P((void *));
+ void *arg;
+{
+ struct aucc_softc *sc;
+ int mask;
+ int i, j, k;
+ u_short *dmap[4];
+ u_char *pp;
+
+ sc = addr;
+ mask = sc->sc_channelmask;
+
+ dmap[0] = dmap[1] = dmap[2] = dmap[3] = NULL;
+
+ DPRINTF(("sa_start_output: cc=%d %p (%p)\n", cc, intr, arg));
+
+ if (sc->sc_channels > 1)
+ mask &= masks[sc->sc_channels - 1];
+ /* we use first sc_channels channels */
+ if (mask == 0) /* active and used channels are disjoint */
+ return (EINVAL);
+
+ for (i = 0; i < 4; i++) { /* channels available ? */
+ if ((masks2[i] & mask) && (sc->sc_channel[i].nd_busy))
+ return (EBUSY); /* channel is busy */
+ if (channel[i].isaudio == -1)
+ return (EBUSY); /* system uses them */
+ }
+
+ /* enable interrupt on 1st channel */
+ for (i= j = 0; i < AUCC_MAXINT; i++) {
+ if (masks2[i] & mask) {
+ DPRINTF(("first channel is %d\n", i));
+ j = i;
+ sc->sc_channel[i].nd_intr = intr;
+ sc->sc_channel[i].nd_intrdata = arg;
+ break;
+ }
+ }
+
+ DPRINTF(("dmap is %p %p %p %p, mask=0x%x\n", dmap[0], dmap[1],
+ dmap[2], dmap[3], mask));
+
+ /*
+ * disable ints, dma for channels, until all parameters set
+ * XXX dont disable DMA! custom.dmacon = mask;
+ */
+ custom.intreq = mask << INTB_AUD0;
+ custom.intena = mask << INTB_AUD0;
+
+ /* copy data to dma buffer */
+
+ pp = (u_char *)p;
+
+ if (sc->sc_channels == 1) {
+ dmap[0] = dmap[1] = dmap[2] = dmap[3] =
+ sc->sc_channel[j].nd_dma;
+ } else {
+ for (k = 0; k < 4; k++) {
+ if (masks2[k+j] & mask)
+ dmap[k] = sc->sc_channel[k+j].nd_dma;
+ }
+ }
+
+ sc->sc_channel[j].nd_doublebuf ^= 1;
+ if (sc->sc_channel[j].nd_doublebuf) {
+ dmap[0] += AUDIO_BUF_SIZE / sizeof (u_short);
+ dmap[1] += AUDIO_BUF_SIZE / sizeof (u_short);
+ dmap[2] += AUDIO_BUF_SIZE / sizeof (u_short);
+ dmap[3] += AUDIO_BUF_SIZE / sizeof (u_short);
+ }
+
+ aucc_encode(sc->sc_encoding, sc->sc_channels, cc, pp, dmap);
+
+ /* dma buffers: we use same buffer 4 all channels */
+ /* write dma location and length */
+ for (i = k = 0; i < 4; i++) {
+ if (masks2[i] & mask) {
+ DPRINTF(("turning channel %d on\n", i));
+ /* sc->sc_channel[i].nd_busy = 1;*/
+ channel[i].isaudio = 1;
+ channel[i].play_count = 1;
+ channel[i].handler = NULL;
+ custom.aud[i].per = sc->sc_channel[i].nd_per;
+ custom.aud[i].vol = sc->sc_channel[i].nd_volume;
+ custom.aud[i].lc = PREP_DMA_MEM(dmap[k++]);
+ custom.aud[i].len = cc / (sc->sc_channels * 2);
+ sc->sc_channel[i].nd_mask = mask;
+ DPRINTF(("per is %d, vol is %d, len is %d\n",\
+ sc->sc_channel[i].nd_per,
+ sc->sc_channel[i].nd_volume, cc >> 1));
+
+ }
+ }
+
+ channel[j].handler = aucc_inthdl;
+
+ /* enable ints */
+ custom.intena = INTF_SETCLR|INTF_INTEN|(masks2[j] << INTB_AUD0);
+
+ DPRINTF(("enabled ints: 0x%x\n", (masks2[j] << INTB_AUD0)));
+
+ /* enable dma */
+ custom.dmacon = DMAF_SETCLR|DMAF_MASTER|mask;
+
+ DPRINTF(("enabled dma, mask=0x%x\n",mask));
+
+ return (0);
+}
+
+/* ARGSUSED */
+int
+aucc_start_input(addr, p, cc, intr, arg)
+ void *addr;
+ void *p;
+ int cc;
+ void (*intr) __P((void *));
+ void *arg;
+{
+ return (ENXIO); /* no input */
+}
+
+int
+aucc_halt_output(addr)
+ void *addr;
+{
+ struct aucc_softc *sc = addr;
+ int i;
+
+ /* XXX only halt, if input is also halted ?? */
+ /* stop dma, etc */
+ custom.intena = AUCC_ALLINTF;
+ custom.dmacon = AUCC_ALLDMAF;
+ /* mark every busy unit idle */
+ for (i = 0; i < 4; i++) {
+ sc->sc_channel[i].nd_busy = sc->sc_channel[i].nd_mask = 0;
+ channel[i].isaudio = 0;
+ channel[i].play_count = 0;
+ }
+
+ return (0);
+}
+
+int
+aucc_halt_input(addr)
+ void *addr;
+{
+ /* no input */
+
+ return (ENXIO);
+}
+
+int
+aucc_cont_output(addr)
+ void *addr;
+{
+ DPRINTF(("aucc_cont_output: never called, what should it do?!\n"));
+ /* reenable DMA XXX */
+ return (ENXIO);
+}
+
+int
+aucc_cont_input(addr)
+ void *addr;
+{
+ DPRINTF(("aucc_cont_input: never called, what should it do?!\n"));
+ return (0);
+}
+
+int
+aucc_getdev(addr, retp)
+ void *addr;
+ struct audio_device *retp;
+{
+ *retp = aucc_device;
+ return (0);
+}
+
+int
+aucc_set_port(addr, cp)
+ void *addr;
+ mixer_ctrl_t *cp;
+{
+ struct aucc_softc *sc = addr;
+ int i,j;
+
+ DPRINTF(("aucc_set_port: port=%d", cp->dev));
+
+ switch (cp->type) {
+ case AUDIO_MIXER_SET:
+ if (cp->dev != AUCC_CHANNELS)
+ return (EINVAL);
+ i = cp->un.mask;
+ if ((i < 1) || (i > 15))
+ return (EINVAL);
+ sc->sc_channelmask = i;
+ break;
+
+ case AUDIO_MIXER_VALUE:
+ i = cp->un.value.num_channels;
+ if ((i < 1) || (i > 4))
+ return (EINVAL);
+
+#ifdef __XXXwhatsthat
+ if (cp->dev != AUCC_VOLUME)
+ return (EINVAL);
+#endif
+
+ /* set volume for channel 0..i-1 */
+ if (i > 1)
+ for (j = 0; j < i; j++)
+ sc->sc_channel[j].nd_volume =
+ cp->un.value.level[j] >> 2;
+ else if (sc->sc_channels > 1)
+ for (j = 0; j < sc->sc_channels; j++)
+ sc->sc_channel[j].nd_volume =
+ cp->un.value.level[0] >> 2;
+ else
+ for (j = 0; j < 4; j++)
+ sc->sc_channel[j].nd_volume =
+ cp->un.value.level[0] >> 2;
+ break;
+
+ default:
+ return (EINVAL);
+ break;
+ }
+ return (0);
+}
+
+int
+aucc_get_port(addr, cp)
+ void *addr;
+ mixer_ctrl_t *cp;
+{
+ struct aucc_softc *sc = addr;
+ int i, j;
+
+ DPRINTF(("aucc_get_port: port=%d", cp->dev));
+
+ switch (cp->type) {
+ case AUDIO_MIXER_SET:
+ if (cp->dev != AUCC_CHANNELS)
+ return (EINVAL);
+ cp->un.mask = sc->sc_channelmask;
+ break;
+
+ case AUDIO_MIXER_VALUE:
+ i = cp->un.value.num_channels;
+ if ((i < 1) || (i > 4))
+ return (EINVAL);
+
+ for (j = 0; j < i; j++)
+ cp->un.value.level[j] =
+ (sc->sc_channel[j].nd_volume << 2) +
+ (sc->sc_channel[j].nd_volume >> 4);
+ break;
+
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+int
+aucc_get_props(addr)
+ void *addr;
+{
+ return 0;
+}
+
+int
+aucc_query_devinfo(addr, dip)
+ void *addr;
+ register mixer_devinfo_t *dip;
+{
+ int i;
+
+ switch (dip->index) {
+ case AUCC_CHANNELS:
+ dip->type = AUDIO_MIXER_SET;
+ dip->mixer_class = AUCC_OUTPUT_CLASS;
+ dip->prev = dip->next = AUDIO_MIXER_LAST;
+ strcpy(dip->label.name, AudioNspeaker);
+ for (i = 0; i < 16; i++) {
+ sprintf(dip->un.s.member[i].label.name,
+ "channelmask%d", i);
+ dip->un.s.member[i].mask = i;
+ }
+ dip->un.s.num_mem = 16;
+ break;
+
+ case AUCC_VOLUME:
+ dip->type = AUDIO_MIXER_VALUE;
+ dip->mixer_class = AUCC_OUTPUT_CLASS;
+ dip->prev = dip->next = AUDIO_MIXER_LAST;
+ strcpy(dip->label.name, AudioNspeaker);
+ dip->un.v.num_channels = 4;
+ strcpy(dip->un.v.units.name, AudioNvolume);
+ break;
+
+ case AUCC_OUTPUT_CLASS:
+ dip->type = AUDIO_MIXER_CLASS;
+ dip->mixer_class = AUCC_OUTPUT_CLASS;
+ dip->next = dip->prev = AUDIO_MIXER_LAST;
+ strcpy(dip->label.name, AudioCOutputs);
+ break;
+ default:
+ return (ENXIO);
+ /*NOTREACHED*/
+ }
+
+ DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
+
+ return (0);
+}
+
+
+/* audio int handler */
+void
+aucc_inthdl(ch)
+ int ch;
+{
+ int i;
+ int mask = aucc->sc_channel[ch].nd_mask;
+
+ /*
+ * For all channels in this maskgroup:
+ * disable dma, int
+ * mark idle
+ */
+ DPRINTF(("inthandler called, channel %d, mask 0x%x\n", ch, mask));
+
+ custom.intreq = mask << INTB_AUD0; /* clear request */
+
+ /*
+ * XXX: maybe we can leave ints and/or DMA on, if another sample has
+ * to be played?
+ */
+ custom.intena = mask << INTB_AUD0;
+
+ /*
+ * XXX custom.dmacon = mask; NO!!!
+ */
+ for (i = 0; i < 4; i++) {
+ if (masks2[i] && mask) {
+ DPRINTF(("marking channel %d idle\n", i));
+ aucc->sc_channel[i].nd_busy = 0;
+ aucc->sc_channel[i].nd_mask = 0;
+ channel[i].isaudio = channel[i].play_count = 0;
+ }
+ }
+
+ /* call handler */
+ if (aucc->sc_channel[ch].nd_intr) {
+ DPRINTF(("calling %p\n",aucc->sc_channel[ch].nd_intr));
+ (*(aucc->sc_channel[ch].nd_intr))(
+ aucc->sc_channel[ch].nd_intrdata);
+ } else
+ DPRINTF(("zero int handler\n"));
+ DPRINTF(("ints done\n"));
+}
+
+/* transform frequency to period, adjust bounds */
+u_int
+freqtoper(freq)
+ u_int freq;
+{
+ u_int per = eclockfreq * 5 / freq;
+
+ if (per < 124)
+ per = 124; /* must have at least 124 ticks between samples */
+
+ return per;
+}
+
+/* transform period to frequency */
+u_int
+pertofreq(per)
+ u_int per;
+{
+ u_int freq = eclockfreq * 5 / per;
+
+ return freq;
+}
+
+void
+aucc_encode(enc, channels, i, p, dmap)
+ int enc, channels, i;
+ u_char *p;
+ u_short **dmap;
+{
+ char *q, *r, *s, *t;
+ int off;
+ u_char *tab;
+#ifdef AUCCDEBUG
+ static int debctl = 6;
+#endif
+
+ off = 0;
+ tab = NULL;
+
+#ifdef AUCCDEBUG
+ if (--debctl >= 0)
+ printf("Enc: enc %d, chan %d, dmap %p %p %p %p\n",
+ enc, channels, dmap[0], dmap[1], dmap[2], dmap[3]);
+#endif
+
+ switch (enc) {
+ case AUDIO_ENCODING_ULAW:
+ tab = ulaw_to_lin;
+ break;
+ case AUDIO_ENCODING_ULINEAR_BE:
+ case AUDIO_ENCODING_ULINEAR_LE:
+ off = -128;
+ break;
+ case AUDIO_ENCODING_SLINEAR_BE:
+ case AUDIO_ENCODING_SLINEAR_LE:
+ break;
+ default:
+ return;
+ }
+
+ q = (char *)dmap[0];
+ r = (char *)dmap[1];
+ s = (char *)dmap[2];
+ t = (char *)dmap[3];
+
+ if (tab)
+ while (i) {
+ switch (channels) {
+ case 4: *t++ = tab[*p++];
+ case 3: *s++ = tab[*p++];
+ case 2: *r++ = tab[*p++];
+ case 1: *q++ = tab[*p++];
+ }
+ i -= channels;
+ }
+ else
+ while (i) {
+ switch (channels) {
+ case 4: *t++ = *p++ + off;
+ case 3: *s++ = *p++ + off;
+ case 2: *r++ = *p++ + off;
+ case 1: *q++ = *p++ + off;
+ }
+ i -= channels;
+ }
+
+}
+
+#endif /* NAUCC > 0 */