/* $OpenBSD: aria.c,v 1.13 2006/05/11 18:50:18 miod Exp $ */ /* * Copyright (c) 1995, 1996 Roland C. Dowdeswell. 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 Roland C. Dowdeswell. * 4. The name of the authors may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. */ /* * TODO: * o Test the driver on cards other than a single * Prometheus Aria 16. * o Look into where aria_prometheus_kludge() belongs. * o Add some dma code. It accomplishes its goal by * direct IO at the moment. * o Look into return values on aria_set_sr(), if there is * no matching rate. (I think that this behaves in the * same way as sbdsp.c) * o Different programs should be able to open the device * with O_RDONLY and O_WRONLY at the same time. But I * do not see support for this in /sys/dev/audio.c, so * I cannot effectively code it. * o Separate the debugging code, with a #define. * Write more into aria_printsc(). * o Rework the mixer interface. * o Deal with the lvls better. We need to do better mapping * between logarithmic scales and the one byte that * we are passed. * o Deal better with cards that have no mixer. * * roland@imrryr.org * update from http://www.imrryr.org/NetBSD/hacks/aria/ */ #include "aria.h" #if NARIA > 0 #include <sys/param.h> #include <sys/systm.h> #include <sys/errno.h> #include <sys/ioctl.h> #include <sys/syslog.h> #include <sys/device.h> #include <sys/proc.h> #include <sys/buf.h> #include <machine/cpu.h> #include <machine/pio.h> #include <sys/audioio.h> #include <dev/audio_if.h> #include <dev/mulaw.h> #include <dev/isa/isavar.h> #include <dev/isa/isadmavar.h> #include <dev/isa/ariareg.h> #define FREAD 1 #define FWRITE 2 #ifdef AUDIO_DEBUG extern void Dprintf(const char *, ...); #define DPRINTF(x) if (ariadebug) Dprintf x int ariadebug = 0; #else #define DPRINTF(x) #endif struct aria_mixdev_info { u_char num_channels; u_char level[2]; u_char mute; }; struct aria_mixmaster { u_char num_channels; u_char level[2]; u_char treble[2]; u_char bass[2]; }; struct aria_softc { struct device sc_dev; /* base device */ struct isadev sc_id; /* ISA device */ void *sc_ih; /* interrupt vectoring */ u_short sc_iobase; /* I/O port base address */ u_short sc_irq; /* interrupt */ u_short sc_drq; /* dma chan */ u_short sc_open; /* reference count of open calls */ u_short sc_play; /* non-paused play chans 2**chan */ u_short sc_record; /* non-paused record chans 2**chan */ u_short sc_change; /* to keep track of changes of a type */ u_short gain[2]; /* left/right gain (play) */ u_int spkr_state; /* non-null is on */ u_long sc_rate; /* Sample rate for input and output */ u_int sc_encoding; /* audio encoding -- ulaw/linear */ int sc_chans; /* # of channels */ int sc_precision; /* # bits per sample */ u_long sc_interrupts; /* number of interrupts taken */ void (*sc_rintr)(void *); /* record transfer completion intr handler */ void (*sc_pintr)(void *); /* play transfer completion intr handler */ void *sc_rarg; /* arg for sc_rintr() */ void *sc_parg; /* arg for sc_pintr() */ int sc_blocksize; /* literal dio block size */ void *sc_rdiobuffer; /* record: where the next samples should be */ void *sc_pdiobuffer; /* play: where the next samples are */ u_short sc_hardware; /* bit field of hardware present */ #define ARIA_TELEPHONE 0x0001 /* has telephone input */ #define ARIA_MIXER 0x0002 /* has SC18075 digital mixer */ #define ARIA_MODEL 0x0004 /* is SC18025 (=0) or SC18026 (=1) */ struct aria_mixdev_info aria_mix[6]; struct aria_mixmaster ariamix_master; u_char aria_mix_source; }; struct { int sendcmd; int wmidi; } ariaerr; int ariaprobe(); void ariaattach(struct device *, struct device *, void *); void ariaclose(void *); int ariaopen(dev_t, int); int aria_getdev(void *, struct audio_device *); void aria_do_kludge(u_short, u_short, u_short, u_short, u_short); void aria_prometheus_kludge(struct isa_attach_args *); int aria_set_sr(void *, u_long); u_long aria_get_sr(void *); int aria_query_encoding(void *, struct audio_encoding *); int aria_set_format(void *, u_int, u_int); int aria_get_encoding(void *); int aria_get_precision(void *); int aria_set_channels(void *, int); int aria_get_channels(void *); int aria_round_blocksize(void *, int); int aria_set_out_port(void *, int); int aria_get_out_port(void *); int aria_set_in_port(void *, int); int aria_get_in_port(void *); int aria_speaker_ctl(void *, int); int aria_commit_settings(void *); int aria_start_output(void *, void *, int, void (*)(), void *); int aria_start_input(void *, void *, int, void (*)(), void *); int aria_halt_input(void *); int aria_halt_output(void *); int aria_cont(void *); int aria_sendcmd(u_short, u_short, int, int, int); u_short aria_getdspmem(u_short, u_short); u_short aria_putdspmem(u_short, u_short, u_short); int aria_intr(void *); short ariaversion(struct aria_softc *); int aria_setfd(void *, int); void aria_mix_write(struct aria_softc *, int, int); int aria_mix_read(struct aria_softc *, int); int aria_mixer_set_port(void *, mixer_ctrl_t *); int aria_mixer_get_port(void *, mixer_ctrl_t *); int aria_mixer_query_devinfo(void *, mixer_devinfo_t *); /* * Mixer defines... */ struct cfattach aria_ca = { sizeof(struct aria_softc), ariaprobe, ariaattach }; struct cfdriver aria_cd = { NULL, "aria", DV_DULL }; struct audio_device aria_device = { "Aria 16(se)", "x", "aria" }; /* * Define our interface to the higher level audio driver. */ struct audio_hw_if aria_hw_if = { ariaopen, ariaclose, NULL, aria_set_sr, aria_get_sr, aria_set_sr, aria_get_sr, aria_query_encoding, aria_set_format, aria_get_encoding, aria_get_precision, aria_set_channels, aria_get_channels, aria_round_blocksize, aria_set_out_port, aria_get_out_port, aria_set_in_port, aria_get_in_port, aria_commit_settings, mulaw_expand, mulaw_compress, aria_start_output, aria_start_input, aria_halt_input, aria_halt_output, aria_cont, aria_cont, aria_speaker_ctl, aria_getdev, aria_setfd, aria_mixer_set_port, aria_mixer_get_port, aria_mixer_query_devinfo, 1, /* full-duplex */ 0, NULL, NULL }; /* * Probe / attach routines. */ /* * Probe for the aria hardware. */ int ariaprobe(parent, self, aux) struct device *parent, *self; void *aux; { register struct aria_softc *sc = (void *)self; register struct isa_attach_args *ia = aux; struct cfdata *cf = sc->sc_dev.dv_cfdata; register u_short iobase = ia->ia_iobase; static u_char irq_conf[11] = { -1, -1, 0x01, -1, -1, 0x02, -1, 0x04, -1, 0x01, 0x08 }; int i,j; int flags = cf->cf_flags; if (!ARIA_BASE_VALID(ia->ia_iobase)) { printf("aria: configured iobase %d invalid\n", ia->ia_iobase); return 0; } sc->sc_iobase = iobase; if (!ARIA_IRQ_VALID(ia->ia_irq)) { printf("aria: configured irq %d invalid\n", ia->ia_irq); return 0; } sc->sc_irq = ia->ia_irq; if (flags & ARIAR_PROMETHEUS_KLUDGE) aria_prometheus_kludge(ia); if (aria_reset(sc) != 0) { DPRINTF(("aria: aria probe failed\n")); return 0; } ia->ia_iosize = ARIADSP_NPORT; return 1; } /* * I didn't call this a kludge for * nothing. This is cribbed from * ariainit, the author of that * disassembled some code to discover * how to set up the initial values of * the card. Without this, the card * is dead. (It will not respond to _any_ * input at all.) * * ariainit can be found (ftp) at: * ftp://ftp.wi.leidenuniv.nl/pub/audio/aria/programming/contrib/ariainit.zip * currently. */ void aria_prometheus_kludge(ia) register struct isa_attach_args *ia; { int i, j; u_short end; u_short rba = ia->ia_iobase; DPRINTF(("aria_prometheus_kludge\n")); /* Begin Config Sequence */ outb(0x204, 0x4c); outb(0x205, 0x42); outb(0x206, 0x00); outw(0x200, 0x0f); outb(0x201, 0x00); outw(0x200, 0x02); outb(0x201, rba>>2); /* These next three lines set up the iobase, and the irq; and disable the drq. */ aria_do_kludge(0x111, ((ia->ia_iobase-0x280)>>2)+0xA0, 0xbf, 0xa0, rba); aria_do_kludge(0x011, ia->ia_irq-6, 0xf8, 0x00, rba); aria_do_kludge(0x011, 0x00, 0xef, 0x00, rba); /* The rest of these lines just disable everything else */ aria_do_kludge(0x113, 0x00, 0x88, 0x00, rba); aria_do_kludge(0x013, 0x00, 0xf8, 0x00, rba); aria_do_kludge(0x013, 0x00, 0xef, 0x00, rba); aria_do_kludge(0x117, 0x00, 0x88, 0x00, rba); aria_do_kludge(0x017, 0x00, 0xff, 0x00, rba); /* End Sequence */ outb(0x200, 0x0f); end = inb(rba); outw(0x200, 0x0f); outb(0x201, end|0x80); inb(0x200); /* * This delay is necessary for some reason, * at least it would crash, and sometimes not * probe properly if it did not exist. */ delay(1000000); } void aria_do_kludge(func, bits, and, or, rba) u_short func; u_short bits; u_short and; u_short or; u_short rba; { u_int i; if (func & 0x100) { func &= ~0x100; if (bits) { outw(0x200, func-1); outb(0x201, bits); } } else or |= bits; outb(0x200, func); i = inb(rba); outw(0x200, func); outb(0x201, (i&and) | or); } /* * Attach hardware to driver, attach hardware driver to audio * pseudo-device driver. */ void ariaattach(parent, self, aux) struct device *parent, *self; void *aux; { register struct aria_softc *sc = (struct aria_softc *)self; struct isa_attach_args *ia = (struct isa_attach_args *)aux; register u_short iobase = ia->ia_iobase; register u_short i; int err; sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, IPL_AUDIO, aria_intr, sc, sc->sc_dev.dv_xname); i = aria_getdspmem(iobase, ARIAA_HARDWARE_A); sc->sc_hardware = 0; sc->sc_hardware |= ((i>>13)&0x01==1)?ARIA_TELEPHONE:0; sc->sc_hardware |= (((i>>5)&0x07)==0x04)?ARIA_MIXER:0; sc->sc_hardware |= (aria_getdspmem(iobase, ARIAA_MODEL_A)==1)?ARIA_MODEL:0; sc->sc_open = 0; sc->sc_play = 0; sc->sc_record = 0; sc->sc_rate = 7875; sc->sc_chans = 1; sc->sc_change = 1; sc->sc_blocksize = 1024; sc->sc_precision = 8; sc->sc_rintr = 0; sc->sc_rarg = 0; sc->sc_pintr = 0; sc->sc_parg = 0; sc->gain[0] = 127; sc->gain[1] = 127; for (i=0; i<6; i++) { if (i == ARIAMIX_TEL_LVL) sc->aria_mix[i].num_channels = 1; else sc->aria_mix[i].num_channels = 2; sc->aria_mix[i].level[0] = 127; sc->aria_mix[i].level[1] = 127; } sc->ariamix_master.num_channels = 2; sc->ariamix_master.level[0] = 222; sc->ariamix_master.level[1] = 222; sc->ariamix_master.bass[0] = 127; sc->ariamix_master.bass[1] = 127; sc->ariamix_master.treble[0] = 127; sc->ariamix_master.treble[1] = 127; sc->aria_mix_source = 0; sc->sc_change = 1; aria_commit_settings(sc); /* so that my cdplayer is at the 'right' vol */ printf(": dsp %s", (ARIA_MODEL&sc->sc_hardware)?"SC18026":"SC18025"); if (ARIA_TELEPHONE&sc->sc_hardware) printf(", tel"); if (ARIA_MIXER&sc->sc_hardware) printf(", SC18075 mixer"); printf("\n"); snprintf(aria_device.version, sizeof aria_device.version, "%s", (ARIA_MODEL&sc->sc_hardware?"SC18026":"SC18025")); if ((err = audio_hardware_attach(&aria_hw_if, sc)) != 0) printf("aria: could not attach to audio pseudo-device driver (%d)\n", err); } /* * Various routines to interface to higher level audio driver */ int ariaopen(dev, flags) dev_t dev; int flags; { struct aria_softc *sc; register u_short iobase = sc->sc_iobase; int unit = AUDIOUNIT(dev); short err; DPRINTF(("ariaopen() called\n")); if (unit >= aria_cd.cd_ndevs) return ENXIO; sc = aria_cd.cd_devs[unit]; if (!sc || sc->sc_open != 0) return ENXIO; sc->sc_open = 0; if (flags&FREAD) sc->sc_open |= ARIAR_OPEN_RECORD; if (flags&FWRITE) sc->sc_open |= ARIAR_OPEN_PLAY; sc->sc_play = 0; sc->sc_record= 0; sc->sc_rintr = 0; sc->sc_rarg = 0; sc->sc_pintr = 0; sc->sc_parg = 0; sc->sc_change= 1; return 0; } int aria_getdev(addr, retp) void *addr; struct audio_device *retp; { *retp = aria_device; return 0; } #ifdef AUDIO_DEBUG void aria_printsc(struct aria_softc *sc) { printf("open %x dmachan %d irq %d iobase %x nintr %d\n", sc->sc_open, sc->sc_drq, sc->sc_irq, sc->sc_iobase, sc->sc_interrupts); printf("irate %d encoding %x chans %d\n", sc->sc_rate, sc->encoding, sc->sc_chans); printf("\n"); } #endif /* * Various routines to interface to higher level audio driver */ int aria_set_sr(addr, sr) void *addr; u_long sr; { struct aria_softc *sc = addr; if (sr<=9000) sr = 7875; else if (sr<=15000) sr = 11025; else if (sr<=20000) sr = 15750; else if (sr<=25000) sr = 22050; else if (sr<=40000) sr = 31500; else sr = 44100; sc->sc_rate = sr; return 0; } u_long aria_get_sr(addr) void *addr; { struct aria_softc *sc = addr; return sc->sc_rate; } int aria_query_encoding(addr, fp) void *addr; struct audio_encoding *fp; { register struct aria_softc *sc = addr; switch (fp->index) { case 0: strlcpy(fp->name, AudioEmulaw, sizeof fp->name); fp->format_id = AUDIO_ENCODING_ULAW; break; case 1: strlcpy(fp->name, AudioEpcm16, sizeof fp->name); fp->format_id = AUDIO_ENCODING_PCM16; break; default: return(EINVAL); /*NOTREACHED*/ } return (0); } int aria_set_format(addr, enc, precision) void *addr; u_int enc, prec; { register struct aria_softc *sc = addr; DPRINTF(("aria_set_format\n")); switch(enc){ case AUDIO_ENCODING_ULAW: case AUDIO_ENCODING_PCM16: case AUDIO_ENCODING_PCM8: break; default: return (EINVAL); } if (prec!=8 && prec!=16) return (EINVAL); if (sc->encoding!=AUDIO_ENCODING_PCM16 && prec==16) return (EINVAL); sc->sc_encoding = enc; sc->sc_precision = prec; return (0); } int aria_get_encoding(addr) void *addr; { register struct aria_softc *sc = addr; DPRINTF(("aria_get_encoding\n")); return(sc->encoding); } int aria_get_precision(addr) void *addr; { struct aria_softc *sc = addr; DPRINTF(("aria_get_precision\n")); return sc->sc_precision; } int aria_set_channels(addr, chans) void *addr; int chans; { struct aria_softc *sc = addr; DPRINTF(("aria_set_channels\n")); if (chans != 1 && chans != 2) return EINVAL; sc->sc_chans = chans; return(0); } int aria_get_channels(addr) void *addr; { struct aria_softc *sc = addr; DPRINTF(("aria_get_channels\n")); return sc->sc_chans; } /* * There is only one way to output on * this card. */ int aria_set_out_port(addr, port) void *addr; int port; { DPRINTF(("aria_set_out_port\n")); return(0); } int aria_get_out_port(addr) void *addr; { DPRINTF(("aria_get_out_port\n")); return(ARIAMIX_OUT_LVL); } int aria_set_in_port(addr, port) void *addr; int port; { register struct aria_softc *sc = addr; DPRINTF(("aria_set_in_port\n")); if (port<0 || port>6) return ENXIO; sc->aria_mix_source = port; return(0); } int aria_get_in_port(addr) void *addr; { register struct aria_softc *sc = addr; DPRINTF(("aria_get_in_port\n")); return(sc->aria_mix_source); } /* * XXX -- to be done * I should probably just add a mixer thing, and * access it through here. */ int aria_speaker_ctl(addr, newstate) void *addr; int newstate; { return(0); } /* * Store blocksize in words (what the chipset * understands), but report and take values * in bytes. */ int aria_round_blocksize(addr, blk) void *addr; int blk; { int i; struct aria_softc *sc = addr; for (i=64; i<1024; i*=2) if (blk <= i) break; sc->sc_blocksize = i; sc->sc_change = 1; return(i); } /* * This is where all of the twiddling goes on. */ int aria_commit_settings(addr) void *addr; { struct aria_softc *sc = addr; register u_short iobase = sc->sc_iobase; u_char tones[16] = { 7, 6, 5, 4, 3, 2, 1, 0, 8, 9, 10, 11, 12, 13, 14, 15 }; u_short format; u_short left, right; u_short samp; u_char i; DPRINTF(("aria_commit_settings\n")); switch (sc->sc_rate) { case 7875: format = 0x00; samp = 0x60; break; case 11025: format = 0x00; samp = 0x40; break; case 15750: format = 0x10; samp = 0x60; break; case 22050: format = 0x10; samp = 0x40; break; case 31500: format = 0x10; samp = 0x20; break; case 44100: format = 0x20; samp = 0x00; break; default: format = 0x00; samp = 0x40; break; } format |= (sc->sc_chans==2)?1:0; format |= (sc->sc_precision==16)?2:0; aria_sendcmd(iobase, ARIADSPC_FORMAT, format, -1, -1); outw(iobase+ARIADSP_CONTROL, (inw(iobase+ARIADSP_STATUS)&~0x60)|samp); /* Addition parm for sample rate */ if (sc->sc_hardware&ARIA_MIXER) { for (i=0; i<6; i++) { u_char source; switch(i) { case ARIAMIX_MIC_LVL: source = 0x0001; break; case ARIAMIX_CD_LVL: source = 0x0002; break; case ARIAMIX_LINE_IN_LVL: source = 0x0008; break; case ARIAMIX_TEL_LVL: source = 0x0020; break; case ARIAMIX_AUX_LVL: source = 0x0010; break; case ARIAMIX_DAC_LVL: source = 0x0004; break; default: source = 0x0000; break; } if (source != 0x0000 && source != 0x0004) { if (sc->aria_mix[i].mute == 1) aria_sendcmd(iobase, ARIADSPC_INPMONMODE, source, 3, -1); else aria_sendcmd(iobase, ARIADSPC_INPMONMODE, source, (sc->aria_mix[i].num_channels==2)?0:1, -1); aria_sendcmd(iobase, ARIADSPC_INPMONMODE, 0x8000|source, (sc->aria_mix[i].num_channels==2)?0:1, -1); aria_sendcmd(iobase, ARIADSPC_MIXERVOL, source, sc->aria_mix[i].level[0] << 7, sc->aria_mix[i].level[1] << 7); } if (sc->aria_mix_source == i) { aria_sendcmd(iobase, ARIADSPC_ADCSOURCE, source, -1, -1); if (sc->sc_open & ARIAR_OPEN_RECORD) aria_sendcmd(iobase, ARIADSPC_ADCCONTROL, 1, -1, -1); else aria_sendcmd(iobase, ARIADSPC_ADCCONTROL, 0, -1, -1); } } if (sc->sc_chans==2) { aria_sendcmd(iobase, ARIADSPC_CHAN_VOL, (sc->gain[0]+sc->gain[1])/2, -1, -1); aria_sendcmd(iobase, ARIADSPC_CHAN_PAN, (sc->gain[0]-sc->gain[1])/4+0x40, -1, -1); } else { aria_sendcmd(iobase, ARIADSPC_CHAN_VOL, sc->gain[0], -1, -1); aria_sendcmd(iobase, ARIADSPC_CHAN_PAN, 0x40, -1, -1); } /* aria_sendcmd(iobase, ARIADSPC_MASMONMODE, (sc->ariamix_master.num_channels==2)?0:1 | (1<<8), -1, -1); */ aria_sendcmd(iobase, ARIADSPC_MASMONMODE, (sc->ariamix_master.num_channels==2)?0:1, -1, -1); aria_sendcmd(iobase, ARIADSPC_MIXERVOL, 0x0004, sc->ariamix_master.level[0] << 7, sc->ariamix_master.level[1] << 7); /* Convert treb/bass from byte to soundcard style */ left = tones[(sc->ariamix_master.bass[0]>>4)&0x0f]<<8 | tones[(sc->ariamix_master.treble[0]>>4)&0x0f]; right = tones[(sc->ariamix_master.bass[1]>>4)&0x0f]<<8 | tones[(sc->ariamix_master.treble[1]>>4)&0x0f]; aria_sendcmd(iobase, ARIADSPC_TONE, left, right, -1); } if (sc->sc_change != 0) aria_sendcmd(iobase, ARIADSPC_BLOCKSIZE, sc->sc_blocksize/2, -1, -1); /* * If we think that the card is recording or playing, start it up again here. * Some of the previous commands turn the channels off. */ if (sc->sc_record&(1<<ARIAR_RECORD_CHAN)) { aria_sendcmd(iobase, ARIADSPC_START_REC, ARIAR_PLAY_CHAN, -1, -1); sc->sc_play |= (1<<ARIAR_RECORD_CHAN); } if (sc->sc_play&(1<<ARIAR_PLAY_CHAN)) { aria_sendcmd(iobase, ARIADSPC_START_PLAY, ARIAR_PLAY_CHAN, -1, -1); sc->sc_play |= (1<<ARIAR_PLAY_CHAN); } sc->sc_change = 0; return(0); } void ariaclose(addr) void *addr; { struct aria_softc *sc = addr; register u_int iobase = sc->sc_iobase; DPRINTF(("aria_close sc=0x%x\n", sc)); sc->spkr_state = SPKR_OFF; sc->sc_rintr = 0; sc->sc_pintr = 0; sc->sc_rdiobuffer = 0; sc->sc_pdiobuffer = 0; if (sc->sc_play&(1<<ARIAR_PLAY_CHAN) && sc->sc_open & ARIAR_OPEN_PLAY) { aria_sendcmd(iobase, ARIADSPC_STOP_PLAY, ARIAR_PLAY_CHAN, -1, -1); sc->sc_play &= ~(1<<ARIAR_PLAY_CHAN); } if (sc->sc_record&(1<<ARIAR_RECORD_CHAN) && sc->sc_open & ARIAR_OPEN_RECORD) { aria_sendcmd(iobase, ARIADSPC_STOP_REC, ARIAR_RECORD_CHAN, -1, -1); sc->sc_record &= ~(1<<ARIAR_RECORD_CHAN); } sc->sc_open = 0; if (aria_reset(sc) != 0) { delay(500); aria_reset(sc); } } /* * Reset the hardware. */ int aria_reset(sc) register struct aria_softc *sc; { register u_short iobase = sc->sc_iobase; int fail=0; outw(iobase + ARIADSP_CONTROL, ARIAR_ARIA_SYNTH|ARIAR_SR22K|ARIAR_DSPINTWR); aria_putdspmem(iobase, 0x6102, 0); fail |= aria_sendcmd(iobase, ARIADSPC_SYSINIT, 0x0000, 0x0000, 0x0000); while (aria_getdspmem(iobase, ARIAA_TASK_A) != 1) ; outw(iobase+ARIADSP_CONTROL, ARIAR_ARIA_SYNTH|ARIAR_SR22K|ARIAR_DSPINTWR|ARIAR_PCINTWR); fail |= aria_sendcmd(iobase, ARIADSPC_MODE, ARIAV_MODE_NO_SYNTH,-1,-1); return (fail); } /* * Lower-level routines */ u_short aria_putdspmem(iobase, loc, val) register u_short iobase; register u_short loc; register u_short val; { outw(iobase + ARIADSP_DMAADDRESS, loc); outw(iobase + ARIADSP_DMADATA, val); } u_short aria_getdspmem(iobase, loc) register u_short iobase; register u_short loc; { outw(iobase+ARIADSP_DMAADDRESS, loc); return inw(iobase+ARIADSP_DMADATA); } /* * aria_sendcmd() * each full DSP command is unified into this * function. */ int aria_sendcmd(iobase, command, arg1, arg2, arg3) u_short iobase; u_short command; int arg1; int arg2; int arg3; { int i, fail = 0; for (i = ARIAR_NPOLL; (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY) != 0 && i>0; i-- ) ; fail |= (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY)==0?0:1; outw(iobase + ARIADSP_WRITE, (u_short) command); if (arg1 != -1) { for (i = ARIAR_NPOLL; (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY) != 0 && i>0; i-- ) ; fail |= (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY)==0?0:2; outw(iobase + ARIADSP_WRITE, (u_short) arg1); } if (arg2 != -1) { for (i = ARIAR_NPOLL; (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY) != 0 && i>0; i-- ) ; fail |= (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY)==0?0:4; outw(iobase + ARIADSP_WRITE, (u_short) arg2); } if (arg3 != -1) { for (i = ARIAR_NPOLL; (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY) != 0 && i>0; i-- ) ; fail |= (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY)==0?0:8; outw(iobase + ARIADSP_WRITE, (u_short) arg3); } for (i = ARIAR_NPOLL; (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY) != 0 && i>0; i-- ) ; fail |= (inw(iobase + ARIADSP_STATUS) & ARIAR_BUSY)==0?0:16; outw(iobase + ARIADSP_WRITE, (u_short) ARIADSPC_TERM); #ifdef AUDIO_DEBUG if (fail) { ++ariaerr.sendcmd; DPRINTF(("aria_sendcmd: failure=(%d) cmd=(0x%x) fail=(0x%x)\n", ariaerr.sendcmd, command, fail)); return -1; } #else if (fail != 0) { ++ariaerr.sendcmd; return -1; } #endif return 0; } int aria_halt_input(addr) void *addr; { register struct aria_softc *sc = addr; DPRINTF(("aria_halt_input\n")); if (sc->sc_record&(1<<0)) { aria_sendcmd(sc->sc_iobase, ARIADSPC_STOP_REC, 0, -1, -1); sc->sc_record &= ~(1<<0); } return(0); } int aria_halt_output(addr) void *addr; { register struct aria_softc *sc = addr; DPRINTF(("aria_halt_output\n")); if (sc->sc_play & (1<<1)) { aria_sendcmd(sc->sc_iobase, ARIADSPC_STOP_PLAY, 1, -1, -1); sc->sc_play &= ~(1<<1); } return(0); } /* * This is not called in dev/audio.c? */ int aria_cont(addr) void *addr; { register struct aria_softc *sc = addr; DPRINTF(("aria_cont\n")); if (!(sc->sc_record&(1<<0)) && (sc->sc_open&ARIAR_OPEN_RECORD)) { aria_sendcmd(sc->sc_iobase, ARIADSPC_START_REC, ARIAR_RECORD_CHAN, -1, -1); sc->sc_record |= ~(1<<ARIAR_RECORD_CHAN); } if (!(sc->sc_play&(1<<ARIAR_PLAY_CHAN)) && (sc->sc_open&ARIAR_OPEN_PLAY)) { aria_sendcmd(sc->sc_iobase, ARIADSPC_START_PLAY, 1, -1, -1); sc->sc_play |= ~(1<<ARIAR_PLAY_CHAN); } return(0); } /* * Here we just set up the buffers. If we receive * an interrupt without these set, it is ignored. */ int aria_start_input(addr, p, cc, intr, arg) void *addr; void *p; int cc; void (*intr)(); void *arg; { register struct aria_softc *sc = addr; register int i; DPRINTF(("aria_start_input %d @ %x\n", cc, p)); if (cc != sc->sc_blocksize) { DPRINTF(("aria_start_input reqsize %d not sc_blocksize %d\n", cc, sc->sc_blocksize)); return EINVAL; } sc->sc_rarg = arg; sc->sc_rintr = intr; sc->sc_rdiobuffer = p; if (!(sc->sc_record&(1<<0))) { aria_sendcmd(sc->sc_iobase, ARIADSPC_START_REC, 0, -1, -1); sc->sc_record |= (1<<0); } return 0; } int aria_start_output(addr, p, cc, intr, arg) void *addr; void *p; int cc; void (*intr)(); void *arg; { register struct aria_softc *sc = addr; register int i; DPRINTF(("aria_start_output %d @ %x\n", cc, p)); if (cc != sc->sc_blocksize) { DPRINTF(("aria_start_output reqsize %d not sc_blocksize %d\n", cc, sc->sc_blocksize)); return EINVAL; } sc->sc_parg = arg; sc->sc_pintr = intr; sc->sc_pdiobuffer = p; if (!(sc->sc_play&(1<<1))) { aria_sendcmd(sc->sc_iobase, ARIADSPC_START_PLAY, 1, -1, -1); sc->sc_play |= (1<<1); } return 0; } /* * Process an interrupt. This should be a * request (from the card) to write or read * samples. */ int aria_intr(arg) void *arg; { register struct aria_softc *sc = arg; register u_short iobase = sc->sc_iobase; register u_short *pdata = sc->sc_pdiobuffer; register u_short *rdata = sc->sc_rdiobuffer; u_short address; int i; if (inw(iobase) & 1 != 0x1) return 0; /* not for us */ sc->sc_interrupts++; DPRINTF(("aria_intr\n")); if ((sc->sc_open & ARIAR_OPEN_PLAY) && (pdata!=NULL)) { DPRINTF(("aria_intr play=(%x)\n", pdata)); address = 0x8000 - 2*(sc->sc_blocksize); address+= aria_getdspmem(iobase, ARIAA_PLAY_FIFO_A); outw(iobase+ARIADSP_DMAADDRESS, address); outsw(iobase + ARIADSP_DMADATA, pdata, sc->sc_blocksize/2); if (sc->sc_pintr != NULL) (*sc->sc_pintr)(sc->sc_parg); } if ((sc->sc_open & ARIAR_OPEN_RECORD) && (rdata!=NULL)) { DPRINTF(("aria_intr record=(%x)\n", rdata)); address = 0x8000 - (sc->sc_blocksize); address+= aria_getdspmem(iobase, ARIAA_REC_FIFO_A); outw(iobase+ARIADSP_DMAADDRESS, address); insw(iobase + ARIADSP_DMADATA, rdata, sc->sc_blocksize/2); if (sc->sc_rintr != NULL) (*sc->sc_rintr)(sc->sc_rarg); } aria_sendcmd(iobase, ARIADSPC_TRANSCOMPLETE, -1, -1, -1); return 1; } int aria_setfd(addr, flag) void *addr; int flag; { /* * okay return yes. I'll assume that it will only * ask when the file open read/write... Or before... */ return(0); } int aria_mixer_set_port(addr, cp) void *addr; mixer_ctrl_t *cp; { register struct aria_softc *sc = addr; int error = EINVAL; DPRINTF(("aria_mixer_set_port\n")); if (!(ARIA_MIXER&sc->sc_hardware)) /* This could be done better, no mixer still has some controls. */ return ENXIO; if (cp->type == AUDIO_MIXER_VALUE) { register mixer_level_t *mv = &cp->un.value; switch (cp->dev) { case ARIAMIX_MIC_LVL: if (mv->num_channels == 1 || mv->num_channels == 2) { sc->aria_mix[ARIAMIX_MIC_LVL].num_channels = mv->num_channels; sc->aria_mix[ARIAMIX_MIC_LVL].level[0] = mv->level[0]; sc->aria_mix[ARIAMIX_MIC_LVL].level[1] = mv->level[1]; error = 0; } break; case ARIAMIX_LINE_IN_LVL: if (mv->num_channels == 1 || mv->num_channels == 2) { sc->aria_mix[ARIAMIX_LINE_IN_LVL].num_channels = mv->num_channels; sc->aria_mix[ARIAMIX_LINE_IN_LVL].level[0] = mv->level[0]; sc->aria_mix[ARIAMIX_LINE_IN_LVL].level[1] = mv->level[1]; error = 0; } break; case ARIAMIX_CD_LVL: if (mv->num_channels == 1 || mv->num_channels == 2) { sc->aria_mix[ARIAMIX_CD_LVL].num_channels = mv->num_channels; sc->aria_mix[ARIAMIX_CD_LVL].level[0] = mv->level[0]; sc->aria_mix[ARIAMIX_CD_LVL].level[1] = mv->level[1]; error = 0; } break; case ARIAMIX_TEL_LVL: if (mv->num_channels == 1) { sc->aria_mix[ARIAMIX_TEL_LVL].num_channels = mv->num_channels; sc->aria_mix[ARIAMIX_TEL_LVL].level[0] = mv->level[0]; error = 0; } break; case ARIAMIX_DAC_LVL: if (mv->num_channels == 1 || mv->num_channels == 2) { sc->aria_mix[ARIAMIX_DAC_LVL].num_channels = mv->num_channels; sc->aria_mix[ARIAMIX_DAC_LVL].level[0] = mv->level[0]; sc->aria_mix[ARIAMIX_DAC_LVL].level[1] = mv->level[1]; error = 0; } break; case ARIAMIX_AUX_LVL: if (mv->num_channels == 1 || mv->num_channels == 2) { sc->aria_mix[ARIAMIX_AUX_LVL].num_channels = mv->num_channels; sc->aria_mix[ARIAMIX_AUX_LVL].level[0] = mv->level[0]; sc->aria_mix[ARIAMIX_AUX_LVL].level[1] = mv->level[1]; error = 0; } break; case ARIAMIX_MASTER_LVL: if (mv->num_channels == 1 || mv->num_channels == 2) { sc->ariamix_master.num_channels = mv->num_channels; sc->ariamix_master.level[0] = mv->level[0]; sc->ariamix_master.level[1] = mv->level[1]; error = 0; } break; case ARIAMIX_MASTER_TREBLE: if (mv->num_channels == 2) { sc->ariamix_master.treble[0] = (mv->level[0]==0)?1:mv->level[0]; sc->ariamix_master.treble[1] = (mv->level[1]==0)?1:mv->level[1]; error = 0; } break; case ARIAMIX_MASTER_BASS: if (mv->num_channels == 2) { sc->ariamix_master.bass[0] = (mv->level[0]==0)?1:mv->level[0]; sc->ariamix_master.bass[1] = (mv->level[1]==0)?1:mv->level[1]; error = 0; } break; case ARIAMIX_OUT_LVL: if (mv->num_channels == 1 || mv->num_channels == 2) { sc->gain[0] = mv->level[0]; sc->gain[1] = mv->level[1]; error = 0; } break; default: } } if (cp->type == AUDIO_MIXER_ENUM) switch(cp->dev) { case ARIAMIX_RECORD_SOURCE: if (cp->un.ord>=0 && cp->un.ord<=6) { sc->aria_mix_source = cp->un.ord; error = 0; } break; case ARIAMIX_MIC_MUTE: if (cp->un.ord == 0 || cp->un.ord == 1) { sc->aria_mix[ARIAMIX_MIC_LVL].mute = cp->un.ord; error = 0; } break; case ARIAMIX_LINE_IN_MUTE: if (cp->un.ord == 0 || cp->un.ord == 1) { sc->aria_mix[ARIAMIX_LINE_IN_LVL].mute = cp->un.ord; error = 0; } break; case ARIAMIX_CD_MUTE: if (cp->un.ord == 0 || cp->un.ord == 1) { sc->aria_mix[ARIAMIX_CD_LVL].mute = cp->un.ord; error = 0; } break; case ARIAMIX_DAC_MUTE: if (cp->un.ord == 0 || cp->un.ord == 1) { sc->aria_mix[ARIAMIX_DAC_LVL].mute = cp->un.ord; error = 0; } break; case ARIAMIX_AUX_MUTE: if (cp->un.ord == 0 || cp->un.ord == 1) { sc->aria_mix[ARIAMIX_AUX_LVL].mute = cp->un.ord; error = 0; } break; case ARIAMIX_TEL_MUTE: if (cp->un.ord == 0 || cp->un.ord == 1) { sc->aria_mix[ARIAMIX_TEL_LVL].mute = cp->un.ord; error = 0; } break; default: return ENXIO; /* NOTREACHED */ } return(error); } int aria_mixer_get_port(addr, cp) void *addr; mixer_ctrl_t *cp; { register struct aria_softc *sc = addr; int error = EINVAL; DPRINTF(("aria_mixer_get_port\n")); if (!(ARIA_MIXER&sc->sc_hardware)) /* This could be done better, no mixer still has some controls. */ return ENXIO; switch (cp->dev) { case ARIAMIX_MIC_LVL: if (cp->type == AUDIO_MIXER_VALUE) { cp->un.value.num_channels = sc->aria_mix[ARIAMIX_MIC_LVL].num_channels; cp->un.value.level[0] = sc->aria_mix[ARIAMIX_MIC_LVL].level[0]; cp->un.value.level[1] = sc->aria_mix[ARIAMIX_MIC_LVL].level[1]; error = 0; } break; case ARIAMIX_LINE_IN_LVL: if (cp->type == AUDIO_MIXER_VALUE) { cp->un.value.num_channels = sc->aria_mix[ARIAMIX_LINE_IN_LVL].num_channels; cp->un.value.level[0] = sc->aria_mix[ARIAMIX_LINE_IN_LVL].level[0]; cp->un.value.level[1] = sc->aria_mix[ARIAMIX_LINE_IN_LVL].level[1]; error = 0; } break; case ARIAMIX_CD_LVL: if (cp->type == AUDIO_MIXER_VALUE) { cp->un.value.num_channels = sc->aria_mix[ARIAMIX_CD_LVL].num_channels; cp->un.value.level[0] = sc->aria_mix[ARIAMIX_CD_LVL].level[0]; cp->un.value.level[1] = sc->aria_mix[ARIAMIX_CD_LVL].level[1]; error = 0; } break; case ARIAMIX_TEL_LVL: if (cp->type == AUDIO_MIXER_VALUE) { cp->un.value.num_channels = sc->aria_mix[ARIAMIX_TEL_LVL].num_channels; cp->un.value.level[0] = sc->aria_mix[ARIAMIX_TEL_LVL].level[0]; error = 0; } break; case ARIAMIX_DAC_LVL: if (cp->type == AUDIO_MIXER_VALUE) { cp->un.value.num_channels = sc->aria_mix[ARIAMIX_DAC_LVL].num_channels; cp->un.value.level[0] = sc->aria_mix[ARIAMIX_DAC_LVL].level[0]; cp->un.value.level[1] = sc->aria_mix[ARIAMIX_DAC_LVL].level[1]; error = 0; } break; case ARIAMIX_AUX_LVL: if (cp->type == AUDIO_MIXER_VALUE) { cp->un.value.num_channels = sc->aria_mix[ARIAMIX_AUX_LVL].num_channels; cp->un.value.level[0] = sc->aria_mix[ARIAMIX_AUX_LVL].level[0]; cp->un.value.level[1] = sc->aria_mix[ARIAMIX_AUX_LVL].level[1]; error = 0; } break; case ARIAMIX_MIC_MUTE: if (cp->type == AUDIO_MIXER_ENUM) { cp->un.ord = sc->aria_mix[ARIAMIX_MIC_LVL].mute; error = 0; } break; case ARIAMIX_LINE_IN_MUTE: if (cp->type == AUDIO_MIXER_ENUM) { cp->un.ord = sc->aria_mix[ARIAMIX_LINE_IN_LVL].mute; error = 0; } break; case ARIAMIX_CD_MUTE: if (cp->type == AUDIO_MIXER_ENUM) { cp->un.ord = sc->aria_mix[ARIAMIX_CD_LVL].mute; error = 0; } break; case ARIAMIX_DAC_MUTE: if (cp->type == AUDIO_MIXER_ENUM) { cp->un.ord = sc->aria_mix[ARIAMIX_DAC_LVL].mute; error = 0; } break; case ARIAMIX_AUX_MUTE: if (cp->type == AUDIO_MIXER_ENUM) { cp->un.ord = sc->aria_mix[ARIAMIX_AUX_LVL].mute; error = 0; } break; case ARIAMIX_TEL_MUTE: if (cp->type == AUDIO_MIXER_ENUM) { cp->un.ord = sc->aria_mix[ARIAMIX_TEL_LVL].mute; error = 0; } break; case ARIAMIX_MASTER_LVL: if (cp->type == AUDIO_MIXER_VALUE) { cp->un.value.num_channels = sc->ariamix_master.num_channels; cp->un.value.level[0] = sc->ariamix_master.level[0]; cp->un.value.level[1] = sc->ariamix_master.level[1]; error = 0; } break; case ARIAMIX_MASTER_TREBLE: if (cp->type == AUDIO_MIXER_VALUE) { cp->un.value.num_channels = 2; cp->un.value.level[0] = sc->ariamix_master.treble[0]; cp->un.value.level[1] = sc->ariamix_master.treble[1]; error = 0; } break; case ARIAMIX_MASTER_BASS: if (cp->type == AUDIO_MIXER_VALUE) { cp->un.value.num_channels = 2; cp->un.value.level[0] = sc->ariamix_master.bass[0]; cp->un.value.level[1] = sc->ariamix_master.bass[1]; error = 0; } break; case ARIAMIX_OUT_LVL: if (cp->type == AUDIO_MIXER_VALUE) { cp->un.value.num_channels = sc->sc_chans; cp->un.value.level[0] = sc->gain[0]; cp->un.value.level[1] = sc->gain[1]; error = 0; } break; case ARIAMIX_RECORD_SOURCE: if (cp->type == AUDIO_MIXER_ENUM) { cp->un.ord = sc->aria_mix_source; error = 0; } break; default: return ENXIO; /* NOT REACHED */ } return(error); } int aria_mixer_query_devinfo(addr, dip) void *addr; register mixer_devinfo_t *dip; { register struct aria_softc *sc = addr; DPRINTF(("aria_mixer_query_devinfo\n")); if (!(ARIA_MIXER&sc->sc_hardware)) /* This could be done better, no mixer still has some controls. */ return ENXIO; dip->prev = dip->next = AUDIO_MIXER_LAST; switch(dip->index) { case ARIAMIX_MIC_LVL: dip->type = AUDIO_MIXER_VALUE; dip->mixer_class = ARIAMIX_INPUT_CLASS; dip->next = ARIAMIX_MIC_MUTE; strlcpy(dip->label.name, AudioNmicrophone, sizeof dip->label.name); dip->un.v.num_channels = 2; strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name); break; case ARIAMIX_LINE_IN_LVL: dip->type = AUDIO_MIXER_VALUE; dip->mixer_class = ARIAMIX_INPUT_CLASS; dip->next = ARIAMIX_LINE_IN_MUTE; strlcpy(dip->label.name, AudioNline, sizeof dip->label.name); dip->un.v.num_channels = 2; strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name); break; case ARIAMIX_CD_LVL: dip->type = AUDIO_MIXER_VALUE; dip->mixer_class = ARIAMIX_INPUT_CLASS; dip->next = ARIAMIX_CD_MUTE; strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name); dip->un.v.num_channels = 2; strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name); break; case ARIAMIX_TEL_LVL: dip->type = AUDIO_MIXER_VALUE; dip->mixer_class = ARIAMIX_INPUT_CLASS; dip->next = ARIAMIX_TEL_MUTE; strlcpy(dip->label.name, "telephone", sizeof dip->label.name); dip->un.v.num_channels = 1; strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name); break; case ARIAMIX_DAC_LVL: dip->type = AUDIO_MIXER_VALUE; dip->mixer_class = ARIAMIX_INPUT_CLASS; dip->next = ARIAMIX_DAC_MUTE; strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name); dip->un.v.num_channels = 1; strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name); break; case ARIAMIX_AUX_LVL: dip->type = AUDIO_MIXER_VALUE; dip->mixer_class = ARIAMIX_INPUT_CLASS; dip->next = ARIAMIX_AUX_MUTE; strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name); dip->un.v.num_channels = 1; strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name); break; case ARIAMIX_MIC_MUTE: dip->prev = ARIAMIX_MIC_LVL; goto mode; case ARIAMIX_LINE_IN_MUTE: dip->prev = ARIAMIX_LINE_IN_LVL; goto mode; case ARIAMIX_CD_MUTE: dip->prev = ARIAMIX_CD_LVL; goto mode; case ARIAMIX_DAC_MUTE: dip->prev = ARIAMIX_DAC_LVL; goto mode; case ARIAMIX_AUX_MUTE: dip->prev = ARIAMIX_AUX_LVL; goto mode; case ARIAMIX_TEL_MUTE: dip->prev = ARIAMIX_TEL_LVL; goto mode; mode: dip->mixer_class = ARIAMIX_INPUT_CLASS; dip->type = AUDIO_MIXER_ENUM; strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name); dip->un.e.num_mem = 2; strlcpy(dip->un.e.member[0].label.name, AudioNoff, sizeof dip->un.e.member[0].label.name); dip->un.e.member[0].ord = 0; strlcpy(dip->un.e.member[1].label.name, AudioNon, sizeof dip->un.e.member[0].label.name); dip->un.e.member[1].ord = 1; break; case ARIAMIX_MASTER_LVL: dip->type = AUDIO_MIXER_VALUE; dip->mixer_class = ARIAMIX_OUTPUT_CLASS; dip->next = ARIAMIX_MASTER_TREBLE; strlcpy(dip->label.name, AudioNvolume, sizeof dip->label.name); dip->un.v.num_channels = 2; strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name); break; case ARIAMIX_MASTER_TREBLE: dip->type = AUDIO_MIXER_VALUE; dip->mixer_class = ARIAMIX_OUTPUT_CLASS; dip->prev = ARIAMIX_MASTER_LVL; dip->next = ARIAMIX_MASTER_BASS; strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name); dip->un.v.num_channels = 2; strlcpy(dip->un.v.units.name, AudioNtreble, sizeof dip->un.v.units.name); break; case ARIAMIX_MASTER_BASS: dip->type = AUDIO_MIXER_VALUE; dip->mixer_class = ARIAMIX_OUTPUT_CLASS; dip->prev = ARIAMIX_MASTER_TREBLE; strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name); dip->un.v.num_channels = 2; strlcpy(dip->un.v.units.name, AudioNbass, sizeof dip->un.v.units.name); break; case ARIAMIX_OUT_LVL: dip->type = AUDIO_MIXER_VALUE; dip->mixer_class = ARIAMIX_OUTPUT_CLASS; strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name); dip->un.v.num_channels = 2; strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name); break; case ARIAMIX_RECORD_SOURCE: dip->mixer_class = ARIAMIX_RECORD_CLASS; dip->type = AUDIO_MIXER_ENUM; strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name); dip->un.e.num_mem = 6; strlcpy(dip->un.e.member[0].label.name, AudioNoutput, sizeof dip->un.e.member[0].label.name); dip->un.e.member[0].ord = ARIAMIX_AUX_LVL; strlcpy(dip->un.e.member[1].label.name, AudioNmicrophone, sizeof dip->un.e.member[0].label.name); dip->un.e.member[1].ord = ARIAMIX_MIC_LVL; strlcpy(dip->un.e.member[2].label.name, AudioNdac, sizeof dip->un.e.member[0].label.name); dip->un.e.member[2].ord = ARIAMIX_DAC_LVL; strlcpy(dip->un.e.member[3].label.name, AudioNline, sizeof dip->un.e.member[0].label.name); dip->un.e.member[3].ord = ARIAMIX_LINE_IN_LVL; strlcpy(dip->un.e.member[3].label.name, AudioNcd, sizeof dip->un.e.member[0].label.name); dip->un.e.member[4].ord = ARIAMIX_CD_LVL; strlcpy(dip->un.e.member[3].label.name, "telephone", sizeof dip->un.e.member[0].label.name); dip->un.e.member[5].ord = ARIAMIX_TEL_LVL; break; case ARIAMIX_INPUT_CLASS: dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = ARIAMIX_INPUT_CLASS; strlcpy(dip->label.name, AudioCInputs, sizeof dip->label.name); break; case ARIAMIX_OUTPUT_CLASS: dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = ARIAMIX_OUTPUT_CLASS; strlcpy(dip->label.name, AudioCOutputs, sizeof dip->label.name); break; case ARIAMIX_RECORD_CLASS: dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = ARIAMIX_RECORD_CLASS; strlcpy(dip->label.name, AudioCRecord, sizeof dip->label.name); break; case ARIAMIX_EQ_CLASS: dip->type = AUDIO_MIXER_CLASS; dip->mixer_class = ARIAMIX_EQ_CLASS; strlcpy(dip->label.name, AudioCEqualization, sizeof dip->label.name); break; default: return ENXIO; /*NOTREACHED*/ } return 0; } #endif /* NARIA */