📄 bsd_audio.c
字号:
/* * Copyright (c) 1991, 1992, 1993 * The Regents of the University of California. All rights reserved. * * This software was developed by the Computer Systems Engineering group * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and * contributed to Berkeley. * * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Lawrence Berkeley Laboratory. * * 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 the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. * * @(#)bsd_audio.c 8.1 (Berkeley) 6/11/93 * * from: $Header: bsd_audio.c,v 1.18 93/04/24 16:20:35 leres Exp $ (LBL) */#include "bsdaudio.h"#if NBSDAUDIO > 0#include <sys/param.h>#include <sys/systm.h>#if BSD < 199103#ifndef SUNOS#define SUNOS#endif#endif#include <sys/errno.h>#include <sys/file.h>#include <sys/proc.h>#include <sys/user.h>#include <sys/vnode.h>#include <sys/ioctl.h>#include <sys/time.h>#ifndef SUNOS#include <sys/tty.h>#endif#include <sys/uio.h>#ifdef SUNOS#include <sundev/mbvar.h>#include <sun4c/intreg.h>#else#include <sys/device.h>#include <machine/autoconf.h>#endif#include <machine/cpu.h>/* * Avoid name clashes with SunOS so we can config either the bsd or sun * streams driver in a SunOS kernel. */#ifdef SUNOS#include <sbusdev/bsd_audioreg.h>#include <sbusdev/bsd_audiovar.h>#include <sbusdev/bsd_audioio.h>struct selinfo { struct proc *si_proc; int si_coll;};#else#include <sparc/dev/bsd_audioreg.h>#include <sparc/dev/bsd_audiovar.h>#include <machine/bsd_audioio.h>#endif#ifdef SUNOS#include "bsd_audiocompat.h"#endif/* * Initial/default block size is patchable. */int audio_blocksize = DEFBLKSIZE;int audio_backlog = 400; /* 50ms in samples *//* * Software state, per AMD79C30 audio chip. */struct audio_softc {#ifndef SUNOS struct device sc_dev; /* base device */ struct intrhand sc_hwih; /* hardware interrupt vector */ struct intrhand sc_swih; /* software interrupt vector */#endif int sc_interrupts; /* number of interrupts taken */ int sc_open; /* single use device */ u_long sc_wseek; /* timestamp of last frame written */ u_long sc_rseek; /* timestamp of last frame read */ struct mapreg sc_map; /* current contents of map registers */ struct selinfo sc_wsel; /* write selector */ struct selinfo sc_rsel; /* read selector */ /* * keep track of levels so we don't have to convert back from * MAP gain constants */ int sc_rlevel; /* record level */ int sc_plevel; /* play level */ int sc_mlevel; /* monitor level */ /* sc_au is special in that the hardware interrupt handler uses it */ struct auio sc_au; /* recv and xmit buffers, etc */};/* interrupt interfaces */#ifndef AUDIO_C_HANDLERint audiohwintr __P((void *));#endifint audioswintr __P((void *));/* forward declarations */int audio_sleep __P((struct aucb *, int));void audio_setmap __P((volatile struct amd7930 *, struct mapreg *));static void init_amd();#if !defined(AUDIO_C_HANDLER) || defined(SUNOS)struct auio *audio_au;extern void audio_trap();#endif#ifdef SUNOSstruct audio_softc audio_softc;#define SOFTC(dev) &audio_softc#define UIOMOVE(cp, len, code, uio) uiomove(cp, len, code, uio)#define AUDIOOPEN(d, f, i, p)\ audioopen(d, f, i)\ dev_t d; int f, i;#define AUDIOCLOSE(d, f, i, p)\ audioclose(d, f, i)\ dev_t d; int f, i;#define AUDIOREAD(d, u, f) \ audioread(d, u) dev_t d; struct uio *u;#define AUDIOWRITE(d, u, f) \ audiowrite(d, u) dev_t d; struct uio *u;#define AUDIOIOCTL(d, c, a, f, o)\ audioioctl(d, c, a, f)\ dev_t d; int c; caddr_t a; int f;#define AUDIOSELECT(d, r, p)\ audio_select(d, r, p)\ dev_t d; int r; struct proc *p;#define AUDIO_SET_SWINTR set_intreg(IR_SOFT_INT4, 1)intaudioselect(dev, rw) register dev_t dev; int rw;{ return (audio_select(dev, rw, u.u_procp));}static voidselrecord(p, si) struct proc *p; struct selinfo *si;{ if (si->si_proc != 0) si->si_coll = 1; else si->si_proc = p;}#define SELWAKEUP(si) \{\ if ((si)->si_proc != 0) {\ selwakeup((si)->si_proc, (si)->si_coll); \ (si)->si_proc = 0;\ (si)->si_coll = 0;\ }\}static int audioattach();static int audioidentify();struct dev_ops bsdaudio_ops = { 0, audioidentify, audioattach,};static intaudioidentify(cp) char *cp;{ return (strcmp(cp, "audio") == 0);}static intaudioattach(dev) struct dev_info *dev;{ register struct audio_softc *sc; register volatile struct amd7930 *amd; struct dev_reg *reg; sc = &audio_softc; if (dev->devi_nreg != 1 || dev->devi_nintr != 1) { printf("audio: bad config\n"); return (-1); } reg = dev->devi_reg; amd = (struct amd7930 *)map_regs(reg->reg_addr, reg->reg_size, reg->reg_bustype); sc->sc_au.au_amd = amd; init_amd(amd); audio_au = &sc->sc_au;#ifndef AUDIO_C_HANDLER settrap(dev->devi_intr->int_pri, audio_trap);#else /* XXX */ addintr(dev->devi_intr->int_pri, audiohwintr, dev->devi_name, dev->devi_unit);#endif addintr(4, audioswintr, dev->devi_name, dev->devi_unit); report_dev(dev); return (0);}#else#define AUDIOOPEN(d, f, i, p) audioopen(dev_t d, int f, int i, struct proc *p)#define AUDIOCLOSE(d, f, i, p) audioclose(dev_t d, int f, int i, \ struct proc *p)#define AUDIOREAD(d, u, f) audioread(dev_t d, struct uio *u, int f)#define AUDIOWRITE(d, u, f) audiowrite(dev_t d, struct uio *u, int f)#define AUDIOIOCTL(d, c, a, f, o)\ audioioctl(dev_t dev, int c, caddr_t a, int f, struct proc *p)#define AUDIOSELECT(d, r, p) audioselect(dev_t dev, int rw, struct proc *p)#define SELWAKEUP selwakeup#define AUDIO_SET_SWINTR ienab_bis(IE_L6)/* autoconfiguration driver */void audioattach(struct device *, struct device *, void *);struct cfdriver audiocd = { NULL, "audio", matchbyname, audioattach, DV_DULL, sizeof(struct audio_softc) };#define SOFTC(dev) audiocd.cd_devs[minor(dev)]#define UIOMOVE(cp, len, code, uio) uiomove(cp, len, uio)/* * Audio chip found. */voidaudioattach(parent, self, args) struct device *parent, *self; void *args;{ register struct audio_softc *sc = (struct audio_softc *)self; register struct romaux *ra = args; register volatile struct amd7930 *amd; register int pri; if (ra->ra_nintr != 1) { printf(": expected 1 interrupt, got %d\n", ra->ra_nintr); return; } pri = ra->ra_intr[0].int_pri; printf(" pri %d, softpri %d\n", pri, PIL_AUSOFT); amd = (volatile struct amd7930 *)(ra->ra_vaddr ? ra->ra_vaddr : mapiodev(ra->ra_paddr, sizeof *amd)); sc->sc_au.au_amd = amd; init_amd(amd);#ifndef AUDIO_C_HANDLER audio_au = &sc->sc_au; intr_fasttrap(pri, audio_trap);#else sc->sc_hwih.ih_fun = audiohwintr; sc->sc_hwih.ih_arg = &sc->sc_au; intr_establish(pri, &sc->sc_hwih);#endif sc->sc_swih.ih_fun = audioswintr; sc->sc_swih.ih_arg = sc; intr_establish(PIL_AUSOFT, &sc->sc_swih);}#endifstatic voidinit_amd(amd) register volatile struct amd7930 *amd;{ /* disable interrupts */ amd->cr = AMDR_INIT; amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE; /* * Initialize the mux unit. We use MCR3 to route audio (MAP) * through channel Bb. MCR1 and MCR2 are unused. * Setting the INT enable bit in MCR4 will generate an interrupt * on each converted audio sample. */ amd->cr = AMDR_MUX_1_4; amd->dr = 0; amd->dr = 0; amd->dr = (AMD_MCRCHAN_BB << 4) | AMD_MCRCHAN_BA; amd->dr = AMD_MCR4_INT_ENABLE;}static int audio_default_level = 150;static void ausetrgain __P((struct audio_softc *, int));static void ausetpgain __P((struct audio_softc *, int));static void ausetmgain __P((struct audio_softc *, int));static int audiosetinfo __P((struct audio_softc *, struct audio_info *));static int audiogetinfo __P((struct audio_softc *, struct audio_info *));struct sun_audio_info;static int sunaudiosetinfo __P((struct audio_softc *, struct sun_audio_info *));static int sunaudiogetinfo __P((struct audio_softc *, struct sun_audio_info *));static void audio_setmmr2 __P((volatile struct amd7930 *, int));/* ARGSUSED */intAUDIOOPEN(dev, flags, ifmt, p){ register struct audio_softc *sc; register volatile struct amd7930 *amd; int unit = minor(dev);#ifdef SUNOS if (unit > 0) return (ENXIO); sc = &audio_softc;#else if (unit >= audiocd.cd_ndevs || (sc = audiocd.cd_devs[unit]) == NULL) return (ENXIO);#endif if (sc->sc_open) return (EBUSY); sc->sc_open = 1; sc->sc_au.au_lowat = audio_blocksize; sc->sc_au.au_hiwat = AUCB_SIZE - sc->sc_au.au_lowat; sc->sc_au.au_blksize = audio_blocksize; sc->sc_au.au_backlog = audio_backlog; /* set up read and write blocks and `dead sound' zero value. */ AUCB_INIT(&sc->sc_au.au_rb); sc->sc_au.au_rb.cb_thresh = AUCB_SIZE; AUCB_INIT(&sc->sc_au.au_wb); sc->sc_au.au_wb.cb_thresh = -1; /* nothing read or written yet */ sc->sc_rseek = 0; sc->sc_wseek = 0; bzero((char *)&sc->sc_map, sizeof sc->sc_map); /* default to speaker */ sc->sc_map.mr_mmr2 = AMD_MMR2_AINB | AMD_MMR2_LS; /* enable interrupts and set parameters established above */ amd = sc->sc_au.au_amd; audio_setmmr2(amd, sc->sc_map.mr_mmr2); ausetrgain(sc, audio_default_level); ausetpgain(sc, audio_default_level); ausetmgain(sc, 0); amd->cr = AMDR_INIT; amd->dr = AMD_INIT_PMS_ACTIVE; return (0);}static intaudio_drain(sc) register struct audio_softc *sc;{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -