155102Storek /* 255102Storek * Copyright (c) 1991, 1992 The Regents of the University of California. 355102Storek * All rights reserved. 455102Storek * 555102Storek * This software was developed by the Computer Systems Engineering group 655102Storek * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 755102Storek * contributed to Berkeley. 855102Storek * 955499Sbostic * All advertising materials mentioning features or use of this software 1055499Sbostic * must display the following acknowledgement: 1155499Sbostic * This product includes software developed by the University of 12*59182Storek * California, Lawrence Berkeley Laboratory. 1355499Sbostic * 1455102Storek * %sccs.include.redist.c% 1555102Storek * 16*59182Storek * @(#)bsd_audio.c 7.4 (Berkeley) 04/20/93 1755102Storek * 18*59182Storek * from: $Header: bsd_audio.c,v 1.17 93/04/20 05:31:28 torek Exp $ (LBL) 1955102Storek */ 2055102Storek #include "bsdaudio.h" 2155102Storek #if NBSDAUDIO > 0 2255102Storek 2356536Sbostic #include <sys/param.h> 2456536Sbostic #include <sys/systm.h> 2555102Storek 2655102Storek #if BSD < 199103 2755102Storek #ifndef SUNOS 2855102Storek #define SUNOS 2955102Storek #endif 3055102Storek #endif 3155102Storek 3256536Sbostic #include <sys/errno.h> 3356536Sbostic #include <sys/file.h> 3456536Sbostic #include <sys/proc.h> 3556536Sbostic #include <sys/user.h> 3656536Sbostic #include <sys/vnode.h> 3756536Sbostic #include <sys/ioctl.h> 3856536Sbostic #include <sys/time.h> 3955102Storek #ifndef SUNOS 4056536Sbostic #include <sys/tty.h> 4155102Storek #endif 4256536Sbostic #include <sys/uio.h> 4355102Storek 4455102Storek #ifdef SUNOS 4555102Storek #include <sundev/mbvar.h> 4655102Storek #include <sun4c/intreg.h> 4755102Storek #else 4856536Sbostic #include <sys/device.h> 4956536Sbostic #include <machine/autoconf.h> 5055102Storek #endif 5156536Sbostic #include <machine/cpu.h> 5255102Storek 5355102Storek /* 5455102Storek * Avoid name clashes with SunOS so we can config either the bsd or sun 5555102Storek * streams driver in a SunOS kernel. 5655102Storek */ 5755102Storek #ifdef SUNOS 58*59182Storek #include <sbusdev/bsd_audioreg.h> 59*59182Storek #include <sbusdev/bsd_audiovar.h> 60*59182Storek #include <sbusdev/bsd_audioio.h> 6155102Storek struct selinfo { 6255102Storek struct proc *si_proc; 6355102Storek int si_coll; 6455102Storek }; 6555102Storek #else 6656536Sbostic #include <sparc/dev/bsd_audioreg.h> 6756536Sbostic #include <sparc/dev/bsd_audiovar.h> 6856536Sbostic #include <machine/bsd_audioio.h> 6955102Storek #endif 7055102Storek 7155102Storek #ifdef SUNOS 7255102Storek #include "bsd_audiocompat.h" 7355102Storek #endif 7455102Storek 7555102Storek /* 7655102Storek * Initial/default block size is patchable. 7755102Storek */ 7855102Storek int audio_blocksize = DEFBLKSIZE; 79*59182Storek int audio_backlog = 400; /* 50ms in samples */ 8055102Storek 8155102Storek /* 8255102Storek * Software state, per AMD79C30 audio chip. 8355102Storek */ 8455102Storek struct audio_softc { 8555102Storek #ifndef SUNOS 8655102Storek struct device sc_dev; /* base device */ 8755102Storek struct intrhand sc_hwih; /* hardware interrupt vector */ 8855102Storek struct intrhand sc_swih; /* software interrupt vector */ 8955102Storek #endif 9055102Storek int sc_interrupts; /* number of interrupts taken */ 9155102Storek 9255102Storek int sc_open; /* single use device */ 9355102Storek u_long sc_wseek; /* timestamp of last frame written */ 9455102Storek u_long sc_rseek; /* timestamp of last frame read */ 9555102Storek struct mapreg sc_map; /* current contents of map registers */ 9655102Storek struct selinfo sc_wsel; /* write selector */ 9755102Storek struct selinfo sc_rsel; /* read selector */ 9855102Storek /* 9955102Storek * keep track of levels so we don't have to convert back from 10055102Storek * MAP gain constants 10155102Storek */ 10255102Storek int sc_rlevel; /* record level */ 10355102Storek int sc_plevel; /* play level */ 10455102Storek int sc_mlevel; /* monitor level */ 10555102Storek 10655102Storek /* sc_au is special in that the hardware interrupt handler uses it */ 10755102Storek struct auio sc_au; /* recv and xmit buffers, etc */ 10855102Storek 10955102Storek }; 11055102Storek 11155102Storek /* interrupt interfaces */ 11255102Storek #ifndef AUDIO_C_HANDLER 11355102Storek int audiohwintr __P((void *)); 11455102Storek #endif 11555102Storek int audioswintr __P((void *)); 11655102Storek 11755102Storek /* forward declarations */ 11855102Storek int audio_sleep __P((struct aucb *, int)); 11955102Storek void audio_setmap __P((volatile struct amd7930 *, struct mapreg *)); 12055102Storek 12155102Storek static void init_amd(); 12255102Storek 12355102Storek #if !defined(AUDIO_C_HANDLER) || defined(SUNOS) 12455102Storek struct auio *audio_au; 12555102Storek extern void audio_trap(); 12655102Storek #endif 12755102Storek 12855102Storek #ifdef SUNOS 12955102Storek struct audio_softc audio_softc; 13055102Storek #define SOFTC(dev) &audio_softc 13155102Storek #define UIOMOVE(cp, len, code, uio) uiomove(cp, len, code, uio) 13255102Storek 13355102Storek #define AUDIOOPEN(d, f, i, p)\ 13455102Storek audioopen(d, f, i)\ 13555102Storek dev_t d; int f, i; 13655102Storek #define AUDIOCLOSE(d, f, i, p)\ 13755102Storek audioclose(d, f, i)\ 13855102Storek dev_t d; int f, i; 13955102Storek #define AUDIOREAD(d, u, f) \ 14055102Storek audioread(d, u) dev_t d; struct uio *u; 14155102Storek #define AUDIOWRITE(d, u, f) \ 14255102Storek audiowrite(d, u) dev_t d; struct uio *u; 14355102Storek #define AUDIOIOCTL(d, c, a, f, o)\ 14455102Storek audioioctl(d, c, a, f)\ 14555102Storek dev_t d; int c; caddr_t a; int f; 14655102Storek #define AUDIOSELECT(d, r, p)\ 14755102Storek audio_select(d, r, p)\ 14855102Storek dev_t d; int r; struct proc *p; 14955102Storek 15055102Storek 15155102Storek #define AUDIO_SET_SWINTR set_intreg(IR_SOFT_INT4, 1) 15255102Storek 15355102Storek int 15455102Storek audioselect(dev, rw) 15555102Storek register dev_t dev; 15655102Storek int rw; 15755102Storek { 15855102Storek return (audio_select(dev, rw, u.u_procp)); 15955102Storek } 16055102Storek 16155102Storek static void 16255102Storek selrecord(p, si) 16355102Storek struct proc *p; 16455102Storek struct selinfo *si; 16555102Storek { 16655102Storek if (si->si_proc != 0) 16755102Storek si->si_coll = 1; 16855102Storek else 16955102Storek si->si_proc = p; 17055102Storek } 17155102Storek #define SELWAKEUP(si) \ 17255102Storek {\ 17355102Storek if ((si)->si_proc != 0) {\ 17455102Storek selwakeup((si)->si_proc, (si)->si_coll); \ 17555102Storek (si)->si_proc = 0;\ 17655102Storek (si)->si_coll = 0;\ 17755102Storek }\ 17855102Storek } 17955102Storek 18055102Storek 18155102Storek static int audioattach(); 18255102Storek static int audioidentify(); 18355102Storek 18455102Storek struct dev_ops bsdaudio_ops = { 18555102Storek 0, 18655102Storek audioidentify, 18755102Storek audioattach, 18855102Storek }; 18955102Storek 19055102Storek static int 19155102Storek audioidentify(cp) 19255102Storek char *cp; 19355102Storek { 19455102Storek return (strcmp(cp, "audio") == 0); 19555102Storek } 19655102Storek 19755102Storek static int 19855102Storek audioattach(dev) 19955102Storek struct dev_info *dev; 20055102Storek { 20155102Storek register struct audio_softc *sc; 20255102Storek register volatile struct amd7930 *amd; 20355102Storek struct dev_reg *reg; 20455102Storek 20555102Storek sc = &audio_softc; 20655102Storek if (dev->devi_nreg != 1 || dev->devi_nintr != 1) { 20755102Storek printf("audio: bad config\n"); 20855102Storek return (-1); 20955102Storek } 21055102Storek reg = dev->devi_reg; 21155102Storek amd = (struct amd7930 *)map_regs(reg->reg_addr, reg->reg_size, 21255102Storek reg->reg_bustype); 21355102Storek sc->sc_au.au_amd = amd; 21455102Storek init_amd(amd); 21555102Storek 21655102Storek audio_au = &sc->sc_au; 21755102Storek #ifndef AUDIO_C_HANDLER 21855102Storek settrap(dev->devi_intr->int_pri, audio_trap); 21955102Storek #else 22055102Storek /* XXX */ 22155102Storek addintr(dev->devi_intr->int_pri, audiohwintr, dev->devi_name, 22255102Storek dev->devi_unit); 22355102Storek #endif 22455102Storek addintr(4, audioswintr, dev->devi_name, dev->devi_unit); 22555102Storek report_dev(dev); 22655102Storek 22755102Storek return (0); 22855102Storek } 22955102Storek #else 23055102Storek #define AUDIOOPEN(d, f, i, p) audioopen(dev_t d, int f, int i, struct proc *p) 23155102Storek #define AUDIOCLOSE(d, f, i, p) audioclose(dev_t d, int f, int i, \ 23255102Storek struct proc *p) 23355102Storek #define AUDIOREAD(d, u, f) audioread(dev_t d, struct uio *u, int f) 23455102Storek #define AUDIOWRITE(d, u, f) audiowrite(dev_t d, struct uio *u, int f) 23555102Storek #define AUDIOIOCTL(d, c, a, f, o)\ 23655102Storek audioioctl(dev_t dev, int c, caddr_t a, int f, struct proc *p) 23755102Storek #define AUDIOSELECT(d, r, p) audioselect(dev_t dev, int rw, struct proc *p) 23855102Storek #define SELWAKEUP selwakeup 23955102Storek 24055102Storek #define AUDIO_SET_SWINTR ienab_bis(IE_L6) 24155102Storek 24255102Storek /* autoconfiguration driver */ 24355102Storek void audioattach(struct device *, struct device *, void *); 24455102Storek struct cfdriver audiocd = 24555102Storek { NULL, "audio", matchbyname, audioattach, 24655102Storek DV_DULL, sizeof(struct audio_softc) }; 24755102Storek #define SOFTC(dev) audiocd.cd_devs[minor(dev)] 24855102Storek #define UIOMOVE(cp, len, code, uio) uiomove(cp, len, uio) 24955102Storek 25055102Storek /* 25155102Storek * Audio chip found. 25255102Storek */ 25355102Storek void 25455102Storek audioattach(parent, self, args) 25555102Storek struct device *parent, *self; 25655102Storek void *args; 25755102Storek { 25855102Storek register struct audio_softc *sc = (struct audio_softc *)self; 25955102Storek register struct romaux *ra = args; 26055102Storek register volatile struct amd7930 *amd; 26155102Storek register int pri; 26255102Storek 26355102Storek if (ra->ra_nintr != 1) { 26455102Storek printf(": expected 1 interrupt, got %d\n", ra->ra_nintr); 26555102Storek return; 26655102Storek } 26755102Storek pri = ra->ra_intr[0].int_pri; 26855102Storek printf(" pri %d, softpri %d\n", pri, PIL_AUSOFT); 26955102Storek amd = (volatile struct amd7930 *)(ra->ra_vaddr ? 27055102Storek ra->ra_vaddr : mapiodev(ra->ra_paddr, sizeof *amd)); 27155102Storek sc->sc_au.au_amd = amd; 27255102Storek 27355102Storek init_amd(amd); 27455102Storek 27555102Storek #ifndef AUDIO_C_HANDLER 27655102Storek audio_au = &sc->sc_au; 27755102Storek intr_fasttrap(pri, audio_trap); 27855102Storek #else 27955102Storek sc->sc_hwih.ih_fun = audiohwintr; 28055102Storek sc->sc_hwih.ih_arg = &sc->sc_au; 28155102Storek intr_establish(pri, &sc->sc_hwih); 28255102Storek #endif 28355102Storek sc->sc_swih.ih_fun = audioswintr; 28455102Storek sc->sc_swih.ih_arg = sc; 28555102Storek intr_establish(PIL_AUSOFT, &sc->sc_swih); 28655102Storek } 28755102Storek #endif 28855102Storek 28955102Storek static void 29055102Storek init_amd(amd) 29155102Storek register volatile struct amd7930 *amd; 29255102Storek { 29355102Storek /* disable interrupts */ 29455102Storek amd->cr = AMDR_INIT; 29555102Storek amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE; 29655102Storek 29755102Storek /* 29855102Storek * Initialize the mux unit. We use MCR3 to route audio (MAP) 29955102Storek * through channel Bb. MCR1 and MCR2 are unused. 30055102Storek * Setting the INT enable bit in MCR4 will generate an interrupt 30155102Storek * on each converted audio sample. 30255102Storek */ 30355102Storek amd->cr = AMDR_MUX_1_4; 30455102Storek amd->dr = 0; 30555102Storek amd->dr = 0; 30655102Storek amd->dr = (AMD_MCRCHAN_BB << 4) | AMD_MCRCHAN_BA; 30755102Storek amd->dr = AMD_MCR4_INT_ENABLE; 30855102Storek } 30955102Storek 31055102Storek static int audio_default_level = 150; 31155102Storek static void ausetrgain __P((struct audio_softc *, int)); 31255102Storek static void ausetpgain __P((struct audio_softc *, int)); 313*59182Storek static void ausetmgain __P((struct audio_softc *, int)); 31455102Storek static int audiosetinfo __P((struct audio_softc *, struct audio_info *)); 31555102Storek static int audiogetinfo __P((struct audio_softc *, struct audio_info *)); 31655102Storek struct sun_audio_info; 31755102Storek static int sunaudiosetinfo __P((struct audio_softc *, 31855102Storek struct sun_audio_info *)); 31955102Storek static int sunaudiogetinfo __P((struct audio_softc *, 32055102Storek struct sun_audio_info *)); 32155102Storek static void audio_setmmr2 __P((volatile struct amd7930 *, int)); 32255102Storek 32355102Storek int 32455102Storek AUDIOOPEN(dev, flags, ifmt, p) 32555102Storek { 32655102Storek register struct audio_softc *sc; 32755102Storek register volatile struct amd7930 *amd; 32855102Storek int unit = minor(dev), error, s; 32955102Storek 33055102Storek #ifdef SUNOS 33155102Storek if (unit > 0) 33255102Storek return (ENXIO); 33355102Storek sc = &audio_softc; 33455102Storek #else 33555102Storek if (unit >= audiocd.cd_ndevs || (sc = audiocd.cd_devs[unit]) == NULL) 33655102Storek return (ENXIO); 33755102Storek #endif 33855102Storek if (sc->sc_open) 33955102Storek return (EBUSY); 34055102Storek sc->sc_open = 1; 34155102Storek 34255102Storek sc->sc_au.au_lowat = audio_blocksize; 34355102Storek sc->sc_au.au_hiwat = AUCB_SIZE - sc->sc_au.au_lowat; 34455102Storek sc->sc_au.au_blksize = audio_blocksize; 345*59182Storek sc->sc_au.au_backlog = audio_backlog; 34655102Storek 34755102Storek /* set up read and write blocks and `dead sound' zero value. */ 34855102Storek AUCB_INIT(&sc->sc_au.au_rb); 34955102Storek sc->sc_au.au_rb.cb_thresh = AUCB_SIZE; 35055102Storek AUCB_INIT(&sc->sc_au.au_wb); 35155102Storek sc->sc_au.au_wb.cb_thresh = -1; 35255102Storek 35355102Storek /* nothing read or written yet */ 35455102Storek sc->sc_rseek = 0; 35555102Storek sc->sc_wseek = 0; 35655102Storek 35755102Storek bzero((char *)&sc->sc_map, sizeof sc->sc_map); 35855102Storek /* default to speaker */ 35955102Storek sc->sc_map.mr_mmr2 = AMD_MMR2_AINB | AMD_MMR2_LS; 36055102Storek 36155102Storek /* enable interrupts and set parameters established above */ 36255102Storek amd = sc->sc_au.au_amd; 36355102Storek audio_setmmr2(amd, sc->sc_map.mr_mmr2); 36455102Storek ausetrgain(sc, audio_default_level); 36555102Storek ausetpgain(sc, audio_default_level); 366*59182Storek ausetmgain(sc, 0); 36755102Storek amd->cr = AMDR_INIT; 36855102Storek amd->dr = AMD_INIT_PMS_ACTIVE; 36955102Storek 37055102Storek return (0); 37155102Storek } 37255102Storek 37355102Storek static int 37455102Storek audio_drain(sc) 37555102Storek register struct audio_softc *sc; 37655102Storek { 37755102Storek register int error; 37855102Storek 37955102Storek while (!AUCB_EMPTY(&sc->sc_au.au_wb)) 38055102Storek if ((error = audio_sleep(&sc->sc_au.au_wb, 0)) != 0) 38155102Storek return (error); 38255102Storek return (0); 38355102Storek } 38455102Storek 38555102Storek /* 38655102Storek * Close an audio chip. 38755102Storek */ 38855102Storek /* ARGSUSED */ 38955102Storek int 39055102Storek AUDIOCLOSE(dev, flags, ifmt, p) 39155102Storek { 39255102Storek register struct audio_softc *sc = SOFTC(dev); 39355102Storek register volatile struct amd7930 *amd; 39455102Storek register struct aucb *cb; 39555102Storek register int s; 39655102Storek 39755102Storek /* 39855102Storek * Block until output drains, but allow ^C interrupt. 39955102Storek */ 40055102Storek sc->sc_au.au_lowat = 0; /* avoid excessive wakeups */ 40155102Storek s = splaudio(); 40255102Storek /* 40355102Storek * If there is pending output, let it drain (unless 40455102Storek * the output is paused). 40555102Storek */ 40655102Storek cb = &sc->sc_au.au_wb; 40755102Storek if (!AUCB_EMPTY(cb) && !cb->cb_pause) 40855102Storek (void)audio_drain(sc); 40955102Storek /* 41055102Storek * Disable interrupts, clear open flag, and done. 41155102Storek */ 41255102Storek amd = sc->sc_au.au_amd; 41355102Storek amd->cr = AMDR_INIT; 41455102Storek amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE; 41555102Storek splx(s); 41655102Storek sc->sc_open = 0; 41755102Storek return (0); 41855102Storek } 41955102Storek 42055102Storek int 42155102Storek audio_sleep(cb, thresh) 42255102Storek register struct aucb *cb; 42355102Storek register int thresh; 42455102Storek { 42555102Storek register int error; 426*59182Storek register int s = splaudio(); 42755102Storek 42855102Storek cb->cb_thresh = thresh; 42955102Storek error = tsleep((caddr_t)cb, (PZERO + 1) | PCATCH, "audio", 0); 430*59182Storek splx(s); 43155102Storek return (error); 43255102Storek } 43355102Storek 43455102Storek int 43555102Storek AUDIOREAD(dev, uio, ioflag) 43655102Storek { 43755102Storek register struct audio_softc *sc = SOFTC(dev); 43855102Storek register struct aucb *cb; 439*59182Storek register int n, head, taildata, error; 44055102Storek register int blocksize = sc->sc_au.au_blksize; 44155102Storek 44255102Storek if (uio->uio_resid == 0) 44355102Storek return (0); 44455102Storek cb = &sc->sc_au.au_rb; 44555102Storek error = 0; 44655102Storek cb->cb_drops = 0; 44755102Storek sc->sc_rseek = sc->sc_au.au_stamp - AUCB_LEN(cb); 44855102Storek do { 44955102Storek while (AUCB_LEN(cb) < blocksize) { 45055102Storek #ifndef SUNOS 45155102Storek if (ioflag & IO_NDELAY) { 45255102Storek error = EWOULDBLOCK; 453*59182Storek return (error); 45455102Storek } 45555102Storek #endif 45655102Storek if ((error = audio_sleep(cb, blocksize)) != 0) 457*59182Storek return (error); 45855102Storek } 45955102Storek /* 46055102Storek * The space calculation can only err on the short 46155102Storek * side if an interrupt occurs during processing: 46255102Storek * only cb_tail is altered in the interrupt code. 46355102Storek */ 46455102Storek head = cb->cb_head; 46555102Storek if ((n = AUCB_LEN(cb)) > uio->uio_resid) 46655102Storek n = uio->uio_resid; 46755102Storek taildata = AUCB_SIZE - head; 46855102Storek if (n > taildata) { 46955102Storek error = UIOMOVE((caddr_t)cb->cb_data + head, 47055102Storek taildata, UIO_READ, uio); 47155102Storek if (error == 0) 47255102Storek error = UIOMOVE((caddr_t)cb->cb_data, 47355102Storek n - taildata, UIO_READ, uio); 47455102Storek } else 47555102Storek error = UIOMOVE((caddr_t)cb->cb_data + head, n, 47655102Storek UIO_READ, uio); 47755102Storek if (error) 478*59182Storek break; 47955102Storek head = AUCB_MOD(head + n); 48055102Storek cb->cb_head = head; 48155102Storek } while (uio->uio_resid >= blocksize); 482*59182Storek 48355102Storek return (error); 48455102Storek } 48555102Storek 48655102Storek int 48755102Storek AUDIOWRITE(dev, uio, ioflag) 48855102Storek { 48955102Storek register struct audio_softc *sc = SOFTC(dev); 49055102Storek register struct aucb *cb = &sc->sc_au.au_wb; 491*59182Storek register int n, tail, tailspace, error, first, watermark, drops; 49255102Storek 49355102Storek error = 0; 49455102Storek first = 1; 49555102Storek while (uio->uio_resid > 0) { 49655102Storek watermark = sc->sc_au.au_hiwat; 49755102Storek while (AUCB_LEN(cb) > watermark) { 49855102Storek #ifndef SUNOS 49955102Storek if (ioflag & IO_NDELAY) { 50055102Storek error = EWOULDBLOCK; 501*59182Storek return (error); 50255102Storek } 50355102Storek #endif 50455102Storek if ((error = audio_sleep(cb, watermark)) != 0) 505*59182Storek return (error); 50655102Storek watermark = sc->sc_au.au_lowat; 50755102Storek } 50855102Storek /* 50955102Storek * The only value that can change on an interrupt is 51055102Storek * cb->cb_head. We only pull that out once to decide 51155102Storek * how much to write into cb_data; if we lose a race 51255102Storek * and cb_head changes, we will merely be overly 51355102Storek * conservative. For a legitimate time stamp, 51455102Storek * however, we need to synchronize the accesses to 51555102Storek * au_stamp and cb_head at a high ipl below. 51655102Storek */ 517*59182Storek tail = cb->cb_tail; 518*59182Storek if ((n = (AUCB_SIZE - 1) - AUCB_LEN(cb)) > uio->uio_resid) { 51955102Storek n = uio->uio_resid; 520*59182Storek if (cb->cb_head == tail && 521*59182Storek n <= sc->sc_au.au_blksize && 522*59182Storek sc->sc_au.au_stamp - sc->sc_wseek > 400) { 523*59182Storek /* 524*59182Storek * the write is 'small', the buffer is empty 525*59182Storek * and we have been silent for at least 50ms 526*59182Storek * so we might be dealing with an application 527*59182Storek * that writes frames synchronously with 528*59182Storek * reading them. If so, we need an output 529*59182Storek * backlog to cover scheduling delays or 530*59182Storek * there will be gaps in the sound output. 531*59182Storek * Also take this opportunity to reset the 532*59182Storek * buffer pointers in case we ended up on 533*59182Storek * a bad boundary (odd byte, blksize bytes 534*59182Storek * from end, etc.). 535*59182Storek */ 536*59182Storek register u_int* ip; 537*59182Storek register int muzero = 0x7f7f7f7f; 538*59182Storek register int i = splaudio(); 539*59182Storek cb->cb_head = cb->cb_tail = 0; 540*59182Storek splx(i); 541*59182Storek tail = sc->sc_au.au_backlog; 542*59182Storek ip = (u_int*)cb->cb_data; 543*59182Storek for (i = tail >> 2; --i >= 0; ) 544*59182Storek *ip++ = muzero; 545*59182Storek } 546*59182Storek } 54755102Storek tailspace = AUCB_SIZE - tail; 54855102Storek if (n > tailspace) { 54955102Storek /* write first part at tail and rest at head */ 55055102Storek error = UIOMOVE((caddr_t)cb->cb_data + tail, 55155102Storek tailspace, UIO_WRITE, uio); 55255102Storek if (error == 0) 55355102Storek error = UIOMOVE((caddr_t)cb->cb_data, 55455102Storek n - tailspace, UIO_WRITE, uio); 55555102Storek } else 55655102Storek error = UIOMOVE((caddr_t)cb->cb_data + tail, n, 55755102Storek UIO_WRITE, uio); 55855102Storek if (error) 559*59182Storek break; 560*59182Storek 56155102Storek tail = AUCB_MOD(tail + n); 56255102Storek if (first) { 563*59182Storek register int s = splaudio(); 564*59182Storek sc->sc_wseek = AUCB_LEN(cb) + sc->sc_au.au_stamp + 1; 56555102Storek /* 56655102Storek * To guarantee that a write is contiguous in the 56755102Storek * sample space, we clear the drop count the first 56855102Storek * time through. If we later get drops, we will 56955102Storek * break out of the loop below, before writing 57055102Storek * a new frame. 57155102Storek */ 57255102Storek cb->cb_drops = 0; 573*59182Storek cb->cb_tail = tail; 574*59182Storek splx(s); 575*59182Storek first = 0; 576*59182Storek } else { 577*59182Storek if (cb->cb_drops != 0) 578*59182Storek break; 579*59182Storek cb->cb_tail = tail; 58055102Storek } 58155102Storek } 58255102Storek return (error); 58355102Storek } 58455102Storek 58555102Storek /* Sun audio compatibility */ 58655102Storek struct sun_audio_prinfo { 58755102Storek u_int sample_rate; 58855102Storek u_int channels; 58955102Storek u_int precision; 59055102Storek u_int encoding; 59155102Storek u_int gain; 59255102Storek u_int port; 59355102Storek u_int reserved0[4]; 59455102Storek u_int samples; 59555102Storek u_int eof; 59655102Storek u_char pause; 59755102Storek u_char error; 59855102Storek u_char waiting; 59955102Storek u_char reserved1[3]; 60055102Storek u_char open; 60155102Storek u_char active; 60255102Storek }; 60355102Storek struct sun_audio_info { 60455102Storek struct sun_audio_prinfo play; 60555102Storek struct sun_audio_prinfo record; 60655102Storek u_int monitor_gain; 60755102Storek u_int reserved[4]; 60855102Storek }; 60955102Storek 61055102Storek #ifndef SUNOS 61155102Storek #define SUNAUDIO_GETINFO _IOR('A', 1, struct sun_audio_info) 61255102Storek #define SUNAUDIO_SETINFO _IOWR('A', 2, struct sun_audio_info) 61355102Storek #else 61455102Storek #define SUNAUDIO_GETINFO _IOR(A, 1, struct sun_audio_info) 61555102Storek #define SUNAUDIO_SETINFO _IOWR(A, 2, struct sun_audio_info) 61655102Storek #endif 61755102Storek 61855102Storek int 61955102Storek AUDIOIOCTL(dev, cmd, addr, flag, p) 62055102Storek { 62155102Storek register struct audio_softc *sc = SOFTC(dev); 62255102Storek int error = 0, i, s; 62355102Storek 62455102Storek switch (cmd) { 62555102Storek 62655102Storek case AUDIO_GETMAP: 62755102Storek bcopy((caddr_t)&sc->sc_map, addr, sizeof(sc->sc_map)); 62855102Storek break; 62955102Storek 63055102Storek case AUDIO_SETMAP: 63155102Storek bcopy(addr, (caddr_t)&sc->sc_map, sizeof(sc->sc_map)); 63255102Storek sc->sc_map.mr_mmr2 &= 0x7f; 63355102Storek audio_setmap(sc->sc_au.au_amd, &sc->sc_map); 63455102Storek break; 63555102Storek 63655102Storek case AUDIO_FLUSH: 63755102Storek s = splaudio(); 63855102Storek AUCB_INIT(&sc->sc_au.au_rb); 63955102Storek AUCB_INIT(&sc->sc_au.au_wb); 640*59182Storek sc->sc_au.au_stamp = 0; 64155102Storek splx(s); 64255102Storek sc->sc_wseek = 0; 64355102Storek sc->sc_rseek = 0; 64455102Storek break; 64555102Storek 64655102Storek /* 64755102Storek * Number of read samples dropped. We don't know where or 64855102Storek * when they were dropped. 64955102Storek */ 65055102Storek case AUDIO_RERROR: 65155102Storek *(int *)addr = sc->sc_au.au_rb.cb_drops != 0; 65255102Storek break; 65355102Storek 65455102Storek /* 655*59182Storek * How many samples will elapse until mike hears the first 656*59182Storek * sample of what we last wrote? 65755102Storek */ 65855102Storek case AUDIO_WSEEK: 659*59182Storek s = splaudio(); 660*59182Storek *(u_long *)addr = sc->sc_wseek - sc->sc_au.au_stamp 661*59182Storek + AUCB_LEN(&sc->sc_au.au_rb); 662*59182Storek splx(s); 66355102Storek break; 66455102Storek 66555102Storek case AUDIO_SETINFO: 66655102Storek error = audiosetinfo(sc, (struct audio_info *)addr); 66755102Storek break; 66855102Storek 66955102Storek case AUDIO_GETINFO: 67055102Storek error = audiogetinfo(sc, (struct audio_info *)addr); 67155102Storek break; 67255102Storek 67355102Storek case SUNAUDIO_GETINFO: 67455102Storek error = sunaudiogetinfo(sc, (struct sun_audio_info *)addr); 67555102Storek break; 67655102Storek 67755102Storek case SUNAUDIO_SETINFO: 67855102Storek error = sunaudiosetinfo(sc, (struct sun_audio_info *)addr); 67955102Storek break; 68055102Storek 68155102Storek case AUDIO_DRAIN: 68255102Storek error = audio_drain(sc); 68355102Storek break; 68455102Storek 68555102Storek default: 68655102Storek error = EINVAL; 68755102Storek break; 68855102Storek } 68955102Storek return (error); 69055102Storek } 69155102Storek 69255102Storek int 69355102Storek AUDIOSELECT(dev, rw, p) 69455102Storek { 69555102Storek register struct audio_softc *sc = SOFTC(dev); 69655102Storek register struct aucb *cb; 69755102Storek register int s = splaudio(); 69855102Storek 69955102Storek switch (rw) { 70055102Storek 70155102Storek case FREAD: 70255102Storek cb = &sc->sc_au.au_rb; 70355102Storek if (AUCB_LEN(cb) >= sc->sc_au.au_blksize) { 70455102Storek splx(s); 70555102Storek return (1); 70655102Storek } 70755102Storek selrecord(p, &sc->sc_rsel); 70855102Storek cb->cb_thresh = sc->sc_au.au_blksize; 70955102Storek break; 71055102Storek 71155102Storek case FWRITE: 71255102Storek cb = &sc->sc_au.au_wb; 71355102Storek if (AUCB_LEN(cb) <= sc->sc_au.au_lowat) { 71455102Storek splx(s); 71555102Storek return (1); 71655102Storek } 71755102Storek selrecord(p, &sc->sc_wsel); 71855102Storek cb->cb_thresh = sc->sc_au.au_lowat; 71955102Storek break; 72055102Storek } 72155102Storek splx(s); 72255102Storek return (0); 72355102Storek } 72455102Storek 72555102Storek #ifdef AUDIO_C_HANDLER 72655102Storek int 72755102Storek audiohwintr(au0) 72855102Storek void *au0; 72955102Storek { 73055102Storek #ifdef SUNOS 73155102Storek register struct auio *au = audio_au; 73255102Storek #else 73355102Storek register struct auio *au = au0; 73455102Storek #endif 73555102Storek register volatile struct amd7930 *amd = au->au_amd; 73655102Storek register struct aucb *cb; 73755102Storek register int h, t, k; 73855102Storek 73955102Storek k = amd->ir; /* clear interrupt */ 74055102Storek ++au->au_stamp; 74155102Storek 74255102Storek /* receive incoming data */ 74355102Storek cb = &au->au_rb; 74455102Storek h = cb->cb_head; 74555102Storek t = cb->cb_tail; 74655102Storek k = AUCB_MOD(t + 1); 74755102Storek if (h == k) 74855102Storek cb->cb_drops++; 74955102Storek else if (cb->cb_pause != 0) 75055102Storek cb->cb_pdrops++; 75155102Storek else { 75255102Storek cb->cb_data[t] = amd->bbrb; 75355102Storek cb->cb_tail = t = k; 75455102Storek } 75555102Storek if (AUCB_MOD(t - h) >= cb->cb_thresh) { 75655102Storek cb->cb_thresh = AUCB_SIZE; 75755102Storek cb->cb_waking = 1; 75855102Storek AUDIO_SET_SWINTR; 75955102Storek } 76055102Storek /* send outgoing data */ 76155102Storek cb = &au->au_wb; 76255102Storek h = cb->cb_head; 76355102Storek t = cb->cb_tail; 76455102Storek if (h == t) 76555102Storek cb->cb_drops++; 76655102Storek else if (cb->cb_pause != 0) 76755102Storek cb->cb_pdrops++; 76855102Storek else { 76955102Storek cb->cb_head = h = AUCB_MOD(h + 1); 77055102Storek amd->bbtb = cb->cb_data[h]; 77155102Storek } 77255102Storek if (AUCB_MOD(t - h) <= cb->cb_thresh) { 77355102Storek cb->cb_thresh = -1; 77455102Storek cb->cb_waking = 1; 77555102Storek AUDIO_SET_SWINTR; 77655102Storek } 77755102Storek return (1); 77855102Storek } 77955102Storek #endif 78055102Storek 78155102Storek int 78255102Storek audioswintr(sc0) 78355102Storek void *sc0; 78455102Storek { 78555102Storek register struct audio_softc *sc; 78655102Storek register int s, ret = 0; 78755102Storek #ifdef SUNOS 78855102Storek sc = &audio_softc; 78955102Storek #else 79055102Storek sc = sc0; 79155102Storek #endif 79255102Storek s = splaudio(); 79355102Storek if (sc->sc_au.au_rb.cb_waking != 0) { 79455102Storek sc->sc_au.au_rb.cb_waking = 0; 79555102Storek splx(s); 79655102Storek ret = 1; 79755102Storek wakeup((caddr_t)&sc->sc_au.au_rb); 79855102Storek SELWAKEUP(&sc->sc_rsel); 79955102Storek } 80055102Storek if (sc->sc_au.au_wb.cb_waking != 0) { 80155102Storek sc->sc_au.au_wb.cb_waking = 0; 80255102Storek splx(s); 80355102Storek ret = 1; 80455102Storek wakeup((caddr_t)&sc->sc_au.au_wb); 80555102Storek SELWAKEUP(&sc->sc_wsel); 80655102Storek } else 80755102Storek splx(s); 80855102Storek return (ret); 80955102Storek } 81055102Storek 81155102Storek /* Write 16 bits of data from variable v to the data port of the audio chip */ 81255102Storek 813*59182Storek #define WAMD16(amd, v) ((amd)->dr = (v), (amd)->dr = (v) >> 8) 81455102Storek 81555102Storek void 81655102Storek audio_setmap(amd, map) 81755102Storek register volatile struct amd7930 *amd; 81855102Storek register struct mapreg *map; 81955102Storek { 82055102Storek register int i, s, v; 82155102Storek 82255102Storek s = splaudio(); 82355102Storek amd->cr = AMDR_MAP_1_10; 82455102Storek for (i = 0; i < 8; i++) { 82555102Storek v = map->mr_x[i]; 82655102Storek WAMD16(amd, v); 82755102Storek } 82855102Storek for (i = 0; i < 8; ++i) { 82955102Storek v = map->mr_r[i]; 83055102Storek WAMD16(amd, v); 83155102Storek } 83255102Storek v = map->mr_gx; WAMD16(amd, v); 83355102Storek v = map->mr_gr; WAMD16(amd, v); 83455102Storek v = map->mr_ger; WAMD16(amd, v); 83555102Storek v = map->mr_stgr; WAMD16(amd, v); 83655102Storek v = map->mr_ftgr; WAMD16(amd, v); 83755102Storek v = map->mr_atgr; WAMD16(amd, v); 83855102Storek amd->dr = map->mr_mmr1; 83955102Storek amd->dr = map->mr_mmr2; 84055102Storek splx(s); 84155102Storek } 84255102Storek 84355102Storek /* 84455102Storek * Set the mmr1 register and one other 16 bit register in the audio chip. 84555102Storek * The other register is indicated by op and val. 84655102Storek */ 84755102Storek void 84855102Storek audio_setmmr1(amd, mmr1, op, val) 84955102Storek register volatile struct amd7930 *amd; 85055102Storek register int mmr1; 85155102Storek register int op; 85255102Storek register int val; 85355102Storek { 85455102Storek register int s = splaudio(); 85555102Storek 85655102Storek amd->cr = AMDR_MAP_MMR1; 85755102Storek amd->dr = mmr1; 85855102Storek amd->cr = op; 85955102Storek WAMD16(amd, val); 86055102Storek splx(s); 86155102Storek } 86255102Storek 86355102Storek /* 864*59182Storek * Set the mmr2 register. 86555102Storek */ 86655102Storek static void 86755102Storek audio_setmmr2(amd, mmr2) 86855102Storek register volatile struct amd7930 *amd; 86955102Storek register int mmr2; 87055102Storek { 87155102Storek register int s = splaudio(); 87255102Storek 87355102Storek amd->cr = AMDR_MAP_MMR2; 87455102Storek amd->dr = mmr2; 87555102Storek splx(s); 87655102Storek } 87755102Storek 878*59182Storek /* 879*59182Storek * gx, gr & stg gains. this table must contain 256 elements with 880*59182Storek * the 0th being "infinity" (the magic value 9008). The remaining 881*59182Storek * elements match sun's gain curve (but with higher resolution): 882*59182Storek * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps. 883*59182Storek */ 884*59182Storek static const u_short gx_coeff[256] = { 885*59182Storek 0x9008, 0x8b7c, 0x8b51, 0x8b45, 0x8b42, 0x8b3b, 0x8b36, 0x8b33, 886*59182Storek 0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22, 887*59182Storek 0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b, 888*59182Storek 0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb, 889*59182Storek 0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a, 890*59182Storek 0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213, 891*59182Storek 0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231, 892*59182Storek 0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4, 893*59182Storek 0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2, 894*59182Storek 0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa, 895*59182Storek 0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b, 896*59182Storek 0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b, 897*59182Storek 0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd, 898*59182Storek 0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808, 899*59182Storek 0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243, 900*59182Storek 0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224, 901*59182Storek 0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb, 902*59182Storek 0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33, 903*59182Storek 0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32, 904*59182Storek 0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323, 905*59182Storek 0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a, 906*59182Storek 0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23, 907*59182Storek 0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1, 908*59182Storek 0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333, 909*59182Storek 0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227, 910*59182Storek 0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6, 911*59182Storek 0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2, 912*59182Storek 0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba, 913*59182Storek 0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033, 914*59182Storek 0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021, 915*59182Storek 0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012, 916*59182Storek 0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e, 91755102Storek }; 91855102Storek 919*59182Storek /* 920*59182Storek * second stage play gain. 921*59182Storek */ 922*59182Storek static const u_short ger_coeff[] = { 923*59182Storek 0x431f, /* 5. dB */ 924*59182Storek 0x331f, /* 5.5 dB */ 925*59182Storek 0x40dd, /* 6. dB */ 926*59182Storek 0x11dd, /* 6.5 dB */ 927*59182Storek 0x440f, /* 7. dB */ 928*59182Storek 0x411f, /* 7.5 dB */ 929*59182Storek 0x311f, /* 8. dB */ 930*59182Storek 0x5520, /* 8.5 dB */ 931*59182Storek 0x10dd, /* 9. dB */ 932*59182Storek 0x4211, /* 9.5 dB */ 933*59182Storek 0x410f, /* 10. dB */ 934*59182Storek 0x111f, /* 10.5 dB */ 935*59182Storek 0x600b, /* 11. dB */ 936*59182Storek 0x00dd, /* 11.5 dB */ 937*59182Storek 0x4210, /* 12. dB */ 938*59182Storek 0x110f, /* 13. dB */ 939*59182Storek 0x7200, /* 14. dB */ 940*59182Storek 0x2110, /* 15. dB */ 941*59182Storek 0x2200, /* 15.9 dB */ 942*59182Storek 0x000b, /* 16.9 dB */ 943*59182Storek 0x000f /* 18. dB */ 944*59182Storek #define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0])) 94555102Storek }; 94655102Storek 94755102Storek static void 94855102Storek ausetrgain(sc, level) 94955102Storek register struct audio_softc *sc; 95055102Storek register int level; 95155102Storek { 95255102Storek level &= 0xff; 95355102Storek sc->sc_rlevel = level; 954*59182Storek sc->sc_map.mr_mmr1 |= AMD_MMR1_GX; 955*59182Storek sc->sc_map.mr_gx = gx_coeff[level]; 95655102Storek audio_setmmr1(sc->sc_au.au_amd, sc->sc_map.mr_mmr1, 95755102Storek AMDR_MAP_GX, sc->sc_map.mr_gx); 95855102Storek } 95955102Storek 96055102Storek static void 96155102Storek ausetpgain(sc, level) 96255102Storek register struct audio_softc *sc; 96355102Storek register int level; 96455102Storek { 965*59182Storek register int gi, s; 966*59182Storek register volatile struct amd7930 *amd; 967*59182Storek 96855102Storek level &= 0xff; 96955102Storek sc->sc_plevel = level; 970*59182Storek sc->sc_map.mr_mmr1 |= AMD_MMR1_GER|AMD_MMR1_GR; 971*59182Storek level *= 256 + NGER; 972*59182Storek level >>= 8; 973*59182Storek if (level >= 256) { 974*59182Storek gi = level - 256; 975*59182Storek level = 255; 976*59182Storek } else 977*59182Storek gi = 0; 978*59182Storek sc->sc_map.mr_ger = ger_coeff[gi]; 979*59182Storek sc->sc_map.mr_gr = gx_coeff[level]; 980*59182Storek 981*59182Storek amd = sc->sc_au.au_amd; 982*59182Storek s = splaudio(); 983*59182Storek amd->cr = AMDR_MAP_MMR1; 984*59182Storek amd->dr = sc->sc_map.mr_mmr1; 985*59182Storek amd->cr = AMDR_MAP_GR; 986*59182Storek gi = sc->sc_map.mr_gr; 987*59182Storek WAMD16(amd, gi); 988*59182Storek amd->cr = AMDR_MAP_GER; 989*59182Storek gi = sc->sc_map.mr_ger; 990*59182Storek WAMD16(amd, gi); 991*59182Storek splx(s); 99255102Storek } 99355102Storek 99455102Storek static void 99555102Storek ausetmgain(sc, level) 99655102Storek register struct audio_softc *sc; 99755102Storek register int level; 99855102Storek { 99955102Storek level &= 0xff; 100055102Storek sc->sc_mlevel = level; 1001*59182Storek sc->sc_map.mr_mmr1 |= AMD_MMR1_STG; 1002*59182Storek sc->sc_map.mr_stgr = gx_coeff[level]; 100355102Storek audio_setmmr1(sc->sc_au.au_amd, sc->sc_map.mr_mmr1, 100455102Storek AMDR_MAP_STG, sc->sc_map.mr_stgr); 100555102Storek } 100655102Storek 100755102Storek static int 100855102Storek audiosetinfo(sc, ai) 100955102Storek struct audio_softc *sc; 101055102Storek struct audio_info *ai; 101155102Storek { 101255102Storek struct audio_prinfo *r = &ai->record, *p = &ai->play; 101355102Storek register int s, bsize; 101455102Storek 101555102Storek if (p->gain != ~0) 101655102Storek ausetpgain(sc, p->gain); 101755102Storek if (r->gain != ~0) 101855102Storek ausetrgain(sc, r->gain); 101955102Storek if (ai->monitor_gain != ~0) 1020*59182Storek ausetmgain(sc, ai->monitor_gain); 102155102Storek if (p->port == AUDIO_SPEAKER) { 102255102Storek sc->sc_map.mr_mmr2 |= AMD_MMR2_LS; 102355102Storek audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2); 102455102Storek } else if (p->port == AUDIO_HEADPHONE) { 102555102Storek sc->sc_map.mr_mmr2 &=~ AMD_MMR2_LS; 102655102Storek audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2); 102755102Storek } 102855102Storek if (p->pause != (u_char)~0) 102955102Storek sc->sc_au.au_wb.cb_pause = p->pause; 103055102Storek if (r->pause != (u_char)~0) 103155102Storek sc->sc_au.au_rb.cb_pause = r->pause; 103255102Storek 103355102Storek if (ai->blocksize != ~0) { 103455102Storek if (ai->blocksize == 0) 103555102Storek bsize = ai->blocksize = DEFBLKSIZE; 103655102Storek else if (ai->blocksize > MAXBLKSIZE) 103755102Storek bsize = ai->blocksize = MAXBLKSIZE; 103855102Storek else 103955102Storek bsize = ai->blocksize; 104055102Storek 104155102Storek s = splaudio(); 104255102Storek sc->sc_au.au_blksize = bsize; 104355102Storek /* AUDIO_FLUSH */ 104455102Storek AUCB_INIT(&sc->sc_au.au_rb); 104555102Storek AUCB_INIT(&sc->sc_au.au_wb); 104655102Storek splx(s); 104755102Storek 104855102Storek } 104955102Storek if (ai->hiwat != ~0 && (unsigned)ai->hiwat < AUCB_SIZE) 105055102Storek sc->sc_au.au_hiwat = ai->hiwat; 105155102Storek if (ai->lowat != ~0 && ai->lowat < AUCB_SIZE) 105255102Storek sc->sc_au.au_lowat = ai->lowat; 1053*59182Storek if (ai->backlog != ~0 && ai->backlog < (AUCB_SIZE/2)) 1054*59182Storek sc->sc_au.au_backlog = ai->backlog; 105555102Storek 105655102Storek return (0); 105755102Storek } 105855102Storek 105955102Storek static int 106055102Storek sunaudiosetinfo(sc, ai) 106155102Storek struct audio_softc *sc; 106255102Storek struct sun_audio_info *ai; 106355102Storek { 106455102Storek struct sun_audio_prinfo *r = &ai->record, *p = &ai->play; 106555102Storek 106655102Storek if (p->gain != ~0) 106755102Storek ausetpgain(sc, p->gain); 106855102Storek if (r->gain != ~0) 106955102Storek ausetrgain(sc, r->gain); 107055102Storek if (ai->monitor_gain != ~0) 1071*59182Storek ausetmgain(sc, ai->monitor_gain); 107255102Storek if (p->port == AUDIO_SPEAKER) { 107355102Storek sc->sc_map.mr_mmr2 |= AMD_MMR2_LS; 107455102Storek audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2); 107555102Storek } else if (p->port == AUDIO_HEADPHONE) { 107655102Storek sc->sc_map.mr_mmr2 &=~ AMD_MMR2_LS; 107755102Storek audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2); 107855102Storek } 107955102Storek /* 108055102Storek * The bsd driver does not distinguish between paused and active. 108155102Storek * (In the sun driver, not active means samples are not ouput 108255102Storek * at all, but paused means the last streams buffer is drained 108355102Storek * and then output stops.) If either are 0, then when stop output. 108455102Storek * Otherwise, if either are non-zero, we resume. 108555102Storek */ 108655102Storek if (p->pause == 0 || p->active == 0) 108755102Storek sc->sc_au.au_wb.cb_pause = 0; 108855102Storek else if (p->pause != (u_char)~0 || p->active != (u_char)~0) 108955102Storek sc->sc_au.au_wb.cb_pause = 1; 109055102Storek if (r->pause == 0 || r->active == 0) 109155102Storek sc->sc_au.au_rb.cb_pause = 0; 109255102Storek else if (r->pause != (u_char)~0 || r->active != (u_char)~0) 109355102Storek sc->sc_au.au_rb.cb_pause = 1; 109455102Storek 109555102Storek return (0); 109655102Storek } 109755102Storek 109855102Storek static int 109955102Storek audiogetinfo(sc, ai) 110055102Storek struct audio_softc *sc; 110155102Storek struct audio_info *ai; 110255102Storek { 110355102Storek struct audio_prinfo *r = &ai->record, *p = &ai->play; 110455102Storek 110555102Storek p->sample_rate = r->sample_rate = 8000; 110655102Storek p->channels = r->channels = 1; 110755102Storek p->precision = r->precision = 8; 110855102Storek p->encoding = r->encoding = AUDIO_ENCODING_ULAW; 110955102Storek 111055102Storek ai->monitor_gain = sc->sc_mlevel; 111155102Storek r->gain = sc->sc_rlevel; 111255102Storek p->gain = sc->sc_plevel; 111355102Storek r->port = 1; p->port = (sc->sc_map.mr_mmr2 & AMD_MMR2_LS) ? 111455102Storek AUDIO_SPEAKER : AUDIO_HEADPHONE; 111555102Storek 111655102Storek p->pause = sc->sc_au.au_wb.cb_pause; 111755102Storek r->pause = sc->sc_au.au_rb.cb_pause; 111855102Storek p->error = sc->sc_au.au_wb.cb_drops != 0; 111955102Storek r->error = sc->sc_au.au_rb.cb_drops != 0; 112055102Storek 112155102Storek p->open = sc->sc_open; 112255102Storek r->open = sc->sc_open; 112355102Storek 112455102Storek p->samples = sc->sc_au.au_stamp - sc->sc_au.au_wb.cb_pdrops; 112555102Storek r->samples = sc->sc_au.au_stamp - sc->sc_au.au_rb.cb_pdrops; 112655102Storek 112755102Storek p->seek = sc->sc_wseek; 112855102Storek r->seek = sc->sc_rseek; 112955102Storek 113055102Storek ai->blocksize = sc->sc_au.au_blksize; 113155102Storek ai->hiwat = sc->sc_au.au_hiwat; 113255102Storek ai->lowat = sc->sc_au.au_lowat; 1133*59182Storek ai->backlog = sc->sc_au.au_backlog; 113455102Storek 113555102Storek return (0); 113655102Storek } 113755102Storek 113855102Storek static int 113955102Storek sunaudiogetinfo(sc, ai) 114055102Storek struct audio_softc *sc; 114155102Storek struct sun_audio_info *ai; 114255102Storek { 114355102Storek struct sun_audio_prinfo *r = &ai->record, *p = &ai->play; 114455102Storek 114555102Storek p->sample_rate = r->sample_rate = 8000; 114655102Storek p->channels = r->channels = 1; 114755102Storek p->precision = r->precision = 8; 114855102Storek p->encoding = r->encoding = AUDIO_ENCODING_ULAW; 114955102Storek 115055102Storek ai->monitor_gain = sc->sc_mlevel; 115155102Storek r->gain = sc->sc_rlevel; 115255102Storek p->gain = sc->sc_plevel; 115355102Storek r->port = 1; p->port = (sc->sc_map.mr_mmr2 & AMD_MMR2_LS) ? 115455102Storek AUDIO_SPEAKER : AUDIO_HEADPHONE; 115555102Storek 115655102Storek p->active = p->pause = sc->sc_au.au_wb.cb_pause; 115755102Storek r->active = r->pause = sc->sc_au.au_rb.cb_pause; 115855102Storek p->error = sc->sc_au.au_wb.cb_drops != 0; 115955102Storek r->error = sc->sc_au.au_rb.cb_drops != 0; 116055102Storek 116155102Storek p->waiting = 0; 116255102Storek r->waiting = 0; 116355102Storek p->eof = 0; 116455102Storek r->eof = 0; 116555102Storek 116655102Storek p->open = sc->sc_open; 116755102Storek r->open = sc->sc_open; 116855102Storek 116955102Storek p->samples = sc->sc_au.au_stamp - sc->sc_au.au_wb.cb_pdrops; 117055102Storek r->samples = sc->sc_au.au_stamp - sc->sc_au.au_rb.cb_pdrops; 117155102Storek 117255102Storek return (0); 117355102Storek } 117455102Storek #endif 1175